{ dcss_versions = {"0.29.1"} small_races = { Spriggan={}} medium_races = { Demigod={}, Human={}} big_races = { Naga={}, Troll={}} -- TODO: move to a context table and fill races equipment_slots = { -- clua armor slots cloak="Cloak", helmet="Helmet", gloves="Gloves", boots="Boots", body="Body Armour"} -- there is also shield="Shield", but it's often excluded due to AC computations -- so if one wants, can use raw "Shield" exceptionally -- TODO: jewellry -- TODO: move to a context table Options = { -- crawl RC setters/appenders set_as = function (option, alias) crawl.setopt(alias .. ":=" .. option) end, set = function (option, value) crawl.setopt(option .. "=" .. value) end, append = function (option, value) crawl.setopt(option .. "+=" .. value) end} -- end of Options Player = { -- player extension functions AC = function (args) local total = 0 for _, slotname in pairs(equipment_slots) do it = items.equipped_at(slotname) if it then total = total + it.ac + it.plus end end return total end} -- end of Player Utility = { -- utility functions concat = function (...) local m = "" for _, v in ipairs(...) do m = m .. tostring(v) end return m end, tagged = function (message, tag) -- returns `message` local ltag = "<" .. tag .. ">" local rtag = "" return ltag .. message .. rtag end, gdr = function (AC) -- calculate GDR % and real reduction it calculates to local gdr_percent = math.pow(AC, 0.25) * 16 local gdr_real = AC * gdr_percent / 100 return gdr_percent, gdr_real end, percent_of = function (value, base) -- what % of `base` `value` calculates to return value * 100 / base end, delayed = function (delay, func, ...) -- execute `func` every `delay` turns if math.fmod(you.turns(), delay) == 0 then func(...) end end} -- end of Utility Color = { -- crawl recognized colors white="white", lightgrey="lightgrey", darkgrey="darkgrey", lightgreen="lightgreen", green="green", yellow="yellow", red="red", magenta="magenta", lightmagenta="lightmagenta", blue="blue", lightblue="lightblue", cyan="cyan", lightcyan="lightcyan", lightred="lightred", brown="brown", black="black"} Channel = { -- crawl's recognized channel names plain="plain", friend_action="friend_action", prompt="prompt", god="god", duration="duration", danger="danger", warning="warning", recovery="recovery", sound="sound", talk="talk", talk_visual="talk_visual",intrinsic_gain="intrinsic_gain", mutation="mutation", monster_spell="monster_spell", monster_enchant="monster_enchant", friend_spell="friend_spell", friend_enchant="friend_enchant", monster_damage="monster_damage", monster_target="monster_target", banishment="banishment", equipment="equipment", floor="floor", multiturn="multiturn", examine="examine", examine_filter="examine_filter", diagnostic="diagnostic", error="error", tutorial="tutorial", orb="orb", timed_portal="timed_portal", hell_effect="hell_effect", monster_warning="monster_warning", dgl_message="dgl_message"} Console = { -- crawl console I/O print_c = function (color, message, ...) -- print in specified color if color == nil then color = Color.lightgrey end crawl.mpr(Utility.tagged(string.format(message, ...), color)) end, print = function (message, ...) if message ~= nil then -- TODO: typechecking and printing other types crawl.mpr(string.format(message, ...)) end end, print_ch = function (ch, message, ...) -- print to specific channel if message ~= nil then if ch == nil then ch = Channel.plain end crawl.mpr(string.format(message, ...), ch) end end, warning = function (message, ...) Console.print_ch(Channel.warning, message, ...) end, danger = function (message, ...) Console.print_ch(Channel.danger, message, ...) crawl.more() end, prompt = function (message, ...) Console.print_ch(Channel.prompt, message, ...) return crawl.getch() end, input = function () local input_value = crawl.c_input_line() if input_value ~= nil then crawl.mpr(">>> " .. input_value, Channel.dgl_message) return input_value end end} -- end of Console Announce = { -- functions meant to run every action gdr_change = function (force) local current_AC = Player.AC() if buffer.previous_AC ~= current_AC then local gdr_proc, gdr_real = Utility.gdr(current_AC) local msg = "GDR: %.0f%% / %.0fdmg" if buffer.previous_AC < current_AC then -- AC increased msg = msg .. Utility.tagged(" -> %.0f%% / %.0fdmg", Color.lightgreen) else -- AC descreased msg = msg .. Utility.tagged(" -> %.0f%% / %.0fdmg", Color.lightred) end local prev_proc, prev_real = Utility.gdr(buffer.previous_AC) Console.print(msg, prev_proc, prev_real, gdr_proc, gdr_real) elseif force ~= nil then Console.print("GDR: %.0f%% / %.0fdmg", Utility.gdr(Player.AC())) end buffer.previous_AC = current_AC end, hp_change = function () local current_HP, max_HP = you.hp() if buffer.previous_HP ~= current_HP then local hp_diff = current_HP - buffer.previous_HP local percent = Utility.percent_of(math.abs(hp_diff), max_HP) if hp_diff < 0 and percent > 20 then -- issue warning if hit by more than 20% of max hp Console.danger("MASSIVE (%d) damage taken!", math.abs(hp_diff)) elseif hp_diff > 1 then -- announce any healing bigger than what regen gives Console.print_c(Color.lightgreen, "Healed for %d (%d%%)", hp_diff, percent) end buffer.previous_HP = current_HP end end, gold_change = function () local current_gold = you.gold() if buffer.previous_gold ~= current_gold then local gold_diff = current_gold - buffer.previous_gold if gold_diff < 0 then -- inform on lost gold Console.print_c(Color.yellow, "Lost %d gold! (%d)", math.abs(gold_diff), current_gold) elseif gold_diff > 0 then -- announce any healing bigger than what regen gives Console.print_c(Color.yellow, "Gained %d gold! (%d)", gold_diff, current_gold) end buffer.previous_gold = current_gold end end} -- end of Announce function cmd() -- run command passed via crawl input -- by default set to F2 as macro by set_defaults() function Console.print(assert(loadstring("return " .. Console.input()))()) end -- end of cmd() function enable_aliases() -- ingame cmd convenience aliases print = Console.print print_c = Console.print_c percent = Utility.percent_of gdr = function () Announce.gdr_change(true) end Options.append("macros", "M \\{F5} ===gdr") end -- end of enable_aliases() function adjust_autofight() -- Adjust autofight_stop option according to the player state. local hp, max_hp = you.hp() local af_stop = 50 -- base autofight stop % if medium_races[you.race()] ~= nil then if max_hp < 100 then af_stop = 55 elseif max_hp < 200 then af_stop = 40 else af_stop = 25 end end -- end of level setting Options.set("autofight_stop", af_stop) end -- end of adjust_autofight() function adjust_autodrop() return nil -- TODO autodrop according to level etc. end -- end of adjust_autodrop() function adjusted_autopickup(item, name)-- meant for add_autopickup_func() if item.is_useless then return end if item.artefact then return true end -- Pickup missing must-have items. if item.class(true) == "armour" then slot, _ = item.subtype() return (equipment_slots[slot] ~= nil and items.equipped_at(equipment_slots[slot]) == nil) end end -- end of adjusted_autopickup() function set_defaults() -- Set default rc options local set_opts = { default_manual_training = "true", hp_warning = 30, hp_colour = "100:green, 95:lightgreen, 80:yellow, 40:lightred, 25:red", mp_warning = 40, mp_colour = "100:blue, 70:lightblue, 55:yellow, 40:lightred, 25:red", stat_colour = "1:lightred, 3:red, 10:yellow, 30:lightgreen, 50:green, 70:cyan", clear_messages = "true", equip_bar = "true", always_show_zot = "true"} -- TODO add repr and put long values into lua arrays local append_opts = { macros = {"M \\{F2} ===cmd"}} -- bind commandline to F2 key -- TODO add colours? or move them to adjust_*() for opt, value in pairs(set_opts) do Options.set(opt, value) end for opt, values in pairs(append_opts) do for _, value in ipairs(values) do Options.append(opt, value) end end end -- end of set_defaults() set_defaults() add_autopickup_func(adjusted_autopickup) -- open skills at start if you.turns() == 0 then crawl.sendkeys("m") end buffer = { -- global buffer context previous_AC = Player.AC(), previous_HP = (you.hp()), previous_gold = you.gold()} function ready() -- Main function executed after every action. Announce.gdr_change() Announce.hp_change() Announce.gold_change() Utility.delayed(10, adjust_autofight) end -- end of ready() } -- TODO: walkable tiles according to resistances -- TODO: spellcasting penalty according to armor worn http://crawl.chaosforge.org/Encumbrance_rating -- TODO: dynamic type recognition in print for tables, arrays, etc. -- TODO: add namespace -- TODO: player settings -- TODO: add spellpower change announce (with enhancements at least) -- convenience aliases