##### Crawl Init file ###############################################
# For descriptions of all options, as well as some more in-depth information
# on setting them, consult the file
# options_guide.txt
# in your /docs directory. If you can't find it, the file is also available
# online at:
# https://github.com/crawl/crawl/blob/master/crawl-ref/docs/options_guide.txt
#
# Crawl uses the first file of the following list as its option file:
# * init.txt in the -rcdir directory (if specified)
# * .crawlrc in the -rcdir directory (if specified)
# * init.txt (in the Crawl directory)
# * ~/.crawl/init.txt (Unix only)
# * ~/.crawlrc (Unix only)
# * ~/init.txt (Unix only)
# * settings/init.txt (in the Crawl directory)
##### Some basic explanation of option syntax #######################
# Lines beginning with '#' are comments. The basic syntax is:
#
# field = value or field.subfield = value
#
# Only one specification is allowed per line.
#
# The terms are typically case-insensitive except in the fairly obvious
# cases (the character's name and specifying files or directories when
# on a system that has case-sensitive filenames).
#
# White space is stripped from the beginning and end of the line, as
# well as immediately before and after the '='. If the option allows
# multiple comma/semicolon-separated terms (such as
# autopickup_exceptions), all whitespace around the separator is also
# trimmed. All other whitespace is left intact.
#
# There are three broad types of Crawl options: true/false values (booleans),
# arbitrary values, and lists of values. The first two types use only the
# simple =, with later options - which includes your options that are different
# from the defaults - overriding earlier ones. List options allow using +=, ^=,
# -=, and = to append, prepend, remove, and reset, respectively. Usually you will
# want to use += to add to a list option. Lastly, there is := which you can use
# to create an alias, like so:
# ae := autopickup_exceptions
# From there on, 'ae' will be treated as if it you typed autopickup_exceptions,
# so you can save time typing it.
#
##### Other files ###################################################
# You can include other files from your options file using the 'include'
# option. Crawl will treat it as if you copied the whole text of that file
# into your options file in that spot. You can uncomment some of the following
# lines by removing the beginning '#' to include some of the other files in
# this folder.
# Some useful, more advanced options, implemented in LUA.
# include = advanced_optioneering.txt
# Alternative vi bindings for Dvorak users.
# include = dvorak_command_keys.txt
# Alternative vi bindings for Colemak users.
# include = colemak_command_keys.txt
# Alternative vi bindings for Neo users.
# include = neo_command_keys.txt
# Override the vi movement keys with a non-command.
# include = no_vi_command_keys.txt
# Turn the shift-vi keys into safe move, instead of run.
# include = safe_move_shift.txt
##### Ancient versions ##############################################
# If you're used to the interface of ancient versions of Crawl, you may
# get back parts of it by uncommenting the following options:
# include = 034_command_keys.txt
# And to revert monster glyph and colouring changes:
# include = 052_monster_glyphs.txt
# include = 060_monster_glyphs.txt
# include = 071_monster_glyphs.txt
# include = 080_monster_glyphs.txt
# include = 0.9_monster_glyphs.txt
# include = 0.12_monster_glyphs.txt
# include = 0.13_monster_glyphs.txt
# include = 0.14_monster_glyphs.txt
autofight_stop = 80
hp_warning = 50
default_manual_training = true
show_more = false
sort_menus = true : equipped, identified, basename, qualname, charged
#################
# Lua Functions #
#################
-----------------------------------------------------------------------------------
-- Armour/Weapon autopickup by rwbarton, enhanced by HDA with fixes from Bloaxor --
-----------------------------------------------------------------------------------
{
add_autopickup_func(function(it, name)
local class = it.class(true)
local armour_slots = {cloak="Cloak", helmet="Helmet", gloves="Gloves", boots="Boots", body="Armour", shield="Shield"}
if (class == "armour") then
if it.is_useless then return false end
sub_type = it.subtype()
equipped_item = items.equipped_at(armour_slots[sub_type])
if (sub_type == "cloak") or (sub_type == "helmet") or (sub_type == "gloves") or (sub_type == "boots") then
if not equipped_item then
return true
else
return it.artefact or it.branded or it.ego
end
end
if (sub_type == "body") then
if equipped_item then
local armourname = equipped_item.name()
if equipped_item.artefact or equipped_item.branded or equipped_item.ego or (equipped_item.plus > 2) or armourname:find("dragon") or armourname:find("troll") then
return it.artefact
else
return it.artefact or it.branded or it.ego
end
end
return true
end
if (sub_type == "shield") then
if equipped_item then
return it.artefact or it.branded or it.ego
end
end
end
end)
}
-------------------------
-- Dynamic Force Mores --
-------------------------
{
last_turn = you.turns()
fm_patterns = {
{name = "XL5", cond = "xl", cutoff = 5, pattern = "adder|gnoll"},
-- {name = "XL8", cond = "xl", cutoff = 8, pattern = "ogre|centaur|orc wizard|scorpion|worker ant"},
-- {name = "XL15", cond = "xl", cutoff = 15, pattern = "two-headed ogre|centaur warrior|orc (warlord|knight)"},
-- {name = "50mhp", cond = "maxhp", cutoff = 50, pattern = "orc priest|electric eel"},
-- {name = "60mhp", cond = "maxhp", cutoff = 60, pattern = "acid dragon|steam dragon|manticore"},
-- {name = "70mhp", cond = "maxhp", cutoff = 70, pattern = "meliai"}
} -- end fm_patterns
active_fm = {}
-- Set to true to get a message when the fm change
notify_fm = false
function init_force_mores()
for i,v in ipairs(fm_patterns) do
active_fm[#active_fm + 1] = false
end
end
function update_force_mores()
local activated = {}
local deactivated = {}
local hp, maxhp = you.hp()
for i,v in ipairs(fm_patterns) do
local msg = "(" .. v.pattern .. ").*into view"
local action = nil
local fm_name = v.pattern
if v.name then
fm_name = v.name
end
if not v.cond and not active_fm[i] then
action = "+"
elseif v.cond == "xl" then
if active_fm[i] and you.xl() >= v.cutoff then
action = "-"
elseif not active_fm[i] and you.xl() < v.cutoff then
action = "+"
end
elseif v.cond == "rf" then
if active_fm[i] and you.res_fire() >= v.cutoff then
action = "-"
elseif not active_fm[i] and you.res_fire() < v.cutoff then
action = "+"
end
elseif v.cond == "rc" then
if active_fm[i] and you.res_cold() >= v.cutoff then
action = "-"
elseif not active_fm[i] and you.res_cold() < v.cutoff then
action = "+"
end
elseif v.cond == "relec" then
if active_fm[i] and you.res_shock() >= v.cutoff then
action = "-"
elseif not active_fm[i] and you.res_shock() < v.cutoff then
action = "+"
end
elseif v.cond == "rpois" then
if active_fm[i] and you.res_poison() >= v.cutoff then
action = "-"
elseif not active_fm[i] and you.res_poison() < v.cutoff then
action = "+"
end
elseif v.cond == "rcorr" then
if active_fm[i] and you.res_corr() then
action = "-"
elseif not active_fm[i] and not you.res_corr() then
action = "+"
end
elseif v.cond == "rn" then
if active_fm[i] and you.res_draining() >= v.cutoff then
action = "-"
elseif not active_fm[i] and you.res_draining() < v.cutoff then
action = "+"
end
elseif v.cond == "fly" then
if active_fm[i] and not you.flying() then
action = "-"
elseif not active_fm[i] and you.flying() then
action = "+"
end
elseif v.cond == "mhp" then
if active_fm[i] and maxhp >= v.cutoff then
action = "-"
elseif not active_fm[i] and maxhp < v.cutoff then
action = "+"
end
end
if action == "+" then
activated[#activated + 1] = fm_name
elseif action == "-" then
deactivated[#deactivated + 1] = fm_name
end
if action ~= nil then
local opt = "force_more_message " .. action .. "= " .. msg
crawl.setopt(opt)
active_fm[i] = not active_fm[i]
end
end
if #activated > 0 and notify_fm then
mpr("Activating force_mores: " .. table.concat(activated, ", "))
end
if #deactivated > 0 and notify_fm then
mpr("Deactivating force_mores: " .. table.concat(deactivated, ", "))
end
end
local last_turn = nil
function force_mores()
if last_turn ~= you.turns() then
update_force_mores()
last_turn = you.turns()
end
end
init_force_mores()
}
##################
# Ready Function #
##################
{
local need_skills_opened = true
function ready()
force_mores()
-- Skill menu at game start by rwbarton
if you.turns() == 0 and need_skills_opened then
need_skills_opened = false
crawl.sendkeys("m")
end
end
}
#######################
# Compare Best Weapon #
#######################
{
function c_message(text, channel)
if string.match(text, "!checkdmg") then
local item = items.equipped_at(0)
if item == nil or is_valid_weapon(item) then
display_damage(item)
else
display_line("No valid weapon equipped...", "magenta")
end
end
if string.match(text, "!bestwep") then
compare_damage()
end
end
function is_valid_weapon(item)
return item:class() == "Hand Weapons" or item:class() == "Magical Staves"
end
function is_staff(item)
return string.match(item:class(), "Magical Staves") ~= nil
end
function unarmed_data()
local base_damage = 3
local claws_level = you.get_base_mutation_level("claws")
local skill = you.skill("Unarmed Combat")
local item =
{ damage = (base_damage + 2 * claws_level) + skill,
ego = function() return nil end,
name = function() return "Unarmed" end,
name_coloured = function() return "Unarmed" end,
subtype = function() return "Unarmed" end,
class = function() return "Hand Weapons" end,
branded = false,
fully_identified = true,
is_useless = false,
weap_skill = "Unarmed Combat",
accuracy = 0,
plus = 0,
delay = 10 - 1 * (skill / 5.4),
is_unarmed = true, }
return item
end
function compare_damage()
display_line("Comparing items in your inventory and under your feet...")
display_line("Fighting against imaginary ogres...", "darkgray")
local highest_base_damage = 0
local highest_total_damage = 0
local highest_base_damage_weapon
local highest_total_damage_weapon
local items_ = items.inventory()
local weapons = { unarmed_data() }
function get_weapons_from(tab)
if tab ~= nil and tab[0] == nil then
for i, item in ipairs(tab) do
if type(item) == "userdata" then
-- display_line((item))
if is_valid_weapon(item) and item.fully_identified and not (item.is_useless) then -- weapon
table.insert(weapons, item)
end
end
end
end
end
get_weapons_from(items.inventory())
-- display_line(tostring(items.shopping_list()))
get_weapons_from(you.floor_items())
-- get_weapons_from(known_weapons)
-- crawl.mpr(tostring(items.inventory()))
local base_damage_map = {}
local total_damage_map = {}
for i, item in ipairs(weapons) do
-- display_line(weapon:name())
local enemy_stats = { ac = 1, ev = 6 }
enemy_stats.hit_chance = hit_chance(to_hit(item), enemy_stats.ev)
local base_damage = get_dpt(item, enemy_stats, false, false)
local total_damage = (item.branded or is_staff(item)) and get_dpt(item, enemy_stats, true, false) or base_damage
-- display_line(tostring(base_damage) .. " " .. tostring(total_damage))
-- item.base_damage = base_damage
-- item.total_damage = total_damage
base_damage_map[item] = base_damage
total_damage_map[item] = total_damage
if base_damage >= highest_base_damage then
highest_base_damage = base_damage
highest_base_damage_weapon = item
end
if total_damage >= highest_total_damage then
highest_total_damage = total_damage
highest_total_damage_weapon = item
end
end
-- display_line("Highest damage: " .. highest_base_damage_weapon:name_coloured() .. " at " .. fmt_num(highest_base_damage) .. " damage per 1.0 AUTs", "white")
display_line("Highest total (branded) damage: " .. highest_total_damage_weapon:name_coloured() .. " at " .. fmt_num(base_damage_map[highest_total_damage_weapon]) .. " / " .. fmt_num(total_damage_map[highest_total_damage_weapon]) .. " damage per 1.0 AUTs", "white")
crawl.more()
function sort_predicate(a, b)
return total_damage_map[a] > total_damage_map[b]
end
table.sort(weapons, sort_predicate)
for i, item in ipairs(weapons) do
if i > 1 then
local damage = fmt_num(base_damage_map[item]) .. " / " .. fmt_num(total_damage_map[item])
display_line(tostring(i) .. ". " .. item:name_coloured() .. " - " .. damage .. " dmg")
end
end
end
function display_line(text, color)
color = color or "lightgray"
crawl.message("<"..color..">"..text..""..color..">", 0)
end
function display_damage(item)
-- if item == nil then
-- return
-- end
-- display_line(item:class())
item = item or unarmed_data()
local enemy_stats = { ac = 1, ev = 6}
crawl.mpr("Enemy AC (default 1): ", 2)
local ac = tonumber(crawl.c_input_line())
crawl.mpr("Enemy EV (default 6): ", 2)
local ev = tonumber(crawl.c_input_line())
if type(ac) == "number" then
enemy_stats.ac = ac
end
if type(ev) == "number" then
enemy_stats.ev = ev
end
enemy_stats.hit_chance = hit_chance(to_hit(item), enemy_stats.ev)
local dpt_no_brand = get_dpt(item, enemy_stats, false)
display_line("Warning: this figure is a VERY rough approximation and does not account for armor encumbrance, slaying, and most other buffs or status effects.", "lightred")
display_line("Fighting against imaginary enemy with " .. tostring(enemy_stats.ac) .. " AC and " .. tostring(enemy_stats.ev) .. " EV...", "darkgray")
if item.is_unarmed then
display_line("Unarmed calculations assume no gloves worn.", "magenta")
end
function extra_reports(has_ego) --
local ego_avg_damage = has_ego and (" / " .. fmt_num(get_damage(item, enemy_stats, true))) or ""
local ego_max_damage = has_ego and (" / " .. fmt_num(get_damage(item, enemy_stats, true, true))) or ""
display_line("Average damage per attack: " .. fmt_num(get_damage(item, enemy_stats, false)) .. ego_avg_damage .. " ~(" .. fmt_num(weapon_delay(item) / 10) .. " AUTs)", "green")
display_line("Max damage per attack: " .. fmt_num(get_damage(item, enemy_stats, false, true)) .. ego_max_damage, "green")
end
if not (item.branded or is_staff(item)) then
display_line("Approx pre-buff weapon damage per 1.0 AUTs: " .. "" .. tostring(dpt_no_brand) .. "", "lightgreen")
extra_reports(false)
else
local dpt_with_brand = get_dpt(item, enemy_stats, true)
display_line("Approx pre-buff weapon damage per 1.0 AUTs:", "lightgreen")
display_line("(before brand / after brand vs susceptible creatures)", "lightgreen")
display_line(" " .. tostring(dpt_no_brand) .. " / " .. tostring(dpt_with_brand), "lightcyan")
extra_reports(true)
end
local hit_chance = enemy_stats.hit_chance * 100
local hit_chance_color = "darkgrey"
if hit_chance >= 10 then
hit_chance_color = "red"
end
if hit_chance >= 30 then
hit_chance_color = "lightred"
end
if hit_chance >= 50 then
hit_chance_color = "yellow"
end
if hit_chance >= 70 then
hit_chance_color = "green"
end
if hit_chance >= 90 then
hit_chance_color = "lightgreen"
end
display_line("Chance to hit: <" .. hit_chance_color .. ">" .. "~" .. fmt_num(hit_chance) .. "%" .. "" .. hit_chance_color .. ">")
-- item.description = item.description .. message_string
end
function get_dpt(item, enemy_stats, use_brand, format_result)
if format_result == nil then format_result = true end
local damage_per_swing = get_damage(item, enemy_stats, use_brand)
local additional_notes = ""
local you_delay = weapon_delay(item)
local venom_adjustment = 0
if use_brand then
if is_staff(item) then
if item:subtype() == "poison" then
local activation_chance = math.min((50 + you.skill("Poison Magic") * 12.5), 100)
venom_adjustment = midrange(1, 7) * (activation_chance / 100)
additional_notes = additional_notes .. " (estimated adjustment for poison damage, " .. fmt_num(activation_chance) .. "% chance to activate)"
end
else
if item:ego() == "venom" then
venom_adjustment = midrange(1, 7)
additional_notes = additional_notes .. " (estimated adjustment for poison damage, 75% chance to activate)"
end
end
end
local result = damage_per_swing * (1 / (you_delay / 10)) + venom_adjustment
if format_result then
return fmt_num(result) .. additional_notes
else
return result
end
end
function get_damage(item, enemy_stats, use_brand, max)
local dice_avg = not max and dice_avg or (function(num_dice, num_sides) return num_dice * num_sides end) -- if we're looking for the max possible damage, dont get the average of any dice rolls - just the highest possible rolls.
-- ignores slaying bonus, other "final multipliers"
--[[
Damage =
{
[1d(Base damage * Strength modifier +1)-1]
* Weapon skill modifier
* Fighting modifier
+ Misc modifiers
+ Slaying bonuses
} * Final multipliers
+ Stabbing bonus
- AC damage reduction[1]
--]]
local die_num = item.damage * strength_modifier(max) + 1
local effective_enchantment = item.plus or 0
if effective_enchantment > 0 then
effective_enchantment = dice_avg(1, 1 + effective_enchantment) - 1
elseif effective_enchantment < 0 then
effective_enchantment = -dice_avg(1, 1 - effective_enchantment) + 1
end
local damage = math.max(((dice_avg(1, die_num) - 1) * weapon_skill_modifier(item, max) * fighting_modifier(max)) + effective_enchantment - (enemy_stats.ac/2), 0)
if not max then
damage = damage * enemy_stats.hit_chance
end
-- display_line(tostring(string.match(item:class(), "Magical Staves")))
if use_brand then
if is_staff(item) then
damage = damage + staff_bonus(item, damage, max)
else
damage = damage + brand_bonus(item, damage, max)
end
end
return damage
end
function weapon_delay(item)
if item.is_unarmed then
return item.delay
end
local base_delay = item.delay
local min_delay = math.min(base_delay / 2, 7)
if item.subtype() == "rapier" then
min_delay = 5
end
local you_delay = math.max(base_delay - math.ceil(you.skill(item.weap_skill)/2 + 0.5), min_delay)
if item:ego() == "speed" then
you_delay = you_delay * 0.66666
end
return you_delay
end
function hit_chance(to_hit, ev)
if ev <= 0 then
return 0.99
end
local total = 0
for i=1,to_hit do
for j=1,ev do
if i >= j then
total = total + 1
end
end
end
return total / (to_hit * ev)
end
function to_hit(item)
local base = 15 + you.dexterity()/2 + you.skill("Fighting")/2
-- item.plus = item.plus
local weapon_accuracy = you.skill(item.weap_skill)/2 + item.accuracy + (item.plus or 0)
base = base + weapon_accuracy
return (base-1) / 2 -- average roll
end
function strength_modifier(max)
local dice_avg = not max and dice_avg or (function(num_dice, num_sides) return num_dice * num_sides end)
local strength = you.strength()
if strength > 10 then
return (39 + ((dice_avg(1, strength - 8) - 1) * 2)) / 39
elseif strength < 10 then
return (39 - ((dice_avg(1, 12 - strength) - 1) * 3)) / 39
else
return 1
end
end
function weapon_skill_modifier(item, max)
local dice_avg = not max and dice_avg or (function(num_dice, num_sides) return num_dice * num_sides end)
local modifier = (2499 + dice_avg(1, 100 * you.skill(item.weap_skill) + 1)) / 2500
return modifier
end
function fighting_modifier(max)
local dice_avg = not max and dice_avg or (function(num_dice, num_sides) return num_dice * num_sides end)
return (3999 + dice_avg(1, 100 * you.skill("Fighting") + 1)) / 4000
end
function brand_bonus(item, damage, max)
local midrange = not max and midrange or (function(low, high) return high end)
local dice_avg = not max and dice_avg or (function(num_dice, num_sides) return num_dice * num_sides end)
local brand = item:ego()
local bonuses =
{ disruption = damage * 0.67,
draining = damage * 0.25,
electrocution = midrange(8, 20) * 0.33,
flaming = damage * 0.25,
freezing = damage * 0.25,
["holy wrath"] = damage * 0.75,
pain = damage * you.skill("Necromancy")/2,
silver = damage * 0.1667,
vorpal = damage * 0.1667, }
local bonus = 0
for k,v in pairs(bonuses) do
if string.match(brand, k) then
bonus = v
break
end
end
return bonus
end
function staff_bonus(item, damage, max)
local midrange = not max and midrange or (function(low, high) return high end)
local item_type = item:subtype()
function calculate_bonus(school)
local evo_skill = you.skill("Evocations")
local school_skill = you.skill(school)
return midrange(0, 1.25 * (school_skill+evo_skill/2)) * midrange(0, 6.66 + (evo_skill + school_skill/2)) / 100
end
local bonuses =
{ fire = calculate_bonus("Fire Magic"),
cold = calculate_bonus("Ice Magic"),
earth = calculate_bonus("Earth Magic"),
air = calculate_bonus("Air Magic"),
conjuration = calculate_bonus("Conjurations"),
death = calculate_bonus("Necromancy")}
-- display_line("got here")
return bonuses[item_type] or 0
end
function dice_avg(num_dice, num_sides)
return ((num_sides + 1) / 2) * num_dice
end
function midrange(low, high)
return (low + high) / 2
end
function round_tenths(num)
return round(num * 10) / 10
end
function round(num)
return math.floor(num + 0.5)
end
function random_round(num)
end
function fmt_num(num)
return tostring(round_tenths(num))
end
}