Module:HeroUtil

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

Utility functions for Heroes.

Lua functions[edit source]

getLowestRarities {...}[edit source]

Obtains the non-focus rarities, focus rarities, and reward rarities of a Hero or all Heroes. Focus and reward rarities are based on all Summoning Focuses and rewards over time.

Parameters[edit source]

  • page: The page name of the Hero.
  • current: True if only the current general summoning pool is used to populate non-focus rarities, false to use all previous general summoning pools as well. This does not affect focus and reward rarities.
  • new: True if only Heroes that appear in New Heroes or Special Heroes summoning events are considered, false to include all summoning events. Has no effect if page is given.
  • mask: If given, must be a table with the following keys:
    • nonfocus: Query non-focus rarities if this field is true, skip the query otherwise.
    • focus: Query focus rarities if this field is true, skip the query otherwise.
    • reward: Query reward rarities if this field is true, skip the query otherwise.

Return values[edit source]

The availability object is a Lua table with the following fields:

  • nonfocus: Lua sequence of rarities at which a Hero can be summoned as a non-focus unit. Unavailable if omitted using the mask parameter; otherwise, always present even if it is empty.
  • focus: Lua sequence of rarities at which a Hero can be summoned as a focus unit. Similarly masked.
  • reward: Lua sequence of rarities at which a Hero has been rewarded. Similarly masked.

And the following method:

  • bounds(): Returns the minimum and maximum rarities the Hero is available at, based on the rarities present in this object. Returns nil if the Hero is unavailable.

If page is given, the return value is simply the availability object of the Hero with that page name.

If page is nil, the function returns a table instead, where each key is a Hero's page name and the value is the availability object of that Hero. Only Heroes with available rarities appear in this table (e.g. Special Heroes will not appear at all if mask is set to {nonfocus = true}, because they never appear as non-focus units in summoning events).

getReleaseTimes {...}[edit source]

Like getLowestRarities, but for the earliest times the Heroes are released.

Parameters[edit source]

  • page, mask: Same as getLowestRarities.
  • current, new: Ignored; these options only affect Heroes who are previously available and therefore cannot alter the release times.

Return values[edit source]

The availability object is a Lua table with the following fields:

  • nonfocus: Unix timestamp representing the earliest time a Hero can be summoned as a non-focus unit. May be masked.
  • focus: Unix timestamp representing the earliest time a Hero can be summoned as a focus unit. May be masked.
  • reward: Unix timestamp representing the earliest time a Hero has been rewarded. May be masked.

And the following method:

  • earliest(): Returns the earliest time a Hero is available, based on the release times present in this object.

All timestamps represent {{MaxTime}} if a Hero is unavailable.

The top-level return value is defined in the same way as getLowestRarities.

Wikitext functions[edit source]

lowestRarity[edit source]

Returns the lowest rarity a Hero is available at, by considering non-focus / focus / reward sources of the Hero. Returns nothing if the Hero is unavailable.

Parameters[edit source]

  • 1: Page name of the Hero.
  • nonfocus: Whether the current general summoning pool is considered.
  • focus: Whether all past summoning events are considered.
  • reward: Whether reward units are considered.

Omitting all of nonfocus, focus, and reward has the same effect as considering all these sources. If only some of these arguments are omitted, the omitted sources are ignored.

availabilityText[edit source]

Returns a wikitext string representing the rarities the Hero on the given page is available at. Only rarities from a single source are chosen; non-focus rarities have the highest priority, followed by focus rarities, and finally reward rarities.

Parameters[edit source]

  • 1, nonfocus, focus, reward: Same as lowestRarity.
  • avail: Lua-only. If given, should be an availability object returned from getLowestRarities; in this case the function uses the rarities defined in that object instead of querying the database with the other parameters.
local cargo = mw.ext.cargo
local List = require 'Module:ListUtil'
local Datetime = require 'Module:DatetimeUtil'
local escq = require 'Module:EscQ'.main1
local toboolean = require 'Module:Bool'.toboolean
local memoize = require 'Module:Memoizer'.memoizer



local getLowestRarities = function (args)
	args = args or {}
	local useNonfocus = not (args.mask and not args.mask.nonfocus)
	local useFocus = not (args.mask and not args.mask.focus)
	local useReward = not (args.mask and not args.mask.reward)
	local unavailable = function ()
		return {
			nonfocus = useNonfocus and {} or nil,
			focus = useFocus and {} or nil,
			reward = useReward and {} or nil,
			bounds = function (self)
				local r = {}
				if self.nonfocus then
					List.concat_self(r, self.nonfocus)
				end
				if self.focus then
					List.concat_self(r, self.focus)
				end
				if self.reward then
					List.concat_self(r, self.reward)
				end
				return List.minmax(r)
			end,
		}
	end
	local ret = {}

	if useNonfocus then
		local nonfocusQuery = cargo.query('SummoningAvailability,Units=U', 'U._pageName=page,Rarity', {
			join = 'SummoningAvailability._pageName=U._pageName',
			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..
				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND Rarity IS NOT NULL" ..
				(args.current and ' AND (NOW() BETWEEN StartTime AND EndTime)' or '') ..
				(args.new and ' AND NewHeroes' or ''),
			groupBy = 'page,Rarity',
			orderBy = 'page,Rarity',
			limit = 5000,
		})
		for page, vs in pairs(List.group_by(nonfocusQuery, function (v) return v.page end)) do
			ret[page] = unavailable()
			for _, v in ipairs(vs) do
				table.insert(ret[page].nonfocus, tonumber(v.Rarity))
			end
		end
	end

	if useFocus then
		local focusQuery = cargo.query('SummoningEventFocuses=SEF,Units=U', 'U._pageName=page,Rarity', {
			join = 'SEF.Unit=U.WikiName',
			where = 'U.WikiName IS NOT NULL AND Rarity IS NOT NULL' .. (args.page and (" AND U._pageName='%s'"):format(escq(args.page)) or ''),
			groupBy = 'page,Rarity',
			orderBy = 'page,Rarity',
			limit = 5000,
		})
		for page, vs in pairs(List.group_by(focusQuery, function (v) return v.page end)) do
			ret[page] = ret[page] or unavailable()
			for _, v in ipairs(vs) do
				table.insert(ret[page].focus, tonumber(v.Rarity))
			end
		end
	end

	if useReward then
		local rewardQuery = cargo.query('Distributions,Units=U', 'U._pageName=page,Rarity', {
			join = 'Distributions.Unit=U._pageName',
			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..
				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND Rarity IS NOT NULL",
			groupBy = 'page,Rarity',
			orderBy = 'page,Rarity',
			limit = 5000,
		})
		for page, vs in pairs(List.group_by(rewardQuery, function (v) return v.page end)) do
			ret[page] = ret[page] or unavailable()
			for _, v in ipairs(vs) do
				table.insert(ret[page].reward, tonumber(v.Rarity))
			end
		end
	end

	return args.page and (ret[args.page] or unavailable()) or ret
end

local getReleaseTimes = function (args)
	args = args or {}
	local useNonfocus = not (args.mask and not args.mask.nonfocus)
	local useFocus = not (args.mask and not args.mask.focus)
	local useReward = not (args.mask and not args.mask.reward)
	local unavailable = function ()
		return {
			nonfocus = useNonfocus and 0x7FFFFFFF or nil,
			focus = useFocus and 0x7FFFFFFF or nil,
			reward = useReward and 0x7FFFFFFF or nil,
			earliest = function (self)
				return select(2, List.min(List.compact {0x7FFFFFFF, self.nonfocus, self.focus, self.reward}))
			end,
		}
	end
	local ret = {}

	if useNonfocus then
		local nonfocusQuery = cargo.query('SummoningAvailability,Units=U', 'U._pageName=page,MIN(StartTime)=t', {
			join = 'SummoningAvailability._pageName=U._pageName',
			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..
				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND StartTime IS NOT NULL",
			groupBy = 'U.WikiName',
			orderBy = 'U.WikiName',
			limit = 5000,
		})
		for _, v in ipairs(nonfocusQuery) do
			ret[v.page] = ret[v.page] or unavailable()
			local t = Datetime.from_cargo(v.t)
			if t < ret[v.page].nonfocus then
				ret[v.page].nonfocus = t
			end
		end
	end

	if useFocus then
		local focusQuery = cargo.query('SummoningEvents=SE,SummoningEventFocuses=SEF,Units=U', 'U._pageName=page,MIN(StartTime)=t', {
			join = 'SE.WikiName=SEF.WikiName,SEF.Unit=U.WikiName',
			where = 'U.WikiName IS NOT NULL AND StartTime IS NOT NULL' .. (args.page and (" AND U._pageName='%s'"):format(escq(args.page)) or ''),
			groupBy = 'U.WikiName',
			orderBy = 'U.WikiName',
			limit = 5000,
		})
		for _, v in ipairs(focusQuery) do
			ret[v.page] = ret[v.page] or unavailable()
			local t = Datetime.from_cargo(v.t)
			if t < ret[v.page].focus then
				ret[v.page].focus = t
			end
		end
	end

	if useReward then
		local rewardQuery = cargo.query('Distributions,Units=U', 'U._pageName=page,MIN(StartTime)=t', {
			join = 'Distributions.Unit=U._pageName',
			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..
				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND StartTime IS NOT NULL",
			groupBy = 'U.WikiName',
			orderBy = 'U.WikiName',
			limit = 5000,
		})
		for _, v in ipairs(rewardQuery) do
			ret[v.page] = ret[v.page] or unavailable()
			local t = Datetime.from_cargo(v.t)
			if t < ret[v.page].reward then
				ret[v.page].reward = t
			end
		end
	end

	return args.page and (ret[args.page] or unavailable()) or ret
end



local getAvail = function (args)
	if args[1] then
		local nonfocus = toboolean(args.nonfocus)
		local focus = toboolean(args.focus)
		local reward = toboolean(args.reward)
		local mask = (nonfocus ~= nil or focus ~= nil or reward ~= nil) and {
			nonfocus = nonfocus,
			focus = focus,
			reward = reward,
		} or nil
		return getLowestRarities {page = args[1], current = true, mask = mask}
	end
end

local lowestRarity = function (args)
	local avail = getAvail(args)
	return avail and (avail:bounds())
end

local availabilityText; do
	local rarityText = memoize(function (rarity)
		return mw.getCurrentFrame():expandTemplate {title = 'Rarity', args = {rarity}}
	end)
availabilityText = function (args)
	local avail = type(args.avail) == 'table' and args.avail or getAvail(args)
	if avail then
		if avail.nonfocus and #avail.nonfocus > 0 then
			avail.focus = nil
			avail.reward = nil
		elseif avail.focus and #avail.focus > 0 then
			avail.reward = nil
		end
		local lo, hi = avail:bounds()
		if hi then
			if lo == hi then
				return rarityText(lo)
			else
				return ('%s&nbsp;–&nbsp;%s'):format(rarityText(lo), rarityText(hi))
			end
		end
	end
	return 'N/A'
end end



local p = require 'Module:MakeMWModule'.makeMWModule {
	lowestRarity = lowestRarity,
	availabilityText = availabilityText,
}
p.getLowestRarities = getLowestRarities
p.getReleaseTimes = getReleaseTimes
return p