Module:Abilities-test/card: Difference between revisionsGive feedback
m Add status effect box |
mNo edit summary |
||
| (9 intermediate revisions by the same user not shown) | |||
| Line 4: | Line 4: | ||
local p = {} | local p = {} | ||
local data = mw.loadJsonData(" | local data = mw.loadJsonData("Data:AbilityCards.json") | ||
-- Maps attr type to an appropriate image and page link | -- Maps attr type to an appropriate image and page link | ||
| 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 | -- TODO - replace this with utils file | ||
function get_ability_card_data(hero_key, ability_num) | function utils.get_ability_card_data(hero_key, ability_num) | ||
if(hero_key == nil) then return nil end | if(hero_key == nil) then return nil end | ||
return data[hero_key][tonumber(ability_num)] | return data[hero_key][tonumber(ability_num)] | ||
| Line 38: | Line 40: | ||
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 66: | Line 73: | ||
-- Pulls data from Data:AbilityCards.json to populate Template:Ability card v2 | -- Pulls data from Data:AbilityCards.json to populate Template:Ability card v2 | ||
function build_ability_card(hero_key, ability_num, add_link, notes, notes_source_page) | function build_ability_card(hero_key, ability_num, add_link, notes, notes_source_page) | ||
local ability = get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then | if(ability == nil) then | ||
return 'Ability data not found for hero ' ..hero_key.. ' and num ' .. ability_num | return 'Ability data not found for hero ' ..hero_key.. ' and num ' .. ability_num | ||
| Line 146: | 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 157: | 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, | ||
| Line 255: | Line 262: | ||
local info_section_num = frame.args[3] | local info_section_num = frame.args[3] | ||
local ability = 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 270: | Line 277: | ||
function get_info_desc(hero_key, ability_num, info_section_num) | function get_info_desc(hero_key, ability_num, info_section_num) | ||
local ability = get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then return "Ability Not Found" end | if(ability == nil) then return "Ability Not Found" end | ||
local info_section = ability['Info'..info_section_num] | local info_section = ability['Info'..info_section_num] | ||
| Line 286: | Line 293: | ||
function get_main_boxes(hero_key, ability_num, info_section_num) | function get_main_boxes(hero_key, ability_num, info_section_num) | ||
local ability = get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then return "Ability Not Found" end | if(ability == nil) then return "Ability Not Found" end | ||
| Line 296: | 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 | 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 332: | Line 344: | ||
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 = | -- 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", | |||
} | } | ||
} | } | ||
| Line 366: | Line 379: | ||
function get_alt_boxes(hero_key, ability_num, info_section_num) | function get_alt_boxes(hero_key, ability_num, info_section_num) | ||
local ability = get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then return "Ability Not Found" end | if(ability == nil) then return "Ability Not Found" end | ||
| Line 411: | Line 424: | ||
local UPGRADE_COST_MAP = {1, 2, 5} | local UPGRADE_COST_MAP = {1, 2, 5} | ||
function get_upgrade_boxes(hero_key, ability_num) | function get_upgrade_boxes(hero_key, ability_num) | ||
local ability = get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then return "Ability Not Found" end | if(ability == nil) then return "Ability Not Found" end | ||
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 440: | Line 466: | ||
title = "User:Saag/Sandbox/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 452: | Line 479: | ||
return upgrade_boxes | return upgrade_boxes | ||
end | end | ||
function create_description(prop, frame) | function create_description(prop, frame) | ||
| Line 459: | 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 501: | 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 559: | Line 593: | ||
end | end | ||
local ability = get_ability_card_data(hero_key, ability_num) | local ability = utils.get_ability_card_data(hero_key, ability_num) | ||
if(ability == nil) then | if(ability == nil) then | ||
return 'Ability data not found for hero ' ..hero_key.. ' and num ' .. ability_num | return 'Ability data not found for hero ' ..hero_key.. ' and num ' .. ability_num | ||