travel_delay = -1 explore_delay = 20 # force_more_message = curse toe, enormous slime creature, titanic slime creature, Erolcha, Meliai, hell sentinel, Jorgrun, Moth of Wrath, Floating Eye, Flayed Ghosts, Tzitzim, tormentor #tile_player_tile = tile: mons_Radroach explore_stop = shops,altars,portals,branches,runed_doors autofight_stop = 75 show_more = false autofight_fires = true bold_brightens_foreground=true explore_auto_rest=true default_manual_training = true tile_layout_priority = minimap, inventory, command, spell, monster tile_upstairs_col = green tile_branchstairs_col = red tile_downstairs_col = red tile_door_col = #c27149 tile_wall_col = #4c4141 tile_explore_horizon_col = #919191 tile_floor_col = #0f0d0d tile_item_col = #0f0d0d tile_feature_col = #d4be21 tile_plant_col = #3e5a2f tile_water_col = #0b5d79 tile_deep_water_col = #1212b3 tile_trap_col = #f447ff tile_transporter_col = #ff5656 tile_transporter_landing_col = #59ff89 tile_lava_col = #5f0a00 macros += M o ===start_auto_kill macros += M O ===manual_reset_auto_kill_script { local auto_fight_health_threshold = 0.75 local auto_fight_mana_threshold = 0.35 local need_skills_opened = true local turn_delay = 150 local danger_threshold = 2 local debug_enabled = true local debug_text_channel = 3 local notify_text_channel = 4 local infinite_loop_safety_net = 0 local infinite_loop_safety_net_max = 100 local attack_range = 1 local auto_kill = false local preferred_combat_style = 'melee' function ready() crawl.setopt("autofight_fires = true") if you.turns() == 0 and need_skills_opened then need_skills_opened = false crawl.sendkeys("m") end get_preferred_combat_style() if do_I_prefer_spells() then get_current_spell_in_slot_a() else attack_range = get_melee_range() end if auto_kill then if infinite_loop_safety_net < infinite_loop_safety_net_max then infinite_loop_safety_net = infinite_loop_safety_net + 1 kill_and_explore() else stop_fighting('Loop max') end end end function c_interrupt_activity(aname, iname, cause) if string.find(aname, "travel") then if type(cause) == "string" and string.find(cause, "Key pressed") then stop_fighting("Auto Killed stopped - Key pressed") elseif type(cause) == "string" and string.find(cause, "Done exploring.") then stop_fighting("Auto Killed stopped - Done exploring.") elseif type(cause) == "string" and string.find(cause, "Partly explored") then stop_fighting("Auto Killed stopped - Partly explored.") elseif type(cause) == "string" and string.find(cause, "Could not explore") then stop_fighting("Auto Killed stopped - Could not explore.") elseif string.find(iname, "monster") or string.find(cause, "monsters nearby") or string.find(aname, "macro") then kill_and_explore() end end return false end function start_auto_kill() debug_print('Starting script') reset_auto_kill_script() auto_kill = true kill_and_explore() end function kill_and_explore() local monster_table = initialize_monster_table() debug_print('killing and exploring') if is_monster_nearby(monster_table) then debug_print('evalutating dangerous sitituation') local too_dangerous, reason = is_situation_too_dangerous(monster_table) if too_dangerous then stop_fighting(reason) else local target = get_closest_visible_monster(monster_table) debug_print('getting closest target') if target then debug_print('target found') fight_enemy(target) end end elseif not you.feel_safe() then stop_fighting('Auto kill stopped - Not safe, but cannot find any monsters (likely invisible monster, or translucent walls)') else debug_print('no nearby monsters, exploring now') infinite_loop_safety_net = 0 go_explore() end end function is_monster_nearby(monster_table) return table_length(monster_table) > 0 end function do_I_prefer_spells() return preferred_combat_style == 'spells' end function do_I_prefer_melee() return preferred_combat_style == 'melee' end function is_situation_too_dangerous(monster_table) local EXTREMELY_DANGEROUS = 3 local DANGEROUS = 2 local EASY = 1 local HARMLESS = 0 local threat_level = 0; local extremely_dangerous_monster_count = 0; local dangerous_monster_count = 0 local easy_monster_count = 0 local harmless_monster_count = 0 for _, monster_details in pairs(monster_table) do if monster_details:threat() <= HARMLESS then harmless_monster_count = harmless_monster_count + 1 threat_level = threat_level + HARMLESS elseif monster_details:threat() == EASY then easy_monster_count = easy_monster_count + 1 threat_level = threat_level + EASY elseif monster_details:threat() == DANGEROUS then dangerous_monster_count = dangerous_monster_count + 1 threat_level = threat_level + DANGEROUS else extremely_dangerous_monster_count = extremely_dangerous_monster_count + 1 threat_level = threat_level + EXTREMELY_DANGEROUS end end if threat_level > danger_threshold then return true, "Auto kill stopped - Too dangerous: Extremely Dangerous (" .. extremely_dangerous_monster_count .. ") Dangerous (" .. dangerous_monster_count .. ") Easy (" .. easy_monster_count .. ") Harmless (" .. harmless_monster_count .. ")" end return false end function get_preferred_combat_style() local player_class = you.class() local melee_styles = util.set({ "Fighter", "Gladiator", "Monk", "Hunter", "Brigand", "Berserker", "Chaos", "Cinder", "Transmuter", "Warper", "Hexslinger", "Enchanter", "Reaver" }) local spell_styles = util.set({ "Hedge Wizard", "Conjurer", "Summoner", "Necromancer", "Fire Elementalist", "Ice Elementalist", "Air Elementalist", "Earth Elementalist", "Venom Mage" }) if melee_styles[player_class] then preferred_combat_style = 'melee' elseif spell_styles[player_class] then preferred_combat_style = 'spells' end end function attack_enemy(target) if preferred_combat_style == 'melee' then swing_weapon_at_enemy(target) elseif preferred_combat_style == 'spells' then cast_spell_at_enemy(target) else shoot_at_enemy(target) end end function initialize_monster_table() local los = you.los() local enemy_monster_array = {} local count = 0 for y = los, -los, -1 do for x = -los, los do local monster_details = monster.get_monster_at(x, y) if monster_details then debug_print("Monster found") end if monster_details and not monster_details:is_safe() and you.see_cell_solid(monster_details:x_pos(), monster_details:y_pos()) then enemy_monster_array[count] = monster_details count = count + 1 end end end return enemy_monster_array end function can_I_see_monster(monster_details) local is_monster_invisible = view.invisible_monster(monster_details:x_pos(), monster_details:y_pos()) local can_see_tile = you.see_cell_solid(monster_details:x_pos(), monster_details:y_pos()) local can_see_monster = not is_monster_invisible or you.see_invisible() if is_monster_invisible then debug_print("Monster is invisible - yes") else debug_print("Monster is invisible - not") end if not can_see_tile then debug_print('Cannot see tile') else debug_print('Can see tile') end if not can_see_monster then debug_print('Cannot see monster') end return can_see_tile and can_see_monster end function get_closest_visible_monster(monster_table) local shortest_distance_to_a_monster = 100; local closest_monster = nil for _, monster_details in pairs(monster_table) do if monster_details and can_I_see_monster then local distance_to_monster = get_distance_to_cell(monster_details:x_pos(), monster_details:y_pos()) if shortest_distance_to_a_monster > distance_to_monster then shortest_distance_to_a_monster = distance_to_monster closest_monster = monster_details end end end return closest_monster end function take_action(action, delay) crawl.delay(delay) crawl.do_commands(action) end function move_closer_to_enemy(target) debug_print('Lua - moving closer to ' .. target:name()) take_action({ "CMD_AUTOFIGHT" }, turn_delay) end function swing_weapon_at_enemy(target) debug_print('Lua - attempting to attack ' .. target:name()) take_action({ "CMD_AUTOFIGHT" }, turn_delay) end function shoot_at_enemy(target) debug_print('Lua - attempting to use ranged weapon on' .. target:name()) take_action({ "CMD_AUTOFIRE" }, turn_delay) end function wait_a_turn() take_action({ "CMD_WAIT " }, turn_delay) end function cast_spell_at_enemy(target) debug_print('Lua - attempting to cast spell on ' .. target:name()) take_action({ "CMD_AUTOFIRE" }, turn_delay) end function go_explore() take_action({ "CMD_WAIT", "CMD_EXPLORE" }, turn_delay) end function in_fighting_shape() local _, maxHp = you.hp() local mp, maxMp = you.mp() local hp_after_poison = you.poison_survival() if you.confused() or you.asleep() or you.mesmerised() or you.paralysed() or you.petrifying() then return false, 'Lua - Auto Kill stopped. Suffering from a bad status effect' end if do_I_prefer_melee() then if hp_after_poison / maxHp >= auto_fight_health_threshold then return true else return false, 'Lua - Auto Kill stopped. Not in fighting shape.' end elseif do_I_prefer_spells() then if you.silenced() then return false, 'Lua - Auto Kill stopped. Not in fighting shape.' end if hp_after_poison / maxHp >= auto_fight_health_threshold and mp / maxMp >= auto_fight_mana_threshold then return true else return false, 'Lua - Auto Kill stopped. Not in fighting shape.' end end end function get_current_spell_in_slot_a() local spell_table = you.spell_table() local slot_a_spell_name = spell_table['a'] attack_range = spells.range(slot_a_spell_name) end function get_distance_to_cell(x, y) local absX = math.abs(x) local absY = math.abs(y) local highest_value = absX if absY > absX then highest_value = absY end return highest_value end function get_melee_range() local range = 1 local weapon = items.equipped_at("weapon") if weapon then range = weapon.reach_range end return range end function distance_to_target(target) return get_distance_to_cell(target:x_pos(), target:y_pos()) end function am_I_in_range_to_attack(target) return attack_range >= distance_to_target(target) end function manual_reset_auto_kill_script() stop_fighting("Auto Kill stopped - Manually stopped") end function reset_auto_kill_script() stop_fighting() end function am_I_being_struck_by_melee_out_of_my_range(target) return target:reach_range() > attack_range and distance_to_target(target) == target:reach_range() end function stop_fighting(message) if message then notify_print(message) end auto_kill = false infinite_loop_safety_net = 0 end function fight_enemy(target) debug_print('Lua - initiating combat actions on ' .. target:name() .. " || reach is " .. target:reach_range()) local should_fight, reason = in_fighting_shape() if should_fight then if am_I_in_range_to_attack(target) then attack_enemy(target) elseif am_I_being_struck_by_melee_out_of_my_range(target) then crawl.setopt("autofight_fires = false") attack_enemy(target) else move_closer_to_enemy(target) end else stop_fighting(reason) end debug_print('Lua - done fight_enemy()') end function dev_print(message) crawl.mpr(message, 2) end function debug_print(message) if debug_enabled then crawl.mpr(message, debug_text_channel) end end function notify_print(message) crawl.mpr(message, notify_text_channel) end function table_length(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end }