# DCSS 0.26 ############################################################################ # options # ############################################################################ # prevents accidental resting or abilities bindkey = [s] CMD_NO_CMD_DEFAULT bindkey = [p] CMD_NO_CMD_DEFAULT # prevents accidental movement #bindkey = [y] CMD_NO_CMD_DEFAULT #bindkey = [n] CMD_NO_CMD_DEFAULT #bindkey = [b] CMD_NO_CMD_DEFAULT #bindkey = [c] CMD_NO_CMD_DEFAULT #bindkey = [Y] CMD_NO_CMD_DEFAULT #bindkey = [N] CMD_NO_CMD_DEFAULT #bindkey = [B] CMD_NO_CMD_DEFAULT #bindkey = [C] CMD_NO_CMD_DEFAULT # speeds up gameplay travel_delay = -1 travel_key_stop = false show_travel_trail = false rest_delay = -1 explore_auto_rest = true rest_wait_both = true show_more = false easy_confirm = all # other options automagic_enable = true autofight_stop = 0 force_more_message += flicker back into view force_more_message += you miscast force_more_message += know that spell force_more_message += resists force_more_message += struggles to resist force_more_message += calcifying dust hits you force_more_message += unable to access your magic force_more_message += too confused to cast spells force_more_message += wracked with pain force_more_message += powers of darkness force_more_message += horrible wounds force_more_message += smites you force_more_message += back at you force_more_message += transformation is almost over force_more_message += back to life force_more_message += magic feels tainted force_more_message += winds around you calm down force_more_message += translocation energy dissipates force_more_message += mighty Pandemonium lord force_more_message += grow feeble force_more_message += are being watched #force_more_message += feel yourself slow down runrest_stop_message += transformation is almost over runrest_stop_message += back to life explore_stop = stairs, shops, altars, portals, branches, runed_doors explore_stop += greedy_pickup #autopickup_exceptions += brilliance, holy word, silence #autopickup_exceptions += polymorph, random effects autopickup_exceptions += 0 then : local channel = nil : local message = "Danger: " : message = message .. math.floor(100 * threat_level / 16) .. "%" : message = message .. " (" .. math.floor(hp_percent()) .. "% health)" : if threat_level >= 2 ^ 4 then : channel = 6 : end : print(message, channel) : if scary_monster_present() then : print_scary_monsters() : end : if scary_weapon_present() then : print_scary_weapons() : end : end : if running then : crawl.more_autoclear(true) : if is_safe() then : explore() : else : if must_berserk() then : crawl.sendkeys("aa") : return : end : tab() : end : else : crawl.more_autoclear(false) : end :end :function step() : if not running then : running = true : run() : running = false : end :end ############################################################################ # exploration # ############################################################################ :function must_rest() : return is_after_berserk() or : hp_percent() < 100 or : mp_percent() < 100 or : you.slowed() or : you.confused() or : you.status("barbed spikes") :end :function is_after_berserk() : return you.status("berserk cooldown") :end :function explore() : if is_safe() then : if you.berserk() or must_rest() then : crawl.sendkeys("5") : return : end : if remove_curse() then : return : end : if ready_to_identify_items() and identify_items() then : return : end : if upgrade_equipment() then : return : end : if remove_dangerous() then : return : end : if drop_junk() then : return : end : else : running = false : end : crawl.sendkeys("o") :end ############################################################################ # combat # ############################################################################ :function tab() : if hp_percent() <= 50 then : print("You are too injured to fight recklessly!") : return : end : crawl.sendkeys(string.char(9)) :end :function five() : if must_rest() or : crawl.yesno("Are you sure you want to wait?", true, "n") then : crawl.sendkeys("5") : end :end :function must_berserk() : if is_safe() or berserk_disabled() then : return false : end : if threat(1) == 0 then : return false : end : if threat() >= 2 ^ 3 or hp_percent() <= 75 or you.poisoned() then : return true : end : return false :end :function berserk_disabled() : return you.berserk() or you.status("berserk cooldown") :end :function is_scared() : if you.poison_survival() < 1 or : you.caught() then : return true : end : if not is_safe() then : if scary_monster_present() then : return true : end : if scary_weapon_present() then : return true : end : if you.status("barbed spikes") then : return false : end : if is_after_berserk() then : return threat() >= 2 ^ 2 or hp_percent() <= 75 : end : return threat() >= 2 ^ 4 or hp_percent() <= 50 : end : return false :end :function is_scary_monster(target) : if target.is_unique(target) or : has_spell(target, "Symbol of Torment") or : has_spell(target, "Flay") then : return true : end : local names = { : -- acid : "oklob plant", : -- electric : "electric eel", : "shock serpent", : -- paralysis : "floating eye", : "basilisk", : "dream sheep", : "catoblepas", : -- torment : "lurking horror", : -- misc : "hydra", : "manticore", : "killer bee" : } : for _, name in ipairs(names) do : if target.name(target):find(name) then : return true : end : end : return false :end :function scary_monster_present() : return table.getn(scary_monsters()) > 0 :end :function scary_monsters() : local result = {} : for a = -8, 8 do : for b = -8, 8 do : c = monster.get_monster_at(a, b) : if c and not c.is_safe(c) and is_scary_monster(c) then : result[table.getn(result) + 1] = c : end : end : end : return result :end :function print_scary_monsters() : for _, monster in ipairs(scary_monsters()) do : print(monster.name(monster) .. " is dangerous!", 6) : end :end :function has_spell(monster, name) : for _, book in ipairs(monster.spells(monster)) do : for _, spell in ipairs(book) do : if spell:find(name) then : return true : end : end : end : return false :end :function has_electrocution_weapon(monster) : if monster.desc(c, true):find("of electrocution%.") then : return true : end : return false :end :function has_distortion_weapon(monster) : if monster.desc(c, true):find("of distortion%.") then : return true : end : return false :end :function scary_weapons() : local result = {} : for a = -8, 8 do : for b = -8, 8 do : c = monster.get_monster_at(a, b) : if c then : if has_electrocution_weapon(c) then : result[table.getn(result) + 1] = c.name(c) .. " has electrocution!" : end : if has_distortion_weapon(c) then : result[table.getn(result) + 1] = c.name(c) .. " has distortion!" : end : end : end : end : return result :end :function scary_weapon_present() : return table.getn(scary_weapons()) > 0 :end :function print_scary_weapons() : for _, message in ipairs(scary_weapons()) do : print(message, 6) : end :end :function threat(radius) : radius = radius or 8 : local result = 0 : for a = -radius, radius do : for b = -radius, radius do : c = monster.get_monster_at(a, b) : if c and not c.is_safe(c) then : result = result + calculate_threat(c) : end : end : end : return result :end :function calculate_threat(target) : local big_threats = { : "adder", : "ogre", : "ugly thing" : } : for _, threat in ipairs(big_threats) do : if target.name(target):find(threat) then : return 2 ^ (target.threat(target) + 1) : end : end : return 2 ^ target.threat(target) :end :function is_safe() : for a = -8,8 do : for b = -8,8 do : c = monster.get_monster_at(a, b) : if c and not c.is_safe(c) then : return false : end : end : end : return true :end :function hp_percent() : a, b = you.hp() : a = you.poison_survival() or a : return 100 * a / b :end :function mp_percent() : a, b = you.mp() : return 100 * a / b :end ############################################################################ # item dropping # ############################################################################ :function drop(item) : local letter = items.index_to_letter(item.slot) : crawl.sendkeys("d" .. letter .. string.char(13)) :end :function can_drop_if_burdened(item) : if item.class(true) == "wand" then : return not (item.subtype() == "digging") : end : return false :end :function drop_junk() : for item in inventory() do : if is_junk(item) then : if not (item.cursed and item.equipped) then : drop(item) : return true : end : end : end : return false :end :function is_junk_weapon(item) : if item.class(true) == "weapon" then : for other in inventory() do : if compare_weapons(item, other) < 0 then : return true : end : end : end : return false :end :function is_junk_armour(item) : if item.subtype() == "body" then : local equipped = items.equipped_at("Armour") : if equipped and is_scales(equipped) then : return true : end : end : if item.class(true) == "armour" and not item.branded then : for other in inventory() do : if compare_armour(item, other) < 0 then : return true : end : end : end : return false :end :function is_junk_amulet(item) : if is_amulet(item) then : if item.subtype() == "amulet of inaccuracy" then : return true : end : for other in inventory() do : if compare_amulets(item, other) < 0 then : return true : end : end : end : return false :end :function is_junk_ring(item) : if is_ring(item) then : if item.subtype() == "ring of teleportation" or : item.subtype() == "ring of attention" then : return true : end : if item.plus and item.plus < 0 then : return true : end : end : return false :end :function is_dangerous(item) : if is_ring(item) then : return item.subtype() == "ring of fire" or : item.subtype() == "ring of ice" : end : return false :end # rings are not supported yet :function is_junk_ring2(item) : local good_rings = { : "ring of evasion", : "ring of poison resistance", : "ring of positive energy", : "ring of protection", : "ring of protection from cold", : "ring of protection from fire", : "ring of resist corrosion", : "ring of see invisible", : "ring of slaying", : "ring of willpower" : } : if is_ring(item) and : item.subtype() and : not item.artefact then : if item.plus and item.plus < 0 then : return true : end : for _, subtype in ipairs(good_rings) do : if item.subtype() == subtype then : return false : end : end : return true : end : return false :end :function is_junk(item) : if is_junk_weapon(item) or : is_junk_armour(item) or : is_junk_amulet(item) or : is_junk_ring(item) or : unneeded_duplicate(item) then : return true : end : if burdened() and can_drop_if_burdened(item) then : return true : end : -- todo: add an is_junk_cloak : local junk_egos = { : "harm" : } : local junk_subtypes = { : "attraction", : "degeneration", : "lignification", : --"brilliance", : --"holy word", : --"silence", : "immolation", : "noise", : "random uselessness", : "torment", : "vulnerability" : } : for _, ego in ipairs(junk_egos) do : if item.ego(true) == ego then : return true : end : end : for _, subtype in ipairs(junk_subtypes) do : if item.subtype() == subtype then : return true : end : end : return false :end ############################################################################ # autopickup # ############################################################################ :function unneeded_duplicate(item) : if item.artefact then : return false : end : if item.subtype() == "phantom mirror" then : for other in inventory() do : if other.subtype() == item.subtype() and : not (item.slot == other.slot) then : return true : end : end : end : return false :end # duplicate detection is not supported yet :function unneeded_duplicate2(item) : if item.artefact then : return false : end : if item.class(true) == "jewellery" and item.subtype() or : item.subtype() == "phantom mirror" then : for other in inventory() do : if item.subtype() == other.subtype() and : not (item.slot == other.slot) then : return true : end : end : end : return false :end :function want_weapon(item) : if item.subtype() == "hand axe" then : -- avoids early cursed hand axes : return false : end : if item.class(true) == "weapon" and : not is_useless(item) then : local best = best_damage(item.weap_skill) : if item.damage > best then : return true : end : if item.damage == best then : return item.branded : end : end : return false :end :function want_armour(item) : if item.class(true) == "armour" and : not is_useless(item) and : not is_scales(item) then : local best = best_ac(item.subtype()) : if item.ac > best then : return true : end : if item.subtype() == "helmet" or : item.subtype() == "cloak" or : item.damage == best then : return item.branded : end : end : return false :end :function want_book(item) : return item.class(true) == "book" and not item.is_useless :end :function autopickup(item, name) : if unneeded_duplicate(item) or : is_useless(item) or : is_junk_ring(item) then : return false : end : if burdened() and can_drop_if_burdened(item) then : return false : end : if item.artefact then : return true : end : if want_book(item) then : return true : end : if want_weapon(item) then : return true : end : if want_armour(item) then : return true : end :end :add_autopickup_func(autopickup) ############################################################################ # curse removal # ############################################################################ :function scroll_of_remove_curse_letter() : for item in inventory() do : if item.class(true) == "scroll" and : item.subtype() == "remove curse" then : return items.index_to_letter(item.slot) : end : end :end :function remove_curse() : local rc_letter = scroll_of_remove_curse_letter() : if rc_letter then : for item in inventory() do : if item.cursed and item.equipped then : return read_scroll(rc_letter) : end : end : end : return false :end ############################################################################ # item identification # ############################################################################ :function scroll_of_identify_letter() : for item in inventory() do : if item.class(true) == "scroll" and item.subtype() == "identify" then : return items.index_to_letter(item.slot) : end : end :end :function ready_to_identify_items() : if scroll_of_identify_letter() then : return true : end : for item in inventory() do : if want_to_identify(item) then : return true : end : end : return false :end :function want_to_identify(item) : if not item.fully_identified then : if faith_equipped() and is_amulet(item) then : return true : end : if item.class(true) == "potion" then : return true : end : if item.class(true) == "scroll" and : scroll_of_identify_quantity() > 5 then : return true : end : end : return false :end :function scroll_of_identify_quantity() : for item in inventory() do : if item.class(true) == "scroll" and item.subtype() == "identify" then : return item.quantity : end : end : return 0 :end :function identify_items() : local id_letter = scroll_of_identify_letter() : for item in inventory() do : if item.class(true) == "scroll" and : not item.fully_identified and : item.quantity > 1 then : return read_scroll(items.index_to_letter(item.slot)) : end : if want_to_identify(item) and not item.artefact and id_letter then : return read_scroll(id_letter .. items.index_to_letter(item.slot)) : end : end : return false :end ############################################################################ # item utility # ############################################################################ :function inventory() : return iter.invent_iterator:new(items.inventory()) :end :function burdened() : return table.getn(items.inventory()) > 47 :end :function read_scroll(letter) : if you.silenced() then : return false : end : crawl.sendkeys("r" .. letter) : return true :end ############################################################################ # equipment utility # ############################################################################ :function uses_weapon_skill(item) : return item.class(true) == "weapon" and item.weap_skill == "Axes" :end :function is_amulet(item) : if item.class(true) == "jewellery" then : return item.name():find("amulet") or item.name():find("necklace") : end : return false :end :function is_ring(item) : if item.class(true) == "jewellery" then : return item.name():find("ring") : end : return false :end :function is_scales(item) : return item.name():find("scales") :end :function compare_amulets(left, right) : -- todo: handle artefacts : if left.artefact or right.artefact then : return 0 : end : if not is_amulet(left) or not is_amulet(right) then : return 0 : end : if not left.fully_identified or not right.fully_identified then : return 0 : end : return compare(amulet_level(left), amulet_level(right)) :end :function amulet_level(amulet) : if amulet.subtype() == "amulet of regeneration" then : return 6 : end : if amulet.subtype() == "amulet of guardian spirit" then : return 5 : end : if amulet.subtype() == "amulet of faith" then : return 4 : end : if amulet.subtype() == "amulet of reflection" then : return 3 : end : if amulet.subtype() == "amulet of the acrobat" then : return 2 : end : if amulet.subtype() == "amulet of magic regeneration" then : return 1 : end : return 0 :end :function compare_rings(left, right) : -- todo: handle artefacts : if left.artefact or right.artefact then : return 0 : end : if not is_ring(left) or not is_ring(right) then : return 0 : end : if not left.fully_identified or not right.fully_identified then : return 0 : end : return compare(ring_level(left), ring_level(right)) :end :function ring_level(ring) : -- todo: add better ring logic : if ring.subtype() == "ring of see invisible" then : return 0 : end : if ring.subtype() == "ring of poison resistance" then : return 0 : end : if ring.subtype() == "ring of protection from fire" then : return 0 : end : if ring.subtype() == "ring of protection from cold" then : return 0 : end : if ring.subtype() == "ring of resist corrosion" then : return 0 : end : if ring.subtype() == "ring of positive energy" then : return 0 : end : if ring.subtype() == "ring of slaying" then : return 7 : end : if ring.subtype() == "ring of protection" then : return 6 : end : if ring.subtype() == "ring of evasion" then : return 5 : end : if ring.subtype() == "ring of willpower" then : return 4 : end : if ring.subtype() == "ring of stealth" then : return 3 : end : if ring.subtype() == "ring of strength" then : return 2 : end : if ring.subtype() == "ring of dexterity" then : return 1 : end : -- flight, magical power, wizardry, intelligence, fire, ice : return 0 :end :function faith_equipped() : local amulet = items.equipped_at("Amulet") : return amulet and amulet.subtype() == "amulet of faith" :end :function equip_ring(item, letter) : if is_ring(item) then : if is_ring_missing() then : return item.puton() : end : local left = items.equipped_at("Left Ring") : local right = items.equipped_at("Right Ring") : if left.cursed and right.cursed then : return false : end : if left.cursed or right.cursed then : return item.puton() : end : if compare_rings(left, right) > 0 then : letter = letter or items.index_to_letter(right.slot) : else : letter = letter or items.index_to_letter(left.slot) : end : crawl.sendkeys("P" .. items.index_to_letter(item.slot) .. letter) : return true : end : return false :end :function is_ring_missing() : local left = items.equipped_at("Left Ring") : local right = items.equipped_at("Right Ring") : return not left or not right :end :function equipped_at(subtype) : local translations = { : cloak = "Cloak", : helmet = "Helmet", : gloves = "Gloves", : boots = "Boots", : body = "Armour", : shield = "Shield" : } : return items.equipped_at(translations[subtype]) :end :function is_useless(item) : if item.class(true) == "armour" then : return item.subtype() == "shield" or item.name():find("barding") : end : if item.class(true) == "weapon" then : return not uses_weapon_skill(item) : end : return false :end :function upgrade_equipment() : for item in inventory() do : if not item.equipped and : not item.artefact and : not is_dangerous(item) and : not is_useless(item) and : not is_junk(item) then : if item.class(true) == "weapon" then : local equipped = items.equipped_at("Weapon") : if not equipped or : not item.fully_identified or : compare_weapons(item, equipped) > 0 then : if not (equipped and equipped.cursed) and : item.wield() then : return true : end : end : end : if item.class(true) == "armour" then : local equipped = equipped_at(item.subtype()) : if not equipped or : not item.fully_identified or : compare_armour(item, equipped) > 0 then : if not (equipped and equipped.cursed) and : item.wear() then : return true : end : end : end : if is_amulet(item) then : local equipped = items.equipped_at("Amulet") : if not equipped or : not item.fully_identified and not faith_equipped() or : compare_amulets(item, equipped) > 0 then : if not (equipped and equipped.cursed) and : item.puton() then : return true : end : end : end : -- rings are not fully supported yet : if is_ring(item) then : if is_ring_missing() or : not item.fully_identified then : if not item.equipped and : equip_ring(item) then : return true : end : end : local left = items.equipped_at("Left Ring") : if not (left and left.cursed) and : compare_rings(item, left) > 0 and : equip_ring(item) then : return true : end : local right = items.equipped_at("Right Ring") : if not (right and right.cursed) and : compare_rings(item, right) > 0 and : equip_ring(item) then : return true : end : end : end : end : return false :end :function remove_dangerous() : for item in inventory() do : if item.equipped and not item.cursed and is_dangerous(item) then : if item.remove() then : return true : end : end : end : return false :end ############################################################################ # weapon and armour utility # ############################################################################ :function compare_weapons(left, right) : -- todo: handle artefacts : -- todo: handle egos : if left.artefact or right.artefact then : return 0 : end : if left.is_useless or right.is_useless then : return 0 : end : if not left.class(true) == "weapon" or : not right.class(true) == "weapon" then : return 0 : end : if not (left.weap_skill == right.weap_skill) then : return 0 : end : if not left.fully_identified or not right.fully_identified then : return 0 : end : return compare(left.damage + left.plus, right.damage + right.plus) :end :function compare_armour(left, right) : -- todo: handle artefacts : -- todo: handle egos : if left.artefact or right.artefact then : return 0 : end : if left.is_useless or right.is_useless then : return 0 : end : if not left.class(true) == "armour" or : not right.class(true) == "armour" then : return 0 : end : if not (left.subtype() == right.subtype()) then : return 0 : end : if not left.fully_identified or not right.fully_identified then : return 0 : end : if is_scales(left) or is_scales(right) then : return 0 : end : return compare(left.ac + left.plus, right.ac + right.plus) :end :function best_damage(weap_skill) : local result = 0 : for item in inventory() do : if item.weap_skill == weap_skill and item.damage > result then : result = item.damage : end : end : return result :end :function best_ac(subtype) : local result = 0 : for item in inventory() do : if item.subtype() == subtype and item.ac > result then : result = item.ac : end : end : return result :end ############################################################################ # general utility # ############################################################################ :function in_last_message(message, count) : count = count or 1 : return crawl.messages(count):find(message) :end :function print(value, channel) : crawl.mpr(tostring(value), channel) :end :function compare(left, right) : if left < right then : return -1 : end : if left > right then : return 1 : end : return 0 :end ############################################################################ # hooks # ############################################################################ :function c_answer_prompt(prompt) : if prompt:find("Keep disrobing") or prompt:find("Keep equipping") then : return false : end : if prompt:find("Really unwield") or : prompt:find("Really take off") or : prompt:find("Really remove") or : prompt:find("Really wield") or : prompt:find("Really wear") or : prompt:find("Really put on") then : return true : end :end :function choose_stat_gain() : return "i" :end ############################################################################ # debug # ############################################################################ macros += M c ===debug :function debug() : for item in inventory() do : print(item.subtype()) : end :end