# TID's crawlrc v0.52 # Inspired by many other Crawlers' rc files. default_autopickup = false default_manual_training = true show_more = false tile_web_mouse_control = false # Dump file options note_hp_percent = 20 note_all_skill_levels = true dump_item_origins += ego_arm, ego_weap, jewellery, runes, staves, books dump_message_count = 100 dump_order += turns_by_place, kills_by_place, vaults # none = force capitals on Y/N questions. Inhibits accidental melee # with a launcher when attacking NW. easy_confirm = none autofight_stop = 30 hp_warning = 50 mp_warning = 0 hp_colour = 75:yellow, 50:red mp_colour = 50:yellow, 25:red ###################################################################### ## Inscriptions # Usually you don't want to attack with the utility staves autoinscribe += staff of conjuration:!a autoinscribe += staff of energy:!a autoinscribe += staff of power:!a autoinscribe += staff of wizardry:!a # Don't accidentally waste rare missiles autoinscribe += throwing net:!f autoinscribe += tomahawk.*dispersal:!f autoinscribe += scrolls? of immolation:!r autoinscribe += scrolls? of noise:!r autoinscribe += scrolls? of silence:!r autoinscribe += scrolls? of vulnerability:!r autoinscribe += potions? of degeneration:!q autoinscribe += potions? of mutation:!q ###################################################################### ## Spell slot letters spell_slot += animate dead:N spell_slot += animate skeleton:n spell_slot += apportation:A spell_slot += beastly appendage:e spell_slot += blade hands:h spell_slot += ^blink:b spell_slot += bolt of fire:o spell_slot += bolt of magma:m spell_slot += borgnjor's revivification:K spell_slot += borgnjor's vile clutch:v spell_slot += call canine familiar:c spell_slot += call imp:i spell_slot += confuse:c spell_slot += confusing touch:t spell_slot += conjure flame:c # Removed in 0.21: spell_slot += control undead:u spell_slot += controlled blink:B spell_slot += corona:a spell_slot += dazzling spray:d spell_slot += death's door:O spell_slot += deflect missiles:m spell_slot += dragon form:d spell_slot += ensorcelled hibernation:e spell_slot += ^fireball:f spell_slot += fire storm:F spell_slot += freeze:a spell_slot += glaciate:G spell_slot += hydra form:y spell_slot += ice form:i spell_slot += infusion:i spell_slot += invisibility:v spell_slot += iron shot:i spell_slot += iskenderun's battlesphere:s spell_slot += iskenderun's mystic blast:i spell_slot += lee's rapid deconstruction:D spell_slot += lehudib's crystal spear:j spell_slot += lesser beckoning:l spell_slot += magic dart:a spell_slot += necromutation:N spell_slot += ozocubu's armour:o spell_slot += passage of golubria:g spell_slot += passwall:p spell_slot += portal projectile:p spell_slot += regeneration:r spell_slot += sandblast:a spell_slot += searing ray:r spell_slot += shatter:E spell_slot += shock:a spell_slot += shroud of golubria:g spell_slot += song of slaying:y spell_slot += spectral weapon:w spell_slot += spider form:p spell_slot += statue form:s spell_slot += sticks to snakes:k spell_slot += sting:a spell_slot += stone arrow:j spell_slot += summon mana viper:V spell_slot += sublimation of blood:Z spell_slot += summon butterflies:P spell_slot += swiftness:W spell_slot += throw icicle:i spell_slot += throw frost:j spell_slot += tornado:R spell_slot += vampiric draining:d ###################################################################### ### Attention! more := force_more_message stop := runrest_stop_message flsh := flash_screen_message ###################################################################### ## Dungeon features more += Found a staircase to the Ecumenical Temple more += Found a snail[-]covered altar of Cheibriados more += Found a stone staircase leading (up|down) more += ^Found # more += shouts? ###################################################################### ## Dangerous monsters # when playing Chei or weak races more += comes? into view # corrupters, temporary or permanent more += (giant eyeball|shining eye|cacodemon|neqoxec|corrupter|wretched star).*into view # tormentors more += (curse toe|curse skull|fiend|tzitzimitl|tormentor|mummy priest|greater mummy).*into view # damnators more += (deep elf high priest|deep elf sorcerer|draconian scorcher|draconian zealot|hell sentinel|hellion).*into view # summoners and displacers more += (deep elf demonologist|doom hound|draconian shifter|guardian serpent|ironbrand convoker|shadow demon).*into view # just plain strong more += (ancient lich|caustic shrike|iron giant|juggernaut|orb of fire).*into view # nasty statuses more += (ancient zyme|death cob|death drake|entropy weaver|flayed ghost|ghost moth|moth of wrath|starcursed mass|vault warden|warmonger).*into view # uniques or pan lords, also Killer Klown, Orb Guardian and some others more += (?-i:[A-Z]).* comes? into view # Hit by invisible monster more += [Ss]omething hits you[.|!] # Invisible ghost moth more += watched by something flsh += watched by something # Hit by Airstrike while flying more += The air twists around and violently strikes you in flight # ironbrand convoker's delayed summon more += begins to recite a word of recall ## Distortion weapon # "It is wielding a .* of distortion" ## Dancing weapon of distortion # "There is a .* of distortion" # "The .* of distortion completely misses you" more += Space warps horribly around you flsh += Space warps horribly around you more += Space bends around you flsh += Space bends around you more += hits you.*distortion flsh += hits you.*distortion more += warns you.*of distortion flsh += warns you.*of distortion more += is wielding.*of distortion flsh += is wielding.*of distortion more += is a .* of distortion flsh += is a .* of distortion ## Announcements of timed portal vaults (bazaar, labyrinths) more += interdimensional caravan more += You feel an oppressive heat about you more += You hear .* (creaking of a.* portcullis|drain|roar of battle|rushing water|a distant snort|tolling of a bell) more += A sentinel's mark forms upon you more += The blast of calcifying dust hits you more += The writing blurs in front of your eyes more += There are no visible monsters within range more += This wand has no charges more += You are (blasted|electrocuted)! more += You are confused more += You are engulfed in seething chaos more += You are starting to lose your buoyancy more += You can't carry that many items more += You convulse more += You don't have enough magic more += You don't know any spells more += You don't know that spell more += You enter a teleport trap more += You fail to use your ability more += You feel less protected from missiles more += You feel less wooden more += You feel yourself come back to life more += You flicker back into view more += You have a feeling this form more += You have finished your manual more += You miscast # Statue Form ran out. more += You revert to your normal fleshy form more += You start to feel a little slower more += You start to feel a little uncertain more += You warm up again ## .21 gnolls get a lot of these: ###more += Your .* Skill increases more += Your front paws revert to their normal proportions more += Your lightning spire disappears in a puff of smoke more += Your time is quickly running out flsh += Your time is quickly running out more += Your skin stops crawling more += Your song has ended more += Your surroundings flicker more += Your surroundings suddenly seem different more += Your transformation is almost over more += dispelling energy hits you more += divine experience more += god:(sends|finds|silent|anger) more += is unaffected more += life is in your own hands more += not good enough to have a special ability more += time is quickly running out flsh += The blast of calcifying dust hits you flsh += You are engulfed in seething chaos flsh += You convulse ###################################################################### ## Bad mutations # berserkitis more += You feel a little pissed off more += You feel angry more += You feel extremely angry at everything! # blurry vision more += Your vision blurs # teleportitis more += You feel weirdly uncertain more += You feel even more weirdly uncertain # deformed body more += Your body twists and deforms # frail more += You feel frail # subdued magic more += Your connection to magic feels subdued more += Your connection to magic feels more subdued more += Your connection to magic feels nearly dormant # wild magic more += You feel less in control of your magic more += You feel your magical power running wild # no device heal [2-3] more += Your system mostly rejects artificial healing more += Your system completely rejects artificial healing # slow healing 3 more += You stop regenerating ###################################################################### # https://github.com/gammafunk/dcss-rc/blob/master/speedrun_rest.lua # Copy-pasted in 2017-09-10 # # See https://github.com/gammafunk/dcss-rc/blob/master/README.md # # "Additionally assign two macros, one with a target of # ===one_turn_rest for the single-turn rest and one with a target of # ===start_resting for the multiple turn rest. You can also set a # macro to a target of ===set_swing_slot or call set_swing_slot() from # the lua console to change the swing slot on the fly." { ----------------------------- ---- Begin speedrun_rest ---- ----------------------------- -- See README.md for documentation. -- How many turns to rest at max. num_rest_turns = 30 -- 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 = false -- 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 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() 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" or item.class() == "Books" or item.class() == "Wands" or item.class() == "Missiles" or item.class() == "Miscellaneous" or (item.class() == "Hand Weapons" and (item.subtype():find("bow") or item.subtype():find("sling") or item.subtype():find("crossbow") or item.subtype():find("blowgun"))) 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 c_persist.swing_slot ~= nil 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.race() == "Barachi" 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 swing_item_wielded() and 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 ---- --------------------------- } { function ready() speedrun_rest() end }