# Set this to true when playing online.
: DELAYED = true
# Set this to 100 or so when playing online.
: DELAY_TIME = 100
# imposes the delay for Zot:5 at least
: DELAYEDZOT = false
# GrBe with hand axe is classic qw.
species = Te
background = Be
weapon = hand axe
# * don't try to sacrifice plague shambler corpses
# * don't unwield vamp as much
# * do more waiting for monsters to come to melee range, like xw
# - might be able to use the thing that Grunt added to lua recently
# * handle shafting better
# * plan_stuck_clear_exclusions is ugly, so disabled for now
# * should look over the monster lists at some point for good removals
# or regex issues
# * better hydra strats would still be good
# * 8 starvation deaths in Depths (out of 172 games) is weird
# * 16 DT deaths in Depths in those games...
# * 10 to spriggans, 14 to giants
# * failure to swap with BiA is the main reason it gets stuck now
# * doesn't panic soon enough when surrounded?
# * ctrl-f corpses while very hungry after teleport is sort of bad
# * maybe generally be more careful about AF_FIRE/AF_COLD stuff?
# * still slow when tons of monsters/plants are in sight
# * maybe do second lair branch before depths?
# * maybe teleport away if too many summons are in sight (or other conditions,
# like player illusion or triple mara)
# * shoals mesm is scary because no berserk, but it seems to handle it okay
# * also it doesn't list any merfolk on scary_monsters...
# * maybe swap with BiA sometimes, or don't push past it
# * Mara is terrifying
# * tab shouldn't open runed doors
# * be more careful about hitting jellies with good weapons at under +5
# * Joseph more dangerous?
# * evilmike suggested pre-buffing before entering v:5
# * mute more messages (e.g. "Sorry, I don't know how to get there")
# * improve orbrun more - use haste?
# * enter lair immediately instead of waiting until clearing the level?
# known issues:
# major:
# * it doesn't use haste
# * enter ziggurats
# * could use some optimization for non-Gr
# minor:
# * could enter and do labs I guess
# * say more interesting things after pressing _
# * should use holy word, might, cure mut
# * can conceivably get burdened (less likely without hive)
# - qw-nostalgia.rc has something for this
# * can also conceivably run out of slots (less likely)
# * it could try going upstairs and down a different stairs when stuck
# * it likes to leave Depths:5 early before finishing exploring, not sure why
# - I know why now, it happened online on V:4
# * maybe should handle starving status better (eat something)
# * armour upgrading code could be better
# * brand valuation could be improved maybe
# * enchant weapon/brand weapon read-IDing isn't optimal (needs crawl change?)
#####################################
# miscellaneous simple options
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_inventory_weights = true
show_newturn_mark = false
list_rotten = false
force_more_message =
show_travel_trail = false
skill_focus = false
autoinscribe += slaying:mikee
flush.failure = false
char_set = ascii
cset = cloud:xa4
cset_ascii=item_orb:0
use_fake_player_cursor = true
equip_unequip = true
# most of these don't generate normally any more I guess
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,mutations,skills,spells,inventory
dump_order += overview
dump_order += messages,screenshot,monlist,kills,notes,vaults,action_counts
ood_interesting = 6
note_hp_percent = 25
note_skill_levels = 1,3,6,9,12,15,18,21,24,27
note_all_spells = true
####################################
# not sure exactly how important or correct these settings are
explore_stop =
explore_stop += branches,portals,stairs,altars
explore_stop += greedy_visited_item_stack,greedy_pickup_smart
stop := runrest_stop_message
ignore := runrest_ignore_message
stop =
ignore =
ignore += .*
runrest_ignore_poison = 3:15
runrest_ignore_monster += butterfly:1
runrest_ignore_monster += orb of destruction:1
####################################
# These keys are useful to answer prompts and aren't critical for manual play
bindkey = [Y] CMD_NO_CMD_DEFAULT
bindkey = [N] CMD_NO_CMD_DEFAULT
bindkey = [B] CMD_NO_CMD_DEFAULT
bindkey = [.] CMD_NO_CMD_DEFAULT
####################################
# autopickup/drop_filter stuff, just used for scrolls/potions/wands
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 (blinking|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 (blinking|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|berserk rage)
ae += potions? of (flight|invisibility|blood|coagulated blood)
ae += potions? of (agility|cure mutation|might|porridge)
ae += potions? of (confusion|decay|degeneration|mutation|paralysis)
ae += potions? of (poison|lignification|strong poison)
df += potions? of (brilliance|magic|berserk rage)
df += potions? of (flight|invisibility|blood|coagulated blood)
df += potions? of (agility|cure mutation|might|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)
########################################
# now the lua, beginning with autopickup code
{
-- We assign a numerical value to all armour/weapon/jewellery, which
-- is used both for autopickup (so it has to work for unIDed items) and
-- for equipment selection. A negative value means we never want to use the
-- item.
good_slots = {cloak="Cloak", helmet="Helmet",
gloves="Gloves", boots="Boots", body="Armour"}
function armour_value(it, name, with_resists)
local value = 100
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("%-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("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("barding") 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
return -1
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 + 810
elseif name:find("scale mail") then
value = value + 600
elseif name:find("chain mail") then
value = value + 800
elseif name:find("crystal plate") then
value = value + 1499
elseif name:find("plate") then
value = value + 801
elseif name:find("storm dragon") then
value = value + 809
elseif name:find("steam dragon") then
value = value + 1000
elseif name:find("mottled dragon") then
value = value + 1000
elseif name:find("swamp dragon") then
value = value + 1000
elseif name:find("fire dragon") then
value = value + 1500
elseif name:find("ice dragon") then
value = value + 1489 -- less because rF-
elseif name:find("pearl dragon") then
value = value + 1491
elseif name:find("gold dragon") then
value = value + 1490 -- more because resists
end
end
return value
end
function weapon_value(it, name, with_resists)
if you.race() == "Troll" then
return -1
end
local value = 1000
if not name:find("axe") then
return -1
end
if name:find("distort") 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 + 1610 -- requires too much skill
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("conservation") then
if with_resists and you.conservation() then
return -1
else
return 10
end
end
if name:find("resist corrosion") then
if with_resists and you.res_corr() then
return -1
else
return 9
end
end
if name:find("faith") then return 8 end
if name:find("resist mutation") then return 7 end
if name:find("clarity") then return 6 end
if name:find("guardian spirit") then return 5 end -- not enough MP
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 18 + plus end
if name:find("evasion") then return 19 + 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 14 + 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 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)
--------------------------------------------
-- options that we switch on/off with the bot
-- maybe should add more mutes for watchability
function set_options()
--crawl.setopt("auto_list = false")
crawl.setopt("confirm_butcher = always")
crawl.setopt("pickup_mode = multi")
crawl.setopt("message_colour += mute:Search for what")
crawl.setopt("message_colour += mute:Can't find anything")
crawl.setopt("message_colour += mute:Drop what")
crawl.setopt("message_colour += mute:Okay, then")
crawl.setopt("message_colour += mute:Use which ability")
crawl.setopt("message_colour += mute:Read which item")
crawl.setopt("message_colour += mute:Drink which item")
crawl.setopt("message_colour += mute:not good enough")
crawl.setopt("message_colour ^= mute:Unknown command")
end
function unset_options()
--crawl.setopt("auto_list = true")
crawl.setopt("always_confirm_butcher = auto")
crawl.setopt("pickup_mode = auto")
crawl.setopt("message_colour -= mute:Search for what")
crawl.setopt("message_colour -= mute:Can't find anything")
crawl.setopt("message_colour -= mute:Drop what")
crawl.setopt("message_colour -= mute:Okay, then")
crawl.setopt("message_colour -= mute:Use which ability")
crawl.setopt("message_colour -= mute:Read which item")
crawl.setopt("message_colour -= mute:Drink which item")
crawl.setopt("message_colour -= mute:not good enough")
crawl.setopt("message_colour -= mute:Unknown command")
end
-----------------------------------------------
-- now we have actual non-option lua, beginning with some tables
-- branch data: code, full name, where name
local branch_data = {
{"T", "the Ecumenical Temple", "Temple"},
{"O", "the Orcish Mines", "Orc"},
--{"E", "the Elven Halls", "Elf"},
{"L", "the Lair", "Lair"},
{"S", "the Swamp", "Swamp"},
{"A", "the Shoals", "Shoals"},
{"P", "the Snake Pit", "Snake"},
{"N", "the Spider Nest", "Spider"},
--{"M", "the Slime Pits", "Slime"},
{"V", "the Vaults", "Vaults"},
--{"B", "the Hall of Blades", "Blade"},
--{"C", "the Crypt", "Crypt"},
--{"W", "the Tomb", "Tomb"},
{"D", "the Dungeon", "D:"},
{"U", "the Depths", "Depths"},
{"Z", "Zot", "Zot"},
} -- hack
-- portal data: where name, full name, feature name
local portal_data = {
--{"Bailey", "a flagged portal", "bailey"},
--{"Bazaar", "gateway to a bazaar", "bazaar"},
--{"IceCv", "a frozen archway", "ice_cave"},
{"Ossuary", "covered staircase", "ossuary"},
{"Sewer", "a glowing drain", "sewer"},
--{"Volcano", "a dark tunnel", "volcano"},
--{"WizLab", "a magical portal", "wizlab"},
--{"Zig", "gateway to a ziggurat", "ziggurat"},
--{"Lab", "labyrinth entrance", "labyrinth"},
} -- hack
------------------------------------------------------
-- now some tables of monsters, with XL cutoffs
-- berserk these
local scary_monsters = {
{3, "worm"},
{3, "Terence"},
{5, "gnoll"},
{5, "Ijyb"},
{5, "ice beast"},
{5, "iguana"},
{5, "Natasha"},
{7, "orc wizard"},
{7, "Grinder"},
{7, "Prince Ribbit"},
{7, "Dowan"},
{7, "Duvessa"},
{7, "Menkaure"},
{7, "Edmund"},
{7, "Blork"},
{7, "Eustachio"},
{7, "gnoll sergeant"},
{10, "Pikel"},
{10, "Crazy Yiuf"},
{10, "Sigmund"},
{10, "ogre"},
{10, "goliath beetle"},
{12, "orc priest"},
{12, "orc warrior"},
{12, "troll"},
{12, "cyclops"},
{12, "hill giant"},
{12, "spiny frog"},
{12, "black mamba"},
{12, "Snorg"},
{12, "fire drake"},
{12, "Harold"},
{12, "komodo dragon"},
{12, "Gastronok"},
{12, "snapping turtle"},
{12, "Urug"},
{12, "boring beetle"},
{12, "Grum"},
{12, "electric eel"},
{12, "Nergalle"},
{12, "jelly"},
{12, "manticore"},
{12, "guardian mummy"},
{12, "Psyche"},
{13, "blink frog"},
{15, "death yak"},
{15, "Maud"},
{15, "Erica"},
{15, "catoblepas"},
{15, "orc knight"},
{15, "boulder beetle"},
{15, "shark"},
{17, "fire dragon"},
{17, "ice dragon"},
{17, "storm dragon"},
{17, "ogre mage"},
{17, "orc sorcerer"},
{17, "orc high priest"},
{17, "orc warlord"},
{17, "dire elephant"},
{17, "very large slime creature"},
{17, "spiny worm"},
{17, "skeletal warrior"},
{17, "greater naga"},
{17, "naga sharpshooter"},
{17, "Arachne"},
{17, "deep troll"},
{17, "thorn hunter"},
{17, "sun demon"},
{20, "greater naga"},
{20, "naga sharpshooter"},
{20, "Wiglaf"},
{20, "Rupert"},
{20, "Aizul"},
{20, "hydra"},
{20, "Azrael"},
{20, "Frances"},
{20, "Saint Roka"},
{20, "Agnes"},
{20, "Jory"},
{20, "Nikola"},
{20, "stone giant"},
{20, "fire giant"},
{20, "frost giant"},
{20, "acid blob"},
{20, "azure jelly"},
{20, "Asterion"},
{20, "spriggan defender"},
{20, "spriggan air mage"},
{20, "spriggan druid"},
{20, "deep troll shaman"},
{20, "Xtahua"},
{20, "tengu reaver"},
{100, "deep elf annihilator"},
{100, "deep elf sorcerer"},
{100, "Enchantress"},
{100, "Vashnia"},
{100, "Sojobo"},
{100, "berserk"},
{100, "Roxanne"},
{100, "Norris"},
{100, "Erolcha"},
{100, "statue"},
{100, "Nessos"},
{100, "Sonja"},
{100, "Louise"},
{100, "Mennas"},
{100, "Margery"},
{100, "Frederick"},
{100, "Boris"},
{100, "Mara"},
{100, "boggart"},
{100, "lich"},
{100, "'s ghost"},
{100, "' ghost"},
{100, "'s illusion"},
{100, "' illusion"},
{100, "oklob"},
{100, "hellion"},
{100, "tormentor"},
{100, "hell sentinel"},
{100, "fiend"},
{100, "curse toe"},
{100, "curse skull"},
{100, "Tiamat"},
{100, "titanic slime creature"},
{100, "enormous slime creature"},
{100, "titan"},
{100, "orb of fire"},
} -- hack
-- BiA these
local bia_monsters = {
{15, "Rupert"},
{15, "hydra"},
{15, "Azrael"},
{15, "fire dragon"},
{15, "ice dragon"},
{15, "Snorg"},
{15, "death yak"},
{20, "orc warlord"},
{20, "Aizul"},
{20, "Frances"},
{20, "Saint Roka"},
{20, "Agnes"},
{20, "Jory"},
{20, "Norris"},
{20, "Arachne"},
{20, "Nikola"},
{20, "Vashnia"},
{20, "Asterion"},
{20, "orb spider"},
{20, "thorn hunter"},
{20, "sun demon"},
{100, "deep troll shaman"},
{100, "spriggan air mage"},
{100, "Enchantress"},
{100, "Sojobo"},
{100, "Roxanne"},
{100, "Erolcha"},
{100, "statue"},
{100, "Nessos"},
{100, "Sonja"},
{100, "Louise"},
{100, "Mennas"},
{100, "Margery"},
{100, "Frederick"},
{100, "Boris"},
{100, "Mara"},
{100, "boggart"},
{100, "lich"},
{100, "'s ghost"},
{100, "' ghost"},
{100, "oklob"},
{100, "hell sentinel"},
{100, "fiend"},
{100, "Tiamat"},
{100, "orb of fire"},
} -- hack
-- Trog's Hand these
local hand_monsters = {
{10, "Grinder"},
{17, "orc sorcerer"},
{17, "^wizard"},
{100, "ogre mage"},
{100, "Rupert"},
{100, "Aizul"},
{100, "Norris"},
{100, "Erolcha"},
{100, "Louise"},
{100, "lich"},
{100, "Kirke"},
{100, "golden eye"},
{100, "deep elf sorcerer"},
{100, "deep elf demonologist"},
{100, "sphinx"},
{100, "great orb of eyes"},
{100, "vault sentinel"},
{100, "Enchantress"},
{100, "satyr"},
{100, "vampire knight"},
} -- hack
-- potion of resistance these
local resistance_monsters = {
{100, "Margery"},
{100, "orb of fire"},
{100, "hellephant"},
{100, "Xtahua"},
} -- hack
-----------------------------
-- some global variables:
local dump_count = you.turns() + 100 - (you.turns() % 100)
local skill_count = you.turns() - (you.turns() % 100)
local danger
local where = you.where()
local expect_new_location
local expect_portal
local automatic = false
local ignore_list = { }
local failed_move = { }
local invisi_count = 0
local next_delay = 100
local sigmund_dx = 0
local sigmund_dy = 0
local invisi_sigmund = false
local stuck_turns = 0
local stepped_on_lair = false
local kill_plant_mode = false
-- are these still necessary?
local did_move = false
local move_count = 0
local old_turn_count = you.turns()
-- commented out because this messes up loading them from saves
-- local branches_entered
-- local portals_found
local travel_destination = nil
local have_message = false
local read_message = true
local monster_array
local upgrade_phase = false
-- a couple enums from crawl
local ATT_NEUTRAL = 1
local ATT_HOSTILE = 0
---------------------------------------
-- initialization and control
function initialize()
automatic = true
where = you.where()
expect_new_location = false
if branches_entered == nil then
branches_entered = { "D" }
end
if portals_found == nil then
portals_found = { }
end
set_options()
initialize_monster_array()
end
function stop()
automatic = false
unset_options()
crawl.enable_more(true)
end
function start()
initialize()
ready()
end
function panic(msg)
crawl.mpr("" .. msg .. "")
stop()
end
function startstop()
if automatic then
stop()
else
start()
end
end
function hit_closest()
startstop()
end
function ready()
--if you.turns() >= 7463 then stop() return end
if you.turns() >= dump_count then
dump_count = dump_count+100
crawl.dump_char()
end
if you.turns() >= skill_count then
skill_count = skill_count+100
handle_skills()
end
if you.turns() > old_turn_count then
if did_move then
move_count = move_count + 1
else
move_count = 0
end
old_turn_count = you.turns()
did_move = false
end
if you.where() ~= where then
clear_ignores()
where = you.where()
if not expect_new_location then
say("Shafted?")
end
if cur_branch() and not util.contains(branches_entered, cur_branch()) then
say("Entered " .. cur_branch() .. ".")
table.insert(branches_entered, cur_branch())
end
if expect_portal and in_portal() then
say("Entered " .. where .. ".")
end
portals_found = { }
end
expect_new_location = false
expect_portal = false
check_messages()
if automatic then
crawl.flush_input()
crawl.more_autoclear(true)
update_monster_array()
danger = sense_danger(8)
sense_sigmund()
if have_message then
plan_message()
elseif you.where():find("Abyss") then
plan_abyss_move()
elseif you.have_orb() then
plan_orbrun_move()
else
plan_move()
end
end
end
function plan_message()
if read_message then
crawl.setopt("clear_messages = false")
magic("_")
read_message = false
else
crawl.setopt("clear_messages = true")
magic(":qwqwqw\r")
read_message = true
have_message = false
crawl.delay(2500)
end
end
---------------------------------------------
-- general status-checking functions
function hp_is_low(percentage)
local hp, mhp = you.hp()
return (100*hp <= percentage*mhp)
end
function sense_danger(r, no_ignored)
local x,y
for x = -r,r do
for y = -r,r do
if is_candidate_for_attack(x,y,no_ignored) then
return true
end
end
end
return false
end
function sense_sigmund()
local x,y
for x = -8,8 do
for y = -8,8 do
m = monster_array[x][y]
if m and string.find(m:desc(), "Sigmund") then
sigmund_dx = x
sigmund_dy = y
return
end
end
end
end
function initialize_monster_array()
monster_array = {}
local x
for x = -8,8 do
monster_array[x] = {}
end
end
function update_monster_array()
local x,y
for x = -8,8 do
for y = -8,8 do
monster_array[x][y] = monster.get_monster_at(x, y)
end
end
end
function check_monsters(r, mlist)
local x,y
local xl = you.xl()
for x = -r,r do
for y = -r,r do
m = monster_array[x][y]
if m and (m:attitude() == 0) and
not contains_string_in(m:desc(), {"skeleton", "zombie",
"simulacrum", "spectral"}) then
desc = m:desc()
for _, value in ipairs(mlist) do
if xl < value[1] and string.find(desc, value[2]) then
return true
end
end
end
end
end
return false
end
function count_bia(r)
local x, y
local i = 0
for x = -r,r do
for y = -r,r do
m = monster_array[x][y]
if m and m:is_safe() and string.find(m:desc(),"berserk")
and contains_string_in(m:desc(), {"ogre","giant","bear","troll"}) then
i = i+1
end
end
end
return i
end
function on_corpses()
local fl = you.floor_items()
for it in iter.invent_iterator:new(fl) do
if string.find(it.name(), "corpse")
and not string.find(it.name(), "rotting")
and not string.find(it.name(), "plague") then
return true
end
end
return false
end
function on_dangerous_corpse()
local fl = you.floor_items()
for it in iter.invent_iterator:new(fl) do
if string.find(it.name(), "corpse") then
return food.dangerous(it)
end
end
return false
end
function bad_food(it)
return (food.dangerous(it) or string.find(it.name(), "rotting"))
end
function inventory()
return iter.invent_iterator:new(items.inventory())
end
function check_messages()
local recent_messages = crawl.messages(20)
local very_recent_messages = crawl.messages(5)
if very_recent_messages:find("Sigmund flickers and vanishes") then
invisi_sigmund = true
end
if very_recent_messages:find("Your surroundings suddenly seem different")
then
invisi_sigmund = false
end
str1 = "Your pager goes off"
str2 = "qwqwqw"
if recent_messages:find(str1) then
a = recent_messages:reverse():find(str1:reverse())
b = recent_messages:reverse():find(str2:reverse())
if (not b) or a < b then
have_message = true
end
end
if in_portal() then
return false
end
if recent_messages:find("Found") then
for _, value in ipairs(portal_data) do
if recent_messages:find(value[2]) then
record_portal_found(value[1])
end
end
end
end
function in_portal()
for _, value in ipairs(portal_data) do
if value[1] == where then
return true
end
end
return false
end
function record_portal_found(por)
if not util.contains(portals_found, por) then
say("Found " .. por .. ".")
table.insert(portals_found, por)
end
end
function can_swap(equip_slot)
local it = items.equipped_at(equip_slot)
if it and it.cursed then return false end
return true
end
function cur_branch()
for _, value in ipairs(branch_data) do
if where:find(value[3]) then
return value[1]
end
end
end
function found_branch(br)
if br == "D" then
return true
end
for _, value in ipairs(branch_data) do
if value[1] == br then
if travel.find_deepest_explored(value[3]) > 0 then
return true
else
return false
end
end
end
return false
end
function in_branch(br)
for _, value in ipairs(branch_data) do
if value[1] == br then
if where:find(value[3]) then
return true
else
return false
end
end
end
return false
end
function find_item(cls,name)
if cls == "wand" then return find_wand(name) end
for it in inventory() do
if it.class(true) == cls and it.name():find(name) then
return items.index_to_letter(it.slot)
end
end
end
function find_wand(name)
for it in inventory() do
if it.class(true) == "wand" and it.name():find(name) and
not it.name():find("empty") and (it.plus == nil or it.plus > 0) then
return items.index_to_letter(it.slot)
end
end
end
function have_reaching()
local wp = items.equipped_at("weapon")
return wp and wp.reach_range == 8 and not wp.is_melded
end
function monster_in_way(dx,dy)
m = monster_array[dx][dy]
return (m and (m:attitude() <= ATT_NEUTRAL and not kill_plant_mode or
m:is_constricted() or m:is_caught()))
end
function try_move(dx, dy)
if view.is_safe_square(dx, dy) and not view.withheld(dx, dy) and
not monster_in_way(dx,dy) then
return delta_to_vi(dx, dy)
else
return nil
end
end
function tabbable_square(x,y)
if view.feature_at(x,y) ~= "unseen" and view.is_safe_square(x,y) then
local m = monster_array[x][y]
if not m or not m:is_firewood() then
return true
end
end
return false
end
function will_tab(cx, cy, ex, ey)
local dx = ex - cx
local dy = ey - cy
if abs(dx) <= 1 and abs(dy) <= 1 then
return true
end
local function attempt_move(fx, fy)
if fx == 0 and fy == 0 then return end
if abs(cx+fx) > 8 or abs(cy+fy) > 8 then return end
if tabbable_square(cx+fx, cy+fy) then
return will_tab(cx+fx, cy+fy, ex, ey)
end
end
local move = nil
if abs(dx) > abs(dy) then
if abs(dy) == 1 then move = attempt_move(sign(dx), 0) end
if move == nil then move = attempt_move(sign(dx), sign(dy)) end
if move == nil then move = attempt_move(sign(dx), 0) end
if move == nil and abs(dx) > abs(dy)+1 then
move = attempt_move(sign(dx), 1) end
if move == nil and abs(dx) > abs(dy)+1 then
move = attempt_move(sign(dx), -1) end
if move == nil then move = attempt_move(0, sign(dy)) end
elseif abs(dx) == abs(dy) then
move = attempt_move(sign(dx), sign(dy))
if move == nil then move = attempt_move(sign(dx), 0) end
if move == nil then move = attempt_move(0, sign(dy)) end
else
if abs(dx) == 1 then move = attempt_move(0, sign(dy)) end
if move == nil then move = attempt_move(sign(dx), sign(dy)) end
if move == nil then move = attempt_move(0, sign(dy)) end
if move == nil and abs(dy) > abs(dx)+1 then
move = attempt_move(1, sign(dy)) end
if move == nil and abs(dy) > abs(dx)+1 then
move = attempt_move(-1, sign(dy)) end
if move == nil then move = attempt_move(sign(dx), 0) end
end
if move == nil then return false end
return move
end
function get_monster_info(dx, dy)
m = monster_array[dx][dy]
if not m then return nil end
name = m:name()
info = {}
info.distance = (abs(dx) > abs(dy)) and -abs(dx) or -abs(dy)
if not have_reaching() then
info.attack_type = (-info.distance < 2) and 2 or 0
else
if -info.distance > 2 then info.attack_type = 0
elseif -info.distance < 2 then info.attack_type = 2
else info.attack_type = view.can_reach(dx, dy) and 1 or 0 end
end
info.can_attack = (info.attack_type > 0) and 1 or 0
info.safe = m:is_safe() and -1 or 0
info.constricting_you = m:is_constricting_you() and 1 or 0
info.very_stabbable = (m:stabbability() >= 1) and 1 or 0
-- info.stabbable = m:is(0) and 1 or 0
info.injury = m:damage_level()
info.threat = m:threat()
info.orc_priest_wizard = (name == "orc priest" or
name == "orc wizard") and 1 or 0
return info
end
function compare_monster_info(m1, m2)
flag_order = {"can_attack", "safe", "distance", "constricting_you",
"very_stabbable", "injury", "threat", "orc_priest_wizard"}
for i, flag in ipairs(flag_order) do
if m1[flag] > m2[flag] then return true end
if m1[flag] < m2[flag] then return false end
end
return false
end
function is_candidate_for_attack(x, y, no_untabbable)
m = monster_array[x][y]
if not m or m:attitude() > ATT_NEUTRAL then
return false
end
if m:name() == "butterfly"
or m:name() == "orb of destruction" then
return false
end
if m:is_firewood() then
if not string.find(m:name(), "ballistomycete") then
return false
end
end
if no_untabbable then
if will_tab(0,0,x,y) then
remove_ignore(x,y)
else
add_ignore(x,y)
return false
end
end
return true
end
function get_target()
local x, y, bestx, besty, best_info, new_info
bestx = 0
besty = 0
best_info = nil
for x = -8, 8 do
for y = -8, 8 do
if not util.contains(failed_move, 20*x+y) then
if is_candidate_for_attack(x, y, true) then
new_info = get_monster_info(x, y)
if (not best_info) or
compare_monster_info(new_info, best_info) then
bestx = x
besty = y
best_info = new_info
end
end
end
end
end
return bestx, besty, best_info
end
function is_traversable(x,y)
local feat = view.feature_at(x,y)
return feat ~= "unseen" and travel.feature_traversable(feat)
end
---------------------------------------------
-- plans (+ auxiliary functions)
-- plans should return: true if they tried to do something,
-- false if they didn't do anything,
-- nil if they should be rerun (only used currently by
-- cascades, be careful of loops... this is
-- poorly tested)
function should_rest()
if you.confused() or you.berserk() or transformed() then
return true
end
if dangerous_to_rest() then
return false
end
return (hp_is_low(90) or you.slowed() or you.exhausted() or you.teleporting()
or you.silencing())
end
function dangerous_to_rest()
if danger then
return true
end
for x = -1,1 do
for y = -1,1 do
if view.feature_at(x,y):find("slimy_wall") then
return true
end
end
end
return false
end
function want_permafood()
return ((you.hunger_name() == "near starving" or
you.hunger_name() == "very hungry" and you.xl() >= 18) or
you.hunger_name() == "starving")
end
function want_chunk()
return you.hunger_name() == "hungry" or
you.hunger_name() == "very hungry" or want_permafood()
end
function rest()
magic("s")
next_delay = 10
end
function attack()
local success = false
failed_move = { }
while not success do
bestx, besty, best_info = get_target()
if best_info == nil then
return false
end
success = make_attack(bestx, besty, best_info)
end
return true
end
function pray()
magic("p")
end
function chop()
magic("ccq")
end
function berserk()
use_ability("Berserk")
--magic("aa")
end
function hand()
use_ability("Trog's Hand")
--magic("ab")
end
function bia()
use_ability("Brothers in Arms")
--magic("ac")
end
function plan_bia()
if can_bia() and want_to_bia() then
say("INVOKING BIA.")
bia()
return true
end
return false
end
function transformed()
return (you.transform() ~= "")
end
function plan_resistance()
if not you.berserk() and not you.extra_resistant() and
not you.teleporting() and want_resistance() and not transformed() then
local c = find_item("potion","resistance")
if c then
say("DRINKING RESISTANCE.")
quaff_helper(c)
return true
end
end
return false
end
function quaff_helper(c)
magic("q" .. c)
end
function plan_hand()
if can_hand() and want_to_hand() and not you.teleporting() then
say("INVOKING TROG'S HAND.")
hand()
return true
end
return false
end
function plan_abyss_hand()
local hp,mhp = you.hp()
if mhp - hp >= 30 and can_hand() then
say("INVOKING TROG'S HAND.")
hand()
return true
end
return false
end
function plan_orbrun_hand()
local hp,mhp = you.hp()
if mhp - hp >= 30 and can_hand() then
say("INVOKING TROG'S HAND.")
hand()
return true
end
return false
end
function plan_heal_wounds()
if not you.berserk() and want_to_heal_wounds() then
return heal_wounds()
end
return false
end
function heal_wounds()
if transformed() or you.berserk() then
return false
end
local c = find_item("potion","heal wounds")
if c then
say("DRINKING HEAL WOUNDS.")
quaff_helper(c)
return true
end
c = find_item("wand","heal wounds")
if c and not you.confused() then
say("ZAPPING HEAL WOUNDS.")
magic("V" .. c .. ".")
return true
end
return false
end
function plan_water_step()
if you.confused() or you.berserk() or you.flying() then
return false
end
if not sense_danger(2) then
return false
end
if not view.feature_at(0,0):find("shallow_water") then
return false
end
local x,y
for x = -1,1 do
for y = -1,1 do
if view.is_safe_square(x,y) and not view.withheld(x, y) and
(not view.feature_at(x,y):find("shallow_water")) and
not monster_in_way(x,y) then
for x2 = -1,1 do
for y2 = -1,1 do
m2 = monster_array[x+x2][y+y2]
if m2 and (m2:attitude() == 0) then
say("Stepping out of shallow water.")
magic(delta_to_vi(x,y))
return true
end
end
end
end
end
end
return false
end
function plan_berserk()
if can_berserk() and want_to_berserk() and not you.have_orb() then
say("INVOKING BERSERK.")
berserk()
return true
end
return false
end
function can_bia()
return (not (you.berserk() or you.confused() or you.silenced() or
you.hunger_name() == "starving" or you.piety_rank() < 4 or
you.god() ~= "Trog"))
end
function too_hungry_to_berserk()
return (you.hunger_name() == "starving" or
you.hunger_name() == "near starving" or
you.hunger_name() == "very hungry")
end
function can_berserk()
return (not (you.berserk() or you.confused() or you.silenced() or
you.exhausted() or you.mesmerised() or
too_hungry_to_berserk() or
you.piety_rank() < 1 or
you.god() ~= "Trog" or
you.transform() == "tree" or
you.transform() == "wisp"))
end
function want_to_bia()
if (want_to_berserk() and not can_berserk()) or
check_monsters(8, bia_monsters) then
if count_bia(4) == 0 and not you.teleporting() then
return true
end
end
return false
end
function want_to_teleport()
return ((you.slowed() or too_hungry_to_berserk()) and want_to_berserk()
and not can_berserk() and
count_bia(4) == 0)
end
function want_to_heal_wounds()
return (danger and hp_is_low(25))
end
function want_resistance()
return check_monsters(8, resistance_monsters) and you.res_fire() < 3
end
function want_to_hand()
return check_monsters(8, hand_monsters)
end
function want_to_berserk()
return (hp_is_low(50) and sense_danger(2) or
check_monsters(2, scary_monsters) or
-- check_monsters(3, scary_monsters) and sense_danger(2) or
(invisi_sigmund and not options.autopick_on))
end
function plan_zot_wait()
if (not danger) or (where ~= "Zot:5") or sense_danger(1) or
you.berserk() or you.have_orb() then
return false
end
count = 0
for x = -8,8 do
for y = -8,8 do
m = monster_array[x][y]
if m and not (m:name():find("Orb Guardian") or
m:name():find("Killer Klown") or
m:name():find("moth of wrath") or
m:name():find("bone dragon") or
m:name():find("tentacled monstrosity")) then
return false
end
if m and will_tab(0,0,x,y) then
count = count + 1
end
end
end
if count == 0 then
return false
end
-- say "Waiting for Orb Guardians."
magic("s")
return true
end
function plan_attack()
if danger then
if attack() then
return true
end
end
return false
end
function plan_eat_chunk()
if want_chunk() then
for it in inventory() do
if string.find(it.name(), "chunk") and
not bad_food(it) then
magic("ee")
return true
end
end
end
return false
end
function plan_eat_permafood()
if where == "Zot:5" then
return plan_orbrun_eat_permafood()
end
if want_permafood() then
if eat_permafood() then
return true
end
end
return false
end
function plan_orbrun_eat_permafood()
if you.hunger_name() ~= "completely stuffed" and
you.hunger_name() ~= "very full" then
if eat_permafood() then
return true
end
end
return false
end
function plan_eat_anyway()
if you.hunger_name() == "very hungry" then
if eat_permafood() then
return true
end
end
return false
end
function eat_permafood()
local l
local max_prefer = 0
local food_name
for it in inventory() do
if it.class(true) == "food" and not bad_food(it) then
local name = it.name()
local prefer
if name:find("ration") or name:find("royal") then
prefer = 1
elseif name:find("honey") then
prefer = 2
elseif name:find("chunk") then
prefer = 0
else
prefer = 3
end
if prefer > max_prefer then
l = items.index_to_letter(it.slot)
max_prefer = prefer
food_name = it.name()
end
end
end
if max_prefer > 0 then
items.swap_slots(items.letter_to_index(l), items.letter_to_index('e'),
false)
say("EATING " .. food_name .. ".")
magic("ee")
return true
end
end
function plan_rest()
if should_rest() then
rest()
return true
end
return false
end
function plan_orbrun_rest()
if you.confused() or you.slowed() or
you.berserk() or you.teleporting() or you.silencing() or
transformed() then
rest()
return true
end
return false
end
function plan_abyss_rest()
local hp,mhp = you.hp()
if you.confused() or you.slowed() or
you.berserk() or you.teleporting() or you.silencing() or
transformed() or (hp < mhp) and you.regenerating() then
rest()
return true
end
return false
end
function want_pray()
return (you.god() == "Trog")
end
function plan_handle_corpses()
if on_corpses() then
if want_pray() and (not want_chunk() or on_dangerous_corpse())
and not string.find(view.feature_at(0, 0), "altar")
and not you.silenced() then
pray()
else
chop()
end
return true
end
return false
end
function plan_find_altar()
if you.god() == "Trog" then
return false
end
magic(control('f') .. "@altar&&trog" .. "\ra\r")
return true
end
function plan_abandon_god()
if you.god() ~= "No God" and you.god() ~= "Trog" then
magic("aXYY")
return true
end
return false
end
function plan_unwield_weapon()
if you.race() ~= "Troll" then
return false
end
if not items.equipped_at("Weapon") then
return false
end
magic("w-")
return true
end
function plan_join_god()
if you.god() == "Trog" then
return false
end
if string.find(view.feature_at(0, 0), "altar_trog") then
if you.silenced() then
rest()
else
magic("pYY")
end
return true
end
return false
end
function plan_find_corpses()
magic(control('f') .. "@corpse$&&!!rott&&!!skel" .. "\ra\r")
return true
end
function plan_autoexplore()
magic("o")
return true
end
function plan_drop_filtered_items()
magic("d,,\r")
upgrade_phase = false
return true
end
function plan_quaff_id()
for it in inventory() do
if it.class(true) == "potion" and it.quantity > 1 and
not it.fully_identified then
l = items.index_to_letter(it.slot)
quaff_helper(l)
return true
end
end
return false
end
function plan_read_id()
if you.silenced() or you.confused() then
return false
end
for it in inventory() do
if it.class(true) == "scroll" and
not it.fully_identified then
items.swap_slots(it.slot, items.letter_to_index('Y'), false)
weap = items.equipped_at("Weapon")
scroll_letter = 'Y'
if weap and not weap:name():find("vamp") then
scroll_letter = items.index_to_letter(weap.slot)
items.swap_slots(weap.slot, items.letter_to_index('Y'), false)
end
magic("r" .. scroll_letter .. ".Y" ..
string.char(27) .. "YB") -- hack
return true
end
end
return false
end
function plan_use_id_scrolls()
if you.silenced() or you.confused() then
return false
end
local id_scroll
for it in inventory() do
if it.class(true) == "scroll" and it.name():find("identify") then
id_scroll = it
end
end
if not id_scroll then
return false
end
local oldslots = { }
local newslots = {[0] = 'B', [1] = 'N', [2] = 'Y'} -- harmless keys
local count = 0
for it in inventory() do
if it.class(true) == "jewellery" and not it.fully_identified
and count < 3 then
oldslots[count] = it.slot
count = count + 1
end
end
for it in inventory() do
if it.class(true) == "wand" and not it.fully_identified and
(it.name():find("empty") or it.name():find("teleportation") or
it.name():find("heal wounds") or it.name():find("hasting")) and
count < 3 then
oldslots[count] = it.slot
count = count + 1
end
end
if count == 0 then
return false
end
for it in inventory() do
if it.class(true) == "potion" and not it.fully_identified and
count < 3 then
oldslots[count] = it.slot
count = count + 1
end
end
for i = 0,count-1 do
items.swap_slots(oldslots[i], items.letter_to_index(newslots[i]), false)
for j = i+1,count-1 do
if oldslots[j] == items.letter_to_index(newslots[i]) then
oldslots[j] = oldslots[i]
end
end
end
if count > 0 then
for it in inventory() do
if it.class(true) == "scroll" and it.name():find("identify") then
id_scroll = it
end
end
say("READING IDENTIFY.")
magic("r" .. items.index_to_letter(id_scroll.slot) .. "B N Y")
return true
end
return false
end
function plan_use_good_consumables()
for it in inventory() do
if it.class(true) == "scroll" and not you.silenced() then
if it.name():find("acquirement") then
say("READING ACQUIREMENT.")
magic("r" .. items.index_to_letter(it.slot) .. " b")
return true
elseif it.name():find("enchant weapon") then
weapon = items.equipped_at("weapon")
if weapon and not weapon.artefact and
weapon.plus < 9 and weapon.plus2 < 9 then
say("ENCHANTING WEAPON.")
magic("r" .. items.index_to_letter(it.slot) ..
items.index_to_letter(weapon.slot))
return true
end
elseif it.name():find("enchant armour") then
body = items.equipped_at("armour")
if body and not body.artefact and
(body.name():find("gold dragon") and body.plus < 12
or body.name():find("plate armour of fire") and body.plus < 10
or body.name():find("crystal plate")
and body.plus < 14) then
say("ENCHANTING BODY ARMOUR.")
magic("r" .. items.index_to_letter(it.slot)
.. items.index_to_letter(body.slot))
return true
end
for _,slotname in pairs(good_slots) do
if slotname ~= "Armour" then
it2 = items.equipped_at(slotname)
if it2 and not it2.artefact and it2.plus < 2 and it2.plus >= 0
then
say("ENCHANTING " .. slotname .. ".")
say("ENCHANTING BODY ARMOUR.")
magic("r" .. items.index_to_letter(it.slot)
.. items.index_to_letter(it2.slot))
return true
end
end
end
if body and not body.artefact and
(body.name():find("pearl dragon") or body.name():find("plate"))
and body.plus < 10 then
say("ENCHANTING BODY ARMOUR.")
magic("r" .. items.index_to_letter(it.slot)
.. items.index_to_letter(body.slot))
return true
end
elseif it.name():find("recharging") then
for it2 in inventory() do
if it2.class(true) == "wand" and
(it2.name():find("heal wounds") or
it2.name():find("teleportation"))
and not (it2.name():find("recharged") or
it2.plus and it2.plus > 6) then
say("RECHARGING WAND.")
magic("r" .. items.index_to_letter(it.slot)
.. items.index_to_letter(it2.slot))
return true
end
end
elseif it.name():find("remove curse") then
for it2 in inventory() do
if it2.cursed and it2.equipped then
say("READING REMOVE CURSE.")
magic("r" .. items.index_to_letter(it.slot))
return true
end
end
end
elseif it.class(true) == "potion" then
if it.name():find("beneficial") or it.name():find("experience") then
say("DRINKING " .. it.name() .. ".")
quaff_helper(items.index_to_letter(it.slot))
return true
end
end
end
return false
end
function plan_zap_id()
for it in inventory() do
if it.class(true) == "wand" and
not (it.name():find("wand of") or it.name():find("empty")) then
l = items.index_to_letter(it.slot)
magic("V" .. l .. "YY")
return true
end
end
return false
end
function plan_wield_weapon()
if items.equipped_at("Weapon") or you.berserk() or transformed() then
return false
end
if you.race() == "Troll" then
return false
end
for it in inventory() do
if it and it.class(true) == "weapon" then
if equip_value(it, it:name()) >= 0 and not it:name():find("vamp") then
l = items.index_to_letter(it.slot)
say("Wielding weapon " .. it:name() .. ".")
magic("w" .. l .. "YY")
return true
end
end
end
say("Failed to find a weapon to wield.")
return false
end
function plan_upgrade_weapon()
if you.race() == "Troll" then
return false
end
it_old = items.equipped_at("Weapon")
swappable = can_swap("Weapon")
for it in inventory() do
if it and it.class(true) == "weapon" and not it.equipped then
local equip = false
local drop = false
local new_value = equip_value(it, it:name())
if new_value < 0 then
drop = true
elseif not it_old then
equip = true
elseif new_value > equip_value(it_old, it_old:name()) then
equip = true
else
drop = true
end
if equip and swappable then
if it.name():find("vamp") and not
(you.hunger_name() == "full" or you.hunger_name() == "very full" or
you.hunger_name() == "completely stuffed") then
say("Eating in order to wield vampiric weapon.")
if eat_permafood() then
return true
end
else
l = items.index_to_letter(it.slot)
say("Upgrading to " .. it:name() .. " (value " .. new_value .. ").")
magic("w" .. l .. "YY")
-- this might have a 0-turn fail because of vamp, so return nil
return nil
end
end
if drop then
l = items.index_to_letter(it.slot)
say("Dropping " .. it:name() .. " (value " .. new_value .. ").")
magic("d" .. l .. "\r")
return true
end
end
end
return false
end
function plan_upgrade_amulet()
it_old = items.equipped_at("Amulet")
swappable = can_swap("Amulet")
for it in inventory() do
if it and it.class(true) == "jewellery" and it:name():find("amulet of") and
not it.equipped then
local equip = false
local drop = false
local new_value = equip_value(it, it:name())
local new_value_with_resists = equip_value(it, it:name(), true)
if new_value < 0 then
drop = true
elseif not it_old then
if new_value_with_resists >= 0 then
equip = true
end
elseif new_value_with_resists > equip_value(it_old, it_old:name()) then
equip = true
elseif new_value <= equip_value(it_old, it_old:name()) then
drop = true
end
if equip and swappable then
l = items.index_to_letter(it.slot)
say("Upgrading to " .. it:name() .. " (value " ..
new_value_with_resists .. ").")
magic("P" .. l .. "YY")
return true
end
if drop then
l = items.index_to_letter(it.slot)
say("Dropping " .. it:name() .. " (value " .. new_value .. ").")
magic("d" .. l .. "\r")
return true
end
end
end
return false
end
function plan_upgrade_rings()
it_old1 = items.equipped_at("Left Ring")
it_old2 = items.equipped_at("Right Ring")
swappable = can_swap("Left Ring")
for it in inventory() do
if it and it.class(true) == "jewellery" and it:name():find("ring of") and
it.fully_identified and not it.equipped then
local equip = false
local drop = false
local swap = nil
local new_value = equip_value(it, it:name())
local new_value_with_resists = equip_value(it, it:name(), true)
if new_value < 0 then
drop = true
elseif (not it_old1 or not it_old2) then
if new_value_with_resists >= 0 then
equip = true
end
elseif new_value_with_resists > equip_value(it_old1, it_old1:name()) then
equip = true
swap = it_old1.slot
elseif new_value_with_resists > equip_value(it_old2, it_old2:name()) then
equip = true
swap = it_old2.slot
elseif new_value <= equip_value(it_old1, it_old1:name()) and
new_value <= equip_value(it_old2, it_old2:name()) then
drop = true
end
if equip and swappable then
l = items.index_to_letter(it.slot)
say("Upgrading to " .. it:name() .. " (value " ..
new_value_with_resists .. ").")
if swap then
items.swap_slots(swap, items.letter_to_index('Y'), false)
if l == 'Y' then
l = items.index_to_letter(swap)
end
end
magic("P" .. l .. "YY")
return true
end
if drop then
l = items.index_to_letter(it.slot)
say("Dropping " .. it:name() .. " (value " .. new_value .. ").")
magic("d" .. l .. "\r")
return true
end
end
end
return false
end
function plan_maybe_upgrade_armour()
if not upgrade_phase then
return false
end
return plan_upgrade_armour()
end
function plan_upgrade_armour()
for it in inventory() do
if it and it.class(true) == "armour" and not it.equipped then
local st, _ = it.subtype()
local equip = false
local drop = false
local swappable
it_old = items.equipped_at(good_slots[st])
swappable = can_swap(good_slots[st])
local new_value = equip_value(it, it:name())
local new_value_with_resists = equip_value(it, it:name(), true)
if new_value < 0 then
drop = true
elseif not it_old then
if new_value_with_resists >= 0 then
equip = true
end
elseif new_value_with_resists > equip_value(it_old, it_old:name()) then
equip = true
elseif new_value <= equip_value(it_old, it_old:name()) then
drop = true
end
if it:name():find("helmet") and (you.mutation("horns") > 0
or you.mutation("beak") > 0 or you.mutation("antennae") > 0) then
equip = false
drop = true
end
if it:name():find("boots") and you.mutation("talons") >= 3 then
equip = false
drop = true
end
if equip and swappable then
l = items.index_to_letter(it.slot)
say("Upgrading to " .. it:name() .. " (value " ..
new_value_with_resists .. ").")
magic("W" .. l .. "YN")
upgrade_phase = true
return true
end
if drop then
l = items.index_to_letter(it.slot)
say("Dropping " .. it:name() .. " (value " .. new_value .. ").")
magic("d" .. l .. "\r")
return true
end
end
end
return false
end
function plan_remove_redundant_jewels()
it = items.equipped_at("Amulet")
if it and (it:name():find("conservation") or
it:name():find("resist corrosion")) then
it2 = items.equipped_at("Cloak")
if it2 and it2:name():find("preservation") and can_swap("Amulet") then
say("Removing redundant " .. it:name() .. ".")
magic("P" .. items.index_to_letter(it.slot) .. "YY")
return true
end
end
it = items.equipped_at("Left Ring")
if it and it:name():find("see invisible") then
it2 = items.equipped_at("Helmet")
if it2 and it2:name():find("see invisible") and can_swap("Left Ring") then
say("Removing redundant " .. it:name() .. ".")
magic("P" .. items.index_to_letter(it.slot) .. "YY")
return true
end
for _,slotname in pairs(good_slots) do
it2 = items.equipped_at(slotname)
if it2 and it2:name():find("SInv") and can_swap("Left Ring") then
say("Removing redundant " .. it:name() .. ".")
magic("P" .. items.index_to_letter(it.slot) .. "YY")
return true
end
end
end
it = items.equipped_at("Right Ring")
if it and it:name():find("see invisible") then
it2 = items.equipped_at("Helmet")
if it2 and it2:name():find("see invisible") and can_swap("Right Ring") then
say("Removing redundant " .. it:name() .. ".")
magic("P" .. items.index_to_letter(it.slot) .. "YY")
return true
end
for _,slotname in pairs(good_slots) do
it2 = items.equipped_at(slotname)
if it2 and it2:name():find("SInv") and can_swap("Right Ring") then
say("Removing redundant " .. it:name() .. ".")
magic("P" .. items.index_to_letter(it.slot) .. "YY")
return true
end
end
end
return false
end
function plan_go_up()
local feat = view.feature_at(0,0)
if feat:find("stone_stairs_up") or feat:find("escape_hatch_up")
or feat:find("return_from_zot") or feat:find("exit_dungeon")
or feat:find("return_from_depths") then
expect_new_location = true
magic("<")
return true
end
return false
end
function plan_go_down()
local feat = view.feature_at(0,0)
if feat:find("stone_stairs_down") then
expect_new_location = true
magic(">")
return true
end
return false
end
function plan_simple_go_down()
if travel_destination then
return false
end
if found_branch("L") and not
util.contains(branches_entered, "L") then
return false
end
if where == "Orc:3" then
return false
end
if where == "Vaults:4" and you.num_runes() < 2 then
return false
end
expect_new_location = true
magic("G>")
return true
end
function plan_go_to_temple()
if found_branch("T") and you.god() ~= "Trog" and not
util.contains(branches_entered, "T") and in_branch("D") then
expect_new_location = true
magic("GTY")
return true
end
return false
end
function plan_go_to_lair()
if found_branch("L") and not
util.contains(branches_entered, "T") and in_branch("D") then
expect_new_location = true
magic("GL\rY")
return true
end
return false
end
function plan_enter_branch()
local br
if found_branch("L") and not
util.contains(branches_entered, "L") and in_branch("D") then
br = "L"
elseif found_branch("O") and not
util.contains(branches_entered, "O") and in_branch("D") and
util.contains(branches_entered, "L") then
br = "O"
end
if br then
expect_new_location = true
magic("G" .. br .. "\rY")
return true
end
return false
end
function plan_go_to_portal_entrance()
for _, por in ipairs(portals_found) do
for _, val in ipairs(portal_data) do
if val[1] == por then
magic(control('f') .. "@" .. val[2] .. "\ra\r")
return true
end
end
end
return false
end
function plan_go_to_zig()
if you.num_runes() < 3 then
return false
end
magic(control('f') .. "gateway to a ziggurat" .. "\ra\r")
return true
end
function plan_go_to_portal_exit()
if in_portal() then
magic("X<\r")
return true
end
return false
end
function plan_go_to_abyss_exit()
magic("X<\r")
return true
end
function get_feat_name(where_name)
for _, value in ipairs(portal_data) do
if where_name == value[1] then
return value[3]
end
end
end
function plan_enter_zig()
if you.num_runes() < 3 then
return false
end
if string.find(view.feature_at(0,0), "enter_ziggurat") then
expect_new_location = true
magic(">")
return true
end
return false
end
function plan_enter_portal()
for _, por in ipairs(portals_found) do
if string.find(view.feature_at(0,0), "enter_" .. get_feat_name(por)) then
expect_portal = true
expect_new_location = true
magic(">")
return true
end
return false
end
return false
end
function plan_exit_portal()
if not in_portal() then
return false
end
if string.find(view.feature_at(0,0), "exit_" .. get_feat_name(where)) then
expect_new_location = true
magic("<")
return true
end
return false
end
function plan_zig_leave_level()
if not where:find("Zig") then
return false
end
if where:find("10") and string.find(view.feature_at(0,0), "exit_ziggurat")
then
magic("")
return true
end
return false
end
function plan_exit_abyss()
if string.find(view.feature_at(0,0), "exit_abyss") then
expect_new_location = true
magic("<")
return true
end
return false
end
function plan_step_towards_lair()
local x, y
if stepped_on_lair then
return false
end
for x = -8,8 do
for y = -8,8 do
if view.feature_at(x,y) == "enter_lair"
and you.see_cell_no_trans(x,y) then
if x == 0 and y == 0 then
stepped_on_lair = true
return false
else
kill_plant_mode = true
local result = move_towards(x,y)
kill_plant_mode = false
return result
end
end
end
end
return false
end
function plan_continue_travel()
if travel_destination then
if in_branch(travel_destination) or
not found_branch(travel_destination) then
travel_destination = nil
return false
end
expect_new_location = true
magic("G" .. travel_destination .. "\rY")
return true
end
return false
end
function choose_lair_rune_branch()
--if crawl.random2(2) == 0 then
--branch_options = { "A", "P", "S", "N" }
--else
--branch_options = { "P", "A", "N", "S" }
--branch_options = { "N", "S", "P", "A" }
--end
branch_options = { "P", "N", "S", "A" }
for _, branch_code in ipairs(branch_options) do
if found_branch(branch_code) and
not util.contains(branches_entered, branch_code) then
return branch_code
end
end
--tries = 0
--while tries < 100 do
-- i = 1 + crawl.random2(4)
-- branch_code = branch_options[i]
-- if found_branch(branch_code) and
-- not util.contains(branches_entered, branch_code) then
-- return branch_code
-- end
-- tries = tries + 1
--end
return nil
end
function plan_new_travel()
local back_to_D_places = { "Temple", "Lair:8", "Orc:3", "Orc:4", "Vaults:4"}
if util.contains(back_to_D_places, where) then
travel_destination = "D"
end
if where == "Snake:5" and you.have_rune("serpentine") then
travel_destination = "D"
end
if where == "Swamp:5" and you.have_rune("decaying") then
travel_destination = "D"
end
if where == "Spider:5" and you.have_rune("gossamer") then
travel_destination = "D"
end
if where == "Shoals:5" and you.have_rune("barnacled") then
travel_destination = "D"
end
if where == "Vaults:5" and you.have_rune("silver") then
travel_destination = "D"
end
if where == "D:15" then
if you.num_runes() == 1 and not util.contains(branches_entered, "V")
or you.num_runes() == 2 then
travel_destination = "V"
elseif you.num_runes() == 1 and not util.contains(branches_entered, "U")
or you.num_runes() >= 3 then
travel_destination = "U"
else
travel_destination = choose_lair_rune_branch()
end
end
if where == "Depths:5" then
if you.num_runes() >= 3 then
travel_destination = "Z"
else
travel_destination = "D"
end
end
return plan_continue_travel()
end
function plan_fly()
if you.xl() >= 14 and not you.flying() then
local a,b = you.mp()
if a >= 3 and not you.rooted() then
if use_ability("Fly") then
say("FLYING.")
return true
end
end
end
return false
end
function plan_find_upstairs()
magic("X<\r")
return true
end
function plan_zig_go_to_stairs()
if not where:find("Zig") then
return false
end
if where:find("10") then
magic("X<\r")
else
magic("X>\r")
end
return true
end
function plan_find_downstairs()
-- try to avoid branch entrances by going to a random > from them
local feat = view.feature_at(0,0)
if feat:find("enter_") or feat:find("escape_hatch_down") then
local i,j
local c = "X"
j = crawl.roll_dice(1,12)
for i = 1,j do
c = (c .. ">")
end
magic(c .. "\r")
return true
end
magic("X>\r")
return true
end
function plan_stuck()
if you.hunger_name() == "starving" then
return random_step("starving")
end
stuck_turns = stuck_turns + 1
if stuck_turns > 5000 then
magic(control('q') .. "yes\r")
return true
end
return random_step("stuck")
-- panic("Stuck!")
end
function plan_not_coded()
panic("Need to code this!")
return true
end
function random_step(reason)
if you.mesmerised() then
say("Waiting to end mesmerise (" .. reason .. ").")
magic("s")
return true
end
local i,j
local dx,dy
local count = 0
for i = -1,1 do
for j = -1,1 do
if not (i == 0 and j == 0) and is_traversable(i,j)
and not monster_in_way(i,j) then
count = count + 1
if crawl.one_chance_in(count) then
dx = i
dy = j
end
end
end
end
if count > 0 then
say("Stepping randomly (" .. reason .. ").")
magic(delta_to_vi(dx,dy) .. "YY")
return true
else
say("Standing still (" .. reason .. ").")
magic("s")
return true
end
-- return false
end
function plan_disturbance_random_step()
if crawl.messages(5):find("There is a strange disturbance nearby!") then
return random_step("disturbance")
end
return false
end
function plan_wait()
rest()
return true
end
function plan_flail_at_invis()
if options.autopick_on then
invisi_count = 0
invisi_sigmund = false
return false
end
if invisi_count > 100 then
say("Invisible monster not found???")
invisi_count = 0
invisi_sigmund = false
magic(control('a'))
return true
end
invisi_count = invisi_count + 1
local x,y
if invisi_sigmund and (sigmund_dx ~= 0 or sigmund_dy ~= 0) then
x = sigmund_dx
y = sigmund_dy
if adjacent(x,y) and is_traversable(x,y) then
magic(control(delta_to_vi(x,y)))
return true
elseif x == 0 and is_traversable(0,sign(y)) then
magic(delta_to_vi(0,sign(y)))
return true
elseif y == 0 and is_traversable(sign(x),0) then
magic(delta_to_vi(sign(x),0))
return true
end
end
local success = false
local tries = 0
while not success and tries < 100 do
x = -1 + crawl.random2(3)
y = -1 + crawl.random2(3)
tries = tries + 1
if (x ~= 0 or y ~= 0) and is_traversable(x,y) then
success = true
end
end
if tries >= 100 then
magic("s")
else
magic(control(delta_to_vi(x,y)))
end
return true
end
function plan_cure_confusion()
if you.confused() and not you.berserk() and
(danger or not options.autopick_on) and not transformed() then
local c = find_item("potion","curing")
if c then
say("CURING CONFUSION.")
quaff_helper(c)
return true
end
end
return false
end
function plan_cure_statzero()
if you.berserk() or transformed() then
return false
end
local str, mstr = you.strength()
local int, mint = you.intelligence()
local dex, mdex = you.dexterity()
if str <= 0 and mstr > 0 or int <= 0 and mint > 0 or dex <= 0 and mdex > 0
then
local c = find_item("potion","restore abilities")
if c then
say("DRINKING RESTORE ABILITIES.")
quaff_helper(c)
return true
end
end
return false
end
function plan_cure_bad_statdrain()
if you.berserk() or transformed() then
return false
end
local str, mstr = you.strength()
local int, mint = you.intelligence()
local dex, mdex = you.dexterity()
if str <= mstr - 3 or str <= 3 and str < mstr or
int <= mint - 3 or int <= 3 and int < mint or
dex <= mint - 3 or dex <= 3 and dex < mdex then
local c = find_item("potion","restore abilities")
if c then
say("DRINKING RESTORE ABILITIES.")
quaff_helper(c)
return true
end
end
return false
end
function plan_teleport()
if can_teleport() and want_to_teleport() then
-- return false
return teleport()
end
return false
end
function plan_stuck_clear_exclusions()
magic("X" .. control('e'))
return true
end
function plan_stuck_teleport()
if can_teleport() then
return teleport()
end
return false
end
function can_teleport()
return (not you.berserk() and not you.teleporting() and not you.anchored()
and not you.confused() and you.transform() ~= "wisp"
and you.transform() ~= "tree"
and you.transform() ~= "porcupine")
end
function teleport()
local c = find_item("scroll","teleportation")
if c and not you.silenced() and not you.confused() then
say("READING TELEPORTATION.")
magic("r" .. c)
return true
end
c = find_item("wand","teleportation")
if c and not you.confused() then
say("ZAPPING TELEPORTATION.")
magic("V" .. c .. ".")
return true
end
return false
end
function plan_cure_poison_rotting()
local hp, mhp = you.hp()
local c
if you.berserk() or transformed() then
return false
end
if (you.poisoned() and hp < 10) or you.rotting() then
c = find_item("potion","curing")
if c then
say("DRINKING CURING.")
quaff_helper(c)
return true
end
end
if (you.poisoned() and hp < 10) and can_hand() then
say("INVOKING TROG'S HAND.")
hand()
return true
end
return false
end
function can_hand()
return (not (you.berserk() or you.confused() or you.silenced() or
you.regenerating() or
you.hunger_name() == "starving" or you.piety_rank() < 2 or
you.god() ~= "Trog"))
end
function move_towards(dx, dy)
if you.transform() == "tree" or you.transform() == "fungus" then
magic("s")
return true
end
local move = nil
if abs(dx) > abs(dy) then
if abs(dy) == 1 then move = try_move(sign(dx), 0) end
if move == nil then move = try_move(sign(dx), sign(dy)) end
if move == nil then move = try_move(sign(dx), 0) end
if move == nil and abs(dx) > abs(dy)+1 then
move = try_move(sign(dx), 1) end
if move == nil and abs(dx) > abs(dy)+1 then
move = try_move(sign(dx), -1) end
if move == nil then move = try_move(0, sign(dy)) end
elseif abs(dx) == abs(dy) then
move = try_move(sign(dx), sign(dy))
if move == nil then move = try_move(sign(dx), 0) end
if move == nil then move = try_move(0, sign(dy)) end
else
if abs(dx) == 1 then move = try_move(0, sign(dy)) end
if move == nil then move = try_move(sign(dx), sign(dy)) end
if move == nil then move = try_move(0, sign(dy)) end
if move == nil and abs(dy) > abs(dx)+1 then
move = try_move(1, sign(dy)) end
if move == nil and abs(dy) > abs(dx)+1 then
move = try_move(-1, sign(dy)) end
if move == nil then move = try_move(sign(dx), 0) end
end
if move == nil or move_count >= 10 then
add_ignore(dx,dy)
table.insert(failed_move, 20*dx+dy)
return false
else
if (abs(dx) > 1 or abs(dy) > 1) and not kill_plant_mode then
did_move = true
end
magic(move .. "Y")
return true
end
end
function add_ignore(dx,dy)
m = monster_array[dx][dy]
if not m then
return
end
name = m:name()
if not util.contains(ignore_list, name) then
table.insert(ignore_list, name)
crawl.setopt("runrest_ignore_monster ^= " .. name .. ":1")
say("Ignoring " .. name .. ".")
end
end
function remove_ignore(dx,dy)
m = monster_array[dx][dy]
name = m:name()
for i,mname in ipairs(ignore_list) do
if mname == name then
table.remove(ignore_list, i)
crawl.setopt("runrest_ignore_monster -= " .. name .. ":1")
say("Unignoring " .. name .. ".")
return
end
end
end
function clear_ignores()
local size = #ignore_list
local mname
local i
if size > 0 then
for i = 1, size do
mname = table.remove(ignore_list)
crawl.setopt("runrest_ignore_monster -= " .. mname .. ":1")
say("Unignoring " .. mname .. ".")
end
end
end
function attack_reach(x, y)
magic('vr' .. vector_move(x, y) .. '.')
end
function attack_melee(x, y)
if you.transform() == "tree" or you.transform() == "fungus" then
magic(control(delta_to_vi(x, y)) .. "Y")
else
magic(delta_to_vi(x, y) .. "Y")
end
end
function make_attack(x, y, info)
if info.attack_type == 2 then attack_melee(x, y)
elseif info.attack_type == 1 then attack_reach(x, y)
else
return move_towards(x, y)
end
return true
end
function use_ability(name)
for letter, abil in pairs(you.ability_table()) do
if abil == name then
magic("a" .. letter)
return true
end
end
end
---------------------------------------------
-- cascading plans: this is the bot's flowchart
function cascade(plans)
local plan_turns = {}
local plan_result = {}
return function ()
for i, plandata in ipairs(plans) do
plan = plandata[1]
if you.turns() ~= plan_turns[plan] or plan_result[plan] == nil then
--say(plandata[2])
result = plan()
if not automatic then
return true
end
plan_turns[plan] = you.turns()
plan_result[plan] = result
if result == nil or result == true then
if (DELAYED or DELAYEDZOT and where == "Zot:5") and
result == true then
crawl.delay(next_delay)
end
next_delay = DELAY_TIME
return nil
end
elseif plan_turns[plan] and plan_result[plan] == true then
if not plandata[2]:find("^try") then
panic(plandata[2] .. " failed despite returning true.")
end
end
end
return false
end
end
plan_pre_explore = cascade {
{plan_fly, "fly"},
{plan_upgrade_weapon, "upgrade_weapon"},
{plan_maybe_upgrade_armour, "maybe_upgrade_armour"},
{plan_use_good_consumables, "use_good_consumables"},
} -- hack
plan_pre_explore2 = cascade {
{plan_disturbance_random_step, "disturbance_random_step"},
{plan_remove_redundant_jewels, "remove_redundant_jewels"},
{plan_upgrade_armour, "upgrade_armour"},
{plan_upgrade_amulet, "upgrade_amulet"},
{plan_upgrade_rings, "upgrade_rings"},
{plan_read_id, "read_id"},
{plan_zap_id, "zap_id"},
{plan_use_id_scrolls, "use_id_scrolls"},
{plan_quaff_id, "quaff_id"},
{plan_drop_filtered_items, "try_drop_filtered_items"},
} -- hack
plan_emergency = cascade {
{plan_cure_statzero, "cure_statzero"},
{plan_cure_confusion, "cure_confusion"},
{plan_teleport, "teleport"},
{plan_heal_wounds, "heal_wounds"},
{plan_hand, "hand"},
{plan_resistance, "resistance"},
{plan_bia, "bia"},
{plan_wield_weapon, "wield_weapon"},
{plan_water_step, "water_step"},
{plan_berserk, "berserk"},
} -- hack
plan_eatrest = cascade {
{plan_eat_chunk, "eat_chunk"},
{plan_eat_permafood, "eat_permafood"},
{plan_rest, "rest"},
{plan_handle_corpses, "handle_corpses"},
{plan_find_corpses, "try_find_corpses"},
{plan_eat_anyway, "eat_anyway"},
} -- hack
plan_abyss_eatrest = cascade {
{plan_eat_chunk, "eat_chunk"},
{plan_eat_permafood, "eat_permafood"},
{plan_go_to_abyss_exit, "try_go_to_abyss_exit"},
{plan_abyss_hand, "abyss_hand"},
{plan_abyss_rest, "rest"},
{plan_handle_corpses, "handle_corpses"},
{plan_find_corpses, "try_find_corpses"},
{plan_eat_anyway, "eat_anyway"},
} -- hack
plan_orbrun_eatrest = cascade {
{plan_orbrun_eat_permafood, "orbrun_eat_permafood"},
{plan_orbrun_rest, "orbrun_rest"},
{plan_orbrun_hand, "orbrun_hand"},
} -- hack
plan_explore = cascade {
{plan_enter_zig, "enter_zig"},
{plan_continue_travel, "try_continue_travel"},
{plan_enter_portal, "enter_portal"},
{plan_go_to_portal_entrance, "try_go_to_portal_entrance"},
{plan_autoexplore, "try_autoexplore"},
} -- hack
plan_explore2 = cascade {
{plan_zig_leave_level, "zig_leave_level"},
{plan_zig_go_to_stairs, "try_zig_go_to_stairs"},
{plan_exit_portal, "exit_portal"},
{plan_go_to_portal_exit, "try_go_to_portal_exit"},
{plan_enter_branch, "try_enter_branch"},
{plan_go_to_zig, "try_go_to_zig"},
{plan_simple_go_down, "try_simple_go_down"},
{plan_new_travel, "try_new_travel"},
} -- hack
plan_move = cascade {
{plan_emergency, "emergency"},
{plan_zot_wait, "zot_wait"},
{plan_attack, "attack"},
{plan_cure_poison_rotting, "cure_poison_rotting"},
{plan_cure_bad_statdrain, "cure_bad_statdrain"},
{plan_flail_at_invis, "try_flail_at_invis"},
{plan_eatrest, "eatrest"},
{plan_pre_explore, "pre_explore"},
{plan_step_towards_lair, "step_towards_lair"},
--{plan_abandon_god, "abandon_god"},
--{plan_unwield_weapon, "unwield_weapon"},
--{plan_join_god, "join_god"},
--{plan_find_altar, "try_find_altar"},
--{plan_go_to_temple, "try_go_to_temple"},
--{plan_go_to_lair, "try_go_to_lair"},
{plan_explore, "explore"},
{plan_pre_explore2, "pre_explore2"},
{plan_explore2, "explore2"},
--{plan_stuck_clear_exclusions, "try_stuck_clear_exclusions"},
{plan_stuck_teleport, "stuck_teleport"},
{plan_stuck, "stuck"},
} -- hack
plan_orbrun_move = cascade {
{plan_emergency, "emergency"},
{plan_attack, "attack"},
{plan_cure_poison_rotting, "cure_poison_rotting"},
{plan_cure_bad_statdrain, "cure_bad_statdrain"},
{plan_orbrun_eatrest, "orbrun_eatrest"},
{plan_go_up, "go_up"},
{plan_fly, "fly"},
{plan_find_upstairs, "try_find_upstairs"},
{plan_disturbance_random_step, "disturbance_random_step"},
--{plan_stuck_clear_exclusions, "try_stuck_clear_exclusions"},
{plan_stuck_teleport, "stuck_teleport"},
{plan_autoexplore, "try_autoexplore"},
{plan_stuck, "stuck"},
} -- hack
plan_abyss_move = cascade {
{plan_exit_abyss, "exit_abyss"},
{plan_emergency, "emergency"},
{plan_attack, "attack"},
{plan_cure_poison_rotting, "cure_poison_rotting"},
{plan_cure_bad_statdrain, "cure_bad_statdrain"},
{plan_flail_at_invis, "try_flail_at_invis"},
{plan_abyss_eatrest, "abyss_eatrest"},
{plan_pre_explore, "pre_explore"},
{plan_autoexplore, "try_autoexplore"},
{plan_pre_explore2, "pre_explore2"},
{plan_wait, "wait"},
} -- hack
---------------------------------------------
-- "abstract" functions that have very little to do with playing crawl
function magic(command)
crawl.enable_more(false)
crawl.process_keys(command .. string.char(27) .. string.char(27) ..
string.char(27))
end
function note(x)
crawl.take_note(you.turns() .. " ||| " .. x)
end
function say(x)
crawl.mpr(you.turns() .. " ||| " .. x)
note(x)
end
function contains_string_in(name,t)
for _, value in ipairs(t) do
if string.find(name, value) then
return true
end
end
return false
end
function handle_skills()
weapon_skill = "Axes"
if you.race() == "Troll" then
weapon_skill = "Unarmed Combat"
end
train_weapon = you.skill(weapon_skill) <= 27 and 1 or 0
train_fight_armour = you.skill(weapon_skill) >= 18 and 1 or 0
train_dodge = you.skill("Fighting") >= 26 and 1 or 0
you.train_skill(weapon_skill, train_weapon)
you.train_skill("Fighting", train_fight_armour)
you.train_skill("Armour", train_fight_armour)
you.train_skill("Dodging", train_fight_armour) -- this is just to not get stuck
you.train_skill("Throwing", train_dodge)
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)
you.train_skill("Short Blades", 0)
you.train_skill("Maces & Flails", 0)
end
function control(c)
return string.char(string.byte(c) - string.byte('a') + 1)
end
function delta_to_vi(dx, dy)
local d2v = {
[-1] = { [-1] = 'y', [0] = 'h', [1] = 'b'},
[0] = { [-1] = 'k', [1] = 'j'},
[1] = { [-1] = 'u', [0] = 'l', [1] = 'n'},
} -- hack
return d2v[dx][dy]
end
function sign(a)
return a > 0 and 1 or a < 0 and -1 or 0
end
function abs(a)
return a * sign(a)
end
function vector_move(dx, dy)
local str = ''
for i = 1, abs(dx) do
str = str .. delta_to_vi(sign(dx), 0)
end
for i = 1, abs(dy) do
str = str .. delta_to_vi(0, sign(dy))
end
return str
end
function supdist(dx, dy)
if abs(dx) <= abs(dy) then
return abs(dx)
else
return abs(dy)
end
end
function adjacent(dx, dy)
return abs(dx) <= 1 and abs(dy) <= 1
end
function choose_stat_gain()
return "d"
end
function auto_experience()
return true
end
function write_string_array(arr, aname)
local res = aname .. " = { "
for i, v in ipairs(arr) do
res = res .. '"' .. v .. '"' .. ", "
end
return res .. "}\n"
end
function qw_save()
local res = ""
if branches_entered then
res = res .. write_string_array(branches_entered, "branches_entered")
end
if portals_found then
res = res .. write_string_array(portals_found, "portals_found")
end
return res
end
table.insert(chk_lua_save, qw_save)
-- for testing random stuff
function ttt()
say(view.feature_at(0,0))
end
}
# Crawl Init file
#
# On Unix systems (such as Mac OS X, Linux and the BSDs), you must copy
# init.txt to ~/.crawlrc or ~/.crawl/init.txt as:
# cp init.txt ~/.crawlrc
#
# Lines beginning with '#' are comments. The basic syntax is:
#
# field = value or field.subfield = value
#
# Only one specification is allowed per line.
#
# The terms are typically case-insensitive except in the fairly obvious
# cases (the character's name and specifying files or directories when
# on a system that has case-sensitive filenames).
#
# White space is stripped from the beginning and end of the line, as
# well as immediately before and after the '='. If the option allows
# multiple comma/semicolon-separated terms (such as
# autopickup_exceptions), all whitespace around the separator is also
# trimmed. All other whitespace is left intact.
#
# For descriptions concerning an option consult the file
# options_guide.txt
# in your /docs directory. Also note that the ordering of the options
# is taken from that file; this is for presentational reasons only.
#
# Note that all boolean options (i.e. values of 'true' or 'false') have
# their non-default value commented out. You can toggle these by just
# uncommenting.
# Options with several values, e.g.
# confirm_butcher = (auto | always | never),
# usually have the first value as default.
#
# The options for monster glyphs and item colours don't matter for Tiles.
# Similarily, tile options are ignored in console games.
##### Ancient versions ##############################################
# If you're used to the interface of ancient versions of Crawl, you may
# get back parts of it by uncommenting the following options:
# include = 034_command_keys.txt
# clear_messages = true
#
# And to revert monster glyph and colouring changes:
# include = 034_monster_glyphs.txt
# include = 052_monster_glyphs.txt
# include = 060_monster_glyphs.txt
# include = 071_monster_glyphs.txt
# include = 080_monster_glyphs.txt
# include = 0.9_monster_glyphs.txt
# include = 0.12_monster_glyphs.txt
# include = 0.13_monster_glyphs.txt
##### 1- Starting Screen ############################################
#
# name = Delilah
# remember_name = false
# weapon = (short sword | falchion | quarterstaff | hand axe | spear | mace
# | trident | unarmed | random)
# species = (Human |...| Vampire | random)
# job = (Fighter |...| Wanderer | random)
# random_pick = true
# good_random = false
# restart_after_game = true
# default_manual_training = true
##### 2- File System ###############################################
#
# crawl_dir =
# morgue_dir = morgue
# save_dir = saves
# macro_dir = settings/
# sound = :
##### 3- Interface #################################################
#
##### 3-a Picking up and Dropping ###############
#
# Rods are \ here.
# autopickup = $?!:"/%
# drop_filter += useless_item
# default_autopickup = false
# autopickup_no_burden = false
# pickup_thrown = false
# chunks_autopickup = false
# assign_item_slot = (forward | backward)
#
# pickup_menu = false
# pickup_menu_limit = 4
# drop_filter += skeleton, corpse, useless_item
# default_friendly_pickup = (none | friend | player | all)
##### 3-b Targeting ############################
#
# darken_beyond_range = false
##### 3-c Passive Sightings #####################
#
# detected_monster_colour = lightred
# detected_item_colour = green
# remembered_monster_colour = darkgrey
##### 3-d Branding ##############################
#
# friend_brand = hi:green
# neutral_brand = hi:lightgrey
# stab_brand = hi:blue
# may_stab_brand = hi:yellow
# heap_brand = reverse
# feature_item_brand = reverse
# trap_item_brand = reverse
##### 3-e Level Map Functions ###################
#
# level_map_cursor_step = 7
# show_waypoints = false
##### 3-f Viewport Options ###################
#
# view_max_width = 33
# view_max_height = 21
# view_lock_x = false
# view_lock_y = false
# view_lock = false
# center_on_scroll = true
# symmetric_scroll = false
# scroll_margin_x = 2
# scroll_margin_y = 2
# scroll_margin = 2
##### 3-g Travel and Exploration #################
#
# travel_delay = 20 (or -1 online)
# explore_delay = -1
# rest_delay = 0 (or -1 online)
# travel_avoid_terrain = shallow water
#
# explore_greedy = false
# explore_stop = items,stairs,shops,altars,portals,branches,runed_doors
# explore_stop += greedy_pickup_smart,greedy_visited_item_stack
# explore_stop += greedy_sacrificeable
# sacrifice_before_explore = true
# explore_improved = true
# explore_wall_bias = 0
# travel_key_stop = false
# auto_sacrifice = true
#
# explore_stop_pickup_ignore += curare
# auto_exclude += oklob,statue,curse skull,roxanne,hyperactive,lightning spire
# auto_exclude += mimic
# tc_reachable = blue
# tc_dangerous = cyan
# tc_disconnected = darkgrey
# tc_excluded = lightmagenta
# tc_exclude_circle = red
# Interrupting run and rest compound commands:
# runrest_safe_poison = 80:100
# runrest_ignore_monster ^= butterfly:1
# runrest_ignore_monster ^= swamp worm:3
# runrest_stop_message += You hear a.* slurping noise
# runrest_ignore_message += Jiyva's power touches on your attributes
# A good number of runrest_messages are defined by default; you may want to
# clear them or override some.
# trapwalk_safe_hp = dart:20,needle:15,arrow:35,bolt:45,spear:40,blade:95
#rest_wait_both = true
##### 3-h Command Enhancements ##################
#
# auto_switch = true
# travel_open_doors = false
# easy_unequip = false
# equip_unequip = true
# easy_confirm = (none | safe | all)
# allow_self_target = (yes | no | prompt)
# confirm_butcher = (auto | always | never)
# easy_eat_chunks = true
# auto_eat_chunks = true
# auto_drop_chunks = (never | rotten | yes)
# prompt_for_swap = false
# easy_quit_item_prompts = false
# easy_exit_menu = true
# sort_menus = pickup: true : art, ego, basename, qualname, curse, qty
# sort_menus = inv: true : equipped, freshness, charged
# autofight_stop = 30
# automagic_enable = false
# automagic_fight = false
# automagic_stop = 0
##### 3-i Messages and Display Enhancements #####
#
# hp_warning = 30
# mp_warning = 0
# hp_colour = 50:yellow, 25:red
# mp_colour = 50:yellow, 25:red
# stat_colour = 1:lightred, 3:red
# status_caption_colour = yellow
# clear_messages = true
# small_more = true
# show_more = false
# show_inventory_weights = (drop_pickup | true | false)
# show_newturn_mark = false
# show_gold_turns = false
# show_game_turns = false
# item_stack_summary_minimum = 4
# mlist_min_height = 4
# mlist_allow_alternate_layout = true
# mlist_targeting = true
# msg_min_height = 7
# msg_max_height = 10
# messages_at_top = true
# msg_condense_repeats = false
# msg_condense_short = false
# skill_focus = false
# show_travel_trail = false (true for online)
# view_delay = 600
# You can also enforce a --more-- prompt for messages
## Avoid wasting turns with aborted actions:
# force_more_message += There are no visible monsters within range
# force_more_message += This wand has no charges
##### 3-j Colours (messages and menus) ##########
#
# Items are colour coded by default as follows:
#
# yellow = useful escape item / preferred food
# darkgrey = cannot be used
# lightred = harmful / cursed and in use
# magenta = dangerous to use / mutagenic
# red = disliked by your deity
# lightgreen = poisonous (food only)
# brown = less nutritious (food only)
# cyan = useful non-combat item
# white = artefact
# lightblue = unidentified magic item
#
# You can change colours by using something like
# menu_colour ^= inventory:magenta:shillelagh
# or ones in pick-up dialogs:
# menu_colour ^= pickup:green:god gift
# Colouring of messages
# Messages are colour coded as follows:
#
# lightred = really important messages
# yellow = significant messages
# lightred = item damaged/destroyed
# darkgrey = boring, message clutter
#
# Notes also use, quite misnamed, menu_colour:
# menu_colour ^= notes:white:Reached XP level
# These lines will suppress extra feedback messages from travel/shift-running.
#
# message_colour ^= mute:monster_warning:
# message_colour ^= mute:You start resting
# message_colour ^= mute:(HP|Magic) restored
# message_colour ^= mute:warning:Not with.*(in view|monsters around)
##### 3-k Firing Commands #######################
#
# fire_items_start = a
# fire_order = launcher, return
# fire_order += javelin / tomahawk / dart / stone / rock / net
# fire_order += inscribed
##### 3-l Channels ##############################
#
# channel.multiturn = mute
##### 3-m Inscriptions ##########################
#
# autoinscribe += bad_item.*potion:!q
# autoinscribe += potion.*mutation:!q
# autoinscribe_cursed = false
# autoinscribe += fruit:!e
# show_god_gift = yes|unident|no
##### 3-n Macro related Options #################
#
# flush.failure = false
# flush.command = true
# flush.message = true
##### 3-o Tile related Options ##################
#
# tile_show_items = !?/%=([)x}:|\
# tile_skip_title = true
# tile_menu_icons = false
### The following lines define the colours of various objects within the
### tiles minimap. See options_guide.txt for more details.
# tile_player_col = white
# tile_monster_col = #660000
# tile_neutral_col = #660000
# tile_peaceful_col = #664400
# tile_friendly_col = #664400
# tile_plant_col = #446633
# tile_item_col = #005544
# tile_unseen_col = black
# tile_floor_col = #333333
# tile_wall_col = #666666
# tile_mapped_floor_col = #222266
# tile_mapped_wall_col = #444499
# tile_door_col = #775544
# tile_downstairs_col = #ff00ff
# tile_upstairs_col = cyan
# tile_branchstairs_col = #ff7788
# tile_portal_col = #ffdd00
# tile_feature_col = #997700
# tile_trap_col = #aa6644
# tile_water_col = #114455
# tile_deep_water_col = #001122
# tile_lava_col = #552211
# tile_excluded_col = #552266
# tile_excl_centre_col = #552266
# tile_window_col = #558855
# If Crawl's response rate is too slow, try increasing the update rate.
# tile_update_rate = 1000
# If Crawl is lagging when running or resting, try increasing this number.
# tile_runrest_rate = 100
# tile_key_repeat_delay = 200
# tile_tooltip_ms = 500
# tile_tag_pref = enemy
### Note: setting window, map or font sizes to '0' implies auto-sizing.
# tile_full_screen = true
# tile_window_width = 1024
# tile_window_height = 768
# tile_use_small_layout = true
# tile_map_pixels = 3
# tile_cell_pixels = 32
# tile_filter_scaling = true
# tile_force_overlay = true
# tile_layout_priority = minimap, inventory, gold_turn, command, spell
# tile_layout_priority += ability, monster
# tile_font_crt_file = VeraMono.ttf
# tile_font_stat_file = VeraMono.ttf
# tile_font_msg_file = VeraMono.ttf
# tile_font_tip_file = VeraMono.ttf
# tile_font_lbl_file = Vera.ttf
# tile_font_ft_light = false
# tile_font_crt_size = 15
# tile_font_stat_size = 16
# tile_font_msg_size = 14
# tile_font_tip_size = 15
# tile_font_lbl_size = 14
# tile_show_minihealthbar = false
# tile_show_minimagicbar = false
# tile_show_demon_tier = false
# tile_water_anim = false
# tile_misc_anim = false
### WebTiles only
# tile_font_crt_family = monospace
# tile_font_stat_family = monospace
# tile_font_msg_family = monospace
# tile_font_lbl_family = monospace
# tile_realtime_anim = true
# tile_display_mode = glyph
# tile_level_map_hide_messages = false
# tile_level_map_hide_sidebar = true
##### 4- Dump File #################################################
#
##### 4-a Saving ################################
#
# dump_on_save = false
##### 4-b Items and Kill List ###################
#
# kill_map = friend:you, other:you
# dump_kill_places = (single | all | none)
# dump_kill_breakdowns = true
# dump_item_origins = all,artifacts,ego_arm,ego_weap,jewellery,runes
# dump_item_origin_price = -1
# dump_message_count = 20
# dump_order = header, hiscore, stats, misc, notes, inventory,
# dump_order += turns_by_place, skills, spells, overview, mutations,
# dump_order += messages, screenshot, monlist, kills_by_place, kills
# dump_order += action_counts
# dump_book_spells = false
##### 4-c Notes #################################
#
# user_note_prefix=@@@
# note_hp_percent = 5
# note_skill_levels = 1,5,10,15,27
# note_all_skill_levels = true
# note_skill_max = false
# note_xom_effects = false
# note_chat_messages = false
# note_items += rod of, acquirement, preservation, running, of Zot
# note_monsters += orb of fire, ancient lich, Sigmund
##### 5- Miscellaneous #############################################
#
##### 5-a All OS ################################
#
# mouse_input = true
# wiz_mode = no
# char_set = ascii
# use_fake_player_cursor = false
#
# Translation to use (descriptions only for now).
# language = pl|fr|zh|ko|fi|ru|el|da|li|pt|de|lv|cs|hu
#
# Joke translations (complete!).
# language = dwarven|jagerkin|kraut|runes|wide|grunt
#
# colour.lightgray = black
# colour.lightcyan = cyan
# colour.yellow = brown
#
# show_player_species = true
# See options_guide.txt for the options
# cset, feature, mon_glyph, item_glyph
## Highlight the edge of unexplored terrain.
# feature = explore horizon {',,green}
##### 5-b Windows console #######################
#
# dos_use_background_intensity = true
# background = black
##### 5-c Unix console ##########################
#
# use_fake_cursor = false
##### 5-d Alternative keybinding files ##########
#
# Alternative vi bindings for Dvorak users.
# include = dvorak_command_keys.txt
#
# Alternative vi bindings for Colemak users.
# include = colemak_command_keys.txt
#
# Override the vi movement keys with a non-command.
# include = no_vi_command_keys.txt