Module:AbilityData

From Deadlock Wiki
Revision as of 19:28, 14 October 2024 by Sur (talk | contribs) (get_ability_card function forwarding simplified now that the alternate function is internal and not external)
Jump to navigation Jump to search

Deprecated

This module is being replaced by multiple modules in Module:Abilities. Any new functions should be created there


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 ability_num = frame.args[2]
	local add_link = frame.args[3]
	local notes = frame.args[4]
	
	local hero_key = get_hero_key(hero_name)
	
	return get_ability_card_from_key(hero_key, ability_num, add_link, notes)
end

function get_ability_card_from_key(hero_key, ability_num, add_link, notes)
	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 ability_name_localized = lang.get_string(ability.Key)
	local name_link = nil
	if add_link == 'true' then
		name_link = ability_name_localized
	end
	
	return mw.getCurrentFrame():expandTemplate{
		title = "Ability card v2/Card",
		args = {
			hero_key = hero_key,
			ability_num = ability_num,
			name = ability_name_localized,
			name_link = name_link,
			icon = lang.get_string(ability.Key, 'en') .. '.png',
			description = mw.getCurrentFrame():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",
				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