Last active
January 25, 2017 20:44
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how well did it fare?