We are currently performing an upgrade to our software. This upgrade will bring MediaWiki from version 1.31 to 1.33. While the upgrade is being performed on your wiki it will be in read-only mode. For more information check here.

Module:CurrentEvents

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

This module implements Template:Current Events.

  • maps (t0 = nil)
Displays a list of banners for Special Maps active at the given time (defaults to the current time if not given).
  • events (t0 = nil)
Displays a list of banners for events active at the given time (defaults to the current time if not given).
local cargo = mw.ext.cargo
local Util = require 'Module:Util'
local CargoUtil = require 'Module:CargoUtil'
local List = require 'Module:ListUtil'
local Hash = require 'Module:HashUtil'

-- sort_id1 == 3000
local GHB_REVIVAL = List.to_set {
	'T0003', 'T0001', 'T0004', 'T0007', 'T0002', 'T0005', 'T0006',
	'T0009', 'T0008', 'T0010', 'T0011', 'T0012', 'T0014', 'T0019',
}

local RIVAL_DOMAINS_CYCLE = {'Infantry', 'Armored', 'Cavalry', 'Flying'}

-- reverse appearance order for special maps
-- hero battles -> ghb revivals -> special training -> rival domains -> ghb / bhb / lhb / mhb -> event maps
local MAP_ORDER_FN = {
	function (v) return v.MapGroup == 'Hero Battle' end,
	function (v) return GHB_REVIVAL[v.Map] end,
	function (v) return v.MapGroup == 'Special Training' end,
	function (v) return v.MapGroup == 'Rival Domains' end,
	function (v) return v.MapGroup == 'Grand Hero Battle' or v.MapGroup == 'Bound Hero Battle' or
		v.MapGroup == 'Legendary Hero Battle' or v.MapGroup == 'Mythic Hero Battle' end,
	function (v) return true end,
}

local EVENT_SOURCES = {
	{'VotingGauntlets', "CONCAT('Voting Gauntlet')=kind,   _pageName=page,Name=text,CONCAT('Voting Gauntlet: ',Name)=name"},
	{'TempestTrials',   "CONCAT('Tempest Trials')=kind,    _pageName=page,Name=text,FullName=name"},
	{'TapBattles',      "CONCAT('Tap Battle')=kind,        _pageName=page,Name=text,CONCAT('Illusory Dungeon: ',Name)=name"},
	{'GrandConquests',  "CONCAT('Grand Conquests')=kind,   _pageName=page,          _pageName=name"},
	{'ForgingBonds',    "CONCAT('Forging Bonds')=kind,     _pageName=page,Name=text,CONCAT('Forging Bonds: ',Name)=name"},
	{'RokkrSieges',     "CONCAT('Røkkr Sieges')=kind,      _pageName=page,          _pageName=name"},
	{'LostLore',        "CONCAT('Lost Lore')=kind,         _pageName=page,Name=text,CONCAT('Lost Lore: ',Name)=name"},
	{'HallOfForms',     "CONCAT('Hall of Forms')=kind,     _pageName=page,          _pageName=name"},
	{'MjolnirsStrike',  "CONCAT('Mjölnir\\'s Strike')=kind,_pageName=page,          _pageName=name"},
}



local countdown = function (dt)
	if dt >= 86400 then
		return ('Days left: %d'):format(math.floor(dt / 86400))
	elseif dt >= 3600 then
		return ('Hrs. left: %d'):format(math.floor(dt / 3600))
	else
		return ('Mins. left: %d'):format(math.floor(dt / 60))
	end
end

local eventEntry = function (banner, dt)
	local eventbox = mw.html.create('div'):addClass('panel-eventbox'):css('vertical-align', 'middle')
	eventbox:tag('div'):addClass('img-responsive'):wikitext(banner)
	eventbox:tag('b'):wikitext(countdown(dt))
	return eventbox
end



local maps = function (args, frame)
	local now = args[1] and tonumber(frame:callParserFunction('#time', 'U', args[1])) or os.time()
	local allMaps = cargo.query('Maps,MapDates', 'Map,MapGroup,Maps._pageName=Page,StartTime,EndTime,CycleTime,AvailTime', {
		join = 'Maps._pageName=MapDates._pageName',
		where = ("MapGroup!='Tempest Trials' AND ('%s' BETWEEN StartTime AND EndTime) AND NOT ((CycleTime IS NULL OR AvailTime IS NULL) AND EndTime='%s')"):format(
			Util.formatTime(now), Util.MAX_TIME),
		orderBy = 'StartTime,Map',
		limit = 100,
	})
	for _, v in ipairs(allMaps) do
		v.StartTime = CargoUtil.parse_datetime(v.StartTime)
		v.EndTime = CargoUtil.parse_datetime(v.EndTime)
		v.CycleTime = tonumber(v.CycleTime)
		v.AvailTime = tonumber(v.AvailTime)
	end
	List.keep_if(allMaps, function (v)
		if not v.CycleTime or not v.AvailTime then
			return true
		end
		v.StartTime = math.max(v.StartTime, v.StartTime + math.floor((now - v.StartTime) / v.CycleTime) * v.CycleTime)
		v.EndTime = math.min(v.EndTime, v.StartTime + v.AvailTime - 1)
		return now >= v.StartTime and now <= v.EndTime
	end)

	local sortedMaps = {}
	for _, fn in ipairs(MAP_ORDER_FN) do
		List.concat_self(sortedMaps, List.delete_if(allMaps, fn))
	end
	List.reverse_self(sortedMaps)

	-- existing special map banners
	local vbanners = Hash.from_pairs(cargo.query('_pageData', '_pageName', {
		where = "_pageName RLIKE '^File:Banner V[[:digit:]]+\\.(webp|png)$'",
		limit = 200,
	}), function (v) return mw.ustring.match(v._pageName, 'Banner (V%d+)'), true end)

	return table.concat(List.map(sortedMaps, function (v)
		local bannerName = nil
		if mw.ustring.sub(v.Map, 1, 1) == 'V' then
			bannerName = vbanners[v.Map] and v.Map or 'V0001'
		elseif v.MapGroup == 'Rival Domains' then
			bannerName = 'Rival Domains'
			local num = tonumber(mw.ustring.match(v.Map, '^Q(%d+)$'))
			if num and num >= 9 then
				bannerName = ('Q%04d'):format((num - 1) % 4 + 1)
			end
		elseif v.MapGroup == 'Relay Defense' then
			bannerName = 'R0001'
		end
		local banner = frame:expandTemplate {title = 'Banner HB', args = {v.Page, bannerName = bannerName}}
		return tostring(eventEntry(banner, v.EndTime - now))
	end))
end

local events = function (args, frame)
	local allEvents = {}
	local now = args[1] and tonumber(frame:callParserFunction('#time', 'U', args[1])) or os.time()
	local queryArgs = {where = ("'%s' BETWEEN StartTime AND EndTime"):format(Util.formatTime(now)), groupBy = '_pageName'}
	for _, v in ipairs(EVENT_SOURCES) do
		List.concat_self(allEvents, cargo.query(v[1], v[2] .. ',EndTime', queryArgs))
	end
	for _, v in ipairs(allEvents) do
		v.EndTime = CargoUtil.parse_datetime(v.EndTime)
	end
--	table.sort(allEvents, function (x, y) return x.EndTime < y.EndTime end)

	return table.concat(List.map(allEvents, function (v)
		local banner = v.kind == 'Tempest Trials' and
			frame:expandTemplate {title = 'Banner TT', args = {bannerName = v.text}} or
			frame:expandTemplate {title = 'Banner Event', args = {bannerType = v.kind, fontSize = 4, text1 = v.text, link = v.page}}
		return tostring(eventEntry(('%s<br>[[%s|%s]]'):format(banner, v.page, v.name), v.EndTime - now))
	end))
end

return require 'Module:MakeMWModule'.makeMWModule {
	maps = maps,
	events = events,
}