Module:AbilityData/test

Revision as of 02:25, 12 October 2024 by Sur (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:AbilityData/test/doc

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'},
	bullet_armor_down = {img='Bullet_armor_down.png', link='Damage_Resistance', size='23px'},
	cast = {img='AttributeIconMaxChargesIncrease.png', link=''},
	charges = {img='AttributeIconMaxChargesIncrease.png', link=''},
	damage = {img='Damage_heart.png', link='', color = 'NoColor'}, -- 'NoColor' will apply no icon color and use the original image
	bullet_damage = {img='Damage.png', link='Bullet_Damage', color = 'Brown'},
	fire_rate = {img='Fire Rate.png', link='Fire_Rate'},
	healing = {img='Health regen.png', link='Health_Regen'},
	health = {img='Extra Health.png', link='Health'},
	move_speed = {img='Move speed.png', link='Move Speed'},
	range = {img='CastRange.png', link='Ability_Range'},
	tech_armor_up = {img='Spirit_Armor.png', link='Damage_Resistance'},
	tech_damage = {img='AttributeIconTechShieldHealth.png', link='Spirit_Damage', color = 'Purple',size = '12px'},
	distance = {img='AttributeIconTechRange.png', link='Ability_Range'},
	duration = {img='AttributeIconTechDuration.png', link='Ability Duration'},
	slow = {img='MoveSlow.png', link=''}
}

-- returns the table of a specific item
function get_ability(hero_key, ability_num)
	local ui_data = data[hero_key]
	if(ui_data == nil) then return "Hero Not Found" end
	return ui_data[tonumber(ability_num)]
end

function get_hero_key(hero_name)
	for i, hero in pairs(data) do
		if hero["Name"] == hero_name then
			return i
		end
	end
	return nil
end

--{{#invoke:AbilityData|get_ability_card|HERO_NAME|ABILITY_NUM|ADD_LINK|NOTES}}--
--Simply calls get_ability_card_from_key with the same parameters, but with key
--get_ability_card and invoke_get_ability_card_key will eventually be removed, and
--get_ability_card_from_key will be renamed to get_ability_card
--both routes exist temporarily as current hero pages use get_ability_card via hero name
--and im currently testing via hero_key on [[User:Sur/Abrams]]
--on the final version with fully automated pages, hero_key will be used.
--for now, hero_name can suffice
p.get_ability_card = function(frame)
	local hero_name = frame.args[1]
	
	local hero_key = get_hero_key(hero_name)
	
	return get_ability_card_from_key(hero_key, frame)
end
--used in development testing on [[User:Sur/Abrams]]
p.invoke_get_ability_card_from_key = function(frame)
	local hero_key = frame.args[1]
	local ability_num = frame.args[2]
	local add_link = frame.args[3]
	local notes = frame.args[4]
	
	local hero_name = data[hero_key]["Name"]
	
	--Replace hero_key in frame.args[1] with hero_name
	local new_frame = mw.clone(frame)
    local new_args = mw.clone(frame.args)
    new_args[1] = hero_name
    new_frame.args = new_args
	return get_ability_card_from_key(hero_key, frame)
end

function get_ability_card_from_key(hero_key, frame)
	local hero_name = frame.args[1]
	local ability_num = frame.args[2]
	local add_link = frame.args[3]
	local notes = frame.args[4]
	
	local ability = get_ability(hero_key, ability_num)
	if(ability == nil) then 
		return 'Ability data not found for hero ' ..hero_key.. ' and num ' .. ability_num
	end
	
	local name_link = nil
	if add_link == 'true' then
		name_link = string.format("%s#(%s)_%s", hero_name, ability_num, ability.Name)
	end
	
	return frame:expandTemplate{
		title = "Ability card v2/Card/test",
		args = {
			hero_key = hero_key,
			ability_num = ability_num,
			name = lang.get_string(ability.Key),
			name_link = name_link,
			icon = lang.get_string(ability.Key, 'en') .. '.png',
			description = frame:preprocess(lang.get_string(ability.DescKey)),
			radius = ability.Radius and ability.Radius.Value,
			range = ability.AbilityCastRange and ability.AbilityCastRange.Value,
			duration = ability.AbilityDuration and ability.AbilityDuration.Value,
			-- ability_width = format_value_with_prepost(width_key, ability[width_key]),
			cooldown =ability.AbilityCooldown and ability.AbilityCooldown.Value,
			charge_cooldown = ability.AbilityCooldownBetweenCharge and ability.AbilityCooldownBetweenCharge.Value,
			num_of_charges = ability.AbilityCharges and ability.AbilityCharges.Value,
			notes = notes
		}
	}	
end

-- Get all info sections for specified ability
--{{#invoke:AbilityData|get_ability_card|HERO_KEY|ABILITY_NUM}}--
p.get_all_info_sections = function(frame)
	local hero_key = frame.args[1]
	local ability_num = frame.args[2]

	local ability = get_ability(hero_key, ability_num)
	if(ability == nil) then return "Ability Not Found" end
	
	local output_template = ''
	for info_section_num=1, 10 do
		local info_section = ability['Info'..info_section_num]
		-- some abilities have no info sections
		if info_section == nil then break end
		local info_template = frame:expandTemplate{
				title = "Ability_card_v2/Card/Info section/test",
				args = {
					hero_key = hero_key,
					ability_num = ability_num,
					info_section_num = info_section_num,
				}
			}
		output_template = output_template .. info_template
	end
	
	return output_template
end

-- Get the description for an ability's info section
--{{#invoke:AbilityData|get_info_desc|HERO_KEY|ABILITY_NUM|INFO_SECTION_INDEX}}--
p.get_info_desc = function(frame)
	local hero_key = frame.args[1]
	local ability_num = frame.args[2]
	local info_section_num = frame.args[3]
	
	local ability = get_ability(hero_key, ability_num)
	if(ability == nil) then return "Ability Not Found" end
	local info_section = ability['Info'..info_section_num]
	
	-- some abilities have no info sections
	if info_section == nil then return '' end
	
	if info_section.DescKey == nil then
		return ''	
	end
	
	return frame:preprocess(lang.get_string(info_section.DescKey))
end
	
--{{#invoke:AbilityData|get_info_main|HERO_KEY|ABILITY_NUM|INFO_SECTION_INDEX}}--
p.get_info_main = function(frame)
	local hero_key = frame.args[1]
	local ability_num = frame.args[2]
	local info_section_num = frame.args[3]
		
	local ability = get_ability(hero_key, ability_num)
	if(ability == nil) then return "Ability Not Found" end
	
	local info_section = ability['Info'..info_section_num]
	
	-- some abilities have no info sections
	if info_section == nil then return '' end
	
	local main = info_section.Main
	if main == nil then
		return ''
	end
	
	local props = info_section.Main.Props
	-- Concatenate multiple section boxes into a single output template 
	local info_box_template = ''
	for k, prop in pairs(props) do
		-- Exclude 0 values
		if prop.Value and prop.Value ~= 0 then
			local icon = get_icon(prop.Type)
			
			section_box = frame:expandTemplate{
				title = "Ability_card_v2/Card/MainBox",
				args = {
					title = prop.Title,
					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
				}
			}
			info_box_template = info_box_template .. section_box .. '\n'
		end
	end
	
	return info_box_template
end

--{{#invoke:AbilityData|get_info_alt|HERO_KEY|ABILITY_NUM|INFO_SECTION_INDEX}}--
p.get_info_alt = function(frame)
	local hero_key = frame.args[1]
	local ability_num = frame.args[2]
	local info_section_num = frame.args[3]
		
	local ability = get_ability(hero_key, ability_num)
	if(ability == nil) then return "Ability Not Found" end
	
	local info_section = ability['Info'..info_section_num]
	
	-- some abilities have no info sections
	if info_section == nil then return '' end
	
	local props = info_section.Alt
	if props == nil then
		return ''
	end
	
	-- Concatenate multiple section boxes into a single output template 
	local info_box_template = ''
	for k, prop in pairs(props) do
		-- 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
		if prop.Value and prop.Value ~= 0 then
			local icon = get_icon(prop.Type)
			section_box = frame:expandTemplate{
				title = "Ability_card_v2/Card/AltBox",
				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
				}
			}
			info_box_template = info_box_template .. section_box .. '\n'
		end
	end
	
	return info_box_template
end

local UPGRADE_COST_MAP = {1, 2, 5}
--{{#invoke:AbilityData|get_upgrades|HERO_KEY|ABILITY_NUM}}--
p.get_upgrades = function(frame)
	local hero_key = frame.args[1]
	local ability_num = frame.args[2]
	local ability = get_ability(hero_key, ability_num)
	if(ability == nil) then return "Ability Not Found" end
	
	local props = ability.Upgrades
	
	-- Concatenate multiple section boxes into a single output template 
	local upgrades_template = ''
	for k, prop in pairs(props) do
		local description = lang.get_string(prop.DescKey)
		
		-- Generate a description if there is no localized string
		if (description == nil or description == '') then
			description = create_description(prop, frame)	
		end
		
		-- Vary the font size based on the number of characters to prevent overflow
		local fontsize = '1rem'
		if #description > 60 and #description < 71 then
			fontsize = '0.95rem'
		elseif #description > 70 and #description < 91 then
			fontsize = '0.875rem'
		elseif #description > 90 then
			fontsize = '0.8rem'
		end
		
		box = frame:expandTemplate{
			title = "Ability_card_v2/Card/UpgradeBox",
			args = {
			  cost = UPGRADE_COST_MAP[k],	
			  description = frame:preprocess(description),
			  scale_value = prop.Scale and commonutils.round_to_sig_fig(prop.Scale.Value, 3),
			  scale_type =  prop.Scale and prop.Scale.Type,
			  fontsize = fontsize
			}
		}
		upgrades_template = upgrades_template .. box .. '\n'
	end
	
	return upgrades_template
end

function create_description(prop, frame)
	local description = ''
	for k, v in pairs(prop) do
		local formatted_value = utils.format_value_with_prepost(k, v, frame)
		local attr_name = lang.get_string(k..'_label')
		description = description .. string.format('%s %s', formatted_value, attr_name)
	end
	
	return description
end

function get_icon(attr_type)
	local mappedAttr = ATTR_TYPE_ICON_MAP[attr_type]
	local img = 'GenericProperty.png'
	local link = ''
	local size = nil
	local color = 'Grey'
	if mappedAttr then
		img = mappedAttr.img
		link = mappedAttr.link
		size = mappedAttr.size
		color = mappedAttr.color or color
	end	
	
	return {img=img, link=link, color=color, size=size}
end

--{{#invoke:AbilityData|get_ability_name|HERO_NAME|ABILITY_NUM}}--
p.get_ability_name = function(frame)
	local hero_name = frame.args[1]
	local ability_num = frame.args[2]
	
	local ability = get_ability(hero_name, ability_num)
	if(ability == nil) then return "Ability Not Found" end
	return ability.Name
end

--Write's an ability link for a given ability name in english
--Siphon Life --> Abrams#(1)_Siphon_Life
function ability_to_hyperlink(ability_name_to_search)
	if (ability_name_to_search == nil) then return "No ability name provided" end
	local hero_name
	local ability_name
	
	-- Iterate heros
	for hero_key, hero_data in pairs(data) do
		-- Iterate abilities
		hero_name = hero_data["Name"]
		for ability_num, ability_data in pairs(hero_data) do
			if (ability_num ~= "Name") then
				ability_name = ability_data["Name"]
				if (ability_name == ability_name_to_search) then
					-- Ability number and hero found
					-- "Siphon Life" > "Siphon_Life"
					ability_name = ability_name:gsub(" ", "_")
					return hero_name .. "#(" .. ability_num .. ")_" .. ability_name
				end
			end
		end
	end
	
	return nil
end

--Writes an ability's icon from its name
--Shoulder Charge --> [[File:Shoulder Charge.png|link=Abrams#(1)_Shoulder_Charge|size=20px]] [[Abrams...|Shoulder Charge]]
p.write_ability_icon = function(frame)
	local ability_name = frame.args[1]
	local custom_display_text = frame.args[2]
	if (custom_display_text == nil or custom_display_text == "") then custom_display_text = ability_name end
	
	local size = 20
	
	local hyperlink = ability_to_hyperlink(ability_name)
	if (hyperlink == nil) then return "Ability " .. ability_name .. " not found" end
	
	local icon = "[[File:" .. ability_name .. ".png|link=" .. hyperlink .. "|" .. size .. "px]]"
	icon = '<span style="position: relative; bottom: 2px; filter: brightness(0) saturate(100%);">' .. icon .. '</span>'
	
	local link = "[[" .. hyperlink .. "|" .. custom_display_text .. "]]"
	
	return icon .. " " .. link
end

function find_width_key(ability)
	for key, value in pairs(ability) do
		if type(key) == "string" and key:sub(-5) == "Width" then
			return key
		end
	end
	return nil
end

function string_in_list(str, list)
	for _, value in ipairs(list) do
		if value == str then
			return true
		end
	end
	return false
end

return p