From Dark and Darker Wiki

(Created page with "local p = {} local AD = mw.loadJsonData("Data:Armor.json") local is_special = {["Move Speed"]=true, ["Armor Rating"]=true, ["Magical Resistance"]=true} local is_primitive = {["Strength"]=true, ["Vigor"]=true, ["Agility"]=true, ["Dexterity"]=true, ["Will"]=true, ["Knowledge"]=true, ["Resourcefulness"]=true} -- local color_rarity = {"cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", "cr8"} local function get_type(item) --Assumes that the item only has one type local key,...")
 
(Table header is made redundant and unnecessary by the tab toggles)
 
(12 intermediate revisions by the same user not shown)
Line 1: Line 1:
local p = {}
local p = {}
local AD = mw.loadJsonData("Data:Armor.json")
local AD = mw.loadJsonData("Data:Armor.json")
local insert = table.insert
local concat = table.concat
local is_special = {["Move Speed"]=true, ["Armor Rating"]=true, ["Magical Resistance"]=true}
local is_special = {["Move Speed"]=true, ["Armor Rating"]=true, ["Magical Resistance"]=true}
local is_primitive = {["Strength"]=true, ["Vigor"]=true, ["Agility"]=true, ["Dexterity"]=true, ["Will"]=true, ["Knowledge"]=true, ["Resourcefulness"]=true}
local is_primitive = {["Strength"]=true, ["Vigor"]=true, ["Agility"]=true, ["Dexterity"]=true, ["Will"]=true, ["Knowledge"]=true, ["Resourcefulness"]=true}
-- local color_rarity = {"cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", "cr8"}




---Get the type of the armor as a string
--- @param item table
--- @return string
local function get_type(item)
local function get_type(item)
--Assumes that the item only has one type
--Assumes that the item only has one type
local key,_ = next(item.types)
for key,_ in pairs(item.types) do
return key or ""
--Scribunto uses meta tables so we can't use next() here
return key
end
return ""
end
end




---Get the size of the armor in pixels
--- @param item table
--- @return string
local function size(item)
local function size(item)
return tostring(item.invwidth*45).."x"..tostring(item.invheight*45).."px"
return tostring(item.invwidth*45).."x"..tostring(item.invheight*45).."px"
end
---Counts number of keys. Tables from Misc.json don't work with next() or the # operator
--- @param t table
--- @return number
local function count(t)
local c = 0
for _ in pairs(t) do c = c + 1 end
return c
end
end


Line 22: Line 42:
---@return string
---@return string
local function iconbox(item)
local function iconbox(item)
local wikitext = "<div class='iconbox' style='display:inline-flex;width:max-content;max-width:initial;flex-direction:column;align-items:center;flex-wrap:wrap;white-space:pre-wrap'>"
local color = "2"
local image = "[[File:"..item.name..".png|"..size(item).."|link="..item.name.."]]"
local amount = "<span class='iconamount' style='pointer-events:none;color:#EEEA;font-size:16px'>"..get_type(item).."</span>"
local caption = "[["..item.name
local caption = "[["..item.name
local color = "2"
if count(item.rarities) == 1 then
if #item.rarities == 1 then
color = item.rarities[1]
color = item.rarities[1]
caption = caption.."|<b class=cr"..color..">"..item.name.."</b>"
caption = caption.."|<b class=cr"..color..">"..item.name.."</b>"
end
end
image = "<div class='rarity-"..color.." rounded relative'>"..image..amount.."</div>"
return "<div class='iconbox' style='display:inline-flex;width:max-content;max-width:initial;flex-direction:column;align-items:center;flex-wrap:wrap;white-space:pre-wrap'>"
return wikitext..image..caption.."]]</div>"
.."<div class='rarity"..color.." rounded relative'>"
.."[[File:"..item.name..".png|"..size(item).."|link="..item.name.."]]"
.."<span class='iconamount' style='pointer-events:none;color:#EEEA;font-size:16px'>"..get_type(item).."</span></div>"
..caption.."]]</div>"
end


---Turns a list of classes into a wikitext string with line break separators
--- @param list table
--- @return string
local function classes(list)
local wikitext = "" --classes are few enough that we can just concatenate them without worrying about performance
local newline = ""
for i, class in ipairs(list) do
wikitext = wikitext..newline..class
if i == 1 then newline = "<br>" end
end
return wikitext
end
end




local function color_values(values)
---Marks up a list of values with color based on rarity
if type(values)=="string" then return values end
---@param values string|table
---@param armor table
---@return string
local function color_values(values,armor)
if values == nil then return "" end
if type(values)=="string" then
if count(armor.rarities) == 1 then return "<span class='cr"..armor.rarities[1].."'>"..values.."</span>" end
return values
end


--TODO this assumes i is the same as the color rating, this may result in a bug
--TODO this assumes i is the same as the color rating, this may result in a bug
Line 47: Line 88:
if i == 1 then newline = "<br>" end
if i == 1 then newline = "<br>" end
end
end
return wikitext
return wikitext
end
end




local function inline_block(stat, values)
---Marks up a stat block with the stat name and colored values and appropriate margins and alignment
if values == nil then return "" end
--- @param stat string
return "<div style='display:inline-block; margin:0 15px 0 15px'><b style='color:#eee8'>"..stat..":</b><br>"..color_values(values).."</div>"
--- @param armor table
--- @return string
local function inline_block(stat, armor)
if armor.stats[(stat):lower()] == nil then return "" end
return "<div style='display:inline-block;vertical-align:top;margin:0 15px 0 15px'><b style='color:#eee8'>"..stat.."</b><br>"..color_values(armor.stats[(stat):lower()],armor).."</div>"
end
end


Line 62: Line 106:
--- @return string
--- @return string
local function row(armor)
local function row(armor)
local wikitext = "<tr><td>"
local wikitext = {}
..iconbox(armor)
insert(wikitext,"<tr><td>")
.."</td><td>"
insert(wikitext,iconbox(armor))
insert(wikitext,"</td><td>")


if armor.slottype ~= "Back" then
if armor.slottype ~= "Back" then
wikitext = wikitext
insert(wikitext,classes(armor.classes))
.."[["
insert(wikitext,"</td><td>")
..table.concat(armor.classes,"]]<br>[[")
insert(wikitext,color_values(armor.stats["move speed"],armor))
.."]]</td><td>"
insert(wikitext,"</td><td>")
..color_values(armor.stats["move speed"])
-- elseif armor.stats["move speed"] then
.."</td><td>"
-- insert(wikitext,"<span style='color:red;'>Error: Back "..armor.name.." has unpresented move speed.</span>")
-- elseif next(armor.classes) then
-- insert(wikitext,"<span style='color:red;'>Error: Back "..armor.name.." has unpresented class requirements.</span>")
end
end


wikitext = wikitext
insert(wikitext,inline_block("Armor Rating",armor))
..inline_block("Armor Rating", armor.stats["armor rating"])
insert(wikitext,inline_block("Magical Resistance",armor))
..inline_block("Magical Resistance", armor.stats["magical resistance"])
insert(wikitext,"</td><td>")
.."</td><td>"


-- create the table data cell for attributes
-- create the table data cell for attributes
for _,stat in ipairs(armor.stats.order) do
for _,stat in ipairs(armor.stats.order) do
if is_primitive[stat] then
if is_primitive[stat] then
wikitext = wikitext..inline_block(stat, armor.stats[(stat):lower()])
insert(wikitext,inline_block(stat,armor))
end
end
end
end
wikitext = wikitext.."</td><td>"
insert(wikitext,"</td><td>")


-- create the table data cell for the rest of the stats
-- create the table data cell for the rest of the stats
for _, stat in ipairs(armor.stats.order) do
for _, stat in ipairs(armor.stats.order) do
if not is_primitive[stat] and not is_special[stat] then
if not is_primitive[stat] and not is_special[stat] then
wikitext = wikitext..inline_block(stat, armor.stats[(stat):lower()])
insert(wikitext,inline_block(stat,armor))
end
end
end
end
return wikitext.."</td></tr>"
insert(wikitext,"</td></tr>")
return concat(wikitext)
end
end


Line 101: Line 148:
--- @param frame table
--- @param frame table
--- @return table - strings
--- @return table - strings
local function get_armor_list(frame)
local function get_list(frame)
--TODO add minor string validation and correction, e.g. "DeMoN" -> "demon"  ("DeMoN"):lower()
--TODO add minor string validation and correction, e.g. "DeMoN" -> "demon"  ("DeMoN"):lower()
return AD[frame.args[1] or ""] or {}
return AD[frame.args[1]][frame.args[2]] or {}
end
end


Line 111: Line 158:
--- @return string
--- @return string
local function table_header(frame)
local function table_header(frame)
local wikitext = [=[<tr><th style="width:5%">Name</th>]=]
local wikitext = [=[<table cellspacing="0" class="wikitable sortable jquery-tablesorter" style="width:95%;color:#eee;background:transparent;text-align:center;vertical-align:middle;"><tr><th style="width:5%">Name</th>]=]
 
if (frame.args[1] or ""):lower() ~= "back" then
if (frame.args[1] or ""):lower() ~= "back" then
wikitext = wikitext..[=[<th style="width:5%">Class Requirements</th><th style="width:5%">Movement Speed</th>]=]
wikitext = wikitext..[=[<th style="width:5%">Class Requirements</th><th style="width:5%">Movement Speed</th>]=]
end
end
return wikitext..[=[<th style="width:10%">Armor/magical Rating</th><th style="width:10%">Attributes</th><th style="width:25%">Other</th></tr>]=]
return wikitext..[=[<th style="width:10%">Armor/magical Rating</th><th style="width:10%">Attributes</th><th style="width:25%">Other</th></tr>]=]
end
end


---Create monster table wikitext
---Create monster table wikitext
---- Test on wiki with: mw.log(p.draw_table({args={"bosses"}})) or mw.log(p.draw_table({args={"Demon","true"}}))
--- @param frame table
--- @param frame table
--- @return string
--- @return string
Line 127: Line 171:
if not AD then return "<span style='color:red;'>Error: Could not load Armor data in [[Module:Armor]]</span>" end
if not AD then return "<span style='color:red;'>Error: Could not load Armor data in [[Module:Armor]]</span>" end


local wikitext = table_header(frame) or "<table class='wikitable sortable'>"
local wikitext = {}
insert(wikitext, table_header(frame))
for _, key in ipairs(get_list(frame)) do
insert(wikitext, row(AD.Armor[key]))
end
insert(wikitext, "</table>")
return concat(wikitext)
end
 
 
--[=[
################################################################################
                        Functions for individual armor pages
################################################################################
]=]
 
local function tab_toggle(title,content,active,tabid)
local class = ""
if active then
class = " class='selected-tab tab-toggle tab'"
else
class = " class='tab-toggle tab'"
end
return string.format("<div style='display:inline-block' %s data-tabid='%s' data-tab='%s' title='%s'>%s</div>",class,tabid,title,title,content)
end
 
local function reference_table(wt,table_type)
local types_order = {"Head","Chest","Legs","Hands","Foot","Back"}
local separator = "]] • [["
 
wt[#wt+1] = "<table cellspacing='0' class='wikitable sortable jquery-tablesorter' style='width:100%;text-align:center;vertical-align:middle;margin-top:15px'>"
 
for _,armor_type in ipairs(types_order) do
wt[#wt+1] = string.format("<tr><td style='font-weight:bold; background-color:rgb(220,220,220,0.2); width:10%%'>[[Armors#%s|%s]]</td><td style='text-align-last:left;padding:10px 25px'>",armor_type,armor_type)
if AD[armor_type][table_type] then
wt[#wt+1] = "[["
for i,v in ipairs(AD[armor_type][table_type]) do
if i~=1 then wt[#wt+1] = separator end
wt[#wt+1] = v
end
wt[#wt+1] = "]]"
end
wt[#wt+1] = "</td></tr>"
end
wt[#wt+1] = "</table>"
end
 
function p.references()
local table_types = {"Uncraftable","Craftable"}


for _, key in ipairs(get_armor_list(frame)) do
local wt = {}
wikitext = wikitext..row(AD.armor[key])
wt[#wt+1] = "<br><h2>References</h2>"
wt[#wt+1] = "<div style='display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;margin-top:15px'>"
for i,table_type in ipairs(table_types) do
wt[#wt+1] = tab_toggle(table_type,table_type.." Armors",i==1,"")
end
wt[#wt+1] = "</div>"
for i,table_type in ipairs(table_types) do
wt[#wt+1] = "<div class='"..table_type.."-data'"
if i==1 then wt[#wt+1] = ">" else wt[#wt+1] = "style='display:none'>" end
reference_table(wt,table_type)
wt[#wt+1] = "</div>"
end
end


return wikitext.."</table>"
return concat(wt)
end
end




return p
return p
-- Test on wiki with
-- mw.log(p.draw_table({args={"Back","Craftable"}}))
-- mw.log(p.draw_table({args={"Head","Uncraftable"}}))
-- mw.log(p.references())

Latest revision as of 07:31, 13 April 2026

Overview

Functions for making Armor table. Data comes from Data:Armor.json.

Functions

draw_table

Creates a table of armors

Parameters

  • 1 - <Slot Type>
  • 2 - Craftable or Uncraftable


draw_table examples

Back


{{#invoke:Armor|draw_table|Back|Craftable}}


NameArmor/magical RatingAttributesOther
Armor Rating
11
Will
2
Spell Casting Speed
3%
Armor Rating
10
Agility
3
Action Speed
1%
Armor Rating
15
Dexterity
3
Vigor
3
Will
3
Resourcefulness
3
Luck
40
All Attributes
3
Armor Rating
13
Knowledge
3
Armor Penetration
3.5%
Magical Penetration
3.5%
Armor Rating
19
Strength
3
Dexterity
3
Will
3
Armor Rating
8
Vigor
3
Debuff Duration Bonus
2%


Head


{{#invoke:Armor|draw_table|Head|Uncraftable}}


NameClass RequirementsMovement SpeedArmor/magical RatingAttributesOther
Wizard
Warlock
Druid
Sorcerer
-5
Armor Rating
4
4
5
6
6
7
8
Magical Resistance
20
25
31
37
41
49
54
Headshot Damage Reduction
6%
Spell Casting Speed
1.5%
Armet.pngPlate
Armet
Fighter-12
Armor Rating
25~27
28~31
31~33
33~35
34~36
37~39
39~42
Headshot Damage Reduction
18%
Projectile Damage Reduction
7%
Physical Damage Reduction
1.5%
Fighter
Barbarian
-10
Armor Rating
20~21
22~23
23~24
25~26
27~28
29~30
30~31
Magical Resistance
10
Headshot Damage Reduction
12%
Projectile Damage Reduction
4%
Physical Power
2
Warlock-7
Armor Rating
18
20
21
23
26
27
28
Headshot Damage Reduction
9%
Projectile Damage Reduction
5.5%
Undead Race Damage Bonus
2%
Ranger-5
Armor Rating
6
6
7
8
9
10
11
Headshot Damage Reduction
6%
Headshot Damage Modifier
2%
Cleric
Sorcerer
-5
Armor Rating
6
6
6
8
8~9
9
11
Magical Resistance
16
20
25
29
33
39
43
Headshot Damage Reduction
6%
Cooldown Reduction Bonus
2%
Fighter
Cleric
-8
Armor Rating
16~17
18~19
20~21
21~22
23~24
24~25
26
Magical Resistance
10
Headshot Damage Reduction
10%
Projectile Damage Reduction
2%
Physical Power Bonus
1.5%
Cleric
Sorcerer
-5
Armor Rating
4
4
5
5
6
7
8
Magical Resistance
16
20
25
29
33
39
43
Headshot Damage Reduction
5%
Magical Damage Reduction
1.5%
Coif.pngCloth
Coif
Wizard
Cleric
Druid
Sorcerer
-2
Armor Rating
5
5
6
6~7
7~8
8
10
Headshot Damage Reduction
6%
Memory Capacity Add
3
Fighter
Cleric
-17
Armor Rating
23
25
27
28
30
33
34
Headshot Damage Reduction
15%
Projectile Damage Reduction
5.5%
Demon Race Damage Reduction
2%
Druid-5
Armor Rating
11
13
15
15
18~19
20
21
Headshot Damage Reduction
7%
Cooldown Reduction Bonus
2%
Dryad Mask.pngLeather
Dryad Mask
Warlock
Druid
-5
Armor Rating
11
13
16
15~16
19~20
21
22
Headshot Damage Reduction
8%
Physical Power Bonus
1.5%
Druid-7
Armor Rating
12
14
16~18
17~18
20~21
22
25
Headshot Damage Reduction
8%
Undead Race Damage Bonus
2%
Bard-5
Armor Rating
11
13
16
16~17
20
21
22
Headshot Damage Reduction
7%
Buff Duration Bonus
1.5%
Ranger
Druid
-7
Armor Rating
6
6
7
8
9
10
12
Magical Resistance
14
18
21
26
29
34
38
Headshot Damage Reduction
6%
Magical Interaction Speed
1.5%
Barbarian-10
Armor Rating
20~21
22~24
25~26
27~28
28~30
31~32
32~33
Magical Resistance
8
9
10
11
12
13
15
Headshot Damage Reduction
12%
Projectile Damage Reduction
4%
Max Health Add
2
Fighter
Cleric
-17
Armor Rating
23
26
28
29
31
34
34
Headshot Damage Reduction
16%
Projectile Damage Reduction
6.5%
Max Health Bonus
1%
Fighter
Cleric
-17
Armor Rating
25
27
28
30
32
35
35
Magical Resistance
-5
Headshot Damage Reduction
17%
Projectile Damage Reduction
6.5%
Max Health Add
2
Rogue
Bard
-5
Armor Rating
6
6
7
8
9
10
11
Headshot Damage Reduction
6%
Headshot Damage Modifier
2%
Fighter
Cleric
-8
Armor Rating
16~17
18~19
20~21
21~22
23~24
24~25
26
Magical Resistance
10
Headshot Damage Reduction
10%
Projectile Damage Reduction
2%
Luck
15
Bard-5
Armor Rating
11
13
16
16~17
20
22
22
Headshot Damage Reduction
8%
Luck
15
-5
Armor Rating
12
14
16~18
19~20
20~21
22~23
23~25
Headshot Damage Reduction
7%
Outgoing Physical Healing Add
1
Mitre.pngLeather
Mitre
Cleric-5
Armor Rating
11
13
16
16
20
21
22
Headshot Damage Reduction
8%
Undead Race Damage Bonus
2%
Barbarian-7
Armor Rating
19
21
22
24
27
28
30
Headshot Damage Reduction
9%
Projectile Damage Reduction
2.5%
Action Speed
0.5%
Warlock-5
Armor Rating
6
6
7
8
9
10
12
Headshot Damage Reduction
6%
Outgoing Magical Healing Add
1
Fighter
Ranger
Cleric
Bard
-7
Armor Rating
18
21
22
23
26
28
29
Headshot Damage Reduction
10%
Projectile Damage Reduction
2.5%
Undead Race Damage Reduction
2%
Ranger-5
Armor Rating
8
8
9
9~10
11~12
12~13
15
Headshot Damage Reduction
4%
Action Speed
0.5%
Cleric-5
Armor Rating
11
13
16
16
20
21
22
Headshot Damage Reduction
8%
Demon Race Damage Bonus
2%
Rogue-5
Armor Rating
6
7
7~8
8~9
10~11
11~12
13~14
Headshot Damage Reduction
4%
Item Swap Speed
1.5%
Sallet.pngPlate
Sallet
Fighter
Cleric
-7
Armor Rating
18
20
21
23
26
27
28
Headshot Damage Reduction
9%
Projectile Damage Reduction
2.5%
Magical Damage Reduction
1.5%
Rogue
Warlock
-5
Armor Rating
5
6
6
7~8
8
9
10
Magical Resistance
14
18
21
26
29
34
38
Headshot Damage Reduction
6%
Debuff Duration Bonus
1.5%
Rogue
Warlock
-2
Armor Rating
3
3
4
5
5
6
8
Action Speed
0.5%
Fighter
Ranger
Cleric
-10
Armor Rating
19
22
23
25
27
29
30
Headshot Damage Reduction
10%
Projectile Damage Reduction
3.5%
Armor Penetration
2%
Rogue
Bard
-5
Armor Rating
6
6
6
8
8
9
11
Headshot Damage Reduction
6%
Buff Duration Bonus
1.5%
Bard
Druid
-5
Armor Rating
6
6
7
8
9
10
12
Headshot Damage Reduction
6%
Regular Interaction Speed
1.5%
Fighter
Cleric
-17
Armor Rating
24
26
28
29
32
34
35
Headshot Damage Reduction
16%
Projectile Damage Reduction
6.5%
Cooldown Reduction Bonus
2%
Ranger
Barbarian
-7
Armor Rating
12
15
18
17
21
22
23
Headshot Damage Reduction
8%
Headshot Damage Modifier
2%
Barbarian-11
Armor Rating
22~23
25~26
27~28
29~30
30~32
33~34
34~35
Headshot Damage Reduction
12%
Projectile Damage Reduction
4%
Physical Power Bonus
1.5%
Fighter-10
Armor Rating
20~21
22~23
23~24
25~26
27~28
29~30
30~31
Headshot Damage Reduction
13%
Action Speed
0.5%
Projectile Damage Reduction
6%
Barbarian-12
Armor Rating
22
25
26
28
30
32
33
Headshot Damage Reduction
11%
Projectile Damage Reduction
6.5%
Max Health Bonus
1%
Wizard
Warlock
-5
Armor Rating
4
5
5
6
7
8
9
Headshot Damage Reduction
2.5%
Magical Power
2
-5
Armor Rating
5
6
6
8
8
9
10
Headshot Damage Reduction
4%
Max Health Add
2

local p = {}
local AD = mw.loadJsonData("Data:Armor.json")
local insert = table.insert
local concat = table.concat
local is_special = {["Move Speed"]=true, ["Armor Rating"]=true, ["Magical Resistance"]=true}
local is_primitive = {["Strength"]=true, ["Vigor"]=true, ["Agility"]=true, ["Dexterity"]=true, ["Will"]=true, ["Knowledge"]=true, ["Resourcefulness"]=true}


---Get the type of the armor as a string
--- @param item table
--- @return string
local function get_type(item)
	--Assumes that the item only has one type
	for key,_ in pairs(item.types) do
		--Scribunto uses meta tables so we can't use next() here
		return key
	end
	return ""
end


---Get the size of the armor in pixels
--- @param item table
--- @return string
local function size(item)
	return tostring(item.invwidth*45).."x"..tostring(item.invheight*45).."px"
end


---Counts number of keys. Tables from Misc.json don't work with next() or the # operator
--- @param t table
--- @return number
local function count(t)
	local c = 0
	for _ in pairs(t) do c = c + 1 end
	return c
end


---Create css/html wikitext for iconbox
---@param item table
---@return string
local function iconbox(item)
	local color = "2"
	local caption = "[["..item.name
	if count(item.rarities) == 1 then
		color = item.rarities[1]
		caption = caption.."|<b class=cr"..color..">"..item.name.."</b>"
	end
	return "<div class='iconbox' style='display:inline-flex;width:max-content;max-width:initial;flex-direction:column;align-items:center;flex-wrap:wrap;white-space:pre-wrap'>"
		.."<div class='rarity"..color.." rounded relative'>"
		.."[[File:"..item.name..".png|"..size(item).."|link="..item.name.."]]"
		.."<span class='iconamount' style='pointer-events:none;color:#EEEA;font-size:16px'>"..get_type(item).."</span></div>"
		..caption.."]]</div>"
end


---Turns a list of classes into a wikitext string with line break separators
--- @param list table
--- @return string
local function classes(list)
	local wikitext = "" --classes are few enough that we can just concatenate them without worrying about performance
	local newline = ""
	for i, class in ipairs(list) do
		wikitext = wikitext..newline..class
		if i == 1 then newline = "<br>" end
	end
	return wikitext
end


---Marks up a list of values with color based on rarity
---@param values string|table
---@param armor table
---@return string
local function color_values(values,armor)
	if values == nil then return "" end
	if type(values)=="string" then
		if count(armor.rarities) == 1 then return "<span class='cr"..armor.rarities[1].."'>"..values.."</span>" end
		return values
	end

	--TODO this assumes i is the same as the color rating, this may result in a bug
	local wikitext = ""
	local newline = ""
	for i, value in ipairs(values) do
		wikitext = wikitext..newline.."<span class='cr"..i.."'>"..value.."</span>"
		if i == 1 then newline = "<br>" end
	end
	return wikitext
end


---Marks up a stat block with the stat name and colored values and appropriate margins and alignment
--- @param stat string
--- @param armor table
--- @return string
local function inline_block(stat, armor)
	if armor.stats[(stat):lower()] == nil then return "" end
	return "<div style='display:inline-block;vertical-align:top;margin:0 15px 0 15px'><b style='color:#eee8'>"..stat.."</b><br>"..color_values(armor.stats[(stat):lower()],armor).."</div>"
end


---Return a table row of data cells containing armor information
--- @param armor table
--- @return string
local function row(armor)
	local wikitext = {}
	insert(wikitext,"<tr><td>")
	insert(wikitext,iconbox(armor))
	insert(wikitext,"</td><td>")

	if armor.slottype ~= "Back" then
		insert(wikitext,classes(armor.classes))
		insert(wikitext,"</td><td>")
		insert(wikitext,color_values(armor.stats["move speed"],armor))
		insert(wikitext,"</td><td>")
	-- elseif armor.stats["move speed"] then
	-- 	insert(wikitext,"<span style='color:red;'>Error: Back "..armor.name.." has unpresented move speed.</span>")
	-- elseif next(armor.classes) then
	-- 	insert(wikitext,"<span style='color:red;'>Error: Back "..armor.name.." has unpresented class requirements.</span>")
	end

	insert(wikitext,inline_block("Armor Rating",armor))
	insert(wikitext,inline_block("Magical Resistance",armor))
	insert(wikitext,"</td><td>")

	-- create the table data cell for attributes
	for _,stat in ipairs(armor.stats.order) do
		if is_primitive[stat] then
			insert(wikitext,inline_block(stat,armor))
		end
	end
	insert(wikitext,"</td><td>")

	-- create the table data cell for the rest of the stats
	for _, stat in ipairs(armor.stats.order) do
		if not is_primitive[stat] and not is_special[stat] then
			insert(wikitext,inline_block(stat,armor))
		end
	end
	insert(wikitext,"</td></tr>")
	return concat(wikitext)
end


--- Return a list of armor keys to be used in the table
--- @param frame table
--- @return table - strings
local function get_list(frame)
	--TODO add minor string validation and correction, e.g. "DeMoN" -> "demon"  ("DeMoN"):lower()
	return AD[frame.args[1]][frame.args[2]] or {}
end


--- Return a table row of appropriate headers cells
--- @param frame table
--- @return string
local function table_header(frame)
	local wikitext = [=[<table cellspacing="0" class="wikitable sortable jquery-tablesorter" style="width:95%;color:#eee;background:transparent;text-align:center;vertical-align:middle;"><tr><th style="width:5%">Name</th>]=]
	if (frame.args[1] or ""):lower() ~= "back" then
		wikitext = wikitext..[=[<th style="width:5%">Class Requirements</th><th style="width:5%">Movement Speed</th>]=]
	end
	return wikitext..[=[<th style="width:10%">Armor/magical Rating</th><th style="width:10%">Attributes</th><th style="width:25%">Other</th></tr>]=]
end

---Create monster table wikitext
--- @param frame table
--- @return string
function p.draw_table(frame)
	if not AD then return "<span style='color:red;'>Error: Could not load Armor data in [[Module:Armor]]</span>" end

	local wikitext = {}
	insert(wikitext, table_header(frame))
	for _, key in ipairs(get_list(frame)) do
		insert(wikitext, row(AD.Armor[key]))
	end
	insert(wikitext, "</table>")
	return concat(wikitext)
end


--[=[
################################################################################
                        Functions for individual armor pages
################################################################################
]=]

local function tab_toggle(title,content,active,tabid)
	local class = ""
	if active then
		class = " class='selected-tab tab-toggle tab'"
	else
		class = " class='tab-toggle tab'"
	end
	return string.format("<div style='display:inline-block' %s data-tabid='%s' data-tab='%s' title='%s'>%s</div>",class,tabid,title,title,content)
end

local function reference_table(wt,table_type)
	local types_order = {"Head","Chest","Legs","Hands","Foot","Back"}
	local separator = "]] • [["

	wt[#wt+1] = "<table cellspacing='0' class='wikitable sortable jquery-tablesorter' style='width:100%;text-align:center;vertical-align:middle;margin-top:15px'>"

	for _,armor_type in ipairs(types_order) do
		wt[#wt+1] = string.format("<tr><td style='font-weight:bold; background-color:rgb(220,220,220,0.2); width:10%%'>[[Armors#%s|%s]]</td><td style='text-align-last:left;padding:10px 25px'>",armor_type,armor_type)
		if AD[armor_type][table_type] then
			wt[#wt+1] = "[["
			for i,v in ipairs(AD[armor_type][table_type]) do
				if i~=1 then wt[#wt+1] = separator end
				wt[#wt+1] = v
			end
			wt[#wt+1] = "]]"
		end
		wt[#wt+1] = "</td></tr>"
	end
	wt[#wt+1] = "</table>"
end

function p.references()
	local table_types = {"Uncraftable","Craftable"}

	local wt = {}
	wt[#wt+1] = "<br><h2>References</h2>"
	wt[#wt+1] = "<div style='display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;margin-top:15px'>"
	for i,table_type in ipairs(table_types) do
		wt[#wt+1] = tab_toggle(table_type,table_type.." Armors",i==1,"")
	end
	wt[#wt+1] = "</div>"
	for i,table_type in ipairs(table_types) do
		wt[#wt+1] = "<div class='"..table_type.."-data'"
		if i==1 then wt[#wt+1] = ">" else wt[#wt+1] = "style='display:none'>" end
		reference_table(wt,table_type)
		wt[#wt+1] = "</div>"
	end

	return concat(wt)
end



return p



-- Test on wiki with
-- mw.log(p.draw_table({args={"Back","Craftable"}}))
-- mw.log(p.draw_table({args={"Head","Uncraftable"}}))

-- mw.log(p.references())