From Dark and Darker Wiki

Overview

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

Functions

draw_table

Creates a table of weapons

Parameters

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


draw_table examples

Sword, Craftable


{{#invoke:Weapon|draw_table|Sword|Craftable}}


NameClassSlotMovement SpeedDamage on HitStatsHitbox + Impact ResistImpact Zones + Impact PowerComboAction Movement PenaltySlowdown On Hit
Fighter
Warlock
Sorcerer
Main-Hand
Two Handed
-30
Physical Base Weapon Damage
38
Undead Race Damage Bonus
15%
Blade of Righteousness Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Special Riposte Attack 2
100%/90% + 4

Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

Special Attacks
Slash/Slash
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x85%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-30/-30/-30 for 0.35/0.35/0.35s
Ranger
Rogue
Bard
Main-Hand
One Handed
-15
Physical Base Weapon Damage
26
Magical Base Weapon Damage
1
Demon's Glee Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 2

Primary Attack 2
100%/90% + 2

Primary Attack 3
100%/90% + 2

Primary Attack 4
100%/90% + 2

Special Riposte Attack 1
100%/90% + 2

Special Riposte Attack 2
100%/90% + 2

Primary Attacks
Pierce/Pierce/Pierce/Pierce
100%/105%/110%/115%

Special Attacks
Slash/Pierce
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x85%

Primary Attacks
Mid Attack: x60%/60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-15/-15/-15/-15 for 0.2/0.2/0.2/0.2s
Fighter
Warlock
Sorcerer
Main-Hand
Two Handed
-30
Physical Base Weapon Damage
39
Undead Race Damage Bonus
15%
Divine Blade Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Special Riposte Attack 2
100%/90% + 4

Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

Special Attacks
Slash/Slash
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x85%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-30/-30/-30 for 0.35/0.35/0.35s
Fighter
Rogue
Ranger
Bard
Off-Hand
One Handed
-15
Physical Base Weapon Damage
26
Undead Race Damage Bonus
15%
Divine Short Sword Hitbox.png
Impact Resist
3

Secondary Attack 1
100%/90% + 2

Secondary Attack 2
100%/90% + 2

Secondary Attack 3
100%/90% + 2

Special Riposte Attack 1
100%/90% + 2

Special Riposte Attack 2
100%/90% + 2

Secondary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash/Pierce
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x75%

Secondary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-15/-15/-30 for 0.2/0.2/0.2s
Fighter
Bard
Warlock
Sorcerer
Main-Hand
One Handed
-25
Physical Base Weapon Damage
37
Armor Penetration
2~3%
Falchion of Honor Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Primary Attacks
Slash/Slash/Slash
100%/105%/110%

Special Attacks
Slash
150%
Block Actions
Always: x97%

Other Actions
Always: x75%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%
Hitslow
-25/-25/-25 for 0.35/0.35/0.35s
Wizard
Warlock
Sorcerer
Main-Hand
Two Handed
-25
Physical Base Weapon Damage
13
Magical Base Weapon Damage
18
Action Speed
2%
Frostlight Crystal Sword Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 3

Primary Attack 2
100%/90% + 3

Primary Attack 3
100%/90% + 3

Special Riposte Attack 1
100%/90% + 3

Primary Attacks
Slash/Slash/Slash
100%/105%/110%

Special Attacks
Slash
150%
Block Actions
Always: x85%

Other Actions
Always: x75%/70%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%
Hitslow
-25/-25/-25 for 0.35/0.35/0.35s
Fighter
Barbarian
Main-Hand
One Handed
-20
Physical Base Weapon Damage
33
Luck
10
Magical Damage Reduction
2%
Golden Viking Sword Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 3

Primary Attack 2
100%/90% + 3

Primary Attack 3
100%/90% + 3

Special Riposte Attack 1
100%/90% + 3

Primary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash
150%
Block Actions
Always: x97%

Other Actions
Always: x75%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%
Hitslow
-20/-20/-20 for 0.35/0.35/0.35s
Fighter
Barbarian
Warlock
Main-Hand
Two Handed
-40
Physical Base Weapon Damage
45~46
Physical Power
5
Undead Race Damage Bonus
30%
Grimslayer Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Primary Attacks
Slash/Slash/Slash
100%/105%/110%

Special Attacks
Slash
125%
Block Actions
Always: x85%

Other Actions
Mid Attack: x70%/85%
Otherwise: x/92.5%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%
Hitslow
-40/-40/-40 for 0.35/0.35/0.35s
Fighter
Rogue
Ranger
Bard
Off-Hand
One Handed
-15
Physical Base Weapon Damage
25
Undead Race Damage Bonus
15%
Short Sword of Righteousness Hitbox.png
Impact Resist
3

Secondary Attack 1
100%/90% + 2

Secondary Attack 2
100%/90% + 2

Secondary Attack 3
100%/90% + 2

Special Riposte Attack 1
100%/90% + 2

Special Riposte Attack 2
100%/90% + 2

Secondary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash/Pierce
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x75%

Secondary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-15/-15/-30 for 0.2/0.2/0.2s
Wizard
Warlock
Sorcerer
Main-Hand
Two Handed
-25
Physical Base Weapon Damage
13
Magical Base Weapon Damage
18
Outgoing Magical Healing Add
2
Move Speed Bonus
2%
Sovereign's Ghostblade Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 3

Primary Attack 2
100%/90% + 3

Primary Attack 3
100%/90% + 3

Special Riposte Attack 1
100%/90% + 3

Primary Attacks
Slash/Slash/Slash
100%/105%/110%

Special Attacks
Slash
150%
Block Actions
Always: x85%

Other Actions
Always: x75%/70%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%
Hitslow
-25/-25/-25 for 0.35/0.35/0.35s
Fighter
Warlock
Sorcerer
Main-Hand
Two Handed
-30
Physical Base Weapon Damage
40
Action Speed
5%
Headshot Damage Modifier
5%
File:Spectral Blade Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Special Riposte Attack 2
100%/90% + 4

Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

Special Attacks
Slash/Slash
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x85%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-30/-30/-30 for 0.35/0.35/0.35s
Fighter
Warlock
Sorcerer
Main-Hand
Two Handed
-30
Physical Base Weapon Damage
37
Undead Race Damage Bonus
15%
Sterling Blade Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Special Riposte Attack 2
100%/90% + 4

Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

Special Attacks
Slash/Slash
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x85%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-30/-30/-30 for 0.35/0.35/0.35s
Fighter
Rogue
Ranger
Bard
Off-Hand
One Handed
-15
Physical Base Weapon Damage
24
Undead Race Damage Bonus
15%
Sterling Short Sword Hitbox.png
Impact Resist
3

Secondary Attack 1
100%/90% + 2

Secondary Attack 2
100%/90% + 2

Secondary Attack 3
100%/90% + 2

Special Riposte Attack 1
100%/90% + 2

Special Riposte Attack 2
100%/90% + 2

Secondary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash/Pierce
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x75%

Secondary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-15/-15/-30 for 0.2/0.2/0.2s
Fighter
Bard
Warlock
Sorcerer
Main-Hand
One Handed
-25
Physical Base Weapon Damage
37
Debuff Duration Bonus
1.5%
File:Tidal Falchion Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Primary Attacks
Slash/Slash/Slash
100%/105%/110%

Special Attacks
Slash
150%
Block Actions
Always: x97%

Other Actions
Always: x75%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%
Hitslow
-25/-25/-25 for 0.35/0.35/0.35s
Fighter
Warlock
Sorcerer
Main-Hand
Two Handed
-30
Physical Base Weapon Damage
41
Magical Base Weapon Damage
2
True Magical Damage
2
Void Blade Hitbox.png
Impact Resist
3

Primary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Special Riposte Attack 2
100%/90% + 4

Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

Special Attacks
Slash/Slash
150%/150%
Block Actions
Always: x97%

Other Actions
Always: x85%

Primary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Special Attacks
Always: x85%/85%
Hitslow
-30/-30/-30 for 0.35/0.35/0.35s


Firearm, Uncraftable


{{#invoke:Weapon|draw_table|Firearm|Uncraftable}}

Code

NameClassSlotMovement SpeedDamage on HitStatsHitbox + Impact ResistImpact Zones + Impact PowerComboAction Movement PenaltySlowdown On Hit
Fighter
Ranger
Main-Hand
Two Handed
-30
Physical Base Weapon Damage
45~46
47~48
49~50
51~52
53~54
55~56
57~58
True Physical Damage
10
File:Hand Cannon Hitbox.png
Impact Resist
3

Primary Attack 1
100% + 6

Primary Attacks
Pierce
Block Actions
Always: x85%

Other Actions
Always: x70%/50%

Primary Attacks
Always: x50%
Hitslow
-135 for 1.5s

local p = {}
local WD = mw.loadJsonData("Data:Weapon.json") --Global var holding tables from Data:Weapon.json
local concat = table.concat


---Iterate keys in ascending order, with numbers going before strings.  Iterator returns: (key, value).
---@param dict table
---@return function
local function spairs(dict)
	if not dict then return function() return nil,nil end end

	local set = {}
	for key,_ in pairs(dict) do
		if key ~= "order" then
			set[#set+1] = key
		end
	end

	--Sort such that numbers and strings are in ascending order, with all numbers going before strings
	--Slightly different from alphanumerical order in that numbers aren't compared as strings.
	--For example, 24 doesn't go ahead of 3.
	table.sort(set,function(a,b)
	if type(a) ~= type(b) then
		return tostring(a) < tostring(b)
	else
		return a < b
	end
	end)

	local i = 0
	return function()
		i = i + 1
		local key = set[i]
		if key ~= nil then
			return key, dict[key]
		end
	end
end


---Get the item's size 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 Weapon.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


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

	local wt = ""
	local newline = ""
	for i, key in ipairs(weapon.rarities) do
		wt = wt..newline.."<span class='cr"..key.."'>"..tostring(values[tonumber(key)] or "").."</span>"
		if i == 1 then newline = "<br>" end
	end
	return wt
end


---Marks up a stat block with the stat name and colored values and appropriate margins and alignment
--- @param weapon table
--- @param stat string
--- @return string
local function inline_block(weapon,stat)
	if weapon.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(weapon,weapon.stats[(stat):lower()]).."</div>"
end


---Formats a table cell for the iconbox
---@param item table
---@return string
local function name(item, is_header)
	if is_header then return [[<th style="width:5%">Name</th>]] end

	local color = "2"
	local bold_link = "|<b>"..item.name
	if count(item.rarities) == 1 then
		color = item.rarities[1]
		bold_link = "|<b class=cr"..color..">"..item.name
	end

	local icon_amount = ""
	if item.maxammocount > 0 then
		icon_amount = "<span class='iconamount' style='pointer-events:none;color:#EEEA;font-size:16px'>"..item.maxammocount.."</span>"
	end

	return "<td><div class='iconbox'><div class='rarity"..color.." rounded relative'>[[File:"..item.name..".png|"..size(item).."|link="..item.name.."]]"
				..icon_amount
			.."</div><br>[["..item.name..bold_link.."</b>]]</div></td>"
end


---Formats the weapon's list of classes into a table cell of classes separated by linebreaks
--- @param weapon table
--- @param is_header boolean
--- @return string
local function classes(weapon,is_header)
	if is_header then return [[<th style="width:5%">Class</th>]] end

	local wt = ""
	local newline = ""
	for i, class in ipairs(weapon.classes) do
		wt = wt..newline..class
		if i == 1 then newline = "<br>" end -- Subsequent loops will prefix a linebreak
	end
	return "<td>"..wt.."</td>"
end


---Formats a table cell of slottype and handtype
--- @param weapon table
--- @param is_header boolean
--- @return string
local function slot_type(weapon,is_header)
	if is_header then return [[<th style="width:5%">Slot</th>]] end

	return "<td>"..weapon.slottype.."<br>"..weapon.handtype.."</td>"
end


---Formats a table cell of move speeds
--- @param weapon table
--- @param is_header boolean
--- @return string
local function move_speed(weapon,is_header)
	if is_header then return [[<th style="width:5%">Movement Speed</th>]] end

	return "<td>"..color_values(weapon,weapon.stats["move speed"]).."</td>"
end


---Formats a table cell of Armor rating and Magical Resistance
--- @param weapon table
--- @param is_header boolean
--- @return string
local function armor_rating(weapon,is_header)
	if is_header then return [[<th style="width:15%">Armor Rating</th>]] end

	return "<td>"..inline_block(weapon,"Armor Rating")..inline_block(weapon,"Magical Resistance").."</td>"
end


local function impact_zones(weapon,is_header)
	if is_header then return [[<th style="width:10%">Impact Zones + Impact Power</th>]] end

	local wt= ""
	for ability_name,ability in spairs(weapon.abilities) do
		if ability_name ~= "Other" then
			for attack_name,attack in spairs(ability) do
				if attack.impactpower and attack.impactzones then
					wt = wt.."<br><span style='color:#eee8'>"..ability_name.." "..attack_name.."</span><br>"
					for i,v in ipairs(attack.impactzones) do
						if i~=1 then wt = wt.."/" end
						wt = wt..v
					end
					wt = wt.." + "..attack.impactpower.."<br>"
				end
			end
		end
	end
	return "<td>"..wt.."<br></td>"
end


local function collect_multipliers(ability)
	local move, prep_move = "",""
	local i = 1
	for _,attack in spairs(ability) do
		if attack.movementmultiplier then
			if i ~= 1 then
				move = move.."/"
				prep_move = prep_move.."/"
			end
			move = move..(attack.movementmultiplier or "")
			prep_move = prep_move..(attack.preparemovementmultiplier or "")
			i = i + 1
		end
	end

	return move,prep_move
end


--TODO not always the same for each attack
local function action_move_speed_penalty(weapon,is_header)
	if is_header then return [=[<th style="width:10%">[[Weapons#Movement_Multiplier_Explanation|Action Movement Penalty]]</th>]=] end

	local wt = ""
	local i = 1
	for ability_name,ability in spairs(weapon.abilities) do
		if i~=1 then wt = wt.."<br><br>" end
		i = i+1

		-- ability identifier
		wt = wt.."<span style='color:#eee8; font-size:110%; font-weight:bold'>"
		if ability_name=="Other" or ability_name=="Block" then wt = wt..ability_name.." Actions" else wt = wt..ability_name.." Attacks" end
		wt = wt.."</span><br>"

		local movement_multiplier,prepare_movement_multiplier = collect_multipliers(ability)
		if #prepare_movement_multiplier > 3 then
			wt = wt.."<span style='color:#eee8'>Mid Attack:&nbsp;</span>x"..movement_multiplier
			.."<br><span style='color:#eee8'>Otherwise:&nbsp;</span>x"..prepare_movement_multiplier
		else
			wt = wt.."<span style='color:#eee8'>Always:&nbsp;</span>x"..movement_multiplier
		end
	end
	return "<td>"..wt.."</td>"
end


---Formats a table cell containing base Physical and Magical damage, if present.
---@param weapon any
---@param is_header any
---@return string
local function damage_on_hit(weapon,is_header)
	if is_header then return [[<th style="width:25%">Damage on Hit</th>]] end

	local wt = ""
	wt = wt..inline_block(weapon,"Physical Base Weapon Damage")
			..inline_block(weapon,"Magical Base Weapon Damage")
	return "<td>"..wt.."</td>"
end


---These stats get their own table cells, as such they are excluded from the stats cell to avoid needless redundancy
local exclude_stat = {["Physical Base Weapon Damage"]=true,["Magical Base Weapon Damage"]=true,["Armor Rating"]=true,["Magical Resistance"]=true,["Move Speed"]=true}


---Formats a table cell containing any stats not covered by the rest of the row
---@param weapon table
---@param is_header boolean
---@return string
local function stats(weapon,is_header)
	if is_header then return [[<th style="width:12%">Stats</th>]] end

	local wt = ""
	for i,stat in ipairs(weapon.stats.order) do
		if not exclude_stat[stat] then
			wt = wt..inline_block(weapon,stat)
		end
	end
	return "<td>"..wt.."</td>"
end


---Formats a table cell containing animation times for ranges weapons
---@param weapon table
---@param is_header boolean
---@return string
local function animation_time(weapon,is_header)
	if is_header then return [[<th style="width:10%">Animation Times</th>]] end

	local windup = "<br>Windup:"
	local finish = "<br>Finish:"
	local reload = "<br><br><span style='color:#eee8'>Reload</span><br>"

	if weapon.animationtimes["Attack 1"] then
		-- windup = windup..weapon.animationtimes["Attack 1"].Windup
		-- finish = finish..weapon.animationtimes["Attack 1"].Finish
	else
		windup = ""
		finish = ""
	end
	if weapon.animationtimes["Other"] then
		-- reload = reload..weapon.animationtimes["Other"].Reload
	else
		reload = ""
	end

	if #windup == 0 and #finish == 0 and #reload == 0 then
		return ""
	else
		return "<td><span style='color:#eee8'>Primary Attack</span>"..windup..finish..reload.."</td>"
	end
end


---Formats a table cell containing hitslow for each attack
---@param weapon table
---@param is_header boolean
---@return string
local function slowdown_on_hit(weapon,is_header)
	if is_header then return [[<th style="width:8%">Slowdown On Hit</th>]] end
	if not (weapon.abilities.Primary or weapon.abilities.Secondary or weapon.abilities.Special) then return "<td></td>" end

	local ability_type = "Primary"
	if weapon.slottype == "Off-Hand" then ability_type = "Secondary" end

	local wt = "<span style='color:#eee8'>Hitslow</span><br>"
	local duration = " for "
	local i = 1
	for attack_name,attack in spairs(weapon.abilities[ability_type]) do
		if i~=1 then wt = wt.."/" end
		i = i+1
		wt = wt..(attack.effects.HitSlow.rarity.Global["Move Speed Add"] or attack.effects.HitSlow.rarity.Global["Move Speed Bonus"] or "")
	end
	i=1
	for attack_name,attack in spairs(weapon.abilities[ability_type]) do
		if i~=1 then duration = duration.."/" end
		i = i+1
		duration = duration..(attack.effects.HitSlow.rarity.Global["Duration"] or "")
	end
	return "<td>"..wt..duration.."s</td>"
end

---Formats a table cell containing the projectile's initial speed
---@param weapon table
---@param is_header boolean
---@return string
local function initial_speed(weapon,is_header)
	if is_header then return [[<th style="width:5%">Initial Projectile Speed (m/s)</th>]] end

	return "<td>"..weapon.initialspeed.."</td>"
end


---Formats a table cell containing the hitbox image resized by inventory size
---@param weapon table
---@param is_header boolean
---@return string
local function hitbox(weapon,is_header)
	if is_header then return [[<th style="width:10%">Hitbox + Impact Resist</th>]] end

	if weapon.impactresistance~="" then
		return "<td>[[File:"..weapon.name.." Hitbox.png|link=|"..size(weapon).."]]<br><span style='color:#eee8'>Impact Resist</span><br>"..weapon.impactresistance.."</td>"
	else
		return "<td>[[File:"..weapon.name.." Hitbox.png|link=|"..size(weapon).."]]</td>"
	end
end


---Helps format a string containing either Combo Damage or damagetype values
---@param weapon table
---@param attack string
---@param value string
---@return string
local function format_combo(weapon,attack,value)
	local wt = ""
	for _,data in spairs(weapon.abilities[attack]) do
		if #wt ~= 0 then wt = wt.."/" end
		wt = wt..(data[value] or "")
	end
	return wt
end


---Formats a table cell containing ability combo values per attack
---@param weapon table
---@param is_header boolean
---@return string
local function combo(weapon,is_header)
	if is_header then return [[<th style="width:8%">Combo</th>]] end

	local wt = ""
	if weapon.abilities["Primary"] then
		wt = wt.."<span style='color:#eee8'>Primary Attacks</span><br>"..format_combo(weapon,"Primary","damagetype").."<br>"..format_combo(weapon,"Primary","combodamage")
	end
	if weapon.abilities["Secondary"] then
		if #wt ~= 0 then wt = wt.."<br><br>" end
		wt = wt.."<span style='color:#eee8'>Secondary Attacks</span><br>"..format_combo(weapon,"Secondary","damagetype").."<br>"..format_combo(weapon,"Secondary","combodamage")
	end
	if weapon.abilities["Special"] then
		if wt:match("Primary") or wt:match("Secondary") then wt = wt.."<br><br>" end
		wt = wt.."<span style='color:#eee8'>Special Attacks</span><br>"..format_combo(weapon,"Special","damagetype").."<br>"..format_combo(weapon,"Special","combodamage")
	end
	return "<td>"..wt.."</td>"
end


---Determines which table data goes into the table row
local row_type = {
	["Shield"] = {name,classes,slot_type,move_speed,armor_rating,impact_zones,action_move_speed_penalty},
	["Bow or Crossbow"] = {name,classes,slot_type,move_speed,damage_on_hit,stats,impact_zones,animation_time,action_move_speed_penalty,slowdown_on_hit,initial_speed},
	["Default"] = {name,classes,slot_type,move_speed,damage_on_hit,stats,hitbox,impact_zones,combo,action_move_speed_penalty,slowdown_on_hit}
}


---Return a table row of data cells containing weapon information,
--- @param weapon table
--- @return string
local function row(weapon, is_header)
	is_header = is_header or false

	local key = "Default"
	if is_header then
		if weapon.args[1] == "Shield" then key = "Shield" elseif (weapon.args[1]):lower():match("bow") then key = "Bow or Crossbow" end
	else
		if weapon.types.Shield then key = "Shield" elseif weapon.types.Bow or weapon.types.Crossbow then key = "Bow or Crossbow" end
	end

	local wt = {}
	wt[#wt+1] = "<tr>"
	for _,content in ipairs(row_type[key]) do
		wt[#wt+1] = content(weapon,is_header)
	end
	wt[#wt+1] = "</tr>"

	return concat(wt)
end

---Returns a predetermined weapon list
---@param frame table contains args, first key is determined by types, second key must be {Uncraftable, Craftable, Artifact}
---@return table
local function get_list(frame)
	if not (frame.args and frame.args[1] and frame.args[2]) then return {} end
	if not (WD[frame.args[1]] and WD[frame.args[1]][frame.args[2]]) then return {} end

	return WD[frame.args[1]][frame.args[2]]
end


--- @param frame any
--- @return string
function p.draw_table(frame)
	local wt = {}

	wt[#wt+1] = [[<table cellspacing="0" class="wikitable sortable jquery-tablesorter" style="text-align:center; vertical-align:middle;">]]
	wt[#wt+1] = row(frame, true)
	for _,item_name in ipairs(get_list(frame)) do
		wt[#wt+1] = row(WD.Weapon[item_name])
	end
	wt[#wt+1] = "</table>"

	return concat(wt)
end


return p
---- Test on wiki with:  mw.log(p.draw_table({args={"Crossbow","Uncraftable"}}))
---- Test on wiki with:  mw.log(p.draw_table({args={"Shield","Craftable"}}))
---- Test on wiki with:  mw.log(p.draw_table({args={"Polearm","Artifact"}}))