Module:Infobox ModStats new
Documentation for this module may be created at Module:Infobox ModStats new/doc
-- <nowiki>
--[=[
-- Implements [[Template:Infobox ModStats]]
--]=]
local p = {}
local infobox = require('Module:Infobox')
local onmain = require('Module:Mainonly').on_main
local paramtest = require('Module:Paramtest')
local yesno = require('Module:Yesno')
local editbutton = require('Module:Edit button')
local commas = require('Module:Addcommas')._add
-- Accepted slot names
local slots = {
head = 'head',
neck = 'neck',
back = 'back',
cape = 'back',
torso = 'torso',
body = 'torso',
legs = 'legs',
hands = 'hands',
feet = 'feet',
ammo = 'ammo',
ring = 'ring',
aura = 'aura',
pocket = 'pocket',
sigil = 'sigil',
main = 'main hand weapon',
['main hand'] = 'main hand weapon',
['main-hand'] = 'main hand weapon',
mainhand = 'main hand weapon',
weapon = 'main hand weapon',
['2h'] = '2h weapon',
['off-hand'] = 'off-hand',
offhand = 'off-hand',
shield = 'off-hand',
['off-hand weapon'] = 'off-hand weapon',
['offhand weapon'] = 'off-hand weapon',
ohw = 'off-hand weapon',
set = 'e',
none = 'e'
}
-- Categories for slots
local slot_cats = {
head = 'Head slot items',
neck = 'Neck slot items',
back = 'Back slot items',
torso = 'Torso slot items',
legs = 'Legs slot items',
hands = 'Hand slot items',
feet = 'Feet slot items',
ammo = 'Ammunition slot items',
ring = 'Rings',
aura = 'Auras',
pocket = 'Pocket slot items',
sigil = 'Sigil slot items',
['main hand weapon'] = 'Main hand slot items',
['2h weapon'] = 'Two-handed slot items',
['off-hand'] = 'Off-hand slot items',
['off-hand weapon'] = 'Off-hand slot weapon',
e = ''
}
-- Images used for slot display
local slot_images = {
head = '[[File:Head slot.png|link=Head slot]]',
ammo = '[[File:Ammo slot.png|link=Ammunition slot]]',
neck = '[[File:Neck slot.png|link=Neck slot]]',
back = '[[File:Back slot.png|link=Back slot]]',
['main hand weapon'] = '[[File:Main hand slot.png|link=Main hand slot]]',
['2h weapon'] = '[[File:2h slot.png|link=Two-handed slot]]',
torso = '[[File:Torso slot.png|link=Torso slot]]',
['off-hand'] = '[[File:Off-hand slot.png|link=Off-hand slot]]',
['off-hand weapon'] = '[[File:Off-hand slot.png|link=Off-hand slot]]',
legs = '[[File:Legs slot.png|link=Legs slot]]',
hands = '[[File:Gloves slot.png|link=Hands slot]]',
feet = '[[File:Feet slot.png|link=Feet slot]]',
ring = '[[File:Ring slot.png|link=Ring slot]]',
aura = '[[File:Aura slot.png|link=Aura slot]]',
pocket = '[[File:Pocket slot.png|link=Pocket slot]]',
sigil = '[[File:Sigil slot.png|link=Sigil slot]]',
e = 'None'
}
-- 'invention slots'
local inv_slots = {
['main hand weapon'] = 'mh',
['2h weapon'] = '2h',
['off-hand'] = 'oh',
['off-hand weapon'] = 'oh',
shield = 'shield',
torso = 'body',
legs = 'legs',
tool = 'tool',
t = 'tool'
}
-- Accepted class names
local classes = {
melee = 'melee',
ranged = 'ranged',
ranging = 'ranged',
range = 'ranged',
magic = 'magic',
mage = 'magic',
all = 'all',
hybrid = 'hybrid',
none = 'none',
['n/a'] = 'none'
}
-- Classes with images
local class_img = {
melee = '[[File:Attack.png|x24px|link=Melee]]',
ranged = '[[File:Ranged.png|x24px|link=Ranged]]',
magic = '[[File:Magic.png|x24px|link=Magic]]',
hybrid = '[[File:CombatSwords.png|x24px|link=Armour#Hybrid]]',
all = '[[File:CombatSwords.png|x24px|link=Armour#All]]',
none = ''
}
local class_cats = {
melee = 'Melee',
magic = 'Magic',
ranged = 'Ranged',
hybrid = 'Hybrid',
all = 'Hybrid',
none = 'Typeless',
}
-- Accepted style names
local styles = {
stab = 'stab',
stabbing = 'stab',
slash = 'slash',
slashing = 'slash',
crush = 'crush',
crushing = 'crush',
arrow = 'arrows',
arrows = 'arrows',
bolt = 'bolts',
bolts = 'bolts',
thrown = 'thrown',
throwing = 'thrown',
magic = 'spell-casting',
spell = 'spell-casting',
spells = 'spell-casting',
none = 'none',
['n/a'] = 'none'
}
-- Categories for styles
local style_cats = {
stab = 'Stab weapons',
slash = 'Slash weapons',
crush = 'Crush weapons',
thrown = 'Thrown weapons'
}
local types = {
power = 'Power armour',
['power armour'] = 'Power armour',
tank = 'Tank armour',
['tank armour'] = 'Tank armour',
pvp = 'PvP armour',
['pvp armour'] = 'PvP armour',
shieldbow = 'Shieldbow',
shortbow = 'Shortbow',
defender = 'Defender',
repriser = 'Repriser',
rebounder = 'Rebounder',
halberd = 'Halberd',
shield = 'Shield',
chargebow = 'Chargebow',
cosmetic = 'Cosmetic',
['prevents attack'] = 'Prevents attack',
-- weapon diversity
dagger = 'Dagger',
spear = 'Spear',
scimitar = 'Scimitar',
['2h sword'] = '2h sword',
['two handed sword'] = '2h sword',
mace = 'Mace',
maul = 'Maul',
['1h crossbow'] = 'Crossbow',
['one handed crossbow'] = 'Crossbow',
['crossbow'] = 'Crossbow',
['2h crossbow'] = '2h crossbow',
['two handed crossbow'] = '2h crossbow',
['throwing knife'] = 'Throwing knife',
['throwing axe'] = 'Throwing axe',
}
local type_cats = {
['cosmetic'] = { '[[Cosmetic]]' },
['power armour'] = { '[[Power armour]]', 'Power armour' },
['tank armour'] = { '[[Tank armour]]', 'Tank armour' },
['pvp armour'] = { '[[PvP armour]]', 'PvP armour' },
shieldbow = { '[[Shieldbow (bow type)|Shieldbow]]', 'Shieldbows' },
shortbow = { '[[Shortbow (bow type)|Shortbow]]','Shortbows' },
defender = { '[[Defender]]', 'Defenders' },
repriser = { '[[Repriser]]', 'Defenders' },
rebounder = { '[[Rebounder]]', 'Defenders' },
halberd = { '[[Halberd]]', 'Halberds' },
shield = { '[[Shield]]', 'Shields' },
chargebow = { '[[Chargebow (bow type)|Chargebow]]', 'Chargebows' },
['prevents attack'] = { 'Prevents attack', 'Items which prevent attack' },
dagger = { '[[Dagger]]', 'Daggers' },
spear = { '[[Spear]]', 'Spears' },
scimitar = { '[[Scimitar]]', 'Scimitars' },
['2h sword'] = { '[[Two-handed sword|2h sword]]', 'Two-handed swords'},
mace = { '[[Mace]]', 'Maces' },
maul = { '[[Maul]]', 'Mauls' },
['crossbow'] = { '[[Crossbow (weapon type)|Crossbow]]', 'One-handed crossbows' },
['2h crossbow'] = { '[[Two-handed crossbow|2h crossbow]]', 'Two-handed crossbows' },
['throwing knife'] = { '[[Throwing knife]]', 'Throwing knives' },
['throwing axe'] = { '[[Throwing axes|Throwing axe]]', 'Throwing axes' },
}
local reduction_types = { -- accepts type or class
['tank armour'] = 'tank',
['power armour'] = 'other',
['pvp armour'] = 'pvp',
['shield'] = 'shield',
['shieldbow'] = 'shield',
['hybrid'] = 'other',
['all'] = 'other'
}
local reductions = { -- type -> slot -> pvm, pvp multipliers
tank = {
head = {pvm = 0.02, pvp = 0.0375},
torso = {pvm = 0.02, pvp = 0.06},
legs = {pvm = 0.02, pvp = 0.0525},
hands = {pvm = 0.02, pvp = 0},
feet = {pvm = 0.02, pvp = 0}
},
pvp = {
head = {pvm = 0, pvp = 0.0375},
torso = {pvm = 0, pvp = 0.06},
legs = {pvm = 0, pvp = 0.0525}
},
other = { --power, hybrid, all
head = {pvm = 0, pvp = 0.01875},
torso = {pvm = 0, pvp = 0.03},
legs = {pvm = 0, pvp = 0.02625}
},
shield = { --because hybrid shields are a thing
-- for consistency to continue allowing reduction.type.slot.pvx
['off-hand'] = {pvm = 0.1, pvp = 0},
['2h weapon'] = {pvm = 0.1, pvp = 0}, --shieldbows pls
}
}
function p.main(frame)
local args = frame:getParent().args
local ret = infobox.new(args)
ret:defineParams{
{ name = 'image', func = { name = imagearg, params = { 'image' }, flag = 'p' } },
{ name = 'altimage', func = { name = imagearg, params = { 'altimage' }, flag = 'p' } },
{ name = 'noimgcat', func = { name = noimgcatarg, params = { 'noimgcat', 'image' }, flag='p' } },
{ name = 'requirements', func = requirementsarg },
{ name = 'class', func = { name = lookuparg, params = { classes, 'class' }, flag = { 'r', 'd' } } },
{ name = 'classimg', func = { name = lookuparg, params = { class_img, 'class' }, flag = { 'r', 'd' } } },
{ name = 'classstr', func = { name = classstrarg, params = {'class', 'classimg' }, flag = 'd' } },
{ name = 'class_smw', func = { name = classsmwarg, params = { 'class' }, flag = { 'd' } } },
{ name = 'tier', func = tierarg },
{ name = 'type', func = { name = lookupmultiarg, params = { types, 'type' }, flag = { 'r', 'd' } } },
{ name = 'type_disp', func = { name = type_display, params = { 'type' }, flag = { 'd' } } },
{ name = 'slot', func = { name = lookuparg, params = { slots, 'slot' }, flag = { 'r', 'd' } } },
{ name = 'slotimg', func = { name = lookuparg, params = { slot_images, 'slot' }, flag = { 'r', 'd' } } },
{ name = 'isweapon', func = { name = isweaponarg, params = { 'slot', 'type' }, flag = d } },
{ name = 'style', func = { name = stylearg, params = { 'style', 'isweapon' }, flag = 'd' } },
{ name = 'attackrange', func = { name = attackrangearg, params = { 'isweapon', 'attack_range', 'attack range', 'attackrange' }, flag = { 'd', 'p', 'p', 'p' } } },
{ name = 'attackrangesmw', func = { name = attackrangesmwarg, params = { 'attackrange' }, flag = 'd' } },
{ name = 'damage', func = fnumbers },
{ name = 'accuracy', func = fnumbers },
{ name = 'maindamage', func = { name = mainoffdamarg, params = { 'damage', 'slot', 'damage', {'main hand weapon', '2h weapon', 'ammo'} }, flag = { 'd', 'd', 'p', 'r' } } },
{ name = 'mainaccuracy', func = { name = mainoffaccarg, params = { 'accuracy', 'slot', {'main hand weapon', '2h weapon'} }, flag = { 'd', 'd', 'r' } } },
{ name = 'offdamage', func = { name = mainoffdamarg, params = { 'damage', 'slot', 'damage', {'off-hand weapon'} }, flag = { 'd', 'd', 'p', 'r' } } },
{ name = 'offaccuracy', func = { name = mainoffaccarg, params = { 'accuracy', 'slot', {'off-hand weapon'} }, flag = { 'd', 'd', 'r' } } },
{ name = 'armour', func = armourarg },
{ name = 'life', func = fnumbers2 },
{ name = 'prayer', func = fnumbers2 },
{ name = 'magic', func = fnumbers },
{ name = 'strength', func = fnumbers },
{ name = 'ranged', func = fnumbers },
{ name = 'magicstr', func = { name = stylebonusesarg, params = { 'magic', 'Magic', 'magic' }, flag = { 'd', 'r', 'p' } } },
{ name = 'strengthstr', func = { name = stylebonusesarg, params = { 'strength', 'Strength', 'strength' }, flag = { 'd', 'r', 'p' } } },
{ name = 'rangedstr', func = { name = stylebonusesarg, params = { 'ranged', 'Ranged', 'ranged' }, flag = { 'd', 'r', 'p' } } },
{ name = 'reductionlevel', func = { name = reductionlevelarg, params = { 'reductionlevel', 'tier', 'requirements' }, flag = { 'p', 'd', 'd' } } },
{ name = 'pvmreduction', func = { name = reductionarg, params = { 'reductionlevel', 'pvmReduction', 'type', 'slot', 'class', 'pvm' }, flag = { 'd', 'p', 'd', 'd', 'd', 'r' } } },
{ name = 'pvpreduction', func = { name = reductionarg, params = { 'reductionlevel', 'pvpReduction', 'type', 'slot', 'class', 'pvp' }, flag = { 'd', 'p', 'd', 'd', 'd', 'r' } } },
{ name = 'pvmreductionstr', func = { name = reductionstrarg, params = { 'pvmreduction', "'''PvM: '''" }, flag = { 'd', 'r' } } },
{ name = 'pvpreductionstr', func = { name = reductionstrarg, params = { 'pvpreduction', "'''PvP: '''" }, flag = { 'd', 'r' } } },
{ name = 'speedraw', func = { name = speedrawarg, params = { 'isweapon', 'speed', 'aspeed' }, flag = { 'd', 'p', 'p' } } },
{ name = 'speed', func = { name = speedarg, params = { 'speedraw' }, flag = 'd' } },
{ name = 'layouttype', func = { name = layoutarg, params = { 'image', 'altimage' }, flag ='d' } },
{ name = 'isrecolour', func = { name = recolourarg, params = { 'isrecolour' }, flag = 'd' } },
{ name = 'intbonus', func = { name = intbonusarg, params = { 'armour', 'damage', 'strength', 'ranged', 'magic' }, flag ='p' } },
{ name = 'tier_smw', func = { name = smwtierarg, params = { 'tier' }, flag = 'd' } },
{ name = 'style_smw', func = { name = smwstylearg, params = { 'style' }, flag = 'd' } },
{ name = 'damage_smw', func = { name = smwnumbers, params = { 'damage' }, flag = 'd' } },
{ name = 'accuracy_smw', func = { name = smwnumbers, params = { 'accuracy' }, flag = 'd' } },
{ name = 'armour_smw', func = { name = smwnumbers2, params = { 'armour' }, flag = 'd' } },
{ name = 'life_smw', func = { name = smwnumbers2, params = { 'life' }, flag = 'd' } },
{ name = 'prayer_smw', func = { name = smwnumbers2, params = { 'prayer' }, flag = 'd' } },
{ name = 'magic_smw', func = { name = smwnumbers, params = { 'magic' }, flag = 'd' } },
{ name = 'strength_smw', func = { name = smwnumbers, params = { 'strength' }, flag = 'd' } },
{ name = 'ranged_smw', func = { name = smwnumbers, params = { 'ranged' }, flag = 'd' } },
}
ret:setMaxButtons(7)
ret:setAddRSWInfoboxClass(false)
ret:create()
ret:cleanParams()
ret:customButtonPlacement(true)
ret:defineLinks({
colspan = 12,
links = {
{ 'Template:Infobox ModStats/FAQ', 'FAQ' },
{ 'Template:Infobox ModStats', 'docs' }
}
})
ret:css({
width = '450px',
float = 'none',
margin = '0.8em 0'
})
--smw here later
ret:useSMWSubobject({
smwJSON = 'Equipment JSON',
class_smw = 'Combat class',
slot = 'Equipment slot',
type = 'Equipment type',
damage_smw = 'Weapon damage',
accuracy_smw = 'Weapon accuracy',
style_smw = 'Attack style',
attackrangesmw = 'Attack range',
armour_smw = 'Equipment armour',
life_smw = 'Equipment life points',
speedraw = 'Weapon attack speed',
prayer_smw = 'Prayer bonus',
strength_smw = 'Strength bonus',
ranged_smw = 'Ranged bonus',
magic_smw = 'Magic bonus',
tier_smw = 'Equipment tier',
charges = 'Degradation charges',
invtier = 'Invention tier',
isrecolour = 'Is cosmetic recolour',
intbonus = 'Has integer bonuses'
})
ret:addButtonsCaption()
ret:defineName('Infobox ModStats')
ret:addClass('infobox-modstats wikitable')
ret:tag('caption'):wikitext("'''[[Combat Stats]]'''")
local layout = ret:param('layouttype', 'r')
p['_main'..layout](ret)
if onmain() then
local a1 = ret:param('all')
local a2 = ret:categoryData()
local cats = addcategories(ret,a1,a2)
ret._categories_test = cats
ret:wikitext(cats)
end
return ret:tostring()
end
-- 1 image
function p._mainA(ret)
local row1 = {
{ tag = 'th', content = 'Requirements', colspan = 6, class = 'combat-requirements' },
{ tag = 'argd', content = 'image', colspan = 6, rowspan = 11, class = 'infobox-image bordered-image' }
}
local row2 = {
{ tag = 'argd', content = 'requirements', colspan = 6, css = { ['max-width'] = '240px' } } -- stop skill reqs getting too wide
}
if ret:param('speed', 'r') ~= 'no' then
row1[2].rowspan = 12
end
if infobox.isDefined(ret:param('degradetype', 'r')) then
row1[1].colspan = 3
row2[1].colspan = 3
table.insert(row1, 2, { tag = 'argh', content = 'degradeheader', colspan = 3 })
table.insert(row2, 2, { tag = 'argd', content = 'degradestr', colspan = 3 })
if ret:param('degradetype', 'r') == 'invention' then
ret:append(tostring(ret:param('invdegrade_div', 'r')))
end
end
ret:addRow(row1):addRow(row2)
-- class, slot
ret:addRow{
{ tag = 'th', content = 'Class', colspan = 3 },
{ tag = 'th', content = 'Slot', colspan = 3 }
}
:addRow{
{ tag = 'argd', content = 'classstr', colspan = 3 },
{ tag = 'argd', content = 'slotimg', colspan = 3 }
}
if ret:paramDefined('type') then
-- tier, type
ret:addRow{
{ tag = 'th', content = '[[Equipment tier|Tier]]', colspan = 3 },
{ tag = 'th', content = 'Type', colspan = 3 }
}
:addRow{
{ tag = 'argd', content = 'tier', colspan = 3 },
{ tag = 'argd', content = 'type_disp', colspan = 3 }
}
else
ret:addRow{
{ tag = 'th', content = '[[Equipment tier|Tier]]', colspan = 6 }
}
:addRow{
{ tag = 'argd', content = 'tier', colspan = 6 }
}
end
-- weapons section
ret:addRow{ --headers
{ tag = 'th', content = 'Weapons', colspan = 2, css = { width = '33%' } },
{ tag = 'th', content = 'Main', colspan = 2, css = { width = '33%' } },
{ tag = 'th', content = 'Off', colspan = 2, css = { width = '33%' } }
}
:addRow{ -- damage
{ tag = 'th', content = '[[Ability damage|Damage]]', colspan = 2 },
{ tag = 'argd', content = 'maindamage', colspan = 2 },
{ tag = 'argd', content = 'offdamage', colspan = 2 }
}
:addRow{ -- accuracy
{ tag = 'th', content = '[[Hit chance|Accuracy]]', colspan = 2 },
{ tag = 'argd', content = 'mainaccuracy', colspan = 2 },
{ tag = 'argd', content = 'offaccuracy', colspan = 2 }
}
:addRow{ -- style
{ tag = 'th', content = '[[Attack types|Style]]', colspan = 2 },
{ tag = 'argd', content = 'style', colspan = 4 }
}
:addRow{ -- range
{ tag = 'th', content = '[[Attack range|Range]]', colspan = 2 },
{ tag = 'argd', content = 'attackrange', colspan = 4 }
}
if ret:param('speed', 'r') ~= 'no' then
ret:addRow{ -- rate (formely speed)
{ tag = 'th', content = '[[Attack rate|Rate]]', colspan = 2 },
{ tag = 'argd', content = 'speed', colspan = 4, css = { padding = '0.2em' } }
}
end
-- attributes / bottom section
ret:addRow{ -- attribute & reduction headers
{ tag = 'th', content = 'Attributes', colspan = 6 },
{ tag = 'th', content = '[[Damage reduction]]', colspan = 6, css = { ['min-width'] = '225px' } }, -- force as wide as other side (3x th = 210 from css, + paddings and borders = 225)
}:addRow{ -- armour, reductions
{ tag = 'th', content = skillpic('Defence') .. ' Armour', colspan = 4, class = 'combat-attributes' },
{ tag = 'argd', content = 'armour', colspan = 2, css = { ['text-align'] = 'right' } },
{ tag = 'argd', content = 'pvmreductionstr', colspan = 3 },
{ tag = 'argd', content = 'pvpreductionstr', colspan = 3 }
}:addRow{ -- life points, style header
{ tag = 'th', content = skillpic('Constitution') .. ' Life points', colspan = 4, class = 'combat-attributes' },
{ tag = 'argd', content = 'life', colspan = 2, css = { ['text-align'] = 'right' } },
{ tag = 'th', content = '[[Damage bonus|Style bonuses]]', colspan = 6 },
}:addRow{ -- prayer, style bonuses
{ tag = 'th', content = skillpic('Prayer') .. ' Prayer', colspan = 4, class = 'combat-attributes' },
{ tag = 'argd', content = 'prayer', colspan = 2, css = { ['text-align'] = 'right' } },
{ tag = 'argd', content = 'strengthstr', colspan = 2 },
{ tag = 'argd', content = 'rangedstr', colspan = 2 },
{ tag = 'argd', content = 'magicstr', colspan = 2 },
}
-- bottom row
-- kinda special to accomodate the compare button
--[=[ret :tag('tr')
:addClass('infobox-bonuses-bottomrow')
:css('border', 'none')
:tag('td')
:attr('colspan', 12)
:css({
background = 'transparent !important',
border = 'none !important',
['text-align'] = 'left',
['font-size'] = 'smaller'
})
:wikitext('[[Template:Infobox ModStats/FAQ|[FAQ]]] • [[Template:Infobox ModStats|[doc]]]')
--]=]
end
-- 2 images or no images
function p._mainB(ret, hasImages)
if hasImages then
ret:addRow{
{ tag = 'argd', content = 'image', colspan = 6 },
{ tag = 'argd', content = 'altimage', colspan = 6 }
}
end
local row1 = {
{ tag = 'th', content = 'Requirements', colspan = 6, class = 'combat-requirements' },
{ tag = 'th', content = '[[Equipment tier|Tier]]', colspan = 6 }
}
local row2 = {
{ tag = 'argd', content = 'requirements', colspan = 6, css = { ['max-width'] = '240px' } }, -- stop skill reqs getting too wide
{ tag = 'argd', content = 'tier', colspan = 6 }
}
local row1tier = row1[2]
local row2tier = row2[2]
if infobox.isDefined(ret:param('degradetype', 'r')) then
row1[1].colspan = 3
row2[1].colspan = 3
table.insert(row1, 2, { tag = 'argh', content = 'degradeheader', colspan = 3 })
table.insert(row2, 2, { tag = 'argd', content = 'degradestr', colspan = 3 })
if ret:param('degradetype', 'r') == 'invention' then
ret:append(tostring(ret:param('invdegrade_div', 'r')))
end
end
if ret:paramDefined('type') then
row1tier.colspan = 3
row2tier.colspan = 3
table.insert(row1, { tag = 'th', content = 'Type', colspan = 3 })
table.insert(row2, { tag = 'argd', content = 'type_disp', colspan = 3 })
end
ret:addRow(row1):addRow(row2)
local strSpan = 1
if infobox.isDefined(ret:param('speed', 'r')) and ret:param('speed', 'r') ~= 'no' then
strSpan = 2
end
ret:addRow{
-- class, slot, attr headers
{ tag = 'th', content = 'Class', colspan = 3, css = { width = '50%' } },
{ tag = 'th', content = 'Slot', colspan = 3, css = { width = '50%' } },
{ tag = 'th', content = 'Attributes', colspan = 6 },
}
:addRow{
-- class, slot, armour
{ tag = 'argd', content = 'classstr', rowspan = 2, colspan = 3 },
{ tag = 'argd', content = 'slotimg', rowspan = 2, colspan = 3 },
{ tag = 'th', content = skillpic('Defence') .. ' Armour', colspan = 4, class = 'combat-attributes' },
{ tag = 'argd', content = 'armour', colspan = 2, css = { ['text-align'] = 'right' } }
}
:addRow{
-- [class second row from rowspan]
-- [slot second row from rowspan]
-- life points
{ tag = 'th', content = skillpic('Constitution') .. ' Life points', colspan = 4, class = 'combat-attributes' },
{ tag = 'argd', content = 'life', colspan = 2, css = { ['text-align'] = 'right' } }
}
:addRow{
-- weapons header, prayer
{ tag = 'th', content = 'Weapons', colspan = 2, css = { width = '33%' } },
{ tag = 'th', content = 'Main', colspan = 2, css = { width = '33%' } },
{ tag = 'th', content = 'Off', colspan = 2, css = { width = '33%' } },
{ tag = 'th', content = skillpic('Prayer') .. ' Prayer', colspan = 4, class = 'combat-attributes' },
{ tag = 'argd', content = 'prayer', colspan = 2, css = { ['text-align'] = 'right' } }
}
:addRow{
-- damage, reduction header
{ tag = 'th', content = '[[Ability damage|Damage]]', colspan = 2 },
{ tag = 'argd', content = 'maindamage', colspan = 2 },
{ tag = 'argd', content = 'offdamage', colspan = 2 },
{ tag = 'th', content = '[[Damage reduction]]', colspan = 6 }
}
:addRow{
-- accuracy, reductions
{ tag = 'th', content = '[[Hit chance|Accuracy]]', colspan = 2 },
{ tag = 'argd', content = 'mainaccuracy', colspan = 2 },
{ tag = 'argd', content = 'offaccuracy', colspan = 2 },
{ tag = 'argd', content = 'pvmreductionstr', colspan = 3 },
{ tag = 'argd', content = 'pvpreductionstr', colspan = 3 }
}
:addRow{
-- style, style bonuses header
{ tag = 'th', content = '[[Attack types|Style]]', colspan = 2 },
{ tag = 'argd', content = 'style', colspan = 4 },
{ tag = 'th', content = '[[Damage bonus|Style bonuses]]', colspan = 6 }
}
:addRow{
-- range
{ tag = 'th', content = '[[Attack range|Range]]', colspan = 2 },
{ tag = 'argd', content = 'attackrange', colspan = 4 },
{ tag = 'argd', content = 'strengthstr', colspan = 2, rowspan = strSpan },
{ tag = 'argd', content = 'rangedstr', colspan = 2, rowspan = strSpan },
{ tag = 'argd', content = 'magicstr', colspan = 2, rowspan = strSpan }
}
if ret:param('speed', 'r') ~= 'no' then
ret:addRow{ --(formely speed)
{ tag = 'th', content = '[[Attack rate|Rate]]', colspan = 2 },
{ tag = 'argd', content = 'speed', colspan = 4, css = { padding = '0.2em' } }
}
end
end
function p._mainB0(ret)
return p._mainB(ret, false)
end
function p._mainB2(ret)
return p._mainB(ret, true)
end
-- images
function imagearg(f)
local height, width = 280, 220
if paramtest.is_empty(f) then
return nil
end
f = tostring(f)
if string.lower(f) == 'no' then
return nil
end
f = f:gsub('[Ff]ile:',''):gsub('{{!}}','|')
f = mw.text.split(f, '|')
f = f[1]
return mw.ustring.format('[[File:%s|%sx%spx|frameless|alt=%s: %s equipped by a player]]', f, width, height, f, mw.title.getCurrentTitle().text)
end
function noimgcatarg(nocat, img)
if infobox.isDefined(nocat) then
return 'true'
end
if infobox.isDefined(img) then
if string.lower(img) == 'no' then
return 'true'
end
end
return nil
end
--requirements
function requirementsarg(r)
if infobox.isDefined(r) then
return mw.getCurrentFrame():preprocess(r)
end
return nil
end
-- class style type slot
function lookuparg(t, c)
return t[string.lower(c or '')]
end
function lookupmultiarg(t, c)
local out = {}
if not infobox.isDefined(c) then
return nil
end
c = string.lower(c)
for i in mw.text.gsplit(c, ',') do
table.insert(out, t[mw.text.trim(i)])
end
if #out == 0 then
return nil
end
return table.concat(out, infobox.splitpoint)
end
function type_display(a)
if a == nil then
return nil
end
local out = {}
for i in mw.text.gsplit(a, infobox.splitpoint) do
i = i:lower()
if type_cats[i] then
table.insert(out, type_cats[i][1])
end
end
return table.concat(out, ', ')
end
function stylearg(s, w)
if w == 'true' then
s = styles[string.lower(s or '')]
if s then
return paramtest.ucfirst(s)
end
return s
end
return '-'
end
function smwstylearg(s)
if s ~= '-' then
return string.lower(tostring(s))
end
end
function classstrarg(c, ci)
if c == 'none' then
return 'None'
end
if infobox.isDefined(c) and infobox.isDefined(ci) then
return ci .. ' ' .. paramtest.ucfirst(c)
end
return nil
end
function classsmwarg(c)
if c == 'all' then
return 'hybrid'
end
return c
end
-- tier
function tierarg(t)
t = tostring(t)
t = t:lower()
if t == 'n/a' or t == 'no' or t == 'none' then
t = 0
end
t = clean(t)
if t then
if t == 0 then
return "''None''"
end
return t
end
return nil
end
function smwtierarg(t)
if t == "''None''" then
return 0
end
if type(t) == 'number' then
return t
end
return nil
end
-- numerical args
function fnumbers(x)
x = clean(x)
if x then
return x
end
return '-'
end
function fnumbers2(x)
x = clean(x)
if x then
return x
end
return 0
end
function smwnumbers(x)
if tonumber(x) then
return x
end
return 0
end
function smwnumbers2(x)
if tonumber(x) then
return x
end
return 0
end
function armourarg(pas)
local x = fnumbers(pas)
if x == '-' then --nil
return '0.0'
elseif pas:find('%d%.%d') then --has decimal
return string.format('%.1f', x)
end
return x --no decimal
end
function mainoffaccarg(x, s, slots)
for i,v in ipairs(slots) do
if s == v then
return tonumber(x)
end
end
return '-'
end
function mainoffdamarg(x, s, pas, slots)
local r = nil
local found = false
for i,v in ipairs(slots) do
if s == v then
r = tonumber(x)
found = true
break
end
end
if r then
if pas:find('%d%.%d') then
r = string.format('%.1f', r)
end
return r
end
if found then
return nil
end
return '-'
end
function stylebonusesarg(x, t, passed)
local s = tostring(x)
if x == '-' then
s = '0.0'
elseif passed:find('%d%.%d') then
s = string.format('%.1f', x)
end
return mw.ustring.format('<span style="float:left;">%s</span><span style="float:right;">%s</span>', skillpic(t), s)
end
-- isWeapon boolean
function isweaponarg(s,t)
local weapon_slots = {
['main hand weapon'] = 'true',
['2h weapon'] = 'true',
['off-hand weapon'] = 'true'
}
local non_weapon_types = {
['Prevents attack'] = 'true'
}
if non_weapon_types[t] then
return 'false'
end
return weapon_slots[s] or 'false'
end
--smw
function chargesarg(dt, c)
if dt == 'normal' then
if type(c) == 'number' then
return c
end
end
return nil
end
function invtierarg(dt, t)
if dt == 'invention' then
t = clean(t)
if t then
return t
end
end
return nil
end
-- attack range
function attackrangearg(w,r1,r2,r3)
if w == 'true' then
return clean(r1) or clean(r2) or clean(r3)
end
return '-'
end
function attackrangesmwarg(a)
if a == '-' then
return nil
end
return a
end
-- reductions
function reductionlevelarg(r, tier, reqs)
if r then
r = clean(r)
if r then
return r
end
end
local ret = tonumber(tier) or 0
if infobox.isDefined(reqs) then
local maxR = 0
for v in string.gmatch(reqs, '(%d+) %[%[') do
if tonumber(v) and tonumber(v) > maxR then
maxR = tonumber(v)
end
end
if maxR > 0 then
ret = maxR
end
end
return ret
end
function reductionarg(rl, over, t, s, c, pvx)
over = clean(over)
if over then
--overridden
return over .. '%'
end
if not infobox.isDefined(rl) then
--tier/rl not defined
return '0%'
end
local reduction_table, reduction_type = nil,nil
if infobox.isDefined(t) then
-- check if we have a reduction for this type+slot
reduction_type = reduction_types[t:lower()]
if reduction_type then
reduction_table = reductions[reduction_type][s]
end
end
if not reduction_table and infobox.isDefined(c) then
-- couldn't find type+slot, so class+slot
reduction_type = reduction_types[c:lower()]
if reduction_type then
reduction_table = reductions[reduction_type][s]
end
end
if reduction_table then
return (reduction_table[pvx] or 0) * rl .. '%'
end
-- didn't find anything
return '0%'
end
function reductionstrarg(r, ty)
return mw.ustring.format('<span style="float:left;">%s</span><span style="float:right;">%s</span>', ty, r)
end
-- speed
function speedrawarg(iswep, s1, s2)
if iswep =='true' then
local s
if infobox.isDefined(s1) then
s = string.lower(s1)
elseif infobox.isDefined(s2) then
s = string.lower(s2)
end
return s or ''
else
return 'no'
end
end
function speedarg(s)
if infobox.isDefined(s) then
if s == 'no' then
return 'no'
else
return tostring(attack_speed_bar(s))
end
end
return nil
end
-- layout
function layoutarg(img, alt)
if infobox.isDefined(img) then
if infobox.isDefined(alt) then
-- 2 images
return 'B2'
end
-- 1 image
return 'A'
end
-- no images
return 'B0'
end
function intbonusarg(...)
for _,v in ipairs({...}) do
if paramtest.has_content(v) then
if not v:match('%d%.%d') then
return 'true'
end
end
end
return nil
end
function recolourarg(arg)
-- string to ensure it correctly passes through infobox
return tostring(infobox.isDefined(arg) and yesno(arg, false))
end
-- Removes all plus signs, commas, and percent signs
function clean(number)
if not number then
return nil
else
number = tostring(number)
number = number:gsub('[+,%%]','')
return tonumber(number,10)
end
end
-- legacy SMW JSON
function smwjsonarg(class, slot, style, itype, damage, accuracy, attack_range, armour, life, speed, prayer, strength, ranged, magic, tier, charges, invtier)
local json = {
class = class,
slot = slot,
style = style,
type = itype,
damage = damage,
accuracy = accuracy,
style = style,
attack_range = attack_range,
armour = armour,
lp = life,
speed = speed,
prayer = prayer,
strength = strength,
ranged = ranged,
magic = magic,
tier = tier,
charges = charges,
invention = invtier
}
for k,v in pairs(json) do
if not infobox.isDefined(v) then
json[k] = nil
end
end
local jsonGood, encoded = pcall(mw.text.jsonEncode,json)
if jsonGood then
return encoded
end
return nil
end
-- categories
function addcategories(ibox, args, catargs)
local cats = {'Equipment'}
local versions = ibox.versions
function forAllSwitches(func, param1, param2, param3)
local r = {}
param2 = param2 or {}
param3 = param3 or {}
local p1,p2,p3
p1 = param1.d
p2 = param2.d
p3 = param3.d
table.insert(r, func(p1,p2,p3))
if versions > 0 and (param1.switches or param2.switches or param3.switches) then
local p1s,p2s,p3s
for i = 1,versions,1 do
p1s = p1
if param1.switches then
p1s = param1.switches[i]
if p1s == infobox.nil_param then
p1s = p1
end
end
p2s = p2
if param2.switches then
p2s = param2.switches[i]
if p2s == infobox.nil_param then
p2s = p2
end
end
p3s = p3
if param3.switches then
p3s = param3.switches[i]
if p3s == infobox.nil_param then
p3s = p3
end
end
local ret = func(p1s, p2s, p3s)
if type(ret) == 'table' then
for ir,vr in ipairs(ret) do
table.insert(r, vr)
end
else
table.insert(r, ret)
end
end
end
return r
end
function append(a)
if type(a) == 'table' then
for i,v in ipairs(a) do
table.insert(cats, v)
end
else
table.insert(cats,a)
end
end
-- slot missing
if not catargs.slot.all_defined then
append('Missing slot information')
end
-- tiers
append(forAllSwitches(function(v)
if type(v) == 'number' then
if v == 0 then
return 'Tierless equipment'
elseif v > 0 then
return 'Tier '..v..' equipment'
end
end
return 'Missing equipment tier'
end, args.tier_smw))
-- type
append(forAllSwitches(function(v)
local out = {}
if type(v) == 'string' then
for i in mw.text.gsplit(v, infobox.splitpoint) do
i = i:lower()
if type_cats[i] then
table.insert(out, type_cats[i][2])
end
end
end
return out
end, args.type))
-- slots
append(forAllSwitches(function(v)
v = string.lower(tostring(v))
if v == 'off-hand weapon' then
local k = mw.title.getCurrentTitle().fullText:gsub('[Oo]ff[%- ]?hand ?', '')
return 'Off-hand slot weapons|'..k
elseif slot_cats[v] then
return slot_cats[v]
end
return 'Missing slot information'
end, args.slot))
-- style
append(forAllSwitches(function(v)
return style_cats[v]
end, args.style))
-- degrades
if catargs.normdegrades.one_defined then
append('Degrading equipment')
end
-- class
append(forAllSwitches(function(c,w,s)
local cat = class_cats[c]
if cat then
if s == 'ammo' then
return nil
end
if w == 'true' then
if cat == 'Hybrid' then
cat = 'Typeless'
end
return cat .. ' weapons'
end
return cat .. ' armour'
end
return nil
end, args.class, args.isweapon, args.slot))
-- prayer
append(forAllSwitches(function(p)
if tonumber(p) then
if tonumber(p) > 0 then
return 'Items with a prayer bonus'
end
end
return nil
end, args.prayer_smw))
-- range
if not catargs.attackrange.all_defined then
append('Missing attack range')
end
-- speed
append(forAllSwitches(function(s)
if s == '' then
return 'Missing attack rate'
end
return nil
end, args.speedraw))
-- integer equipment bonuses
if catargs.intbonus.one_defined then
append('Integer equipment bonus')
end
-- equipped image
append(forAllSwitches(function(i, s, n)
if infobox.isDefined(n) then
return nil
end
if s == 'ammo' or s == 'pocket' or s == 'ring' or s == 'sigil' then
return nil
end
if not infobox.isDefined(i) then
return 'Needs equipped image'
end
return nil
end, args.image, args.slot, args.noimgcat))
local _cats = {}
for i,v in ipairs(cats) do
if type(v) == 'table' then
for j,u in ipairs(v) do
if paramtest.has_content(u) then
table.insert(_cats, string.format('[[Category:%s]]', u))
end
end
elseif paramtest.has_content(v) then
table.insert(_cats, string.format('[[Category:%s]]', v))
end
end
return table.concat(_cats, '')
end
return p
-- </nowiki>