Module:Sandbox/LVL

From The Deadlock Wiki
Revision as of 15:34, 29 August 2025 by LVL (talk | contribs)
Jump to navigation Jump to search

Documentation for this module may be created at Module:Sandbox/LVL/doc

local p = {};

-- Load the data from the wiki's JSON pages
local heroes_data = mw.loadJsonData("Data:HeroData.json")
local soul_unlocks_data = mw.loadJsonData("Data:SoulUnlockData.json")

-- A mapping to make the table headers more readable
local level_scaling_key_to_name = {
	BulletDamage = "Bullet Damage",
	MaxHealth = "Health",
	TechPower = "Spirit Power",
	LightMeleeDamage = "Light Melee Damage",
	HeavyMeleeDamage = "Heavy Melee Damage"
}

-- Data for special alternate fire modes not found in HeroData.json
local alt_fires = {
	Shiv = {base = 55.2, level = 2.64, suffix = "alt fire 12 pellets"},
	Viscous = {base = 63, level = 0.9, suffix = "alt fire AOE"},
	Yamato = {base = 63.36, level = 0.35, suffix = "alt fire AOE"}
}

-- This is the main function that will be called from your sandbox page.
-- It generates the HTML for the input box and the interactive table.
p.write_power_increase_table = function(frame)
	-- Calculate the maximum number of boons by counting entries with "PowerIncrease"
	local pi_souls_list = {}
	for _, v in ipairs(soul_unlocks_data) do
		if (v["PowerIncrease"]) then
			table.insert(pi_souls_list, v["RequiredSouls"])
		end
	end
	local max_boons = #pi_souls_list
	
	-- Filter out any disabled heroes
	local filtered_heroes = {}
	for _, hero in pairs(heroes_data) do
		if (not hero["IsDisabled"]) then
			table.insert(filtered_heroes, hero)
		end
	end
	
	local property = frame.args[1] -- The stat we are calculating, e.g., "BulletDamage"
	local name = level_scaling_key_to_name[property]
	
	-- Create a unique ID for the table so the JavaScript can find it
	local table_id = "scaling-table-" .. property
	
	-- Create the table element with standard wiki classes and our unique ID
	local create_table = mw.html.create("table"):addClass("wikitable sortable"):attr("id", table_id)
	
	-- Create the header row for the table
	local header_row = mw.html.create("tr")
	header_row
		:tag("th"):wikitext("Hero"):done()
		:tag("th"):wikitext("Base " .. name):done()
		:tag("th"):wikitext("Increase per Boon"):done()
		-- The header for the "Total" column includes a span that will be updated by JavaScript
		:tag("th"):wikitext("Total (at <span class=\"boon-count-display\">0</span> Boons)"):done()
	create_table:node(header_row)
	
	-- Loop through each hero to create a row for them in the table
	for _, hero in ipairs(filtered_heroes) do
		local base = (hero[property] or 0)
		local level_scaling = hero["LevelScaling"] and hero["LevelScaling"][property] or 0
		local level = level_scaling
		
		local shots = (hero["BulletsPerShot"] or 1)
		local burst = (hero["BulletsPerBurst"] or 1)
		local bullet_mult = shots * burst
		local hero_icon = frame:expandTemplate{ title = "HeroIcon", args = {hero["Name"]}}
		local hero_suffix = ""
		
		-- Special handling for bullet damage with multiple pellets/bursts
		if (property == "BulletDamage" and bullet_mult > 1) then
			if (not hero["HitOnceAcrossAllBullets"]) then
				base = base * bullet_mult
				level = level * bullet_mult
			end

			if (shots > 1) then hero_suffix = hero_suffix .. " (" .. shots .. " pellets)" end
			if (burst > 1) then hero_suffix = hero_suffix .. " (" .. burst .. " bullets)" end
		end
		
		local hero_row = mw.html.create("tr")
		
		-- Add the data-base and data-level attributes to the row for the JavaScript to read
		hero_row
			:attr("data-base", base)
			:attr("data-level", level)
			:tag("td"):wikitext(hero_icon .. " " .. hero["Name"] .. hero_suffix):done()
			:tag("td"):wikitext(string.format("%.2f", base)):done()
			:tag("td"):wikitext("+" .. string.format("%.2f", level)):done()
			-- Add a placeholder cell for the total, with a class for JS to find
			:tag("td"):addClass("total-value"):wikitext(string.format("%.2f", base)):done()
		
		create_table:node(hero_row)
		
		-- If the hero has a special alt-fire, create a separate row for it
		if (property == "BulletDamage" and alt_fires[hero["Name"]] ~= nil) then
			local alt_fire = alt_fires[hero["Name"]]
			local alt_base = alt_fire["base"]
			local alt_level = alt_fire["level"]
			local alt_suffix = " (''" .. alt_fire["suffix"] .. "'')"
			
			local alt_fire_row = mw.html.create("tr")
			
			-- Add data attributes for the alt-fire row as well
			alt_fire_row
				:attr("data-base", alt_base)
				:attr("data-level", alt_level)
				:tag("td"):wikitext(hero_icon .. " ''↳ Alt-fire''" .. alt_suffix):done()
				:tag("td"):wikitext(string.format("%.2f", alt_base)):done()
				:tag("td"):wikitext("+" .. string.format("%.2f", alt_level)):done()
				:tag("td"):addClass("total-value"):wikitext(string.format("%.2f", alt_base)):done()
			
			create_table:node(alt_fire_row)
		end
	end
	
	-- Create a container div to hold both the input controls and the table
	local container = mw.html.create("div"):addClass("scaling-calculator-container")
	
	local input_id = "boon-input-" .. property
	
	-- Create the HTML for the input box and its label
	local input_controls = mw.html.create("div"):addClass("boon-input-controls")
	input_controls
		:tag("label"):attr("for", input_id):wikitext("Number of Boons: "):done()
		:tag("input")
			:attr("type", "number")
			:attr("id", input_id)
			:attr("value", 0)
			:attr("min", 0)
			:attr("max", max_boons) -- Use the max_boons we calculated
			:css("width", "60px")
			:done()
	
	-- Add the input controls and the table to the container
	container:node(input_controls)
	container:node(create_table)
	
	-- Return the complete HTML for the component
	return frame:extensionTag{ name = 'nowiki', content = tostring(container) }
end

return p