show_more = false default_manual_training = true equip_unequip = true autofight_stop = 70 fail_severity_to_confirm = 0 fail_severity_to_quiver = 5 # explore_delay = 24 # tile_player_tile = tile:felid_4 force_more_message += forbidden knowledge force_more_message += mollified record_wtrec = true macros += M 1 ==za macros += M 2 ==zb macros += M 3 ==zc macros += M 4 ==zd macros += M 5 ==ze macros += M 6 ==zf macros += M 7 ==zg macros += M 8 ==zh macros += M 9 ==zi macros += M c ==i macros += M e *f.\{13} macros += M \{-1016} o macros += M 0 ===evaluate_melee # ctrl-L to open the description of the most recently picked up spell macros += M \{12} ===spell_search { function spell_search() local s = crawl.messages(1000) local found_spell for line in s:gmatch("[^\n]+") do local spell_name = line:match("^You add the spell (.*) to your library.$") if spell_name then found_spell = spell_name end end if found_spell then crawl.sendkeys("?/s"..found_spell.."\r") end end } { -- Minimal, self-contained melee evaluation (no autocast bits) local detailed_aveffdam = false local monster_ac = {} -- optional: fill with known ACs to refine guess_ac() function bpr(message) crawl.mpr(tostring(message)) end function melee_evasion_check(m) local s = m:target_weapon() local i = string.find(s, "%% to hit") if i ~= nil then local pct = string.sub(s, i-3, i-1) if tonumber(pct) == nil then pct = string.sub(s, i-2, i-1) end if tonumber(pct) == nil then pct = string.sub(s, i-1, i-1) end return tonumber(pct) * 0.01 end return 1.0 end function melee_attack_delay(weapon) local delay if weapon == nil then delay = 1.0 - 0.5 * you.skill("unarmed combat") / 27 else delay = (weapon.delay - 0.5*you.skill(weapon.weap_skill)) * 0.1 local desc = weapon.description local mindelay_ix = string.find(desc, "minimum attack delay %(") desc = string.sub(desc, mindelay_ix + 22) local ix2 = string.find(desc, "%)") local mindelay = tonumber(string.sub(desc, 1, ix2-1)) if delay < mindelay then delay = mindelay end end local shield = items.equipped_at("offhand", 1) local er = (shield and shield.encumbrance) or 0 local shieldDelay = 0 if er > 0 then shieldDelay = 0.1*er*er*(2/5.0) * (27 - you.skill("shields")) / (27 * (5.0 + you.strength())) end delay = delay + shieldDelay if weapon and string.find(weapon:name(), "quick blade") then delay = delay * 0.5 end return delay end function weapon_enchant(weapon) local n = weapon:name() n = string.sub(n, 2, string.find(n, " ") - 1) return tonumber(n) end function unarmed_plus() local inv = items.inventory() for i = 1,#inv do if inv[i].is_weapon then local plus = weapon_plus(inv[i]) return plus - weapon_enchant(inv[i]) end end bpr("For technical reasons, keep any weapon in inventory to evaluate UC.") return 0 end function weapon_plus(weapon) if weapon == nil then return unarmed_plus() end local desc = weapon.description local skill_ix = string.find(desc, "%(Skill%)") if skill_ix == nil then return 0 end desc = string.sub(desc, skill_ix + 8) local plus_ix = string.find(desc, "+") if plus_ix == nil then return 0 end desc = string.sub(desc, plus_ix + 2) if string.find(desc, "%(") == nil then return 0 end desc = string.sub(desc, 1, string.find(desc, "%(") - 2) return tonumber(desc) end function unarmed_base_damage(plus) local dr = you.unarmed_damage_rating() local strModifier = (75 + you.strength() * 2.5) / 100.0 local fightModifier = (30*100 + math.floor((you.skill("Fighting")*100 + 1) / 2)) / (30*100.0) local result = (dr - plus) / (strModifier * fightModifier) for i=math.floor(result)-1,math.floor(result)+2 do if math.floor(i * strModifier * fightModifier + plus) == dr then return i end end bpr("Could not deduce unarmed base damage.") return 3 end function melee_damage_vs_ac_random(weapon, m, heavyBrand, stat, plus, monster_ac, base_damage, weap_skill, fighting_skill) local damage = base_damage if heavyBrand then damage = damage * 9.0 / 5 end damage = damage * (75 + 2.5 * stat) / 100.0 damage = math.random(0, damage) if weapon then damage = damage * (2500 + math.random(0,100 * weap_skill))/2500.0 end damage = damage * (3000 + math.random(0,100 * fighting_skill))/3000.0 damage = damage + math.random(0, plus) local saved = math.random(0, monster_ac) return math.max(0, damage - saved) end function melee_damage_vs_ac_random_average(weapon, m, brand, iters, monster_ac) local stat if weapon and (weapon.weap_skill == "Short Blades" or weapon.weap_skill == "Long Blades" or weapon.weap_skill == "Ranged Weapons") then stat = you.dexterity() else stat = you.strength() end local plus, base_damage, weap_skill local fighting_skill = you.skill("Fighting") if weapon then plus = weapon_plus(weapon) base_damage = weapon.damage weap_skill = you.skill(weapon.weap_skill) if detailed_aveffdam then bpr("Weapon base damage: " .. base_damage) bpr("Weapon plus: " .. plus) end else plus = unarmed_plus() base_damage = unarmed_base_damage(plus) if detailed_aveffdam then bpr("Unarmed base damage: " .. base_damage) bpr("Unarmed slaying: " .. plus) end end local tot = 0 for i=1,iters do tot = tot + melee_damage_vs_ac_random(weapon, m, brand == "Heavy", stat, plus, monster_ac, base_damage, weap_skill, fighting_skill) end return tot / iters end function get_brand(weapon) local brand, has_brand = nil, false if weapon and weapon.branded then has_brand = true local name = weapon:name() local ix_of = string.find(name, " of ") if ix_of then brand = string.sub(name, ix_of + 4) elseif string.find(name, "vampiric ") then brand = "vampiric" end else brand = you.unarmed_ego() if brand then has_brand = true end end return {brand, has_brand} end function resisted_damage_base(dmg, res, skipres2) if res == 0 then return dmg end if res <= -1 then return dmg*1.5 end if res == 1 then return dmg * 0.5 end if res == 2 then return skipres2 and 0 or dmg * 0.2 end if res == 3 then return 0 end return 0 end function guess_ac(m) local ac_pips = m:ac() -- ceil(real_ac/5) if ac_pips == 0 then return 0 end local known = monster_ac[m:name()] if known and math.ceil(known/5.0) == ac_pips then return known end return 2.5 + (ac_pips - 1) * 5 end function ac_damage_linear(dam1, dam2, ac) local tot, iters = 0, 0 for d = dam1, dam2 do for a = 0, ac do if d > a then tot = tot + d - a end iters = iters + 1 end end return tot / iters end function evaluate_melee_monster(monster) local weapon = items.equipped_at(1,1) local ego, dr if weapon then ego = weapon:ego() dr = weapon:damage_rating() else dr = you:unarmed_damage_rating() ego = you.unarmed_ego() end local tohit = melee_evasion_check(monster) local m_ac = guess_ac(monster) local mname = monster:name() local brandhasbrand = get_brand(weapon) local brand = brandhasbrand[1] local has_brand = brandhasbrand[2] local dam_after_ac = melee_damage_vs_ac_random_average(weapon, monster, brand, 1000, m_ac) local delay = melee_attack_delay(weapon) local aveffdam = dam_after_ac * tohit / delay if detailed_aveffdam then bpr(mname .. " ac: " .. m_ac .. ", hit%: " .. tohit .. ", dmg/hit: " .. dam_after_ac) bpr("Your attack delay: " .. delay) bpr("Damage per 10 auts (pre-brand): " .. aveffdam) end local brand_damage = aveffdam if has_brand then if brand == "freezing" then brand_damage = aveffdam + resisted_damage_base(0.25 * aveffdam, monster:res_cold(), false) elseif brand == "flaming" then brand_damage = aveffdam + resisted_damage_base(0.25 * aveffdam, monster:res_fire(), false) elseif brand == "holy wrath" then local holyMult = (monster:holiness("demonic") or monster:holiness("undead")) and 1 or 0 brand_damage = aveffdam + 0.75*aveffdam*holyMult elseif brand == "draining" then if monster:res_draining() > 0 then brand_damage = 1.5 * tohit / delay + aveffdam*1.125 end elseif brand == "electrocution" then local elecDmg = 0.25 * resisted_damage_base(ac_damage_linear(8, 20, m_ac/2), monster:res_shock(), false) brand_damage = aveffdam + elecDmg*tohit/delay elseif brand == "speed" then brand_damage = aveffdam*1.5 end end if brand_damage > 0 then bpr("Damage per 10 auts vs " .. mname .. ": ") crawl.mpr(brand_damage, 5) end end function evaluate_melee() local LOS = you.los() local r_close = LOS+1 local m_close = nil for x = -LOS,LOS do for y = -LOS,LOS do local m = monster.get_monster_at(x, y) local r = math.max(math.abs(x), math.abs(y)) if m ~= nil and m:attitude() == 0 and not m:is_firewood() and r < r_close then r_close = r m_close = m end end end if m_close ~= nil then evaluate_melee_monster(m_close) else bpr("No monster in sight") end end } # end lua block