species = Mi background = Be weapon = hand axe view_delay = 0 clear_messages = true travel_delay = -1 explore_delay = -1 travel_key_stop = false default_manual_training = true autopickup_no_burden = false auto_exclude = hp_warning = 0 show_more = false show_intenvotry_weights = true show_newturn_mark = false list_rotten = false force_more_message = show_travel_trail = false char_set = ascii cset = cloud:xa4 cset_ascii = item_orb:0 use_fake_player_cursor = true equip_unequip = true auto_sacrifice = before_explore skill_focus = true show_player_species = true trapwalk_safe_hp = net:1,dart:1,needle:1,arrow:1,bolt:1,spear:1,blade:1,alarm:1 dump_order = header, hiscore, stats, misc, inventory, dump_order += skills, spells, overview, mutations, messages, dump_order += screenshot, monlist, turns_by_place, kills_by_place, dump_order += kills, notes, action_counts, vaults runrest_stop_message = runrest_ignore_message = runrest_ignore_message += .* runrest_ignore_poison = 3:15 runrest_ignore_monster += butterfly:1 runrest_ignore_monster += orb of destruction:1 autofight_stop = 0 autopickup = ?!/% ae := autopickup_exceptions df := drop_filter ae = df = ae += scrolls? of (summoning|vulnerability|brand weapon) ae += scrolls? of (magic mapping|fog|fear|silence) ae += scrolls? of (holy word|amnesia) ae += scrolls? of (curse armour|curse jewellery|curse weapon) ae += scrolls? of (immolation|noise|random uselessness|torment) df += scrolls? of (summoning|vulnerability|brand weapon) df += scrolls? of (magic mapping|fog|fear|silence) df += scrolls? of (holy word|amnesia) df += scrolls? of (curse armour|curse jewellery|curse weapon) df += scrolls? of (immolation|noise|random uselessness|torment) ae += potions? of (brilliance|magic|cancellation) ae += potions? of (flight|invisibility|blood|coagulated blood) ae += potions? of (agility|cure mutation|porridge) ae += potions? of (confusion|decay|degeneration|mutation|paralysis) ae += potions? of (poison|lignification|strong poison) df += potions? of (brilliance|magic|cancellation) df += potions? of (flight|invisibility|blood|coagulated blood) df += potions? of (agility|cure mutation|porridge) df += potions? of (confusion|decay|degeneration|mutation|paralysis) df += potions? of (poison|lignification|strong poison) ae += wand of (random effects|slowing|magic darts|flame|frost|confusion) ae += wand of (enslavement|paralysis|invisibility|lightning|fireball) ae += wand of (cold|digging|disintegration|draining|fire|polymorph) df += wand of (random effects|slowing|magic darts|flame|frost|confusion) df += wand of (enslavement|paralysis|invisibility|lightning|fireball) df += wand of (cold|digging|disintegration|draining|fire|polymorph) channel.multiturn = mute message_colour += mute:Reset throwing quiver message_colour += mute:You can't grasp things well bindkey = [D] CMD_DROP # these allow us to use these keys freely in commands to handle prompts bindkey = [Y] CMD_NO_CMD_DEFAULT bindkey = [.] CMD_NO_CMD_DEFAULT bindkey = [N] CMD_NO_CMD_DEFAULT bindkey = [m] CMD_NO_CMD_DEFAULT bindkey = [)] CMD_LUA_CONSOLE : if you.race() == "Troll" or you.race() == "Ogre" then fire_order = rock, javelin, tomahawk, stone : else fire_order = javelin, tomahawk, stone : end #### < local THROTTLE = true local THROTTLE_DELAY = 100 local esc = string.char(27) local bestposx = nil local bestposy = nil local lastx = x local lasty = y local done_exploring = false local invisible_enemy = false local invis_count = 0 local hit_something = false local stuck = false local no_matches = {} local force_fight = false local attack_moving = false local finding_food = false local unexcluded = false local expected_place = "D:1" local travelling = true local playing = false local flee_count = 0 local fled_level = false local fled_branch = nil local just_fled = false local kiting = false local responding_to_message = false local response_turns = -1 local pause = false local hold = false local finesse_time = -100 local heroism_time = -100 local blink_time = -10 local servant_time = -100 local bend_time_time = -10 local entered_temple = false local requivered = false --local god = "trog" --local god = "okawaru" --local god = "makhleb" local god = "qazlal" --local god = "cheibriados" local species = you.race() local class = you.class() local dodging = species == "Ogre" or species == "Troll" or species == "Spriggan" or species == "Vine Stalker" or species == "Merfolk" or species == "Draconian" or species == "Tengu" or species == "Felid" or (species == "Naga" and class ~= "Fighter") local weaponskill = class == "Monk" and "Unarmed Combat" or species == "Deep Dwarf" and "Axes" or species == "Hill Orc" and "Axes" or species == "Vine Stalker" and "Short Blades" or species == "Spriggan" and "Short Blades" or species == "Deep Elf" and "Long Blades" or species == "Naga" and "Long Blades" or species == "Draconian" and "Long Blades" or species == "Ogre" and "Maces & Flails" or species == "Merfolk" and "Polearms" or species == "Centaur" and "Polearms" or species == "Troll" and "Unarmed Combat" or species == "Felid" and "Unarmed Combat" or class == "Gladiator" and "Staves" or species == "Demonspawn" and "Long Blades" or species == "Minotaur" and "Maces & Flails" or species == "Gargoyle" and "Maces & Flails" or "Maces & Flails" local rangedfirst = class == "Hunter" or species == "Centaur" function processkeys(cmd) hold = true crawl.enable_more(false) crawl.flush_input() local ret = crawl.process_keys(cmd .. esc .. esc .. esc) hold = false crawl.flush_input() return ret end function sendkeys(cmd) hold = true crawl.enable_more(false) crawl.flush_input() local ret = crawl.sendkeys(cmd .. esc .. esc .. esc) hold = false crawl.flush_input() return ret end function choose_stat_gain() return "d" end function auto_experience() return true end function start() ready() end -- borrowed from qw function inventory() return iter.invent_iterator:new(items.inventory()) end function have_potion(type) for it in inventory() do if it and string.match(it.name(),"potions? of " .. type) then return items.index_to_letter(it.slot) end end return nil end function quaff(type) if you.berserk() then return false end for it in inventory() do if it and string.match(it.name(),"potions? of " .. type) then local letter = items.index_to_letter(it.slot) sendkeys('q' .. letter) return true end end return false end function have_scroll(type) for it in inventory() do if it and string.match(it.name(),"scrolls? of " .. type) then return items.index_to_letter(it.slot) end end return nil end function read_scroll(type) if you.berserk() or you.confused() then return false end local slot = have_scroll(type) if slot then sendkeys("r" .. slot) return true end return false end function have_wand(type) for it in inventory() do if it and string.match(it.name(),"wand of " .. type) and not string.match(it.name(), "empty") and not string.match(it.name(), "0") then return items.index_to_letter(it.slot) end end return nil end function have_empty_wand(type) for it in inventory() do if it and string.match(it.name(),"wand of " .. type) and (string.match(it.name(), "empty") or string.match(it.name(), "0")) then return items.index_to_letter(it.slot) end end return nil end function self_zap(type) if you.berserk() or you.confused() then return false end local slot = have_wand(type) if slot then sendkeys("V" .. slot .. "rf") return true end return false end function threat(targets) local threat = 0 local allies = 0 -- if #targets == 0 then return 0 end -- for i = 1,#targets do -- local mon = targets[i] -- local m = monster.get_monster_at(mon["x"], mon["y"]) -- local th = m:threat()*m:threat() -- if m:attitude() > 1 then -- threat = threat - th -- allies = allies + 1 -- else -- threat = threat + th -- end -- end for x = -8,8 do for y = -8,8 do local dist = math.max(math.abs(x), math.abs(y)) local m = monster.get_monster_at(x, y) if m then local th = m:threat()*m:threat() if m:attitude() == 0 then threat = threat + th elseif m:attitude() > 1 then threat = threat - th allies = allies + 1 end end end end return threat, allies end function have_ability(name) for letter, abil in pairs(you.ability_table()) do if abil == name then return letter end end return nil end function use_ability(name, needs_target) local letter = have_ability(name) if letter then crawl.sendkeys("a" .. letter) if not needs_target then sendkeys(esc) end return true end return false end function target_square(x, y) local dx = x local dy = y while dx > 0 do crawl.sendkeys("l") dx = dx - 1 end while dx < 0 do crawl.sendkeys("h") dx = dx + 1 end while dy > 0 do crawl.sendkeys("j") dy = dy - 1 end while dy < 0 do crawl.sendkeys("k") dy = dy + 1 end crawl.sendkeys("fYYY") sendkeys(esc) end function has_polearm() local weap = items.equipped_at("Weapon") return weap and (weap:name():find("spear") or weap:name():find("trident") or weap:name():find("halberd") or weap:name():find("glaive") or weap:name():find("bardiche")) end function rechargethewand(what) if you.berserk() or you.confused() then return false end local mp,b = you.mp() local re = have_scroll("recharging") local it = nil if re or (you.race() == "Deep Dwarf" and mp > 0) then it = have_empty_wand(what) if it then if re then crawl.sendkeys("r" .. re .. it) sendkeys(esc) return true end if you.race() == "Deep Dwarf" and you.hunger() == 0 and eat_permafood() then return true end if use_ability("Device Recharging", true) then crawl.sendkeys(it) sendkeys(esc) return true end end end return false end function breathe_at(x, y) if you.berserk() or you.confused() or you.breath_timeout() then return false end local letter = have_ability("Breathe Poison Gas") if not letter then letter = have_ability("Spit Poison") end if not letter then letter = have_ability("Breathe Fire") end if not letter then letter = have_ability("Breathe Frost") end if not letter then letter = have_ability("Spit Acid") end if not letter then letter = have_ability("Breathe Steam") end if not letter and (math.abs(x) <= 1 and math.abs(y) <= 1) then letter = have_ability("Breathe Sticky Flame") end if not letter then letter = have_ability("Breathe Noxious Fumes") end if letter then crawl.sendkeys("a" .. letter .. "r") target_square(x, y) return true end return false end function check_emergency(besttarget, targets, ranged, polearm, fast, slow) local hp, hpmax = you.hp() local realhp = hp if (you.confused() or you.poison_survival() <= 0) and quaff("curing") then return true end if species ~= "Vine Stalker" then local multiplier = species == "Deep Dwarf" and 3 or 4 if multiplier*hp < hpmax then if quaff("heal wounds") then return true end if self_zap("heal wounds") then return true end if rechargethewand("heal wounds") then return true end end end if you.race() == "Deep Dwarf" then hp = hpmax end local th, allies = threat(targets) th = th - math.floor(you.xl() / 3) local m = nil if besttarget["x"] ~= nil then m = monster.get_monster_at(besttarget["x"], besttarget["y"]) local mp,b = you.mp() if you.god() == "Cheibriados" and you.piety_rank() >= 5 and th >= math.ceil(12 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and mp >= 10 and use_ability("Step from Time", false) then return true end if you.god() == "Lugonu" and you.piety_rank() >= 5 and th >= math.ceil(12 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and mp >= 9 and use_ability("Enter the Abyss", false) then return true end if you.god() == "Lugonu" and you.piety_rank() >= 4 and th >= math.ceil(10 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and mp >= 7 and realhp > 5 and use_ability("Corrupt", false) then return true end if you.god() == "Qazlal" and you.piety_rank() >= 5 and th >= math.ceil(10 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and mp >= 7 and use_ability("Disaster Area", true) then target_square(besttarget["x"], besttarget["y"]) return true end if you.god() == "Cheibriados" and you.piety_rank() >= 4 and th >= math.ceil(8 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and mp >= 5 and use_ability("Slouch") then return true end if th >= math.ceil(8 * hp / hpmax) and not you.berserk() and not you.confused() and you.hunger() > 0 and not you.breath_timeout() and use_ability("Breathe Lightning") then return true end if you.god() == "Lugonu" and you.piety_rank() >= 3 and th >= math.ceil(5 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and m:threat() >= 3 and mp >= 4 and use_ability("Banish", true) then target_square(besttarget["x"], besttarget["y"]) return true end if you.god() == "Trog" and you.piety_rank() >= 4 and th >= math.ceil(10 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and (allies < 1 or (th >= math.ceil(12 * hp / hpmax) and allies < 2)) and use_ability("Brothers in Arms", false) then return true end if you.god() == "Makhleb" and you.piety_rank() >= 5 and th >= math.ceil(10 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and realhp > 10 and allies < 1 and use_ability("Greater Servant of Makhleb", false) then return true end if math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) > 3 and you.god() == "Makhleb" and you.piety_rank() >= 4 and th >= math.ceil(8 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and realhp > 6 and you.hunger() > 0 and use_ability("Major Destruction", true) then target_square(besttarget["x"], besttarget["y"]) return true end if you.god() == "Okawaru" and you.piety_rank() >= 5 and th >= math.ceil(10 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and you.turns() - finesse_time > 100 and use_ability("Finesse", false) then finesse_time = you.turns() return true end if you.god() == "Trog" and you.piety_rank() >= 2 and ((you.race() == "Deep Dwarf" and 2*realhp <= hpmax and th >= math.ceil(4 * hp / hpmax)) or (th >= math.ceil(8 * hp / hpmax))) and not you.berserk() and not you.confused() and not you.silenced() and not you.regenerating() and you.hunger() > 0 and use_ability("Trog's Hand", false) then return true end if you.god() == "Makhleb" and you.piety_rank() >= 3 and th >= math.ceil(6 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and realhp > 4 and allies < 1 and use_ability("Lesser Servant of Makhleb", false) then return true end if math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) > 3 and you.god() == "Qazlal" and you.piety_rank() >= 2 and th >= math.ceil(6 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and mp >= 4 and use_ability("Upheaval", true) then target_square(besttarget["x"], besttarget["y"]) return true end if math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) < 3 and you.god() == "Okawaru" and you.piety_rank() >= 1 and th >= math.ceil(5 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and you.turns() - heroism_time > 100 and use_ability("Heroism", false) then heroism_time = you.turns() return true end if math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) < 3 and ((you.god() == "Trog" and you.piety_rank() >= 1) or have_ability("Evoke Berserk Rage") or have_potion("berserk rage")) and you.god() ~= "Cheibriados" and not you.berserk() and not you.exhausted() and not you.confused() and th >= math.ceil(5 * hp / hpmax) then if you.hunger() <= 3 then if check_eat(true) then return true end elseif (you.god() == "Trog" and use_ability("Berserk", false)) or use_ability("Evoke Berserk Rage") or quaff("berserk rage") then flee_count = 0 kiting = false return true end end if math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) < 3 and have_potion("might") and not you.berserk() and not you.exhausted() and not you.confused() and not you.mighty() and th >= math.ceil(5 * hp / hpmax) and quaff("might") then return true end if you.where():match("Abyss") and you.god() == "Lugonu" and you.piety_rank() >= 1 and not you.berserk() and not you.confused() and not you.silenced() and mp >= 1 and th >= math.ceil(5 * hp / hpmax) and use_ability("Depart the Abyss") then return true end if math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) > 3 and you.god() == "Makhleb" and you.piety_rank() >= 2 and th >= math.ceil(4 * hp / hpmax) and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and realhp > 1 and use_ability("Minor Destruction", true) then target_square(besttarget["x"], besttarget["y"]) return true end if m and m:threat() >= 2 and you.hunger() > 0 and not you.breath_timeout() and breathe_at(besttarget["x"], besttarget["y"]) then return true end if you.god() == "Cheibriados" and you.hunger() > 0 and not you.berserk() and not you.confused() and not you.silenced() and mp >= 3 and th >= math.ceil(4 * hp / hpmax) and you.turns() - bend_time_time >= 10 and besttarget["x"] ~= nil and math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) <= 1 and use_ability("Bend Time") then bend_time_time = you.turns() return true end if you.god() == "Cheibriados" and you.piety_rank() >= 3 and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and mp >= 4 and ranged and th >= math.ceil(4 * hp / hpmax) and besttarget["x"] ~= nil and math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) > 1 and use_ability("Temporal Distortion") then bend_time_time = you.turns() return true end end local div = 1 local mp,b = you.mp() if you.exhausted() then div = div * 2 end if you.slowed() then div = div * 2 end local th5 = (th >= math.ceil(7 * hp / hpmax) / div) local fast_race = (slow or species == "Spriggan" or species == "Centaur") and you.god() ~= "Cheibriados" if th5 and not you.teleporting() then if read_scroll("teleportation") then return true end if self_zap("teleportation") then return true end end if ((th5 and ((not fast_race) or math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) <= 2)) or (fast_race and besttarget["x"] ~= nil and math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) <= 1 and (items.fired_item() or has_polearm()) and m and m:name() ~= "bat")) and not you.berserk() and not ranged and not polearm and (fast_race or not fast) then if th5 and you.god() == "Lugonu" and you.piety_rank() >= 3 and not you.berserk() and not you.confused() and not you.silenced() and you.hunger() > 0 and m and math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) >= 2 and m:threat() >= 3 and mp >= 4 and use_ability("Banish", true) then target_square(besttarget["x"], besttarget["y"]) return true end if th5 and you.god() == "Lugonu" and you.piety_rank() >= 2 and mp >= 1 and you.turns() - blink_time >= 10 and besttarget["x"] ~= nil and math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) <= 1 and realhp > 4 and use_ability("Bend Space") then blink_time = you.turns() return true end if th5 and you.turns() - blink_time >= 10 and besttarget["x"] ~= nil and math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) <= 1 and use_ability("Evoke Blink") then blink_time = you.turns() return true end if th5 and ((not fast_race) or math.max(math.abs(besttarget["x"]), math.abs(besttarget["y"])) <= 2) then crawl.mpr("FLEEEEING!") flee_count = th5 and 5 * th or 1 kiting = false else crawl.mpr("KIIIITING") flee_count = 1 kiting = true end local bestsquare, targets, besttarget, ranged, polearm, fast, slow = evaluate_squares() local bl = have_scroll("blinking") if not kiting and bl and not you.berserk() and not you.confused() and not you.silenced() and math.max(math.abs(bestsquare["x"]), math.abs(bestsquare["y"])) >= 5 then crawl.sendkeys("r" .. bl) target_square(bestsquare["x"], bestsquare["y"]) return true end return move_to_goodpos(bestsquare, targets) end return false end -- mostly borrowed from xw function have_chunks() for it in inventory() do if it and string.find(it.name(),"chunk") and not food.dangerous(it) and not food.rotting(it) then return true end end return false end function eat_permafood() for it in inventory() do if it and not string.find(it.name(),"potion") and food.can_eat(it) then if food.eat(it) then sendkeys(esc) return true end end end return false end function count_corpses() local fl = you.floor_items() local count = 0 for it in iter.invent_iterator:new(fl) do if string.find(it.name(),"corpse") then count = count + 1 end end return count end function check_eat(in_combat) -- 4 == HS_SATIATED if you.hunger() < 4 and species ~= "Spriggan" then if have_chunks() then sendkeys("ee") return true end local corpse_count = count_corpses() if corpse_count > 0 then if corpse_count > 1 then sendkeys("ccq") else sendkeys("cc") end return true end if not in_combat and not finding_food then if search_for("@corpse$&&!!rott&&!!skel") then return true end end end if you.hunger() == 0 then return eat_permafood() end return false end function check_rest() local hp, hpmax = you.hp() if you.berserk() or you.confused() or you.exhausted() or (species ~= "Deep Dwarf" and (hp < hpmax or you.poisoned())) or you.transform() == "tree" or you.transform() == "fungus" then processkeys("5") return true end return false end function count_neighbours(x, y) local count = 0 for dx = x-1,x+1 do for dy = y-1,y+1 do if math.abs(dx) <= 8 and math.abs(dy) <= 8 and view.is_safe_square(dx, dy) then if dx ~= x or dy ~= y then count = count + 1 end end end end return count end function feat_is_escape_stair(x, y) if not you.see_cell_no_trans(x,y) then return false end local feat = view.feature_at(x, y) return feat:find("_up") and not feat:find("sealed") or feat:find("exit_") and you.where() ~= "D:1" end function evaluate_squares() local targets = {} local bestsquare = {x = nil, y = nil} local besttarget = {x = nil, y = nil} local bestdist = 999 local bestneighbours = count_neighbours(0, 0) local curneighbours = 1 local have_stair = false local stairdist = 999 local mondist = 0 local curmondist = 1 local ranged = false local polearm = false local fast = species == "Naga" or you.god() == "Cheibriados" local slow = true if bestneighbours < 2 then bestneighbours = 999 else bestsquare["x"] = 0 bestsquare["y"] = 0 end local x, y for x = -8,8 do for y = -8,8 do local dist = math.max(math.abs(x), math.abs(y)) local m = monster.get_monster_at(x, y) if m then if (force_fight and (m:name():find("ballistomycete") or m:name():find("wandering mushroom") ) ) or (not m:is_safe() and not m:is_firewood()) then targets[#targets + 1] = {x = x, y = y} if m:attitude() == 0 then if dist < bestdist then besttarget["x"] = x besttarget["y"] = y bestdist = dist end ranged = ranged or m:has_known_ranged_attack() polearm = polearm or m:reach_range() > 2 -- TODO: moninf speed fast = fast or m:name():find("adder") or m:name():find("worker ant") or m:name():find("hound") or m:name():find("wolf") or m:name():find("water moccasin") slow = slow and (m:name():find("worm") or m:name():find("beetle")) end end end end end for x = -8,8 do for y = -8,8 do local dist = math.max(math.abs(x), math.abs(y)) local m = monster.get_monster_at(x, y) if not m and view.is_safe_square(x, y) and you.see_cell_no_trans(x,y) then if flee_count > 0 then if feat_is_escape_stair(x, y) and not kiting then have_stair = true if dist < stairdist then stairdist = dist bestsquare["x"] = x bestsquare["y"] = y end elseif kiting or not have_stair then local otherdist = dist if besttarget["x"] ~= nil then otherdist = math.max(math.abs(x - besttarget["x"]), math.abs(y - besttarget["y"])) end if otherdist > mondist then mondist = otherdist curmondist = 1 bestsquare["x"] = x bestsquare["y"] = y elseif otherdist == mondist then curmondist = curmondist + 1 if crawl.random2(curmondist) then bestsquare["x"] = x bestsquare["y"] = y end end end elseif bestneighbours ~= 2 then local count = count_neighbours(x, y) if count >= 2 and count <= bestneighbours then if count < bestneighbours then curneighbours = 1 bestneighbours = count bestsquare["x"] = x bestsquare["y"] = y elseif count == bestneighbours then curneighbours = curneighbours + 1 if bestsquare["x"] ~= 0 and bestsquare["y"] ~= 0 and not crawl.random2(curneighbours) then bestsquare["x"] = x bestsquare["y"] = y end end end end end end end return bestsquare, targets, besttarget, ranged, polearm, fast, slow end function check_monster_count() local x, y for x = -8,8 do for y = -8,8 do local m = monster.get_monster_at(x, y) if m and (m:name():find("ballistomycete") or m:name():find("wandering mushroom")) then force_fight = true return end end end force_fight = false end function delta_to_vi(x, y) local d2v = { [-1] = { [-1] = 'y', [0] = 'h', [1] = 'b'}, [0] = { [-1] = 'k', [1] = 'j'}, [1] = { [-1] = 'u', [0] = 'l', [1] = 'n'}, } return d2v[x][y] end function delta_to_dir(x, y, mon) if x == nil or (x == 0 and y == 0) then return nil end local alt1 = { [-1] = { [-1] = { -1, 0}, [0] = { -1, -1}, [1] = { -1, 0} }, [0] = { [-1] = { -1, -1}, [1] = { -1, 1} }, [1] = { [-1] = { 1, 0}, [0] = { 1, -1}, [1] = { 1, 0} }, } local alt2 = { [-1] = { [-1] = { 0, -1}, [0] = { -1, 1}, [1] = { 0, 1} }, [0] = { [-1] = { 1, -1}, [1] = { 1, 1} }, [1] = { [-1] = { 0, -1}, [0] = { 1, 1}, [1] = { 0, 1} }, } if mon and monster.get_monster_at(x, y) or view.is_safe_square(x, y) and (mon or not monster.get_monster_at(x, y)) then return delta_to_vi(x, y), x, y end local x1, x2, y1, y2 if crawl.coinflip() then x1 = alt1[x][y][1] y1 = alt1[x][y][2] x2 = alt2[x][y][1] y2 = alt2[x][y][2] else x1 = alt2[x][y][1] y1 = alt2[x][y][2] x2 = alt1[x][y][1] y2 = alt1[x][y][2] end if mon and monster.get_monster_at(x1, y1) or view.is_safe_square(x1, y1) and (mon or not monster.get_monster_at(x1, y1)) then return delta_to_vi(x1, y1), x1, y1 end if mon and monster.get_monster_at(x2, y2) or view.is_safe_square(x2, y2) and (mon or not monster.get_monster_at(x2, y2)) then return delta_to_vi(x2, y2), x2, y2 end return nil end function normalise_delta(x, y) local dx = 0 local dy = 0 if x > 0 then dx = 1 end if y > 0 then dy = 1 end if x < 0 then dx = -1 end if y < 0 then dy = -1 end if math.abs(y) >= 2*math.abs(x) then dx = 0 end if math.abs(x) >= 2*math.abs(y) then dy = 0 end return dx, dy end function should_move(ranged, x, y) return (ranged or you.berserk() or (x ~= nil and view.feature_at(x, y):find("door")) or force_fight) and you.transform() ~= "tree" and you.transform() ~= "fungus" end function move_to_goodpos(bestsquare, targets) if flee_count <= 0 and (attack_moving or (#targets == 1 and not invisible_enemy) or should_move(false, nil, nil)) or you.transform() == "tree" or you.transform() == "fungus" then return false end if not bestsquare["x"] and not bestposx then return false end local bestx = bestposx local besty = bestposy if bestx == nil or (bestx == 0 and besty == 0) then bestx = bestsquare["x"] besty = bestsquare["y"] end if bestx == 0 and besty == 0 then bestposx = nil bestposy = nil if flee_count > 0 then flee_count = 0 if feat_is_escape_stair(0, 0) and not kiting then fled_level = true just_fled = true fled_branch = you.branch() sendkeys("<") crawl.flush_input() return true end end return false end bestposx = bestx bestposy = besty local x, y = normalise_delta(bestx, besty) local dir,actualx,actualy = delta_to_dir(x, y, false) if dir then if flee_count > 0 then flee_count = flee_count - 1 end bestposx = bestposx - actualx bestposy = bestposy - actualy crawl.mpr("MOVING TO (" .. bestx .. "," .. besty .. ")") processkeys(dir) return true end bestposx = nil bestposy = nil return false end function ranged_attack(x, y, m) if not x or (math.abs(x) <= 1 and math.abs(y) <= 1) then return false end if not you.see_cell_no_trans(x, y) then return false end local have_something = false if m and m:threat() >= 3 then local wand = have_wand("cold") if not wand then wand = have_wand("fire") end if not wand then wand = have_wand("fireball") end if not wand then wand = have_wand("disint") end if not wand then wand = have_wand("lightning") end if not wand then wand = have_wand("draining") end if not wand then wand = have_wand("frost") end if not wand then wand = have_wand("flame") end if not wand then wand = have_wand("magic dart") end if wand then have_something = true crawl.sendkeys("V" .. wand .. "r") end end if not have_something and m and m:threat() >= 2 and you.hunger() > 0 and not you.breath_timeout() and breathe_at(x, y) then return true end if not have_something and (math.abs(x) <= 2 and math.abs(y) <= 2) and has_polearm() then have_something = true local weap = items.equipped_at("Weapon") local letter = items.index_to_letter(weap.slot) crawl.sendkeys("V" .. letter .. "r") end if not have_something then local it = items.fired_item() if it then have_something = true crawl.sendkeys("fr") end end if not have_something and you.god() == "Makhleb" and you.piety_rank() >= 2 and you.hunger() > 0 then local hp, hpmax = you.hp() have_something = hp > 1 and use_ability("Minor Destruction", true) end if not have_something then return false end target_square(x, y) return true end function fight() local bestsquare, targets, besttarget, ranged, polearm, fast, slow = evaluate_squares() attack_moving = ranged or polearm if move_to_goodpos(bestsquare, targets) then return true end local x = 0 local y = 0 local rangedx = nil local rangedy = nil if not besttarget["x"] then if hit_something then x = lastx y = lasty else while (x == 0 and y == 0) or not view.is_safe_square(x, y) do x = -1 + crawl.random2(3) y = -1 + crawl.random2(3) end end else rangedx = besttarget["x"] rangedy = besttarget["y"] x, y = normalise_delta(rangedx, rangedy) end lastx = x lasty = y if check_emergency(besttarget, targets, ranged, polearm, fast, slow) then return true end local dir,actualx,actualy = delta_to_dir(x, y, true) local m = rangedx and monster.get_monster_at(rangedx, rangedy) or nil if dir then if should_move(ranged or polearm, actualx, actualy) then crawl.mpr("ATTACK MOVE TO (" .. x .. "," .. y .. ")") if bestposx ~= nil then bestposx = bestposx - actualx end if bestposy ~= nil then bestposy = bestposy - actualy end crawl.sendkeys(dir) sendkeys(esc) else if m and ranged_attack(rangedx, rangedy, m) then crawl.mpr("RANGED ATTACK TO (" .. x .. "," .. y .. ")") return true else crawl.mpr("ATTACKING (" .. x .. "," .. y .. ")") crawl.sendkeys("*" .. dir) sendkeys(esc) end end return true end if m and ranged_attack(rangedx, rangedy, m) then return true end crawl.mpr("help") stuck = true return false end function identify_items() for it in inventory() do if it and not it.fully_identified then local letter = items.index_to_letter(it.slot) if string.find(it.name(), "scroll") and not you.silenced() then crawl.mpr("READING") local targlet = "a" local targ = items.equipped_at("Weapon") if not targ then targ = items.equipped_at("Armour") end if targ then targlet = items.index_to_letter(targ.slot) end local stuff = targlet .. esc .. 'YYY' .. esc .. 'YYY' sendkeys("r" .. letter .. stuff) return true elseif string.find(it.name(), "potion") then crawl.mpr("QUAFFING") sendkeys("q" .. letter) return true elseif string.match(it.name(), " wand$") then crawl.mpr("ZAPPING") sendkeys("V" .. letter .. "h.") return true end end end return false end -- Most of this item weighting code is from qw. -- no need to apologize for stealing code from qw :P good_slots = {cloak="Cloak", helmet="Helmet", gloves="Gloves", boots="Boots", body="Armour"} function armour_value(it, name, with_resists) local value = 100 if it.is_useless then return -1 end if it.artefact then if it.fully_identified then value = value + 100 -- random stuff is good on average else value = value + 400 -- it might be very good end if name:find("rF%+") then if not with_resists or you.res_fire() < 2 then value = value + 400 -- we like this a lot end end if name:find("SInv") then if not with_resists or not you.see_invisible() then value = value + 400 -- we like this a lot end end if name:find("rPois") then if not with_resists or you.res_poison() <= 0 then value = value + 250 -- we like this end end if name:find("%-Tele") then return -1 end if name:find("Pondering") or name:find("hauberk") or name:find("lightning scales") then return -1 end elseif name:find("runed") or name:find("glowing") or name:find("dyed") or name:find("embroidered") or name:find("shiny") then value = value + 400 -- it might be very good elseif it.fully_identified then if name:find("fire resistance") then if not with_resists or you.res_fire() < 2 then value = value + 400 -- we like this a lot end end if name:find("see invisible") then if not with_resists or not you.see_invisible() then value = value + 400 -- we like this a lot end end if name:find("preservation") then value = value + 250 -- and this end if name:find("poison resistance") then if not with_resists or you.res_poison() <= 0 then value = value + 250 -- we like this end end if name:find("ponderous") then return -1 end if name:find("archery") then value = value - 100 end end if it.plus then value = value + 50*it.plus end if name:find("centaur barding") and species ~= "Centaur" then return -1 end if name:find("naga barding") and species ~= "Naga" then return -1 end st, _ = it.subtype() if good_slots[st] == "Helmet" and not name:find("helmet") then value = value - 100 end if good_slots[st] == "Armour" then if name:find("hide") then if name:find("dragon") then value = value - 200 else return -1 end end if name:find("robe") then value = value + 200 elseif name:find("animal skin") then value = value + 200 elseif name:find("troll leather") then value = value + 400 elseif name:find("leather") then value = value + 300 elseif name:find("ring mail") then value = value + 500 elseif name:find("scale mail") then if dodging then return -1 end value = value + 600 elseif name:find("chain mail") then if dodging then return -1 end value = value + 800 elseif name:find("crystal plate") then if dodging then return -1 end value = value + 1400 elseif name:find("plate") then if dodging then return -1 end value = value + 1000 elseif name:find("storm dragon") then if dodging then return -1 end value = value + 1000 elseif name:find("steam dragon") then value = value + (dodging and 800 or 500) elseif name:find("mottled dragon") then value = value + (dodging and 800 or 500) elseif name:find("swamp dragon") then if dodging then return -1 end value = value + 700 elseif name:find("fire dragon") then if dodging then return -1 end value = value + 800 elseif name:find("ice dragon") then if dodging then return -1 end value = value + 600 -- less because rF- elseif name:find("pearl dragon") then if dodging then return -1 end value = value + 1000 elseif name:find("gold dragon") then if dodging then return -1 end value = value + 1400 -- more because resists end end return value end function weapon_value(it, name, with_resists) if species == "Troll" or species == "Felid" or class == "Monk" then return -1 end local value = 1000 if (weaponskill == "Maces & Flails" and not name:find("mace") and not name:find("flail") and not name:find("whip") and not name:find("ingstar") and (species ~= "Ogre" or (not name:find("giant club") and not name:find("giant spiked club")))) or (weaponskill == "Short Blades" and not name:find("dagger") and not name:find("short sword") and not name:find("cutlass") and not name:find("quick blade")) or (weaponskill == "Long Blades" and not name:find("falchion") and not name:find("long sword") and not name:find("scimitar") and not name:find("demon blade") and not name:find("bastard sword") and not name:find("great sword") and not name:find("claymore")) or (weaponskill == "Polearms" and not name:find("spear") and not name:find("trident") and not name:find("halberd") and not name:find("glaive") and not name:find("bardiche")) or (weaponskill == "Axes" and not name:find("axe")) or (weaponskill == "Staves" and not name:find("quarterstaff") and not name:find("lajatang")) then return -1 end if name:find("distort") and you.god() ~= "Lugonu" then return -1 end if name:find("%-Tele") then return -1 end if it.artefact and not it.fully_identified or name:find("runed") or name:find("glowing") then value = value + 500 -- it might be very good end if name:find("vamp") then value = value + 500 -- this is what we want elseif name:find("speed") then value = value + 300 -- this is good too elseif name:find("elec") then value = value + 150 -- not bad elseif name:find("flam") or name:find("freez") or name:find("chop") or name:find("anti") then value = value + 75 end if it.plus then value = value + 10*it.plus end if it.plus2 then value = value + 20*it.plus2 end if name:find("hand axe") then value = value + 700 elseif name:find("war axe") then value = value + 1000 elseif name:find("broad axe") then value = value + 1300 elseif name:find("battleaxe") then value = value + 1600 elseif name:find("executioner") then value = value + 1550 -- requires too much skill end if name:find("whip") then value = value + 500 elseif name:find("mace") then value = value + 700 elseif name:find("flail") then value = value + 1000 elseif name:find("morningstar") then value = value + 1300 elseif name:find("eveningstar") then value = value + 1600 elseif name:find("dire flail") then value = value + 1500 elseif name:find("demon whip") then value = value + 1600 elseif name:find("great mace") then value = value + 1700 elseif name:find("giant club") and (species == "Ogre" or species == "Troll") then value = value + 2500 elseif name:find("giant spiked club") and (species == "Ogre" or species == "Troll") then value = value + 3500 end if name:find("quick blade") then value = value + 3500 elseif name:find("cutlass") then value = value + 2500 elseif name:find("short sword") then value = value + 500 elseif name:find("dagger") then value = value + 1000 end if name:find("falchion") then value = value + 700 elseif name:find("long sword") then value = value + 1000 elseif name:find("scimitar") then value = value + 1300 elseif name:find("bastard sword") or name:find("demon blade") then value = value + 1600 elseif name:find("great sword") then value = value + 1600 elseif name:find("claymore") then value = value + 1550 end if name:find("spear") then value = value + 400 elseif name:find("demon trident") then value = value + 1300 elseif name:find("trident") then value = value + 700 elseif name:find("halberd") then value = value + 1000 elseif name:find("glaive") then value = value + 1600 elseif name:find("bardiche") then value = value + 1550 -- requires too much skill end if name:find("quarterstaff") then value = value + 500 elseif name:find("lajatang") then value = value + 1000 end return value end function amulet_value(it, name, with_resists) if it.artefact then return -1 end -- should parse inscription instead if not name:find("amulet of") then return 100 end if name:find("stasis") then return -1 end if name:find("resist corrosion") then if with_resists and you.res_corr() then return -1 else return 8 end end if name:find("faith") then return 101 end if name:find("resist mutation") then return 7 end if name:find("clarity") then return 6 end if name:find("guardian spirit") then if species == "Deep Dwarf" then return -1 end return 5 -- not enough MP end if name:find("warding") then return 4 end if name:find("rage") then return 3 end return -1 end function ring_value(it, name, with_resists) if it.artefact then return -1 end -- should parse inscription instead if not name:find("ring of") then return 100 end if it.plus and it.plus < 0 then return -1 end if it.plus2 and it.plus2 < 0 then return -1 end local plus = 0 if it.plus then plus = plus + it.plus end if it.plus2 then plus = (plus + 2*it.plus2)/3 end if not it.fully_identified then plus = 6 end if name:find("see invisible") then if with_resists and you.see_invisible() then return -1 else return 50 end end if name:find("protection from fire") then if with_resists and you.res_fire() >= 2 then return 16 else return 49 end end if name:find("protection from cold") then if with_resists and you.res_cold() >= 1 then return 15 else return 48 end end if name:find("slaying") then return 20 + plus end if name:find("protection from magic") then return 14 end if name:find("protection") then return 19 + plus end if name:find("evasion") then return 18 + plus end if name:find("positive energy") then return 13 end if name:find("regeneration") then return 12 end if name:find("strength") then return 7 + plus end if name:find("dexterity") then return 4 + plus end if name:find("sustenance") then return 3 end if name:find("sustain abilities") then return 2 end return -1 end function equip_value(it, name, with_resists) local class = it.class(true) if class == "armour" then return armour_value(it, name, with_resists) elseif class == "weapon" then return weapon_value(it, name, with_resists) elseif class == "jewellery" then if name:find("amulet") then return amulet_value(it, name, with_resists) else return ring_value(it, name, with_resists) end end return -1 end function autopickup(it, name) if name:find("of Zot") then return true end if name:find("dart") or name:find("stone") or name:find("tomahawk") or name:find("javelin") or (name:find("large rock") and (species == "Ogre" or species == "Troll")) then return true end if it.is_useless then return false end local class = it.class(true) old_value = 0 new_value = 0 ring = false if class == "armour" then st, _ = it.subtype() if good_slots[st] == nil then return false end it2 = items.equipped_at(good_slots[st]) elseif class == "weapon" then it2 = items.equipped_at("Weapon") elseif class == "jewellery" then if name:find("amulet") then it2 = items.equipped_at("Amulet") else it2 = items.equipped_at("Left Ring") it3 = items.equipped_at("Right Ring") ring = true end else return false end new_value = equip_value(it, name) if new_value < 0 then return false end if it2 == nil or ring and it3 == nil then return true else old_value = equip_value(it2, it2:name()) if ring then old_value2 = equip_value(it3, it3:name()) if old_value > old_value2 then old_value = old_value2 end end return (new_value > old_value) end end add_autopickup_func(autopickup) function check_equip() local shield = items.equipped_at("Shield") if shield then sendkeys("d" .. items.index_to_letter(shield.slot) .. "\r") return true end local weap = items.equipped_at("Weapon") local weap_val = weap and equip_value(weap, weap:name()) or -1 for it in inventory() do if it then local equip = false local drop = false local val = equip_value(it, it:name()) local l = items.index_to_letter(it.slot) local equip_key = "" local followup = "" local target = nil if it.is_useless and not it:name():match("wand of heal wounds") and not it:name():match("wand of teleportation") then drop = true elseif it.class(true) == "weapon" then if val < 0 and not it.equipped then drop = true elseif not weap or val > weap_val then target = weap equip = true equip_key = 'w' followup = 'Y' elseif not it.equipped then drop = true end elseif it.class(true) == "armour" then local sub, _ = it.subtype() local it_old = items.equipped_at(good_slots[sub]) local old_val = it_old and equip_value(it_old, it_old:name()) or -1 if val < 0 then drop = true elseif not it_old or val > old_val then target = it_old equip = true equip_key = 'W' elseif not it.equipped then drop = true end elseif it.class(true) == "jewellery" then if string.find(it:name(), "amulet") then local it_old = items.equipped_at("Amulet") local old_val = it_old and equip_value(it_old, it_old:name()) or -1 if val < 0 then drop = true elseif not it_old or val > old_val then target = it_old equip = true equip_key = 'P' elseif not it.equipped then drop = true end else local left = items.equipped_at("Left Ring") local right = items.equipped_at("Right Ring") local lval = left and equip_value(left, left:name()) or -1 local rval = right and equip_value(right, right:name()) or -1 if val < 0 then drop = true elseif (not left or not right) and not it.equipped then equip = true equip_key = 'P' elseif lval <= rval and val > lval and not it.equipped then target = left equip = true equip_key = 'P' followup = '<' elseif rval < lval and val > rval and not it.equipped then target = right equip = true equip_key = 'P' followup = '>' elseif not it.equipped then drop = true end end end if equip then if not target or not target.cursed then if string.find(it:name(), "vamp") and you.hunger() < 5 then if eat_permafood() then return true end else crawl.sendkeys(equip_key .. l .. followup .. 'NNN') sendkeys(esc) return true end elseif target and target.cursed then local rc = have_scroll("remove curse") if rc and not you.confused() then crawl.sendkeys("r" .. rc) sendkeys(esc) end end elseif drop and it and (not it.cursed or not it.equipped) then crawl.sendkeys('d' .. l .. "\rNNN") sendkeys(esc) return true end end end return false end function enchant_items() local ew = have_scroll("enchant weapon") local it = nil if ew then it = items.equipped_at("Weapon") if it and not it.artefact then local stuff = items.index_to_letter(it.slot) crawl.sendkeys("r" .. ew .. stuff) sendkeys(esc) return true end end local ea = have_scroll("enchant armour") if ea then for _,sub in pairs(good_slots) do it = items.equipped_at(sub) if it and not it.artefact then if sub == "Armour" and species ~= "Ogre" and species ~= "Troll" then if (it.name():find("crystal plate") and it.plus < 14) or (it.name():find("gold dragon") and it.plus < 12) or ((it.name():find("plate") or it.name():find("pearl dragon")) and not it.name():find("crystal") and it.plus < 10) then local stuff = items.index_to_letter(it.slot) crawl.sendkeys("r" .. ea .. stuff) sendkeys(esc) return true end else if it.plus < 2 then local stuff = items.index_to_letter(it.slot) crawl.sendkeys("r" .. ea .. stuff) sendkeys(esc) return true end end end end if it then end end if species ~= "Vine Stalker" and rechargethewand("heal wounds") then return true end if species ~= "Formicid" and rechargethewand("teleportation") then return true end if species ~= "Formicid" and you.god() ~= "Cheibriados" and rechargethewand("hasting") then return true end return false end function check_abilities() if ((species == "Gargoyle" and you.xl() >= 14) or (species == "Tengu" and you.xl() >= 15)) and not you.flying() then local mp,b = you.mp() if mp >= 3 and not you.rooted() then if use_ability("Fly", false) then return true end end end end function check_messages() local messages = crawl.messages(20) local recent_messages = crawl.messages(5) local really_recent_messages = crawl.messages(1) done_exploring = recent_messages:find("Done exploring") or recent_messages:find("Partly explored") invisible_enemy = not options.autopick_on hit_something = messages:match("You.*something") if invisible_enemy then if hit_something or invis_count <= 0 then invis_count = 100 else invis_count = invis_count - 1 end else invis_count = 0 end if recent_messages:find("surroundings suddenly seem different") or invis_count <= 0 then if invisible_enemy then sendkeys("*A") invisible_enemy = false end end if recent_messages:find("strange disturbance") or recent_messages:find("You're standing in") then stuck = true end if messages:find("Sorry, I don't") or messages:find("Sorry, you can't") or messages:find("travel-excluded area") then if unexcluded then stuck = true else unexcluded = true sendkeys("X*e" .. esc) crawl.flush_input() crawl.flush_prev_message() end end if not you.feel_safe() then force_fight = false end if recent_messages:find("pager goes off") and not responding_to_message then crawl.setopt("clear_messages = false") responding_to_message = true crawl.sendkeys("_") crawl.flush_input() crawl.flush_prev_message() crawl.redraw_screen() end if recent_messages:find("climb downwards") or recent_messages:find("go down through the gate") then fled_level = false done_exploring = false end if recent_messages:find("You're already here") then travelling = false end end function respond_to_message() response_turns = you.turns() local response = crawl.random2(3) crawl.sendkeys(":") if response == 0 then crawl.sendkeys("gw-responses activated") elseif response == 1 then crawl.sendkeys("Shh! I'm trying to concentrate.") else crawl.sendkeys("Let me focus here...") end sendkeys("\r" .. esc) crawl.redraw_screen() crawl.delay(1500) crawl.setopt("clear_messages = true") responding_to_message = false sendkeys(esc) end function random_move() local x = 0 local y = 0 local tries = 100 while tries > 0 and ((x == 0 and y == 0) or not view.is_safe_square(x, y)) do x = -1 + crawl.random2(3) y = -1 + crawl.random2(3) tries = tries - 1 end if tries == 0 then crawl.mpr("Stuck??? press s") sendkeys("s") else crawl.mpr("Making a random move") if bestposx ~= nil then bestposx = bestposx - x end if bestposy ~= nil then bestposy = bestposy - y end sendkeys(delta_to_vi(x, y)) end end local travel_order = { { branch = "D", start = "D:1", dest = "D:11", cmd = "GD1\r" }, { branch = "Lair", start = "Lair:1", dest = "Lair:8", cmd = "GL1\r" }, { branch = "D", start = "D:12", dest = "D:12", cmd = "GD12\r" }, { branch = "Orc", start = "Orc:1", dest = "Orc:4", cmd = "GO1\r" }, { branch = "D", start = "D:13", dest = "D:15", cmd = "GD13\r" }, { branch = "Swamp", start = "Swamp:1", dest = "Swamp:5", cmd = "GS1\r" }, { branch = "Snake", start = "Snake:1", dest = "Snake:5", cmd = "GP1\r" }, { branch = "Spider", start = "Spider:1", dest = "Spider:5", cmd = "GN1\r" }, { branch = "Vaults", start = "Vaults:1", dest = "Vaults:4", cmd = "GV1\r" }, { branch = "Shoals", start = "Shoals:1", dest = "Shoals:5", cmd = "GA1\r" }, { branch = "Depths", start = "Depths:1", dest = "Depths:5", cmd = "GU1\r" }, { branch = "Vaults", start = "Vaults:5", dest = "Vaults:5", cmd = "GV5\r" }, { branch = "Zot", start = "Zot:1", dest = "Zot:5", cmd = "GZ1\r" }, { branch = "D", start = "D:1", dest = "D:1", cmd = "GD1\r" } } local curtravel = 1 function feat_in_view(feat) for x = -8,8 do for y = -8,8 do if you.see_cell_no_trans(x,y) then local feat_at = view.feature_at(x,y) if feat_at and feat_at:find(feat) then return x,y end end end end return nil,nil end function do_travel() stuck = false if you.where() == "Ossuary" or you.where() == "Sewer" or you.where() == "Volcano" or you.where() == "IceCv" then if view.feature_at(0, 0):find("exit_") then do_dump = true sendkeys("<") else sendkeys("X<.") end return end if travelling then if you.where() == travel_order[curtravel].start then travelling = false else crawl.sendkeys(travel_order[curtravel].cmd) end end if not travelling then if you.have_orb() then if view.feature_at(0, 0):find("exit_dungeon") then crawl.sendkeys("<" .. esc .. esc .. esc .. esc .. esc .. esc) -- yay! else do_dump = true sendkeys("X<.") end elseif fled_level then if you.branch() ~= fled_branch then travelling = true crawl.sendkeys(travel_order[curtravel].cmd) else sendkeys("G>" .. esc) end elseif you.where() == travel_order[curtravel].dest then travelling = true repeat curtravel = curtravel + 1 until travel_order[curtravel].branch == "D" or travel.find_deepest_explored(travel_order[curtravel].branch) > 0 sendkeys(travel_order[curtravel].cmd) elseif you.where() == "Temple" then do_dump = true sendkeys("G<" .. esc) else do_dump = true sendkeys("G>" .. esc) end end crawl.flush_input() crawl.flush_prev_message() sendkeys(esc) end function abyss_move() if view.feature_at(0,0):find("exit_abyss") then processkeys("<") return end local x,y = feat_in_view("exit_abyss") if x then local dx, dy = normalise_delta(x, y) local dir,actualx,actualy = delta_to_dir(dx, dy, false) if dir then processkeys(dir) return end end if not requivered then sendkeys("Q-") requivered = true return end if requivered then sendkeys("o") requivered = false end end function search_for(what) if you.berserk() or you.confused() or you.transform() == "tree" or you.transform() == "fungus" then return false end if not no_matches[what] then finding_food = true sendkeys("*f" .. what .."\ra\r") crawl.flush_input() crawl.flush_prev_message() local messages = crawl.messages(20) if not messages:find("Can't find any") and not messages:find("Sorry, I don't") and not messages:find("Sorry, you can't") then finding_food = false return true end no_matches[what] = true finding_food = false end return false end function do_move() local x,y if you.god() == "No God" and species ~= "Demigod" then x,y = feat_in_view("altar_" .. god) if x then if x == 0 and y == 0 then if you.silenced() then sendkeys("5") else sendkeys("pYY") end return end local dx, dy = normalise_delta(x, y) local dir,actualx,actualy = delta_to_dir(dx, dy, false) if dir then processkeys(dir) return end end if search_for("altar&&"..god) then return true end if not entered_temple and travel.find_deepest_explored("Temple") > 0 then if you.where() == "Temple" then entered_temple = true elseif not stuck then crawl.sendkeys("GT" .. esc) return end end -- if not entered_temple -- and (you.where() == "D:4" or you.where() == "D:5" -- or you.where() == "D:6" or you.where() == "D:7") then -- local x,y = feat_in_view("enter_temple") -- if x then -- if x == 0 and y == 0 then -- entered_temple = true -- crawl.sendkeys(">" .. esc) -- sendkeys(esc) -- return true -- end -- local dx, dy = normalise_delta(x, y) -- local dir,actualx,actualy = delta_to_dir(dx, dy, false) -- if dir then -- processkeys(dir) -- return -- end -- end -- end end x,y = feat_in_view("enter_sewer") if not x then x,y = feat_in_view("enter_ossuary") end if not x then x,y = feat_in_view("enter_volcano") end if not x then x,y = feat_in_view("enter_ice_cave") end if x then if x == 0 and y == 0 then sendkeys(">") return end local dx, dy = normalise_delta(x, y) local dir,actualx,actualy = delta_to_dir(dx, dy, false) if dir then processkeys(dir) return end end if search_for("glowing drain") then return end if search_for("sand-covered staircase") then return end if search_for("frozen archway") then return end if search_for("dark tunnel") then return end if not requivered then sendkeys("Q-") requivered = true return end if requivered then sendkeys("o") requivered = false no_matches = {} unexcluded = false end end function ready() if pause or hold then return end if crawl.kbhit() then crawl.flush_input() end if finding_food then crawl.flush_input() return end if do_dump then do_dump = false sendkeys("#") return end local invocations = you.god() == "Okawaru" or (you.god() == "Lugonu" and you.skill("Invocations") < 10.5) or you.god() == "Makhleb" or you.god() == "Qazlal" or you.god() == "Cheibriados" local mega_invocations = you.god() == "Qazlal" local skillcap = weaponskill == "Short Blades" and 14 or weaponskill == "Long Blades" and 24 or weaponskill == "Axes" and 26 or weaponskill == "Maces & Flails" and 24 or weaponskill == "Polearms" and 26 or weaponskill == "Staves" and 14 or 27 you.train_skill("Fighting", 1) you.train_skill(weaponskill, (you.skill(weaponskill) >= skillcap) and 0 or (rangedfirst or mega_invocations) and 1 or 2) you.train_skill("Armour", dodging and 0 or 1) you.train_skill("Dodging", dodging and 1 or 0) you.train_skill("Stealth", 0) you.train_skill("Throwing", rangedfirst and 2 or 1) you.train_skill("Spellcasting", 0) you.train_skill("Charms", 0) you.train_skill("Hexes", 0) you.train_skill("Stealth", 0) you.train_skill("Shields", 0) if weaponskill ~= "Short Blades" then you.train_skill("Short Blades", 0) end you.train_skill("Invocations", mega_invocations and 2 or invocations and 1 or 0) stuck = false if responding_to_message then if response_turns ~= you.turns() then respond_to_message() sendkeys(esc) end return end check_messages() if responding_to_message then return end if just_fled then if you.branch() == fled_branch then local feat = view.feature_at(0, 0) if feat:match("stone_st") then travel.set_exclude(0, 0, 0) end end if invisible_enemy then sendkeys("*A") invisible_enemy = false invis_count = 0 end just_fled = false end check_monster_count() if not force_fight and you.feel_safe() and not invisible_enemy then bestposx = nil bestposy = nil attack_moving = false if not check_eat(false) and not check_rest() and not check_equip() and not enchant_items() and not check_abilities() then if you.where():match("Abyss") then abyss_move() elseif you.have_orb() or (done_exploring and not identify_items()) then do_travel() else do_move() end else stuck = false end else stuck = false no_matches = {} unexcluded = false fight() end if stuck then random_move() end crawl.flush_input() if THROTTLE then crawl.delay(THROTTLE_DELAY) end end