Module:SummoningFocus

From Fire Emblem Heroes Wiki
Jump to: navigation, search
Template-info.svg Documentation

Usage[edit source]

focusPage[edit source]

{{#invoke:SummoningFocus|focusPage
|name=<!--the exact in-game name of the focus goes here-->
|bannerType=
|description=
|youtubeEN=
|youtubeJP=
|rarity5FocusPercent=
|rarity5Percent=
|rarity4Percent=
|rarity3Percent=
|hero1=
|hero2=
|hero3=
|start=
|end=
|stones=
}}

As many Heroes as needed can be specified.

local cargo = mw.ext.cargo
local Util = require 'Module:Util'
local List = require 'Module:ListUtil'
local FEHStatUtil = require 'Module:FEHStatUtil'
local FocusRates = require 'Module:FocusRates'
local focusTable = require 'Module:FocusTable'._table
local escq = require 'Module:EscQ'.main1
local lang = mw.getContentLanguage()
local p = {}

local collectHeroes = function (args)
	local i = 1
	local heroes = {}
	while not Util.isNilOrEmpty(args['hero' .. i]) do
		heroes[i] = args['hero' .. i]
		i = i + 1
	end
	return heroes
end

p.statsTables = function (frame, heroes)
	local heroStats = List.map(heroes, function (h)
		local q = cargo.query('Units,UnitStats', 'Lv1HP5,Lv1Atk5,Lv1Spd5,Lv1Def5,Lv1Res5,HPGR3,AtkGR3,SpdGR3,DefGR3,ResGR3', {
			join = 'Units.WikiName=UnitStats.WikiName',
			where = ("Units._pageName='%s' AND IFNULL(Properties__full,'') NOT LIKE '%%enemy%%'"):format(escq(h)),
			groupBy = 'Units._pageName',
		})[1]
		if not q then
			return {'?/?/?', '?/?/?', '?/?/?', '?/?/?', '?/?/?'}
		end
		local stats = {tonumber(q.Lv1HP5), tonumber(q.Lv1Atk5), tonumber(q.Lv1Spd5), tonumber(q.Lv1Def5), tonumber(q.Lv1Res5)}
		local rates = {tonumber(q.HPGR3), tonumber(q.AtkGR3), tonumber(q.SpdGR3), tonumber(q.DefGR3), tonumber(q.ResGR3)}
		local rarity = 5
		return List.zip(stats, rates, function (base, rate)
			return {
				('%d/%d/%d'):format(base - 1, base, base + 1),
				('%d/%d/%d'):format(
					base + FEHStatUtil.getGrowthValue(rarity, rate - 5) - 1,
					base + FEHStatUtil.getGrowthValue(rarity, rate),
					base + FEHStatUtil.getGrowthValue(rarity, rate + 5) + 1),
			}
		end)
	end)

	local doMakeTable = function (isLv40)
		local tbl = mw.html.create('table'):addClass('wikitable'):addClass('unsortable'):css('text-align', 'center')

		local row = tbl:tag('tr')
		row:tag('th'):css('width', '25%'):wikitext('Hero')
		row:tag('th'):css('width', '15%'):wikitext('HP')
		row:tag('th'):css('width', '15%'):wikitext('Atk')
		row:tag('th'):css('width', '15%'):wikitext('Spd')
		row:tag('th'):css('width', '15%'):wikitext('Def')
		row:tag('th'):css('width', '15%'):wikitext('Res')
	
		for i, hero in ipairs(heroes) do
			local ss = heroStats[i]
			
			local row = tbl:tag('tr')
			row:tag('td'):css('text-align', 'left'):wikitext(('%s [[%s]]'):format(
				frame:expandTemplate {title = 'UnitIcon', args = {name = hero, size = '50px'}}, hero))
			for _, v in ipairs(ss) do
				row:tag('td'):wikitext(v[isLv40 and 2 or 1])
			end
		end

		return tostring(tbl)
	end

	return doMakeTable(false), doMakeTable(true)
end

local SKILL_CATEGORIES = {'weapon', 'assist', 'special', 'passivea', 'passiveb', 'passivec'}

p.skillsTable = function (frame, heroes)
	local heroSkills = List.map(heroes, function (h)
		return List.group_by(cargo.query('Units,UnitSkills,Skills', 'Skills._pageName=page,Skills.Name=name,Scategory', {
			join = 'Units.WikiName=UnitSkills.WikiName,UnitSkills.skill=Skills.WikiName',
			where = ("Units._pageName='%s' AND IFNULL(Units.Properties__full,'') NOT LIKE '%%enemy%%'"):format(escq(h)),
			groupBy = 'UnitSkills.skill',
			orderBy = 'skillPos',
		}), function (v) return v.Scategory end)
	end)

	local tbl = mw.html.create('table'):addClass('wikitable'):addClass('unsortable'):css('text-align', 'center')
	
	local row = tbl:tag('tr')
	row:tag('th'):css('width', '18em'):wikitext('Hero')
	row:tag('th'):css('width', '9em'):wikitext('Weapon')
	row:tag('th'):css('width', '9em'):wikitext('Assist')
	row:tag('th'):css('width', '9em'):wikitext('Special')
	row:tag('th'):css('width', '9em'):wikitext('Passive A')
	row:tag('th'):css('width', '9em'):wikitext('Passive B')
	row:tag('th'):css('width', '9em'):wikitext('Passive C')

	for i, hero in ipairs(heroes) do
		local ss = heroSkills[i]
		
		local row = tbl:tag('tr')
		row:tag('td'):tag('div'):css('display', 'inline-block'):wikitext(frame:expandTemplate {title = 'UnitText with Type', args = {name = hero}})
		for _, cat in ipairs(SKILL_CATEGORIES) do
			local s = ss[cat]
			row:tag('td'):wikitext(s and table.concat(List.map_self(s, function (skill)
				return ('[[%s|%s]]'):format(skill.page, skill.name)
			end), '<br>') or '—')
		end
	end

	return tostring(tbl)
end

function p.focusPage(frame)
	local ytText
	if not (Util.isNilOrEmpty(frame.args.youtubeEN) and Util.isNilOrEmpty(frame.args.youtubeJP)) then
		ytText = frame:callParserFunction{ name = '#tag', args = { "tabber", "English=" .. frame:callParserFunction{ name="#ev:youtube", args = { frame.args.youtubeEN } } .. "|-|Japanese=".. frame:callParserFunction{ name="#ev:youtube", args = { frame.args.youtubeJP } }} }
	else
		ytText= ""
	end
	
	local rateTbl = mw.html.create("table")
		:addClass("wikitable")
		:addClass("default")
		:css("text-align","center")
	local headers = rateTbl:tag("tr")
	headers:tag("th"):wikitext("Rarity")
	headers:tag("th"):wikitext("Appearance rate")

	local focusRarities = {}
	for i = 5,1,-1 do
		if not Util.isNilOrEmpty(frame.args["rarity" .. i .."FocusPercent"]) then
			table.insert(focusRarities, 1, tostring(i))
			local row = rateTbl:tag("tr")
			row:tag("td"):wikitext(i.."★ Focus")
			row:tag("td"):wikitext(frame.args["rarity" .. i .."FocusPercent"])
		end
		if not Util.isNilOrEmpty(frame.args["rarity" .. i .."Percent"]) then
			local row = rateTbl:tag("tr")
			row:tag("td"):wikitext(i.."★")
			row:tag("td"):wikitext(frame.args["rarity" .. i .."Percent"])
		end
	end
	
	local notesSection
	if Util.isNilOrEmpty(frame.args.notes) then
		notesSection = ""
	else
		notesSection="<h2>Notes</h2>" .. frame.args.notes
	end

	local heroTable = collectHeroes(frame.args)

	--Determine the pool
	local isNew = false
	local startDate
	if not Util.isNilOrEmpty(frame.args.start) then -- this check is required because lang:formatDate will return the current date if it receives no string parameter
		startDate = lang:formatDate('Y-m-d', frame.args.start)
	end
	local endDate
	if not Util.isNilOrEmpty(frame.args['end']) then
		endDate = lang:formatDate('Y-m-d', frame.args['end'])
	end
	
	if startDate and startDate >= '2019-04-05' then
		if frame.args.bannerType == 'New Heroes' then
			isNew = true
		end
		if frame.args.bannerType == 'Special' then
			dates = cargo.query('SummoningFocuses', 'StartDate', {
				where = "Name='" .. escq(frame.args.name) .. "'",
				groupBy = 'StartDate',
				orderBy = 'StartDate'
			})
			if #dates == 0 or dates[1].StartDate == startDate then
				isNew = true
			end
		end
	end

	local lv1stats, lv40stats = p.statsTables(frame, heroTable)

	local contents = {
		frame:expandTemplate {title = 'SummoningFocusDefinition', args = {
			wikiname = frame.args.wikiname,
			name = frame.args.name,
			start = frame.args.start,
			['end'] = frame.args["end"],
			rarity = table.concat(focusRarities, ';'),
			bannerType = frame.args.bannerType,
			heroList = table.concat(heroTable, ";"),
		}},
		'__NOTOC__',
		focusTable {
			page = mw.title.getCurrentTitle().text,
			name = frame.args.name,
			startDate = startDate,
			endDate = endDate,
			heroes = table.concat(heroTable, ";"),
			extratitle = 'Description',
			extratext = frame.args.description,
		},
		ytText,
		'<h2>Appearance rates</h2>',
		frame:expandTemplate {title = 'Hatnote', args = {"See [[Summonable Heroes]] for a full table of the regular pool of summonable heroes."}},
		tostring(rateTbl),
		FocusRates.focusRates(frame, isNew),
		frame:expandTemplate {title = 'Hatnote', args = {"For more detailed information, see [[Summon#Color Distribution]]."}},
		'<h2>Skills</h2>', p.skillsTable(frame, heroTable),
		'<h2>Level 40 stats</h2>', lv40stats,
		notesSection,
		frame:expandTemplate {title = 'Summoning Focus Navbox'},
	}
	
	return table.concat(contents)
end

return p