Editing Module:ItemData

Warning: You are not logged in. Once you make an edit, a temporary account will be created for you. Learn more. Log in or create an account to continue receiving notifications after this account expires, and to access other features.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision Your text
Line 1: Line 1:
local p = {};
local p = {};
local lang = require "Module:Lang"
local util_module = require "Module:Utilities"
local data = mw.loadJsonData("Data:ItemData.json")
local data = mw.loadJsonData("Data:ItemData.json")


-- A list of item properties that should have a '%' sign appended to their base value.
-- returns the table of a specific item
local percentage_properties = {
function get_json_item(name)
AbilityLifestealPercentHero = true,
for i,v in pairs(data) do
AbilityLifestealPercentHeroPassive = true,
ActivatedFireRate = true,
ActiveBonusFireRate = true,
ActiveBonusLifesteal = true,
ActiveReloadPercent = true,
AirBonusDamageGiven = true,
AirBonusDamageTaken = true,
AirControlPercent = true,
AirMoveIncreasePercent = true,
AllyPercentage = true,
AmbushBonusFireRate = true,
AmbushBonusMeleeDamage = true,
AmmoReloadPercent = true,
BaseAttackDamagePercent = true,
BaseAttackDamagePercentAtMaxDuration = true,
BaseAttackDamagePercentBonus = true,
BonusAbilityDurationPercent = true,
BonusAttackRangePercent = true,
BonusBaseHealth = true,
BonusBulletSpeedPercent = true,
BonusClipSizePercent = true,
BonusDamagePercent = true,
BonusFireRate = true,
BonusHeavyMeleeDamage = true,
BonusMeleeDamagePercent = true,
BonusSoulsPct = true,
BonusZoomPercent = true,
BuffBulletResist = true,
BuffMeleeDamageBoost = true,
BuffTechResist = true,
BulletArmorReduction = true,
BulletDamageReflectedPct = true,
BulletLifestealPercent = true,
BulletProcDeflectionPercent = true,
BulletResist = true,
BulletResistBelowThreshold = true,
BulletResistPerStack = true,
BulletResistReduction = true,
CloseRangeBonusWeaponPower = true,
CooldownBetweenChargeReduction = true,
CooldownReduction = true,
CooldownReductionOnChargedAbilities = true,
CooldownReductionOnHitPct = true,
CooldownReductionPctOnNonHeroes = true,
CritDamagePercent = true,
CurrentHealthDamage = true,
DamagePctVsNonHeroes = true,
DeathImmunityDamageReduction = true,
DeflectionPercent = true,
DotHealthPercent = true,
FervorTechResist = true,
FervorFireRate = true,
FireRatePerKill = true,
FireRateBonus = true,
FireRateSlow = true,
FireRateWhileSliding = true,
GravityScale = true,
GroundDashReductionPercent = true,
HealAmpCastPercent = true,
HealAmpReceivePenaltyPercent = true,
HealAmpRegenPenaltyPercent = true,
HealAmpRegenPercent = true,
HealLifePercentOutOfCombat = true,
HealPercentAmount = true,
HealPercentPerHeadshot = true,
HealthPctDamage = true,
ItemCooldownReduction = true,
ImbueAbilityLifesteal = true,
ImbuedCooldownReduction = true,
LifestealHealPercent = true,
LightMeleeAmmo = true,
LongRangeBonusWeaponPower = true,
MagicIncreasePerStack = true,
MagicResistReduction = true,
MaxArmorStacks = true,
MaxHealthDamage = true,
MaxHealthLossPercent = true,
MaxHealthPercentAsDPS = true,
MaxHPDamage = true,
MaxSlowPercent = true,
MeleeDistanceScale = true,
MeleeResistPercent = true,
ModelScaleGrowthTooltip = true,
MoveWhileShootingSpeedPenaltyReductionPercent = true,
MoveWhileZoomedSpeedPenaltyReductionPercent = true,
MovementSpeedSlow = true,
NonHeroHealPct = true,
NonHeroReductionPercent = true,
NonPlayerBonusWeaponPower = true,
NonPlayerBulletResist = true,
OutgoingDamagePenaltyPercent = true,
ParrySuccessHealPercentage = true,
PercentDamage = true,
ProcBaseAttackDamagePercent = true,
ProcBaseAttackDamagePercentAltFire = true,
ProcChance = true,
ReduceFootstepSound = true,
ReloadSpeedMultipler = true,
ResistStealAmount = true,
RespawnTime = true,
RicochetDamagePercent = true,
SelfModifier = true,
SlideScale = true,
SlowPercent = true,
SlowResistancePercent = true,
SpiritDamageReductionProc = true,
SpiritDamageReflectedPct = true,
StackingTechRangeMultiplier = true,
StackingTechRadiusMultiplier = true,
StaminaCooldownReduction = true,
StatusResistancePercent = true,
TechArmorDamageReduction = true,
TechDamagePercent = true,
TechDamageReduction = true,
TechPowerPercent = true,
TechRadiusMultiplier = true,
TechRadiusMultiplierBuff = true,
TechRangeMultiplier = true,
TechRangeMultiplierBuff = true,
TechResist = true,
TechResistBelowThreshold = true,
WeaponDamagePerStack = true,
WeaponPowerPerStack = true,
}
 
-- Mappings from placeholder tokens (used in descriptions) to the actual
-- flat property keys in Data:ItemData.json
local PROPERTY_KEY_OVERRIDES = {
    ["ArcaneSurgeWindow"] = "AbilityDuration",
    -- Add any other mismatches here as they appear
}
 
local function strip_suffix(value)
if type(value) == "number" then
return tostring(value)
end
if type(value) ~= "string" then
return tostring(value)
end
return value:match("[-%d%.]+") or value
end
 
 
---------------------------------------- Utility functions
 
-- Returns the table of a specific item.
-- Prioritizes active (non-disabled) items if multiple entries share the same name.
-- @function  get_json_item
-- @param      {string}
-- @return    {table}
local function get_json_item(name)
-- First, try to find an active item. This handles cases where a disabled item
-- with the same name exists in the data (e.g., old versions).
for _, v in pairs(data) do
if (v["Name"] == name and (v["IsDisabled"] == false or v["IsDisabled"] == nil)) then
return v -- Return the active item immediately
end
end
 
-- If no active item was found, fall back to finding any item with the name.
-- This preserves functionality for items that are intentionally disabled.
for _, v in pairs(data) do
if (v["Name"] == name) then
if (v["Name"] == name) then
return v
return v
end
end
end
end
return nil
return nil -- Return nil if no item was found at all
end
 
-- Returns an array of item tables that have the same properties
-- @function  get_similar_items
-- @param      {string}
-- @return    {array of tables}
local function get_similar_items(property)
local similarItems = {}
for _, v in pairs(data) do
if (v[property] ~= nil) then
table.insert(similarItems, v)
end
end
return similarItems
end
 
-- Adds commas delimiter to the thousands place
local function Format(amount)
local contentLanguage = mw.language.getContentLanguage()
    local formatted = amount
    if(type(formatted) ~= "number") then return "<span style=\"color:red;\">Cannot format non-number value.</span>" end
    return contentLanguage:formatNum(tonumber(formatted))
end
 
--- Get cost of an item
-- @function  get_cost
-- @param      {string}
-- @return    {number}
local function get_cost(item_name)
local item = get_json_item(item_name)
if(item == nil) then return "<span style=\"color:red;\">Item Not Found.</span>" end
return tonumber(item["Cost"])
end
 
--- Get type/slot/category of an item
-- @function  get_type
-- @param      {string} item_name
-- @param      {boolean} raw (optional)
-- @return    {string}
local function get_type(item_name, raw)
local item = get_json_item(item_name)
if not item then
return "<span style=\"color:red;\">Item Not Found.</span>"
end
 
local slot = item["Slot"]
if not slot then return nil end
 
local key_map = {
Weapon = 'CitadelCategoryWeapon',
Armor = 'CitadelCategoryArmor',
Tech = 'CitadelCategoryTech'
}
 
local key = key_map[slot]
if not key then return nil end
 
if raw then
return lang.get_string(key, "en")
else
return lang.get_string(key)
end
end
end


 
--{{#invoke:ItemData|get_cost|ITEM_NAME}}--
---------------------------------------- Invocable functions
 
--- {{#invoke:ItemData|get_cost|ITEM_NAME}} access point
p.get_cost = function(frame)
p.get_cost = function(frame)
local item_name = frame.args[1]
local item_name = frame.args[1]
return Format(get_cost(item_name))
local item = get_json_item(item_name)
end
if(item == nil) then return "Item Not Found" end
local cost = 0
local cur_item = item
repeat
cost = cost + cur_item["Cost"]
if(cur_item["Components"] == nil) then
break
end
cur_item = data[cur_item["Components"][1]]
until cur_item == nil


-- Module access point
return cost
function p._get_cost(a)
a = tostring(a) or '0'
return get_cost(a)
end
end


-- {{#invoke:ItemData|get_type|ITEM_NAME}} access point
--{{#invoke:ItemData|get_type|ITEM_NAME}}--
p.get_type = function(frame)
p.get_type = function(frame)
local item_name = frame.args[1]
local item_name = frame.args[1]
-- Accept 'raw' as string "true" (case sensitive)
local item = get_json_item(item_name)
local raw = frame.args['raw'] == 'true'
if(item == nil) then return "Item Not Found" end
return get_type(item_name, raw)
end
if (item["Slot"] == "Weapon") then
 
return "Weapon"
-- Module access point
elseif (item["Slot"] == "Armor") then
function p._get_type(a)
return "Vitality"
a = tostring(a) or ""
elseif (item["Slot"] == "Tech") then
return get_type(a)
return "Spirit"
else
return nil
end
end
end


Line 272: Line 52:
local item_name = frame.args[1]
local item_name = frame.args[1]
local item = get_json_item(item_name)
local item = get_json_item(item_name)
if(item == nil) then return "<span style=\"color:red;\">Item Not Found.</span>" end
if(item == nil) then return "Item Not Found" end
if (item["Activation"] == "Passive") then
if (item["Activation"] == "Passive") then
Line 284: Line 64:
--check Data:ItemData.json for properties
--check Data:ItemData.json for properties
p.get_prop = function(frame)
p.get_prop = function(frame)
    local item_name = frame.args[1]
local item_name = frame.args[1]
    local property = frame.args[2]
local property = frame.args[2]
    local raw = frame.args.raw == 'true'
local item = get_json_item(item_name)
    local item = get_json_item(item_name)
if(item == nil) then return "Item Not Found" end
    if(item == nil) then return "<span style=\"color:red;\">Item Not Found.</span>" end
 
return item[property]
    -- Look up property directly; if missing, try the override table
    local prop_value = item[property]
    if prop_value == nil and PROPERTY_KEY_OVERRIDES[property] then
        prop_value = item[ PROPERTY_KEY_OVERRIDES[property] ]
    end
    if (prop_value == nil) then return nil end
 
local display_value
local scaling_str = "" -- Default to an empty string for non-scaled values
 
-- Determine the base value and scaling string (if any)
if(type(prop_value) == "table") then
if prop_value["Value"] ~= nil and prop_value["Scale"] ~= nil and prop_value["Scale"]["Value"] ~= nil and prop_value["Scale"]["Type"] ~= nil then
-- This is a structured attribute with scaling data
display_value = raw and strip_suffix(prop_value["Value"]) or tostring(prop_value["Value"])
if not raw then
local scale_val = tonumber(prop_value["Scale"]["Value"])
if scale_val ~= 0 then
local scale_type = prop_value["Scale"]["Type"]
local rounded_scale_val = util_module.round_to_sig_fig(scale_val, 2)
 
local template_title
if scale_type == "power_increase" then
template_title = "Template:Boon"
else
template_title = "Template:Ss"
end
 
local template_args = { [1] = rounded_scale_val }
-- Add a space before the scaling template for proper separation
scaling_str = " " .. mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
end
end
else
-- This is a simple list (e.g., TargetTypes), handle and return it directly
local tableValues = {}
for _, v in pairs(prop_value) do
table.insert(tableValues, raw and strip_suffix(v) or tostring(v))
end
return table.concat(tableValues, ", ")
end
else
-- This is a simple, non-table property
display_value = raw and strip_suffix(prop_value) or tostring(prop_value)
end
 
if raw then
return display_value
end
 
-- Assemble the final string, adding the '%' sign if necessary
if percentage_properties[property] == true then
return display_value .. "%" .. scaling_str
else
return display_value .. scaling_str
end
end
end


p.get_component_name = function(frame)
p.get_component_name = function(frame)
local item_name = frame.args[1]
local item_name = frame.args[1]
local slot_arg = frame.args[2]
local item = get_json_item(item_name)
local item = get_json_item(item_name)
if(item == nil) then return "<span style=\"color:red;\">Item Not Found.</span>" end
if(item == nil) then return "Item Not Found" end
local components = item['Components']
local components = item['Components']
--return empty string if no component found
--return empty string if no component found
if(components == nil) then return nil end
if(item == nil) then return "" end
local slot = tonumber(slot_arg) or 1
local component_key = components[slot]
if (component_key == nil) then return nil end
local component = data[component_key]
local component = data[component_key]
if (component == nil or component["IsDisabled"] == true) then return nil end
local component = get_json_item(components[1])
return component['Name']
return component['Name']
end
-- {{Items count}} access point
function p.get_headcount(frame)
local item_type = frame.args[1]
local iter = 0
local tbl = get_similar_items("IsDisabled")
for _, v in ipairs(tbl) do
if item_type == "Standard" then
-- return only regular items
    if (v["IsDisabled"] == false and v["Slot"] ~= nil and v["StreetBrawl"] == false and v["Name"] ~= nil) then
iter = iter + 1
  end
elseif item_type == "Street Brawl" then
-- return only street brawl items
        if (v["IsDisabled"] == false and v["Slot"] ~= nil and v["StreetBrawl"] == true and v["Name"] ~= nil) then
iter = iter + 1
  end
  end
end
return iter
end
   
-- Gets the codename (the key in the JSON data) for a given item's display name.
-- Prioritizes active items to handle cases where disabled duplicates exist.
p.get_codename = function(frame)
local name = frame.args[1]
-- First, try to find an active item.
for k, v in pairs(data) do
if (v["Name"] == name and (v["IsDisabled"] == false or v["IsDisabled"] == nil)) then
return k -- Return the codename of the active item
end
end
-- If no active item was found, fall back to finding any item with the name.
for k, v in pairs(data) do
if (v["Name"] == name) then
return k
end
end
return nil -- Return nil if no item was found at all
end
-- {{#invoke:ItemData|get_property_upgrade|ITEM_NAME|PROPERTY}} --
p.get_property_upgrade = function(frame)
local item_name = frame.args[1]
local property = frame.args[2]
local raw = frame.args.raw == 'true'
local item = get_json_item(item_name)
if item == nil then
return "<span style=\"color:red;\">Item Not Found.</span>"
end
local upgrades = item["PropertyUpgrades"]
if upgrades == nil then return nil end
local value = upgrades[property]
if value == nil then return nil end
local result = raw and strip_suffix(value) or tostring(value)
if raw then
return result
end
-- Append % if this property is percentage-based
if percentage_properties[property] == true then
return result .. "%"
else
return result
end
end
-- Helping function for [[Module:Enhanced]]
function p.get_prop_meta(item_name, property)
local item = get_json_item(item_name)
if not item then return nil end
local raw = item[property]
if raw == nil then return nil end
local meta = {
unit = nil,    -- "%", "m", "s" or nil
scale = nil    -- { type = "Ss"/"Boon", value = number } or nil
}
if percentage_properties[property] then
meta.unit = "%"
end
if type(raw) == "table"
and raw.Scale
and raw.Scale.Value
and raw.Scale.Type
then
local scale_val = tonumber(raw.Scale.Value)
if scale_val and scale_val ~= 0 then
meta.scale = {
type = raw.Scale.Type == "power_increase" and "Boon" or "Ss",
value = util_module.round_to_sig_fig(scale_val, 2)
}
end
end
return meta
end
-- Builds Into functions
-- Helper: accepts item key or display name, returns the key used in data table
local function get_codename_from_input(input)
if data[input] then return input end
for k, v in pairs(data) do
if v["Name"] == input and (v["IsDisabled"] == false or v["IsDisabled"] == nil) then
return k
end
end
for k, v in pairs(data) do
if v["Name"] == input then return k end
end
return nil
end
-- Core logic: returns table of keys that have this item in their Components
local function get_component_of(item_input)
local target_key = get_codename_from_input(item_input)
if not target_key then return {} end
local parents = {}
for key, item in pairs(data) do
if item.IsDisabled ~= true and item.Components and type(item.Components) == "table" then
for _, comp in ipairs(item.Components) do
if comp == target_key then
table.insert(parents, key)
break
end
end
end
end
table.sort(parents)
return parents
end
-- Template: {{#invoke:ItemData|get_builds_into_count|ITEM_NAME}}
p.get_builds_into_count = function(frame)
local item = frame.args[1]
return #get_component_of(item)
end
-- Template: {{#invoke:ItemData|get_builds_into_name|ITEM_NAME|INDEX}}
p.get_builds_into_name = function(frame)
local item = frame.args[1]
local idx = tonumber(frame.args[2]) or 1
local parents = get_component_of(item)
local key = parents[idx]
return key and data[key] and data[key]["Name"] or ""
end
-- Template: {{#invoke:ItemData|get_builds_into|ITEM_NAME}}
-- Returns fully rendered ItemIcon templates
p.get_builds_into = function(frame)
local item = frame.args[1]
local parents = get_component_of(item)
if #parents == 0 then return "" end
local and_word = frame:preprocess("{{#invoke:Dictionary|translate|And}}")
and_word = mw.ustring.lower(and_word)
local parts = {}
for _, key in ipairs(parents) do
local name = data[key] and data[key]["Name"] or key
local icon = mw.getCurrentFrame():expandTemplate{ title = "ItemIcon", args = { name } }
table.insert(parts, icon)
end
if #parts == 1 then return parts[1] end
if #parts == 2 then
return parts[1] .. " " .. and_word .. " " .. parts[2]
end
local last = table.remove(parts)
return table.concat(parts, ", ") .. ", " .. and_word .. " " .. last
end
end


return p
return p
Please note that all contributions to The Deadlock Wiki are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see Deadlock:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template