Module:Skill

Jump to navigation Jump to search

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

local getArgument = require('Module:Arguments').getArgument

local p = {}

function capitalFirst(str) -- Allows capitalization of the first letter of each word in a string; adapted from (https://stackoverflow.com/questions/20284515/capitalize-first-letter-of-every-word-in-lua)
    return (str:gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end))
end

local function getSkillData(game, input)
    local skillData = mw.loadData('Module:Data/Skill/' .. game).skill
    local skill = skillData[input]
    if not skill then
        error('Skill "' .. input .. '" not defined for ' .. game)
    else
    	return skill
    end
end

local function makeSkillLink(skill, potential)
    if skill.link then
        return '[[' .. skill.link .. '|' .. skill.name .. ']]' .. (potential or '')
    end
    return '[[' .. skill.name .. ']]' .. (potential or '')
end

local function getIcons(game)
    local iconPage = mw.title.makeTitle('Module', 'Data/Icon/' .. game)
    if iconPage.exists then
        return mw.loadData('Module:Data/Icon/' .. game).icon
    else
    	return nil
    end
end

local function makeLinkWithIcon(game, skill, name)
    local icons = getIcons(game)
	if not icons then
        return name
    end
    if game == 'desum' then
        local icon = icons[skill.desumicon]
        return icon .. '<small> </small>' .. name
    end
    if skill.icon and icons[skill.icon] then
        return icons[skill.icon] .. ' ' .. name
    end
    local attribute = skill.attribute and skill.attribute:lower()
    if attribute and icons[attribute] then
        return icons[attribute] .. ' ' .. name
    else
    	return name
    end
end

function p.Name(frame)
    local game = frame.args[1]:lower()
    local input = mw.ustring.lower(frame.args[2])
    local skill = getSkillData(game, input)
    return '<span style="white-space:nowrap">' .. makeLinkWithIcon(game, skill, makeSkillLink(skill)) .. '</span>'
    --Skill potential / skill levels for Nine are not supported at the present
end

function p.Main(frame) 
	local args = frame.args
	local game = args[1]:lower()
	local input = mw.ustring.lower(args[2])
	local icons = getIcons(game) -- Creates information about a given page
	local skills = mw.loadData('Module:Data/Skill/' .. game).skill
-- 1 SKILL NAME
-- 1.1 SKILL POTENTIAL IN SMT5
	local skillPotential = ''
	if game == 'smt5' or game == 'smt5v' then -- Check if game is Shin Megami Tensei V, so that the Skill Potential can be added to the name
		if string.sub(input, -2, -2) == '-' or string.sub(input, -2, -2) == '+' then
			skillPotential = ' ' .. string.sub(input, -2, -1)
			skillPotentialStore = string.sub(input, -2, -1)
			input = string.sub(input, 1, -4)
		else
			skillPotential = ''
		end
	else
		skillPotential = ''
	end
	if game == 'smtn' then -- Check if game is Shin Megami Tensei Nine, so that the Skill Level can be added to the name
		if string.sub(input, -4, -3) == 'lv' then
			skillPotential = " LV " .. string.sub(input, -1, -1)
			input = string.sub(input, 1, -6)
		elseif skills[input] then
			if skills[input].skilltype:lower() ~= "skill" then
				skillPotential = " LV 1"
			end
		else
			skillPotential = ""
		end
	end
	local skill = getSkillData(game,input)
	if not skill then --Error message for invalid skill
		error("Skill \"" .. input .. "\" not defined for " .. game)
	end
-- 1.2 SKILL LINK
	name = makeSkillLink(skill,skillPotential)
-- 3 NAME AND ATTRIBUTE
-- 3.1 NAME NOTE
	if skill and skill.name_note then
		namenote = frame:expandTemplate{ title = 'exp', args = { skill.name_note } }
	else
		namenote = ''
	end
	if game == 'mip' and skill and skill.rpname then
		rpname = ' / ' .. skill.rpname
	else
		rpname = ''
	end
-- 4.1 FOR DESUM
	if game == 'desum' then
		if skill and skill.attribute_link then
			nameattribute = '\n|style="text-align:left; white-space:nowrap"|' .. makeLinkWithIcon(game,skill,name) .. namenote .. '\n|style="text-align:center;"|' .. '[[' .. skill.attribute_link ..  '|' .. capitalFirst(skill.attribute:lower()) .. ']]'
		else
			nameattribute = '\n|style="text-align:left; white-space:nowrap"|' .. makeLinkWithIcon(game,skill,name) .. namenote .. '\n|style="text-align:center;"|' .. '[[' .. capitalFirst(skill.attribute:lower()) .. ']]'
		end
-- 4.2 FOR OTHER GAMES
	else
-- 4.3 SET ATTRIBUTE OUTPUT
		if skill.attribute then
			attribute = skill.attribute:lower()
		else
			attribute = ''
		end
		if attribute == 'pc' or attribute == 'ps' or attribute == 'sf' then
			attributeout = attribute:upper()
		else
			attributeout = capitalFirst(attribute)
		end
-- 4.4 IF ICON PAGE EXISTS
		if icons then
			if skill.icon and icons[skill.icon] then
				nameattribute = '\n|style="text-align:left; white-space:nowrap"|' .. makeLinkWithIcon(game,skill,name) .. rpname .. namenote
			elseif game == 'smtn' and skill.skilltype:lower() == "skill" then
				nameattribute = '\n|style="text-align:center;"|' .. name .. namenote
			elseif game == 'smttc' then
				nameattribute = '\n|style="text-align:center;"|' .. name .. namenote
			elseif icons[attribute] then -- Check if attribute is set in skill data
				nameattribute = '\n|style="text-align:left; white-space:nowrap"|' .. makeLinkWithIcon(game,skill,name) .. rpname .. namenote
			elseif skill and skill.attribute_link then
				nameattribute = '\n|style="text-align:center"|' .. name .. namenote .. '\n|style="text-align:center;"|' .. '[[' .. skill.attribute_link ..  '|' .. attributeout .. ']]'
			else
				nameattribute = '\n|style="text-align:center;"|' .. name .. namenote .. '\n|style="text-align:center;"|' .. '[[' .. attributeout .. ']]'
			end
-- 4.5 IF ICON PAGE DOES NOT EXIST
		elseif game == "ab" then
			nameattribute = '\n|style="text-align:center;"|' .. name .. namenote
		elseif attribute == nil or attribute == '' or attribute == '—' then
			nameattribute = '\n|style="text-align:center;"|' .. name .. namenote .. '\n|style="text-align:center;"|' .. '—'
		elseif skill and skill.attribute_link then
			nameattribute = '\n|style="text-align:center; white-space:nowrap"|' .. name .. namenote .. '\n|style="text-align:center;"|' .. '[[' .. skill.attribute_link ..  '|' .. attributeout .. ']]'
		else
			nameattribute = '\n|style="text-align:center; white-space:nowrap"|' .. name .. namenote .. '\n|style="text-align:center;"|' .. '[[' .. attributeout .. ']]'
		end
	end
-- 5 COST AND COST TYPE
	if skill.costtype then
		costType = ' ' .. skill.costtype
	else
		costType = ''
	end
	if skill.cost == nil then
		cost = ''
	elseif skill.cost == '' or skill.cost == '—' then
		cost = '\n|style="text-align:center;"|' .. '—'
-- 5.1 FOR SMT5
	elseif type(skill.cost) ~= "string" and skillPotentialStore then -- Check if game is Shin Megami Tensei V, as that game has multipliers based on Skill Potential values, as listed below
		if skill.attribute == 'support' or skill.attribute == 'healing' then -- For support skills
			skillPotentialStore = skillPotentialStore .. 'hs'
		end
		costCalc = skill.cost * mw.loadData('Module:Data/Skill_Potential/' .. game).skillPotential[skillPotentialStore]
		if math.fmod(costCalc,1) > 0.95 then
			costOut = math.ceil(costCalc)
		else
			costOut = math.floor(costCalc)
		end
			cost = '\n|style="text-align:center;"|' .. costOut .. costType -- Set cost type with multiplier
-- 5.2 FOR OTHER GAMES
	elseif game == 'smttc' and skill.costIcon ~= '' then
		cost = '\n|style="text-align:center; white-space:nowrap"|' .. icons[skill.costIcon] .. ' ' .. skill.cost .. costType 
	else
		cost = '\n|style="text-align:center; white-space:nowrap"|' .. skill.cost .. costType
	end
-- 6 RANGE
	local excludeRange = {
		['r'] = false,
		['mip'] = false,
		['desum'] = true,
		['sh1'] = true,
		['p5t'] = false,
		['pq1'] = true,
		['pq2'] = true,
		['desu1'] = true,
		['desu1oc'] = true,
		['desu2'] = true,
		['desu2rb'] = true,
	}
	if excludeRange[game] == not true and skill and skill.range then -- Check if the skill has a range parameter; omit if not
		range = '\n|style="text-align:center;"|' .. skill.range
	else
		range = ''
	end
-- 7 LEVEL
	if args[3] and game ~= 'mip' then -- Check if a parameter for the level is set by the user, otherwise omit it
		if args[3] == '' then
			level = ''
		elseif args[3] == '-' then
			level = '\n|style="text-align:center;"|' .. 'Innate'
		else
			level = '\n|style="text-align:center;"|' .. args[3]
		end
	else
		level = ''
	end
-- 8 RANK AND INHERITANCE IN MIP
	if game == 'mip' and args[3] and args[3] ~= '' then -- Check if game is Megami Ibunroku Persona, and if an inherit value is set.
		if args[3]:lower() == 'y' then
			rank = ''
			inherit = '\n|style="text-align:center;"|<span style="color:lime;">✔</span>'
		elseif args[3]:lower() == 'n' then
			rank = ''
			inherit = '\n|style="text-align:center;"|<span style="color:red;">✘</span>'
		else
			rank = '\n|style="text-align:center;"|' .. args[3]
			inherit = ''
			cost = '' -- REMOVES COST
		end
	elseif args[3]:lower() == 'e' then -- Removes cost and level if set to 'e' so that cost can be disabled on enemy tables for games where enemies have no skill costs
		rank = ''
		inherit = ''
		cost = ''
		level = ''
	else
		rank = ''
		inherit = ''
	end
-- 8.1 INHERITANCE IN P5X
	if game == 'p5x' and args[4] and args[4] ~= '' then
		if args[4]:lower() == 'y' then
			inherit = '\n|style="text-align:center;"|<span style="color:lime;">✔</span>'
		elseif args[4]:lower() == 'n' then
			inherit = '\n|style="text-align:center;"|<span style="color:red;">✘</span>'
		else
			inherit = ''
		end
	end
-- 9 DESCRIPTION OR EFFECT
	if skill and skill.description and game ~= 'smttc' and game ~= 'p5x' then
		description = '\n|style="text-align:left;"|' ..skill.description
	elseif skill and skill.description and game == 'p5x' then
		description = '\n|style="text-align:left; max-width:500px"|' ..skill.description
	elseif skill and skill.effect then
		description = '\n|style="text-align:left;"|' .. skill.effect
	else
		description = ''
	end
-- 9.1 SKILL LEVELS IN P5X

	if game == 'p5x' then
		if string.find(description, 'EFF1') and skill.eff1 then
			description = string.gsub(description, 'EFF1', frame:preprocess(skill.eff1))
		end
		if string.find(description, 'EFF2') and skill.eff2 then
			description = string.gsub(description, 'EFF2', frame:preprocess(skill.eff2))
		end
		if string.find(description, 'EFF3') and skill.eff3 then
			description = string.gsub(description, 'EFF3', frame:preprocess(skill.eff3))
		end
		if string.find(description, 'EFF4') and skill.eff4 then
			description = string.gsub(description, 'EFF4', frame:preprocess(skill.eff4))
		end
	end

-- 10 FUSION SPELLS
	if skill and skill.fusion then
		fusion = '\n|style="text-align:center;"|' ..skill.fusion
	else
		fusion = ''
	end
	local prerequisite = ""
	if args[4] and game == 'sh2' then -- Check if a parameter for the level is set by the user, otherwise omit it
		if args[4] ~= "" then
			prerequisite = '\n|style="text-align:center;"|' .. args[4]
		end
	end
-- 11 FINAL OUTPUT
	local output = nameattribute .. cost .. range .. description .. level .. rank .. inherit .. fusion .. prerequisite .. '\n|-'
	return output
end

return p