Editing Module:Sandbox/LVLGive feedback
Jump to navigation
Jump to search
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:Monster_Domosed/ItemData.json") | |||
local | local function get_component_of_sorted(item_input) | ||
-- Find the item's key | |||
local target_key = nil | |||
if data[item_input] then | |||
local | target_key = item_input | ||
else | |||
for k, v in pairs(data) do | |||
if v.Name == item_input and (v.IsDisabled == false or v.IsDisabled == nil) then | |||
target_key = k; break | |||
end | |||
if | end | ||
end | end | ||
return | if not target_key then return {} end | ||
end | |||
local | -- Find all items that have this item as a component | ||
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 | end | ||
-- == | -- Sort by Tier instead of alphabetically | ||
table.sort(parents, function(a, b) | |||
local tier_a = tonumber(data[a] and data[a]["Tier"]) or 0 | |||
local tier_b = tonumber(data[b] and data[b]["Tier"]) or 0 | |||
return tier_a < tier_b | |||
end) | |||
return parents | |||
end | |||
-- Get raw value, CSS class, and LocTokenOverride for a property | |||
local | local function get_raw_value(item_name, prop) | ||
local item = data[item_name] or nil | |||
if not item then | |||
for k,v in pairs(data) do | |||
if v.Name == item_name then item = v; break end | |||
end | |||
end | |||
if not item then return nil, nil, nil end | |||
if | local raw_prop = item[prop] | ||
if type(raw_prop) == "table" then | |||
local loc_override = raw_prop.LocTokenOverride or prop | |||
return raw_prop.Value, raw_prop.CSSClass, loc_override | |||
return | else | ||
return raw_prop, nil, prop | |||
end | end | ||
end | |||
local | -- Check if property exists in language data | ||
local function is_property_in_lang_data(prop) | |||
local keys = { | |||
prop .. "_label", | |||
prop .. "_Label", | |||
prop .. "_prefix", | |||
prop .. "_Prefix", | |||
prop .. "_postfix", | |||
prop .. "_Postfix", | |||
prop .. "_postvalue_label", | |||
prop .. "_Postvalue_Label" | |||
} | |||
for _, key in ipairs(keys) do | |||
if lang.get_string(key) then | |||
return true | |||
end | |||
end | end | ||
return false | |||
end | end | ||
-- | -- Get item by name, ignoring disabled if possible | ||
local function get_json_item(name) | |||
local function | for _, v in pairs(data) do | ||
if v.Name == name and (v.IsDisabled == false or v.IsDisabled == nil) then | |||
return v | |||
for _, | |||
end | end | ||
end | end | ||
for _, v in pairs(data) do | |||
if v.Name == name then return v end | |||
end | |||
return nil | |||
end | |||
-- Format stat value for Infobox, handling prefix/postfix, CSS, scaling, and conditional | |||
local function format_stat(item_name, prop, skip_label, debug, allow_conditional) | |||
if allow_conditional == nil then allow_conditional = true end | |||
if prop == "AbilityCooldown" and not skip_label then | |||
if | return nil | ||
end | end | ||
local value, css, loc_key = get_raw_value(item_name, prop) | |||
if value == nil or value == 0 or value == "" then | |||
return nil | |||
end | end | ||
-- Convert string like "0m" or "0.0" to number for zero check | |||
local | local numeric_val = tonumber(tostring(value):match("^-?%d+%.?%d*")) or 0 | ||
if numeric_val == 0 then | |||
return nil | |||
end | end | ||
-- ========= | -- Skip if property has no lang data | ||
-- | local label_key = loc_key:gsub("^#", "") | ||
if not ( | |||
lang.get_string(label_key.."_label") or | |||
lang.get_string(label_key.."_Label") or | |||
lang.get_string(label_key.."_prefix") or | |||
lang.get_string(label_key.."_Prefix") or | |||
lang.get_string(label_key.."_postfix") or | |||
lang.get_string(label_key.."_Postfix") or | |||
lang.get_string(label_key.."_postvalue_label") or | |||
lang.get_string(label_key.."_Postvalue_Label") | |||
) then | |||
return nil | |||
end | |||
if debug == 2 then | |||
local label_val, prefix_val, postfix_val | |||
-- determine which label key worked | |||
if lang.get_string(label_key.."_label") then | |||
label_val = label_key.."_label" | |||
elseif lang.get_string(label_key.."_Label") then | |||
label_val = label_key.."_Label" | |||
else | |||
label_val = "(none)" | |||
end | |||
-- determine which prefix key worked | |||
if lang.get_string(label_key.."_prefix") then | |||
prefix_val = label_key.."_prefix" | |||
elseif lang.get_string(label_key.."_Prefix") then | |||
prefix_val = label_key.."_Prefix" | |||
else | |||
prefix_val = "(none)" | |||
end | |||
-- determine which postfix key worked | |||
if lang.get_string(label_key.."_postfix") then | |||
postfix_val = label_key.."_postfix" | |||
elseif lang.get_string(label_key.."_Postfix") then | |||
postfix_val = label_key.."_Postfix" | |||
else | |||
postfix_val = "(none)" | |||
end | |||
return string.format( | |||
"raw invoke key: %s | raw value: %s | label key used: %s | prefix key used: %s | postfix key used: %s", | |||
loc_key, | |||
tostring(value), | |||
label_val, | |||
prefix_val, | |||
postfix_val | |||
) | |||
end | |||
if prop == "BuildUpPerShot" then label_key = "BuildupPerShot" | |||
elseif prop == "DotDuration" then label_key = "DOTDuration" | |||
end | |||
local | -- Helper function: get first non-nil string from variants | ||
local function first_non_nil(...) | |||
for i = 1, select("#", ...) do | |||
local v = select(i, ...) | |||
if v and v ~= "" then return v end | |||
end | |||
return "" | |||
end | |||
-- Get actual label, prefix, postfix with fallbacks | |||
local label = skip_label and "" or first_non_nil( | |||
lang.get_string(label_key.."_label"), | |||
lang.get_string(label_key.."_Label") | |||
) | |||
local prefix = first_non_nil( | |||
lang.get_string(label_key.."_prefix"), | |||
lang.get_string(label_key.."_Prefix") | |||
) | |||
local postfix = first_non_nil( | |||
lang.get_string(label_key.."_postfix"), | |||
lang.get_string(label_key.."_Postfix") | |||
) | |||
if prefix == "" and postfix == "" and label == "" then | |||
return nil | |||
end | |||
local val_str = tostring(value) | |||
local | |||
------------------------------------------------------------------ | |||
-- CSS-specific formatting | |||
------------------------------------------------------------------ | |||
if css == "move_speed" or css == "sprint_speed" then | |||
if postfix == "" or not postfix:find("%%") then | |||
val_str = val_str:gsub("/s", "") .. "/s" | |||
end | end | ||
local num = tonumber(val_str:match("^-?%d+%.?%d*")) | |||
- | if num and num > 0 and not val_str:find("^%+") then | ||
if | val_str = "+" .. val_str | ||
end | end | ||
end | |||
------------------------------------------------------------------ | |||
-- Apply prefix | |||
------------------------------------------------------------------ | |||
if prefix ~= "" then | |||
if prefix == "{s:sign}" then | |||
local num = tonumber(val_str:match("^-?%d+%.?%d*")) | |||
if num and num >= 0 and not val_str:find("^%+") then | |||
val_str = "+"..val_str | |||
end | end | ||
else | else | ||
val_str = prefix..val_str | |||
end | end | ||
end | |||
------------------------------------------------------------------ | |||
-- Append postfix | |||
------------------------------------------------------------------ | |||
-- Append postfix | |||
if prop ~= "BuildUpPerShot" and postfix ~= "" and not val_str:find(postfix, 1, true) then | |||
if postfix == "HP/s" then | |||
val_str = val_str .. " " .. postfix | |||
else | |||
val_str = val_str .. postfix | |||
end | |||
end | |||
------------------------------------------------------------------ | |||
-- Append scaling template {{Boon}} or {{Ss}} | |||
------------------------------------------------------------------ | |||
local item = get_json_item(item_name) | |||
local raw_prop = item[prop] | |||
if type(raw_prop) == "table" and raw_prop.Scale and raw_prop.Scale.Value ~= 0 then | |||
local scale_val = util_module.round_to_sig_fig(raw_prop.Scale.Value, 2) | |||
local template_name = (raw_prop.Scale.Type == "power_increase") and "Boon" or "Ss" | |||
val_str = val_str .. " " .. mw.getCurrentFrame():expandTemplate{ title = template_name, args = { scale_val } } | |||
end | |||
------------------------------------------------------------------ | |||
-- Append label | |||
------------------------------------------------------------------ | |||
if label ~= "" then | |||
val_str = val_str.." "..label | |||
end | |||
------------------------------------------------------------------ | |||
-- Append (Conditional) ONLY if allowed | |||
------------------------------------------------------------------ | |||
if allow_conditional | |||
and type(raw_prop) == "table" | |||
and (raw_prop.UsageFlags == "ConditionallyApplied" or raw_prop.UsageFlags == "ConditionallyEnemyApplied") | |||
then | |||
local conditional_text = lang.get_string("Citadel_Shop_ConditionalAttribute") | |||
val_str = val_str .. string.format(' <span style="color:#C0C0C0">(%s)</span>', conditional_text) | |||
end | |||
return val_str | |||
end | |||
-- Special formatting for StatusEffect | |||
local function format_property_for_infobox(item_name, prop, skip_label, debug) | |||
if prop:match("^StatusEffect") then | |||
return string.format( | |||
"[[{{#invoke:Lang|get_string|Citadel_%s}}]] [[{{#invoke:Lang|get_string|Citadel_StatusEffect}}]]", | |||
prop | |||
) | |||
else | |||
return format_stat(item_name, prop, skip_label, debug, true) | |||
end | |||
end | |||
function p.fill_tooltip(frame) | |||
local item_name = frame.args[1] | |||
if not item_name then return "Item name missing" end | |||
local debug = tonumber(frame.args.debug) or 0 | |||
local item = get_json_item(item_name) | |||
if not item then return "Item not found" end | |||
local ItemData = require("Module:ItemData") | |||
local lines = { | |||
"{{Infobox item", | |||
"| item_name = " .. item_name | |||
} | |||
---------------------------------------------------------------------- | |||
-- Check if AbilityCooldown or AbilityChargeUpTime exists in sections | |||
---------------------------------------------------------------------- | |||
local cooldown_found_in_sections = false | |||
local chargeup_found_in_sections = false | |||
for _, section in ipairs(item.TooltipSections or {}) do | |||
for _, entry in ipairs(section.Entries or {}) do | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop == "AbilityCooldown" then cooldown_found_in_sections = true end | |||
if prop == "AbilityChargeUpTime" then chargeup_found_in_sections = true end | |||
end | |||
for _, prop in ipairs(entry.ImportantProperties or {}) do | |||
if prop == "AbilityCooldown" then cooldown_found_in_sections = true end | |||
if prop == "AbilityChargeUpTime" then chargeup_found_in_sections = true end | |||
end | |||
end | end | ||
end | end | ||
-- | ---------------------------------------------------------------------- | ||
-- Innate stats | |||
---------------------------------------------------------------------- | |||
local innate_index = 1 | |||
for _, section in ipairs(item.TooltipSections or {}) do | |||
if section.Type == "EArea_Innate" then | |||
for _, entry in ipairs(section.Entries or {}) do | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop ~= "AbilityCooldown" and prop ~= "AbilityChargeUpTime" then | |||
local val = format_stat(item_name, prop, false, debug, false) | |||
if val then | |||
table.insert(lines, string.format("| item_stat%d = %s", innate_index, val)) | |||
innate_index = innate_index + 1 | |||
end | |||
end | |||
for _, | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
-- | ---------------------------------------------------------------------- | ||
local | -- Passive stats | ||
---------------------------------------------------------------------- | |||
local passive_counter = 1 | |||
for _, section in ipairs(item.TooltipSections or {}) do | |||
if section.Type ~= "EArea_Innate" and section.Type ~= "EArea_Active" then | |||
for _, entry in ipairs(section.Entries or {}) do | |||
local loc = entry.LocString and entry.LocString:gsub("#","") or nil | |||
if loc then | |||
table.insert( | |||
lines, | |||
string.format( | |||
for _, | "| passive%d_description = {{#invoke:Lang|get_string|%s|item_name=%s}}", | ||
if | passive_counter, loc, item_name | ||
) | |||
) | |||
end | |||
local stat_index = 1 | |||
local seen_props = {} | |||
-- ImportantProperties | |||
for _, prop in ipairs(entry.ImportantProperties or {}) do | |||
if prop ~= "AbilityCooldown" and prop ~= "AbilityChargeUpTime" and is_property_in_lang_data(prop) and not seen_props[prop] then | |||
local val = format_property_for_infobox(item_name, prop, false, debug) | |||
if val then | |||
table.insert(lines, string.format("| passive%d_stat%d = %s", passive_counter, stat_index, val)) | |||
stat_index = stat_index + 1 | |||
seen_props[prop] = true | |||
end | |||
end | |||
end | |||
-- Properties | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop ~= "AbilityCooldown" and prop ~= "AbilityChargeUpTime" and is_property_in_lang_data(prop) and not seen_props[prop] then | |||
local val = format_property_for_infobox(item_name, prop, false, debug) | |||
if val then | |||
table.insert(lines, string.format("| passive%d_stat%d = %s", passive_counter, stat_index, val)) | |||
stat_index = stat_index + 1 | |||
seen_props[prop] = true | |||
end | |||
end | |||
end | |||
-- AbilityCooldown | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop == "AbilityCooldown" then | |||
local cd = format_stat(item_name, prop, true, debug) | |||
if cd then | |||
table.insert(lines, string.format("| passive%d_cooldown = %s", passive_counter, cd)) | |||
end | |||
end | |||
end | |||
for _, prop in ipairs(entry.ImportantProperties or {}) do | |||
if prop == "AbilityCooldown" then | |||
local cd = format_stat(item_name, prop, true, debug) | |||
if cd then | |||
table.insert(lines, string.format("| passive%d_cooldown = %s", passive_counter, cd)) | |||
end | |||
end | |||
end | |||
-- AbilityChargeUpTime | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop == "AbilityChargeUpTime" then | |||
local cu = format_stat(item_name, prop, true, debug) | |||
if cu then | |||
table.insert(lines, string.format("| passive%d_chargeup = %s", passive_counter, cu)) | |||
end | |||
end | |||
end | |||
for _, prop in ipairs(entry.ImportantProperties or {}) do | |||
if prop == "AbilityChargeUpTime" then | |||
local cu = format_stat(item_name, prop, true, debug) | |||
if cu then | |||
table.insert(lines, string.format("| passive%d_chargeup = %s", passive_counter, cu)) | |||
end | |||
end | end | ||
end | end | ||
passive_counter = passive_counter + 1 | |||
end | end | ||
end | end | ||
end | end | ||
-- | ---------------------------------------------------------------------- | ||
for _, | -- Active stats | ||
---------------------------------------------------------------------- | |||
local active_index = 1 | |||
for _, section in ipairs(item.TooltipSections or {}) do | |||
if section.Type == "EArea_Active" then | |||
for _, entry in ipairs(section.Entries or {}) do | |||
if entry.LocString then | |||
table.insert( | |||
lines, | |||
string.format( | |||
"| active%d_description = {{#invoke:Lang|get_string|%s|item_name=%s}}", | |||
active_index, | |||
entry.LocString:gsub("#",""), | |||
item_name | |||
) | |||
) | |||
end | |||
local stat_index = 1 | |||
local seen_props = {} | |||
-- ImportantProperties | |||
for _, prop in ipairs(entry.ImportantProperties or {}) do | |||
if prop ~= "AbilityCooldown" and prop ~= "AbilityChargeUpTime" and is_property_in_lang_data(prop) and not seen_props[prop] then | |||
local val = format_property_for_infobox(item_name, prop, false, debug) | |||
if val then | |||
table.insert(lines, string.format("| active%d_stat%d = %s", active_index, stat_index, val)) | |||
stat_index = stat_index + 1 | |||
seen_props[prop] = true | |||
end | end | ||
end | end | ||
end | |||
-- Properties | |||
if | for _, prop in ipairs(entry.Properties or {}) do | ||
if prop ~= "AbilityCooldown" and prop ~= "AbilityChargeUpTime" and is_property_in_lang_data(prop) and not seen_props[prop] then | |||
local val = format_property_for_infobox(item_name, prop, false, debug) | |||
if val then | |||
table.insert(lines, string.format("| active%d_stat%d = %s", active_index, stat_index, val)) | |||
stat_index = stat_index + 1 | |||
seen_props[prop] = true | |||
end | end | ||
end | end | ||
end | end | ||
-- AbilityCooldown | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop == "AbilityCooldown" then | |||
local cd = format_stat(item_name, prop, true, debug) | |||
if cd then | |||
table.insert(lines, string.format("| active%d_cooldown = %s", active_index, cd)) | |||
end | |||
end | |||
end | |||
for _, prop in ipairs(entry.ImportantProperties or {}) do | |||
if prop == "AbilityCooldown" then | |||
local cd = format_stat(item_name, prop, true, debug) | |||
if cd then | |||
table.insert(lines, string.format("| active%d_cooldown = %s", active_index, cd)) | |||
if | |||
end | end | ||
end | end | ||
end | end | ||
-- AbilityChargeUpTime | |||
for _, prop in ipairs(entry.Properties or {}) do | |||
if prop == "AbilityChargeUpTime" then | |||
if | local cu = format_stat(item_name, prop, true, debug) | ||
if cu then | |||
table.insert(lines, string.format("| active%d_chargeup = %s", active_index, cu)) | |||
end | |||
end | end | ||
end | end | ||
local | for _, prop in ipairs(entry.ImportantProperties or {}) do | ||
if prop == "AbilityChargeUpTime" then | |||
local cu = format_stat(item_name, prop, true, debug) | |||
if cu then | |||
table.insert(lines, string.format("| active%d_chargeup = %s", active_index, cu)) | |||
end | |||
end | |||
end | end | ||
active_index = active_index + 1 | |||
end | end | ||
end | end | ||
end | end | ||
---------------------------------------------------------------------- | |||
-- Global fallback for AbilityCooldown and AbilityChargeUpTime | |||
---------------------------------------------------------------------- | |||
if not cooldown_found_in_sections and item.AbilityCooldown then | |||
local cd = format_stat(item_name, "AbilityCooldown", true, debug) | |||
if cd then | |||
) | local has_active = false | ||
for _, section in ipairs(item.TooltipSections or {}) do | |||
if section.Type == "EArea_Active" then has_active = true; break end | |||
end | |||
if has_active then | |||
table.insert(lines, "| active1_cooldown = " .. cd) | |||
else | |||
table.insert(lines, "| item_stat_cooldown = " .. cd) | |||
end | |||
end | |||
end | |||
if not chargeup_found_in_sections and item.AbilityChargeUpTime then | |||
local cu = format_stat(item_name, "AbilityChargeUpTime", true, debug) | |||
if cu then | |||
table.insert(lines, "| item_stat_chargeup = " .. cu) | |||
end | |||
end | |||
---------------------------------------------------------------------- | |||
-- Components | |||
---------------------------------------------------------------------- | |||
for i = 1, 2 do | |||
local comp = ItemData.get_component_name { | |||
args = { item_name, i } | |||
} | |||
if comp and comp ~= "" then | |||
table.insert(lines, string.format("| component%d_name = %s", i, comp)) | |||
end | |||
end | |||
---------------------------------------------------------------------- | |||
-- Is Component Of | |||
---------------------------------------------------------------------- | |||
local parents = get_component_of_sorted(item_name) | |||
for i, key in ipairs(parents) do | |||
local parent_name = data[key] and data[key]["Name"] or "" | |||
if parent_name ~= "" then | |||
table.insert(lines, string.format("| iscomponentof%d_name = %s", i, parent_name)) | |||
end | |||
end | |||
---------------------------------------------------------------------- | |||
-- Sounds (sound1, sound2, sound3, ...) | |||
---------------------------------------------------------------------- | |||
for key, value in pairs(frame.args) do | |||
local index = tostring(key):match("^sound(%d+)$") | |||
if index and value ~= "" then | |||
table.insert(lines, string.format("| sound%s = %s", index, value)) | |||
end | |||
end | |||
---------------------------------------------------------------------- | |||
table.insert(lines, "}}") | |||
local output = table.concat(lines, "\n") | |||
if debug == 1 or debug == 2 then | |||
return output | |||
end | |||
return mw.getCurrentFrame():preprocess(output) | |||
end | end | ||
return p | return p | ||