From Dark and Darker Wiki

(Slightly more confident in this one.)
(Fixed missing artifact abilities. Fixed missing infobox rows.)
 
Line 65: Line 65:


local function stat_block(wt, args, item)
local function stat_block(wt, args, item)
if count(item.stats.order) == 0 or item.numenchants[args.rarity] == 0 then return end
if not item.stats or count(item.stats.order) == 0 or item.numenchants[tonumber(args.rarity)] == 0 then return end


wt[#wt+1] = "<div style='text-align:center'>"
wt[#wt+1] = "<div style='text-align:center'>"
Line 82: Line 82:
end
end


if item.haspassive then
if item.haspassive or item.isartifact then
wt[#wt+1] = "<div style='margin-top:10px;display:flex;width:100%;flex-direction:row;justify-content:space-between;color:rgb(211,178,125)'>"
wt[#wt+1] = "<div style='margin-top:10px;display:flex;width:100%;flex-direction:row;justify-content:space-between;color:rgb(211,178,125)'>"
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div>"
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div>"
Line 94: Line 94:
local ret = ""
local ret = ""
for i,v in ipairs(list) do
for i,v in ipairs(list) do
if i~=1 then ret = ret.."," end
if i ~= 1 then ret = ret..", " end
ret = ret..v
ret = ret..v
end
end
return ret
end
end


local function type_list(t,type)
local function type_list(t,type)
local ret = ""
local ret = ""
local i = 1
for k,v in pairs(t) do
for k,v in pairs(t) do
if v==type then ret=ret..k end
if i ~= 1 then ret = ret..", " end
if v == type then
ret = ret..k
end
i = i + 1
end
end
return ret
return ret
Line 108: Line 114:


local function weapon_rows(rows, args, weapon)
local function weapon_rows(rows, args, weapon)
local index = tonumber(args.rarity)
rows[#rows+1] = hline()
rows[#rows+1] = hline()
stat_block(rows,args,weapon)
stat_block(rows,args,weapon)
Line 125: Line 133:
rows[#rows+1] = hline()
rows[#rows+1] = hline()
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",weapon.invwidth,weapon.invheight))
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",weapon.invwidth,weapon.invheight))
rows[#rows+1] = row_h("Gear Score",weapon.gearscore[args.rarity])
if weapon.maxcount ~= 1 then
rows[#rows+1] = row_h("Sell Price",weapon.sellprices[args.rarity])
rows[#rows+1] = row_h("Stack Size",weapon.maxcount)
rows[#rows+1] = row_h("Stack Size",weapon.maxcount)
end
rows[#rows+1] = row_h("Gear Score",weapon.gearscore[index])
rows[#rows+1] = row_h("Item Achieve",weapon.ap[index])
rows[#rows+1] = row_h("Sell Price",weapon.sellprices[index])


rows[#rows+1] = hline()
rows[#rows+1] = hline()
Line 134: Line 145:


local function armor_rows(rows, args, armor)
local function armor_rows(rows, args, armor)
local index = tonumber(args.rarity)
rows[#rows+1] = hline()
rows[#rows+1] = hline()
stat_block(rows,args,armor)
stat_block(rows,args,armor)
Line 139: Line 152:
rows[#rows+1] = hline()
rows[#rows+1] = hline()
rows[#rows+1] = row_v("Required Class",class_list(armor.classes))
rows[#rows+1] = row_v("Required Class",class_list(armor.classes))
rows[#rows+1] = row_h("Armor Type",type_list(armor.types,"Armor"))
rows[#rows+1] = row_h("Slot Type",armor.slottype)
rows[#rows+1] = row_h("Slot Type",armor.slottype)


rows[#rows+1] = hline()
rows[#rows+1] = hline()
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",armor.invwidth,armor.invheight))
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",armor.invwidth,armor.invheight))
rows[#rows+1] = row_h("Gear Score",armor.gearscore[args.rarity])
rows[#rows+1] = row_h("Gear Score",armor.gearscore[index])
rows[#rows+1] = row_h("Sell Price",armor.sellprices[args.rarity])
rows[#rows+1] = row_h("Item Achieve",armor.ap[index])
rows[#rows+1] = row_h("Sell Price",armor.sellprices[index])


rows[#rows+1] = hline()
rows[#rows+1] = hline()
Line 151: Line 166:


local function accessory_rows(rows, args, accessory)
local function accessory_rows(rows, args, accessory)
local index = tonumber(args.rarity)
rows[#rows+1] = hline()
rows[#rows+1] = hline()
stat_block(rows,args,accessory)
stat_block(rows,args,accessory)
Line 159: Line 176:
rows[#rows+1] = hline()
rows[#rows+1] = hline()
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",accessory.invwidth,accessory.invheight))
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",accessory.invwidth,accessory.invheight))
rows[#rows+1] = row_h("Gear Score",accessory.gearscore[args.rarity])
rows[#rows+1] = row_h("Gear Score",accessory.gearscore[index])
rows[#rows+1] = row_h("Sell Price",accessory.sellprices[args.rarity])
rows[#rows+1] = row_h("Item Achieve",accessory.ap[index])
rows[#rows+1] = row_h("Sell Price",accessory.sellprices[index])


rows[#rows+1] = hline()
rows[#rows+1] = hline()
Line 168: Line 186:


local function utility_rows(rows, args, utility)
local function utility_rows(rows, args, utility)
rows[#rows+1] = hline()
error("monster_rows() needs to be implemented")
stat_block(rows,args,utility)
 
rows[#rows+1] = hline()
rows[#rows+1] = row_v("Required Class",class_list(armor.classes))
rows[#rows+1] = row_h("Slot Type",utility.slottype)
 
rows[#rows+1] = hline()
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",accessory.invwidth,accessory.invheight))
rows[#rows+1] = row_h("Gear Score",utility.gearscore[args.rarity])
rows[#rows+1] = row_h("Sell Price",utility.sellprices[args.rarity])
 
rows[#rows+1] = hline()
rows[#rows+1] = row_v3(utility.flavortext)
end
end


local function misc_rows(rows, args, misc)
local function misc_rows(rows, args, misc)
rows[#rows+1] = hline()
local index = tonumber(args.rarity)
stat_block(rows,args,misc)


rows[#rows+1] = hline()
rows[#rows+1] = hline()
Line 194: Line 198:
rows[#rows+1] = hline()
rows[#rows+1] = hline()
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",misc.invwidth,misc.invheight))
rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",misc.invwidth,misc.invheight))
rows[#rows+1] = row_h("Gear Score",misc.gearscore[args.rarity])
if misc.maxcount ~= 1 then
rows[#rows+1] = row_h("Sell Price",misc.sellprices[args.rarity])
rows[#rows+1] = row_h("Stack Size",misc.maxcount)
rows[#rows+1] = row_h("Item Achieve",misc.ap[args.rarity])
end
rows[#rows+1] = row_h("Max Contents",misc.maxcontentscount)
rows[#rows+1] = row_h("Item Achieve",misc.ap[index])
rows[#rows+1] = row_h("Sell Price",misc.sellprices[index])


rows[#rows+1] = hline()
rows[#rows+1] = hline()
Line 312: Line 319:


--[=[
--[=[
mw.log(p.draw({args={name="Halberd",category="Weapon"}}))
mw.log(p.draw({args={name="Halberd",is_active="2",category="Weapon"}}))
mw.log(p.draw({args={name="Halberd",is_active="2",category="Weapon"}}))
mw.log(p.draw({args={name="Cinder",is_active="8",category="Weapon"}}))
mw.log(p.draw({args={name="Bloodthirst",category="Weapon"}}))
 
mw.log(p.draw({args={name="Golden Scarf",category="Armor"}}))
mw.log(p.draw({args={name="Plate Pants",category="Armor"}}))
 
mw.log(p.draw({args={name="Grimsmile Ring",category="Accessory"}}))
 
mw.log(p.draw({args={name="Diamond",category="Misc"}}))
mw.log(p.draw({args={name="Gold Coin Chest",category="Misc"}}))
mw.log(p.draw({args={name="Quiver",category="Misc"}}))
]=]
]=]

Latest revision as of 10:23, 13 April 2026

Overview

Function for making Iconbox tabs. Data comes from various data jsons: Data:Weapon.json, Data:Armor.json, Data:Accessory.json, Data:Misc.json, Data:Monster.json.

Functions

draw

Creates an iconbox that floats to the right.

Parameters

  • name - <Name>
  • is_active - {1,2,3,4,5,6,7,8,Common,Elite,Nightmare}
  • category - {Weapon,Armor,Accessory,Utility,Misc,Monster,Prop}


draw examples

Halberd,7,Weapon


{{#invoke:Infobox|draw|name=Halberd|category=Weapon}}
 I 
 II 
 III 
 IV 
 V 
 VI 
 VII 
Halberd
Halberd.png
-
Physical Base Weapon Damage 46~47
-
-
Move Speed -45
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.
Halberd
Halberd.png
-
Physical Base Weapon Damage 48~49
-
-
Move Speed -45
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
Gear Score:
1
Sell Price:
20
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.
Halberd
Halberd.png
-
Physical Base Weapon Damage 50~51
-
-
Move Speed -45
-
-
Up to 1 extra enchantments
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
Gear Score:
5
Item Achieve:
10
Sell Price:
30
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.
Halberd
Halberd.png
-
Physical Base Weapon Damage 52~53
-
-
Move Speed -45
-
-
Up to 2 extra enchantments
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
Gear Score:
25
Item Achieve:
20
Sell Price:
60
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.
Halberd
Halberd.png
-
Physical Base Weapon Damage 54~55
-
-
Move Speed -45
-
-
Up to 3 extra enchantments
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
Gear Score:
40
Item Achieve:
30
Sell Price:
100
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.
Halberd
Halberd.png
-
Physical Base Weapon Damage 56~57
-
-
Move Speed -45
-
-
Up to 4 extra enchantments
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
Gear Score:
50
Item Achieve:
50
Sell Price:
200
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.
Halberd
Halberd.png
-
Physical Base Weapon Damage 58~59
-
-
Move Speed -45
-
-
Up to 1 extra enchantments
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.68x15.84x2.25
2x5InvSlot.jpg
Gear Score:
65
Item Achieve:
100
Sell Price:
300
A two handed pole-arm with a long reach, devised with an axe blade containing a sharp spike firmly fasted to the end.


Cinder,8,Weapon


{{#invoke:Infobox|draw|name=Cinder|is_active=8|category=Weapon}}
 VIII 
Cinder
Cinder.png
-
Physical Base Weapon Damage 60~61
-
-
Move Speed -45
-
-
Up to 5 extra enchantments
-
-
Successful weapon attacks sears the target for 10 Fire Fire Magical Base Damage (100% Scaling) and burns them for 27 Fire Fire Magical Base Damage (50% Scaling) over 9 seconds.
-
Required Class:
Weapon Type:
Polearm
Slot Type:
Main-Hand
Hand Type:
Two Handed
Hitbox:
119.7x15.84x2.14
2x5InvSlot.jpg
Item Achieve:
100
Sell Price:
1000
It will be difficult to keep track of your kill count for they have all been reduced to a pile of ash.


Ranger Hood,5,Armor


{{#invoke:Infobox|draw|name=Ranger Hood|is_active=5|category=Armor}}
 I 
 II 
 III 
 IV 
 V 
 VI 
 VII 
Ranger Hood
Ranger Hood.png
-
Armor Rating 25
-
-
Headshot Damage Reduction 8%
-
-
Agility 1
-
-
Move Speed -2
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Lightweight and breathable, cut to hug the head and protect from the elements.
Ranger Hood
Ranger Hood.png
-
Armor Rating 26
-
-
Headshot Damage Reduction 8%
-
-
Agility 2
-
-
Move Speed -2
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Gear Score:
1
Sell Price:
8
Lightweight and breathable, cut to hug the head and protect from the elements.
Ranger Hood
Ranger Hood.png
-
Armor Rating 27
-
-
Headshot Damage Reduction 8%
-
-
Agility 2
-
-
Move Speed -2
-
-
Up to 1 extra enchantments
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Gear Score:
1
Item Achieve:
4
Sell Price:
12
Lightweight and breathable, cut to hug the head and protect from the elements.
Ranger Hood
Ranger Hood.png
-
Armor Rating 28~29
-
-
Headshot Damage Reduction 8%
-
-
Agility 3
-
-
Move Speed -2
-
-
Up to 2 extra enchantments
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Gear Score:
15
Item Achieve:
8
Sell Price:
24
Lightweight and breathable, cut to hug the head and protect from the elements.
Ranger Hood
Ranger Hood.png
-
Armor Rating 30~31
-
-
Headshot Damage Reduction 8%
-
-
Agility 4
-
-
Move Speed -2
-
-
Up to 3 extra enchantments
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Gear Score:
20
Item Achieve:
12
Sell Price:
40
Lightweight and breathable, cut to hug the head and protect from the elements.
Ranger Hood
Ranger Hood.png
-
Armor Rating 32
-
-
Headshot Damage Reduction 8%
-
-
Agility 5
-
-
Move Speed -2
-
-
Up to 4 extra enchantments
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Gear Score:
30
Item Achieve:
20
Sell Price:
80
Lightweight and breathable, cut to hug the head and protect from the elements.
Ranger Hood
Ranger Hood.png
-
Armor Rating 33
-
-
Headshot Damage Reduction 8%
-
-
Agility 5
-
-
Move Speed -2
-
-
Up to 1 extra enchantments
-
Required Class:
Armor Type:
Cloth
Slot Type:
Head
2x2InvSlot.jpg
Gear Score:
40
Item Achieve:
40
Sell Price:
120
Lightweight and breathable, cut to hug the head and protect from the elements.


Code


local p = {}
local concat = table.concat

local function count(t)
	local c = 0
	for _,_ in pairs(t) do c = c + 1 end
	return c
end

local function search(t,v)
	for ind,val in ipairs(t) do
		if v == val then return true end
	end
	return false
end

local function hline()
	return "<div class='line' style='background-image:linear-gradient(to right,rgb(10,10,10),rgb(100,100,100),rgb(10,10,10))'></div>"
end

local function row_h(title, content)
	if not content or content == "" or content == 0 then return "" end
	return string.format("<div style='display:flex;flex-direction:row;justify-content:center;white-space:pre-wrap;color:rgb(160,160,140)'><div style='text-align:right; color:rgb(70,70,70)'>%s: </div><div>%s</div></div>", title, content)
end

local function row_v(title, content)
	if not content or content == "" or content == 0 then return "" end
	return string.format("<div style='display:flex;flex-direction:column;align-items:center;color:rgb(160,160,140);margin-bottom:5px'><div style='color:rgb(70,70,70)'>%s: </div><div>%s</div></div>", title, content)
end


local function row_v2(content)
	if not content or content == "" or content == 0 then return "" end
	return string.format("<div style='display:flex;margin-top:10px;flex-direction:column;align-items:center;text-align:center;margin-bottom:15px'>%s</div>",content)
end


local function row_v3(content)
	if not content or content == "" or content == 0 then return "" end
	return string.format("<div style='display:flex;flex-direction:column;align-items:center;text-align:center;color:rgb(115,83,67)'>%s</div>",content)
end

local function header(args)
	local header_content = ""
	if args.link then
		header_content = string.format("[[%s|<span class='cr%s'>%s</span>]]", args.link, args.rarity, args.name)
	else
		header_content = string.format("<span class='bold cr%s'>%s</span>", args.rarity, args.name)
	end

	return string.format(
		"<div class='itemboxheader' style='width:280px;padding:20px;box-shadow:inset 0px 0px 20px 5px rgb(0 0 0 / 0.5);display:flex;flex-direction:column;align-items:center;background-color:rgb(var(--rarity-%s),0.1);border:2px solid rgb(var(--rarity-%s),0.5)'><div class='bold' style='margin-top:0px!important;font-size:22px'>%s</div></div>",
		args.rarity, args.rarity, header_content
	)
end

local function image(args)
	if not args.name then return end
	return "<div style='display:flex;flex-direction:column;align-items:center'><div class='iconbox' style='width:max-content;align-items:center'><div class='rarity-1 rounded relative'>[[File:"..args.name..".png|90px|link=]]</div></div></div>"
end

local function stat_index(item,rarity)
	return 1 + tonumber(rarity) - item.rarities[1]
end

local function stat_block(wt, args, item)
	if not item.stats or count(item.stats.order) == 0 or item.numenchants[tonumber(args.rarity)] == 0 then return end

	wt[#wt+1] = "<div style='text-align:center'>"
	for i,stat_name in ipairs(item.stats.order) do
		wt[#wt+1] = "<div style='margin-top:10px;display:flex;width:100%;flex-direction:row;justify-content:space-between'>"
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div>"
		wt[#wt+1] = string.format("<div>%s %s</div>",stat_name,item.stats[(stat_name):lower()][stat_index(item,args.rarity)] or item.stats[(stat_name):lower()])
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
	end

	if item.numenchants[tonumber(args.rarity)] then
		wt[#wt+1] = "<div class='cr4' style='margin-top:10px;display:flex; width:100%;flex-direction:row; justify-content:space-between'>"
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div>"
		wt[#wt+1] = string.format("<div>Up to %i extra enchantments</div>",item.numenchants[tonumber(args.rarity)])
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
	end

	if item.haspassive or item.isartifact then
		wt[#wt+1] = "<div style='margin-top:10px;display:flex;width:100%;flex-direction:row;justify-content:space-between;color:rgb(211,178,125)'>"
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div>"
		wt[#wt+1] = string.format("<div>%s</div>",item.artifactpower)
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
	end
	wt[#wt+1] = "</div>"
end

local function class_list(list)
	local ret = ""
	for i,v in ipairs(list) do
		if i ~= 1 then ret = ret..", " end
		ret = ret..v
	end
	return ret
end

local function type_list(t,type)
	local ret = ""
	local i = 1
	for k,v in pairs(t) do
		if i ~= 1 then ret = ret..", " end
		if v == type then
			ret = ret..k
		end
		i = i + 1
	end
	return ret
end

local function weapon_rows(rows, args, weapon)
	local index = tonumber(args.rarity)

	rows[#rows+1] = hline()
	stat_block(rows,args,weapon)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v("Required Class",class_list(weapon.classes))
	rows[#rows+1] = row_h("Weapon Type",type_list(weapon.types,"Weapon"))
	rows[#rows+1] = row_h("Utility Type",type_list(weapon.types,"Utility"))
	rows[#rows+1] = row_h("Slot Type",weapon.slottype)
	rows[#rows+1] = row_h("Hand Type",weapon.handtype)
	rows[#rows+1] = row_h("Reload Speed",weapon.reloadtime)
	rows[#rows+1] = row_h("Quiver Size",weapon.maxammocount)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_h("Hitbox",string.format("%sx%sx%s",weapon.hitbox.height,weapon.hitbox.width,weapon.hitbox.depth))

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",weapon.invwidth,weapon.invheight))
	if weapon.maxcount ~= 1 then
		rows[#rows+1] = row_h("Stack Size",weapon.maxcount)
	end
	rows[#rows+1] = row_h("Gear Score",weapon.gearscore[index])
	rows[#rows+1] = row_h("Item Achieve",weapon.ap[index])
	rows[#rows+1] = row_h("Sell Price",weapon.sellprices[index])

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v3(weapon.flavortext)
end

local function armor_rows(rows, args, armor)
	local index = tonumber(args.rarity)

	rows[#rows+1] = hline()
	stat_block(rows,args,armor)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v("Required Class",class_list(armor.classes))
	rows[#rows+1] = row_h("Armor Type",type_list(armor.types,"Armor"))
	rows[#rows+1] = row_h("Slot Type",armor.slottype)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",armor.invwidth,armor.invheight))
	rows[#rows+1] = row_h("Gear Score",armor.gearscore[index])
	rows[#rows+1] = row_h("Item Achieve",armor.ap[index])
	rows[#rows+1] = row_h("Sell Price",armor.sellprices[index])

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v3(armor.flavortext)
end

local function accessory_rows(rows, args, accessory)
	local index = tonumber(args.rarity)

	rows[#rows+1] = hline()
	stat_block(rows,args,accessory)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_h("Slot Type",accessory.slottype)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",accessory.invwidth,accessory.invheight))
	rows[#rows+1] = row_h("Gear Score",accessory.gearscore[index])
	rows[#rows+1] = row_h("Item Achieve",accessory.ap[index])
	rows[#rows+1] = row_h("Sell Price",accessory.sellprices[index])

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v3(accessory.flavortext)

end

local function utility_rows(rows, args, utility)
	error("monster_rows() needs to be implemented")
end

local function misc_rows(rows, args, misc)
	local index = tonumber(args.rarity)

	rows[#rows+1] = hline()
	rows[#rows+1] = row_h("Type",type_list(misc.types,"Misc"))


	rows[#rows+1] = hline()
	rows[#rows+1] = row_v2(string.format("[[File:%sx%sInvSlot.jpg]]",misc.invwidth,misc.invheight))
	if misc.maxcount ~= 1 then
		rows[#rows+1] = row_h("Stack Size",misc.maxcount)
	end
	rows[#rows+1] = row_h("Max Contents",misc.maxcontentscount)
	rows[#rows+1] = row_h("Item Achieve",misc.ap[index])
	rows[#rows+1] = row_h("Sell Price",misc.sellprices[index])

	rows[#rows+1] = hline()
	rows[#rows+1] = row_v3(misc.flavortext)
end

local function monster_rows(rows, args, monster)
	error("monster_rows() needs to be implemented")
end

local function prop_rows(rows, args, prop)
	error("prop_rows() needs to be implemented")
end

local CATEGORY = {	["Weapon"]    = {["Data"]="Data:Weapon.json"   , ["Function"]=weapon_rows},
					["Armor"]     = {["Data"]="Data:Armor.json"    , ["Function"]=armor_rows},
					["Accessory"] = {["Data"]="Data:Accessory.json", ["Function"]=accessory_rows},
					["Utility"]   = {["Data"]="Data:Utility.json"  , ["Function"]=utility_rows},
					["Misc"]      = {["Data"]="Data:Misc.json"     , ["Function"]=misc_rows},
					["Monster"]   = {["Data"]="Data:Monster.json"  , ["Function"]=monster_rows},
					["Prop"]      = {["Data"]="Data:Prop.json"     , ["Function"]=prop_rows}}


local function get_rows(args, data)
	local rows = {}

	if CATEGORY[args.category] then CATEGORY[args.category].Function(rows,args,data)
	else error("Module:Infobox received an invalid category.  Ensure it is capitalized and singular.") end

	return rows
end

local function infobox(args, data)
	local wt = {}

	wt[#wt+1] = "<div style='background-color:rgb(var(--background-color),0.3);max-width:470px;float:right'>" --Infobox container
	wt[#wt+1] = header(args)
	wt[#wt+1] = "<div style='width:280px;border:2px solid rgb(70,70,70,0.5);padding:20px'>" -- Content container
	wt[#wt+1] = image(args)

	-- Category-specific rows
	local rows = get_rows(args, data)
	for _, row in ipairs(rows) do
		wt[#wt+1] = row
	end

	wt[#wt+1] = "</div></div>"

	return concat(wt)
end

local function panel(rarity, args, data)
	if not search(data.rarities,rarity) then return "" end

	local hidden_panel = "cardtabs__panel--js-hidden"
	if args.is_active == rarity then hidden_panel = "" end

	args.rarity = rarity
	return string.format("<div data-cardtabs-panel='%s' style='overflow:auto' class='cardtabs__panel %s'>%s</div>", rarity, hidden_panel, infobox(args, data))
end

local function tab_panels(args, wt, data)
	wt[#wt+1] = "<div class='mytabs__panels' data-cardtabs-panels>"
	wt[#wt+1] = panel("1", args, data)
	wt[#wt+1] = panel("2", args, data)
	wt[#wt+1] = panel("3", args, data)
	wt[#wt+1] = panel("4", args, data)
	wt[#wt+1] = panel("5", args, data)
	wt[#wt+1] = panel("6", args, data)
	wt[#wt+1] = panel("7", args, data)
	wt[#wt+1] = panel("8", args, data)
	wt[#wt+1] = "</div>"
end

local ROMAN_NUMERAL = {"I","II","III","IV","V","VI","VII","VIII"}

local function button(rarity, args, data)
	if not search(data.rarities,rarity) then return "" end

	local is_active_button = ""
	if args.is_active==rarity then is_active_button = " cardtabs__button--active" end

	return string.format("<div data-cardtabs-btn='%s' class='cardtabs__button rarity%s%s'>&nbsp;%s&nbsp;</div>", rarity, rarity, is_active_button, ROMAN_NUMERAL[tonumber(rarity)])
end

local function tab_buttons(args, wt, data)
	wt[#wt+1] = "<div class='cardtabs__buttons' data-cardtabs-btns>"
	wt[#wt+1] = button("1", args, data)
	wt[#wt+1] = button("2", args, data)
	wt[#wt+1] = button("3", args, data)
	wt[#wt+1] = button("4", args, data)
	wt[#wt+1] = button("5", args, data)
	wt[#wt+1] = button("6", args, data)
	wt[#wt+1] = button("7", args, data)
	wt[#wt+1] = button("8", args, data)
	wt[#wt+1] = "</div>"
end

function p.draw(frame)
	local data = mw.loadJsonData(CATEGORY[frame.args.category].Data)
	data = data[frame.args.category][frame.args.name] -- load data of a specific object

	if not frame.args.is_active then frame.args.is_active = data.rarities[1] end -- If missing argument, make the first make the first rarity infobox active

	local wt = {}
	wt[#wt+1] = "<div class='cardtabs' data-cardtabs>"
	tab_buttons(frame.args, wt, data)
	tab_panels(frame.args, wt, data)
	wt[#wt+1] = "</div>"

	return concat(wt)
end

return p

--[=[
mw.log(p.draw({args={name="Halberd",is_active="2",category="Weapon"}}))
mw.log(p.draw({args={name="Bloodthirst",category="Weapon"}}))

mw.log(p.draw({args={name="Golden Scarf",category="Armor"}}))
mw.log(p.draw({args={name="Plate Pants",category="Armor"}}))

mw.log(p.draw({args={name="Grimsmile Ring",category="Accessory"}}))

mw.log(p.draw({args={name="Diamond",category="Misc"}}))
mw.log(p.draw({args={name="Gold Coin Chest",category="Misc"}}))
mw.log(p.draw({args={name="Quiver",category="Misc"}}))
]=]