Module:Infobox Monster

-- -- -- Module for Template:Infobox Monster

local p = {}

-- "imports" local onmain = require('Module:Mainonly').on_main local paramtest = require('Module:Paramtest') local yesno = require('Module:Yesno') local commas = require('Module:Addcommas')._add local infobox = require('Module:Infobox') local attack_speed_bar = require('Module:Attack speed bar').make_bar local signed = require('Module:Format eq stat').signed

local slayer_masters = { 'turael', 'krystilia', 'mazchna', 'vannaka', 'chaeldar', 'konar', 'nieve', 'steve', 'duradel' }

-- Main function called with invokes function p.main(frame) local args = frame:getParent.args local ret = infobox.new(args)

local numeric_args = { 'combat', 'hitpoints', 'max hit', 'slaylvl', 'slayxp', 'att', 'str', 'def', 'range', 'mage', }

for _, v in ipairs(numeric_args) do		ret:defineParams{ { name = v, func = { name = numericarg, params = { v, v }, flag = { 'd', 'r' } } }} end

local signed_numeric_args = { 'astab', 'aslash', 'acrush', 'amagic', 'arange', 'dstab', 'dslash', 'dcrush', 'dmagic', 'drange', 'attbns', 'strbns', 'rngbns' }

for _, v in ipairs(signed_numeric_args) do		ret:defineParams{ { name = v, func = { name = signednumericarg, params = { v, v }, flag = { 'd', 'r' } } }} end

local signed_percent_numeric_args = { 'mbns' }

for _, v in ipairs(signed_percent_numeric_args) do		ret:defineParams{ { name = v, func = { name = signedpercentnumericarg, params = { v, v }, flag = { 'd', 'r' } } }} end

ret:defineParams{ { name = 'name', func = 'name' }, { name = 'image', func = 'image' },

{ name = 'release', func = 'release' }, { name = 'removal', func = 'removal' }, { name = 'aka', func = 'has_content' },

{ name = 'members', func = 'has_content' }, { name = 'always drops', func = 'has_content' }, { name = 'examine', func = 'has_content' },

{ name = 'aggressive', func = 'has_content' }, { name = 'poisonous', func = 'has_content' }, { name = 'weakness', func = 'has_content' }, { name = 'attack style', func = 'has_content' },

{ name = 'cat', func = 'has_content' }, { name = 'assigned_by', func = { name = slayerarg, params = slayer_masters } },

{ name = 'immunepoison', func = { name = immunearg, params = {'immunepoison', 'immunepoison'}, flag = { 'd', 'r' } } }, { name = 'immunevenom', func = { name = immunearg, params = {'immunevenom', 'immunevenom'}, flag = { 'd', 'r' } } },

{ name = 'attack speed', func = attack_speed_bar },

-- not used; only for categories { name = 'id', func = 'numbers' } }

ret:defineLinks( { links={{ 'Template:%s/FAQ', 'FAQ' },			{ 'Template:%s/doc', 'doc' }} })

ret:create ret:cleanParams

ret:defineName('Infobox Monster') ret:addClass('infobox-monster')

-- PARAMETER: name ret:addRow{ { tag = 'argh', content = 'name', class='infobox-header', colspan = '20' } }

-- PARAMETER: image ret:addRow{ { tag = 'argd', content = 'image', class='infobox-image', colspan = '20' } }

-- PARAMETER: release -- (update included automatically by infobox) ret:addRow{ { tag = 'th', content = 'Released', colspan = '6' }, { tag = 'argd', content = 'release', colspan = '14' } }

-- PARAMETER: removal if ret:paramDefined('removal') then ret:addRow{ { tag = 'th', content = 'Removal', colspan = '6' }, { tag = 'argd', content = 'removal', colspan = '14' } } end

-- PARAMETER: aka if ret:paramDefined('aka') then ret:addRow{ { tag = 'th', content = 'AKA', colspan = '6' }, { tag = 'argd', content = 'aka', colspan = '14' } } end

-- PARAMETER: members ret:addRow{ { tag = 'th', content = 'Members', colspan = '6' }, { tag = 'argd', content = 'members', colspan = '14' } }

-- PARAMETER: combat :addRow{ { tag = 'th', content = 'Combat level', colspan = '6' }, { tag = 'argd', content = 'combat', colspan = '14' } }

-- PARAMETER: always drops :addRow{ { tag = 'th', content = 'Always drops', colspan = '6' }, { tag = 'argd', content = 'always drops', colspan = '14' } }

-- SECTION: EXAMINE :addRow{ { tag = 'th', content = 'Examine', class = 'infobox-subheader', colspan = '20' } }

-- PARAMETER: examine :addRow{ { tag = 'argd', content = 'examine', colspan = '20', class = 'infobox-full-width-content' } }

-- SECTION: COMBAT INFO :addRow{ { tag = 'th', content = 'Combat info', colspan = '20', class = 'infobox-subheader' } }

-- PARAMETER: hitpoints :addRow{ { tag = 'th', content = 'Hitpoints', colspan = '6' }, { tag = 'argd', content = 'hitpoints', colspan = '14' } }

-- PARAMETER: max hit :addRow{ { tag = 'th', content = 'Max hit', colspan = '6' }, { tag = 'argd', content = 'max hit', colspan = '14' } }

-- PARAMETER: aggressive :addRow{ { tag = 'th', content = 'Aggressive', colspan = '6' }, { tag = 'argd', content = 'aggressive', colspan = '14' } }

-- PARAMETER: poisonous :addRow{ { tag = 'th', content = 'Poison', colspan = '6' }, { tag = 'argd', content = 'poisonous', colspan = '14' } }

-- PARAMETER: weakness :addRow{ { tag = 'th', content = 'Weakness', colspan = '6' }, { tag = 'argd', content = 'weakness', colspan = '14' } }

-- PARAMETER: attack style :addRow{ { tag = 'th', content = 'Attack style', colspan = '6' }, { tag = 'argd', content = 'attack style', colspan = '14' } }

-- SECTION: SLAYER INFO :addRow{ { tag = 'th', content = ' Slayer info', colspan = '20', class = 'infobox-subheader' } }

-- If a monster is assigned or has a required level, include slayer info local assigned_by = ret:param('assigned_by') local has_slaylvl = ret:paramDefined('slaylvl') and string.lower(ret:param('slaylvl')) ~= 'no' if infobox.isDefined(assigned_by) or has_slaylvl then -- PARAMETER: slaylvl ret:addRow{ { tag = 'th', content = 'Slayer level', colspan = '6' }, { tag = 'argd', content = 'slaylvl', colspan = '14' } }

-- If a monster is assigned, include assignment info if infobox.isDefined(assigned_by) then -- PARAMETER: slayxp ret:addRow{ { tag = 'th', content = 'Slayer XP', colspan = '6' }, { tag = 'argd', content = 'slayxp', colspan = '14' } }

-- PARAMETER: slayercat :addRow{ { tag = 'th', content = 'Category', colspan = '6' }, { tag = 'argd', content = 'cat', colspan = '14' } }

-- PARAMETER: assigned_by :addRow{ { tag = 'th', content = 'Assigned by', colspan = '6' }, {tag = 'argd', content = 'assigned_by', colspan = '14' } } else ret:addRow{ { tag = 'th', content = 'Assigned by', colspan = '6' }, {tag = 'td', content = 'Not assigned', colspan = '14' } } end else ret:addRow{ { tag = 'td', content = 'Not assigned', colspan = '20', class = 'infobox-full-width-content' } } end

-- SECTION: COMBAT STATS ret:addRow{ { tag = 'th', content = ' Combat stats', colspan = '20', class = 'infobox-subheader' } }

-- NESTED PIC HEADERS: att | str | def | mage | range :addRow{ { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' } }

-- PARAMETER: att | str | def | mage | range :addRow{ { tag = 'argd', content = 'att', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'str', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'def', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'mage', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'range', colspan = '4', class = 'infobox-nested' } }

-- SECTION: AGGRESSIVE STATS :addRow{ { tag = 'th', content = ' Aggressive stats', colspan = '20', class = 'infobox-subheader' } }

-- NESTED PIC HEADERS: astab | aslash | acrush | amagic | arange :addRow{ { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' } }

-- PARAMETER: astab | aslash | acrush | amagic | arange :addRow{ { tag = 'argd', content = 'astab', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'aslash', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'acrush', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'amagic', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'arange', colspan = '4', class = 'infobox-nested' } }

-- SECTION: DEFENSIVE STATS :addRow{ { tag = 'th', content = ' Defensive stats', colspan = '20', class = 'infobox-subheader' } }

-- NESTED PIC HEADERS: dstab | dslash | dcrush | dmagic | drange :addRow{ { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' } }

-- PARAMETER: dstab | dslash | dcrush | dmagic | drange :addRow{ { tag = 'argd', content = 'dstab', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'dslash', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'dcrush', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'dmagic', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'drange', colspan = '4', class = 'infobox-nested' } }

-- SECTION: OTHER BONUSES | IMMUNITIES :addRow{ { tag = 'th', content = 'Other bonuses', colspan = '12', class = 'infobox-subheader' }, { tag = 'th', content = 'Immunities', colspan = '8', class = 'infobox-subheader' } }

-- NESTED PIC HEADERS: attbns | strbns | rngbns | mbns | immunepoison | immunevenom :addRow{ { tag = 'th', content = '', colspan = '3', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '3', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '3', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '3', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' }, { tag = 'th', content = '', colspan = '4', class = 'infobox-nested' } }

-- PARAMETER: attbns | strbns | rngbns | mbns | immunepoison | immunevenom :addRow{ { tag = 'argd', content = 'attbns', colspan = '3', class = 'infobox-nested' }, { tag = 'argd', content = 'strbns', colspan = '3', class = 'infobox-nested' }, { tag = 'argd', content = 'rngbns', colspan = '3', class = 'infobox-nested' }, { tag = 'argd', content = 'mbns', colspan = '3', class = 'infobox-nested' }, { tag = 'argd', content = 'immunepoison', colspan = '4', class = 'infobox-nested' }, { tag = 'argd', content = 'immunevenom', colspan = '4', class = 'infobox-nested' } }

-- SECTION: ATTACK SPEED :addRow{ { tag = 'th', content = 'Attack speed', class = 'infobox-subheader', colspan = '20' } }

-- PARAMETER: attack speed :addRow{ { tag = 'argd', content = 'attack speed', colspan = '20', class = 'infobox-full-width-content' } }

if onmain then local a1 = ret:param('all') local a2 = ret:categoryData ret:wikitext(addcategories(a1, a2)) end return ret:tostring end

-- TODO: Ensure most infoboxes are numeric, then we can ensure args are numbers. -- For now, do not do any special processing. function numericarg(arg, arg_name) if paramtest.is_empty(arg) then return nil end return arg end

-- If the arg is numeric, return the signed version (starts with + or -) function signednumericarg(arg, arg_name) local _arg = numericarg(arg, arg_name) if tonumber(_arg) ~= nil then return signed(_arg) end return nil end

-- Sign the arg and append a percent sign function signedpercentnumericarg(arg, arg_name) local _arg = signednumericarg(arg, arg_name) if _arg ~= nil then return _arg..'%' end return nil end

-- Generate pics for defined slayer masters, or return nil if not assigned function slayerarg(...) local args = {...} -- args[i] is the value passed to the i-th slayer master ('yes' or nil) local result = {} local count = 0

for i, slayer_master in ipairs(slayer_masters) do		if args[i] ~= nil and string.lower(args[i]) == 'yes' then count = count + 1 table.insert(result, string.format('', slayer_master, slayer_master)) end end

if count > 0 then return table.concat(result, ' ') else return nil end end

function immunearg(arg, arg_name) if not infobox.isDefined(arg) then return nil end

local arg = string.lower(arg) if arg == 'no' or arg == 'not immune' then return 'Not immune' elseif arg == 'yes' or arg == 'immune' then return 'Immune' elseif arg:sub(1, #'poison') == 'poison' then return ''.. 'Poison ' elseif arg:sub(1, #'smoke') == 'smoke' then return ''.. 'Smoke spells ' else return badarg(arg_name, "should be 'yes' or 'no'.") end end

-- red ERR span with title hover for explanation function badarg(argname, argmessage) return ''.. 'ERR ' end

function addcategories(args, catargs) local ret = { 'Monsters' }

-- Add the associated category if the parameter has content local defined_args = { aka = 'Pages with AKA', aspeed = 'Pages with aspeed' }	for n, v in pairs(defined_args) do		if catargs[n] and catargs[n].one_defined then table.insert(ret, v)		end end

-- Add the associated category if the parameter doesn't have content local notdefined_args = { image = 'Needs image', members = 'Needs members status', release = 'Needs release date', examine = 'Needs examine added', combat = 'Needs combat level', id = 'Needs ID' }	for n, v in pairs(notdefined_args) do		if catargs[n] and catargs[n].all_defined == false then table.insert(ret, v)		end end

-- Adds Category:Needs Monster Examine if any of these are not defined local monster_examine_args = { 'att', 'str', 'def', 'range', 'mage', 'astab', 'aslash', 'acrush', 'amagic', 'arange', 'dstab', 'dslash', 'dcrush', 'dmagic', 'drange', 'attbns', 'strbns', 'rngbns', 'mbns', 'immunepoison', 'immunevenom', 'attack speed' }	for _, arg in ipairs(monster_examine_args) do		if not catargs[arg] or not catargs[arg].all_defined then table.insert(ret, 'Needs Monster Examine') break end end

-- Adds Category:Needs slayer information if slayer info is required -- but not all args are defined local slayer_args = { 'slaylvl', 'slayxp', 'cat' }	if catargs['assigned_by'].one_defined then for i, arg in ipairs(slayer_args) do			if not catargs[arg] or not catargs[arg].all_defined then table.insert(ret, 'Needs slayer information') break end end end table.insert(ret, 'Slayer monsters')

-- combine table and format category wikicode for i, v in ipairs(ret) do		if (v ~= '') then ret[i] = string.format('', v)		end end

return table.concat(ret, '') end

return p