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).
The above documentation is transcluded from Module:CurrentEvents/doc. (edit | history)
local cargo = mw.ext.cargo
local Datetime = require 'Module:DatetimeUtil'
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',
'T0023', 'T0024', 'T0026', 'T0029', 'T0030', 'T0031', 'T0033',
'T0036', 'T0038', 'T0039', 'T0042', 'T0044', 'T0047', 'T0050',
}
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 List.find({'Grand Hero Battle', 'Bound Hero Battle', 'Legendary Hero Battle',
'Mythic Hero Battle', 'Legendary & Mythic Hero Battle'}, v.MapGroup) end,
function (v) return v.MapGroup == 'Limited 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,IF(World='World of Heroes',1,0)=isSpoil"},
{'HallOfForms', "CONCAT('Hall of Forms')=kind, _pageName=page, _pageName=name"},
{'MjolnirsStrike', "CONCAT('Mjölnir\\'s Strike')=kind, _pageName=page, _pageName=name"},
{'FrontlinePhalanx', "CONCAT('Frontline Phalanx')=kind, _pageName=page, _pageName=name"},
{'PawnsOfLoki', "CONCAT('Pawns of Loki')=kind, _pageName=page, _pageName=name"},
{'HeroesJourney', "CONCAT('Heroes Journey')=kind, _pageName=page, _pageName=name"},
{'EventsSummonerDuels',"SUBSTRING(_pageName,1,16)=kind, _pageName=page, _pageName=name"},
{'BindingWorlds', "CONCAT('Binding Worlds')=kind, _pageName=page, _pageName=name"},
{'SeersSnare', "CONCAT('Seer\\'s Snare')=kind, _pageName=page, _pageName=name"},
{'AffinityAutoBattles',"CONCAT('Affinity Auto-Battles')=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'):css('vertical-align', 'middle'):css("margin","5px 35px"):css("display","inline-block")
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(
Datetime.to_cargo(now), Datetime.MAX_TIME),
orderBy = 'StartTime,Map',
limit = 100,
})
List.concat_self(allMaps, cargo.query('LimitedMaps=LM,LimitedMaps__Entry=LME',
"Map,CONCAT('Limited Hero Battle')=MapGroup,LM._pageName=Page,StartTime,EndTime,GROUP_CONCAT(LME._value SEPARATOR ',')=Entry", {
join = 'LM._ID=LME._rowID',
where = ("'%s' BETWEEN StartTime AND EndTime"):format(Datetime.to_cargo(now)),
orderBy = 'StartTime,Map',
groupBy = 'LM._ID',
limit = 100,
}))
for _, v in ipairs(allMaps) do
v.StartTime = Datetime.from_cargo(v.StartTime)
v.EndTime = Datetime.from_cargo(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_ipairs(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
local limited = 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'
elseif v.MapGroup == 'Limited Hero Battle' then
limited = v.Entry
end
local banner = frame:expandTemplate {title = 'Banner HB', args = {v.Page, bannerName = bannerName, limited = limited}}
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(Datetime.to_cargo(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 = Datetime.from_cargo(v.EndTime)
end
-- table.sort(allEvents, function (x, y) return x.EndTime < y.EndTime end)
return table.concat(List.map(allEvents, function (v)
if v.kind == 'Lost Lore' and v.isSpoil == '1' then v.kind = 'Lost Lore Spoils' end
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,
}