Module:AbilityData

From Deadlock Wiki
Revision as of 18:40, 28 September 2024 by Saag (talk | contribs) (Undo revision 8860 by Saag (talk) found root cause to be the provided ability data)
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 utils = require "Module:Utilities"

local p = {}
local data = mw.loadJsonData("Data:AbilityCards.json")

-- Maps attr type to an appropriate image and page link
-- Optional icon size, otherwise 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'},
	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_name, ability_num)
	local hero_key = get_hero_key(hero_name)
	if(hero_key == nil) then return "Hero Not Found" end
	return data[hero_key][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}}--
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 ability = get_ability(hero_name, ability_num)
	if(ability == nil) then 
		return 'Ability data not found for hero ' ..hero_name.. ' 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",
		args = {
			hero_name = hero_name,
			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_NAME|ABILITY_NUM}}--
p.get_all_info_sections = 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
	
	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/Info section",
				args = {
					hero_name = hero_name,
					ability_num = ability_num,
					info_section_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_NAME|ABILITY_NUM|INFO_SECTION_INDEX}}--
p.get_info_desc = function(frame)
	local hero_name = frame.args[1]
	local ability_num = frame.args[2]
	local info_section_num = frame.args[3]
	
	local ability = get_ability(hero_name, 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
	
	return frame:preprocess(lang._get_string(info_section.DescKey))
end
	
--{{#invoke:AbilityData|get_info_main|HERO_NAME|ABILITY_NUM|INFO_SECTION_INDEX}}--
p.get_info_main = function(frame)
	local hero_name = frame.args[1]
	local ability_num = frame.args[2]
	local info_section_num = frame.args[3]
		
	local ability = get_ability(hero_name, 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.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 ~= 0 then
			local icon = get_icon(prop.Type)
			
			section_box = frame:expandTemplate{
				title = "Ability_card_v2/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 utils.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_NAME|ABILITY_NUM|INFO_SECTION_INDEX}}--
p.get_info_alt = function(frame)
	local hero_name = frame.args[1]
	local ability_num = frame.args[2]
	local info_section_num = frame.args[3]
		
	local ability = get_ability(hero_name, 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
	
	-- 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 then
			local icon = get_icon(prop.Type)
			
			section_box = frame:expandTemplate{
				title = "Ability_card_v2/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 utils.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_NAME|ABILITY_NUM}}--
p.get_upgrades = 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
	
	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 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/UpgradeBox",
			args = {
			  cost = UPGRADE_COST_MAP[k],	
			  description = frame:preprocess(description),
			  scale_value = prop.Scale and utils.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 = 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

-- Add prefix and postfix labels to a value. Eg. "32" -> "32s"
function format_value_with_prepost(key, value, frame)
	if (value == nil) then return nil end
		
	local prefix = lang._get_string(string.format("%s_prefix",key))
	local postfix = lang._get_string(string.format("%s_postfix",key))
	
	-- Default pre/post fix to empty string, as they may not exist
	if (prefix == nil) then prefix = '' end
	if (postfix == nil) then postfix = '' end
	
	-- If string ends with 'm', then set the postfix to 'm' and remove it
	if utils.string_endswith(tostring(value), 'm') then
		value = tonumber(value:sub(1, -2))	
		postfix = 'm'
	end
	
	if (prefix == '{s:sign}') then
		if value < 0 then 
			prefix = '-'
		else 
			prefix = '+'
		end
	-- if no prefix on positive value, add a '+'
	else
		if value > 0 then
			prefix = '+'
		end
	end
	
	value_and_uom = frame:expandTemplate{
		title = 'Template:ValueAndUom',
		args = {
			prefix..value, 
			postfix,
			uom_style = 'font-size: 12px;'
		}
	}

	return value_and_uom
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