# Crawl Init file ##################### ### Tiles options ### ##################### tile_window_width = 1300 tile_window_height = 700 tile_full_screen = false ## To set up RandomTiles, you need (1) the include below and (2) to add/modify ## the ready() function in your rc. See my ready() section below and the ## project page: https://github.com/gammafunk/dcss-rc#randomtiles include += RandomTiles.rc ################## ### UI options ### ################## travel_delay = -1 explore_delay = -1 rest_delay = -1 view_delay = 300 runrest_ignore_poison = 2:10 runrest_ignore_monster += ^butterfly$:1 show_travel_trail = false confirm_butcher = never easy_eat_chunks = true rest_delay = -1 hp_colour = 100:green, 75:yellow, 50:red, 25:lightred mp_colour = 100:green, 75:yellow, 50:red, 25:lightred hp_warning = 25 autofight_stop = 50 auto_sacrifice = true bindkey = [~] CMD_LUA_CONSOLE #################### ### Menu options ### #################### drop_filter += useless_item ### Menu colorings ### ## These should match the item_glyph colours exactly when possible. menu := menu_colour menu = ### General colorings ### ## These two need to come first to override any entries below. menu += darkgrey:.*useless.* menu += red:.*evil_item.* menu += pickup:lightcyan:god gift menu += inventory:white:\w \#\s menu += notes:white:Reached XP level menu += inventory:white:\w \+\s menu += darkgrey:(melded) menu += lightred: cursed menu += inventory:lightgreen:.*equipped.* ### Food ### menu += red:evil_eating.*chunk menu += magenta:mutagenic.*chunk menu += green:poisonous.*chunk menu += darkgrey:(rotting.*chunk|inedible|rot-inducing) menu += brown:contaminated.*chunk menu += lightgrey: +(chunks?$|chunks? +) menu += brown:fruit menu += yellow:(pizza|jerky|jerkies|royal jell) menu += lightcyan:(meat ration|bread ration) ### Potions ### menu += darkgrey:potions? of.*(poison) ## buffs menu += green:potions? of.*(berserk|agility|brilliance|might|flight) menu += lightgreen:potions? of.*(resistance|invisibility|haste) ## healing menu += brown:potions? of.*curing menu += yellow:potions? of.*heal wounds ## "magic" menu += magenta:potions? of.*(cancellation|ambrosia) menu += lightmagenta:potions? of.*magic ## "really good" or restorative menu += cyan:potions? of.*(restore abilities|cure mutation) menu += lightcyan:potions? of.*(beneficial mutation|experience) ## food potions : if you.race() == "Vampire" then menu += lightred:potions? of blood : else menu += darkgrey:potions? of.*blood : end ### Scrolls ### ## "equipment/spells" menu += brown:scroll.*(amnesia|curse) menu += yellow:scroll.*(identify) ## Enchant menu += green:scroll.*enchant weapon menu += lightgreen:scroll.*(enchant armour|brand weapon|enchant weapon III) ## Escape menu += magenta:scroll.*(fog|teleport) menu += lightmagenta:scroll.*(fear|blink) ## Damaging scrolls : if you.race() == "Vampire" or you.race() == "Mummy" : or you.race() == "Ghoul" then menu += blue:scroll.*(holy word) menu += lightred:scroll.*(torment) : else menu += lightred:scroll.*(holy word) menu += blue:scroll.*(torment) : end menu += lightred:scroll.*summoning ## tactical and the really good stuff (mmap for speedruns) menu += cyan:scroll.*(silence|noise|vulnerability|immolation) menu += lightcyan:scroll.*(acquire|recharging|magic map) ### Wands ### menu += lightcyan:wand of.*heal wounds ## hexes menu += green:wand of.*(slowing|confusion|random effects) menu += lightgreen:wand of.*(polymorph|paralysis|enslavement) ## escape menu += magenta:wand of.*(digging|disintegration|teleportation) menu += lightmagenta:wand of.*(hasting|invisibility) ## damage menu += brown:wand of.*(flame|frost|magic dart) menu += yellow:wand of.*(lightning|draining|cold|fire) menu += blue:.*dangerous_item.* ## Identification menu += lightmagenta:unidentified.*artefact.*jewellery menu += white:.*artefact menu += lightblue:unidentified .*(potion|scroll|wand|jewellery|book|rod|magical staff) menu += magenta:.*known.*ring of (dexterity|strength|intelligence|slaying|evasion|protection(?! from)) menu += inventory:lightgray:.*(book|jewellery|magical staff) menu += lightblue:unidentified .*weapon.*(runed|glowing|enchanted) menu += lightblue:unidentified .*armour.*(runed|glowing|embroidered|shiny|dyed) sort_menus += inv: true : equipped, charged ######################## ### Glyphs and colors ## ######################## item := item_glyph ## Reasonable defaults item += potion:lightgrey item += scroll:lightgrey item += dangerous_item:blue ### Potions ### item += potions? of.*(poison):darkgrey item += potions? of.*(berserk|agility|brilliance|might|flight):green item += potions? of.*(resistance|invisibility|haste):lightgreen item += potions? of.*(cancellation|ambrosia):magenta item += potions? of.*magic:lightmagenta item += potions? of.*heal wounds:yellow item += potions? of.*curing:brown item += potions? of.*(restore abilities|cure mutation):cyan item += potions? of.*(beneficial mutation|experience):lightcyan : if you.race() == "Vampire" then item += potions? of blood:lightred item += potions? of coagulated blood:lightgrey : else item += potions? of.*blood:darkgrey : end ### Scrolls ### item += scroll.*(amnesia|curse):brown item += scroll.*identify:yellow item += scroll.*enchant weapon:green item += scroll.*(enchant armour|brand weapon|enchant weapon III):lightgreen item += scroll.*(fog|teleport):magenta item += scroll.*(fear|blink):lightmagenta : if you.race() == "Vampire" or you.race() == "Mummy" : or you.race() == "Ghoul" then item += scroll.*(holy word):red item += scroll.*(torment):lightred : else item += scroll.*(holy word):lightred item += scroll.*(torment):red : end item += scroll.*(summoning):lightred item += scroll.*(vulnerability|noise|silence|immolation):cyan item += scroll.*(acquire|recharging|magic map):lightcyan item += ( rod ):yellow ### Identification item += (book|jewellery|magical staff):brown item += unidentified.*(potion|scroll|jewellery|book|wand|rod|magical staff).*:lightblue item += known.*ring of (dexterity|strength|intelligence|slaying|evasion|protection(?! from)):magenta item += identified.*artefact.*jewellery:white item += unidentified.*artefact.*jewellery.*:lightmagenta item += (a )?stones?$:lightgray ### Food ### item += chunks?.*flesh:lightgrey item += contaminated.*chunk:brown item += mutagenic.*chunk:magenta item += evil_eating.*chunk:red item += (inedible|rotting.*chunk):darkgrey item += poisonous.*chunk:green item += fruit:brown item += (pizza|jerky|jerkies|royal jell):yellow item += (meat ration|bread ration):lightcyan ### Wands ### item += wand of.*heal wounds:lightcyan item += wand of.*(slowing|confusion|random effects):green item += wand of.*(polymorph|paralysis|enslavement):lightgreen item += wand of.*(digging|disintegration|teleportation):magenta item += wand of.*(hasting|invisibility):lightmagenta item += wand of.*(flame|frost|magic dart):brown item += wand of.*(lightning|draining|cold|fire):yellow ## Want this to override anything above item += useless.*(food|book|potion|scroll|missile|armour|weapon|jewellery|rod):darkgrey item += evil_item:red ## Monsters that can be easy to miss mons := mon_glyph mons ^= dancing weapon : cyan { mons ^= spectral weapon : lightcyan { mons ^= * : ✱ ## Wall glyphs, requires a font and terminal that can render these. feature += crystal wall {░} feature += stone wall {▒} feature += metal wall {▓} feature += unnaturally hard rock wall {█} feature += altar {⚑} ######################### ### Interface options ### ######################### ability_menu = false default_manual_training = true allow_self_target = prompt ######################## ### Auotpick options ### ######################## ## Add staves and rods; note you can't use += with this option. autopickup = $?!+"/%|\ ae := autopickup_exceptions ## Don't ever need a second stave ae += staff of .* #################### ### Autoinscribe ### #################### ai := autoinscribe ai += (bad|dangerous)_item.*potion:!q ai += (bad|dangerous)_item.*scroll:!r ai += potion.*(berserk rage):!q ai += of faith:!P ai += ( rod ):!a ai += manual of:!d ai += staff of (Wucad Mu|energy|channeling|wizardry|power|conjuration|summoning):!a ## from simm's rc ai += curing:@q1 ai += potions? of heal wounds:@q2 ai += wand of heal wounds:@v2 ai += potions? of haste:@q3 ai += wand of hasting:@v3 ai += scrolls? of teleportation:@r4 ai += wand of teleportation:@v4 ai += identify:@r1 ai += remove curse:@r2 ai += blowgun:@w1 ai += (curare|dispersal):!f ai += (meat|bread) ration:@e1 ai += (beef jerk|fruit|pizza):@e2 ai += royal jell:@e3 ######### # Notes # ######### note_items += acquirement, of Zot note_messages += You pass through the gate note_messages += cast .* Abyss note_messages += Your scales start note_messages += protects you from harm note_messages += You fall through a shaft ## Nasty undead from Vaults and Tomb note_monster += lich,ancient lich,curse skull,greater mummy ## Some enemies it's good to note for Vaults:5 note_monsters += tengu reaver,storm dragon,titan ## Depths ## 0.17 note_monsters += octopode crusher note_monsters += juggernaut,irong giant,caustic shrike ## Zot note_monsters += killer klown,electric golem,death cob,curse toe,orb of fire ##################### ### More messages ### ##################### more := force_more_message # Important features : if you.god() == "Ashenzari" then more += You have a vision of.*gates? : else more += interdimensional caravan more += distant snort more += Found a gateway leading out of the Abyss : end more += Found .* abyssal rune of Zot more += You feel a terrible weight on your shoulders # Interrupts more += You don't.* that spell more += You fail to use your ability more += You miscast more += You can't (read|drink|do) that more += That item cannot be evoked more += This wand has no charges more += You are held in a net more += You don't have any such object more += do not work when you're silenced more += You can't unwield more += enough magic points more += You feel your control is inadequate # Bad things more += Your surroundings flicker more += sense of stasis more += You cannot teleport right now more += The writing blurs in front of your eyes more += You fall through a shaft more += (blundered into a|invokes the power of) Zot more += Ouch! That really hurt! more += dispelling energy hits you more += You convulse more += You are (blasted|electrocuted)! more += You are (more )?confused more += You are (more |lethally )?poisoned more += wrath finds you more += lose consciousness more += Space warps horribly around you more += hits you.*distortion more += Space bends around you\. more += watched by something more += The dungeon rumbles around more += The air twists around and violently strikes you in flight # Expiring effects more += You feel yourself slow down more += You are starting to lose your buoyancy more += Your hearing returns more += Your transformation is almost over more += You feel yourself come back to life more += uncertain # Others more += You have reached level more += You have finished your manual of more += Deactivating autopickup ## Problematic monsters more += (giant eyeball|shining eye|cacodemon|neqoxec|guardian serpent|flayed ghost|greater mummy|mummy priest|hell sentinel|fiend|tormentor|hellion|lich|executioner|orb of fire|death cob|juggernaut|moth of wrath|ghost moth|curse toe|curse skull|draconian shifter).*into view ## Any uniques and any pan lords more += (?-i:[A-Z]).* comes? into view ## 0.17 more += the royal jelly.* comes? into view ################### ### Spell slots ### ################### # Buff/utility/escape spells we always try to put on specific letters. # Uses following letters: aeghijlmrsBEKU spell_slot += Abjuration:jJA spell_slot += Aura of abjuration:jJA spell_slot += Apportation:aAP spell_slot += Blink:KBI spell_slot += Borgnjor's revivification:BNV spell_slot += Cigotuvi's Embrace:ige spell_slot += Condensation shield:ihe spell_slot += Control teleport:ECT spell_slot += Controlled blink:ieC spell_slot += Cure poison:ieP spell_slot += Death's door:DOT spell_slot += Deflect missiles:rRM spell_slot += Flight:lLF spell_slot += Haste:hHA spell_slot += Invisibility:ivI spell_slot += Phase shift:ieP spell_slot += Mass abjuration:jJA spell_slot += Ozocubu's armour:mMO spell_slot += Passage of golubria:gei spell_slot += Recall:eER spell_slot += Regeneration:geG spell_slot += Repel missiles:rRM spell_slot += Ring of flames:meF spell_slot += Shroud of golubria:ihg spell_slot += Silence:SIC spell_slot += Song of slaying:giS spell_slot += Stoneskin:ieS spell_slot += Swiftness:sST spell_slot += Sublimation of blood:BMN spell_slot += Summon butterflies:UBT # All other spells # Use z for L1 damage/buff spells # Generic: bodkqvwy # Uses the following for specific schools, preferably is spell name contains it # or as a fallback if it doesn't. # Fire: f; Cold: c; Necromancy: n; Earth: t; Poison: p; Summoning: u; Hexes: x spell_slot += Alistair's intoxication:tox spell_slot += Airstrike:ktT spell_slot += Agony:yno spell_slot += Animate dead:ndt spell_slot += Animate skeleton:nkt spell_slot += Beastly appendage:zbt spell_slot += Blade hands:bdB # Try to put bolt spells on b spell_slot += Bolt of cold:bco spell_slot += Bolt of draining:bnd spell_slot += Bolt of fire:bfo spell_slot += Bolt of magma:bof spell_slot += Call canine familiar:fuc spell_slot += Call imp:puc spell_slot += Cause fear:xcf spell_slot += Corona:zox spell_slot += Chain lightning:tcn spell_slot += Cigutovi's embrace:vtn spell_slot += Confusing touch:oxc spell_slot += Confuse:ocf spell_slot += Conjure flame:ofu spell_slot += Control undead:not spell_slot += Corpse rot:otn spell_slot += Dazzling spray:ydz spell_slot += Darkness:DAR spell_slot += Death channel:ndt spell_slot += Discord:DOC spell_slot += Disjunction:dox spell_slot += Dispel undead:ndp spell_slot += Dispersal:dxp spell_slot += Dragon form:dof spell_slot += Dragon's call:dou spell_slot += Ensorcelled hibernation:zbx spell_slot += Excruciating wounds:nwd spell_slot += Fire storm:fot spell_slot += Fireball:fbd spell_slot += Flame tongue:zfo spell_slot += Force lance:ofc spell_slot += Freezing cloud:cdo spell_slot += Freeze:zcf spell_slot += Fulminant prism:ptf spell_slot += Gell's Gravitas:vxt spell_slot += Glaciate:ctb spell_slot += Haunt:unt spell_slot += Hydra form:ydo spell_slot += Ice form:cof spell_slot += Ice storm:cot spell_slot += Iron shot:ton spell_slot += Infusion:ofn spell_slot += Inner flame:fxn spell_slot += Irradiate:tdI spell_slot += Iskenderun's battlesphere:kdb spell_slot += Iskenderun's mystic blast:byd spell_slot += Leda's Liquefaction:qtx spell_slot += Lee's rapid deconstruction:tdo spell_slot += Lehudib's crystal spear:tyb spell_slot += Lightning bolt:bot spell_slot += Magic dart:zdt spell_slot += Malign gateway:wyt spell_slot += Mass confusion:oxc spell_slot += Mephitic cloud:pdc spell_slot += Metabolic englaciation:cob spell_slot += Monstrous menagerie:uot spell_slot += Necromutation:ntN spell_slot += Orb of destruction:odb spell_slot += Ozocubu's refrigeration:coz spell_slot += Pain:znp spell_slot += Passwall:wpP spell_slot += Petrify:yxt spell_slot += Poison arrow:pwo spell_slot += Poisonous cloud:pod spell_slot += Portal projectile:otc spell_slot += Sandblast:zbt spell_slot += Searing ray:ybn spell_slot += Shadow creatures:wdu spell_slot += Shatter:TSH spell_slot += Shock:zok spell_slot += Simulacrum:cnu spell_slot += Slow:wox spell_slot += Spectral weapon:wox spell_slot += Spellforged servitor:vto spell_slot += Spider form:pdS spell_slot += Static discharge:tdc spell_slot += Statue form:toS spell_slot += Sticks to snakes:tkc spell_slot += Sticky flame:yfk spell_slot += Sting:zpt spell_slot += Stone arrow:wto spell_slot += Summon demon:dou spell_slot += Summon forest:ouf spell_slot += Summon greater demon:dou spell_slot += Summon guardian golem:dou spell_slot += Summon horrible things:bou spell_slot += Summon hydra:ydu spell_slot += Summon ice beast:bcu spell_slot += Summon lightning spire:tpu spell_slot += Summon mana viper:vpu spell_slot += Summon small mammal:zou spell_slot += Teleport other:opt spell_slot += Throw frost:cow spell_slot += Throw flame:fow spell_slot += Throw icicle:cwo spell_slot += Tornado:TOD spell_slot += Tukima's Dance:dkx spell_slot += Vampiric draining:vnd spell_slot += Venom bolt:bpo spell_slot += Warp weapon:wop # Default letters spell_slot += .*:YXWZ ################## ### Item slots ### ################## ## In order of letter used. item_slot += amulet of stasis : A item_slot += amulet of rage : B item_slot += ring of (ice|protection from cold) : Cc item_slot += amulet of the gourmand : D item_slot += \+[0-9]+ ring of evasion : Ee item_slot += ring of .*fire : Ff item_slot += amulet of regeneration : g item_slot += amulet of guardian spirit : G item_slot += amulet of faith : H item_slot += \+[0-9]+ ring of intelligence : Ii item_slot += amulet of warding : J item_slot += amulet of clarity : K item_slot += ring of flight : L item_slot += ring of protection from magic : Mm item_slot += ring of positive energy : Nn item_slot += \+[0-9]+ ring of protection : Oo item_slot += ring of poison resistance : P item_slot += ring of stealth : Qq item_slot += amulet of resist corrosion : R item_slot += \+[0-9]+ ring of strength : Ss item_slot += ring of teleportation : T item_slot += ring of sustain (abilities|attributes) : u item_slot += amulet of resist mutation : U item_slot += ring of see invisible : v item_slot += ring of invisibility : V item_slot += ring of magical power : Ww item_slot += \+[0-9]+ ring of dexterity : Xx item_slot += \+[0-9]+ ring of slaying : Yy item_slot += ring of wizardry : Zz ############ ## Macros ## ############ macros += M e ===safe_eat macros += M S ===save_with_message macros += M 1 aa macros += M 3 zz macros += M 6 ===one_turn_rest macros += M 7 ===start_resting macros += M 8 ===new_random_tile macros += M 9 ===set_tile_by_name macros += M 0 ===toggle_tile_timer macros += M - ===toggle_random_tile macros += M ] ===set_target_skill ###################### ### Morgue options ### ###################### dump_message_count = 30 dump_order = header,hiscore,stats,misc,mutations,skills,spells,inventory dump_order += screenshot,monlist,messages,action_counts,vaults,notes,kills note_hp_percent = 10 note_all_skill_levels = true note_chat_messages = false user_note_prefix = >> ################### ## Debug Options ## ################### fsim_rounds = 10000 ############################## ## Lua and ready() function ## ############################## { -- Spellcasting spam reduction by monqy local function generic_cast_spell(cmd) crawl.mpr('Cast which spell?') crawl.flush_prev_message() crawl.process_keys(cmd) end function cast_spell() generic_cast_spell('z') end function force_cast_spell() generic_cast_spell('Z') end -- Some simple options for turncount and realtime runs. Note I don't play much -- of the latter, and these options are taken from the RCs of players who do. -- Uses the toggle_options lua: -- https://github.com/gammafunk/dcss-rc#toggle_options option_groups = { ["turncount"] = { {option = "confirm_butcher = %t", on="never", off="auto"}, {option = "ai %t= (bread|meat) ration:!e", on="+", off="-"}, {option = "ai %t= scroll.+of.*(acquirement|summoning|teleportation" .. "|fear|magic mapping):!r", on="+", off="-"}, {option = "ai %t= potion.+of(curing|heal wounds|might|agility" .. "|brilliance|magic|invisibility):!q", on="+", off="-"} }, ["realtime"] = { {option = "ae %t= >wand of (magic darts|flame|frost)", on="+", off="-"}, {option = "ae %t= >wand of (slowing|polymorph|confusion|paralysis)", on="+", off="-"}, {option = "use_animations = %t", on="", off="beam, range, hp, " .. "monster_in_sight, pickup, monster, player, branch_entry"}, }, } -- end option groups -- Note: My final rc file has the lua files from -- https://github.com/gammafunk/dcss-rc included starting on the next line. ----------------------------- ---- Begin char_defaults ---- ----------------------------- -- Load default skill settings for each race+class combination automatically on -- turn 0. Recommended that you also use *target_skill.lua* so that you can set -- skills (and a skill target) on turn 0 for chars without defaults and have -- this data automatically become the new default. To enable in your rc, add a -- lua code block with the contents of *char_defaults.lua* and a call to -- `char_defaults()` in your `ready()` function. If you are using -- *target_skill.lua*, this call must come before the call to `target_skill()` -- in `ready()`. Additionally, to save or load your defaults on the fly -- (e.g. if you forgotten to set something), you can assign a keys to macros -- with a targets of `===save_char_defaults` or `===load_char_defaults` or -- simply run these functions as needed in the lua console. weapon_skills = {"Unarmed Combat", "Short Blades", "Long Blades", "Axes", "Maces & Flails", "Polearms", "Staves"} ranged_skills = {"Throwing", "Bows", "Crossbows", "Slings"} other_skills = {"Fighting", "Armour", "Dodging", "Shields", "Spellcasting", "Conjurations", "Hexes", "Charms", "Summonings", "Necromancy", "Translocations", "Transmutations", "Fire Magic", "Ice Magic", "Air Magic", "Earth Magic", "Poison Magic", "Invocations", "Evocations","Stealth"} skill_glyphs = { [1] = "+", [2] = "*" } chdat = nil char_combo = you.race() .. you.class() loaded_attempted = false -- Wrapper of crawl.mpr() that prints text in white by default. if not mpr then mpr = function (msg, color) if not color then color = "white" end crawl.mpr("<" .. color .. ">" .. msg .. "") end end function save_default_target_skill(quiet) if not c_persist.target_skill or not have_defaults() then return end c_persist.char_defaults[char_combo].target_skill = c_persist.target_skill if not quiet then mpr("Set default target skill for " .. char_combo .. ": " .. c_persist.target_skill) end end function skill_message(prefix, skill, skill_type, value) local msg = "" if prefix then msg = prefix .. ";" end if skill_type then msg = msg .. skill_type .. "(" .. skill .. "):" .. value else msg = msg .. skill .. ":" .. value end return msg end function save_char_defaults(quiet) if you.class() == "Wanderer" then return end if not c_persist.char_defaults then c_persist.char_defaults = { } end c_persist.char_defaults[char_combo] = { } chdat = c_persist.char_defaults[char_combo] local msg = nil local have_weapon = false for _,sk in ipairs(weapon_skills) do if you.train_skill(sk) > 0 then chdat["Weapon"] = you.train_skill(sk) msg = skill_message(nil, sk, "Weapon", skill_glyphs[chdat["Weapon"]]) have_weapon = true break end end if not have_weapon then chdat["Weapon"] = nil end local have_ranged = false for _,sk in ipairs(ranged_skills) do if you.train_skill(sk) > 0 then chdat["Ranged"] = you.train_skill(sk) msg = skill_message(msg, sk, "Ranged", skill_glyphs[chdat["Ranged"]]) have_ranged = true break end end if not have_ranged then chdat["Ranged"] = nil end for _,sk in ipairs(other_skills) do if you.train_skill(sk) > 0 then chdat[sk] = you.train_skill(sk) msg = skill_message(msg, sk, nil, skill_glyphs[chdat[sk]]) else chdat[sk] = nil end end if target_skill then chdat["target_skill"] = nil if not need_target_skill and c_persist.target_skill then chdat["target_skill"] = c_persist.target_skill msg = skill_message(msg, "Target", nil, c_persist.target_skill) end end if not quiet then mpr("Saved default for " .. char_combo .. ": " .. msg) end end function have_defaults() return you.class() ~= "Wanderer" and c_persist.char_defaults and c_persist.char_defaults[char_combo] end function load_char_defaults(quiet) if not have_defaults() then return end local msg = nil local found_weapon = false chdat = c_persist.char_defaults[char_combo] for _,sk in ipairs(weapon_skills) do if you.base_skill(sk) > 0 and chdat["Weapon"] then you.train_skill(sk, chdat["Weapon"]) msg = skill_message(msg, sk, "Weapon", skill_glyphs[chdat["Weapon"]]) found_weapon = true else you.train_skill(sk, 0) end end if chdat["Weapon"] and not found_weapon then you.train_skill("Unarmed Combat", chdat["Weapon"]) msg = skill_message(msg, "Unarmed Combat", "Weapon", skill_glyphs[chdat["Weapon"]]) end local found_ranged = false for _,sk in ipairs(ranged_skills) do if you.base_skill(sk) > 0 and chdat["Ranged"] then you.train_skill(sk, chdat["Ranged"]) msg = skill_message(msg, sk, "Ranged", skill_glyphs[chdat["Ranged"]]) found_ranged = true else you.train_skill(sk, 0) end end if chdat["Ranged"] and not found_ranged then you.train_skill("Throwing", chdat["Ranged"]) msg = skill_message(msg, "Throwing", "Ranged", skill_glyphs[chdat["Ranged"]]) end for _,sk in ipairs(other_skills) do if chdat[sk] then you.train_skill(sk, chdat[sk]) msg = skill_message(msg, sk, nil, skill_glyphs[chdat[sk]]) else you.train_skill(sk, 0) end end if target_skill then if chdat["target_skill"] then c_persist.target_skill = chdat["target_skill"] msg = skill_message(msg, "Target", nil, c_persist.target_skill) need_target_skill = false record_current_skills(c_persist.target_skill) else -- Called by target_skill() trigger setting a skill target. We call -- it here here since setting it skips the skills menu, which we -- don't want that. This means the call to char_defaults() should -- come before target_skill() in ready() init_target_skill() end end if not quiet and msg ~= "" then mpr("Loaded default for " .. char_combo .. ": " .. msg) end end function char_defaults(quiet) if you.turns() ~= 0 then return end if not load_attempted then load_char_defaults(quiet) load_attempted = true end -- Save defaults if target_skill is loaded and has already been called if need_target_skill ~= nil and need_target_skill ~= true and not have_defaults() then save_char_defaults(quiet) end end --------------------------- ---- End char_defaults ---- --------------------------- ----------------------------- ---- Beging target_skill ---- ----------------------------- -- Opens the skill screen automaticaly when a skill reaches a target level set -- by the player. To enable in your rc, add a lua code block with the contents -- of *target_skill.lua* and a call to `target_skill()` in your `ready()` -- function. Additionally you'll wand to assign a key to a macro with a target -- of `===set_target_skill` so can change the skill target on the fly. Original -- code by elliptic with some reorganization. skill_list = {"Fighting","Short Blades","Long Blades","Axes","Maces & Flails", "Polearms","Staves","Unarmed Combat","Bows","Crossbows", "Throwing","Slings","Armour","Dodging","Shields","Spellcasting", "Conjurations","Hexes","Charms","Summonings","Necromancy", "Translocations","Transmutations","Fire Magic","Ice Magic", "Air Magic","Earth Magic","Poison Magic","Invocations", "Evocations","Stealth"} need_target_skill = nil function record_current_skills(maxlev) c_persist.current_skills = { } for _,sk in ipairs(skill_list) do if you.train_skill(sk) > 0 and you.base_skill(sk) < (maxlev or 27) then table.insert(c_persist.current_skills, sk) end end end function check_skills() if not c_persist.current_skills or not c_persist.target_skill then return end for _,sk in ipairs(c_persist.current_skills) do if you.base_skill(sk) >= c_persist.target_skill then crawl.formatted_mpr(sk .. " reached " .. c_persist.target_skill .. ".", "prompt") crawl.more() set_new_skill_training() break end end end function init_target_skill() c_persist.target_skill = nil c_persist.current_skills = { } need_target_skill = true end function set_new_skill_training() init_target_skill() c_persist.target_skill = 0 crawl.sendkeys("m") end function set_target_skill() record_current_skills() local str = "Currently training: " local first_skill = true for _,sk in ipairs(c_persist.current_skills) do val = you.base_skill(sk) if first_skill then str = str .. sk .. "(" .. val .. ")" else str = str .. ", " .. sk .. "(" .. val .. ")" end first_skill = false end str = str .. "." crawl.formatted_mpr(str, "prompt") crawl.formatted_mpr("Choose a target skill level: ", "prompt") c_persist.target_skill = tonumber(crawl.c_input_line()) record_current_skills(c_persist.target_skill) -- Update the target skill for char_defaults if necessary. if save_default_target_skill and you.turns() == 0 then save_default_target_skill() end end function control(c) return string.char(string.byte(c) - string.byte('a') + 1) end -- Moved this to its own function to clean up ready() -gammafunk function target_skill() prev_need_target = need_target_skill -- Need to look at skills and then set a target skill if our -- need_target_skill variable is uninitialized and we're either at turn 0 or -- c_persist.target_skill also uninitialized. if prev_need_target == nil and (you.turns() == 0 or c_persist.target_skill == nil) then set_new_skill_training() end if prev_need_target then set_target_skill() need_target_skill = false elseif not need_target_skill then check_skills() end end -------------------------- ---- End target_skill ---- -------------------------- --------------------------------------- ---- Begin conditional force_mores ---- --------------------------------------- -- See README.md for details. last_turn = you.turns() -- Each entry must have a name field with a descriptive name, a pattern field -- giving the regexp matching the appropriate monster(s), a cond field giving -- the condition type, and a cutoff field giving the max value where the -- force-more is active. Possible values for cond are xl and maxhp. Note that -- the final pattern will be "(pattern).*into view" where pattern is the value -- from the entry. fm_patterns = { -- General early game threats {pattern = "adder|gnoll|hound", cond = "xl", cutoff = 2, name = "XL1"}, -- Problems for chars with 20, 60, 90, or 120 mhp {pattern = "orc|Ogre", cond = "20mhp", cutoff = 20, name = "20hp"}, {pattern = "orc priest", cond = "maxhp", cutoff = 40, name = "40mhp"}, {pattern = "centaur [^wzs]|drake|blink frog|spiny frog|basilisk" .. "|raven|komodo dragon|blink frog|snapping turtle|black mamba" .. "|(redback|trapdoor) spider|hill giant|deep elf (summoner|mage)" .. "|gargoyle|sixfirhy|sun demon", cond = "maxhp", cutoff = 60, name = "60mhp"}, {pattern = "hydra|death yak|tarantella|(wolf|orb|jumping) spider" .. "|alligator|catoblepas|(fire|ice) dragon|spriggan (rider|druid)" .. "|torpor|yaktaur|vault guard|manticore|harpy|faun|merfolk|siren" .. "|water nymph|mana viper|a wizard|[0-9]+ wizards|ogre mage" .. "|deep elf (knight|conjurer)|tengu conjurer|green death" .. "|shadow demon", cond = "maxhp", cutoff = 90, name = "90mhp"}, {pattern = "centaur warrior|yaktaur captain" .. "|(quicksilver|storm|shadow|iron) dragon|alligator snapping turtle" .. "|satyr|naga sharpshooter|merfolk avatar|anaconda|shock serpent" .. "|emperor scorpion(stone|frost|fire) giant|titan|entropy weaver" .. "|thorn hunter|sphinx|war gargoyle|preserver" .. "|vault (warden|sentinel)|convoker|monstrosity|tengu reaver" .. "|deep elf (master archer|blademaster|death mage" .. "|sorcerer|demonologist|annihilator)" .. "|octopode crusher|yaktaur captain|spriggan (defender|air mage)" .. "|reaper|balrug", cond = "maxhp", cutoff = 120, name = "120mhp"} } -- end fm_patterns active_fm = {} -- Set to true to get a message when the fm change notify_fm = false -- Wrapper of crawl.mpr() that prints text in white by default. if not mpr then mpr = function (msg, color) if not color then color = "white" end crawl.mpr("<" .. color .. ">" .. msg .. "") end end 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 == "maxhp" 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() ------------------------- ---- End force_mores ---- ------------------------- ---------------------------- ---- Begin load_message ---- ---------------------------- -- Leave a message on save that will be displayed next time the player -- loads the game. To enable in your rc, add a lua code block with the -- contents of *load_message.lua*, add a call to `load_message()` in -- your `ready()` function, and make a macro binding 'S' to -- `===save_with_message`. Original code by elliptic with some -- reorganization. message_color = "white" -- Wrapper of crawl.mpr() that prints text in white by default. if not mpr then mpr = function (msg, color) if not color then color = "white" end crawl.mpr("<" .. color .. ">" .. msg .. "") end end function save_with_message() if you.turns() == 0 then crawl.sendkeys("S") return end crawl.formatted_mpr("Save game and exit?", "prompt") local res = crawl.getch() if not (string.char(res) == "y" or string.char(res) == "Y") then crawl.formatted_mpr("Okay, then.", "prompt") return end crawl.formatted_mpr("Leave a message: ", "prompt") local res = crawl.c_input_line() c_persist.message = res crawl.sendkeys(control("s")) end function load_message() if c_persist.message and c_persist.message ~= "nil" and c_persist.message ~= "" then mpr("MESSAGE: " .. c_persist.message, message_color) c_persist.message = nil end end ----------------------------------- ---- End leave message on save ---- ----------------------------------- ------------------------ ---- Begin safe_eat ---- ------------------------ -- Prompt when eating in LOS of charmed tier-one demon, such as those made by -- summon greater demon, since they can become hostile mid-meal. To enable in -- your rc, add a lua code block with the contents of *force_mores.lua* and -- make a macro binding your 'e' key to `===safe_eat`. version = 0.15 if crawl.version then version = tonumber(crawl.version("major")) end los_range = version >= 0.17 and 7 or 8 function safe_eat() tier_one_demons = {["executioner"] = true, ["shadow fiend"] = true, ["ice fiend"] = true, ["brimstone fiend"] = true, ["hell sentinel"] = true} have_t1 = false for x = -los_range,los_range do for y = -los_range,los_range do m = monster.get_monster_at(x, y) if m and m:status("in your thrall") and tier_one_demons[m:desc():lower()] ~= nill then have_t1 = true t1_desc = m:desc() break end end end if have_t1 then crawl.formatted_mpr("Really eat with the " .. t1_desc .. " in view?", "prompt") local res = crawl.getch() if not (string.char(res) == "y" or string.char(res) == "Y") then crawl.formatted_mpr("Okay, then.", "prompt") return end end crawl.sendkeys("e") end ---------------------- ---- End safe_eat ---- ---------------------- ------------------------- ---- Begin char_dump ---- ------------------------- -- Make a character dump every N turns (default of 1000). To enable in your rc, -- add a lua code block with the contents of *char_defaults.lua* and a call to -- `char_defaults()` in your `ready()` function. local dump_count = you.turns() local dump_period = 1000 function char_dump() if you.turns() >= dump_count then dump_count = dump_count + dump_period crawl.dump_char() end end ----------------------- ---- End char_dump ---- ----------------------- ----------------------------- ---- Begin speedrun_rest ---- ----------------------------- -- See README.md for documentation -- How many turns to rest at max. num_rest_turns = 20 -- If true, look for a foot item inventory slot and use fallback_slot if we -- can't find a ration. If false, always use fallback_slot. automatic_slot = true -- Slot where you keep your slow swing item. fallback_slot = "c" -- Set to true to have Na characters always walk instead of item swing if -- they're able to walk slowly. This is not as turncount efficient for non-Chei -- worshipers, but the difference is small and some Na players may prefer it -- over having to change the wielded weapon. naga_always_walk = false -- Delay in milliseconds before sending the next walk command. Makes the -- visuals a bit less jarring when using walk resting. Set to 0 to disable. walk_delay = 50 -- To have the multi-turn rest ignore status change messages, add an entry here -- giving the pattern of the message you'd like to ignore. The entries below -- cover the transition messages from the regen spell, Trog's hand, and poison -- status. The key should be the status that's seen in the output of -- `you.status()` when the status is active, and the value should be a single -- pattern string or an array of pattern strings matching the message you'd -- like to ignore. See the lua string library manual for details on making -- patterns. status_messages = { ["poisoned"] = {"You feel[^%.]+sick%.", "You are no longer poisoned%."}, ["regenerating"] = {"You feel the effects of Trog's Hand fading%.", "Your skin is crawling a little less now%."} } --end status_messages -- Like status_messages above, but for arbitrary messages. Any message matching -- one of these patterns is ignored. ignore_messages = { --RandomTiles messages "Trog roars: Now[^!]+!+", "Sif Muna whispers: Become[^!]+!+", "[^:]+ says: Become[^!]+!+", --Debug messages "Dbg:.*", } -- end ignore_messages -- NOTE: No configuration past this point. ATT_NEUTRAL = 1 version = 0.15 if crawl.version then version = tonumber(crawl.version("major")) end los_range = version >= 0.17 and 7 or 8 -- Wrapper of crawl.mpr() that prints text in white by default. if not mpr then mpr = function (msg, color) if not color then color = "white" end crawl.mpr("<" .. color .. ">" .. msg .. "") end end function control(c) return string.char(string.byte(c) - string.byte('a') + 1) end function delta_to_vi(dx, dy) local d2v = { [-1] = { [-1] = 'y', [0] = 'h', [1] = 'b'}, [0] = { [-1] = 'k', [1] = 'j'}, [1] = { [-1] = 'u', [0] = 'l', [1] = 'n'}, } -- hack return d2v[dx][dy] end function reset_rest() -- Clear out the now-unused persistant table in old versions if c_persist.bread then c_persist.bread = nil end if not rstate then rstate = { } rstate.set_slot = false rstate.dir_x = nil rstate.dir_y = nil end rstate.last_acted = nil rstate.wielding = false rstate.resting = false rstate.num_turns = nil rstate.rest_start = nil rstate.start_hp = nil rstate.start_status = { } rstate.start_message = nil end function abort_rest(msg) if msg then mpr(msg, "lightred") end reset_rest() end function crawl_message(i) local msg = crawl.messages(i):gsub("\n", "") msg = msg:gsub("^%c* *", "") msg = msg:gsub(" *%c*?$", "") return msg end function record_status() -- Record starting status to track any status changes. rstate.start_status = { } local status = you.status() for s,_ in pairs(status_messages) do if status:find(s) then rstate.start_status[s] = true end end rstate.start_message = get_last_message() end function in_water() return view.feature_at(0, 0):find("water") and not you.status("flying") end function get_last_message() local rest_type = get_rest_type() local in_water = in_water() -- Ignore these movement messages when walking. local move_patterns = {"There is a[^%.]+here.", "Things that are here:.*", "Items here:.*"} for i = 1,200 do local msg = crawl_message(i) for s,_ in pairs(rstate.start_status) do if type(status_messages[s]) == "table" then for _,p in ipairs(status_messages[s]) do msg = msg:gsub(p, "") end else msg = msg:gsub(status_messages[s], "") end end if rest_type == "walk" then for _,p in ipairs(move_patterns) do -- Also remove any whitespace. msg = msg:gsub(" *" .. p .. " *", "") end end msg = msg:gsub(" *Beep! [^%.]+%. *", "") for _,p in ipairs(ignore_messages) do msg = msg:gsub(p, "") end if msg ~= "" then return msg end end return nil end function wield_swing_item() rstate.wielding = true rstate.last_acted = you.turns() record_status() crawl.sendkeys("w" .. c_persist.swing_slot) end function find_swing_slot() rstate.set_slot = true if not automatic_slot then c_persist.swing_slot = fallback_slot return end c_persist.swing_slot = nil for _,item in ipairs(items.inventory()) do if item.class() == "Comestibles" then c_persist.swing_slot = items.index_to_letter(item.slot) break end end if not c_persist.swing_slot then c_persist.swing_slot = fallback_slot end end function swing_item_wielded() local weapon = items.equipped_at("Weapon") return weapon and weapon.slot == items.letter_to_index(c_persist.swing_slot) end function hostile_in_los() local have_t1 = false for x = -los_range,los_range do for y = -los_range,los_range do m = monster.get_monster_at(x, y) if m and not m:is_safe() then return true end end end return false end function ponderous_level() local level = 0 for _,item in ipairs(items.inventory()) do local ego = item.ego() if item.equipped and ego == "ponderousness" then level = level + 1 end end return level end -- XXX See if we can move at least some of this into clua, since it's -- recreating play_movement_speed() and player_speed(). The aim is to determine -- if slow move is more regen-efficient and that the saving is worth the -- hassle, this calculates the minimum move speed, which can normally vary at -- random from randomized delay (e.g. water) and the many uses of -- div_rand_round(). function player_move_speed() if you.transform() == "tree" then return 0 end local in_water = in_water() local walk_water = you.race() == "Merfolk" or you.race() == "Octopode" or you.god() == "Beogh" and you.piety_rank() == 5 or you.transform == "ice" -- This is player action speed, based on things that affect all actions. local player_speed = 10 if you.status("slowed") then player_speed = math.floor(player_speed * 3 / 2) end if you.status("berserking") and you.god() ~= "Cheibriados" or you.status("hasted") then player_speed = math.floor(player_speed * 2 / 3) end if you.transform() == "statue" or you.status("petrifying") then player_speed = math.floor(player_speed * 3 / 2) end if in_water and not walk_water then player_speed = math.floor(player_speed * 13 / 10) end -- This is the base player movement speed given all things that affect only -- movement. local move_speed = 10 if you.transform() == "bat" then move_speed = 5 elseif you.transform() == "pig" then move_speed = 7 elseif you.transform() == "porcupine" or you.transform == "wisp" then move_speed = 8 elseif in_water and (you.transform() == "hydra" or you.race() == "Merfolk") then move_speed = 6 elseif you.race() == "Tengu" and you.status("flying") then move_speed = 9 end local boots = items.equipped_at("Boots") local running_level = 0 if boots and not boots.is_melded and boots.ego() and boots.ego() == "running" then running_level = 1 end move_speed = move_speed - running_level move_speed = move_speed + ponderous_level() if you.god() == "Cheibriados" then -- Calculate this based on the minimum piety at the observed rank, -- since we can't know the true piety level. local piety_breaks = { 1, 30, 50, 75, 100, 120, 160 } move_speed = move_speed + 2 + math.floor(math.min(piety_breaks[you.piety_rank() + 1] / 20, 8)) end if you.status("frozen") then move_speed = move_speed + 4 end if you.status("grasped by roots") then move_speed = move_speed + 3 end local speed_mut = you.mutation("speed") local slow_mut = you.mutation("slowness") if speed_mut > 0 then move_speed = move_speed - speed_mut - 1 elseif slow_mut > 0 then move_speed = math.floor(move_speed * (10 + slow_mut * 2) / 10) end if not in_water and you.status("sluggish") then if move_speed >= 8 then move_speed = math.floor(move_speed * 3 / 2) elseif move_speed == 7 then move_speed = math.floor(7 * 6 / 5) end elseif not in_water and you.status("swift") then move_speed = math.floor(move_speed * 3 / 4) end if move_speed < 6 then move_speed = 6 end return math.floor(player_speed * move_speed / 10) end function get_rest_type() if you.race() == "Naga" and naga_always_walk or you.god() == "Cheibriados" or not weapon_can_swap() then return "walk" else return "item" end end function bad_to_act() local hp, mhp = you.hp() local rest_type = get_rest_type() -- Stop multiple turn action when our hp recovers. if rstate.rest_start and rstate.start_hp < mhp and hp == mhp then mpr("HP restored.") reset_rest() return true end if you.status("manticore barbs") then abort_rest("You must remove the manticore barbs first.") return true end if you.hunger_name() == "fainting" or you.hunger_name() == "starving" then abort_rest("You need to eat!") return true end if hostile_in_los() then if not rstate.rest_start then abort_rest("You can't rest with a hostile monster in view!") else abort_rest() end return true end -- If any unrecognized message occurs, assume we need to stop resting. if rstate.last_acted then local msg = get_last_message() if not msg then abort_rest("Unable to find a previous message!") return true end local wield_pt = "^ *" .. c_persist.swing_slot .. " - .+[%)}] *$" local swing_pt = "^ *You swing at nothing%. *$" local pattern = rstate.wielding and wield_pt or swing_pt if (rest_type == "item" and not msg:find(pattern)) or rest_type == "walk" and msg ~= rstate.start_message then abort_rest() return true end end if rest_type == "walk" and player_move_speed() <= 10 then abort_rest("You cannot walk slowly right now!") return true end return false end function feat_is_open(feat) local fname = feat:lower() -- Unique substrings that identify solid features. local solid_features = {"wall", "grate", "tree", "mangrove", "endless_lava", "open_sea", "statue", "idol", "malign_gateway", "sealed_door", "closed_door", "runed_door", "explore_horizon"} for i,p in ipairs(solid_features) do if fname:find(p) then return false end end return true end function safe_walk_pos(x, y) local in_water = in_water() local pos_is_water = view.feature_at(x, y):find("water") -- Don't allow walking out of water if we're in water return (in_water and pos_is_water -- Don't allow walking into water if we're not in it or not in_water and not pos_is_water) -- Require the destination to be safe. and view.is_safe_square(x, y) end function safe_swing_pos(x, y) return not monster.get_monster_at(x, y) and feat_is_open(view.feature_at(x,y)) end function safe_direction(x, y) if get_rest_type() == "walk" then return safe_walk_pos(x, y) else return safe_swing_pos(x, y) end end function weapon_can_swap() local weapon = items.equipped_at("Weapon") if not weapon then return true end if weapon.cursed then return false end local ego = weapon.ego() -- Some unrands like Plut. sword have no ego. if ego and (ego == "vampirism" or ego == "distortion" and you.god() ~= "Lugonu") then return false end if weapon.artefact then local artp = weapon.artprops return not (artp["*Contam"] or artp["*Curse"] or artp["*Drain"]) end return true end function get_safe_direction() local have_t1 = false for x = -1,1 do for y = -1,1 do if (x ~= 0 or y ~= 0) and safe_direction(x, y) then return x, y end end end return nil end function do_resting() -- Our first turn of resting. if not rstate.rest_start then record_status() rstate.rest_start = you.turns() rstate.start_hp = you.hp() end rstate.last_acted = you.turns() local rest_type = get_rest_type() if rest_type == "item" then crawl.sendkeys(control(delta_to_vi(rstate.dir_x, rstate.dir_y))) else local cur_x = rstate.dir_x local cur_y = rstate.dir_y -- Save the return direction as our next direction. rstate.dir_x = -rstate.dir_x rstate.dir_y = -rstate.dir_y crawl.sendkeys(delta_to_vi(cur_x, cur_y)) crawl.delay(walk_delay) end end function one_turn_rest() rstate.resting = true rstate.num_turns = 1 end function start_resting() rstate.resting = true rstate.num_turns = num_rest_turns end function set_swing_slot() crawl.formatted_mpr("Enter an slot letter for the swing item: ", "prompt") local letter = crawl.c_input_line() local index = items.letter_to_index(letter) if not index or index < 0 then mpr("Must be a letter (a-z or A-Z)!", "lightred") return end c_persist.swing_slot = letter rstate.set_slot = true mpr("Set swing slot to " .. letter .. ".") end function speedrun_rest() local rest_type = get_rest_type() if rest_type == "item" and (not c_persist.swing_slot or you.turns() == 0 and not rstate.set_slot) then find_swing_slot() end if not rstate.resting then return end -- Only act once per turn. if rstate.last_acted == you.turns() then -- An error happened with the 'w' command if rstate.wielding and not swing_item_wielded() then abort_rest("Unable to wield swing item on slot " .. c_persist.swing_slot .. "!") end return end if rstate.last_acted and rstate.rest_start and rstate.last_acted + 1 >= rstate.rest_start + rstate.num_turns then reset_rest() return end if bad_to_act() then return end if rest_type == "item" and not swing_item_wielded() then wield_swing_item() return end rstate.wielding = false if not rstate.dir_x -- Don't try to reuse our position if we were walk resting and did -- something inbetween our last rest. or swing_type == "walk" and rstat.last_acted ~= you.turns() - 1 or not safe_direction(rstate.dir_x, rstate.dir_y) then rstate.dir_x, rstate.dir_y = get_safe_direction() if not rstate.dir_x then abort_rest("No safe direction found!") return end end do_resting() end reset_rest() --------------------------- ---- End speedrun_rest ---- --------------------------- ----------------------------- ---- Begin toggle_options --- ----------------------------- -- Wrapper of crawl.mpr() that prints text in white by default. if not mpr then mpr = function (msg, color) if not color then color = "white" end crawl.mpr("<" .. color .. ">" .. msg .. "") end end function set_option_group_state(group, enable, verbose) if not group then return end found = false state_key = enable and "on" or "off" for g,opts in pairs(option_groups) do if group == g then for i, opt in ipairs(opts) do local opt_val = opt.option:gsub("%%t", opt[state_key]) crawl.setopt(opt_val) end c_persist.enabled_options[group] = enable found = true break end end if not found then mpr("Error: Unable to find option group '" .. group .. "'.") return end if verbose then local verb = enable and "Enabling" or "Disabling" mpr(verb .. " option group '" .. group .. "'.") end end function toggle_options(group) if not group then return end if c_persist.enabled_options[group] then set_option_group_state(group, false, true) else set_option_group_state(group, true, true) end end function init_toggle_options() if not c_persist.enabled_options then c_persist.enabled_options = {} end if not option_groups then mpr("Error: option_groups table undefined.", "lightred") return end for group,_ in pairs(option_groups) do local found = false for g,enabled in pairs(c_persist.enabled_options) do if group == g then local toggle_func = function() toggle_options(g) end _G["toggle_" .. g .. "_options"] = toggle_func if enabled then set_option_group_state(g, true, false) end found = true break end end if not found then c_persist.enabled_options[group] = false end end end init_toggle_options() --------------------------- ---- End toggle_options --- --------------------------- function ready() -- Enable char default skills; this must come before target_skill(). char_defaults() -- Enable skill target settings. target_skill() -- Enable speedrun resting. speedrun_rest() -- Enable persistent messages. load_message() -- Dynamic force-mores. force_mores() -- Char dumps every 1k turns. char_dump() -- Enable RandomTiles. random_tile() end }