Module:Sandbox: Difference between revisionsGive feedback
No edit summary |
No edit summary |
||
| Line 2: | Line 2: | ||
local data = mw.loadJsonData("Data:ItemData.json") | local data = mw.loadJsonData("Data:ItemData.json") | ||
-- | -- Normalize strings for comparison | ||
local function normalize(str) | |||
return mw.ustring.lower(mw.text.trim(str or "")) | |||
end | |||
-- Clean and parse numbers | |||
local function cleanNumber(num) | |||
if type(num) == "number" then return num end | |||
if not num then return 0 end | |||
return tonumber(tostring(num):gsub("[^%d.-]", "")) or 0 | |||
end | |||
-- Safe item access | |||
local function get_json_item(name) | local function get_json_item(name) | ||
if not name or type(name) ~= 'string' then return nil end | if not name or type(name) ~= 'string' then return nil end | ||
local | local targetName = normalize(name) | ||
for _, | for _, item in pairs(data) do | ||
if | if item.Name and normalize(item.Name) == targetName then | ||
if | if item.IsDisabled ~= true then | ||
return | return item | ||
end | end | ||
end | end | ||
| Line 17: | Line 29: | ||
end | end | ||
-- | -- Format numbers with localization | ||
local lang = mw.language.getContentLanguage() | local lang = mw.language.getContentLanguage() | ||
local function formatNum(amount) | local function formatNum(amount) | ||
return lang:formatNum(cleanNumber(amount)) | |||
return lang:formatNum(amount) | |||
end | end | ||
-- Main function | -- Main function with improved error handling | ||
p.generate_infobox = function(frame) | p.generate_infobox = function(frame) | ||
local item_name = frame.args[1] | local item_name = frame.args[1] | ||
if not item_name or item_name == | if not item_name or item_name == "" then | ||
return frame:preprocess(" | return frame:preprocess("{{Error|No item name specified}}") | ||
end | end | ||
local item = get_json_item(item_name) | local item = get_json_item(item_name) | ||
if not item then | if not item then | ||
return frame:preprocess(" | return frame:preprocess("{{Error|Item not found: " .. item_name .. "}}") | ||
end | end | ||
-- Determine item type with | -- Determine item type with validation | ||
local item_type = "Weapon" -- default | local item_type = "Weapon" -- default | ||
local valid_types = { | |||
Weapon = {bg = "#80550F", header = "#C97A03", border = "#C97A03"}, | |||
Vitality = {bg = "#4D7214", header = "#659818", border = "#659818"}, | |||
Spirit = {bg = "#623585", header = "#8B56B4", border = "#8B56B4"} | |||
} | |||
if item.Slot then | if item.Slot then | ||
local slot = normalize(item.Slot) | |||
if slot == "armor" then | |||
item_type = "Vitality" | item_type = "Vitality" | ||
elseif | elseif slot == "tech" then | ||
item_type = "Spirit" | item_type = "Spirit" | ||
end | end | ||
end | end | ||
local colors = valid_types[item_type] or valid_types.Weapon | |||
-- | -- Process components | ||
local | local components = {} | ||
if item.Components and type(item.Components) == "table" then | |||
for _, comp_id in ipairs(item.Components) do | for _, comp_id in ipairs(item.Components) do | ||
local component = data[comp_id] | local component = data[comp_id] | ||
if component and component.Name then | if component and component.Name then | ||
table.insert( | table.insert(components, component.Name) | ||
end | end | ||
end | end | ||
end | |||
-- Process stats dynamically | |||
local stats = {} | |||
local stat_formats = { | |||
TechPower = {icon = "Spirit icon.png", suffix = "Spirit Power"}, | |||
WeaponPower = {icon = "Weapon Icon.png", suffix = "Weapon Damage"}, | |||
TechResist = {icon = "Spirit Resist Icon.png", suffix = "Tech Resist"}, | |||
) | BulletResist = {icon = "Bullet Resist Icon.png", suffix = "Bullet Resist"}, | ||
AbilityCooldown = {icon = "Cooldown Icon.png", suffix = "s Cooldown"}, | |||
AbilityCastRange = {suffix = "m Cast Range"}, | |||
AbilityUnitTargetLimit = {prefix = "Targets: "} | |||
} | |||
for stat, format in pairs(stat_formats) do | |||
local value = item[stat] | |||
if value and value ~= "0" and value ~= 0 then | |||
local text = "• " | |||
if format.prefix then text = text .. format.prefix end | |||
text = text .. tostring(value) | |||
if format.icon then text = text .. " [[File:" .. format.icon .. "|20px]]" end | |||
if format.suffix then text = text .. " " .. format.suffix end | |||
table.insert(stats, text) | |||
end | end | ||
end | end | ||
-- Calculate shop bonus | -- Calculate shop bonus | ||
local shop_bonus = "+0" | local shop_bonus = "+0" | ||
local tier = cleanNumber(item.Tier or 1) | |||
if item_type == "Weapon" then | |||
shop_bonus = string.format("+%d%% Weapon Damage", 6 + (tier-1)*4) | |||
elseif item_type == "Vitality" then | |||
shop_bonus = string.format("+%d%% Base Health", 11 + (tier-1)*3) | |||
else -- Spirit | |||
shop_bonus = string.format("+%d Spirit Power", 4 * tier) | |||
end | end | ||
-- Build | -- Build infobox parts | ||
local | local parts = { | ||
-- Header | |||
string.format( | |||
{| class="wikitable" style="text-align:left; border-collapse:collapse; width:312px; max-width:100%%; color: #FFEFD7; padding:12px; font-family:'Retail Demo Regular',serif; %s" | '<div class="infobox_item" style="float:right; display:inline-block; vertical-align:top;">\n' .. | ||
! colspan="4" style="width:280px; padding:5px 12px; text-align:center; font-size:24px; font-family:'Retail Demo Bold',serif; %s" | %s | '{| class="wikitable" style="text-align:left; border-collapse:collapse; width:312px; max-width:100%%; color: #FFEFD7; padding:12px; font-family:\'Retail Demo Regular\',serif; background-color: %s"\n' .. | ||
'! colspan="4" style="width:280px; padding:5px 12px; text-align:center; font-size:24px; font-family:\'Retail Demo Bold\',serif; background-color: %s" | %s', | |||
colors.bg, colors.header, item.Name | |||
), | |||
-- Image | |||
string.format( | |||
'|-\n| colspan=4 class="infobox-image" style="padding:5px; text-align:center;" | [[File:%s.png|144px]]', | |||
item.Name | item.Name | ||
), | |||
-- Cost | |||
string.format( | |||
'|-\n| colspan=2 style="text-align:right; width:50%%; border-right:1px solid %s; padding-right:0.5em;" | Cost\n' .. | |||
'| colspan=2 style="padding-left:0.5em;" | {{Souls|%s}}', | |||
colors.border, formatNum(item.Cost) | |||
), | |||
-- Tier | |||
string.format( | |||
'|-\n| colspan=2 style="text-align:right; width:50%%; border-right:1px solid %s; padding-right:0.5em;" | Tier\n' .. | |||
'| colspan=2 style="padding-left:0.5em;" | %s', | |||
colors.border, tier | |||
), | |||
-- Shop Bonus | |||
string.format( | |||
'|-\n| colspan=2 style="text-align:right; width:50%%; border-right:1px solid %s; padding-right:0.5em;" | Shop Bonus\n' .. | |||
'| colspan=2 style="padding-left:0.5em;" | %s', | |||
colors.border, shop_bonus | |||
) | |||
} | } | ||
-- | -- Add components if they exist | ||
return table.concat( | if #components > 0 then | ||
table.insert(parts, | |||
string.format( | |||
'|-\n! colspan="4" style="text-align:left; padding:0 12px; font-weight:bold; font-size:16px; font-family:\'Retail Demo Bold\',serif; background-color: %s; color: %s" | COMPONENTS:<br/>%s', | |||
(item_type == "Weapon" and "#9E630C" or item_type == "Vitality" and "#203500" or "#372248"), | |||
(item_type == "Weapon" and "#DCCFC6" or item_type == "Vitality" and "#C7C9C6" or "#C9C7CB"), | |||
table.concat(components, "<br/>{{ItemIcon|", "{{ItemIcon|", "}}") | |||
) | |||
) | |||
end | |||
-- Add description | |||
table.insert(parts, | |||
string.format( | |||
'|-\n| colspan="4" style="text-align:left; padding:0 12px; color:#FFEFD7; background-color: %s" | %s', | |||
colors.bg, item.Description or "" | |||
) | |||
) | |||
-- Add stats if they exist | |||
if #stats > 0 then | |||
table.insert(parts, | |||
'|-\n| ' .. table.concat(stats, "\n|-\n| ") | |||
) | |||
end | |||
-- Close table | |||
table.insert(parts, "|}\n</div>") | |||
-- Process and return | |||
return frame:preprocess(table.concat(parts, "\n")) | |||
end | end | ||
return p | return p | ||