From Dark and Darker Wiki

(only show passive for artifact or mini artifact)
(monsters variants should show corresponding image now)
 
(9 intermediate revisions by the same user not shown)
Line 55: Line 55:
end
end


local function image(args)
local function image(args, data, rarity)
if not args.name then return end
local image_name = args.name
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>"
local image_size = "90px"
if args.category == "Monster" then
image_size = "200px"
if rarity ~= "Common" then
image_name = image_name.." "..rarity
end
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:"..image_name..".png|"..image_size.."|link=]]</div></div></div>"
end
end


Line 65: Line 73:


local function stat_block(wt, args, item)
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
if args.category == "Monster" then
 
local monster = item
wt[#wt+1] = "<div style='text-align:center'>"
if not monster.name then return end
for i,stat_name in ipairs(item.stats.order) do
wt[#wt+1] = "<div style='text-align:center'>"
wt[#wt+1] = "<div style='margin-top:10px;display:flex;width:100%;flex-direction:row;justify-content:space-between'>"
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] = "<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] = string.format("<div>Health %s</div>", monster.hp)
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
end
wt[#wt+1] = "</div>"


if item.numenchants[tonumber(args.rarity)] then
wt[#wt+1] = "<div style='text-align:center'>"
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='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] = "<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] = string.format("<div>Move Speed %d</div>", monster.move)
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
end
wt[#wt+1] = "</div>"
else
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 and item.isminiartifact or item.isartifact then
if item.haspassive and item.isminiartifact 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>"
wt[#wt+1] = string.format("<div>%s</div>",item.artifactpower)
wt[#wt+1] = string.format("<div>%s</div>",item.artifactpower)
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
end
wt[#wt+1] = "</div>"
end
end
wt[#wt+1] = "</div>"
end
end


Line 192: Line 218:


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


Line 216: Line 242:


local function monster_rows(rows, args, monster)
local function monster_rows(rows, args, monster)
error("monster_rows() needs to be implemented")
rows[#rows+1] = hline()
stat_block(rows,args,monster)
 
rows[#rows+1] = hline()
local ap_type = "Monster Kill"
if monster.boss then ap_type = "Boss Kill"
elseif monster.miniboss then ap_type = "Subboss Kill" end
rows[#rows+1] = row_h(ap_type, monster.ap)
rows[#rows+1] = row_h("Experience Points", monster.xp)
end
end


Line 241: Line 275:
end
end


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


Line 247: Line 281:
wt[#wt+1] = header(args)
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] = "<div style='width:280px;border:2px solid rgb(70,70,70,0.5);padding:20px'>" -- Content container
wt[#wt+1] = image(args)
wt[#wt+1] = image(args, data, rarity)


-- Category-specific rows
-- Category-specific rows
Line 261: Line 295:


local function panel(rarity, args, data)
local function panel(rarity, args, data)
if not search(data.rarities,rarity) then return "" end
if args.category == "Monster" then
local key
local modified_rarity = rarity
if rarity == "Common" then
key = args.name
modified_rarity = "2"
else
key = args.name.."#"..rarity
end
if not data[key] then return "" end


local hidden_panel = "cardtabs__panel--js-hidden"
local hidden_panel = "cardtabs__panel--js-hidden"
if args.is_active == rarity then hidden_panel = "" end
if args.is_active == rarity then hidden_panel = "" end
args.rarity = modified_rarity
return string.format("<div data-cardtabs-panel='%s' style='overflow:auto' class='cardtabs__panel %s'>%s</div>", rarity, hidden_panel, infobox(args, data[key], rarity))
else
if not search(data.rarities,rarity) then return "" end


args.rarity = rarity
local hidden_panel = "cardtabs__panel--js-hidden"
return string.format("<div data-cardtabs-panel='%s' style='overflow:auto' class='cardtabs__panel %s'>%s</div>", rarity, hidden_panel, infobox(args, data))
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
end
end


local function tab_panels(args, wt, data)
local function tab_panels(args, wt, data)
wt[#wt+1] = "<div class='mytabs__panels' data-cardtabs-panels>"
if args.category == "Monster" then
wt[#wt+1] = panel("1", args, data)
wt[#wt+1] = "<div class='mytabs__panels' data-cardtabs-panels>"
wt[#wt+1] = panel("2", args, data)
wt[#wt+1] = panel("Common", args, data)
wt[#wt+1] = panel("3", args, data)
wt[#wt+1] = panel("Elite", args, data)
wt[#wt+1] = panel("4", args, data)
wt[#wt+1] = panel("Nightmare", args, data)
wt[#wt+1] = panel("5", args, data)
wt[#wt+1] = "</div>"
wt[#wt+1] = panel("6", args, data)
else
wt[#wt+1] = panel("7", args, data)
wt[#wt+1] = "<div class='mytabs__panels' data-cardtabs-panels>"
wt[#wt+1] = panel("8", args, data)
wt[#wt+1] = panel("1", args, data)
wt[#wt+1] = "</div>"
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
end
end


Line 286: Line 346:


local function button(rarity, args, data)
local function button(rarity, args, data)
if not search(data.rarities,rarity) then return "" end
if args.category == "Monster" then
local key
if rarity == "Common" then key = args.name else key = args.name.."#"..rarity end
if not data[key] then return "" end
 
local is_active_button = ""
if args.is_active==rarity then is_active_button = " cardtabs__button--active" end


local is_active_button = ""
local modified_rarity = rarity
if args.is_active==rarity then is_active_button = " cardtabs__button--active" end
if rarity == "Common" then modified_rarity = "2" end
return string.format("<div data-cardtabs-btn='%s' class='cardtabs__button rarity%s%s'>&nbsp;%s&nbsp;</div>", rarity, modified_rarity, is_active_button, rarity)
else
if not search(data.rarities,rarity) then return "" 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)])
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
end
end


local function tab_buttons(args, wt, data)
local function tab_buttons(args, wt, data)
wt[#wt+1] = "<div class='cardtabs__buttons' data-cardtabs-btns>"
if args.category == "Monster" then
wt[#wt+1] = button("1", args, data)
wt[#wt+1] = "<div class='cardtabs__buttons' data-cardtabs-btns>"
wt[#wt+1] = button("2", args, data)
wt[#wt+1] = button("Common", args, data)
wt[#wt+1] = button("3", args, data)
wt[#wt+1] = button("Elite", args, data)
wt[#wt+1] = button("4", args, data)
wt[#wt+1] = button("Nightmare", args, data)
wt[#wt+1] = button("5", args, data)
wt[#wt+1] = "</div>"
wt[#wt+1] = button("6", args, data)
else
wt[#wt+1] = button("7", args, data)
wt[#wt+1] = "<div class='cardtabs__buttons' data-cardtabs-btns>"
wt[#wt+1] = button("8", args, data)
wt[#wt+1] = button("1", args, data)
wt[#wt+1] = "</div>"
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
end
end


function p.draw(frame)
function p.draw(frame)
local data = mw.loadJsonData(CATEGORY[frame.args.category].Data)
-- Monster data isn't in the same form as items right now so have to do this, ideally they are collapsed and fully dynamic
data = data[frame.args.category][frame.args.name] -- load data of a specific object
local data
if frame.args.category == "Monster" then
data = mw.loadJsonData(CATEGORY[frame.args.category].Data)
data = data["monster"]["id"]
if not frame.args.is_active then frame.args.is_active = "Common" end -- If missing argument, make the common variant infobox active
else
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 rarity infobox active
end


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 = {}
local wt = {}
Line 336: Line 427:
mw.log(p.draw({args={name="Gold Coin Chest",category="Misc"}}))
mw.log(p.draw({args={name="Gold Coin Chest",category="Misc"}}))
mw.log(p.draw({args={name="Quiver",category="Misc"}}))
mw.log(p.draw({args={name="Quiver",category="Misc"}}))
mw.log(p.draw({args={name="Abomination", category="Monster"}}))
]=]
]=]

Latest revision as of 20:12, 29 August 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 45
-
-
Move Speed -50
-
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 47
-
-
Move Speed -50
-
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 49
-
-
Move Speed -50
-
-
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 51
-
-
Move Speed -50
-
-
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:
30
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 53
-
-
Move Speed -50
-
-
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 55
-
-
Move Speed -50
-
-
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 57
-
-
Move Speed -50
-
-
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:
60
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
-
-
Move Speed -50
-
-
Up to 5 extra enchantments
-
-
Successful weapon attacks sears the target for 12 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 10%
-
-
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 10%
-
-
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 10%
-
-
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 10%
-
-
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 10%
-
-
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 10%
-
-
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 10%
-
-
Agility 5
-
-
Move Speed -2
-
-
Up to 2 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, data, rarity)
	local image_name = args.name
	local image_size = "90px"
	if args.category == "Monster" then
		image_size = "200px"
		if rarity ~= "Common" then
			image_name = image_name.." "..rarity
		end
	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:"..image_name..".png|"..image_size.."|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 args.category == "Monster" then
		local monster = item
		if not monster.name then return end
		wt[#wt+1] = "<div style='text-align:center'>"
		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>Health %s</div>", monster.hp)
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
		wt[#wt+1] = "</div>"

		wt[#wt+1] = "<div style='text-align:center'>"
		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>Move Speed %d</div>", monster.move)
		wt[#wt+1] = "<div style='padding:0px 5px' class='bold'>-</div></div>"
		wt[#wt+1] = "</div>"
	else
		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 and item.isminiartifact 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
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)

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

	if weapon.invwidth ~= "" then
		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])
	end

	if weapon.flavortext ~= "" then
		rows[#rows+1] = hline()
		rows[#rows+1] = row_v3(weapon.flavortext)
	end
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("utility_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)
	rows[#rows+1] = hline()
	stat_block(rows,args,monster)

	rows[#rows+1] = hline()
	local ap_type = "Monster Kill"
	if monster.boss then ap_type = "Boss Kill"
	elseif monster.miniboss then ap_type = "Subboss Kill" end
	rows[#rows+1] = row_h(ap_type, monster.ap)
	rows[#rows+1] = row_h("Experience Points", monster.xp)
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, rarity)
	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, data, rarity)

	-- 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 args.category == "Monster" then
		local key
		local modified_rarity = rarity
		if rarity == "Common" then
			key = args.name
			modified_rarity = "2"
		else 
			key = args.name.."#"..rarity
		end
		if not data[key] then return "" end

		local hidden_panel = "cardtabs__panel--js-hidden"
		if args.is_active == rarity then hidden_panel = "" end
		
		args.rarity = modified_rarity
		return string.format("<div data-cardtabs-panel='%s' style='overflow:auto' class='cardtabs__panel %s'>%s</div>", rarity, hidden_panel, infobox(args, data[key], rarity))
	else
		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
end

local function tab_panels(args, wt, data)
	if args.category == "Monster" then
		wt[#wt+1] = "<div class='mytabs__panels' data-cardtabs-panels>"
		wt[#wt+1] = panel("Common", args, data)
		wt[#wt+1] = panel("Elite", args, data)
		wt[#wt+1] = panel("Nightmare", args, data)
		wt[#wt+1] = "</div>"
	else
		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
end

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

local function button(rarity, args, data)
	if args.category == "Monster" then
		local key
		if rarity == "Common" then key = args.name else key = args.name.."#"..rarity end
		if not data[key] then return "" end

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

		local modified_rarity = rarity
		if rarity == "Common" then modified_rarity = "2" end
	
		return string.format("<div data-cardtabs-btn='%s' class='cardtabs__button rarity%s%s'>&nbsp;%s&nbsp;</div>", rarity, modified_rarity, is_active_button, rarity)	
	else
		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
	
end

local function tab_buttons(args, wt, data)
	if args.category == "Monster" then
		wt[#wt+1] = "<div class='cardtabs__buttons' data-cardtabs-btns>"
		wt[#wt+1] = button("Common", args, data)
		wt[#wt+1] = button("Elite", args, data)
		wt[#wt+1] = button("Nightmare", args, data)
		wt[#wt+1] = "</div>"
	else
		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
end

function p.draw(frame)
	-- Monster data isn't in the same form as items right now so have to do this, ideally they are collapsed and fully dynamic
	local data
	if frame.args.category == "Monster" then
		data = mw.loadJsonData(CATEGORY[frame.args.category].Data)
		data = data["monster"]["id"]
		if not frame.args.is_active then frame.args.is_active = "Common" end -- If missing argument, make the common variant infobox active
	else
		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 rarity infobox active
	end	


	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"}}))

mw.log(p.draw({args={name="Abomination", category="Monster"}}))
]=]