summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/dat/lua
diff options
context:
space:
mode:
authordolorous <dolorous@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-04 20:27:42 +0000
committerdolorous <dolorous@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-04 20:27:42 +0000
commit2028bc1e0de04991eed99445defc7cf09782572f (patch)
tree047d7a4b35e493e0d9f9a2e04bac932eb4c6e90e /crawl-ref/source/dat/lua
parent848429d68c5c4fd77461a0e44aec8b28d302cc39 (diff)
downloadcrawl-ref-2028bc1e0de04991eed99445defc7cf09782572f.tar.gz
crawl-ref-2028bc1e0de04991eed99445defc7cf09782572f.zip
For consistency, move source/lua/ to source/dat/lua/.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@4867 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/dat/lua')
-rw-r--r--crawl-ref/source/dat/lua/chnkdata.lua35
-rw-r--r--crawl-ref/source/dat/lua/eat.lua108
-rw-r--r--crawl-ref/source/dat/lua/gearset.lua206
-rw-r--r--crawl-ref/source/dat/lua/kills.lua240
-rw-r--r--crawl-ref/source/dat/lua/pickup.lua123
-rw-r--r--crawl-ref/source/dat/lua/runrest.lua201
-rw-r--r--crawl-ref/source/dat/lua/safechnk.lua37
-rw-r--r--crawl-ref/source/dat/lua/stash.lua54
-rw-r--r--crawl-ref/source/dat/lua/trapwalk.lua45
-rw-r--r--crawl-ref/source/dat/lua/wield.lua47
10 files changed, 1096 insertions, 0 deletions
diff --git a/crawl-ref/source/dat/lua/chnkdata.lua b/crawl-ref/source/dat/lua/chnkdata.lua
new file mode 100644
index 0000000000..bfc93be699
--- /dev/null
+++ b/crawl-ref/source/dat/lua/chnkdata.lua
@@ -0,0 +1,35 @@
+-- SPOILER WARNING
+--
+-- This file contains spoiler information. Do not read or use this file if you
+-- don't want to be spoiled. Further, the Lua code in this file may use this
+-- spoily information to take actions on your behalf. If you don't want
+-- automatic exploitation of spoilers, don't use this.
+--
+---------------------------------------------------------------------------
+-- chnkdata.lua:
+-- Raw data on chunks of meat, auto-extracted from mon-data.h.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/chnkdata.lua
+--
+-- This file has no directly usable functions, but is needed by gourmand.lua
+-- and enables auto_eat_chunks in eat.lua.
+---------------------------------------------------------------------------
+
+sc_cont = {"program bug","ettin","goblin","jackal","manticore","orc","ugly thing","two-headed ogre","hobgoblin","ogre","troll","orc warrior","orc wizard","orc knight","minotaur","beast","iron devil","orc sorcerer","","","hell knight","necromancer","wizard","orc priest","orc high priest","human","gnoll","earth elemental","fire elemental","air elemental","Ice Fiend","Shadow Fiend","spectral warrior","pulsating lump","rock troll","stone giant","flayed ghost","insubstantial wisp","vapour","ogre-mage","dancing weapon","elf","war dog","grey rat","giant mosquito","fire giant","frost giant","firedrake","deep troll","giant blowfly","swamp dragon","swamp drake","hill giant","giant cockroach","white imp","lemure","ufetubus","manes","midge","neqoxec","hellwing","smoke demon","ynoxinul","Executioner","Blue Death","Balrug","Cacodemon","demonic crawler","sun demon","shadow imp","shadow wraith","Mnoleg","Lom Lobon","Cerebov","Gloorx Vloq","orc warlord","deep elf soldier","deep elf fighter","deep elf knight","deep elf mage","deep elf summoner","deep elf conjurer","deep elf priest","deep elf high priest","deep elf demonologist","deep elf annihilator","deep elf sorcerer","deep elf death mage","Terence","Jessica","Ijyb","Sigmund","Blork the orc","Edmund","Psyche","Erolcha","Donald","Urug","Michael","Joseph","Snorg","Erica","Josephine","Harold","Norbert","Jozef","Agnes","Maud","Louise","Francis","Frances","Rupert","Wayne","Duane","Xtahua","Norris","Frederick","Margery","Boris","Geryon","Dispater","Asmodeus","Antaeus","Ereshkigal","vault guard","Killer Klown","ball lightning","orb of fire","boggart","quicksilver dragon","iron dragon","skeletal warrior","","&","warg","","","komodo dragon"}
+sc_pois = {"killer bee","killer bee larva","quasit","scorpion","yellow wasp","giant beetle","kobold","queen bee","kobold demonologist","big kobold","wolf spider","brain worm","boulder beetle","giant mite","hydra","mottled dragon","brown snake","death yak","bumblebee","redback","spiny worm","golden dragon","elephant slug","green rat","orange rat","black snake","giant centipede","iron troll","naga","yellow snake","red wasp","soldier ant","queen ant","ant larva","spiny frog","orange demon","Green Death","giant amoeba","giant slug","giant snail","boring beetle","naga mage","naga warrior","brown ooze","azure jelly","death ooze","acid blob","ooze","shining eye","greater naga","eye of devastation","gila monster"}
+sc_hcl = {"necrophage","ghoul"}
+sc_mut = {"guardian naga","eye of draining","giant orange brain","great orb of eyes","glowing shapeshifter","shapeshifter","very ugly thing"}
+
+function sc_to_hash(list)
+ local hash = { }
+ for _, i in ipairs(list) do
+ hash[i] = true
+ end
+ return hash
+end
+
+sc_cont = sc_to_hash( sc_cont )
+sc_pois = sc_to_hash( sc_pois )
+sc_hcl = sc_to_hash( sc_hcl )
+sc_mut = sc_to_hash( sc_mut )
diff --git a/crawl-ref/source/dat/lua/eat.lua b/crawl-ref/source/dat/lua/eat.lua
new file mode 100644
index 0000000000..f27f69068b
--- /dev/null
+++ b/crawl-ref/source/dat/lua/eat.lua
@@ -0,0 +1,108 @@
+---------------------------------------------------------------------------
+-- eat.lua:
+-- Prompts to eat chunks from inventory.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/eat.lua
+--
+-- See c_eat in this file if you want to tweak eating behaviour further.
+---------------------------------------------------------------------------
+function prompt_eat(i)
+ local iname = item.name(i, "a")
+ if item.quantity(i) > 1 then
+ iname = "one of " .. iname
+ end
+ crawl.mpr("Eat " .. iname .. "?", "prompt")
+
+ local res
+ res = crawl.getch()
+ if res == 27 then
+ res = "escape"
+ elseif res < 32 or res > 127 then
+ res = ""
+ else
+ res = string.lower(string.format("%c", res))
+ end
+ return res
+end
+
+function chunk_maybe_safe(chunk)
+ local rot = food.rotting(chunk)
+ local race = you.race()
+
+ if rot then
+ return you.saprovorous() > 0
+ end
+
+ return true
+end
+
+function is_chunk_safe(chunk)
+ local rot = food.rotting(chunk)
+ local race = you.race()
+
+ -- Check if the user has sourced safechunk.lua and chnkdata.lua
+ if not (sc_cont and sc_pois and sc_hcl and sc_mut and sc_safechunk) then
+ return false
+ end
+
+ local cname = item.name(chunk)
+ local mon
+ _, _, mon = string.find(cname, "chunk of (.+) flesh")
+
+ return sc_safechunk(rot, race, mon)
+end
+
+-- Called by Crawl. Note that once Crawl sees a c_eat function, it bypasses the
+-- built-in (e)at command altogether.
+--
+function c_eat(floor, inv)
+ -- To enable auto_eat_chunks, you also need to source chnkdata.lua and
+ -- safechunk.lua. WARNING: These files contain spoily information.
+ local auto_eat_chunks = options.auto_eat_chunks == "yes" or
+ options.auto_eat_chunks == "true"
+
+ if auto_eat_chunks then
+ local all = { }
+ for _, it in ipairs(floor) do table.insert(all, it) end
+ for _, it in ipairs(inv) do table.insert(all, it) end
+
+ for _, it in ipairs(all) do
+ if food.ischunk(it) and food.can_eat(it) and is_chunk_safe(it) then
+ local iname = item.name(it, "a")
+ if item.quantity(it) > 1 then
+ iname = "one of " .. iname
+ end
+ crawl.mpr("Eating " .. iname)
+ food.eat(it)
+ return
+ end
+ end
+ end
+
+ -- Prompt to eat chunks off the floor. Returns true if the player chose
+ -- to eat a chunk.
+ if food.prompt_floor() then
+ return
+ end
+
+ for i, it in ipairs(inv) do
+ -- If we have chunks in inventory that the player can eat, prompt.
+ if food.ischunk(it) and food.can_eat(it) and chunk_maybe_safe(it) then
+ local answer = prompt_eat(it)
+ if answer == "q" then
+ break
+ end
+ if answer == "escape" then
+ return
+ end
+ if answer == "y" or answer == "e" then
+ food.eat(it)
+ return
+ end
+ end
+ end
+
+ -- Allow the player to choose a snack from inventory
+ food.prompt_inventory()
+end
diff --git a/crawl-ref/source/dat/lua/gearset.lua b/crawl-ref/source/dat/lua/gearset.lua
new file mode 100644
index 0000000000..392c7e6f60
--- /dev/null
+++ b/crawl-ref/source/dat/lua/gearset.lua
@@ -0,0 +1,206 @@
+------------------------------------------------------------------------
+-- gearset.lua:
+-- Allows for quick switching between two sets of equipment.
+--
+-- IMPORTANT
+-- This Lua script remembers only the *inventory slots* of the gear you're
+-- wearing (it could remember item names, but they're prone to change based on
+-- identification, enchantment and curse status). If you swap around items in
+-- your inventory, the script may attempt to wear odd items (this will not kill
+-- the game, but it can be disconcerting if you're not expecting it).
+--
+-- To use this, source this file in your init.txt:
+-- lua_file = lua/gearset.lua
+--
+-- Then start Crawl and create two macros:
+-- 1. Any macro input key (say F2), set macro action to "===rememberkit"
+-- 2. Any macro input key (say F3), set macro action to "===swapkit"
+-- It helps to save your macros at this point. :-)
+--
+-- You can now hit F2 to remember the equipment you're wearing. Once you've
+-- defined two sets of equipment, hit F3 to swap between them.
+--
+-- You can also just define one set of equipment; in this case, every time
+-- you hit F3 (swapkit), the macro makes sure you're wearing all the items in
+-- that set (and only the items in that set). This is handy for transmuters who
+-- need to kit up after a transform ends.
+------------------------------------------------------------------------
+function scan_kit()
+ local kit = { }
+ for i = 9, 0, -1 do
+ local it = item.equipped_at(i)
+ if it then
+ table.insert(kit, item.slot(it))
+ end
+ end
+ return kit
+end
+
+function kit_items(kit)
+ local items = { }
+ local inv = item.inventory()
+
+ for _, slot in ipairs(kit) do
+ for _, it in ipairs(inv) do
+ if slot == item.slot(it) then
+ table.insert(items, it)
+ end
+ end
+ end
+ return items
+end
+
+function getkey(vkeys)
+ local key
+
+ while true do
+ key = crawl.getch()
+ if key == 27 then return "escape" end
+
+ if key > 31 and key < 127 then
+ local c = string.lower(string.char(key))
+ if string.find(vkeys, c) then
+ return c
+ end
+ end
+ end
+end
+
+-- Macroable
+function rememberkit()
+ local kit = scan_kit()
+ crawl.mpr("Is this (T)ravel or (B)attle kit? ", "prompt")
+ local answer = getkey("tb")
+ crawl.mesclr()
+ if answer == "escape" then
+ return false
+ end
+
+ if answer == 't' then
+ g_kit_travel = kit
+ else
+ g_kit_battle = kit
+ end
+
+ return false
+end
+
+function write_array(f, arr, aname)
+ file.write(f, aname .. " = { ")
+ for i, v in ipairs(arr) do
+ file.write(f, v .. ", ")
+ end
+ file.write(f, "}\n")
+end
+
+function gearset_save(file)
+ if g_kit_travel then
+ write_array(file, g_kit_travel, "g_kit_travel")
+ end
+ if g_kit_battle then
+ write_array(file, g_kit_battle, "g_kit_battle")
+ end
+end
+
+function matchkit(kit1, kit2)
+ local matches = 0
+ if not kit2 then
+ -- Return a positive match for an empty gearset so that swapkit
+ -- switches to the *other* gearset. :-)
+ return 500
+ end
+ for _, v1 in ipairs(kit1) do
+ for _, v2 in ipairs(kit2) do
+ if v1 == v2 then
+ matches = matches + 1
+ end
+ end
+ end
+ return matches
+end
+
+function wear(it)
+ local _, eqt = item.equip_type(it)
+ if eqt == "Weapon" then
+ return item.wield(it)
+ elseif eqt == "Amulet" or eqt == "Ring" then
+ return item.puton(it)
+ elseif eqt ~= "" then
+ return item.wear(it)
+ else
+ return false
+ end
+end
+
+function wearkit(kit)
+ -- Remove all items not in the kit, then wear all items in the kit
+ local currkit = scan_kit()
+ local toremove = { }
+ local noop = true
+
+ for _, v in ipairs(currkit) do
+ local found = false
+ for _, v1 in ipairs(kit) do
+ if v == v1 then
+ found = true
+ break
+ end
+ end
+ if not found then
+ table.insert(toremove, v)
+ end
+ end
+
+ local remitems = kit_items(toremove)
+ for _, it in ipairs(remitems) do
+ noop = false
+ if not item.remove(it) then
+ coroutine.yield(false)
+ end
+ coroutine.yield(true)
+ end
+
+ local kitems = kit_items(kit)
+
+ for _, it in ipairs(kitems) do
+ if not item.worn(it) then
+ noop = false
+ if not wear(it) then
+ coroutine.yield(false)
+ end
+ coroutine.yield(true)
+ end
+ end
+
+ if noop then
+ crawl.mpr("Nothing to do.")
+ end
+end
+
+-- Macroable
+function swapkit()
+ if not g_kit_battle and not g_kit_travel then
+ crawl.mpr("You need to define a gear set first")
+ return false
+ end
+
+ local kit = scan_kit()
+ if matchkit(kit, g_kit_travel) < matchkit(kit, g_kit_battle) then
+ crawl.mpr("Switching to travel kit")
+ wearkit(g_kit_travel)
+ else
+ crawl.mpr("Switching to battle kit")
+ wearkit(g_kit_battle)
+ end
+end
+
+function swapkit_interrupt_macro(interrupt_name)
+ return interrupt_name == "hp_loss" or interrupt_name == "stat" or
+ interrupt_name == "monster" or interrupt_name == "force"
+end
+
+-- Add a macro interrupt hook so that we don't get stopped by any old interrupt
+chk_interrupt_macro.swapkit = swapkit_interrupt_macro
+
+-- Add ourselves in the Lua save chain
+table.insert(chk_lua_save, gearset_save)
diff --git a/crawl-ref/source/dat/lua/kills.lua b/crawl-ref/source/dat/lua/kills.lua
new file mode 100644
index 0000000000..b84b1f93c0
--- /dev/null
+++ b/crawl-ref/source/dat/lua/kills.lua
@@ -0,0 +1,240 @@
+------------------------------------------------------------------
+-- kills.lua:
+-- Generates fancier vanquished creatures lists.
+--
+-- List ideas courtesy Jukka Kuusisto and Erik Piper.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/kills.lua
+--
+-- Take a look at the c_kill_list function - that's where to start if you
+-- want to customize things.
+------------------------------------------------------------------
+
+function kill_filter(a, condition)
+ local t = { }
+ for i, k in ipairs(a) do
+ if condition(k) then
+ table.insert(t, k)
+ end
+ end
+ return t
+end
+
+function show_sorted_list(list, baseindent, sortfn)
+ baseindent = baseindent or " "
+ sortfn = sortfn or
+ function (x, y)
+ return kills.exp(x) > kills.exp(y) or
+ (kills.exp(x) == kills.exp(y) and
+ kills.base_name(x) < kills.base_name(y))
+ end
+ table.sort(list, sortfn)
+ for i, k in ipairs(list) do
+ kills.rawwrite(baseindent .. " " .. kills.desc(k))
+ end
+ kills.rawwrite(baseindent .. kills.summary(list))
+end
+
+function group_kills(a, namemap, keys, selector)
+ local count = 0
+ for i, key in ipairs(keys) do
+ local selected = kill_filter(a,
+ function (k)
+ return selector(key, k)
+ end
+ )
+ if table.getn(selected) > 0 then
+ if count > 0 then
+ kills.rawwrite("")
+ end
+ count = count + 1
+ kills.rawwrite(" " .. namemap[key])
+ show_sorted_list(selected)
+ end
+ end
+end
+
+function holiness_list(a)
+ local holies = {
+ strange = "Strange Monsters",
+ unique = "Uniques",
+ holy = "Holy Monsters",
+ natural = "Natural Monsters",
+ undead = "Undead Monsters",
+ demonic = "Demonic Monsters",
+ nonliving = "Non-Living Monsters",
+ plant = "Plants",
+ }
+ local holysort = { "strange", "unique",
+ "natural", "nonliving",
+ "undead", "demonic", "plant" }
+ kills.rawwrite(" Monster Nature")
+ group_kills( a, holies, holysort,
+ function ( key, kill )
+ return (kills.holiness(kill) == key and not kills.isunique(kill))
+ or
+ (key == "unique" and kills.isunique(kill))
+ end
+ )
+ kills.rawwrite(" " .. kills.summary(a))
+end
+
+function count_list(a, ascending)
+ kills.rawwrite(" Ascending Order")
+ show_sorted_list(a,
+ " ",
+ function (x, y)
+ if ascending then
+ return kills.nkills(x) < kills.nkills(y)
+ or (kills.nkills(x) == kills.nkills(y) and
+ kills.exp(x) > kills.exp(y))
+ else
+ return kills.nkill(x) > kills.nkills(y)
+ or (kills.nkills(x) == kills.nkills(y) and
+ kills.exp(x) > kills.exp(y))
+ end
+ end
+ )
+end
+
+function symbol_list(a)
+ -- Create a list of monster characters and sort it
+ local allsyms = { }
+ for i, k in ipairs(a) do
+ local ksym = kills.symbol(k)
+ allsyms[ kills.symbol(k) ] = true
+ end
+
+ local sortedsyms = { }
+ for sym, dud in pairs(allsyms) do table.insert(sortedsyms, sym) end
+ table.sort(sortedsyms)
+
+ kills.rawwrite(" Monster Symbol")
+ for i, sym in ipairs(sortedsyms) do
+ if i > 1 then
+ kills.rawwrite("")
+ end
+
+ local symlist = kill_filter(a,
+ function (k)
+ return kills.symbol(k) == sym
+ end
+ )
+ kills.rawwrite(" All '" .. sym .. "'")
+ show_sorted_list(symlist)
+ end
+
+ kills.rawwrite(" " .. kills.summary(a))
+end
+
+function classic_list(title, a, suffix)
+ if table.getn(a) == 0 then return end
+ kills.rawwrite(title)
+ for i, k in ipairs(a) do
+ kills.rawwrite(" " .. kills.desc(k))
+ end
+ kills.rawwrite(" " .. kills.summary(a))
+ if suffix then
+ kills.rawwrite(suffix)
+ end
+end
+
+function separator()
+ kills.rawwrite("----------------------------------------\n")
+end
+
+function newline()
+ kills.rawwrite("")
+end
+
+-----------------------------------------------------------------------------
+-- This is the function that Crawl calls when it wants to dump the kill list
+-- The parameter "a" is the list (Lua table) of kills, initially sorted in
+-- descending order of experience. Kill entries must be inspected using
+-- kills.foo(ke).
+--
+-- NOTE: Comment out the kill lists that you don't like!
+--
+-- As of 20060224, the kill list is divided into three:
+-- * Direct player kills
+-- * Monsters killed by friendlies
+-- * Monsters killed by other things (traps, etc.)
+--
+-- For each category, the game calls c_kill_list, with a table of killed
+-- monsters, and the killer (who). The killer will be nil for direct player
+-- kills, and a string ("collateral kills", "others") otherwise.
+--
+-- c_kill_list will not be called for a category if the category contains no
+-- kills.
+--
+-- After all categories, c_kill_list will be called with no arguments to
+-- indicate the end of the kill listing.
+
+function c_kill_list(a, who, needsep)
+ -- If there aren't any kills yet, bail out
+ if not a or table.getn(a) == 0 then
+ if not a and who and who ~= "" then
+ -- This is the grand total
+ separator()
+ kills.rawwrite(who)
+ end
+ return
+ end
+
+ if needsep then
+ separator()
+ end
+
+ local title = "Vanquished Creatures"
+ if who then
+ title = title .. " (" .. who .. ")"
+ end
+
+ kills.rawwrite(title)
+
+ -- Group kills by monster symbol
+ symbol_list(a)
+ newline()
+
+ -- Group by holiness
+ holiness_list(a)
+ newline()
+
+ -- Sort by kill count (ascending).
+ count_list(a, true)
+ newline()
+
+ -- Classic list without zombies and skeletons
+ -- Commented-out - this is a boring list.
+ --[[
+ -- First re-sort into descending order of exp, since
+ -- count_list has re-sorted the array.
+ table.sort(a, function (x, y)
+ return kills.exp(x) > kills.exp(y)
+ end);
+
+ -- Filter out zombies and skeletons and display the rest
+ classic_list(
+ " Kills minus zombies and skeletons",
+ kill_filter(a,
+ function (k)
+ return kills.modifier(k) ~= "zombie" and
+ kills.modifier(k) ~= "skeleton"
+ end
+ ))
+
+ separator()
+ --]]
+
+ -- Show only monsters with 3 digit kill count
+ classic_list(
+ " The 3-digit Club",
+ kill_filter(a,
+ function (k)
+ return kills.nkills(k) > 99
+ end
+ ),
+ "")
+
+end
diff --git a/crawl-ref/source/dat/lua/pickup.lua b/crawl-ref/source/dat/lua/pickup.lua
new file mode 100644
index 0000000000..feae944ac4
--- /dev/null
+++ b/crawl-ref/source/dat/lua/pickup.lua
@@ -0,0 +1,123 @@
+------------------------------------------------------------
+-- pickup.lua:
+-- Smarter autopickup handling that takes into account the
+-- item type in combination with your character's race,
+-- religion, knowledge, and eating habits.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/pickup.lua
+--
+-- Notes:
+-- * This script only handles items of classes with
+-- autopickup on.
+-- * Any result can still be overridden using
+-- autopickup_exceptions.
+------------------------------------------------------------
+
+function make_hash(ls)
+ local h = { }
+ for _, i in ipairs(ls) do
+ h[i] = true
+ end
+ return h
+end
+
+-- don't count Vampires here because of all those exceptions
+function you_real_undead()
+ return you.race() == "Mummy" or you.race() == "Ghoul"
+end
+
+-- not identified
+function unknown_potion(type)
+ return type == 0
+end
+
+function good_potion(type)
+ return type == 1
+end
+
+function bad_potion(type)
+ return type == 2
+end
+
+-- special cases
+function spec_potion(type)
+ return type == 3
+end
+
+function ch_autopickup(it)
+ local spells = make_hash( you.spells() )
+
+ if item.class(it) == "Potions" then
+
+ local type = item.potion_type(it)
+
+ -- "bad" potions only for Evaporate
+ if spells["Evaporate"] and bad_potion(type) then
+ return true
+ end
+
+ -- no potions for Mummies
+ -- also: no bad potions for anyone else
+ if you.race() == "Mummy" or bad_potion(type) then
+ return false
+ end
+
+ -- pickup "good" and unID'd potions
+ if good_potion(type) or unknown_potion(type) then
+ return true
+ end
+
+ -- special handling
+ if spec_potion(type) then
+
+ -- real undead cannot use berserk
+ -- or anything involving mutations
+ if item.subtype(it) == "berserk"
+ or item.subtype(it) == "gain ability"
+ or item.subtype(it) == "cure mutation" then
+ if you_real_undead() then
+ return false
+ else
+ return true
+ end
+ end
+
+ -- special cases for blood, water, and porridge
+ if item.subtype(it) == "blood"
+ or item.subtype(it) == "water"
+ or item.subtype(it) == "porridge" then
+ return food.can_eat(it, false)
+ end
+ end
+
+ -- anything not handled until here can be picked up
+ return true
+ end
+
+ if item.class(it) == "Carrion"
+ or item.class(it) == "Comestibles" then
+ return food.can_eat(it, false)
+ end
+
+ if item.class(it) == "Books" and you.god() == "Trog"
+ then return false
+ end
+
+ if item.class(it) == "Jewellery" then
+ if item.subtype(it) == "hunger"
+ or item.subtype(it) == "inaccuracy" then
+ return false
+ end
+ if you_real_undead() and
+ (item.subtype(it) == "regeneration"
+ or item.subtype(it) == "rage"
+ or item.subtype(it) == "sustenance"
+ and you.race() == "Mummy") then
+ return false
+ end
+ end
+
+ -- we only get here if class autopickup ON
+ return true
+end
diff --git a/crawl-ref/source/dat/lua/runrest.lua b/crawl-ref/source/dat/lua/runrest.lua
new file mode 100644
index 0000000000..b3fa362820
--- /dev/null
+++ b/crawl-ref/source/dat/lua/runrest.lua
@@ -0,0 +1,201 @@
+---------------------------------------------------------------------------
+-- runrest.lua:
+-- Controls shift-running and resting stop conditions.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/runrest.lua
+--
+-- What it does:
+--
+-- * Any message in runrest_ignore_message will *not* stop your run.
+-- * Poison damage of x will be ignored if you have at least y hp if you've
+-- defined a runrest_ignore_poison = x:y option.
+-- * Any monster in runrest_ignore_monster will *not* stop your run
+-- if it's at least the specified distance away.
+-- You can specify this with runrest_ignore_monster = regex:distance.
+--
+-- IMPORTANT: You must define runrest_ options *after* sourcing runrest.lua.
+---------------------------------------------------------------------------
+
+g_rr_ignored = { }
+
+chk_interrupt_activity.run = function (iname, cause, extra)
+ if not rr_check_params() then
+ return false
+ end
+
+ if iname == 'message' then
+ return rr_handle_message(cause, extra)
+ end
+
+ if iname == 'hp_loss' then
+ return rr_handle_hploss(cause, extra)
+ end
+
+ return false
+end
+
+-- run no longer automatically implies rest as of 0.1.3.
+chk_interrupt_activity.rest = chk_interrupt_activity.run
+chk_interrupt_activity.travel = chk_interrupt_activity.run
+
+function rr_handle_message(cause, extra)
+ local ch, mess = rr_split_channel(cause)
+ for _, m in ipairs(g_rr_ignored) do
+ if m:matches(mess, ch) then
+ return nil
+ end
+ end
+ return false
+end
+
+function rr_split_channel(s)
+ local chi = string.find(s, ':')
+ local channel = -1
+ if chi and chi > 1 then
+ local chstr = string.sub(s, 1, chi - 1)
+ channel = crawl.msgch_num(chstr)
+ end
+
+ local sor = s
+ if chi then
+ s = string.sub(s, chi + 1, -1)
+ end
+
+ return channel, s
+end
+
+function rr_handle_hploss(hplost, source)
+ -- source == 1 for poisoning
+ if not g_rr_yhpmin or not g_rr_hplmax or source ~= 1 then
+ return false
+ end
+
+ -- If the hp lost is smaller than configured, and you have more than the
+ -- minimum health, ignore this poison event.
+ if hplost <= g_rr_hplmax and you.hp() >= g_rr_yhpmin then
+ return nil
+ end
+
+ return false
+end
+
+function rr_check_params()
+ if g_rrim ~= options.runrest_ignore_message then
+ g_rrim = options.runrest_ignore_message
+ rr_add_messages(nil, g_rrim)
+ end
+
+ if ( not g_rr_hplmax or not g_rr_yhpmin )
+ and options.runrest_ignore_poison
+ then
+ local opt = options.runrest_ignore_poison
+ local hpl, hpm
+ _, _, hpl, hpm = string.find(opt, "(%d+)%s*:%s*(%d+)")
+ if hpl and hpm then
+ g_rr_hplmax = tonumber(hpl)
+ g_rr_yhpmin = tonumber(hpm)
+ end
+ end
+ return true
+end
+
+function rr_add_message(s)
+ local channel, str = rr_split_channel(s)
+ table.insert( g_rr_ignored, crawl.message_filter( str, channel ) )
+end
+
+function rr_add_messages(key, value)
+ local segs = crawl.split(value, ',')
+ for _, s in ipairs(segs) do
+ rr_add_message(s)
+ end
+end
+
+chk_lua_option.runrest_ignore_message = rr_add_messages
+
+-----------------------------------------------------------------------
+
+g_rr_monsters = { {}, {} }
+g_rr_monsters_moving = { {}, {} }
+
+function rr_add_monster(mons_table, s)
+ local parts = crawl.split(s, ":")
+
+ if #parts ~= 2 then
+ return
+ end
+
+ local regexp = parts[1]
+ local dist = tonumber(parts[2])
+
+ if dist == 0 then
+ return
+ end
+
+ table.insert( mons_table[1], crawl.regex( regexp ) )
+ table.insert( mons_table[2], dist )
+end
+
+function rr_add_monsters(key, value)
+ local mons_table
+
+ if (key == "runrest_ignore_monster") then
+ mons_table = g_rr_monsters
+ elseif (key == "runrest_ignore_monster_moving") then
+ mons_table = g_rr_monsters_moving
+ else
+ return
+ end
+
+ local segs = crawl.split(value, ',')
+ for _, s in ipairs(segs) do
+ rr_add_monster(mons_table, s)
+ end
+end
+
+function ch_mon_is_safe(mon, default_is_safe, moving, dist)
+ if default_is_safe then
+ return true
+ end
+
+ local mons_table
+
+ -- If player is moving and the monster is in g_rr_monsters_moving,
+ -- then we do the distance comparison without decreasing the
+ -- distance value.
+ if moving then
+ mons_table = g_rr_monsters_moving
+
+ for i = 1, #mons_table[1] do
+ local m = mons_table[1][i]
+ local min_dist = mons_table[2][i]
+
+ if m:matches(mon.name) then
+ return min_dist <= dist
+ end
+ end
+ end
+
+ mons_table = g_rr_monsters
+
+ -- Reduce distance by 1 if moving, since the safety check is
+ -- done *before* moving closer to the monster
+ if moving then
+ dist = dist - 1
+ end
+
+ for i = 1, #mons_table[1] do
+ local m = mons_table[1][i]
+ local min_dist = mons_table[2][i]
+
+ if m:matches(mon.name) then
+ return min_dist <= dist
+ end
+ end
+
+ return false
+end
+
+chk_lua_option.runrest_ignore_monster = rr_add_monsters
+chk_lua_option.runrest_ignore_monster_moving = rr_add_monsters
diff --git a/crawl-ref/source/dat/lua/safechnk.lua b/crawl-ref/source/dat/lua/safechnk.lua
new file mode 100644
index 0000000000..447981f141
--- /dev/null
+++ b/crawl-ref/source/dat/lua/safechnk.lua
@@ -0,0 +1,37 @@
+-- SPOILER WARNING
+--
+-- This file contains spoiler information. Do not read or use this file if you
+-- don't want to be spoiled. Further, the Lua code in this file may use this
+-- spoily information to take actions on your behalf. If you don't want
+-- automatic exploitation of spoilers, don't use this.
+--
+---------------------------------------------------------------------------
+-- safechunk.lua:
+-- Determines whether a chunk of meat is safe for your character to eat.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/safechunk.lua
+--
+-- This file has no directly usable functions, but is needed by gourmand.lua
+-- and enables auto_eat_chunks in eat.lua.
+---------------------------------------------------------------------------
+
+function sc_safechunk(rot, race, mon)
+ if rot then
+ if you.saprovorous() < 2 then
+ return false
+ end
+ end
+
+ if sc_pois[mon] and you.res_poison() > 0 then
+ return true
+ end
+
+ if sc_hcl[mon] or sc_mut[mon] then
+ return race == "Ghoul"
+ end
+
+ -- Only contaminated and clean chunks remain, in theory. We'll accept
+ -- either
+ return true
+end
diff --git a/crawl-ref/source/dat/lua/stash.lua b/crawl-ref/source/dat/lua/stash.lua
new file mode 100644
index 0000000000..3274b41c5b
--- /dev/null
+++ b/crawl-ref/source/dat/lua/stash.lua
@@ -0,0 +1,54 @@
+---------------------------------------------------------------------------
+-- stash.lua
+-- Annotates items for the stash-tracker's search, and for autopickup
+-- exception matches.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/stash.lua
+--
+-- Available annotations:
+-- {artefact} for identified artefacs.
+-- {ego} for identified branded items.
+-- { <skill> } - the relevant weapon skill for weapons.
+-- { <class> } - item class: gold, weapon, missile, armour, wand, carrion,
+-- food, scroll, jewellery, potion, book, staff, orb, misc
+--
+-- You can optionally disable annotate items with the item class name
+-- (such as "weapon" for weapons) by setting
+-- annotate_item_class = false
+-- in your init.txt.
+--
+-- Item annotations are always prefixed to the item name. For instance:
+-- {artefact} the Staff of Wucad Mu
+---------------------------------------------------------------------------
+
+local ch_annotate_item_class = nil
+-- Annotate items for searches
+function ch_stash_search_annotate_item(it)
+ local annot = ""
+
+ if item.artefact(it) then
+ annot = annot .. "{artefact} "
+ elseif item.branded(it) then
+ annot = annot .. "{ego} "
+ end
+
+ local skill = item.weap_skill(it)
+ if skill then
+ annot = annot .. "{" .. skill .. "} "
+ end
+
+ if ch_annotate_item_class == nil then
+ ch_annotate_item_class = opt_boolean("annotate_item_class", true)
+ end
+
+ if ch_annotate_item_class then
+ annot = annot .. "{" .. item.class(it, true) .. "}"
+ end
+
+ return annot
+end
+
+--- If you want dumps (.lst files) to be annotated, uncomment this line:
+-- ch_stash_dump_annotate_item = ch_stash_search_annotate_item
+
diff --git a/crawl-ref/source/dat/lua/trapwalk.lua b/crawl-ref/source/dat/lua/trapwalk.lua
new file mode 100644
index 0000000000..c7e535d5c1
--- /dev/null
+++ b/crawl-ref/source/dat/lua/trapwalk.lua
@@ -0,0 +1,45 @@
+---------------------------------------------------------------------------
+-- trapwalk.lua:
+-- (Thanks to JPEG for this script.)
+--
+-- Allows travel to cross traps provided you have sufficient HP to survive the
+-- trap.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/trapwalk.lua
+-- and add
+-- trapwalk_safe_hp = dart:15, needle:25, spear:50
+-- or similar to your init.txt.
+--
+-- What it does:
+--
+-- * Normally autotravel automatically avoids all traps
+-- * This script allows you to customize at which hp what type of trap is
+-- regarded as safe for autotravel
+--
+-- IMPORTANT: trapwalk options must be defined *after* sourcing trapwalk.lua.
+---------------------------------------------------------------------------
+
+-- Travel will cross certain traps if you have more than safe_hp hp.
+
+function ch_cross_trap(trap)
+
+ if not options.trapwalk_safe_hp then
+ return false
+ end
+
+ local opt = options.trapwalk_safe_hp
+
+ local hpstr
+ _, _, hpstr = string.find(opt, trap .. "%s*:%s*(%d+)")
+
+ if not hpstr then
+ return false
+ end
+
+ local safe_hp = tonumber(hpstr)
+ local hp = you.hp()
+
+ -- finally compare current hp with safe limit
+ return hp >= safe_hp
+end
diff --git a/crawl-ref/source/dat/lua/wield.lua b/crawl-ref/source/dat/lua/wield.lua
new file mode 100644
index 0000000000..e4fe9951e3
--- /dev/null
+++ b/crawl-ref/source/dat/lua/wield.lua
@@ -0,0 +1,47 @@
+---------------------------------------------------------------------------
+-- wield.lua
+-- Selects extra items to wield.
+--
+-- To use this, add this line to your init.txt:
+-- lua_file = lua/wield.lua
+---------------------------------------------------------------------------
+
+function make_hash(ls)
+ local h = { }
+ for _, i in ipairs(ls) do
+ h[i] = true
+ end
+ return h
+end
+
+function ch_item_wieldable(it)
+ -- We only need to check for unusual cases - basic matching is handled
+ -- by Crawl itself.
+ local spells = make_hash( you.spells() )
+
+ if spells["Bone Shards"]
+ and string.find( item.name(it, "a"), " skeleton" )
+ then
+ return true
+ end
+
+ if (spells["Sublimation of Blood"] or spells["Simulacrum"])
+ and food.ischunk(it)
+ then
+ return true
+ end
+
+ if spells["Sandblast"]
+ and string.find( item.name(it, "a"), " stones?$" )
+ then
+ return true
+ end
+
+ if spells["Sticks to Snakes"]
+ and string.find( item.name(it, "a"), " arrows?$" )
+ then
+ return true
+ end
+
+ return false
+end