Skip to content

Instantly share code, notes, and snippets.

@jmbjr
Last active January 25, 2017 20:44
Show Gist options
  • Save jmbjr/3c0ae5aeeb6706e9297c to your computer and use it in GitHub Desktop.
Save jmbjr/3c0ae5aeeb6706e9297c to your computer and use it in GitHub Desktop.
dungeon crawl stone soup bot by Grunt (http://crawl.berotato.org/crawl/rcfiles/crawl-0.15/gw.rc)
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.
-- <elliptic> 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
@Julix91
Copy link

Julix91 commented Jan 25, 2017

how well did it fare?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment