Editing Module:Infobox item

Jump to navigation Jump to search
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 4: Line 4:
local data = mw.loadJsonData("Data:ItemCards.json")
local data = mw.loadJsonData("Data:ItemCards.json")
local stat_links = mw.loadJsonData("Data:StatLinks.json")
local stat_links = mw.loadJsonData("Data:StatLinks.json")
local ATTR_TYPE_ICON_MAP = require("Module:Icon/attr")


-- Local references for hot-path globals
-- Local references for hot-path globals
Line 15: Line 14:
local tostring = tostring
local tostring = tostring
local type = type
local type = type
-- Status Effect Icon Map
local STATUS_EFFECT_ICON_MAP = {
    StatusEffectDisarmed = {img='Status_Disarm.png',        link='Disarm',  color='Red'},
    StatusEffectEMP      = {img='Status_Silence.png',      link='Silence',  color='Purple'},
    StatusEffectInvisible= {img='Invisible.png',            link='Invisible',color='Green'},
    StatusEffectStun    = {img='Status_Stun.png',          link='Stun',    color='NoColor'},
    StatusEffectSlow    = {img='Status_Movement_Slow.png', link='Slow',    color='Purple'},
}


-- Pre-computed constants
-- Pre-computed constants
Line 29: Line 19:
     .. " [[{{#invoke:Lang|get_string|Citadel_StatusEffect}}]]"
     .. " [[{{#invoke:Lang|get_string|Citadel_StatusEffect}}]]"


-- Property keys to completely ignore during processing
-- Spirit damage constants
local IGNORED_PROP_KEYS = {
local SPIRIT_ICON = "[[File:Spirit_damage.png|12px]]"
    BuildUpPerShot = true,
local SPIRIT_COLOR = "#bc8ee8"
}
local SPIRIT_LINK = "Spirit Damage"


-- Label key remapping table (replaces if/elseif chain)
-- Label key remapping table (replaces if/elseif chain)
local LABEL_KEY_REMAP = {
local LABEL_KEY_REMAP = {
    BuildUpPerShot = "BuildupPerShot",
     DotDuration    = "DOTDuration",
     DotDuration    = "DOTDuration",
}
-- Item name override mapping (old name -> new name)
local ITEM_NAME_OVERRIDES = {
    ["debuff remover"] = "Dispel Magic",
    ["backstabber"] = "Stalker",
}
}


Line 69: Line 54:


local conditional_label -- lazily initialised
local conditional_label -- lazily initialised
--------------------------------------------------------------------------------
-- Item name resolution
--------------------------------------------------------------------------------
local function resolve_item_name(name)
    -- Check if there's an override for this name (case-insensitive)
    local lowercase_name = name:lower()
    local override = ITEM_NAME_OVERRIDES[lowercase_name]
    if override then
        return override
    end
   
    -- If no override, try to find the item in data and return its proper Name
    -- First try direct key lookup
    if data[name] and not data[name].IsDisabled then
        return data[name].Name or name
    end
   
    -- Then try case-insensitive search by Name field
    local lowercase_search = name:lower()
    for _, v in pairs(data) do
        if v.Name and v.Name:lower() == lowercase_search and not v.IsDisabled then
            return v.Name
        end
    end
   
    -- Fallback to original name
    return name
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 117: Line 72:


local function get_json_item(name)
local function get_json_item(name)
    -- Apply name override before lookup
     local direct = data[name]
    local resolved_name = resolve_item_name(name)
   
     local direct = data[resolved_name]
     if direct and not direct.IsDisabled then return direct end
     if direct and not direct.IsDisabled then return direct end


     local fallback
     local fallback
     for _, v in pairs(data) do
     for _, v in pairs(data) do
         if v.Name == resolved_name then
         if v.Name == name then
             if not v.IsDisabled then return v end
             if not v.IsDisabled then return v end
             fallback = fallback or v
             fallback = fallback or v
Line 177: Line 129:


local function get_component_of_sorted(item_input)
local function get_component_of_sorted(item_input)
    -- Apply name override before processing
    local resolved_input = resolve_item_name(item_input)
   
     local target_key
     local target_key
     if data[resolved_input] then
     if data[item_input] then
         target_key = resolved_input
         target_key = item_input
     else
     else
         for k, v in pairs(data) do
         for k, v in pairs(data) do
             if v.Name == resolved_input and not v.IsDisabled then
             if v.Name == item_input and not v.IsDisabled then
                 target_key = k
                 target_key = k
                 break
                 break
Line 233: Line 182:
end
end


local function append_label(val_str, prop_key, label, attr_link, link_override, is_main)
local function append_label(val_str, prop_key, label, label_color, link_override)
     if label == "" then return val_str end
     if label == "" then return val_str end
 
     local display_label
     -- Resolve link priority: Override > JSON Stat Link > Attribute Map Link
     local link_page = link_override or stat_links[prop_key]
     local link_target = link_override
     if link_page then
    if not link_target or link_target == "" then
         if link_page == label then
        link_target = stat_links[prop_key]
     end
    if not link_target or link_target == "" then
        link_target = attr_link
    end
 
    -- Construct label with link if valid
    local display_label = label
    if link_target and link_target ~= "" then
         if link_target == label then
             display_label = "[[" .. label .. "]]"
             display_label = "[[" .. label .. "]]"
         else
         else
             display_label = "[[" .. link_target .. "|" .. label .. "]]"
             display_label = "[[" .. link_page .. "|" .. label .. "]]"
         end
         end
    else
        display_label = label
     end
     end
 
     if label_color then
    -- Place label on a new line only for Main stats
         display_label = '<span style="color:' .. label_color .. '">'
     if is_main then
            .. display_label .. '</span>'
         return val_str .. "<br>" .. display_label
    else
        return val_str .. " " .. display_label
     end
     end
    return val_str .. " " .. display_label
end
end


Line 271: Line 210:
     if not conditional_label then
     if not conditional_label then
         conditional_label = format(
         conditional_label = format(
             '<span style="color:#C0C0C0">%s</span>',
             ' <span style="color:#C0C0C0">(%s)</span>',
             lang.get_string("Citadel_Shop_ConditionalAttribute")
             lang.get_string("Citadel_Shop_ConditionalAttribute")
         )
         )
     end
     end
    -- Place conditional text on a new line
     return val_str .. conditional_label
     return val_str .. "<br>" .. conditional_label
end
end


Line 286: Line 224:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Attribute Icon/Style detection helper
-- Spirit damage detection helper
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local function resolve_attr_style(css_type)
local function is_spirit_damage(prop_key, css_type)
     if not css_type then return nil end
     return prop_key == "Damage" and css_type == "tech_damage"
    local attr = ATTR_TYPE_ICON_MAP[css_type]
    if not attr then return nil end
 
    local color = attr.color or "Grey" -- Fallback color
    local img = attr.img or "GenericProperty.png"
    local link = attr.link
    local size = attr.size -- Optional
 
    -- Construct icon using the defined color template: {{Icon/Color|img|size|link=link}}
    local icon_str
    if size and size ~= "" then
        icon_str = format("{{Icon/%s|[[File:%s|%spx|link=%s]]}}", color, img, size, link or "")
    else
        icon_str = format("{{Icon/%s|[[File:%s|%spx|link=%s]]}}", color, img, 18, link or "")
    end
 
    return {
        icon = icon_str,
        link = link
    }
end
 
--------------------------------------------------------------------------------
-- Status Effect Icon helper
--------------------------------------------------------------------------------
 
local function resolve_status_effect_icon(prop_key)
    local effect_config = STATUS_EFFECT_ICON_MAP[prop_key]
    if not effect_config then return nil end
 
    local color = effect_config.color or "NoColor"
    local img = effect_config.img or "GenericProperty.png"
    local link = effect_config.link
 
    -- Construct icon using the defined color template
    local icon_str = format(
        "{{Icon/%s|[[File:%s|18px|link=%s]]}}",
        color, img, link or ""
    )
 
    return {
        icon = icon_str,
        link = link
    }
end
end


Line 342: Line 236:


local function format_value(prop_key, value, css_type, loc_override,
local function format_value(prop_key, value, css_type, loc_override,
                             skip_label, allow_conditional, usage_flags, scale_info,
                             skip_label, allow_conditional, usage_flags, scale_info)
                            disable_attr, is_main)
     local numeric_val = extract_numeric(value)
     local numeric_val = extract_numeric(value)
     if not numeric_val then return nil end
     if not numeric_val then return nil end
Line 374: Line 267:
     end
     end


     -- Attribute styling (Icon via template) based on css_type
     -- Spirit damage: prepend icon before the value
     local attr_style
     local spirit = is_spirit_damage(prop_key, css_type)
    if not disable_attr then
     if spirit then
        attr_style = resolve_attr_style(css_type)
         val_str = SPIRIT_ICON .. " " .. val_str
    end
   
     if attr_style and attr_style.icon then
         val_str = attr_style.icon .. " " .. val_str
     end
     end


     val_str = append_label(val_str, label_key, label,
     val_str = append_label(val_str, label_key, label,
         attr_style and attr_style.link or nil,
         spirit and SPIRIT_COLOR or nil,
         nil, is_main) -- link_override not used here in base calls
         spirit and SPIRIT_LINK or nil)
 
     return append_conditional(val_str, allow_conditional, usage_flags)
     return append_conditional(val_str, allow_conditional, usage_flags)
end
end
Line 397: Line 285:
local function format_value_enhanced(item_name, prop_key, value, css_type,
local function format_value_enhanced(item_name, prop_key, value, css_type,
                                     loc_override, skip_label,
                                     loc_override, skip_label,
                                     allow_conditional, usage_flags,
                                     allow_conditional, usage_flags)
                                    disable_attr, is_main)
     local numeric_val = extract_numeric(value)
     local numeric_val = extract_numeric(value)
     if not numeric_val then return nil end
     if not numeric_val then return nil end
Line 440: Line 327:
     end
     end


     -- Attribute styling (Icon via template) based on css_type
     -- Spirit damage: prepend icon before the value
     local attr_style
     local spirit = is_spirit_damage(prop_key, css_type)
    if not disable_attr then
     if spirit then
        attr_style = resolve_attr_style(css_type)
         val_str = SPIRIT_ICON .. " " .. val_str
    end
 
     if attr_style and attr_style.icon then
         val_str = attr_style.icon .. " " .. val_str
     end
     end


     val_str = append_label(val_str, label_key, label,
     val_str = append_label(val_str, label_key, label,
         attr_style and attr_style.link or nil,
         spirit and SPIRIT_COLOR or nil,
         nil, is_main)
         spirit and SPIRIT_LINK or nil)
 
     return append_conditional(val_str, allow_conditional, usage_flags)
     return append_conditional(val_str, allow_conditional, usage_flags)
end
end
--------------------------------------------------------------------------------
-- Status Effect formatting helper
--------------------------------------------------------------------------------
local function format_status_effect(prop_key)
    local lang_str = format("[[{{#invoke:Lang|get_string|Citadel_%s}}]]", prop_key)
        .. " [[{{#invoke:Lang|get_string|Citadel_StatusEffect}}]]"
   
    -- Get icon for this status effect
    local icon_style = resolve_status_effect_icon(prop_key)
    if icon_style and icon_style.icon then
        return icon_style.icon .. " " .. lang_str
    end
   
    return lang_str
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Tooltip builder helpers
-- Tooltip builder helpers
Line 494: Line 358:
end
end


local function process_stat_list(lines, param_fmt, counter, start_index,
local function process_stats(lines, fmt, counter, start_index, prop_list,
                                prop_list, seen, formatter)
                            item_name, seen, formatter)
     local stat_index = start_index
     local stat_index = start_index
     for _, prop_obj in ipairs(prop_list or {}) do
     for _, prop_obj in ipairs(prop_list or {}) do
         local key = prop_obj.Key
         local key = prop_obj.Key
         if not seen[key] and not IGNORED_PROP_KEYS[key] and (
         if not seen[key] and (
             key:match("^StatusEffect")
             key:match("^StatusEffect")
             or is_property_in_lang_data(key, prop_obj.LocTokenOverride)
             or is_property_in_lang_data(key, prop_obj.LocTokenOverride)
Line 505: Line 369:
             local val = formatter(prop_obj)
             local val = formatter(prop_obj)
             if val then
             if val then
                 insert(lines, format(param_fmt, counter, stat_index, val))
                 insert(lines, format(fmt, counter, stat_index, val))
                 stat_index = stat_index + 1
                 stat_index = stat_index + 1
                 seen[key] = true
                 seen[key] = true
Line 513: Line 377:
     return stat_index
     return stat_index
end
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Unified tooltip builder (handles both default and enhanced modes)
-- Unified tooltip builder (handles both default and enhanced modes)
Line 520: Line 383:
     local item_name = frame.args[1]
     local item_name = frame.args[1]
     if not item_name then return "Item name missing" end
     if not item_name then return "Item name missing" end
    -- Resolve the item name (apply override if exists)
    local resolved_name = resolve_item_name(item_name)


     local item = get_json_item(item_name)
     local item = get_json_item(item_name)
Line 533: Line 393:
         insert(lines, "| enhanced = true")
         insert(lines, "| enhanced = true")
     end
     end
    -- Use resolved name for item_name parameter
     insert(lines, "| item_name = " .. item_name)
     insert(lines, "| item_name = " .. resolved_name)


     if item.StreetBrawl == true then
     if item.StreetBrawl == true then
         insert(lines, "| street_brawl = true")
         insert(lines, "| street_brawl = true")
    end
   
    -- Pass through nocat arg to the Infobox item template if provided
    local nocat = frame.args.nocat
    if nocat and nocat ~= "" then
        insert(lines, "| nocat = " .. nocat)
     end
     end


Line 549: Line 402:


     ------------------------------------------------------------------
     ------------------------------------------------------------------
     -- Innate stats (Main and Alt merged into item_stat sequentially)
     -- Innate stats
     ------------------------------------------------------------------
     ------------------------------------------------------------------
     local innate_index = 1
     local innate_index = 1
Line 555: Line 408:
         if section.Type == "Innate" then
         if section.Type == "Innate" then
             for _, obj in ipairs(section.Main or {}) do
             for _, obj in ipairs(section.Main or {}) do
                 if not IGNORED_PROP_KEYS[obj.Key] and is_property_in_lang_data(obj.Key, obj.LocTokenOverride) then
 
                 if is_property_in_lang_data(obj.Key, obj.LocTokenOverride) then
                     local val
                     local val
                     if enhanced then
                     if enhanced then
                         val = format_value_enhanced(
                         val = format_value_enhanced(item_name, obj.Key, obj.Value, obj.Type, obj.LocTokenOverride, nil, false, obj.UsageFlags)
                            resolved_name, obj.Key, obj.Value, obj.Type,  
                            obj.LocTokenOverride, nil, false, obj.UsageFlags,
                            true -- disable_attr
                        )
                     else
                     else
                         val = format_value(
                         val = format_value(obj.Key, obj.Value, obj.Type, obj.LocTokenOverride, false, false, obj.UsageFlags, obj.Scale)
                            obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,  
                            false, false, obj.UsageFlags, obj.Scale,
                            true -- disable_attr
                        )
                     end
                     end
                     if val then
                     if val then
Line 577: Line 423:
             end
             end
             for _, obj in ipairs(section.Alt or {}) do
             for _, obj in ipairs(section.Alt or {}) do
                 if not IGNORED_PROP_KEYS[obj.Key] and is_property_in_lang_data(obj.Key, obj.LocTokenOverride) then
 
                 if is_property_in_lang_data(obj.Key, obj.LocTokenOverride) then
                     local val
                     local val
                     if enhanced then
                     if enhanced then
                         val = format_value_enhanced(
                         val = format_value_enhanced(
                             resolved_name, obj.Key, obj.Value, obj.Type,
                             item_name, obj.Key, obj.Value, obj.Type,
                             obj.LocTokenOverride, nil, false, obj.UsageFlags,
                             obj.LocTokenOverride, nil, false, obj.UsageFlags
                            true -- disable_attr
                         )
                         )
                     else
                     else
                         val = format_value(
                         val = format_value(
                             obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,
                             obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,
                             false, false, obj.UsageFlags, obj.Scale,
                             false, false, obj.UsageFlags, obj.Scale
                            true -- disable_attr
                         )
                         )
                     end
                     end
Line 602: Line 447:


     ------------------------------------------------------------------
     ------------------------------------------------------------------
     -- Build formatters once (closures capture resolved_name)
     -- Build formatters once (closures capture item_name)
     ------------------------------------------------------------------
     ------------------------------------------------------------------
     local main_formatter, alt_formatter
     local main_formatter, alt_formatter
Line 609: Line 454:
         main_formatter = function(obj)
         main_formatter = function(obj)
             if obj.Key:match("^StatusEffect") then
             if obj.Key:match("^StatusEffect") then
                 return format_status_effect(obj.Key)
                 return format(STATUS_FMT, obj.Key)
             end
             end
             return format_value_enhanced(
             return format_value_enhanced(
                 resolved_name, obj.Key, obj.Value, obj.Type,
                 item_name, obj.Key, obj.Value, obj.Type,
                 obj.LocTokenOverride, false, true, obj.UsageFlags, nil, true
                 obj.LocTokenOverride, false, true, obj.UsageFlags
             )
             )
         end
         end
         alt_formatter = function(obj)
         alt_formatter = function(obj)
            if obj.Key:match("^StatusEffect") then
 
                return format_status_effect(obj.Key)
            end
             return format_value_enhanced(
             return format_value_enhanced(
                 resolved_name, obj.Key, obj.Value, obj.Type,
                 item_name, obj.Key, obj.Value, obj.Type,
                 obj.LocTokenOverride, nil, false, obj.UsageFlags,
                 obj.LocTokenOverride, nil, false, obj.UsageFlags
                true -- disable_attr
             )
             )
         end
         end
     else
     else
        main_formatter = function(obj)
main_formatter = function(obj)
            if obj.Key:match("^StatusEffect") then
    if obj.Key:match("^StatusEffect") then
                return format_status_effect(obj.Key)
        return format(STATUS_FMT, obj.Key)
            end
    end
            return format_value(
 
                obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,
    return format_value(
                false, true, obj.UsageFlags, obj.Scale, nil, true
        obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,
            )
        false, true, obj.UsageFlags, obj.Scale
        end
    )
end
         alt_formatter = function(obj)
         alt_formatter = function(obj)
            if obj.Key:match("^StatusEffect") then
 
                return format_status_effect(obj.Key)
            end
             return format_value(
             return format_value(
                 obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,
                 obj.Key, obj.Value, obj.Type, obj.LocTokenOverride,
                 false, false, obj.UsageFlags, obj.Scale,
                 false, false, obj.UsageFlags, obj.Scale
                true -- disable_attr
             )
             )
         end
         end
Line 649: Line 490:


     ------------------------------------------------------------------
     ------------------------------------------------------------------
     -- Passive & Active sections — Main and Alt output separately
     -- Passive & Active stats (unified loop)
     ------------------------------------------------------------------
     ------------------------------------------------------------------
     local passive_counter, active_counter = 1, 1
     local passive_counter, active_counter = 1, 1
Line 659: Line 500:
             local prefix = is_active and "active" or "passive"
             local prefix = is_active and "active" or "passive"
             local counter = is_active and active_counter or passive_counter
             local counter = is_active and active_counter or passive_counter
            local stat_fmt = "| " .. prefix .. "%d_stat%d = %s"


             -- Description
             -- Description
Line 667: Line 509:
                     insert(lines, format(
                     insert(lines, format(
                         "| %s%d_description = {{#invoke:Lang|get_string|%s|item_name=%s}}",
                         "| %s%d_description = {{#invoke:Lang|get_string|%s|item_name=%s}}",
                         prefix, counter, loc, resolved_name
                         prefix, counter, loc, item_name
                     ))
                     ))
                 end
                 end
             end
             end


             -- Main stats → prefix{N}_main{M}
             -- Stats
             local main_fmt = "| " .. prefix .. "%d_main%d = %s"
             local seen = {}
            local main_seen = {}
             local stat_index = process_stats(
             local main_index = 1
                 lines, stat_fmt, counter, 1,
            for _, prop_obj in ipairs(section.Main or {}) do
                 section.Main, item_name, seen, main_formatter
                local key = prop_obj.Key
             )
                 if not main_seen[key] and not IGNORED_PROP_KEYS[key] and (
             process_stats(
                    key:match("^StatusEffect")
                 lines, stat_fmt, counter, stat_index,
                    or is_property_in_lang_data(key, prop_obj.LocTokenOverride)
                 section.Alt, item_name, seen, alt_formatter
                ) then
             )
                    local val = main_formatter(prop_obj)
                    if val then
                        insert(lines, format(main_fmt, counter, main_index, val))
                        main_index = main_index + 1
                        main_seen[key] = true
                    end
                 end
            end
 
            -- Alt stats → prefix{N}_alt{M}
            local alt_fmt = "| " .. prefix .. "%d_alt%d = %s"
             local alt_seen = {}
             local alt_index = 1
            for _, prop_obj in ipairs(section.Alt or {}) do
                 local key = prop_obj.Key
                -- Skip keys already emitted as main stats
                if not main_seen[key] and not alt_seen[key] and not IGNORED_PROP_KEYS[key] and (
                    key:match("^StatusEffect")
                    or is_property_in_lang_data(key, prop_obj.LocTokenOverride)
                ) then
                    local val = alt_formatter(prop_obj)
                    if val then
                        insert(lines, format(alt_fmt, counter, alt_index, val))
                        alt_index = alt_index + 1
                        alt_seen[key] = true
                    end
                 end
             end


             -- Cooldown / ChargeUp
             -- Cooldown / ChargeUp
             local cd = format_section_cooldown(section, resolved_name, enhanced)
             local cd = format_section_cooldown(section, item_name, enhanced)
             if cd.cooldown then
             if cd.cooldown then
                 insert(lines, format("| %s%d_cooldown = %s", prefix, counter, cd.cooldown))
                 insert(lines, format("| %s%d_cooldown = %s", prefix, counter, cd.cooldown))
Line 732: Line 546:
     ------------------------------------------------------------------
     ------------------------------------------------------------------
     for i = 1, 2 do
     for i = 1, 2 do
         local comp = ItemData.get_component_name { args = { resolved_name, i } }
         local comp = ItemData.get_component_name { args = { item_name, i } }
         if comp and comp ~= "" then
         if comp and comp ~= "" then
             insert(lines, format("| component%d_name = %s", i, comp))
             insert(lines, format("| component%d_name = %s", i, comp))
Line 763: Line 577:
     return concat(lines, "\n")
     return concat(lines, "\n")
end
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Public interface
-- Public interface
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

Page included on this page: