Difference between revisions of "Module:Monster"
(Don't include vault-only monsters in monsters_with_spell) |
(Add possible panlord spells) |
||
Line 194: | Line 194: | ||
["Summon Horrible Things"] = 101, | ["Summon Horrible Things"] = 101, | ||
["Throw Icicle"] = 101, | ["Throw Icicle"] = 101, | ||
+ | } | ||
+ | |||
+ | local panlord_spells = { | ||
+ | ["Fire Storm"] = 101, | ||
+ | Glaciate = 101, | ||
+ | ["Lehudib's Crystal Spear"] = 101, | ||
+ | ["Chain Lightning"] = 101, | ||
+ | ["Orb of Destruction"] = 101, | ||
+ | ["Corrosive Bolt"] = 101, | ||
+ | ["Disintegrate"] = 101, | ||
+ | ["Bolt of Fire"] = 101, | ||
+ | ["Bolt of Cold"] = 101, | ||
+ | ["Iron Shot"] = 101, | ||
+ | ["Poison Arrow"] = 101, | ||
+ | ["Bolt of Draining"] = 101, | ||
+ | ["Quicksilver Bolt"] = 101, | ||
+ | ["Force Lance"] = 101, | ||
+ | Fireball = 101, | ||
+ | ["Bolt of Magma"] = 101, | ||
+ | ["Lee's Rapid Deconstruction"] = 101, | ||
+ | ["Lightning Bolt"] = 101, | ||
+ | Blinkbolt = 101, | ||
+ | ["Venom Bolt"] = 101, | ||
+ | Agony = 101, | ||
+ | Sleep = 101, | ||
+ | ["Iskendrun's Mystic Blast"] = 101, | ||
+ | ["Sticky Flame Range"] = 101, | ||
+ | ["Steam Ball"] = 101, | ||
+ | ["Throw Icicle"] = 101, | ||
+ | Airstrike = 101, | ||
+ | Smiting = 101, | ||
+ | ["Dazzling Spray"] = 101, | ||
+ | ["Stone Arrow"] = 101, | ||
+ | ["Static Discharge"] = 101, | ||
+ | ["Vampiric Draining"] = 101, | ||
+ | ["Throw Flame"] = 101, | ||
+ | ["Throw Frost"] = 101, | ||
+ | ["Summon Demon"] = 101, | ||
+ | ["Summon Dragon"] = 101, | ||
+ | ["Summon Horrible Things"] = 101, | ||
+ | ["Summon Greater Demon"] = 101, | ||
+ | Haunt = 101, | ||
+ | ["Summon Hydra"] = 101, | ||
+ | ["Malign Gateway"] = 101, | ||
+ | Haste = 101, | ||
+ | Invisibility = 101, | ||
+ | ["Symbol of Torment"] = 101, | ||
+ | ["Monstrous Menagerie"] = 101, | ||
+ | Silence = 101, | ||
+ | ["Shadow Creatures"] = 101, | ||
+ | ["Summon Vermin"] = 101, | ||
+ | ["Summon Swarm"] = 101, | ||
+ | ["Iskenderun's Battlesphere"] = 101, | ||
+ | ["Fulminant Prism"] = 101, | ||
+ | ["Summon Ice Beast"] = 101, | ||
+ | Swiftness = 101, | ||
+ | Blink = 101, | ||
+ | ["Summon Butterflies"] = 101, | ||
+ | Shatter = 101, | ||
+ | Banishment = 101, | ||
+ | ["Freezing Cloud"] = 101, | ||
+ | ["Poisonous Cloud"] = 101, | ||
+ | ["Mass Confusion"] = 101, | ||
+ | ["Metabolic Englaciation"] = 101, | ||
+ | ["Dispel Undead"] = 101, | ||
+ | Dig = 101, | ||
+ | Petrify = 101, | ||
+ | ["Olgreb's Toxic Radiance"] = 101, | ||
+ | Paralyse = 101, | ||
+ | Polymorph = 101, | ||
+ | ["Mephitic Cloud"] = 101, | ||
+ | Confuse = 101, | ||
+ | ["Teleport Other"] = 101, | ||
+ | Slow = 101, | ||
+ | ["Hellfire Burst"] = 101, | ||
+ | ["Metal Splinters"] = 101, | ||
+ | ["Energy Bolt"] = 101, | ||
+ | ["Orb of Electricity"] = 101, | ||
+ | ["Hellfire"] = 101, | ||
+ | ["Summon Eyeballs"] = 10, | ||
+ | ["Summon Greater Demon"] = 101 | ||
} | } | ||
Line 212: | Line 293: | ||
if monster.Species == "lich" and monster.Name ~= "Boris" then | if monster.Species == "lich" and monster.Name ~= "Boris" then | ||
return lich_spells[spell_name] or 0 | return lich_spells[spell_name] or 0 | ||
+ | end | ||
+ | |||
+ | if monster.Name == "pandemonium lord" then | ||
+ | return panlord_spells[spell_name] or 0 | ||
end | end | ||
Revision as of 02:19, 29 December 2015
Documentation for this module may be created at Module:Monster/doc
local p = {} local data = mw.loadData('Module: Table of monsters') -- Taken from max_corpse_chunks in mon-util.cc local max_corpse_chunks = { Tiny = 1, Little = 2, Small = 3, Medium = 4, Large = 9, Big = 10, Giant = 12, } local function name_arg(frame) local name = frame.args[1] if not name or name == "" then name = mw.title.getCurrentTitle().text end return name end function p.glyph(frame) local name = name_arg(frame) local monster = data[name] or data[name:lower()] if monster then return frame:expandTemplate{title = monster.Colour, args = {monster.Glyph}} else -- probably obsolete monster; fall back to old templates return frame:expandTemplate{title = "glyph/" .. name} end end function p.monster_info(frame) local name = name_arg(frame) local monster = data[name] or data[name:lower()] if not monster then return name end local args = {} args.name = monster.Name args.glyph = frame:expandTemplate{title = monster.Colour, args = {monster.Glyph}} local flags = {} for i, v in ipairs(monster.Flags) do flags[i] = frame:expandTemplate{title = v} end args.flags = table.concat(flags, "<br>") local resistances = {} for i, v in ipairs(monster.Resistances) do resistances[i] = frame:expandTemplate{title = v} end if #resistances == 0 then args.resistances = "None" else args.resistances = table.concat(resistances, "<br>") end local vulnerabilities = {} for i, v in ipairs(monster.Vulnerabilities) do vulnerabilities[i] = frame:expandTemplate{title = v} end if #vulnerabilities == 0 then args.vulnerabilities = "None" else args.vulnerabilities = table.concat(vulnerabilities, "<br>") end if monster.Corpse ~= "No" then args.max_chunks = max_corpse_chunks[monster.Size] or 0 else args.max_chunks = 0 end args.meat = frame:expandTemplate{title = monster.Corpse .. " corpse"} args.xp = monster.XP args.holiness = frame:expandTemplate{title = monster.Holiness} args.magic_resistance = monster.MR local hp_min = monster.HD*monster["Base HP"] + monster["Fixed HP"] local hp_max = monster.HD*(monster["Base HP"]+monster["Rand HP"])+monster["Fixed HP"] if hp_min == hp_max then args.hp_range = hp_min else args.hp_range = ("%d-%d"):format(hp_min, hp_max) end args.avg_hp = (hp_min + hp_max)/2 args.armour_class = monster.AC args.evasion = monster.EV args.habitat = monster.Habitat args.speed = monster.Speed args.size = frame:expandTemplate{title = monster.Size} local item_use = {} for i, v in ipairs(monster["Item Use"]) do item_use[i] = frame:expandTemplate{title = v} end args.item_use = table.concat(item_use, "<br>") for i = 1, 4 do local attack = monster.Attacks[i] if attack then local typ = frame:expandTemplate{title = attack.Type .. " type"} local flavour = frame:expandTemplate{title = attack.Flavour .. " flavour"} args["attack" .. i] = ("%d (%s: %s)"):format(attack.Damage, typ, flavour) else args["attack" .. i] = "" end end args.hit_dice = monster.HD args.base_hp = monster["Base HP"] args.extra_hp = monster["Rand HP"] args.fixed_hp = monster["Fixed HP"] args.intelligence = frame:expandTemplate{title = monster.Intelligence .. " intelligence"} args.genus = monster.Genus args.species = monster.Species local infobox = frame:expandTemplate{title = "monster", args = args} local flavour = monster.Description if monster.Quote then flavour = flavour .. "\n----\n" .. monster.Quote:gsub("\n", "<br>") end flavour = frame:expandTemplate{title = "flavour", args = {flavour}} return infobox .. "\n" .. flavour end local roman = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"} function p.monster_spells(frame) local name = name_arg(frame) local monster = data[name] or data[name:lower()] local ret = "==Spells==\n[[Category:Spellcaster]]" local cleared = false for i, spells in ipairs(monster.Spellsets) do ret = ret .. [=[<div style="margin: 1.0em; margin-top:0; margin-right:0; padding: 0px; float: left; border:none;"> {| class="prettytable" style="border:none; margin:0; padding:0; width:16em;" ! colspan="3" style="font-size:larger;" | Spell set ]=] .. roman[i] .. "\n" for j, spell in ipairs(spells) do ret = ret .. '|-\n! align="left" | Slot<sup>' .. j .. '</sup>\n| [[' .. spell.Spell .. ']]' if spell.Damage then ret = ret .. " (" .. spell.Damage .. ")" end ret = ret .. '\n| ' local flags = {} for i, v in ipairs(spell.Flags) do flags[i] = frame:expandTemplate{title = v .. " slot flag"} end ret = ret .. table.concat(flags, ", ") .. "\n" end ret = ret .. "|-\n|}</div>" cleared = i % 2 == 0 if cleared then ret = ret .. '<div style="clear:both;"></div>' end end if not cleared then ret = ret .. '<div style="clear:both;"></div>' end return ret end local lich_spells = { ["Corrosive Bolt"] = 101, ["Lehudib's Crystal Spear"] = 101, ["Orb of Destruction"] = 101, ["Summon Greater Demon"] = 50, ["Banishment"] = 33.3, ["Haste"] = 33.3, ["Invisibility"] = 33.3, ["Agony"] = 101, ["Bolt of Cold"] = 101, ["Bolt of Draining"] = 101, ["Bolt of Fire"] = 101, ["Confuse"] = 101, ["Fireball"] = 101, ["Haunt"] = 101, ["Iron Shot"] = 101, ["Iskenderun's Mystic Blast"] = 101, ["Iskenderun's Battlesphere"] = 101, ["Lee's Rapid Deconstruction"] = 101, ["Lightning Bolt"] = 101, ["Malign Gateway"] = 101, ["Paralyse"] = 101, ["Petrify"] = 101, ["Poison Arrow"] = 101, ["Spellforged Servitor"] = 101, ["Simulacrum"] = 101, ["Sleep"] = 101, ["Slow"] = 101, ["Summon Horrible Things"] = 101, ["Throw Icicle"] = 101, } local panlord_spells = { ["Fire Storm"] = 101, Glaciate = 101, ["Lehudib's Crystal Spear"] = 101, ["Chain Lightning"] = 101, ["Orb of Destruction"] = 101, ["Corrosive Bolt"] = 101, ["Disintegrate"] = 101, ["Bolt of Fire"] = 101, ["Bolt of Cold"] = 101, ["Iron Shot"] = 101, ["Poison Arrow"] = 101, ["Bolt of Draining"] = 101, ["Quicksilver Bolt"] = 101, ["Force Lance"] = 101, Fireball = 101, ["Bolt of Magma"] = 101, ["Lee's Rapid Deconstruction"] = 101, ["Lightning Bolt"] = 101, Blinkbolt = 101, ["Venom Bolt"] = 101, Agony = 101, Sleep = 101, ["Iskendrun's Mystic Blast"] = 101, ["Sticky Flame Range"] = 101, ["Steam Ball"] = 101, ["Throw Icicle"] = 101, Airstrike = 101, Smiting = 101, ["Dazzling Spray"] = 101, ["Stone Arrow"] = 101, ["Static Discharge"] = 101, ["Vampiric Draining"] = 101, ["Throw Flame"] = 101, ["Throw Frost"] = 101, ["Summon Demon"] = 101, ["Summon Dragon"] = 101, ["Summon Horrible Things"] = 101, ["Summon Greater Demon"] = 101, Haunt = 101, ["Summon Hydra"] = 101, ["Malign Gateway"] = 101, Haste = 101, Invisibility = 101, ["Symbol of Torment"] = 101, ["Monstrous Menagerie"] = 101, Silence = 101, ["Shadow Creatures"] = 101, ["Summon Vermin"] = 101, ["Summon Swarm"] = 101, ["Iskenderun's Battlesphere"] = 101, ["Fulminant Prism"] = 101, ["Summon Ice Beast"] = 101, Swiftness = 101, Blink = 101, ["Summon Butterflies"] = 101, Shatter = 101, Banishment = 101, ["Freezing Cloud"] = 101, ["Poisonous Cloud"] = 101, ["Mass Confusion"] = 101, ["Metabolic Englaciation"] = 101, ["Dispel Undead"] = 101, Dig = 101, Petrify = 101, ["Olgreb's Toxic Radiance"] = 101, Paralyse = 101, Polymorph = 101, ["Mephitic Cloud"] = 101, Confuse = 101, ["Teleport Other"] = 101, Slow = 101, ["Hellfire Burst"] = 101, ["Metal Splinters"] = 101, ["Energy Bolt"] = 101, ["Orb of Electricity"] = 101, ["Hellfire"] = 101, ["Summon Eyeballs"] = 10, ["Summon Greater Demon"] = 101 } local function is_vault_only(monster) for _, flag in ipairs(monster.Flags) do if flag == "Vault flag" then return true end end return false end -- returns a number between 0 and 100: the percentage chance that a monster will have the spell -- Monsters with no spellsets that contain the spell return 0. -- Monsters with all spellsets containing the spell return 100. -- Monsters that might have the spell, but it's too hard to calculate the percentage chance, return 101. local function monster_has_spell(monster, spell_name) if monster.Species == "lich" and monster.Name ~= "Boris" then return lich_spells[spell_name] or 0 end if monster.Name == "pandemonium lord" then return panlord_spells[spell_name] or 0 end if not monster.Spellsets then return 0 end local has = 0 local total = 0 for _, spellset in ipairs(monster.Spellsets) do total = total + 1 for _, spell in ipairs(spellset) do if spell.Spell == spell_name then has = has + 1 break end end end return has * 100 / total end local function string_icmp(s1, s2) return s1:lower() < s2:lower() end local disambig = { centaur = "Centaur (monster)", ["deep dwarf"] = "Deep dwarf (monster)", demigod = "Demigod (monster)", demonspawn = "Demonspawn (monster)", draconian = "Draconian (monster)", felid = "Felid (monster)", formicid = "Formicid (monster)", gargoyle = "Gargoyle (monster)", ghoul = "Ghoul (monster)", halfling = "Halfling (monster)", human = "Human (monster)", kobold = "Kobold (monster)", merfolk = "Merfolk (monster)", minotaur = "Minotaur (monster)", mummy = "Mummy (monster)", naga = "Naga (monster)", necromancer = "Necromancer (monster)", octopode = "Octopode (monster)", ogre = "Ogre (monster)", spriggan = "Spriggan (monster)", troll = "Troll (monster)", tengu = "Tengu (monster)", vampire = "Vampire (monster)", wizard = "Wizard (monster)", } function p.monsters_with_spell(frame) local spell_name = name_arg(frame) local always = {} local sometimes = {} for monster, monsterdata in pairs(data) do local spell_chance = monster_has_spell(monsterdata, spell_name) if spell_chance > 0 and not is_vault_only(monsterdata) then monster = disambig[monster] or (monster:gsub("^%l", string.upper)) if spell_chance == 100 then table.insert(always, monster) else table.insert(sometimes, {monster, spell_chance}) end end end table.sort(always, string_icmp) table.sort(sometimes, function(m1, m2) return string_icmp(m1[1], m2[1]) end) local ret = {} if #always > 0 then table.insert(ret, "The following enemies cast " .. spell_name .. ":") for _, monster in ipairs(always) do table.insert(ret, "* " .. frame:expandTemplate{title = "monsterlink", args = {monster}}) end end if #sometimes > 0 then table.insert(ret, "The following enemies may be able to cast " .. spell_name .. ", depending on their spell set:") for _, monster in ipairs(sometimes) do local name = monster[1] local chance = monster[2] local bullet = "* " .. frame:expandTemplate{title = "monsterlink", args = {name}} if chance ~= 101 then bullet = bullet .. (" (%.1f%% chance)"):format(monster[2]) end table.insert(ret, bullet) end end return table.concat(ret, "\n") end return p