From Dark and Darker Wiki

(Data validation. When no items in list, display a message instead of an empty table.)
Tag: Reverted
(Undo revision 64664 by Raw Salad (talk))
Tag: Undo
Line 297: Line 297:
return "<td>"..wt..duration.."s</td>"
return "<td>"..wt..duration.."s</td>"
end
end


---Formats a table cell containing the projectile's initial speed
---Formats a table cell containing the projectile's initial speed
Line 413: Line 412:
function p.draw_table(frame)
function p.draw_table(frame)
local wt = {}
local wt = {}
local item_list = get_list(frame)
if #item_list == 0 then return "<span style='font-size:24pt'>There are currently no items of this type.</span>" end


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

Revision as of 08:30, 15 March 2026

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.pngPrimary 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

Impact Resist
3
Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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.pngPrimary 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

Impact Resist
3
Primary Attacks
Pierce/Pierce/Pierce/Pierce
100%/105%/110%/115%

Special Attacks
Slash/Pierce
150%/150%
Primary Attacks
Mid Attack: x60%/60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%/92.5%

Block Actions
Always: x97%

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.pngPrimary 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

Impact Resist
3
Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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.pngSecondary 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

Impact Resist
3
Secondary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash/Pierce
150%/150%
Secondary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Block Actions
Always: x97%

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.pngPrimary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Impact Resist
3
Primary Attacks
Slash/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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.pngPrimary Attack 1
100%/90% + 3

Primary Attack 2
100%/90% + 3

Primary Attack 3
100%/90% + 3

Special Riposte Attack 1
100%/90% + 3

Impact Resist
3
Primary Attacks
Slash/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x85%

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.pngPrimary Attack 1
100%/90% + 3

Primary Attack 2
100%/90% + 3

Primary Attack 3
100%/90% + 3

Special Riposte Attack 1
100%/90% + 3

Impact Resist
3
Primary Attacks
Slash/Slash/Pierce
100%/105%/110%

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

Block Actions
Always: x97%

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.pngPrimary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Impact Resist
3
Primary Attacks
Slash/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x85%

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.pngSecondary 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

Impact Resist
3
Secondary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash/Pierce
150%/150%
Secondary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Block Actions
Always: x97%

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.pngPrimary Attack 1
100%/90% + 3

Primary Attack 2
100%/90% + 3

Primary Attack 3
100%/90% + 3

Special Riposte Attack 1
100%/90% + 3

Impact Resist
3
Primary Attacks
Slash/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x85%

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.pngPrimary 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

Impact Resist
3
Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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.pngPrimary 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

Impact Resist
3
Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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.pngSecondary 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

Impact Resist
3
Secondary Attacks
Slash/Slash/Pierce
100%/105%/110%

Special Attacks
Slash/Pierce
150%/150%
Secondary Attacks
Mid Attack: x60%/60%/60%
Otherwise: x92.5%/92.5%/92.5%

Block Actions
Always: x97%

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.pngPrimary Attack 1
100%/90% + 4

Primary Attack 2
100%/90% + 4

Primary Attack 3
100%/90% + 4

Special Riposte Attack 1
100%/90% + 4

Impact Resist
3
Primary Attacks
Slash/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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.pngPrimary 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

Impact Resist
3
Primary Attacks
Pierce/Slash/Slash
100%/105%/110%

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

Block Actions
Always: x97%

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 HitStatsImpact Zones + Impact PowerAction Movement PenaltySlowdown On HitInitial Projectile Speed (m/s)
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
Primary Attack 1
100% + 6

Impact Resist
3
Primary Attacks
Always: x50%

Block Actions
Always: x85%
Hitslow
-135 for 1.5s
38

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


---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' style='width:max-content;align-items:center'><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 i,ability in ipairs(weapon.abilities.order) do
		if ability ~= "Other" then
			for j,attack in ipairs(weapon.abilities[ability].order) do
				if weapon.abilities[ability][attack].impactpower and weapon.abilities[ability][attack].impactzones then
					wt = wt.."<span style='color:#eee8'>"..ability.." "..attack.."</span><br>"
					for k,impact_zone in ipairs(weapon.abilities[ability][attack].impactzones) do
						if k~=1 then wt = wt.."/" end
						wt = wt..impact_zone
					end
					wt = wt.." + "..weapon.abilities[ability][attack].impactpower.."<br><br>"
				end
			end
		end
	end
	if weapon.impactresistance~="" then
		wt = wt.."<span style='color:#eee8'>Impact Resist</span><br>"..weapon.impactresistance
	end
	return "<td>"..wt.."</td>"
end


---Helper function: Collects move mult and prepare move mult for display
---@param ability table
---@return string
---@return string
local function collect_multipliers(ability)
	local move, prep_move = "",""
	for i,attack_name in ipairs(ability.order) do
		if ability[attack_name].movementmultiplier then
			if i ~= 1 then
				move = move.."/"
				prep_move = prep_move.."/"
			end
			move = move..(ability[attack_name].movementmultiplier or "")
			prep_move = prep_move..(ability[attack_name].preparemovementmultiplier or "")
			i = i + 1
		end
	end

	return move,prep_move
end


---Formats a table cell containing speed penalties for each action
---@param weapon table
---@param is_header boolean
---@return string
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 order = {} --reconstruct order to exclude the other ability group
	for _,ability in ipairs(weapon.abilities.order) do
		if ability ~= "Other" then order[#order+1] = ability end
	end

	local wt = ""
	for i,ability_name in ipairs(order) do
		if i~=1 then wt = wt.."<br><br>" end

		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(weapon.abilities[ability_name])
		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 "
	for i,attack in ipairs(weapon.abilities[ability_type].order) do
		if i~=1 then wt = wt.."/" end
		wt = wt..(weapon.abilities[ability_type][attack].effects.HitSlow.rarity.Global["Move Speed Add"]
				or weapon.abilities[ability_type][attack].effects.HitSlow.rarity.Global["Move Speed Bonus"] or "")
	end
	for i,attack in ipairs(weapon.abilities[ability_type].order) do
		if i~=1 then duration = duration.."/" end
		duration = duration..(weapon.abilities[ability_type][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

	return "<td>[[File:"..weapon.name.." Hitbox.png|link=|"..size(weapon).."]]</td>"
end


---Helps format a string containing either Combo Damage or damagetype values
---@param weapon table
---@param ability string
---@param value string
---@return string
local function format_combo(weapon,ability,value)
	local wt = ""
	for i,attack in ipairs(weapon.abilities[ability].order) do
		if i~=1 then wt = wt.."/" end
		wt = wt..(weapon.abilities[ability][attack][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


---@param weapon table
---@return string
local function determine_table_type(weapon)
	if weapon.args then
		if weapon.args[1] == "Shield" then return "Shield"
		elseif (weapon.args[1]):lower():match("bow") or weapon.args[1] == "Firearm" or weapon.args[1] == "Throwable" then return "Ranged" end
	elseif weapon.types then
		if weapon.types.Shield then return "Shield"
		elseif weapon.types.Bow or weapon.types.Crossbow or weapon.types.Firearm or weapon.types.Throwable then return "Ranged" end
	end

	return "Default"
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},
	["Ranged"] = {name,classes,slot_type,move_speed,damage_on_hit,stats,impact_zones,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 wt = {}
	wt[#wt+1] = "<tr>"
	for _,content in ipairs(row_type[determine_table_type(weapon)]) 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"}}))