# vim: set ft=dcss-rc: # enc=latin1 ##### 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 { is_stoat_soup = string.find(crawl.version(), '%d+%.%d+-ish') ~= nil is_bcrawl = string.find(crawl.version(), 'bcrawl-') ~= nil } ###################### WIZMODE NOTES ####################### # # &% to create an item with spec # # Example: # # the +11 sling of Uceiwk (weapon) {flame, Int+3 Dex+4} # => sling plus:11 ego:flaming mundane artprops:int:3&dex:4 # # the +6 morningstar of the Lamprey {freeze, rElec Int+2} # => morningstar plus:6 ego:freezing mundane artprops:rElec:1&int:2 # # the +3 long sword "Giantbane" {drain, rF- Will+ Dex+3} # => long sword plus:3 ego:draining mundane artprops:rf:-1&will:1&dex:3 # # a +2 pair of gloves of strength # => pair of gloves plus:2 ego:strength # # the +11 demon trident of Viyrr {freeze, rF++} # => demon trident plus:11 ego:freezing artprops:rf:2 mundane # # the ring "Kuhatin" {rElec rC+ Dex+4} # => ring of protection from cold artprops:rElec:dex:4 mundane # # => any potion q:99 pre_id # # Just double-check that the item didn't create with more artprops than it should have. # ############################################################ { -- Convenience function. Be careful of shadowing/collisions. function p(...) local arg = {...} for i = 1, #arg do if arg[i] == nil then arg[i] = 'nil' else local t = type(arg[i]) if t == 'table' then arg[i] = json.stringify(arg[i]) elseif t ~= 'string' then arg[i] = tostring(arg[i]) end end end return crawl.mpr('> ' .. table.concat(arg, ', ')) end } { function control(c) return string.char(string.byte(c) - string.byte('a') + 1) end } { -- it = with_item('g', function(it); return it.damage_rating(); end) function with_item(letter, fn) local it = items.inslot(items.letter_to_index(letter)) if fn ~= nil then crawl.mpr(string.format('> %s', fn(it))) end return it end function tostring_item(it) if it ~= nil and type(it.name) == 'function' then return string.format('%s %s %s', it.slot and items.index_to_letter(it.slot) or '?', it.equipped and '+' or '-', it.name_coloured()) else return tostring(it) end end function dump_item(it) if it ~= nil and type(it.name) == 'function' then return string.format('%s %s %s (class(true)=%s, subtype(true)=%s, subtype(false)=%s, artefact=%s, branded=%s, ac=%s, plus=%s)', it.slot and items.index_to_letter(it.slot) or '?', it.equipped and '+' or '-', it.name_coloured(), it.class(true), it.subtype(true), it.subtype(false), it.artefact, it.branded, it.ac, it.plus) end end function item_cur_atk_delay(it) return string.match(tostring(it.description), 'Current attack delay: (%d+.%d+).') end } { -- https://gist.github.com/pocco81/9ee123862db531e439190209207beaa5 --[[ json.lua A compact pure-Lua JSON library. The main functions are: json.stringify, json.parse. ## json.stringify: This expects the following to be true of any tables being encoded: * They only have string or number keys. Number keys must be represented as strings in json; this is part of the json spec. * They are not recursive. Such a structure cannot be specified in json. A Lua table is considered to be an array if and only if its set of keys is a consecutive sequence of positive integers starting at 1. Arrays are encoded like so: `[2, 3, false, "hi"]`. Any other type of Lua table is encoded as a json object, encoded like so: `{"key1": 2, "key2": false}`. Because the Lua nil value cannot be a key, and as a table value is considerd equivalent to a missing key, there is no way to express the json "null" value in a Lua table. The only way this will output "null" is if your entire input obj is nil itself. An empty Lua table, {}, could be considered either a json object or array - it's an ambiguous edge case. We choose to treat this as an object as it is the more general type. To be clear, none of the above considerations is a limitation of this code. Rather, it is what we get when we completely observe the json specification for as arbitrary a Lua object as json is capable of expressing. ## json.parse: This function parses json, with the exception that it does not pay attention to \u-escaped unicode code points in strings. It is difficult for Lua to return null as a value. In order to prevent the loss of keys with a null value in a json string, this function uses the one-off table value json.null (which is just an empty table) to indicate null values. This way you can check if a value is null with the conditional `val == json.null`. If you have control over the data and are using Lua, I would recommend just avoiding null values in your data to begin with. --]] -- local json = {} json = {} -- Internal functions. local function kind_of(obj) if type(obj) ~= 'table' then return type(obj) end local i = 1 for _ in pairs(obj) do if obj[i] ~= nil then i = i + 1 else return 'table' end end if i == 1 then return 'table' else return 'array' end end local function escape_str(s) local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} for i, c in ipairs(in_char) do s = s:gsub(c, '\\' .. out_char[i]) end return s end -- Returns pos, did_find; there are two cases: -- 1. Delimiter found: pos = pos after leading space + delim; did_find = true. -- 2. Delimiter not found: pos = pos after leading space; did_find = false. -- This throws an error if err_if_missing is true and the delim is not found. local function skip_delim(str, pos, delim, err_if_missing) pos = pos + #str:match('^%s*', pos) if str:sub(pos, pos) ~= delim then if err_if_missing then error('Expected ' .. delim .. ' near position ' .. pos) end return pos, false end return pos + 1, true end -- Expects the given pos to be the first character after the opening quote. -- Returns val, pos; the returned pos is after the closing quote character. local function parse_str_val(str, pos, val) val = val or '' local early_end_error = 'End of input found while parsing string.' if pos > #str then error(early_end_error) end local c = str:sub(pos, pos) if c == '"' then return val, pos + 1 end if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end -- We must have a \ character. local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} local nextc = str:sub(pos + 1, pos + 1) if not nextc then error(early_end_error) end return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) end -- Returns val, pos; the returned pos is after the number's final character. local function parse_num_val(str, pos) local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) local val = tonumber(num_str) if not val then error('Error parsing number at position ' .. pos .. '.') end return val, pos + #num_str end -- Public values and functions. function json.stringify(obj, as_key) local s = {} -- We'll build the string as an array of strings to be concatenated. local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. if kind == 'array' then if as_key then error('Can\'t encode array as key.') end s[#s + 1] = '[' for i, val in ipairs(obj) do if i > 1 then s[#s + 1] = ', ' end s[#s + 1] = json.stringify(val) end s[#s + 1] = ']' elseif kind == 'table' then if as_key then error('Can\'t encode table as key.') end s[#s + 1] = '{' for k, v in pairs(obj) do if #s > 1 then s[#s + 1] = ', ' end s[#s + 1] = json.stringify(k, true) s[#s + 1] = ':' s[#s + 1] = json.stringify(v) end s[#s + 1] = '}' elseif kind == 'string' then return '"' .. escape_str(obj) .. '"' elseif kind == 'number' then if as_key then return '"' .. tostring(obj) .. '"' end return tostring(obj) elseif kind == 'boolean' then return tostring(obj) elseif kind == 'nil' then return 'null' elseif kind == 'userdata' then if type(obj.name_coloured) == 'function' then return tostring_item(obj) else _debug = obj return 'undefined' end else -- error('Unjsonifiable type: ' .. kind .. '.') _debug = obj return 'undefined' end return table.concat(s) end json.null = {} -- This is a one-off table to represent the null value. function json.parse(str, pos, end_delim) pos = pos or 1 if pos > #str then error('Reached unexpected end of input.') end local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. local first = str:sub(pos, pos) if first == '{' then -- Parse an object. local obj, key, delim_found = {}, true, true pos = pos + 1 while true do key, pos = json.parse(str, pos, '}') if key == nil then return obj, pos end if not delim_found then error('Comma missing between object items.') end pos = skip_delim(str, pos, ':', true) -- true -> error if missing. obj[key], pos = json.parse(str, pos) pos, delim_found = skip_delim(str, pos, ',') end elseif first == '[' then -- Parse an array. local arr, val, delim_found = {}, true, true pos = pos + 1 while true do val, pos = json.parse(str, pos, ']') if val == nil then return arr, pos end if not delim_found then error('Comma missing between array items.') end arr[#arr + 1] = val pos, delim_found = skip_delim(str, pos, ',') end elseif first == '"' then -- Parse a string. return parse_str_val(str, pos + 1) elseif first == '-' or first:match('%d') then -- Parse a number. return parse_num_val(str, pos) elseif first == end_delim then -- End of an object or array. return nil, pos + 1 else -- Parse true, false, or null. local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} for lit_str, lit_val in pairs(literals) do local lit_end = pos + #lit_str - 1 if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end end local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) error('Invalid json syntax starting at ' .. pos_info_str) end end -- return json } # https://crawl.dcss.io/crawl/rcfiles/crawl-git/dossy.rc.persist { -- ------------------------------------------------------------ -- SKILLS: BEGIN -- ------------------------------------------------------------ Skills = {} Skills.__index = function(tbl, key) return rawget(tbl, key) end Skills = setmetatable(Skills, Skills) Skills.loaded = false Skills.key = you.race() .. "/" .. you.class() Skills.names = { "Fighting", "Maces & Flails", "Axes", "Polearms", "Staves", "Unarmed Combat", "Throwing", "Short Blades", "Long Blades", "Ranged Weapons", "Armour", "Dodging", "Shields", "Stealth", "Spellcasting", "Conjurations", "Hexes", "Summonings", "Necromancy", "Forgecraft", "Translocations", "Alchemy", "Fire Magic", "Ice Magic", "Air Magic", "Earth Magic", "Invocations", "Evocations", "Shapeshifting" } Skills.skills = {} for _, s in ipairs(Skills.names) do Skills.skills[s] = { 0, 0.0 } end function Skills:read() for _, s in ipairs(self.names) do self.skills[s] = { you.train_skill(s), you.get_training_target(s) } end end function Skills:write() for _, s in ipairs(self.names) do local status, target = table.unpack(self.skills[s]) you.train_skill(s, status) you.set_training_target(s, target) end end function Skills:__tostring(all) local results = {} local glyphs = { [0] = "-", [1] = "+", [2] = "*" } for _, s in ipairs(self.names) do local state, target = table.unpack(self.skills[s]) if all or (state > 0 or target > 0) then local str = glyphs[state] .. " " .. s if target > 0 then str = str .. " (" .. target .. ")" end table.insert(results, str) end end return table.concat(results, "; ") end function Skills:exists() return c_persist.char_defaults ~= nil and c_persist.char_defaults[self.key] ~= nil end function Skills:save() self:read() if not c_persist.char_defaults then c_persist.char_defaults = {} end local value = {} for _, s in ipairs(self.names) do local state, target = table.unpack(self.skills[s]) if state > 0 or target > 0 then value[s] = self.skills[s] end end c_persist.char_defaults[self.key] = value end function Skills:load() if self:exists() then local values = c_persist.char_defaults[self.key] for _, s in ipairs(self.names) do if values[s] then self.skills[s] = values[s] else self.skills[s] = { 0, 0 } end end self:write() end self.loaded = true end function Skills:init() if you.turns() ~= 0 then return end if not Skills.loaded then Skills:load() if you.race() ~= 'Gnoll' and not Skills:exists() then crawl.sendkeys("m") end end end Skills:init() -- ------------------------------------------------------------ -- SKILLS: END -- ------------------------------------------------------------ } ############### # Damage Calc # ############### # lifted from https://underhound.eu/crawl/rcfiles/crawl-git/HyperOdds.rc { local previous_hp = 0 local previous_mp = 0 local previous_form = "" local was_berserk_last_turn = false function AnnounceDamage() local current_hp, max_hp = you.hp() local current_mp, max_mp = you.mp() --Things that increase hp/mp temporarily really mess with this local current_form = you.transform() local you_are_berserk = you.berserk() local max_hp_increased = false local max_hp_decreased = false if (current_form ~= previous_form) then if (previous_form:find("dragon") or previous_form:find("statue") or previous_form:find("tree") or previous_form:find("ice")) or previous_form:find("hydra")then max_hp_decreased = true elseif (current_form:find("dragon") or current_form:find("statue") or current_form:find("tree") or previous_form:find("ice")) or previous_form:find("hydra")then max_hp_increased = true end end if (was_berserk_last_turn and not you_are_berserk) then max_hp_decreased = true elseif (you_are_berserk and not was_berserk_last_turn) then max_hp_increased = true end --crawl.mpr(string.format("previous_form is: %s", previous_form)) --crawl.mpr(string.format("current_form is: %s", current_form)) --crawl.mpr(string.format("max_hp_increased is: %s", max_hp_increased and "True" or "False")) --crawl.mpr(string.format("max_hp_decreased is: %s", max_hp_decreased and "True" or "False")) --crawl.mpr(string:format("you_are_berserk is: %s", you_are_berserk and "True" or "False")) --crawl.mpr(string:format("was_berserk_last_turn is: %s", was_berserk_last_turn and "True" or "False")) --Skips message on initializing game if previous_hp > 0 then local hp_difference = previous_hp - current_hp local mp_difference = previous_mp - current_mp if max_hp_increased or max_hp_decreased then if max_hp_increased then crawl.mpr("You now have " .. current_hp .. "/" .. max_hp .. " hp.") else crawl.mpr("You now have " .. current_hp .. "/" .. max_hp .. " hp.") end else local hp_percent = current_hp / max_hp local color = "" --On losing health if (current_hp < previous_hp) then if current_hp <= (max_hp * 0.30) then color = "lightred" elseif current_hp <= (max_hp * 0.50) then color = "" elseif current_hp <= (max_hp * 0.70) then color = "yellow" elseif current_hp <= (max_hp * 0.90) then color = "lightgrey" else color = "green" end crawl.mpr(string.format("You take %i damage, %sand have %i/%i hp (%.0f%%).%s", hp_difference, color ~= "" and "<" .. color .. ">" or "", current_hp, max_hp, hp_percent * 100, color ~= "" and "" or "")) if hp_difference > (max_hp * 0.20) then crawl.mpr("MASSIVE DAMAGE!!") end end --On gaining more than 1 health if (current_hp > previous_hp) then --Removes the negative sign local health_inturn = (0 - hp_difference) if (health_inturn > 1) and not (current_hp == max_hp) then if current_hp <= (max_hp * 0.30) then color = "lightred" elseif current_hp <= (max_hp * 0.50) then color = "red" elseif current_hp <= (max_hp * 0.70) then color = "yellow" elseif current_hp <= (max_hp * 0.90) then color = "lightgrey" else color = "green" end crawl.mpr(string.format("You regained %i hp, %sand now have %i/%i hp (%.0f%%).%s", health_inturn, color ~= "" and "<" .. color .. ">" or "", current_hp, max_hp, hp_percent * 100, color ~= "" and "" or "")) end if (current_hp == max_hp) then crawl.mpr("Health restored: " .. current_hp .. "") end end --On gaining more than 1 magic if (current_mp > previous_mp) then --Removes the negative sign local mp_inturn = (0 - mp_difference) if (mp_inturn > 1) and not (current_mp == max_mp) then if current_mp < (max_mp * 0.25) then crawl.mpr("You regained " .. mp_inturn .. " mp, and now have " .. current_mp .. "/" .. max_mp .. " mp.") elseif current_mp < (max_mp * 0.50) then crawl.mpr("You regained " .. mp_inturn .. " mp, and now have " .. current_mp .. "/" .. max_mp .. " mp.") else crawl.mpr("You regained " .. mp_inturn .. " mp, and now have " .. current_mp .. "/" .. max_mp .. " mp.") end end if (current_mp == max_mp) then crawl.mpr("MP restored: " .. current_mp .. "") end end --On losing magic if current_mp < previous_mp then if current_mp <= (max_mp / 5) then crawl.mpr("You now have " .. current_mp .. "/" ..max_mp .." mp.") elseif current_mp <= (max_mp / 2) then crawl.mpr("You now have " .. current_mp .. "/" ..max_mp .." mp.") else crawl.mpr("You now have " .. current_mp .. "/" ..max_mp .." mp.") end end end end --Set previous hp/mp and form at end of turn previous_hp = current_hp previous_mp = current_mp previous_form = current_form was_berserk_last_turn = you_are_berserk end } { function items_in_class(class, skip) local its = {} for _, it in pairs(items.inventory()) do -- don't include items in slots a (0) and b (1) for weapon swapping if it.slot > 1 or skip == false then if it.class() == class then table.insert(its, it) end end end return its end function add_or_replace(str, prefix, value) escaped = string.gsub(prefix, '%+.*', '%%+') value = tostring(value) local s, n = string.gsub(str, escaped .. '%S*', prefix .. value) if n == 0 then if #s > 0 then s = s .. ' ' end s = s .. prefix .. value end return s end function is_two_handed(it) return string.find(tostring(it.description), 'a two-%S+ weapon') end function is_a_shield(it) return string.find('buckler, kite shield, tower shield', it.subtype(false)) end function uninscribe_item(it) local ins = '' for token in string.gmatch(it.inscription, '%S+') do if string.match(token, '^[@!=+]') then if #ins > 0 then ins = ins .. ' ' end ins = ins .. token end end return it.inscribe(ins, false) end function uninscribe_items() return tidy_inventory(true, true) end -- x = 'n'; it = items.inslot(items.letter_to_index(x)); crawl.mpr(string.format('> %s | %s | %s', it.name('qual'), it.subtype(false), it.ego(true))) function auto_inscribe_item(it) if not it.inscribe then return end local subtype = it.subtype(false) local ins = it.inscription local dr = it.damage_rating and it.damage_rating() or nil if dr ~= nil then ins = add_or_replace(ins, 'd:', dr) end local cur_atk_delay = item_cur_atk_delay(it) if cur_atk_delay ~= nil then ins = add_or_replace(ins, 's:', cur_atk_delay) end if dr ~= nil and cur_atk_delay ~= nil then ins = add_or_replace(ins, 'dpt:', string.format('%.1f', dr / cur_atk_delay)) end if is_two_handed(it) then ins = add_or_replace(ins, 'h:', 2) end if it.reach_range ~= nil and it.reach_range > 1 then ins = add_or_replace(ins, 'r:', it.reach_range) end if (it.ac ~= nil and it.ac ~= 0) or (it.encumbrance ~= nil and it.encumbrance ~= 0) then if it.ac ~= nil then ins = add_or_replace(ins, is_a_shield(it) and 'sh:' or 'ac:', it.ac) end if it.encumbrance ~= nil then ins = add_or_replace(ins, 'er:', it.encumbrance) end end local ego = it.ego(true) if ego ~= nil then local fullname = it.name('plain') local name = it.name('qual', true) for token in string.gmatch(ego, '%S+') do local escaped = string.gsub(token, '%+', '%%+') if not string.find(string.lower(name), string.lower(escaped)) and not string.find(string.lower(fullname), string.lower(escaped)) then ins = add_or_replace(ins, token, '') end end end local mapping = { ['acid dragon scales']='rCorr', ['fire dragon scales']='rF++ rC-', ['golden dragon scales']='rF+ rC+ rPois', ['ice dragon scales']='rC++ rF-', ['pearl dragon scales']='rN+', ['quicksilver dragon scales']='Will+', ['shadow dragon scales']='Stlth+', ['steam dragon scales']='rSteam', ['storm dragon scales']='rElec', ['swamp dragon scales']='rPois', ['troll leather armour']='Regen+' } if mapping[subtype] ~= nil then for token in string.gmatch(mapping[subtype], '%S+') do token, value = string.match(token, '([^%+%-]+.-)([%+%-]*)') ins = add_or_replace(ins, token, value) end end return it.inscribe(ins, false) end function tidy_inventory(quiet, uninscribe) if is_stoat_soup then crawl.mpr('Inventory tidying not supported.', 25) return end local gear_classes = { 'Hand Weapons', 'Missiles', 'Armour', 'Magical Staves', 'Jewellery', 'Talismans' } local consumable_classes = { 'Potions', 'Scrolls', 'Wands', 'Miscellaneous' } local classes if not is_bcrawl then classes = gear_classes else classes = { 'Hand Weapons', 'Missiles', 'Armour', 'Magical Staves', 'Jewellery', 'Talismans', 'Wands', 'Scrolls', 'Potions' } end -- skip a (0) and b (1) for weapon swap slots local offset = 2 for _, c in ipairs(classes) do local its = items_in_class(c, false) for _, it in ipairs(its) do if uninscribe then uninscribe_item(it) else auto_inscribe_item(it) end end local n = #items_in_class(c) if not quiet then crawl.mpr(string.format('(%s) ========== begin class: %s (%s) ==========', offset, c, n), 25) end for i = 1, n do local its = items_in_class(c) table.sort(its, function(a, b) -- local a_value = a.name('qual') -- local b_value = b.name('qual') -- if a_value ~= b_value then -- return a_value < b_value -- end -- In older crawl, unidentified items will not disclose their -- details to Lua, returning nils. if a == nil or b == nil then return a ~= nil and b == nil end local a_subtype = a.subtype(false) local b_subtype = b.subtype(false) -- In older crawl, unidentified items will not disclose their -- details to Lua, returning nils. if a_subtype == nil or b_subtype == nil then return a_subtype ~= nil and b_subtype == nil end if a_subtype ~= b_subtype then return a_subtype < b_subtype end if a.plus ~= b.plus then return (a.plus or 0) > (b.plus or 0) end if a.name() == b.name() then return a.slot < b.slot end return a.name() < b.name() end) if not quiet then crawl.mpr(string.format('# (sorted)'), 25) end local found = false for j = i, #its do local it = its[j] local idx = offset + j - 1 if not quiet then crawl.mpr(string.format('# offset=%s, i=%s, j=%s, idx=%s, slot=%s, it=%s', offset, i, j, idx, it.slot, tostring_item(it)), 25) end if it.slot ~= nil and it.slot ~= idx then local to = items.inslot(idx) if not quiet then crawl.mpr(string.format('# %s (%s) => %s (%s)', tostring_item(it), it.slot, tostring_item(to), idx), 25) crawl.mpr(string.format('# items.swap_gear_slots(%s, %s, true)', it.slot, idx), 25) end if items.swap_gear_slots then items.swap_gear_slots(it.slot, idx, true) else items.swap_slots(it.slot, idx, true) end found = true break end end if not found then break end end offset = offset + n if not quiet then crawl.mpr(string.format('(%s) ========== end class: %s (%s) ==========', offset, c, n), 25) end end crawl.mpr('Inventory tidied.', 25) end function tidy_inventory_quiet() return tidy_inventory(true) end } macros += M - ===tidy_inventory_quiet macros += M ] ===tidy_inventory { function analyze_spells() local s = you.spells() local out = {} for _, name in ipairs(s) do local desc = spells.describe(name) local dmg = string.match(desc, 'Damage: ([^*%s]+)') if dmg then local mult, dice = string.match(dmg, '(%d+)x(%S+)') if mult then dmg = '' for i = 1, mult do if #dmg > 0 then dmg = dmg .. ' + ' end dmg = dmg .. dice end end -- 6-21 -> d{6..21} dmg = string.gsub(dmg, '^(%d+)-(%d+).*', 'd{%1..%2}') -- 2d(25-37) -> 2d{25..37} dmg = string.gsub(dmg, '^(%d+d)%((%d+)-(%d+)%).*', '%1{%2..%3}') local str = string.format('output %s named "%s %s%%"', dmg, name, spells.power_perc(name)) table.insert(out, str) end end crawl.mpr('\n' .. table.concat(out, '\n')) end } # [^&] doesn't work here, but \{-9} (webtiles) or \{-41} (tiles) does: : if not is_stoat_soup and not is_bcrawl then bindkey = [\{-9}] CMD_LUA_CONSOLE bindkey = [\{-41}] CMD_LUA_CONSOLE : else bindkey = [&] CMD_LUA_CONSOLE :end travel_delay = 10 # travel_open_doors = approach { crawl.setopt("travel_open_doors = false") toggleable_settings = { autopickup_weapons=true, explore_auto_rest=false, rest_wait_both=false, rest_wait_percent=100, spell_menu=false, travel_open_doors=false, explore_never_die=true, warn_hatches=false } function set_travel_open_doors(value) local options = { avoid=true, approach=true, open=true, ['true']=true, ['false']=true } if options[tostring(value)] ~= nil then crawl.setopt(string.format('travel_open_doors = %s', tostring(value))) end end function set_or_toggle_setting(option, value_on, value_off) local msgch_diagnostic = crawl.msgch_num('diagnostic') local value = toggleable_settings[option] if value_on ~= nil and value_off ~= nil then toggleable_settings[option] = not toggleable_settings[option] if toggleable_settings[option] then value = value_on else value = value_off end elseif value_on ~= nil and value_off == nil then value = value_on else toggleable_settings[option] = not toggleable_settings[option] value = toggleable_settings[option] end local opt = string.format('%s = %s', option, tostring(value)) crawl.mpr(string.format('Setting %s', opt), msgch_diagnostic) crawl.setopt(opt) end function toggle_settings() local msgch_prompt = crawl.msgch_num('prompt') crawl.mpr(string.format( 'Toggle (a)utopickup weapons [%s] *DOES NOT WORK YET*, (t)ravel_open_doors [%s], (e)xplore_auto_rest [%s], (r)est_wait_both [%s], rest_wait_(p)ercent [%s], (s)pell_menu [%s], (f)iltered find, never (d)ie in explore mode [%s], (c)lear force_more_message and monster_alert, tidy (i/I)nventory, (u)ninscribe inventory, (w)arn_hatches [%s]?', tostring(toggleable_settings['autopickup_weapons']), tostring(toggleable_settings['travel_open_doors']), tostring(toggleable_settings['explore_auto_rest']), tostring(toggleable_settings['rest_wait_both']), tostring(toggleable_settings['rest_wait_percent']), tostring(toggleable_settings['spell_menu']), tostring(toggleable_settings['explore_never_die']), tostring(toggleable_settings['warn_hatches'])), msgch_prompt) local num = crawl.getch() local ch = string.char(num) if ch == '\x1b' then crawl.mpr('Okay, then.', msgch_prompt) elseif ch == 'a' then set_or_toggle_setting('autopickup_weapons') elseif ch == 'c' then crawl.mpr('Clearing force_more_message') crawl.setopt("force_more_message = nil") crawl.mpr('Clearing monster_alert') crawl.setopt("monster_alert = nil") elseif ch == 'd' then set_or_toggle_setting('explore_never_die') elseif ch == 'e' then set_or_toggle_setting('explore_auto_rest') elseif ch == 'f' then crawl.sendkeys(control('f') .. '@ && !!gate && !!door && !!transp && !!gold\r') elseif ch == 'i' then tidy_inventory_quiet() elseif ch == 'I' then tidy_inventory() elseif ch == 'p' then crawl.mpr('New percentage? ', msgch_prompt) local value = crawl.c_input_line() set_or_toggle_setting('rest_wait_percent', value) elseif ch == 'r' then set_or_toggle_setting('rest_wait_both') elseif ch == 's' then set_or_toggle_setting('spell_menu') elseif ch == 't' then set_or_toggle_setting('travel_open_doors') elseif ch == 'u' then tidy_inventory(true, true) elseif ch == 'w' then set_or_toggle_setting('warn_hatches') else crawl.mpr('Huh?') end end function autopickup_weapons_func(it, _name) if it.class(true) == 'weapon' and not toggleable_settings['autopickup_weapons'] then return false end end -- clear_autopickup_funcs() add_autopickup_func(autopickup_weapons_func) } macros += M _ ===toggle_settings { if not crawl.is_webtiles() then crawl.setopt('msg_min_height = 25') crawl.setopt('msg_max_height = 25') end } tile_window_height = -200 msg_webtiles_height = 15 ## slot += label:key ## item_slot ^= regexp:key # Space = CMD_EXPLORE # macros += M \{32} o # NP0 = CMD_EXPLORE macros += M \{-1000} o # NP+ = > macros += M \{-1016} > # NP- = < macros += M \{-1018} < # PgDn = G> macros += M \{-245} G> # PgUp = G< macros += M \{-246} G< # Num Lock (Clear) = G> (webtiles only) macros += M \{-247} G> # crawl.mpr() will print to the console. { -- Press "tab" when enemies are visible and "o" when they are not function autoplay(autofire) autofire = autofire or false if you.feel_safe() then crawl.sendkeys("o") else -- {9} = Tab, {-233} = Shift-Tab (or p) if autofire then crawl.sendkeys({-233}) else if is_bcrawl then crawl.sendkeys(string.char(9)) else crawl.sendkeys({9}) end end end end function autoplay_autofight() autoplay() end function autoplay_autofire() autoplay(true) end } # NP/ = autoplay_autofight macros += M \{-1012} ===autoplay_autofight : if is_stoat_soup then macros += M / ===autoplay_autofight : end # NP* = autoplay_autofire # macros += M \{-1015} ===autoplay_autofire macros += M \{-1015} p : if is_bcrawl then macros += M * zaf : end # Ctrl-1 \{-15} = CMD_AUTOFIGHT_NOMOVE bindkey = [^1] CMD_AUTOFIGHT_NOMOVE { function smart_rest() local hp, max_hp = you.hp() local mp, max_mp = you.mp() if hp < max_hp or mp < max_mp then crawl.do_commands({"CMD_REST"}) else crawl.mpr("HP and MP is already full. Ctrl-5 to rest for 100 turns.") end end } macros += M 5 ===smart_rest # \{-1005} = NP5 macros += M \{-1005} ===smart_rest # webtiles: [^5] = Ctrl-5 bindkey = [^5] CMD_REST # tiles: \{-43} = Ctrl-5 : if not is_stoat_soup and not is_bcrawl then bindkey = [\{-43}] CMD_REST : end # See: crawl-ref/source/initfile.cc item_class_by_sym() autopickup = $?!+"/|(0% # " closing quote because of syntax coloring # drop_disables_autopickup = true ae := autopickup_exceptions ae ^= boomerang, >javelin, >stone, >talisman : end # : if you.race() == 'Minotaur' and you.class() == 'Fighter' then # ae += book # : end : if you.race() == 'Felid' then fail_severity_to_confirm = 0 fail_severity_to_quiver = 5 : end ###################################################################### # Add the following to your options file to automatically pick up # armour for non-body armour slots (gloves, boots, etc.), if you don't # already have an item equipped there. { -- x = 'j'; it = items.inslot(items.letter_to_index(x)); crawl.mpr(string.format('>> %s / %s', it.class(true), it.subtype())) function smart_autopickup_func(it, _name) if it.is_useless then return false end local name = it.name('qual') if name == 'orb' then return end if name == 'gold piece' then return true end if it.class(true) == 'armour' then local good_slots = {cloak="cloak", helmet="helmet", gloves="gloves", boots="boots", barding="barding", offhand="offhand"} local slot_type = it.subtype(true) local subtype = it.subtype(false) -- if good_slots[slot_type] ~= nil and items.slot_is_available(slot_type) == true then if items.slot_is_available(slot_type) then return true end if false then local cur = items.equipped_at(slot_type == 'body' and 'armour' or slot_type) if cur == nil then crawl.mpr(string.format('> %s (something is wrong, cur is nil, we should have returned true earlier)', name)) return end -- crawl.mpr(string.format('> %s (branded:%s, ac:%s, plus:%s)', name, it.branded, it.ac, it.plus)) if it.branded and it.plus == nil then crawl.mpr(string.format('> %s (branded and plus unknown, we need to go identify it)', name)) return true end -- crawl.mpr(string.format('> %s (cur:%s, branded:%s, ac:%s, plus:%s)', name, cur.name('qual'), cur.branded, cur.ac, cur.plus)) local found = false for _, it2 in pairs(items.inventory()) do local n = it2.name('qual') if n ~= 'orb' then if it2.class(true) == slot_type then if it2.ac + it2.plus > it.ac + it.plus then return true end end end end end end end -- clear_autopickup_funcs() if items.slot_is_available and not is_stoat_soup then add_autopickup_func(smart_autopickup_func) end } explore_greedy = true explore_greedy_visit += glowing_items, artefacts explore_greedy_visit -= stacks explore_item_greed = 999 explore_stop = stairs,shops,altars,portals,branches,runed_doors explore_stop += greedy_pickup_smart, glowing_items, artefacts # Sets autoexplore to favor traveling towards walls, the higher the more # favored. Negative values instead travels away from walls. Default 0. explore_wall_bias = 1 explore_auto_rest = false rest_wait_ancestor = false rest_wait_both = false rest_wait_percent = 90 #################### VIEW AND CONTROLS ##################### tile_map_scale = 1.0 tile_viewport_scale = 1.25 #tile_web_mouse_control = false ############################################################ # default = 50 autofight_stop = 70 # attempt to escape webs or nets autofight_caught = true # use thrown items during autofight? autofight_fires = false autofight_nomove_fires = false # default = 10 hp_warning = 50 # default = 70:yellow, 40:red # hp_colour = 80:yellow, 60:lightred, 40:red hp_colour = 100:green, 85:lightgreen, 67:lightblue, 50:yellow, 33:lightmagenta, 15:red mp_colour = 100:green, 85:lightgreen, 67:lightblue, 50:yellow, 33:lightmagenta, 15:red # when using lua console: # crawl.setopt("hp_warning = 0") warn_hatches = false warn_contam_cost = true # fail_severity_to_confirm = 3 # fail_severity_to_quiver = 2 ############# FORCE MORE AND AUTOEXPLORE STOP ############## more := force_more_message stop := runrest_stop_message more += Found a faded altar of an unknown god stop += Found a faded altar of an unknown god more += Found a staircase to the Ecumenical Temple stop += Found a staircase to the Ecumenical Temple more += Found an escape hatch in the ceiling stop += Found an escape hatch in the ceiling more += seems less pained. stop += seems less pained. more += Your body becomes as fragile as glass more += Your eldritch tentacle suddenly becomes enraged stop += Your eldritch tentacle suddenly becomes enraged # The portal closes; your eldritch tentacle is severed. # The portal closes; something is severed. more += The portal closes; .* is severed # The Killer Klown pies you viciously! # The klown pie hits you! Blueberry! An unnatural silence engulfs you. more += An unnatural silence engulfs you more += Your transformation is almost over stop += Your transformation is almost over more += The roar of the dragon horde subsides stop += The roar of the dragon horde subsides # more += You.*engulfed.*chaos.* more += breathes chaos more += You detect # runrest_ignore_message ^= Your toxic aura wanes. more += You are slowing down. more += You fail to use your ability more += You miscast more += You are too exhausted more += The catoblepas breathes a plume of calcifying dust at you more += You suddenly lose the ability to move stop += You suddenly lose the ability to move more += You are poisoned stop += You are poisoned more += The acid corrodes you[.!] more += You are covered in (intense )?liquid fire flash_screen_message += The liquid fire burns you flash_screen_message += You are on fire # more += The shock serpent discharges a tendril of electricity # more += The shock serpent's electric aura discharges\, shocking you[.!] more += The .* electric aura discharges\, shocking you[.!] more += The bolt of electricity hits you[.!] # The black draconian breathes lightning at you. more += The bolt of lightning hits you[.!] # The drowned soul touches you. The drowned soul drowns you! more += The .* drowns you message_colour += lightcyan:The .* drowns you flash_screen_message += The .* drowns you # The water elemental engulfs you! more += The .* engulfs you[.!] message_colour += lightcyan:The .* engulfs you[.!] flash_screen_message += The .* engulfs you[.!] # Water floods into your lungs! more += Water floods into your lungs message_colour += lightcyan:Water floods into your lungs flash_screen_message += Water floods into your lungs # You finish coughing all the water out of your lungs. more += You finish coughing all the water out of your lungs # The Tzitzimitl calls on the powers of darkness! # Your body is wracked with pain! more += Your body is wracked with pain message_colour += lightcyan:Your body is wracked with pain flash_screen_message += Your body is wracked with pain more += You are confused more += You are marked more += You are slowed more += You are corroded more += You are mesmerised more += You feel yourself slow down more += You are constricted more += You encounter .* wielding .* distortion more += is wielding .* distortion more += hits you with .* distortion # The naga ritualist invokes the aid of its god against you. # You feel yourself grow more vulnerable to poison. more += You feel yourself grow more vulnerable message_colour += lightcyan:You feel yourself grow more vulnerable flash_screen_message += You feel yourself grow more vulnerable more += You feel your attacks grow feeble more += Your willpower is stripped away more += You hear a loud "Zot" more += The power of Zot is invoked against you # more += Your walking alembic finishes brewing potions and dispenses them more += Mmmm\.\.\. tastes like # For just a moment, the protean progenitor begins to look like , then it explodes! more += For just a moment\, .* begins to look like .*\, then it explodes! # May want to do this if it's too spammy for Gnoll. # : if you.race() ~= 'Gnoll' then # more += Your .* skill increases to level .*! # : end more += Training target .* for .* reached # the spriggan druid more += With its final breath\, .* offers up its power to the beasts of the wild more += seems to grow more fierce # You have finished your manual of %s and %stoss it away. more += You have finished your manual stop += You have finished your manual monster_alert += hydra monster_alert += moth of wrath monster_alert += guardian serpent monster_alert += revenant monster_alert += distortion monster_alert += hornet monster_alert += two-headed ogre monster_alert += acid dragon monster_alert += shock serpent monster_alert += fire giant monster_alert += frost giant monster_alert += ettin monster_alert += deep elf annihilator monster_alert += lich # these things can flood/drown you monster_alert += water elemental # 50 damage hit, Manifold Assault and Throw Bolas - yikes! monster_alert += oni incarcerator # xykzyl has malmutate monster_alert += zykzyl # total chad mode, when explore mode is on: # # crawl.setopt("hp_warning = 0") # crawl.setopt("autofight_stop = 0") # crawl.enable_more(false) : function go_chad_mode() : crawl.enable_more(false) hp_warning = 0 autofight_stop = 0 : end ################### MESSAGE AND DISPLAY #################### # item_stack_summary_minimum = 4 default_manual_training = true default_show_all_skills = true auto_hide_spells = false cloud_status = true always_show_zot = true always_show_gems = true more_gem_info = true tile_show_threat_levels = tough, nasty, unusual unusual_monster_items += wand unusual_monster_items += javelin, throwing net unusual_monster_items += curare, atropa, datura, dispersal unusual_monster_items += venom, protection, elec, holy wrath, draining, distortion, chaos # "unusual_monster_items += vulnerable:venom:5" will hilight monsters with venom weapons while the player is non-immune to them and XL 5 or below. message_colour += lightblue:You encounter # Uskayaw piety messages. message_colour += lightcyan:You can now stomp with the beat message_colour += lightcyan:You can now pass through a line of other dancers message_colour += lightcyan:Uskayaw will force your foes to helplessly watch your dance message_colour += lightcyan:Uskayaw will force your foes to share their pain message_colour += lightcyan:You can now merge with and destroy a victim force_more_message += You can now pass through a line of other dancers force_more_message += You can now merge with and destroy a victim message_colour += lightcyan:Uskayaw links your audience in an emotional bond message_colour += lightcyan:Uskayaw prepares the audience for your solo message_colour += cyan:You can no longer pass through a line of other dancers message_colour += cyan:You can no longer merge with and destroy a victim # Ru piety messages. force_more_message += Ru believes you are ready to make a new sacrifice ####################### SPELL SLOTS ######################## # Always show the full-screen spell selection menu? # spell_menu = true force_spell_targeter += Arcjolt force_spell_targeter += Blink force_spell_targeter += Conjure Ball Lightning force_spell_targeter += Death Channel force_spell_targeter += Death's Door force_spell_targeter += Detonation Catalyst force_spell_targeter += Dragon's Call force_spell_targeter += Eringya's Noxious Bog force_spell_targeter += Fireball force_spell_targeter += Fire Storm force_spell_targeter += Fortress Blast force_spell_targeter += Freezing Cloud force_spell_targeter += Hoarfrost Cannonade force_spell_targeter += Hellfire Mortar force_spell_targeter += Ignite Poison force_spell_targeter += Irradiate force_spell_targeter += Iskenderun's Mystic Blast force_spell_targeter += Leda's Liquefaction force_spell_targeter += Malign Gateway force_spell_targeter += Manifold Assault force_spell_targeter += Olgreb's Toxic Radiance force_spell_targeter += Ozocubu's Refrigeration force_spell_targeter += Permafrost Eruption force_spell_targeter += Plasma Beam force_spell_targeter += Polar Vortex force_spell_targeter += Scorch force_spell_targeter += Silence force_spell_targeter += Starburst force_spell_targeter += Static Discharge force_spell_targeter += Summon Forest ## Uskayaw force_ability_targeter += Stomp ## Cheibriados force_ability_targeter += Bend Time force_ability_targeter += Temporal Distortion force_ability_targeter += Slouch force_ability_targeter += Step From Time # doesn't work force_spell_targeter += Animate Dead force_spell_targeter += Fulsome Fusillade # doesn't work: https://github.com/crawl/crawl/issues/3811 force_spell_targeter += Ozocubu's Armour force_scroll_targeter += immolation force_scroll_targeter += noise force_scroll_targeter += silence force_scroll_targeter += vulnerability force_scroll_targeter += butterflies : if you.race() ~= 'Djinni' then ss := spell_slot : else ss := dummy : end ss += Apportation:at ss += Arcjolt:JA ss += Blink:bilk ss += Bombard:r ss += Brom's Barrelling Boulder:rB ss += Dispel Undead:D ss += Fireball:f ss += Fire Storm:FS ss += Fortress Blast:FB ss += Fugue of the Fallen:f ss += Gloom:g ss += Hailstorm:H ss += Hellfire Mortar:hH ss += Ignite Poison:IP ss += Iskenderun's Battlesphere:BS ss += Kiss of Death:k ss += Lee's Rapid Deconstruction:L ss += Lesser Beckoning:tl ss += Martyr's Knell:m ss += Mephitic Cloud:cf ss += Momentum Strike:m ss += Nazja's Percussive Tempering:ty ss += Olgreb's Toxic Radiance:rR ss += Passage of Golubria:g ss += Passwall:w ss += Permafrost Eruption:e ss += Petrify:e ss += Plasma Beam:e ss += Shatter:s ss += Slow:s ss += Spellspark Servitor:v ss += Sublimation of Blood:s ss += Summon Forest:f ss += Vhi's Electric Charge:v ## Hedge Wizard Start : if you.class() == 'Hedge Wizard' then ss += Magic Dart:a : else ss += Magic Dart:D : end # ss += Blink:b # ss += Call Imp:c # ss += Grave Claw:d # ss += Mephitic Cloud:e ## Forgewright Start : if you.class() ~= 'Forgewright' then ss += Forge Blazeheart Golem:G ss += Forge Lightning Spire:SL : end ## Conjurer Start # ... Magic Dart ss += Searing Ray:bs ss += Fulminant Prism:cF ss += Iskenderun's Mystic Blast:dM ## Enchanter Start ss += Ensorcelled Hibernation:ah ss += Tukima's Dance:btD ss += Confusing Touch:ct ss += Gloom:dgG ## Summoner Start ss += Summon Small Mammal:am ss += Call Imp:bciI ss += Call Canine Familiar:cD ss += Eringya's Surprising Crocodile:dC ss += Summon Seismosaurus Egg:E ## Necromancer Start ss += Soul Splinter:asS ss += Grave Claw:bcgG ss += Vampiric Draining:cvV ss += Animate Dead:dAD ss += Curse of Agony:eC ## Fire Elementalist Start ss += Foxfire:ao ss += Scorch:bs : if you.class() ~= 'Hexslinger' then ss += Inner Flame:iI : end ss += Volatile Blastmotes:cvV ss += Flame Wave:dw ## Air Elementalist Start ss += Shock:as ss += Static Discharge:bS ss += Swiftness:cw ss += Airstrike:dA ## Ice Elementalist Start ss += Freeze:aF ss += Frozen Ramparts:br ss += Ozocubu's Armor:co ss += Summon Ice Beast:dS ####################### AUTOINSCRIBE ####################### ai := autoinscribe # autoinscribe =f on ranged weapons to keep them from # auto-quivering when wielding them ai += potion:!q ai += (bad|dangerous)_item.*scroll:!r ai += scrolls? of (fog|teleportation|poison|revelation|summoning):!r ai += ranged weapon:=f ai += boomerang:@f1 ai += javelin:@f2 ai += large rock:@f3 ###################### DUMP AND NOTES ###################### dump_message_count = 250 dump_item_origins = all dump_order += turns_by_place, kills_by_place note_all_skill_levels = true note_items += wand, potions?, scrolls? note_hp_percent = 50 note_messages += (You add the spell|wells up from within) note_messages += You quaff a potion note_messages += As you read (a|the) scroll note_messages += You invoke # haste note_messages += You feel yourself speed up # curing, healing # This seems to also appear when Makleb gives you HP for killing things. # note_messages += You feel better note_messages += You feel much better # resistance note_messages += You feel protected # brilliance note_messages += You feel clever all of a sudden # lignification note_messages += You turn into a tree # ambrosia note_messages += You savour every drop. You feel invigorated # invisibility note_messages += You fade into invisibility # magic note_messages += You savour every drop. Magic courses through your body # might note_messages += You feel very mighty all of a sudden # cancellation note_messages += You feel magically purged # enlightenment note_messages += You feel very buoyant # attraction note_messages += You feel attractive to monsters # heavenly storm note_messages += The air is filled with shimmering golden clouds note_messages += The storm will not cease as long as you keep fighting note_messages += The heavenly storm settles ##### Sound Support (requires DWEM module) ######################### # sound_on = true # one_SDL_sound_channel = true # sound_fade_time = 0.5 # sound_volume = 0.4 # bgm_volume = 0.4 # sound_pack += https://crawl-br.roguelikes.gg/soundpacks/osp-latest.zip:["init.txt"] # sound_pack += https://crawl-br.roguelikes.gg/soundpacks/BindTheEarth.zip:["init.txt"] ############################################################ { function c_answer_prompt(prompt) if toggleable_settings['explore_never_die'] and prompt == "Die?" then crawl.mpr("(You would have died, but you're in explore mode.)") return false end end } ############################################################ # these aren't really necessary: # # crawl.setopt("clear_messages = false") # crawl.setopt("show_more = false") # crawl.setopt("force_more_message = nil") { function ready() AnnounceDamage() end } : if is_bcrawl then tile_full_screen = false auto_butcher = true # auto_butcher_max_chunks = 2 macros += M - < macros += M + > macros += M \{32} ===false tile_player_tile = tile:MONS_MARA : end # tile_player_tile = tile:MONS_MARA # autopickup_exceptions ^= >shield