#Goals: # Automate everything I don't like. # Prevent deaths by boredom/Not noticing things. autofight_wait = true confirm_butcher = never easy_eat_chunks = true auto_eat_chunks = true auto_drop_chunks = yes show_more = false autopickup_exceptions += 0 then : if bot_hp < dmg_old_hp then : dmg_inturn = dmg_old_hp - bot_hp : percent_old_hp = math.ceil((dmg_old_hp*100)/bot_mhp) : percent_hp = math.ceil((bot_hp*100)/bot_mhp) : percent_hp_txt = percent_hp .. "%" : if percent_hp < 30 then : percent_hp_txt = "" .. percent_hp_txt .. "" : elseif percent_hp < 55 then : percent_hp_txt = "" .. percent_hp_txt .. "" : elseif percent_hp < 75 then : percent_hp_txt = "" .. percent_hp_txt .. "" : end : percent_hp_txt = percent_hp_txt .. "(" .. bot_hp .. "hp)" : if dmg_inturn > (bot_hp*0.25) then : huge_dmg_note(dmg_inturn) : crawl.mpr("Huge Dmg: -" .. (percent_old_hp-percent_hp) .. "%(-" .. dmg_inturn .. "hp)" .. " hp: " .. percent_hp_txt) : dmg_old_hp = bot_hp : crawl.flush_prev_message() : crawl.more() : crawl.more_autoclear(false) : else : if dmg_inturn > (bot_hp*0.15) then : crawl.mpr("Damage: -" .. (percent_old_hp-percent_hp) .. "%(-" .. dmg_inturn .. "hp)" .. " hp: " .. percent_hp_txt) : else : crawl.mpr("Damage: -" .. (percent_old_hp-percent_hp) .. "%(-" .. dmg_inturn .. "hp)" .. " hp: " .. percent_hp_txt) : end : end : crawl.flush_prev_message() : end : end : dmg_old_hp = bot_hp : end : function huge_dmg_note(x) : crawl.take_note("Huge Dmg: " .. x .. " Dmg") : end dump_message_count = 100 easy_eat_chunks=true chunks_autopickup = true confirm_butcher = never auto_eat_chunks = true auto_drop_chunks = yes #################### # Autoinscriptions # #################### autoinscribe += of faith:!P autoinscribe += manual of:!d autoinscribe += berserk rage:!q { function should_prompt() local hp, mhp = you.hp() local mp, mmp =you.mp() return ((2*hp < mhp or you.confused() or you.slowed() or you.silencing()) and (you.xl() > 5)) end } ################# better_autofight: :function delta_to_vi(dx, dy) : local d2v = { : [-1] = { [-1] = 'y', [0] = 'h', [1] = 'b'}, : [0] = { [-1] = 'k', [1] = 'j'}, : [1] = { [-1] = 'u', [0] = 'l', [1] = 'n'}, : } : return d2v[dx][dy] :end { --------------------------------------------------------------------------- -- My divergent version of autofight. -- I use hit_closest_nomove normally. --------------------------------------------------------------------------- local ATT_HOSTILE = 0 local ATT_NEUTRAL = 1 number_hits = 0 AUTOFIGHT_STOP = 70 AUTOFIGHT_CAUGHT = false AUTOFIGHT_THROW = false AUTOFIGHT_THROW_NOMOVE = false AUTOFIGHT_FIRE_STOP = false --automagic AUTOMAGIC_ACTIVE = false -- Utility functions used by autofight local function sign(a) return a > 0 and 1 or a < 0 and -1 or 0 end local function abs(a) return a * sign(a) end local function adjacent(dx, dy) return abs(dx) <= 1 and abs(dy) <= 1 end local function vector_move(dx, dy) local str = '' for i = 1,abs(dx) do str = str .. delta_to_vi(sign(dx), 0) end for i = 1,abs(dy) do str = str .. delta_to_vi(0, sign(dy)) end return str end -- Weapon ranges local function have_reaching() local wp = items.equipped_at("weapon") return wp and wp.reach_range == 2 and not wp.is_melded end local function have_ranged() local wp = items.equipped_at("weapon") return wp and wp.is_ranged and not wp.is_melded end local function have_throwing(no_move) return (AUTOFIGHT_THROW or no_move and AUTOFIGHT_THROW_NOMOVE) and items.fired_item() ~= nil end -- rest of autofight local function wait() crawl.sendkeys(".") end local function get_monster_info(dx,dy,no_move) m = monster.get_monster_at(dx,dy) name = m:name() if not m then return nil end info = {} info.distance = (abs(dx) > abs(dy)) and -abs(dx) or -abs(dy) if have_ranged() then info.attack_type = you.see_cell_no_trans(dx, dy) and 3 or 0 elseif not have_reaching() then info.attack_type = (-info.distance < 2) and 2 or 0 else if -info.distance > 2 then info.attack_type = 0 elseif -info.distance < 2 then info.attack_type = 2 else info.attack_type = view.can_reach(dx, dy) and 1 or 0 end end if info.attack_type == 0 and have_throwing(no_move) and you.see_cell_no_trans(dx, dy) then -- Melee is better than throwing. info.attack_type = 3 end info.can_attack = (info.attack_type > 0) and 1 or 0 info.safe = m:is_safe() and -1 or 0 info.constricting_you = m:is_constricting_you() and 1 or 0 -- Only prioritize good stabs: sleep and paralysis. info.very_stabbable = (m:stabbability() >= 1) and 1 or 0 info.injury = m:damage_level() info.threat = m:threat() info.orc_priest_wizard = (name == "orc priest" or name == "orc wizard") and 1 or 0 return info end local function compare_monster_info(m1, m2) flag_order = autofight_flag_order if flag_order == nil then flag_order = {"can_attack", "safe", "distance", "constricting_you", "very_stabbable", "injury", "threat", "orc_priest_wizard"} end for i,flag in ipairs(flag_order) do if m1[flag] > m2[flag] then return true elseif m1[flag] < m2[flag] then return false end end return false end local function is_candidate_for_attack(x,y) m = monster.get_monster_at(x, y) --if m then crawl.mpr("Checking: (" .. x .. "," .. y .. ") " .. m:name()) end if not m or m:attitude() ~= ATT_HOSTILE then return false end if m:name() == "butterfly" or m:name() == "orb of destruction" then return false end if m:is_firewood() then --crawl.mpr("... is firewood.") if string.find(m:name(), "ballistomycete") then return true end return false end return true end local function get_target(no_move) local x, y, bestx, besty, best_info, new_info bestx = 0 besty = 0 best_info = nil for x = -8,8 do for y = -8,8 do if is_candidate_for_attack(x, y) then new_info = get_monster_info(x, y, no_move) if (not best_info) or compare_monster_info(new_info, best_info) then bestx = x besty = y best_info = new_info end end end end return bestx, besty, best_info end local function attack_fire(x,y) move = 'fr' .. vector_move(x, y) .. 'f' crawl.process_keys(move) end local function attack_fire_stop(x,y) move = 'fr' .. vector_move(x, y) .. '.' crawl.process_keys(move) end local function attack_reach(x,y) move = 'vr' .. vector_move(x, y) .. '.' crawl.process_keys(move) end local function attack_melee(x,y) move = delta_to_vi(x, y) crawl.process_keys(move) end function af_hp_is_low() local hp, mhp = you.hp() return (100*hp <= AUTOFIGHT_STOP*mhp) end function hit_closest_nomove() allow_movement = false local x, y, info = get_target(not allow_movement) local caught = you.caught() if af_hp_is_low() then crawl.mpr("You are too injured to fight recklessly!") number_hits = 0 elseif you.confused() then crawl.mpr("You are too confused!") number_hits = 0 elseif caught then if AUTOFIGHT_CAUGHT then crawl.process_keys(delta_to_vi(1, 0)) -- Direction doesn't matter. else crawl.mpr("You are " .. caught .. "!") end number_hits = 0 elseif should_prompt() then crawl.mpr("You can't fight recklessly due to (Slow/Silence/etc.)!") number_hits = 0 elseif info == nil then wait() elseif info.attack_type == 3 then if AUTOFIGHT_FIRE_STOP then attack_fire_stop(x,y) else attack_fire(x,y) end elseif info.attack_type == 2 then attack_melee(x,y) elseif info.attack_type == 1 then attack_reach(x,y) elseif AUTOMAGIC_ACTIVE and you.spell_table()[AUTOMAGIC_SPELL_SLOT] then mag_attack(false) else wait() end end local function mp_is_low() local AUTOMAGIC_STOP = 30 local mp, mmp = you.mp() return (100*mp <= AUTOMAGIC_STOP*mmp) end local function get_monster_info_magic(dx,dy) m = monster.get_monster_at(dx,dy) name = m:name() if not m then return nil end info = {} info.distance = (abs(dx) > abs(dy)) and -abs(dx) or -abs(dy) -- Decide what to do for target's range by squareLOS range range = spells.range(you.spell_table()[AUTOMAGIC_SPELL_SLOT]) if abs(dx) <= range and abs(dy) <= range then -- In range info.attack_type = 1 else -- Out of range info.attack_type = 2 end info.can_attack = (info.attack_type == 1) and 1 or 0 info.safe = m:is_safe() and -1 or 0 info.constricting_you = m:is_constricting_you() and 1 or 0 info.injury = m:damage_level() info.threat = m:threat() info.orc_priest_wizard = (name == "orc priest" or name == "orc wizard") and 1 or 0 return info end local function compare_monster_info_magic(m1, m2) flag_order = automagic_flag_order if flag_order == nil then flag_order = {"can_attack", "safe", "distance", "constricting_you", "injury", "threat", "orc_priest_wizard"} end for i,flag in ipairs(flag_order) do if m1[flag] > m2[flag] then return true elseif m1[flag] < m2[flag] then return false end end return false end local function is_candidate_for_attack_magic(x,y) m = monster.get_monster_at(x, y) --if m then crawl.mpr("Checking: (" .. x .. "," .. y .. ") " .. m:name()) end if not m or m:attitude() ~= ATT_HOSTILE then return false end if m:name() == "butterfly" or m:name() == "orb of destruction" then return false end if m:is_firewood() then --crawl.mpr("... is firewood.") if string.find(m:name(), "ballistomycete") then return true end return false end return true end local function get_target_magic() local los_radius = you.los() local x, y, bestx, besty, best_info, new_info bestx = 0 besty = 0 best_info = nil for x = -los_radius,los_radius do for y = -los_radius,los_radius do if is_candidate_for_attack_magic(x, y) then new_info = get_monster_info_magic(x, y) if (not best_info) or compare_monster_info_magic(new_info, best_info) then bestx = x besty = y best_info = new_info end end end end return bestx, besty, best_info end local function spell_attack(x,y) -- There has already been a valid target check to have gotten this far. -- Required magic points have also been checked. -- Spells that could hurt you (clouds, fireball) will still trigger "are you -- sure" so that safeguard is not bypassed. move = 'z' .. AUTOMAGIC_SPELL_SLOT .. 'r' .. vector_move(x, y) .. 'f' crawl.process_keys(move, true) end function mag_attack(allow_movement) local x, y, info = get_target_magic() if af_hp_is_low() then crawl.mpr("You are too injured to fight recklessly!") elseif you.confused() then crawl.mpr("You are too confused!") elseif info == nil then crawl.mpr("No target in view!") elseif spells.mana_cost(you.spell_table()[AUTOMAGIC_SPELL_SLOT]) > you.mp() then -- First check for enough magic points, then check if below threshold crawl.mpr("You don't have enough magic to cast " .. you.spell_table()[AUTOMAGIC_SPELL_SLOT] .. "!") wait() elseif mp_is_low() then crawl.mpr("You are too depleted to cast spells recklessly!") wait() elseif info.attack_type == 1 then spell_attack(x,y) else wait() end end function megahit() hit_closest_nomove() number_hits = 4 end function hit_nonmagic() attack(true) end function hit_nonmagic_nomove() attack(false) end function hit_magic_nomove() if you.spell_table()[AUTOMAGIC_SPELL_SLOT] then mag_attack(false) else crawl.mpr("No spell in slot " .. AUTOMAGIC_SPELL_SLOT .. "!") end end function toggle_autothrow() AUTOFIGHT_THROW = not AUTOFIGHT_THROW crawl.mpr(AUTOFIGHT_THROW and "Enabling autothrow." or "Disabling autothrow.") end } ###################################################################### # Automatically opens the skill menu when starting a new game. { local need_pregame_options = true function ready() if you.turns() == 0 and need_pregame_options then crawl.sendkeys("m") need_pregame_options = false end if you.turns() == 1 then if you.spell_table()["a"] ~= nil then am_set_spell() end end DmgTrack() if (number_hits ~= 0) then number_hits = (number_hits - 1) hit_closest_nomove() end -- Force slowing down play in dangerous situations if should_prompt() then crawl.setopt("tile_player_tile = mons:ignacio") crawl.delay(1000) else crawl.setopt("tile_player_tile = normal") end end }