Module:Abilities-test/card: Difference between revisionsGive feedback
Created page with "local lang = require "Module:Lang" local commonutils = require "Module:Utilities" local utils = require "Module:Abilities/utils" local p = {} local data = mw.loadJsonData("Data:AbilityCards.json") -- Maps attr type to an appropriate image and page link -- Optional icon size, will be defaulted on the template local ATTR_TYPE_ICON_MAP = { bullet_armor_up = {img='Bullet_Armor.png', link='Damage_Resistance', color = 'NoColor'}, bullet_armor_down = {img='Bullet_Armor.png'..." |
mNo edit summary |
||
| (39 intermediate revisions by the same user not shown) | |||
| Line 12: | Line 12: | ||
bullet_armor_down = {img='Bullet_Armor.png', link='Damage_Resistance', color = 'NoColor'}, | bullet_armor_down = {img='Bullet_Armor.png', link='Damage_Resistance', color = 'NoColor'}, | ||
cast = {img='AttributeIconMaxChargesIncrease.png', link=''}, | cast = {img='AttributeIconMaxChargesIncrease.png', link=''}, | ||
charges = {img='AttributeIconMaxChargesIncrease.png', link=''}, | charges = {img='AttributeIconMaxChargesIncrease.png', link='', color = 'Purple'}, | ||
damage = {img='Damage_heart.png', link='', color = 'NoColor'}, -- 'NoColor' will apply no icon color and use the original image | damage = {img='Damage_heart.png', link='', color = 'NoColor'}, -- 'NoColor' will apply no icon color and use the original image | ||
bullet_damage = {img='Bullet_damage.png', link='Bullet_Damage', color = 'NoColor'}, | bullet_damage = {img='Bullet_damage.png', link='Bullet_Damage', color = 'NoColor'}, | ||
| Line 19: | Line 19: | ||
health = {img='Health.png', link='Health', color = 'Green'}, | health = {img='Health.png', link='Health', color = 'Green'}, | ||
move_speed = {img='Move speed.png', link='Move Speed', color = 'Green'}, | move_speed = {img='Move speed.png', link='Move Speed', color = 'Green'}, | ||
range = {img='CastRange.png', link='Ability_Range'}, | range = {img='CastRange.png', link='Ability_Range', color = 'Purple'}, | ||
radius = {img='CastRange.png', link='Ability_Range', color = 'Purple'}, | |||
tech_armor_up = {img='Spirit_Armor.png', link='Damage_Resistance', color = 'NoColor'}, | tech_armor_up = {img='Spirit_Armor.png', link='Damage_Resistance', color = 'NoColor'}, | ||
tech_damage = {img='AttributeIconTechShieldHealth.png', link='Spirit_Damage', color = 'NoColor',size = '12px'}, | tech_damage = {img='AttributeIconTechShieldHealth.png', link='Spirit_Damage', color = 'NoColor',size = '12px'}, | ||
distance = {img='AttributeIconTechRange.png', link='Ability_Range'}, | distance = {img='AttributeIconTechRange.png', link='Ability_Range'}, | ||
duration = {img='AttributeIconTechDuration.png', link='Ability Duration'}, | duration = {img='AttributeIconTechDuration.png', link='Ability Duration', color = 'Purple'}, | ||
slow = {img='MoveSlow.png', link=''}, | slow = {img='MoveSlow.png', link='', color = 'Purple'}, | ||
melee_damage = {img='Melee damage.png', link='Melee Damage'}, | melee_damage = {img='Melee damage.png', link='Melee Damage'}, | ||
cooldown = {img='AttributeIconTechDuration.png', link='Ability Cooldown'}, | cooldown = {img='AttributeIconTechDuration.png', link='Ability Cooldown'}, | ||
combat_barrier = {img='Barrier.png', link='Barrier', color = 'Green'}, | combat_barrier = {img='Barrier.png', link='Barrier', color = 'Green'}, | ||
time = {img='AttributeIconTechDuration.png', link='Ability Duration', color = 'Purple'}, | |||
} | } | ||
-- TODO - replace this with utils file | |||
function utils.get_ability_card_data(hero_key, ability_num) | |||
if(hero_key == nil) then return nil end | |||
return data[hero_key][tonumber(ability_num)] | |||
end | |||
function get_hero_key(hero_name) | function get_hero_key(hero_name) | ||
if hero_name == nil then return nil end | |||
-- if name starts with "hero_", use it directly as the key | |||
if string.sub(hero_name, 1, 5) == "hero_" then return hero_name end | |||
for i, hero in pairs(data) do | for i, hero in pairs(data) do | ||
if hero["Name"] == hero_name then | if hero["Name"] == hero_name then | ||
| Line 92: | Line 106: | ||
table.insert(info1_main_boxes, 1, | table.insert(info1_main_boxes, 1, | ||
frame:expandTemplate{ | frame:expandTemplate{ | ||
title = "Ability_card_v2/Card/MainBox", | title = "User:Saag/Sandbox/Ability_card_v2/Card/MainBox", | ||
args = { | args = { | ||
key = "HexDuration", | key = "HexDuration", | ||
| Line 130: | Line 144: | ||
title = "User:Saag/Sandbox/Ability_card_v2/Card", | title = "User:Saag/Sandbox/Ability_card_v2/Card", | ||
args = { | args = { | ||
id = hero_key .. ':' .. ability.Key, | |||
hero_key = hero_key, | hero_key = hero_key, | ||
ability_num = ability_num, | ability_num = ability_num, | ||
| Line 138: | Line 153: | ||
icon = lang.get_string(ability.Key, 'en') .. '.png', | icon = lang.get_string(ability.Key, 'en') .. '.png', | ||
channel_time = ability.Cast and ability.Cast.AbilityChannelTime and ability.Cast.AbilityChannelTime.Value, | channel_time = ability.Cast and ability.Cast.AbilityChannelTime and ability.Cast.AbilityChannelTime.Value ~= 9999 and ability.Cast.AbilityChannelTime.Value, | ||
channel_time_ss = ability.Cast and get_attr_ss(ability.Cast.AbilityChannelTime), | channel_time_ss = ability.Cast and get_attr_ss(ability.Cast.AbilityChannelTime), | ||
radius = ability.Radius and ability.Radius.Value, | radius = ability.Radius and ability.Radius.Value, | ||
| Line 149: | Line 164: | ||
cooldown =ability.AbilityCooldown and ability.AbilityCooldown.Value, | cooldown =ability.AbilityCooldown and ability.AbilityCooldown.Value, | ||
cooldown_ss = get_attr_ss(ability.AbilityCooldown), | cooldown_ss = get_attr_ss(ability.AbilityCooldown), | ||
charge_cooldown = ability.AbilityCooldownBetweenCharge and ability.AbilityCooldownBetweenCharge.Value, | charge_cooldown = ability.AbilityCooldownBetweenCharge and ability.AbilityCooldownBetweenCharge.Value ~= -1 and ability.AbilityCooldownBetweenCharge.Value, | ||
charge_cooldown_ss = get_attr_ss(ability.AbilityCooldownBetweenCharge), | charge_cooldown_ss = get_attr_ss(ability.AbilityCooldownBetweenCharge), | ||
num_of_charges = ability.AbilityCharges and ability.AbilityCharges.Value, | num_of_charges = ability.AbilityCharges and ability.AbilityCharges.Value, | ||
-- Info section #1 defined in "Info1" attribute | -- Info section #1 defined in "Info1" attribute | ||
hide_info1 = infobox_is_hidden(ability.Info1) and "true" or "false", | |||
info1_desc = info1_desc, | info1_desc = info1_desc, | ||
info1_mainbox1 = info1_main_boxes[1], | info1_mainbox1 = info1_main_boxes[1], | ||
info1_mainbox2 = info1_main_boxes[2], | info1_mainbox2 = info1_main_boxes[2], | ||
info1_mainbox3 = info1_main_boxes[3], | info1_mainbox3 = info1_main_boxes[3], | ||
info1_mainbox4 = info1_main_boxes[4], | |||
info1_mainbox5 = info1_main_boxes[5], | |||
info1_altbox1 = info1_alt_boxes[1], | info1_altbox1 = info1_alt_boxes[1], | ||
info1_altbox2 = info1_alt_boxes[2], | info1_altbox2 = info1_alt_boxes[2], | ||
| Line 166: | Line 184: | ||
-- Info section #2 defined in "Info2" attribute | -- Info section #2 defined in "Info2" attribute | ||
hide_info2 = infobox_is_hidden(ability.Info2) and "true" or "false", | |||
info2_desc = info2_desc, | info2_desc = info2_desc, | ||
info2_mainbox1 = info2_main_boxes[1], | info2_mainbox1 = info2_main_boxes[1], | ||
info2_mainbox2 = info2_main_boxes[2], | info2_mainbox2 = info2_main_boxes[2], | ||
info2_mainbox3 = info2_main_boxes[3], | info2_mainbox3 = info2_main_boxes[3], | ||
info2_mainbox4 = info2_main_boxes[4], | |||
info2_mainbox5 = info2_main_boxes[5], | |||
info2_altbox1 = info2_alt_boxes[1], | info2_altbox1 = info2_alt_boxes[1], | ||
info2_altbox2 = info2_alt_boxes[2], | info2_altbox2 = info2_alt_boxes[2], | ||
| Line 178: | Line 199: | ||
-- Info section #3 defined in "Info3" attribute | -- Info section #3 defined in "Info3" attribute | ||
hide_info3 = infobox_is_hidden(ability.Info3) and "true" or "false", | |||
info3_desc = info3_desc, | info3_desc = info3_desc, | ||
info3_mainbox1 = info3_main_boxes[1], | info3_mainbox1 = info3_main_boxes[1], | ||
info3_mainbox2 = info3_main_boxes[2], | info3_mainbox2 = info3_main_boxes[2], | ||
info3_mainbox3 = info3_main_boxes[3], | info3_mainbox3 = info3_main_boxes[3], | ||
info3_mainbox4 = info3_main_boxes[4], | |||
info3_mainbox5 = info3_main_boxes[5], | |||
info3_altbox1 = info3_alt_boxes[1], | info3_altbox1 = info3_alt_boxes[1], | ||
info3_altbox2 = info3_alt_boxes[2], | info3_altbox2 = info3_alt_boxes[2], | ||
| Line 199: | Line 223: | ||
} | } | ||
} | } | ||
end | |||
function infobox_is_hidden(infobox) | |||
if infobox == nil then | |||
return false | |||
end | |||
return infobox.RequiresUpgradeIndex ~= nil | |||
end | end | ||
| Line 231: | Line 263: | ||
local ability = utils.get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then return | if(ability == nil) then return {} end -- return empty table, not string | ||
local info_section = ability['Info'..info_section_num] | local info_section = ability['Info'..info_section_num] | ||
| Line 271: | Line 303: | ||
local main = info_section.Main | local main = info_section.Main | ||
if main == nil then | if main == nil then | ||
return | return {} | ||
end | end | ||
local frame = mw.getCurrentFrame() | local frame = mw.getCurrentFrame() | ||
local props = | local props = {} | ||
-- Start with the standard Props array | |||
if main.Props then | |||
for _, prop in ipairs(main.Props) do | |||
table.insert(props, prop) | |||
end | |||
end | |||
local main_boxes = {} | local main_boxes = {} | ||
for k, prop in | for k, prop in ipairs(props) do -- use ipairs for ordered iteration | ||
local value = prop.Value | local value = prop.Value | ||
-- If it scales with melee damage, set the value using the hero's base melee to match in game visuals | -- If it scales with melee damage, set the value using the hero's base melee to match in game visuals | ||
| Line 287: | Line 327: | ||
end | end | ||
local icon = get_icon(prop.Type) | |||
if value | |||
local main_box | |||
if prop.StatusEffect then | |||
title = "Ability_card_v2/Card/MainBox", | main_box = frame:expandTemplate{ | ||
title = "User:Saag/Sandbox/Ability_card_v2/Card/StatusBox", | |||
args = { | |||
title = prop.Title, | |||
key = prop.Key, | |||
value = value, | |||
status_effect = prop.StatusEffect, | |||
icon = icon.img, | |||
icon_link = icon.link, | |||
icon_color = icon.color, | |||
icon_size = icon.size, | |||
scale_value = prop.Scale and commonutils.round_to_sig_fig(prop.Scale.Value, 3), | |||
scale_type = prop.Scale and prop.Scale.Type, | |||
-- allow nil value here as some status effects don't have a value but should not be hidden | |||
hide = value == 0 and "true" or "false", | |||
} | |||
} | |||
else | |||
main_box = frame:expandTemplate{ | |||
title = "User:Saag/Sandbox/Ability_card_v2/Card/MainBox", | |||
args = { | args = { | ||
title = prop.Title, | title = prop.Title, | ||
| Line 301: | Line 360: | ||
icon_size = icon.size, | icon_size = icon.size, | ||
scale_value = prop.Scale and commonutils.round_to_sig_fig(prop.Scale.Value, 3), | scale_value = prop.Scale and commonutils.round_to_sig_fig(prop.Scale.Value, 3), | ||
scale_type = prop.Scale and prop.Scale.Type | scale_type = prop.Scale and prop.Scale.Type, | ||
hide = (value == nil or value == 0) and "true" or "false", | |||
} | } | ||
} | } | ||
end | end | ||
table.insert(main_boxes, main_box) | |||
end | end | ||
| Line 339: | Line 399: | ||
-- Some props don't have values, as those come from upgrades | -- Some props don't have values, as those come from upgrades | ||
-- For now, we will ignore these and only show data for the base ability | -- For now, we will ignore these and only show data for the base ability | ||
if prop.Value | if prop.Value then | ||
local icon = get_icon(prop.Type) | local icon = get_icon(prop.Type) | ||
local alt_box = frame:expandTemplate{ | local alt_box = frame:expandTemplate{ | ||
title = "Ability_card_v2/Card/AltBox", | title = "User:Saag/Sandbox/Ability_card_v2/Card/AltBox", | ||
args = { | args = { | ||
key = prop.Key, | |||
value = prop.Value, | |||
icon = icon.img, | |||
icon_link = icon.link, | |||
icon_color = icon.color, | |||
icon_size = icon.size, | |||
scale_value = prop.Scale and commonutils.round_to_sig_fig(prop.Scale.Value, 3), | |||
scale_type = prop.Scale and prop.Scale.Type, | |||
hide = prop.Value == 0 and "true" or "false", | |||
} | } | ||
} | } | ||
| Line 368: | Line 429: | ||
local frame = mw.getCurrentFrame() | local frame = mw.getCurrentFrame() | ||
local | local upgrades = ability.Upgrades | ||
local upgrade_boxes = {} | local upgrade_boxes = {} | ||
for k, | for k, upgrade in pairs(upgrades) do | ||
local description = lang.get_string( | local description = lang.get_string(upgrade.DescKey) | ||
-- bypass some keys if they are mistakenly left in game files | |||
local IGNORE_DESC_KEYS = {'citadel_ability_hornet_snipe_t3_desc', 'ability_fencer_ultimate_t3_desc'} | |||
-- Generate a description if there is no localized string | -- Generate a description if there is no localized string | ||
if (description == nil or description == '') then | if (description == nil or description == '' or commonutils.contains(IGNORE_DESC_KEYS, upgrade.DescKey)) then | ||
description = create_description( | description = create_description(upgrade, frame) | ||
else | |||
-- Replace embedded value placeholders with just the base value | |||
-- Pattern: {'Value': X, 'Scale': {...}} -> X | |||
description = description:gsub("{'Value':%s*([%d%.%-]+),%s*'Scale':%s*{[^}]+}}", function(value) | |||
return commonutils.round_to_sig_fig(tonumber(value), 3) | |||
end) | |||
-- Pattern: {'Value': X} -> X | |||
description = description:gsub("{'Value':%s*([%d%.%-]+)}", function(value) | |||
return commonutils.round_to_sig_fig(tonumber(value), 3) | |||
end) | |||
end | end | ||
| Line 390: | Line 464: | ||
local upgrade_box = frame:expandTemplate{ | local upgrade_box = frame:expandTemplate{ | ||
title = "Ability_card_v2/Card/UpgradeBox", | title = "User:Saag/Sandbox/Ability_card_v2/Card/UpgradeBox", | ||
args = { | args = { | ||
index = k, | |||
cost = UPGRADE_COST_MAP[k], | |||
description = frame:preprocess(description), | |||
scale_value = upgrade.Scale and commonutils.round_to_sig_fig(upgrade.Scale.Value, 3), | |||
scale_type = upgrade.Scale and upgrade.Scale.Type, | |||
fontsize = fontsize | |||
} | } | ||
} | } | ||
| Line 404: | Line 479: | ||
return upgrade_boxes | return upgrade_boxes | ||
end | end | ||
function create_description(prop, frame) | function create_description(prop, frame) | ||
| Line 411: | Line 487: | ||
for k, v in pairs(prop) do | for k, v in pairs(prop) do | ||
local value | |||
if type(v) | if type(v) == 'table' then | ||
value = v.Value | |||
else | |||
value = v | |||
end | |||
local formatted_value = utils.format_value_with_prepost(k, value, frame) | |||
local attr_name = lang.get_string(k..'_label') | |||
local key = formatted_value .. '|' .. attr_name -- Unique identifier | |||
-- skip DescKey for the edge case where we are generating description instead of using localization files | |||
if k ~= 'DescKey' then | |||
-- Skip if this combination has already been added | |||
if not seen[key] then | |||
-- Add line break if this is not the first item | |||
if not first then | |||
description = description .. '<br>' | |||
end | |||
end | |||
description = description .. string.format('%s %s', formatted_value, attr_name) | |||
first = false | |||
seen[key] = true -- Mark this combination as added | |||
end | end | ||
end | end | ||
| Line 453: | Line 535: | ||
size = mappedAttr.size | size = mappedAttr.size | ||
color = mappedAttr.color or color | color = mappedAttr.color or color | ||
end | end | ||
return {img=img, link=link, color=color, size=size} | return {img=img, link=link, color=color, size=size} | ||
| Line 532: | Line 614: | ||
return mw.getCurrentFrame():expandTemplate{ | return mw.getCurrentFrame():expandTemplate{ | ||
title = " | title = "User:Saag/Sandbox/Ability card v2/Card", | ||
args = { | args = { | ||
hero_key = hero_key, | hero_key = hero_key, | ||
| Line 553: | Line 635: | ||
num_of_charges = ability.AbilityCharges and ability.AbilityCharges.Value, | num_of_charges = ability.AbilityCharges and ability.AbilityCharges.Value, | ||
notes = notes, | notes = notes, | ||
notes_source_page = notes_source_page | notes_source_page = notes_source_page, | ||
} | } | ||
} | } | ||