From Dark and Darker Wiki

m (Testing)
Tag: Reverted
(Changing to table.concat for large strings and for loops.)
 
(3 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_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
local wikitext = {}
insert(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'>")
insert(wikitext,"<div class='rarity"..color.." rounded relative'>")
insert(wikitext,"[[File:"..item.name..".png|"..size(item).."|link="..item.name.."]]")
insert(wikitext,"<span class='iconamount' style='pointer-events:none;color:#EEEA;font-size:16px'>"..get_type(item).."</span></div>")
insert(wikitext,caption.."]]</div>")
return concat(wikitext)
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
insert(wikitext,newline.."<span class='cr"..i.."'>"..value.."</span>")
if i == 1 then newline = "<br>" end
end
return concat(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 = {}
insert(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
insert(wikitext,[=[<th style="width:5%">Class Requirements</th><th style="width:5%">Movement Speed</th>]=])
end
insert(wikitext,[=[<th style="width:10%">Armor/magical Rating</th><th style="width:10%">Attributes</th><th style="width:25%">Other</th></tr>]=])
return concat(wikitext)
end
---Create monster table wikitext
---- Test on wiki with:  mw.log(p.draw_table({args={"Back","Craftable"}}))
----                    mw.log(p.draw_table({args={"Head","Uncraftable"}}))
--- @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


return p
return p

Latest revision as of 22:51, 2 March 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
1
Vigor
1
Will
1
Resourcefulness
1
Luck
40
All Attributes
1
Armor Rating
19
Strength
2
Dexterity
2
Will
2
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
-2
Armor Rating
21
22
23
24~25
26~27
28
29
Will
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Armet.pngPlate
Armet
Fighter-5
Armor Rating
54
55
56~57
58~59
60~61
62
63
Strength
1
2
2
3
4
5
5
Projectile Damage Reduction
2.1%
Headshot Damage Reduction
18%
Fighter
Barbarian
-4
Armor Rating
26
27
28~29
30~31
32~33
34
35
Magical Resistance
30
Dexterity
1
2
2
3
4
5
5
Projectile Damage Reduction
1.2%
Headshot Damage Reduction
15%
Warlock-3
Armor Rating
33
34
35~36
37~38
39~40
41
42
Will
1
1
1
2
2
3
3
Projectile Damage Reduction
1.8%
Headshot Damage Reduction
15%
Headshot Damage Modifier
2.5%
3%
3%
3%
3.5%
3.5%
4%
Ranger-2
Armor Rating
24
25
26
27
28
29
30
Dexterity
1
1
1
2
2
3
3
Headshot Damage Reduction
8%
Headshot Damage Modifier
2.5%
3%
3%
3%
3.5%
3.5%
4%
Cleric
Sorcerer
-2
Armor Rating
21
22
23
24~25
26~27
28
29
Magical Resistance
20
Resourcefulness
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Fighter
Cleric
-3
Armor Rating
39
40
41~42
43~44
45~46
47
48
Magical Resistance
10
Agility
1
2
2
3
4
5
5
Projectile Damage Reduction
0.6%
Headshot Damage Reduction
13%
Cleric
Sorcerer
-2
Armor Rating
23
24
25
26~27
28~29
30
31
Magical Resistance
20
Will
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Coif.pngCloth
Coif
Wizard
Cleric
Druid
Sorcerer
-1
Armor Rating
17
18
19
20~21
22~23
24
25
Knowledge
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Fighter
Cleric
-5
Armor Rating
52
53
54~55
56~57
58~59
60
61
Strength
1
1
1
2
2
3
3
Vigor
1
1
1
2
2
2
Projectile Damage Reduction
1.8%
Headshot Damage Reduction
18%
Druid-2
Armor Rating
24
25
26
27~28
29~30
31
32
Strength
1
1
1
2
2
3
3
Will
1
1
1
2
2
2
Headshot Damage Reduction
8%
Warlock
Druid
-2
Armor Rating
26
27
28
29~30
31~32
33
34
Strength
1
1
1
2
2
2
2
Knowledge
1
1
1
1
2
2
2
Agility
1
1
1
1
2
2
Headshot Damage Reduction
10%
Druid-3
Armor Rating
31
32
33~34
35~36
37~38
39
40
Vigor
1
1
1
2
2
3
3
Dexterity
1
1
1
2
2
2
Headshot Damage Reduction
11%
Bard-2
Armor Rating
28
29
30
31~32
33~34
35
36
Knowledge
1
2
2
3
4
5
5
Headshot Damage Reduction
9%
Ranger
Druid
-2
Armor Rating
25
26
27
28~29
30~31
32
33
Magical Resistance
15
Strength
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Barbarian-4
Armor Rating
41
42
43~44
45~46
47~48
49
50
Magical Resistance
15
Vigor
1
2
2
3
4
5
5
Projectile Damage Reduction
1.2%
Headshot Damage Reduction
15%
Fighter
Cleric
-5
Armor Rating
55
56
57~58
59~60
61~62
63
64
Knowledge
1
2
2
3
4
5
5
Projectile Damage Reduction
2.1%
Headshot Damage Reduction
23%
Fighter
Cleric
-5
Armor Rating
58
59
60~61
62~63
64~65
66
67
Magical Resistance
-10
Vigor
1
2
2
3
4
5
5
Projectile Damage Reduction
2.1%
Headshot Damage Reduction
23%
Rogue
Bard
-2
Armor Rating
24
25
26
27
28
29
30
Dexterity
1
1
1
2
2
3
3
Headshot Damage Reduction
8%
Headshot Damage Modifier
2.5%
3%
3%
3%
3.5%
3.5%
4%
Fighter
Cleric
-3
Armor Rating
36
37
38~39
40~41
42~43
44
45
Magical Resistance
10
Knowledge
1
2
2
3
4
5
5
Projectile Damage Reduction
0.6%
Headshot Damage Reduction
13%
Bard-2
Armor Rating
29
30
31
32~33
34~35
36
37
Resourcefulness
1
2
2
3
4
5
5
Headshot Damage Reduction
10%
-3
Armor Rating
31
32
33~34
35~36
37~38
39
40
Vigor
1
2
2
3
4
5
5
Headshot Damage Reduction
11%
Cleric-2
Armor Rating
28
29
30
31
32
33
34
Will
1
1
1
2
2
3
3
Headshot Damage Reduction
11%
Undead Race Damage Bonus
5%
6%
6%
6%
7%
7%
8%
Barbarian-3
Armor Rating
37
38
39~40
41~42
43~44
45
46
Vigor
1
1
1
2
2
3
3
Strength
1
1
1
2
2
2
Projectile Damage Reduction
0.9%
Headshot Damage Reduction
13%
Warlock-2
Armor Rating
25
26
27
28~29
30~31
32
33
Headshot Damage Reduction
8%
Outgoing Magical Healing Add
1
1
1
2
2
3
3
Magical Power
1
1
1
2
2
2
Fighter
Ranger
Cleric
Bard
-3
Armor Rating
35
36
37~38
39~40
41~42
43
44
Will
1
1
1
2
2
2
2
Knowledge
1
1
1
1
2
2
2
Resourcefulness
1
1
1
1
2
2
Projectile Damage Reduction
0.9%
Headshot Damage Reduction
14%
Ranger-2
Armor Rating
25
26
27
28~29
30~31
32
33
Agility
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Cleric-2
Armor Rating
28
29
30
31
32
33
34
Will
1
1
1
2
2
3
3
Headshot Damage Reduction
11%
Demon Race Damage Bonus
5%
6%
6%
6%
7%
7%
8%
Rogue-2
Armor Rating
25
26
27
28~29
30~31
32
33
Agility
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Sallet.pngPlate
Sallet
Fighter
Cleric
-3
Armor Rating
33
34
35~36
37~38
39~40
41
42
Strength
1
1
1
2
2
3
3
Vigor
1
1
1
2
2
2
Projectile Damage Reduction
0.9%
Headshot Damage Reduction
13%
Rogue
Warlock
-2
Armor Rating
18
19
20
21~22
23~24
25
26
Magical Resistance
15
Strength
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Rogue
Warlock
-1
Armor Rating
5
6
7
8
9
10
11
Agility
1
1
1
2
2
2
2
Dexterity
1
1
1
1
2
2
2
Strength
1
1
1
1
2
2
Fighter
Ranger
Cleric
-4
Armor Rating
40
41
42~43
44~45
46~47
48
49
Agility
1
1
1
2
2
3
3
Dexterity
1
1
1
2
2
2
Projectile Damage Reduction
1.2%
Headshot Damage Reduction
16%
Rogue
Bard
-2
Armor Rating
21
22
23
24
25
26
27
Strength
1
1
1
2
2
3
3
Dexterity
1
1
1
2
2
2
Headshot Damage Reduction
8%
Bard
Druid
-2
Armor Rating
26
27
28
29~30
31~32
33
34
Strength
1
2
2
3
4
5
5
Headshot Damage Reduction
8%
Fighter
Cleric
-5
Armor Rating
57
58
59~60
61~62
63~64
65
66
Vigor
1
1
1
2
2
3
3
Will
1
1
1
2
2
2
Projectile Damage Reduction
2.1%
Headshot Damage Reduction
24%
Ranger
Barbarian
-3
Armor Rating
33
34
35
36
37
38
39
Strength
1
1
1
2
2
3
3
Headshot Damage Reduction
11%
Headshot Damage Modifier
2.5%
3%
3%
3%
3.5%
3.5%
4%
Barbarian-3
Armor Rating
37
38
39~40
41~42
43~44
45
46
Agility
1
2
2
3
4
5
5
Projectile Damage Reduction
2%
Headshot Damage Reduction
15%
Fighter-4
Armor Rating
48
49
50~51
52~53
54~55
56
57
Will
1
2
2
3
4
5
5
Projectile Damage Reduction
1.8%
Headshot Damage Reduction
16%
Action Speed
1.4%
1.4%
1.4%
1.6%
1.8%
2%
2.2%
Barbarian-5
Armor Rating
50
51
52~53
54~55
56~57
58
59
Agility
1
1
1
2
2
3
3
Dexterity
1
1
1
2
2
2
Projectile Damage Reduction
2.1%
Headshot Damage Reduction
18%
Wizard
Warlock
-2
Armor Rating
20
21
22
23~24
25~26
27
28
Headshot Damage Reduction
5%
Magical Power
1
2
2
3
4
5
5
-2
Armor Rating
20
21
22
23
24
25
26
Vigor
1
1
1
2
2
2
2
Dexterity
1
1
1
1
2
2
2
Agility
1
1
1
1
2
2
Headshot Damage Reduction
5%

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
	local wikitext = {}
	insert(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'>")
	insert(wikitext,"<div class='rarity"..color.." rounded relative'>")
	insert(wikitext,"[[File:"..item.name..".png|"..size(item).."|link="..item.name.."]]")
	insert(wikitext,"<span class='iconamount' style='pointer-events:none;color:#EEEA;font-size:16px'>"..get_type(item).."</span></div>")
	insert(wikitext,caption.."]]</div>")
	return concat(wikitext)
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
		insert(wikitext,newline.."<span class='cr"..i.."'>"..value.."</span>")
		if i == 1 then newline = "<br>" end
	end
	return concat(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 = {}
	insert(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
		insert(wikitext,[=[<th style="width:5%">Class Requirements</th><th style="width:5%">Movement Speed</th>]=])
	end
	insert(wikitext,[=[<th style="width:10%">Armor/magical Rating</th><th style="width:10%">Attributes</th><th style="width:25%">Other</th></tr>]=])
	return concat(wikitext)
end

---Create monster table wikitext
---- Test on wiki with:  mw.log(p.draw_table({args={"Back","Craftable"}}))
----                     mw.log(p.draw_table({args={"Head","Uncraftable"}}))
--- @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


return p