Module:HeroDataArrays

From The Deadlock Wiki
Revision as of 00:08, 26 September 2025 by Gammaton32 (talk | contribs)
Jump to navigation Jump to search

Overview

This module consists of one generic function, heroDataArray, and a series of functions that create specific wikitables using the output from heroDataArray.


local p = {};
local util_module = require('Module:Utilities')
local allHeroData = mw.loadJsonData("Data:HeroData.json")
local soul_unlock = require('Module:SoulUnlock')
local inGameHeroData = {}

-- Just get heroes that are playable
for i, heroData in pairs(allHeroData) do
	if heroData["InDevelopment"] == false then
    if heroData["IsDisabled"] == false then
        table.insert(inGameHeroData, heroData)
        end
    end
end

-- Helper function to round numeric values
local function roundValue(value)
    if type(value) == "number" then
        return util_module.round_to_sig_fig(value, 3)
    end
    return value
end

-- heroDataArray takes as argument a table of any length containing keys or 
-- paths of keys in the HeroData JSON, e.g. {Name, MaxHealth, LevelScaling>Health}.
-- A path of keys should be specified as such, with the ">" character separating
-- subsequent keys.
local heroDataArray = function(args)
    local outData = {}
    
    for i, heroData in ipairs(inGameHeroData) do            -- Iterate over each hero
        local out = {}                                      -- First creating a table to hold data
        for j, key in pairs(args) do                        -- Iterate over each key:
            if string.find(key, ">") ~= nil then            -- If the key is actually a path of keys,
                local node = heroData                       -- start with the biggest node heroData, and
                for k in string.gmatch(key, "([^>]+)") do   -- iterate over each key, splitting on ">",
                    if node and node[k] ~= nil then         -- trying the key as a string e.g. "1", (Added 'node and' for safety)
                        node = node[k]                      
                    elseif node and node[tonumber(k)] ~= nil then -- else using the key as numeric, (Added 'node and' for safety)
                        node = node[tonumber(k)]
                    else                                    -- If at any point the path breaks, the result is nil
                        node = nil
                        break
                    end                                     -- drilling down the JSON node after node
                end
                out[key] = roundValue(node)                 -- until outputting the final node (rounded)
            else
                out[key] = roundValue(heroData[key])        -- or just grab the data if not a path (rounded)
            end
        end
        outData[heroData["Name"]] = out                     -- Save data in the big table of heroes
    end
    return(outData)
end

p.heroHealthTable = function(frame)
    -- Pull data
    local heroHealthData = heroDataArray({"Name", "MaxHealth", "LevelScaling>MaxHealth"})

    -- Input table will be called a, output wikitable will be called z
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Health Stats \n"..
        "! Hero !! Starting !! Added per Boon !! At Max Boon \n"

    -- Iterate over heroes adding a new row to the wikitable for each
    for i,a in pairs(heroHealthData) do
        local maxHealth = a["MaxHealth"] or 0
        local scalingHealth = a["LevelScaling>MaxHealth"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..maxHealth.." || +"..scalingHealth.." || "..
                tostring(roundValue(tonumber(maxHealth) + tonumber(scalingHealth) * soul_unlock.get_max('PowerIncrease'))).." \n"
    end
    
    z = z.."|}"
    return z
end

p.heroRegenTable = function(frame)
    local heroRegenData = heroDataArray({"Name", "BaseHealthRegen"})
    
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Health Regen \n"..
        "! Hero !! HP/s \n"

    for i,a in pairs(heroRegenData) do
        local baseHealthRegen = a["BaseHealthRegen"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..baseHealthRegen.." \n"
    end
    z = z.."|}"
    return z
end

p.heroDpsTable = function(frame)
    local heroDpsData = heroDataArray({"Name","ReloadSingle","ReloadDelay","ReloadTime",
        "ClipSize","RoundsPerSecond","BulletDamage","BulletsPerShot"})
   
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Damage \n"..
        "! Hero !! Reload Delay (s) !! Reload Time (s) !! Ammo !! Bullets per sec !! Bullet Damage !! Bullets Per Shot \n"
        
    for i,a in pairs(heroDpsData) do
    	local reloadDelay = a["ReloadDelay"] or 0
    	local reloadTime = a["ReloadTime"] or 0
    	local clipSize = a["ClipSize"] or 0
    	local roundsPerSecond = a["RoundsPerSecond"] or 0
    	local bulletDamage = a["BulletDamage"] or 0
    	local bulletsPerShot = a["BulletsPerShot"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..reloadDelay.." || "..reloadTime.."  || "..clipSize..
                " || "..roundsPerSecond.." || "..bulletDamage.." || "..bulletsPerShot.." \n"
    end
    z = z.."|}"
    return z
end

p.heroBulletSpeedTable = function(frame)
    local heroBulletSpeedData = heroDataArray({"Name", "BulletSpeed"})
    
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Base Bullet Velocity \n"..
        "! Hero !! m/s \n"

    for i,a in pairs(heroBulletSpeedData) do
    	local bulletSpeed = a["BulletSpeed"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..bulletSpeed.." \n"
    end
    z = z.."|}"
    return z
end

p.heroClipSizeTable = function(frame)
    local heroClipSizeData = heroDataArray({"Name", "ClipSize"})
    
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Base Ammo Count \n"..
        "! Hero !! Ammo \n"

    for i,a in pairs(heroClipSizeData) do
    	local clipSize = a["ClipSize"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..clipSize.." \n"
    end
    z = z.."|}"
    return z
end

p.heroMoveSpeedTable = function(frame)
    local heroMoveSpeedData = heroDataArray({"Name", "MoveSpeed"})
    
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Base Movement Speed \n"..
        "! Hero !! m/s \n"

    for i,a in pairs(heroMoveSpeedData) do
        local moveSpeed = a["MoveSpeed"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..moveSpeed.." \n"
    end
    z = z.."|}"
    return z
end

p.heroRoundsPerSecondTable = function(frame)
    local heroRoundsPerSecondData = heroDataArray({"Name", "RoundsPerSecond"})
    
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Base Fire Rate \n"..
        "! Hero !! Rounds/s \n"

    for i,a in pairs(heroRoundsPerSecondData) do
    	local roundsPerSecond = a["RoundsPerSecond"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..roundsPerSecond.." \n"
    end
    z = z.."|}"
    return z
end

p.heroFalloffRangeTable = function(frame)
    local heroFalloffRangeData = heroDataArray({"Name", "FalloffStartRange", "FalloffEndRange"})
    
    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Base Falloff Range \n"..
        "! Hero !! Minimum Range (m) !! Maximum Range (m)  \n"

    for i,a in pairs(heroFalloffRangeData) do
    	local falloffStartRange = a["FalloffStartRange"] or 0
    	local falloffEndRange = a["FalloffEndRange"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..falloffStartRange.." || "..falloffEndRange.." \n"
    end
    z = z.."|}"
    return z
end

p.heroBulletDamageTable = function(frame)
    -- Pull data
    local heroBulletDamageData = heroDataArray({"Name", "BulletDamage", "LevelScaling>BulletDamage"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Bullet Damage Stats \n"..
        "! Hero !! Starting !! Added per Boon !! At Max Boon \n"

    -- Iterate over heroes adding a new row to the wikitable for each
    for i,a in pairs(heroBulletDamageData) do
        -- FIX: Set default values of 0 if the data is nil to prevent arithmetic errors
    	local bulletDamage = a["BulletDamage"] or 0
    	local scalingDamage = a["LevelScaling>BulletDamage"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                -- Use the safe variables here
                " || "..bulletDamage.." || +"..scalingDamage.." || "..
                -- And use them in the calculation
                tostring(roundValue(tonumber(bulletDamage) + tonumber(scalingDamage) * soul_unlock.get_max('PowerIncrease'))).." \n"
    end
    
    z = z.."|}"
    return z
end

p.heroLightMeleeTable = function(frame)
    -- Pull data
    local heroLightMeleeData = heroDataArray({"Name", "LightMeleeDamage", "LevelScaling>LightMeleeDamage"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Light Melee Stats \n"..
        "! Hero !! Starting !! Added per Boon !! At Max Boon \n"

    -- Iterate over heroes adding a new row to the wikitable for each
    for i,a in pairs(heroLightMeleeData) do
        local lightMeleeDamage = a["LightMeleeDamage"] or 0
        local scalingDamage = a["LevelScaling>LightMeleeDamage"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..lightMeleeDamage.." || +"..scalingDamage.." || "..
                tostring(roundValue(tonumber(lightMeleeDamage) + tonumber(scalingDamage) * soul_unlock.get_max('PowerIncrease'))).." \n"
    end
    
    z = z.."|}"
    return z
end

p.heroHeavyMeleeTable = function(frame)
    -- Pull data
    local heroHeavyMeleeData = heroDataArray({"Name", "HeavyMeleeDamage", "LevelScaling>HeavyMeleeDamage"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Heavy Melee Stats \n"..
        "! Hero !! Starting !! Added per Boon !! At Max Boon \n"

    -- Iterate over heroes adding a new row to the wikitable for each
    for i,a in pairs(heroHeavyMeleeData) do
        local heavyMeleeDamage = a["HeavyMeleeDamage"] or 0
        local scalingDamage = a["LevelScaling>HeavyMeleeDamage"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..heavyMeleeDamage.." || +"..scalingDamage.." || "..
                tostring(roundValue(tonumber(heavyMeleeDamage) + tonumber(scalingDamage) * soul_unlock.get_max('PowerIncrease'))).." \n"
    end
    
    z = z.."|}"
    return z
end

p.heroStaminaTable = function(frame)
    local heroStaminaData = heroDataArray({"Name", "Stamina"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Stamina Stats \n"..
        "! Hero !! Stamina Bars \n"

    for i,a in pairs(heroStaminaData) do
        local stamina = a["Stamina"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..stamina.." \n"
    end
    z = z.."|}"
    return z
end

p.heroDashTable = function(frame)
    local heroDashData = heroDataArray({"Name", "GroundDashDuration"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Dash Speed Stats \n"..
        "! Hero !! Dash Speed \n"

    for i,a in pairs(heroDashData) do
    	local groundDashDuration = a["GroundDashDuration"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..groundDashDuration.."s \n"
    end
    z = z.."|}"
    return z
end

p.heroReloadTable = function(frame)
    local heroReloadData = heroDataArray({"Name", "ReloadTime"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Reload Time Stats \n"..
        "! Hero !! Reload Time \n"

    for i,a in pairs(heroReloadData) do
    	local reloadTime = a["ReloadTime"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                " || "..reloadTime.."s \n"
    end
    z = z.."|}"
    return z
end

p.heroMoveSpeedTable = function(frame)
    local heroMoveSpeedData = heroDataArray({"Name", "MaxMoveSpeed", "SprintSpeed"})

    local z = "{| class=\"wikitable sortable mw-collapsible\" style=\"text-align:center\" \n"..
        "|+ Hero Base Move Speed Stats \n"..
        "! Hero !! Move Speed !! Sprint Speed !! Total Sprint Speed \n"

    for i,a in pairs(heroMoveSpeedData) do
    	local moveSpeed = a["MaxMoveSpeed"] or 0
    	local sprintSpeed = a["SprintSpeed"] or 0
        z = z..
            "|- \n"..
            "| style=\"text-align:left;\" | "..
                frame:expandTemplate{title="PageRef", args={a["Name"]}}..
                 " || "..moveSpeed.." || "..sprintSpeed.." || "..tonumber(moveSpeed) + tonumber(sprintSpeed).." \n"
    end
    z = z.."|}"
    return z
end

return p