Module:Infobox Bonuses new
Jump to navigation
Jump to search
Module documentation
This documentation is transcluded from Module:Infobox Bonuses new/doc. [edit] [history] [purge]
Module:Infobox Bonuses new's function main is invoked by Template:Infobox Bonuses.
Module:Infobox Bonuses new requires .
--[=[
-- Implements [[Template:Infobox Bonuses]]
--]=]
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 skillpic = require('Module:Skill clickpic')._main
local commas = require('Module:Addcommas')._add
local chargedrain = nil
local function getChargeDrainModule()
if chargedrain == nil then
chargedrain = require('Module:Augmented degrade')
end
return chargedrain
end
local attack_speed_bar = require('Module:Attack speed bar').weapon
-- 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',
necro = 'necromancy',
necromancy = 'necromancy',
all = 'all',
hybrid = 'hybrid',
none = 'none',
['n/a'] = 'none'
}
-- Classes with images
local class_img = {
melee = '[[File:Melee style bonus.png|x24px|link=Melee]]',
ranged = '[[File:Ranged style bonus.png|x24px|link=Ranged]]',
magic = '[[File:Magic style bonus.png|x24px|link=Magic]]',
necromancy = '[[File:Necromancy style bonus.png|x24px|link=Necromancy]]',
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',
necromancy = 'Necromancy',
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',
necromancy = 'necromancy',
necro = 'necromancy',
none = '-',
['n/a'] = '-',
no = '-'
}
-- 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',
hybrid = 'Hybrid armour',
['hybrid armour'] = 'Hybrid armour',
['power hybrid'] = 'Power Hybrid armour',
['hybrid power'] = 'Power Hybrid 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',
['death guard'] = 'Death guard'
}
local type_cats = {
['cosmetic'] = { '[[Cosmetic]]' },
['power armour'] = { '[[Armour#Power|Power armour]]', 'Power armour' },
['tank armour'] = { '[[Armour#Tank|Tank armour]]', 'Tank armour' },
['pvp armour'] = { '[[Armour#PvP|PvP armour]]', 'PvP armour' },
['hybrid armour'] = { '[[Armour#Hybrid|Hybrid armour]]', 'Hybrid armour' },
['power hybrid armour'] = { '[[Armour#Hybrid power|Power Hybrid armour]]', 'Power armour' },
shieldbow = { '[[Shieldbow (bow type)|Shieldbow]]', 'Shieldbows' },
shortbow = { '[[Shortbow (bow type)|Shortbow]]','Shortbows' },
defender = { '[[Defenders|Defender]]', 'Defenders' },
repriser = { '[[Repriser]]', 'Defenders' },
rebounder = { '[[Rebounder]]', 'Defenders' },
halberd = { '[[Halberds|Halberd]]', 'Halberds' },
shield = { '[[Shield]]', 'Shields' },
chargebow = { '[[Chargebow (bow type)|Chargebow]]', 'Chargebows' },
['prevents attack'] = { 'Prevents attack', 'Items which prevent attack' },
dagger = { '[[Daggers|Dagger]]', 'Daggers' },
spear = { '[[Spears|Spear]]', 'Spears' },
scimitar = { '[[Scimitars|Scimitar]]', 'Scimitars' },
['2h sword'] = { '[[Two-handed sword|2h sword]]', 'Two-handed swords'},
mace = { '[[Maces|Mace]]', 'Maces' },
maul = { '[[Mauls|Maul]]', 'Mauls' },
['crossbow'] = { '[[Crossbows|Crossbow]]', 'One-handed crossbows' },
['2h crossbow'] = { '[[Two-handed crossbow|2h crossbow]]', 'Two-handed crossbows' },
['throwing knife'] = { '[[Throwing knife]]', 'Throwing knives' },
['throwing axe'] = { '[[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},
hands = {pvm = 0, pvp = 0},
feet = {pvm = 0, pvp = 0}
},
other = { --power, hybrid, all
head = {pvm = 0, pvp = 0.01875},
torso = {pvm = 0, pvp = 0.03},
legs = {pvm = 0, pvp = 0.02625},
hands = {pvm = 0, pvp = 0},
feet = {pvm = 0, pvp = 0}
},
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
}
}
local imagearg, noimgcatarg, requirementsarg, lookuparg, lookupmultiarg,
type_display, stylearg, bucketstylearg, classstrarg, classbucketarg, tierarg, armourtierarg, armourdamagetierarg,
buckettierarg, fnumbers, fnumbers2, bucketnumbers, bucketnumbers2, armourarg,
mainoffaccarg, mainoffdamarg, abilityDamage, abilityDamage_raw,
abilityDamage_disp, stylebonusesarg, isweaponarg, invdegradearg,
invdegradetooltipspanarg, invdegradetooltipdivarg, normdegradesarg,
degradestypearg, degradesstrarg, degradeheaderarg, chargesarg, invtierarg,
hasstylearg, attackrangearg, attackrangebucketarg, reductionlevelarg,
reductionarg, reductionstrarg, speedrawarg, speedarg,
accuracybonusarg, accuracybonusstrarg,
intbonusarg, recolourarg, clean, bucketjsonarg, addcategories
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_bucket', func = { name = classbucketarg, params = { 'class' }, flag = { 'd' } } },
{ name = 'tier', func = tierarg },
{ name = 'damageTier', func = tierarg },
{ name = 'accuracyTier', func = tierarg },
{ name = 'armourTier', func = { name = armourtierarg, params = { 'armourTier', 'type', 'tier' } } },
{ name = 'armourDamageTier', func = { name = armourdamagetierarg, params = { 'armourDamageTier', 'type', 'tier' } } },
{ 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 = 'invdegrade', func = { name = invdegradearg, params = { 'invtier', 'invslot', 'slot' }, flag = 'd' } },
{ name = 'invdegrade_span', func = { name = invdegradetooltipspanarg, params = { 'invtier', 'invslot', 'slot' }, flag = 'd' } },
{ name = 'invdegrade_div', func = { name = invdegradetooltipdivarg, params = { 'invtier', 'invslot', 'slot' }, flag = 'd' } },
{ name = 'normdegrades', func = { name = normdegradesarg, params = { 'degrades' }, flag = 'p' } },
{ name = 'degradetype', func = { name = degradestypearg, params = { 'normdegrades', 'invdegrade' }, flag = 'd' } },
{ name = 'degradestr', func = { name = degradesstrarg, params = { 'degradetype', 'normdegrades', 'invdegrade', 'invdegrade_span' }, flag = 'd' } },
{ name = 'degradeheader', func = { name = degradeheaderarg, params = { 'degradetype' }, flag = 'd' } },
{ name = 'hasstyle', func = { name = hasstylearg, params = { 'slot', 'type' }, flag = 'd' } },
{ name = 'style', func = { name = stylearg, params = { 'style', 'hasstyle', 'class' }, flag = 'd' } },
{ name = 'attackrange', func = { name = attackrangearg, params = { 'isweapon', 'attack_range', 'attack range', 'attackrange' }, flag = { 'd', 'p', 'p', 'p' } } },
{ name = 'attackrangebucket', func = { name = attackrangebucketarg, params = { 'attackrange' }, flag = 'd' } },
{ name = 'damage', func = {name = fnumbers, params={'damage'}, flag='p' } },
{ name = 'accuracy', func = {name = fnumbers, params={'accuracy'}, flag='p' } },
{ name = 'damage_disp', func = { name = mainoffdamarg, params = { 'damage', 'slot', 'damage', {'main hand weapon', '2h weapon', 'ammo', 'off-hand weapon'} }, flag = { 'd', 'd', 'p', 'r' } } },
{ name = 'accuracy_disp', func = { name = mainoffaccarg, params = { 'accuracy', 'slot', {'main hand weapon', '2h weapon', 'off-hand weapon'} }, flag = { 'd', 'd', 'r' } } },
{ name = 'armour', func = {name=armourarg, params={'armour'}, flag=p} },
{ name = 'life', func = {name = fnumbers2, params={'life'}, flag='p' } },
{ name = 'prayer', func = {name = fnumbers2, params={'prayer'}, flag='p' } },
{ name = 'magic', func = {name = fnumbers, params={'magic'}, flag='p' } },
{ name = 'strength', func = {name = fnumbers, params={'strength'}, flag='p' } },
{ name = 'ranged', func = {name = fnumbers, params={'ranged'}, flag='p' } },
{ name = 'necromancy', func = {name = fnumbers, params={'necromancy'}, flag='p' } },
{ name = 'magicstr', func = { name = stylebonusesarg, params = { 'magic', 'Magic', 'magic' }, flag = { 'd', 'r', 'p' } } },
{ name = 'necromancystr', func = { name = stylebonusesarg, params = { 'necromancy', 'Necromancy', 'necromancy' }, flag = { 'd', 'r', 'p' } } },
{ name = 'strengthstr', func = { name = stylebonusesarg, params = { 'strength', 'Attack', 'strength' }, flag = { 'd', 'r', 'p' } } },
{ name = 'rangedstr', func = { name = stylebonusesarg, params = { 'ranged', 'Ranged', 'ranged' }, flag = { 'd', 'r', 'p' } } },
{ name = 'rangedaccuracy', func = {name = accuracybonusarg, params = {'rangedaccuracy', 'ranged', 'slot', 'class', 'armour'}, flag = {'d', 'r', 'd', 'd'} } },
{ name = 'meleeaccuracy', func = {name = accuracybonusarg, params = {'meleeaccuracy', 'melee', 'slot', 'class', 'armour'}, flag = {'d', 'r', 'd', 'd'} } },
{ name = 'magicaccuracy', func = {name = accuracybonusarg, params = {'magicaccuracy', 'magic', 'slot', 'class', 'armour'}, flag = {'d', 'r', 'd', 'd'} } },
{ name = 'necromancyaccuracy', func = {name = accuracybonusarg, params = {'necromancyaccuracy', 'necromancy', 'slot', 'class', 'armour'}, flag = {'d', 'r', 'd', 'd'} } },
{ name = 'rangedaccuracystr', func = { name = accuracybonusstrarg, params={'rangedaccuracy'}} },
{ name = 'meleeaccuracystr', func = { name = accuracybonusstrarg, params={'meleeaccuracy'}} },
{ name = 'magicaccuracystr', func = { name = accuracybonusstrarg, params={'magicaccuracy'}} },
{ name = 'necromancyaccuracystr', func = { name = accuracybonusstrarg, params={'necromancyaccuracy'}} },
{ name = 'reductionlevel', func = { name = reductionlevelarg, params = { 'reductionlevel', 'tier', 'requirements' }, flag = { 'p', 'd', 'd' } } },
{ name = 'pvmreduction', func = { name = reductionarg, params = { 'reductionlevel', 'reductionlevel', 'pvmReduction', 'type', 'slot', 'class', 'pvm' }, flag = { 'p', 'd', 'p', 'd', 'd', 'd', 'r' } } },
{ name = 'pvpreduction', func = { name = reductionarg, params = { 'reductionlevel', 'reductionlevel', 'pvpReduction', 'type', 'slot', 'class', 'pvp' }, flag = { 'p', '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 = 'ability_damage', func = { name = abilityDamage, params = { 'isweapon', 'tier', 'damageTier', 'damage', 'speedraw', 'slot', 'class', 'style', 'type' }, flag = 'd' } },
{ name = 'ability_damage_raw', func = { name = abilityDamage_raw, params = { 'ability_damage' }, flag = 'd' } },
{ name = 'ability_damage_disp', func = { name = abilityDamage_disp, params = { 'ability_damage' }, 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_bucket', func = { name = buckettierarg, params = { 'tier' }, flag = 'd' } },
{ name = 'style_bucket', func = { name = bucketstylearg, params = { 'style' }, flag = 'd' } },
{ name = 'damage_bucket', func = { name = bucketnumbers, params = { 'damage' }, flag = 'd' } },
{ name = 'accuracy_bucket', func = { name = bucketnumbers, params = { 'accuracy' }, flag = 'd' } },
{ name = 'armour_bucket', func = { name = bucketnumbers2, params = { 'armour' }, flag = 'd' } },
{ name = 'life_bucket', func = { name = bucketnumbers2, params = { 'life' }, flag = 'd' } },
{ name = 'prayer_bucket', func = { name = bucketnumbers2, params = { 'prayer' }, flag = 'd' } },
{ name = 'magic_bucket', func = { name = bucketnumbers, params = { 'magic' }, flag = 'd' } },
{ name = 'strength_bucket', func = { name = bucketnumbers, params = { 'strength' }, flag = 'd' } },
{ name = 'ranged_bucket', func = { name = bucketnumbers, params = { 'ranged' }, flag = 'd' } },
{ name = 'necromancy_bucket', func = { name = bucketnumbers, params = { 'necromancy' }, flag = 'd' } },
{ name = 'charges', func = { name = chargesarg, params = { 'degradetype', 'normdegrades' }, flag = 'd' } },
{ name = 'invtier', func = { name = invtierarg, params = { 'degradetype', 'invtier' }, flag = { 'd', 'p' } } },
{ name = 'bucketJSON', func = { name = bucketjsonarg, params = { 'class', 'slot', 'style_bucket', 'type', 'damage_bucket', 'accuracy_bucket', 'attackrangebucket',
'armour_bucket', 'life_bucket', 'speedraw', 'prayer_bucket', 'strength_bucket', 'ranged_bucket', 'magic_bucket', 'necromancy_bucket', 'tier_bucket', 'charges', 'invtier',
'ability_damage_raw', 'ability_damage_disp', 'requirements', 'meleeaccuracy', 'rangedaccuracy', 'magicaccuracy', 'necromancyaccuracy' }, flag = 'd' } }
}
ret:setMaxButtons(7)
ret:setAddRSWInfoboxClass(false)
ret:create()
ret:cleanParams()
ret:customButtonPlacement(true)
ret:defineLinks({ hide = true })
ret:useBucket('infobox_bonuses', {
bucketJSON = 'json',
class_bucket = 'combat_class',
slot = 'equipment_slot',
type = 'equipment_type',
damage_bucket = 'weapon_damage',
accuracy_bucket = 'weapon_accuracy',
style_bucket = 'attack_style',
attackrangebucket = 'attack_range',
armour_bucket = 'equipment_armour',
life_bucket = 'equipment_life_points',
speedraw = 'weapon_attack_speed',
prayer_bucket = 'prayer_bonus',
strength_bucket = 'strength_bonus',
ranged_bucket = 'ranged_bonus',
magic_bucket = 'magic_bonus',
necromancy_bucket = 'necromancy_bonus',
tier_bucket = 'equipment_tier',
charges = 'degradation_charges',
invtier = 'invention_tier',
isrecolour = 'is_cosmetic_recolour',
intbonus = 'has_integer_bonuses',
pvmreduction = 'pvm_damage_reduction',
pvpreduction = 'pvp_damage_reduction'
})
ret:addButtonsCaption()
ret:defineName('Infobox Bonuses')
ret:addClass('infobox-bonuses wikitable')
-- lets just really mess around with the infobox
ret.rtable:addClass('infobox-outer')
local original_rtable = ret.rtable
local maincell = ret.rtable:tag('tr'):tag('td'):addClass('infobox-grid-container')
-- panel 1 - info
ret.rtable = maincell:tag('table'):addClass('wikitable infobox-panel infobox-bonuses-panel-general')
local r1 = {{tag='th', content='Requirements', colspan=3}}
local r2 = {{tag='argd', content='requirements', colspan=3}}
if infobox.isDefined(ret:param('degradetype', 'r')) then
r1[1].colspan=2
r2[1].colspan=2
r1[2] = {tag='argh', content='degradeheader'}
r2[2] = {tag='argd', content='degradestr'}
if ret:param('degradetype', 'r') == 'invention' then
ret:append(tostring(ret:param('invdegrade_div', 'r')))
end
end
ret:addRow(r1):addRow(r2)
:addRow{ {tag='th', content='[[Combat triangle|Class]]', colspan=3} }
:addRow{ {tag='argd', content='classstr', colspan=3} }
:addRow{ {tag='th', content='Slot', colspan=3} }
:addRow{ {tag='argd', content='slotimg', colspan=3} }
if ret:paramDefined('type') then
ret:addRow{ {tag='th', content='[[Equipment tier|Tier]]', colspan=2}, {tag='th', content='Type'} }
if ret:paramDefined('damageTier') or ret:paramDefined('accuracyTier') then
ret:addRow{ {tag = 'th', content = 'Level'}, {tag = 'argd', content = 'tier'}, {tag = 'argd', content = 'type_disp', rowspan = 3} }
:addRow{ {tag = 'th', content = '[[Ability damage|Damage]]'}, {tag = 'argd', content = 'damageTier'} }
:addRow{ {tag = 'th', content = '[[Hit chance|Accuracy]]'}, {tag = 'argd', content = 'accuracyTier'} }
elseif ret:paramDefined('armourTier','all') or ret:paramDefined('armourDamageTier','all') then
ret:addRow{ {tag = 'th', content = 'Level'}, { tag = 'argd', content = 'tier'}, {tag = 'argd', content = 'type_disp', rowspan = 3} }
:addRow{ {tag = 'th', content = '[[Armour#Attributes|Armour]]'}, {tag = 'argd', content = 'armourTier'} }
:addRow{ {tag = 'th', content = '[[Armour#Damage bonus|Damage]]'}, {tag = 'argd', content = 'armourDamageTier'} }
else
ret:addRow{ {tag = 'argd', content = 'tier', colspan = 2}, {tag = 'argd', content = 'type_disp'} }
end
else
ret:addRow{ {tag='th', content='[[Equipment tier|Tier]]', colspan=3} }
if ret:paramDefined('damageTier') or ret:paramDefined('accuracyTier') then
ret:addRow{ {tag = 'th', content = 'Level'}, {tag = 'argd', content = 'tier'} }
:addRow{ {tag = 'th', content = '[[Ability damage|Damage]]'}, {tag = 'argd', content = 'damageTier'} }
:addRow{ {tag = 'th', content = '[[Hit chance|Accuracy]]'}, {tag = 'argd', content = 'accuracyTier'} }
elseif ret:paramDefined('armourTier') or ret:paramDefined('armourDamageTier') then
ret:addRow{ {tag = 'th', content = 'Level'}, { tag = 'argd', content = 'tier'} }
:addRow{ {tag = 'th', content = '[[Armour#Attributes|Armour]]'}, {tag = 'argd', content = 'armourTier'} }
:addRow{ {tag = 'th', content = '[[Armour#Damage bonus|Damage]]'}, {tag = 'argd', content = 'armourDamageTier'} }
else
ret:addRow{ {tag = 'argd', content = 'tier', colspan = 3} }
end
end
-- panel 2 - images
if ret:paramDefined('image') and ret:param('image', 'r') ~= 'no' then
ret.rtable = maincell:tag('table'):addClass('wikitable infobox-panel infobox-bonuses-panel-image')
local rimg = { {tag='argd', content='image'} }
if ret:paramDefined('altimage') then
rimg[2] = {tag='argd', content='altimage', css={width='50%'}}
end
ret:addRow(rimg)
end
-- panel 3 - offensive stats
if ret:param('hasstyle', 'r') == 'true' then
ret.rtable = maincell:tag('table'):addClass('wikitable infobox-panel infobox-bonuses-panel-offensive')
ret:addRow{ {tag='th', content='Offensive attributes', colspan=3, class='offensive-header'} }
:addRow{ {tag='th', content=' '}, {tag='th', content='<span style="display:block;" class="hover-text" title="The damage value shown in the item\'s tooltip, which is used to calculate ability damage. See link for more information."><span>[[Template:Infobox_Bonuses/FAQ#What_is_\'Tooltip\'_damage_and_\'Speed\'?|Tooltip]]</span></span>'}, {tag='th', content='[[Abilities|Ability]]'} }
:addRow{ {tag='th', content='Damage' }, {tag='argd', content='damage_disp'}, {tag='argd', content='ability_damage_disp'} }
:addRow{ {tag='th', content='[[Hit chance#Accuracy|Accuracy]]' }, {tag='argd', content='accuracy_disp', colspan=2} }
:addRow{ {tag='th', content='[[Attack types|Style]]' }, {tag='argd', content='style', colspan=2} }
:addRow{ {tag='th', content='[[Attack range|Range]]' }, {tag='argd', content='attackrange', colspan=2} }
-- Hide speed param after 2026 Combat Style Modernisation
-- As the patch notes says, it does not affect 'basic attack' speed but it still exists
if ret:param('speed', 'r') ~= 'N/A' then
ret:addRow{ {tag='th', content='<span style="display:block;" class="hover-text" title="The attack speed is only used to calculate ability damage and is not used by basic attacks, and is not visible in-game. See link for more information."><span>[[Template:Infobox_Bonuses/FAQ#What_is_\'Tooltip\'_damage_and_\'Speed\'?|Speed]]</span></span>' }, {tag='argd', content='speed', colspan=2, css = { padding = '0.2em' }} }
end
end
-- panel 4 - style stats
ret.rtable = maincell:tag('table'):addClass('wikitable infobox-panel infobox-panel-small infobox-bonuses-panel-style')
ret:addRow{ {tag='th', content='Style attributes', colspan=5, class='style-header'} }
:addRow{ {tag='th', content=' '}, {tag='th', content='[[File:Melee style bonus.png|link=Melee|21x21px]]'}, {tag='th', content='[[File:Ranged style bonus.png|link=Ranged|21x21px]]'}, {tag='th', content='[[File:Magic style bonus.png|link=Magic|21x21px]]'}, {tag='th', content='[[File:Necromancy style bonus.png|link=Necromancy|21x21px]]'} }
:addRow{ {tag='th', content='[[Damage bonus|Damage]]'}, {tag='argd', content='strengthstr'}, {tag='argd', content='rangedstr'}, {tag='argd', content='magicstr'}, {tag='argd', content='necromancystr'} }
:addRow{ {tag='th', content='[[Hit chance#Accuracy|Accuracy]]'}, {tag='argd', content='meleeaccuracystr'}, {tag='argd', content='rangedaccuracystr'}, {tag='argd', content='magicaccuracystr'}, {tag='argd', content='necromancyaccuracystr'} }
-- panel 5 - defensive stats
ret.rtable = maincell:tag('table'):addClass('wikitable infobox-panel infobox-panel-small infobox-bonuses-panel-defensive')
ret:addRow{ {tag='th', content='Defensive attributes', class='defensive-header', colspan=4} }
:addRow{ {tag='th', content='[[File:Shield icon.png|21x21px|link=Armour#Attributes]] [[Armour#Attributes|Armour]]'}, {tag='argd', content='armour'}, {tag='th', content='[[Armour#Damage_reduction|Reduction]]', colspan=2 }}
:addRow{ {tag='th', content='[[File:Tooltip Life Points.png|21x21px|link=Life points]] [[Life points|LP]]'}, {tag='argd', content='life'}, {tag='th', content='PvM'}, {tag='argd', content='pvmreductionstr'} }
:addRow{ {tag='th', content='[[File:Prayer points.png|21x21px|link=Prayer#Prayer bonus]] [[Prayer#Prayer bonus|Prayer]]'}, {tag='argd', content='prayer'}, {tag='th', content='PvP'}, {tag='argd', content='pvpreductionstr'} }
ret.rtable = original_rtable
ret.rtable:tag('tr'):tag('td'):addClass('cioCompareLinkCell cioCompareLinkCellEmpty') -- for compare
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
-- 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 'no'
end
f = f:gsub('[Ff]ile:',''):gsub('{{!}}','|')
f = mw.text.split(f, '|')[1]
if mw.title.new(f, 'File').exists == true then
return string.format('[[File:%s|%sx%spx|frameless|alt=%s: %s equipped by a player]]', f, width, height, f, mw.title.getCurrentTitle().text)
else
local g = f:gsub('%.png',''):gsub(' equipped','')
return string.format('[[File:%s|%sx%spx|frameless|alt=Missing image for %s – help by uploading one!]][[Category:Needs equipped image]]', f, width, height, g)
end
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, b, c)
if b == 'true' then
s = styles[string.lower(s or '')]
if s then
return paramtest.ucfirst(s)
end
if (c == "necromancy") then
return paramtest.ucfirst(styles.necromancy);
end
return s
end
return '-'
end
function bucketstylearg(s)
if s ~= nil and 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 classbucketarg(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 armourtierarg(t,typ,basetier)
local t = tierarg(t)
local typ = string.lower(typ)
local basetier = tierarg(basetier)
if t~=nil then
return t
elseif (typ=='tank' or typ=='tank armour') and type(basetier)=='number' then
return basetier
elseif (typ=='power' or typ=='power armour') and type(basetier)=='number' then
return basetier - 5
elseif (typ=='hybrid' or typ=='hybrid armour') and type(basetier)=='number' then
return basetier - 15
end
return nil
end
function armourdamagetierarg(t,typ,basetier)
local t = tierarg(t)
local typ = string.lower(typ)
if t~=nil then
return t
elseif (typ=='power' or typ=='power armour') and type(basetier)=='number' then
return basetier
elseif (typ=='hybrid' or typ=='hybrid armour' or typ=='tank' or typ=='tank armour') and type(basetier)=='number' then
return "''None''"
end
return nil
end
function buckettierarg(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 bucketnumbers(x)
if tonumber(x) then
return x
end
return 0
end
function bucketnumbers2(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 abilityDamage(isweapon, tier, damageTier, damage, speed, slot, class, style, weaponType)
local weaponTier = tier
if infobox.isDefined(damageTier) then
weaponTier = damageTier
end
local errVal = { nil, '-' }
local abilDamage = nil
local msg = '-'
if (isweapon == 'false' and slot ~= 'ammo') or not infobox.isDefined(weaponTier) then
return errVal
end
local function fnum(num)
return string.format('%.1f', num):gsub('%.0', '')
end
local speedMultiplier = {
average = 96/149,
fast = 192/245,
fastest = 1,
['6'] = 96/149,
['5'] = 192/245,
['4'] = 1,
['3'] = 1,
['0'] = 1
}
local slotMultiplier = {
['main hand weapon'] = 9.6,
['off-hand weapon'] = 4.8,
['2h weapon'] = 14.4,
}
if class == 'melee' or class == 'necromancy' then
if type(damage) ~= 'number' or speedMultiplier[speed] == nil then
return errVal
end
abilDamage = fnum(damage * speedMultiplier[speed])
msg = abilDamage
elseif class == 'ranged' then
if type(damage) ~= 'number' then
return errVal
end
if slot == 'ammo' then
abilDamage = fnum(damage * 1.5)
if style == 'Bolts' then
msg = string.format('<span class="hover-text" title="Assuming tier %d or higher dual wield/2h crossbow is used">%s</span>', weaponTier, abilDamage)
else
msg = string.format('<span class="hover-text" title="Assuming a tier %d or higher bow is used">%s</span>', weaponTier, abilDamage)
end
elseif weaponType == 'Chargebow' or style == 'Thrown' then
abilDamage = fnum(damage * speedMultiplier[speed])
msg = abilDamage
else
if weaponType == 'Shieldbow' then
slot = 'main hand weapon'
end
if weaponType == 'Repriser' then
weaponTier = weaponTier / 2
end
abilDamage = fnum(weaponTier * slotMultiplier[slot])
msg = string.format('<span class="hover-text" title="Assuming tier %d or higher ammunition is used">%s</span>', weaponTier, abilDamage)
end
elseif class == 'magic' then
if type(weaponTier) ~= 'number' then
return errVal
end
if slot == 'ammo' then
msg = "-"
else
if weaponType == 'Rebounder' then
weaponTier = weaponTier / 2
end
abilDamage = fnum(weaponTier * slotMultiplier[slot])
msg = string.format('<span class="hover-text" title="Assuming a tier %d or higher spell is used">%s</span>', weaponTier, fnum(abilDamage))
end
end
return { abilDamage, msg }
end
function abilityDamage_raw(t)
return t[1]
end
function abilityDamage_disp(t)
return t[2]
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 s
end
-- accuracy bonus (non-weapons)
function accuracybonusarg(mainarg, accclass, slot, class, armour)
if infobox.isDefined(mainarg) then
-- if arg set, use that unquestioned
return mainarg
end
if class == 'hybrid' or class == 'all' or class == accclass or not infobox.isDefined(armour) then
-- hybrid/all skips the calc
return 0
end
-- otherwise calc the accuracy penalty for off-style armour
-- this is 1.5x the armour value for armour of the style you are strong against (i.e., ranged armour when using melee), or non-necromancy armour when using necromancy
-- and 0.8x for the other two styles (necromancy armour or magic armour when using melee)
-- only applies to offhand + 5 main armour slots
if slot == 'off-hand' or slot == 'head' or slot == 'torso' or slot == 'legs' or slot == 'hands' or slot == 'feet' then
local mult = 0.8
if (accclass == 'necromancy') or
(accclass == 'melee' and class == 'ranged') or
(accclass == 'ranged' and class == 'magic') or
(accclass == 'magic' and class == 'melee')
then
mult = 1.5
end
local val = math.floor(armour * mult)
if val > 0 then
return -1 * val
end
end
return 0
end
function accuracybonusstrarg(arg)
local cls = 'acc-unk'
local a = tonumber(arg)
if a then
if a > 0 then
cls = 'acc-pos'
elseif a < 0 then
cls = 'acc-neg'
else
cls = 'acc-zero'
end
end
return '<span class="'..cls..'">'..arg..'</span>'
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
-- degradation
-- invention charge drain
function invdegradearg(invtier,invslot,slot)
invtier = tonumber(invtier)
local ret = nil
if invtier then
invslot = slots[invslot] or invslot
invslot = inv_slots[invslot]
if not invslot then
invslot = inv_slots[slot]
end
ret = getChargeDrainModule().get_base(invtier,invslot)
end
return ret
end
function invdegradetooltipspanarg(invtier,invslot,slot)
invtier = tonumber(invtier)
local ret = nil
if invtier then
invslot = slots[invslot] or invslot
invslot = inv_slots[invslot]
if not invslot then
invslot = inv_slots[slot]
end
ret, _ = getChargeDrainModule().get_tooltip(invtier,invslot)
ret = tostring(ret)
end
return ret
end
function invdegradetooltipdivarg(invtier,invslot,slot)
invtier = tonumber(invtier)
local ret = nil
if invtier then
invslot = slots[invslot] or invslot
invslot = inv_slots[invslot]
if not invslot then
invslot = inv_slots[slot]
end
_, ret = getChargeDrainModule().get_tooltip(invtier,invslot)
ret = tostring(ret)
end
return ret
end
-- normal degradation
function normdegradesarg(deg)
local charges = clean(deg)
if charges then
return charges
end
if yesno(deg, false) then
return 'Yes'
end
return nil
end
function degradestypearg(deg,inv)
if infobox.isDefined(inv) and infobox.isDefined(deg) then
return 'both'
end
if infobox.isDefined(inv) then
return 'invention'
end
if infobox.isDefined(deg) then
return 'normal'
end
return nil
end
-- string representation
function degradesstrarg(dtype, deg, inv, invspan)
if dtype == 'invention' then
return mw.ustring.format('%s/s %s', inv, invspan)
end
if dtype == 'normal' or dtype == 'both' then
if type(deg) == 'number' then
return commas(deg) .. ' charges'
elseif deg == true then
return 'Yes'
else
return deg
end
end
return ''
end
-- header
function degradeheaderarg(dtype)
if dtype == 'invention' then
return '[[Charge pack|Charge drain]]'
end
if dtype == 'normal' or dtype == 'both' then
return '[[Equipment degradation|Degrades]]'
end
return ''
end
--bucket
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
-- hasStyle boolean
function hasstylearg(s,t)
return (isweaponarg(s,t) == 'true' or (s == 'ammo')) and 'true' or 'false'
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 attackrangebucketarg(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
local numV = tonumber(v)
if numV and numV > maxR then
maxR = numV
end
end
if maxR > 0 then
ret = maxR
end
end
return ret
end
function reductionarg(rlr, 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 infobox.isDefined(rlr) and not reduction_type then
reduction_table = reductions.tank[s]
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 tostring(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 'N/A'
else
return tostring(attack_speed_bar(s):css("margin", "0 auto"))
end
end
return nil
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 bucket JSON
function bucketjsonarg(class, slot, style, itype, damage, accuracy, attack_range,
armour, life, speed, prayer, strength, ranged, magic, necromancy, tier,
charges, invtier, abilDmg, abilDmgNote, requirements, meleeaccuracy, rangedaccuracy, magicaccuracy, necromancyaccuracy)
local json = {
class = class,
slot = slot,
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,
necromancy = necromancy,
meleeaccuracy = meleeaccuracy,
rangedaccuracy = rangedaccuracy,
magicaccuracy = magicaccuracy,
necromancyaccuracy = necromancyaccuracy,
tier = tier,
charges = charges,
invention = invtier,
ability_damage = abilDmg,
ability_damage_note = abilDmgNote,
requirements = requirements
}
for k,v in pairs(json) do
if not infobox.isDefined(v) then
json[k] = nil
elseif type(v) == "string" then
json[k] = v:gsub(infobox.splitpoint, ", ")
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
local 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
if versions == 0 or not (param1.switches or param2.switches or param3.switches) then
table.insert(r, func(p1,p2,p3))
else
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
local 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_bucket))
-- 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_bucket))
-- 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