Fire Emblem Heroes Wiki
Advertisement
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Template-info Documentation

Used by {{Skill Hero List}} on individual skill pages, to show which heroes learn this skill.

local Util = require('Module:Util')
local HeroUtil = require 'Module:HeroUtil'
local cargo = mw.ext.cargo
local p = {}
local List = require 'Module:ListUtil'
local Hash = require 'Module:HashUtil'
local escq = require 'Module:EscQ'.main1

-- unobtainable rarity value
local BAD_RARITY = 5 + 1

-- breadth-first search, input node goes to index 0
local bfs = function (node, graph)
	local i = 0
	local list = {[i] = node}
	local included = {[node] = true}

	while true do
		local current = list[i]
		if not current then
			break
		end
		i = i + 1
		local neighbours = graph[current]
		if neighbours then
			for _, v in ipairs(neighbours) do
				if not included[v] then
					list[#list + 1] = v
					included[v] = true
				end
			end
		end
	end

	return list
end

local getPreEvolved = function (wikiName, pagename)
	local frame = mw.getCurrentFrame()
	local baseWeaponQuery = cargo.query('WeaponEvolutions,Skills', 'Skills.WikiName=name', {
		join = 'WeaponEvolutions.BaseWeapon=Skills.WikiName',
		where = ("EvolvesInto='%s'"):format(escq(wikiName)),
		groupBy = 'BaseWeapon',
	})
	if #baseWeaponQuery > 0 then
		local links = List.map(baseWeaponQuery, function (v)
			return frame:expandTemplate{title = 'Wt', args = {v.name}}
		end)
		local last = table.remove(links)
		local wepList = #links == 0 and last or (table.concat(links, ', ') .. (#links >= 2 and ', or ' or ' or ') .. last)
		return ('[[Category:Evolved weapons]][[%s]] can be evolved from %s using the [[Weapon Refinery]].<br>'):format(pagename, wepList)
	else
		return ''
	end
end

local heroList = function (args)
	local pagename = args[1]
	-- any skill from the page can be used
	local skillQuery = cargo.query('Skills', 'WikiName,Scategory', {
		where = ("_pageName='%s'"):format(escq(pagename)),
		limit = 1,
	})[1] or {}
	local wikiName = skillQuery.WikiName or ''
	local cat = skillQuery.Scategory or ''
	local header = cat == 'weapon' and getPreEvolved(wikiName, pagename) or ''

	local heroesWithSkill = cargo.query(
		'Units,UnitSkills',
		"Units._pageName=page,Units.WikiName=wikiname,IFNULL(CONCAT(Name,': ',Title),Name)=name", {
			join = 'Units.WikiName=UnitSkills.WikiName',
			where = ("skill='%s'"):format(escq(wikiName)),
			groupBy = 'Units._pageName',
			limit = 500,
		})
	if #heroesWithSkill == 0 then
		return header .. "This skill is currently not owned by any unit."
	end

	local avail = HeroUtil.getLowestRarities {current = true}

	local heroSkills = Hash.from_ipairs(heroesWithSkill, function (hero)
		local lowestRarity = avail[hero.page] and avail[hero.page]:bounds() or BAD_RARITY
		return hero.name, List.map_self(cargo.query('UnitSkills,Skills', 'Skills.WikiName=tag,Skills.Name=name,Skills._pageName=page,defaultRarity=dr,unlockRarity=ur', {
			join = 'Skills.WikiName=UnitSkills.skill',
			where = ("UnitSkills.WikiName='%s' AND Scategory='%s'"):format(escq(hero.wikiname), escq(cat)),
			limit = 1000,
		}), function (v)
			v.rarity = math.max(math.min(tonumber(v.dr) or BAD_RARITY, tonumber(v.ur) or BAD_RARITY), lowestRarity)
			return v
		end)
	end)

	local skillSet = {}
	for _, skills in pairs(heroSkills) do
		for _, skill in ipairs(skills) do
			skillSet[skill.tag] = true
		end
	end

	local prereq_graph, after_graph = Util.getSkillChains(Hash.keys(skillSet))
	local prereqs = List.reverse_self(bfs(wikiName, prereq_graph))
	local afters = bfs(wikiName, after_graph)
	local skillOrder = Hash.invert(List.concat(prereqs, List.concat({wikiName}, afters)))
	Hash.map_self(heroSkills, function (skills)
		local chainSkills = List.select(skills, function (skill) return skillOrder[skill.tag] end)
		table.sort(chainSkills, function (lhs, rhs) return skillOrder[lhs.tag] < skillOrder[rhs.tag] end)
		return chainSkills
	end)

	local maxColumns = math.max(0, unpack(List.map(Hash.values(heroSkills), function (skills) return #skills end)))

	-- Initialize the table
	local tbl = mw.html.create('table')
		:addClass('wikitable striped sortable')
		:css('text-align','center')

	-- Table Headers
	tbl:tag('th')
		:wikitext('Unit')
	tbl:tag('th')
		:attr('colspan', maxColumns)
		:wikitext('Skill chain')
	
	local RARITY_TXT = Util.getRarityTexts()
	RARITY_TXT[BAD_RARITY] = 'N/A'

	for _, hero in ipairs(heroesWithSkill) do
		local cells = List.map(heroSkills[hero.name], function (skill)
			return ("[[%s%s]]<br>%s"):format(skill.page, skill.page == skill.name and '' or ('|' .. skill.name), RARITY_TXT[skill.rarity])
		end)

		local tr = tbl:tag('tr')

		-- Hero Name
		tr:tag('td')
			:tag('div')
			:wikitext(Util.getHeroIcon(hero.page, '51px') .. '<br>')
			:css('margin-top','5px')
			:done()
			:tag('div')
			:wikitext('[[' .. hero.page .. '|' .. hero.name .. ']]')

		for j = 1, maxColumns do
			tr:tag('td')
				:wikitext(cells[j] or '–')
				:css('min-width','80px')
		end
	end

	return header .. tostring(tbl)
end

return require 'Module:MakeMWModule'.makeMWModule {heroList = heroList}
Advertisement