Module:MiniEvent

--[[ Lua script to get Mini Event information

getME: get Mini Event based on input parameters Parameters: 1 = name    : Mini Event name (defaults to PAGENAME) 2 = number  : Event Number (multiple Numbers can be specified                    separated with ",") 3 = options : One or more Output Options Some Options are mutually exclusive --- Fixed Formats The priority is in the below order Only the first ME number will be displayed C = Fixed Text ME Count Till Today E = Event Page Format (Table Row: Columns= Icon, Short Name, Dates w/o year) T = Timeline Page Format (Table Columns: Icon + Short Name #, Dates with year) (Parameter 4 can be  for italic and ' for bold') K = toKen Page Format (Table Row: Columns= Icon, Full Name Sub Text) (sub text in parameter 4) L = Latest Info Main Page Format (Short Name with small Date) G = NPC Generated for Attraction Page R = Rewards (milestone/leaderboard) Parameter 5 specifies the reward type First character M for milestone, L for leaderboard Second character/digit for milestone # / leaderboard pos If the ME is part of LTE, it is automatically added U = Single Event Number entry on the Mini Event Page If the Current Page is not the Mini Event Page, the ME name is displayed as link to the ME page. --- Customizable Display Format Options F = Full ME Name 9 = Include ME Number S = Short ME Name D = Append ME Date(s) A = Alternate Text (parameter 4) 4 = alt text : Alternate Text / Sub Text / bold-italic

getLastME: get Last X Events (formatted for main page) Output Format is Fixed ("L") Parameter: 1 = Count : return Last Count Events (default 5)

getEventME: get Mini Events during LTE Output Format is Fixed ("E") Parameters: 1 = LTE name : Limited Time Event Name

getMEList: get a List of Mini Events in horizontal format Output Format is Fixed ("H") Parameters: None

getMETimeLine: get a Complete Time Line of Mini Events Output Format is Fixed ("T") Parameters: None

getMENPCUsage: get a list of Mini Events using NPC Output is Fixed Text By default only Lists ME with special NPC version or during LTE Parameters: 1 = NPC Name : Non-Playable Character name 2 = All : If present include all NPC usage getMEHeader: get the Mini Event page header Mini Event name is the page name Output is Fixed Text Parameters: 1 = ME Objective (Text) %n or %N are replaced with NPC name 2 = ME Name (default PAGENAME) mainly for testing --]]

local p = {}

local meData = mw.loadData( 'Module:MiniEvent/data') local npc = require('Module:NPC') local lte = require("Module:LTEvent").getLTE local coll = require("Module:ItemCollection").getCollection local date = require('Dev:Date') local util = require('Module:Utility')

-- Get the Event Start time from the utility module local dayStart = util.dayStart local today = os.date("%Y/%m/%d %H:%M:%S")

-- local functions --

-- function get single event local function singleEvent(sName, sNumber, sOption, altText, sReward) local eventName = "Unknown Event" local eventNumb = {} local eventDate = "" local eventDays = nil local eventMain = nil local npcVer   = nil local eventRuns = nil

local linkText = "Work In Progress" local linkPage = "" local linkHash = "" local eType = ""

-- save Event table and first Number table for later local tEvent = {} local tNumb = {}

if meData[sName] then -- ME-Type Data table tEvent = meData[sName]

eventName = tEvent["Name"] or "Data Error" nameNPC  = tEvent["NPC"] or "" linkText = eventName .. " Mini Event"

for n in string.gmatch(sNumber, "%d+") do           if tonumber(n) == 0 then eventRuns = true end if tEvent[tonumber(n)] then table.insert(eventNumb, tonumber(n)) end end

if nameNPC == "TTC" then eType = "T" linkText = eventName eventName = tEvent["Disp"] or eventName

if eventNumb[1] then tNumb = tEvent[eventNumb[1]] eventDate = tNumb[1] or "" eventDays = tNumb[2] or 0 eventMain = tNumb[3] npcVer   = tNumb[4]

linkHash = "#Mini Events" end else if tEvent["Disp"] then eventName = tEvent["Disp"] end

if eventNumb[1] then -- ME# data table tNumb = tEvent[eventNumb[1]] eventDate = tNumb[1] or "" eventDays = tNumb[2] or 0 eventMain = tNumb[3] npcVer   = tNumb[4]

-- check if the ME page has parts if tEvent["Page"] then for i, n in ipairs(tEvent["Page"]) do                      if eventNumb[1] < n then linkPage = "/Part " .. tostring(i) break end end end

-- check if npcVer is "none", in case LTE but no special version if npcVer and npcVer == "none" then npcVer = nil end

-- check for alternate NPC if tNumb[5] and tEvent["NPC" .. tNumb[5]] then nameNPC = tEvent["NPC".. tNumb[5]] end linkHash = "#" .. eventName .. " #"                  .. tostring(eventNumb[1]) end end end

local outText = {  "", "", "", "", "", "", "", "", "", "",                       "",                        eventName, "", "", "", "", "", "", "", "", "",                       "", "", "", "", "\n" }

if eType == "T" then outText[17] = " Chapter #" .. tostring(eventNumb[1]) end if string.match(sOption, "[ETKLGRUI]") then -- Fixed Formats if string.match(sOption, "I") and nameNPC ~= ""then return npc.getNPC({nameNPC, nil, nil, (altText or 60), eventMain or npcVer}) elseif string.match(sOption, "E") then -- Event Page Format return table.concat({'|-|', eventName, " #", eventNumb[1], '=\n\n'}) elseif string.match(sOption, "T") then -- TimeLine Page Format outText[1] = "|"

if nameNPC ~= "" then outText[5] = npc.getNPC({nameNPC, nil, nil, nil, eventMain or npcVer}) end

outText[6] = " " outText[7] = altText

if eventNumb[1] and eventDate ~= "" and eType ~= "T" then outText[17] = " #" .. tostring(eventNumb[1]) end if eType == "T" then outText[16] = "" end

outText[21] = altText outText[22] = "\n|"

if eventDate ~= "" then outText[23] = util.strDate(eventDate, eventDays) end elseif string.match(sOption, "L") then -- Latest Info Main Page Format outText[1] = "* "

if eventDate ~= "" then outText[22] = " " outText[23] = util.strDate(eventDate, 0, nil, true) outText[24] = " " end elseif string.match(sOption, "G") then -- Gold Trophy Format outText[2] = npc.getNPC({nameNPC, nil, nil, nil, eventMain or npcVer}) .. " "           outText[3] = mw.title.getCurrentTitle.text outText[4] = " generated " outText[6] = " during the "

if nameNPC ~= "" then outText[5] = npc.getNPC({nameNPC, "L"}) end if eventNumb[1] then outText[7] = util.ordinal(eventNumb[1]) if eventRuns then outText[4] = " generates " outText[6] = " since the " elseif eventNumb[2] then outText[6] = " from the " outText[8] = " to the " outText[9] = util.ordinal(eventNumb[2]) end outText[10] = " " end outText[18] = " Mini Event" outText[30] = "." elseif string.match(sOption, "R") then -- Reward format local mile, pos = string.match(sReward, "^([LM])(.*)") local vars = { ["P"] = mw.title.getCurrentTitle.subpageText:gsub("s?$","s",1), ["p"] = mw.title.getCurrentTitle.subpageText:gsub("s?$","",1), }

outText[2] = npc.getNPC({nameNPC, nil, nil, nil, eventMain or npcVer}) .. " "           if altText and altText ~= "" then outText[3] = altText:gsub("%%(.)", vars) else outText[3] = mw.title.getCurrentTitle.subpageText end if eventDate > today then outText[4] = " will be" elseif string.match(outText[3], "s$") then outText[4] = " were" else outText[4] = " was" end

local pos1, posTo, pos2 = string.match((pos or ""), "(%d+)([,%-]?)(%d*)") pos1 = tonumber(pos1) pos2 = tonumber(pos2)

if pos1 then outText[5] = " the " outText[6] = util.wordinal(pos1)

if pos2 then outText[7] = ((posTo == "-") and " to " or " and ") .. util.wordinal(pos2) end if mile == "L" then outText[8] = " tier" end else outText[5] = " a"           end

outText[9] = (mile == "M") and " milestone" or " leaderboard" outText[10] = " prize to win in "

if eventNumb[1] and eventDate ~= "" then local sep = ""

outText[17] = "" for idx = #eventNumb, 1, -1 do                    outText[17] = (eType=="T" and " Chapter #" or " #") .. eventNumb[idx] .. sep .. outText[17] if sep == "" then sep = " and" else sep = "," end end outText[22] = " on the " local tDates = {} for _, n in ipairs(eventNumb) do                   table.insert(tDates, meData[sName][n][1]) end outText[23] = util.strMultiDate(tDates) end

outText[18] = " Mini Event"

if eventMain and eType ~= "T" then outText[24] = ", during " outText[25] = lte({eventMain}) end outText[30] = "." elseif string.match(sOption, "U") then -- Single Event on ME Page outText[1] = "'''" outText[20] = "'''"

-- check for self-link if linkText == mw.title.getCurrentTitle.baseText then outText[11] = "" outText[12] = "" outText[13] = "" outText[14] = "" outText[15] = "" outText[19] = "" end

if eventNumb[1] then if eType == "T" then outText[16] = "" else outText[17] = " #" .. tostring(eventNumb[1]) end outText[23] = util.strDate(eventDate, eventDays, nil, nil, true) end

if eventMain and eType ~= "T" then local startDate = eventDate .. dayStart local endDate = date(eventDate):adddays(eventDays):fmt("%Y/%m/%d") .. dayStart if today < startDate then outText[24] = ". This mini event will be part of the " elseif today < endDate then outText[24] = ". This mini event is part of the " else outText[24] = ". This mini event was part of the " end outText[25] = lte({eventMain}) end if altText and altText ~= "" then outText[26] = ", " outText[27] = altText end

if tNumb[6] then local tSpawn = { ".\n* ", "NPCs", " are spawned in groups of ", (tostring(tNumb[6]) or "?"), " every ", (tostring(tNumb[7]) or "?"), (((tNumb[8] and tNumb[8] == "m") and " minutes") or " hours"), ", a total of ", "?",			" this special event" }           	if nameNPC ~= "" then tSpawn[2] = npc.getNPC({nameNPC, "L"}) end if date < date(eventDate .. " " .. dayStart) then tSpawn[3] = " will spawn in groups of " end

if type(tNumb[7]) == "number" and tNumb[7] > 0 then local nCount = (tonumber(tNumb[6]) or 0) * (tonumber(tNumb[2]) or 0) * 24

if tNumb[8] and tNumb[8] == "m" then nCount = nCount * 60 end

nCount = nCount / tNumb[7] nCount = tostring(nCount)

while true do 	            	nCount, k = string.gsub(nCount, "^(-?%d+)(%d%d%d)%.?%d*", '%1,%2') if (k==0) then break end end

if tNumb[9] then tSpawn[8 ] = ". Once the last creature was eliminated, the respawn wait could be skipped" if date < (date(eventDate .. " " .. dayStart):adddays(eventDays)) then tSpawn[8 ] = ". Once the last creature is eliminated, the respawn wait can be skipped" end tSpawn[9 ] = "" else tSpawn[9] = tostring(nCount) end end outText[28] = table.concat(tSpawn) end

if (tEvent["Themed"]) and (eventMain or npcVer) and tNumb[4] ~= "none" then local tThemed = { ".\n* ", "",			nameNPC,			"", " were ", "",		}

local startDate = eventDate .. dayStart local endDate = date(eventDate):adddays(eventDays):fmt("%Y/%m/%d") .. dayStart if today < startDate then tThemed[5] = " will be " elseif today < endDate then tThemed[5] = " are " end

if eventMain ~= nil then tThemed[6] = npc.getNPC({nameNPC, "X", nil, nil, eventMain}) end

if npcVer ~= nil then tThemed[6] = npc.getNPC({nameNPC, "X", nil, nil, npcVer}) end

outText[28] = table.concat(tThemed) end outText[30] = "." end else -- Normal Mode

-- check for sel-link if linkText == mw.title.getCurrentTitle.baseText then outText[11] = "'''" outText[12] = "" outText[13] = "" outText[14] = "" outText[15] = "" outText[19] = "'''" end

if string.match(sOption, "9") then if not string.match(sOption, "S") then outText[18] = " Mini Event" end

if eventNumb[1] and eventDate ~= "" then local sep = "" outText[17] = ""

for idx = #eventNumb, 1, -1 do                              outText[17] = (eType=="T" and " Chapter #" or " #") .. eventNumb[idx] .. sep .. outText[17] if sep == "" then sep = " and" else sep = "," end end end elseif string.match(sOption, "A") and altText ~= "" then outText[16] = altText else if not string.match(sOption, "S") then outText[17] = " Mini Event" end end

if string.match(sOption, "D") then outText[22] = " on the "

local tDates = {}

for _, n in ipairs(eventNumb) do               table.insert(tDates, meData[sName][n][1]) end

outText[23] = util.strMultiDate(tDates) end outText[30] = "" end

return table.concat(outText) end

local function getCount(sName) local nCount = 0 if meData[sName] then for idx, data in ipairs(meData[sName]) do           if today > (data[1] .. dayStart) then nCount = nCount + 1 end end end

return "* This mini event has occurred " .. nCount .. " time" .. ((nCount > 1) and "s" or "") .. ".\n" end

-- Public Functions --

-- function get Mini Event function p.getME(frame) local tArgs = util.getArgs(frame)

local sName   = tArgs[1] or "" local sNumber = tArgs[2] or "" local sOption = tArgs[3] or "" local altText = tArgs[4] or "" local sReward = tArgs[5] or ""

if sName == "" then sName = mw.title.getCurrentTitle.baseText end sName = sName:lower:gsub("^%s*(.-)%s*$", "%1") or '' sName = sName:gsub(" mini event$", "") sName = mw.text.decode(sName, false)

sOption = tostring(sOption) sOption = sOption:upper

if sOption == "" then if sNumber ~= "" then sOption = "S" end end

local retText = ""

if string.match(sOption, "P") then if meData[sName] and meData[sName]["NPC"] then retText = meData[sName]["NPC"] end elseif string.match(sOption, "N") then if meData[sName] and meData[sName]["NPC"] then retText = npc.getNPC({meData[sName]["NPC"], "", "", "30"}) end elseif string.match(sOption, "C") then retText = getCount(sName) else retText = singleEvent(sName, sNumber, sOption, altText, sReward) end return retText end

-- return last X versions formatted for Main Page function p.getLastME(frame) local tArgs = util.getArgs(frame)

local count = tArgs[1] or 5 count = tonumber(count) or 5

local tIndex = {}

for k, v in pairs(meData) do       if not (k:lower:match("^ttc")) then for idx, data in ipairs(v) do               if today > (data[1] .. dayStart) then local t = {data[1], k, idx} table.insert(tIndex, t)               end end end end

table.sort(tIndex, function(a,b) return a[1] > b[1] end)

local outText = {}

for i, ver in ipairs(tIndex) do       table.insert(outText, singleEvent(ver[2], ver[3], "L", "")) if i >= count then break end end

return table.concat(outText) end

-- return next X versions formatted for Main Page function p.getUpcomingME(frame) local tArgs = util.getArgs(frame)

local count = tArgs[1] or 5 count = tonumber(count) or 5

local tIndex = {}

for k, v in pairs(meData) do       for idx, data in ipairs(v) do            if today < (data[1] .. dayStart) then local t = {data[1], k, idx} table.insert(tIndex, t)           end end end

table.sort(tIndex, function(a,b) return a[1] < b[1] end)

local outText = {}

for i, ver in ipairs(tIndex) do       table.insert(outText, singleEvent(ver[2], ver[3], "L", "")) if i >= count then break end end

if table.concat(outText) == "" then return " There is no upcoming mini events for now... \n" end

return table.concat(outText) end

-- return all ME during Limited Time Event formatted for Event Page function p.getEventME(frame) local tArgs = util.getArgs(frame)

local event = tArgs[1] or ""

-- Does not make sense if no Event specified so return blank if event == "" then return "" end

event = string.lower(event)

local tIndex = {}

for k, v in pairs(meData) do       for idx, data in ipairs(v) do            if event == data[3] then local t = {data[1], k, idx} table.insert(tIndex, t)           end end end

table.sort(tIndex, function(a,b) return a[1] < b[1] end)

local outText = {}

for i, ver in ipairs(tIndex) do       table.insert(outText, singleEvent(ver[2], ver[3], "E", "")) end

return frame:preprocess(table.concat(outText)) end

-- return all ME Types in horizontal format function p.getMEList(frame) local npcData = mw.loadData( 'Module:NPC/data' ) local tArgs = util.getArgs(frame) local eType = tArgs[1] or "" local tIndex = {}

for k, v in pairs(meData) do   	if not (k:lower:match("^ttc")) then if tArgs[1] == "M" and npcData[v["NPC"]] and npcData[v["NPC"]]["T"] then table.insert(tIndex, k)           elseif tArgs[1] == "T" and npcData[v["NPC"]] and not npcData[v["NPC"]]["T"] and not npcData[v["NPC"]]["I"] and not npcData[v["NPC"]]["V"] then table.insert(tIndex, k)           elseif tArgs[1] == "O" and npcData[v["NPC"]] and (npcData[v["NPC"]]["I"] or npcData[v["NPC"]]["V"]) then table.insert(tIndex, k)           end end end

table.sort(tIndex)

local outText = {} local space = ""

for _, me in ipairs(tIndex) do       table.insert(outText, space .. singleEvent(me, 0, "S", ""))

space = " · " end

return table.concat(outText) end

function p.getMETimeLine local tIndex = {} local tMainEvents = {} local nCount = 0 local nEventCount = 0

local lastEvent = nil local nextEvent = nil

for k, v in pairs(meData) do   	local lastOfType = nil for idx, data in ipairs(v) do       	if data[1] then if today > (data[1] .. dayStart) then if not lastEvent or data[1] > lastEvent[1] then lastEvent = data end else if not nextEvent or data[1] < nextEvent[1] then nextEvent = data end end end

table.insert(tIndex, {data[1], k, idx, data[3], nil}) if data[3] then if not tMainEvents[data[3]] then tMainEvents[data[3]] = 0 end tMainEvents[data[3]] = tMainEvents[data[3]] + 1 end if data[1] then if today > (data[1] .. dayStart) then lastOfType = #tIndex nCount = nCount + 1 if data[3] then nEventCount = nEventCount + 1 end end end end if lastOfType then tIndex[lastOfType][5] = true end end

table.sort(tIndex, function(a,b) return a[1] > b[1] end)

local prevMain = "" local future = nil local during = nil

if tMainEvents[lastEvent[3]] and nextEvent and lastEvent[3] == nextEvent[3] then tMainEvents[lastEvent[3]] = tMainEvents[lastEvent[3]] + 1 during = true end

local outText = {"{| class=\"article-table\" style=\"width: 100%;\"\n", "! width=\"30%\"|Major Event\n", "! width=\"35%\"|Mini Event\n", "! width=\"35%\"|Date(s)\n"}

for i, data in ipairs(tIndex) do if not future and today > (data[1] .. dayStart) then future = true table.insert(outText, "|-\n! colspan=\"")			if during then				table.insert(outText, "2")			else				table.insert(outText, "3")			end			table.insert(outText, "\" style=\"text-align: center;\"|Upcoming Events...\n") end table.insert(outText, "|-\n")

if data[4] then local eventName = data[4] local eventType = "N" if data[2]:match("^ttc") then eventName = string.gsub(data[4], "ttc ", "") eventType = "T" end if eventName ~= prevMain then table.insert(outText,                           "| style=\"text-align: center;\" rowspan=\""                            .. tMainEvents[data[4]]                            .. "\" |"                            .. lte({eventName, eventType, "P"})                            .. "\n")

prevMain = eventName end else table.insert(outText, "|\n") prevMain = "" end

if data[5] and not (data[2]:match("^ttc")) then table.insert(outText, singleEvent(data[2], data[3], "T", "'''")) else table.insert(outText, singleEvent(data[2], data[3], "T", "")) end end

table.insert(outText, "|}\n")

return "==Trivia==\n" .. "* There has been a total of " .. nCount .. " mini events, out of which " .. nEventCount .. " occurred during a major event, while " .. (nCount - nEventCount) .. " occured separately.\n\n==Event Timeline==\n" .. table.concat(outText) end

function p.getMENPCUsage(frame) local tArgs = util.getArgs(frame)

local npcName = tArgs[1] or "" local allVers = (tArgs[2] and tArgs[2] ~= "")

-- return if no NPC specified if npcName == "" then return "No NPC Name Specified\n" end

local tIndex = {} local tMainEvents = {}

local nCount = 0 local nEventCount = 0 local npcThemed = nil

for k, v in pairs(meData) do       if not (k:lower:match("^ttc")) then npcThemed = (v["Themed"] ~= nil)

for idx, data in ipairs(v) do               local meNPC = v["NPC"]

-- check alternate NPC if data[5] and v["NPC" .. data[5]] then meNPC = v["NPC" .. data[5]] end

if npcName == meNPC then local vers = data[3] or data[4]

if vers or allVers then local themed = npcThemed and (data[3] ~= nil or data[4] ~= nil) if (data[4] and data[4]=="none") then themed = nil end

local t = {data[1], k, idx, data[3], vers, themed} table.insert(tIndex, t)                   end end end end end

table.sort(tIndex, function(a,b) return a[1] < b[1] end)

local prevData = tIndex[1] local prevNumb = ""

local outText = {}

local function oneLine local themed = prevData[5] and prevData[6] table.insert(outText, "* The "               .. npc.getNPC({npcName, "D", nil, nil, prevData[5]})                .. " were used for the ") if prevData[4] then table.insert(outText,                    singleEvent(prevData[2], prevNumb, "F", "")                    .. "s during the "                    .. lte({prevData[4], "N", "D"})                    .. ".\n") else table.insert(outText,                   singleEvent(prevData[2], prevNumb, "FD", "")                    .. ".\n") end end for i, data in ipairs(tIndex) do       if data[4] ~= prevData[4] or data[5] ~= prevData[5] then oneLine prevNumb = "" end prevData = data prevNumb = prevNumb .. " " .. data[3] end

if prevNumb ~= "" then oneLine end

return table.concat(outText) end

function p.getGallery(frame) local tArgs = util.getArgs(frame)

local npcName = tArgs[1] or "No NPC Name Specified\n"

local tIndex = {} local tMainEvents = {} local tVersAdded = {}

local nCount = 0 local nEventCount = 0 local npcThemed = nil

for k, v in pairs(meData) do       if not (k:lower:match("^ttc")) then npcThemed = (v["Themed"] ~= nil)

for idx, data in ipairs(v) do               local meNPC = v["NPC"]

-- check alternate NPC if data[5] and v["NPC" .. data[5]] then meNPC = v["NPC" .. data[5]] end

if npcName == meNPC then local vers = data[3] or data[4]

if vers then local themed = npcThemed and (data[3] ~= nil or data[4] ~= nil)

if (data[4] and data[4]=="none") then themed = nil end

local t = {data[1], k, idx, data[3], vers, themed} if not tVersAdded[vers] then table.insert(tIndex, t)	                       tVersAdded[vers] = true end end end end end end

table.sort(tIndex, function(a,b) return a[1] < b[1] end)

local prevData = tIndex[1] local prevNumb = "" local outText = {"")

if       type(frame.args) == 'table' and type(frame.getParent) == 'function' then return frame:preprocess(table.concat(outText)) end return table.concat(outText) end

function p.getMEHeader(frame) local npcData = mw.loadData( 'Module:NPC/data' ) local tArgs = util.getArgs(frame)

local meObj = tArgs[1] or "" local meText = tArgs[2] or "" local meName = tArgs[3] or mw.title.getCurrentTitle.baseText meName = meName:lower:gsub(" [mM]ini [eE]vent$", "") meName = mw.text.decode(meName, false)

if not meData[meName] or not meData[meName]["Name"] then return "Invalid Mini Event Name" end

local outText = {}

table.insert(outText, ' ') table.insert(outText, (meData[meName]["Disp"] or meData[meName]["Name"])) table.insert(outText, ' Mini Event \n') table.insert(outText, meObj) table.insert(outText, "\n\n\n'''") table.insert(outText, (meData[meName]["Disp"] or meData[meName]["Name"])) table.insert(outText, "'''") table.insert(outText, ' is a mini event that has occurred ') local nCount = 0 for idx, data in ipairs(meData[meName]) do if today > (data[1] .. dayStart) then nCount = nCount + 1 end end table.insert(outText, nCount) table.insert(outText, ' time') table.insert(outText, ((nCount > 1) and "s" or "")) table.insert(outText, '.') if npcData[meData[meName]["NPC"]] and npcData[meData[meName]["NPC"]]["T"] then table.insert(outText, "This mini event is a Mini Boss Event.") elseif npcData[meData[meName]["NPC"]] and (npcData[meData[meName]["NPC"]]["I"] or npcData[meData[meName]["NPC"]]["V"]) then table.insert(outText, "") else table.insert(outText, "This mini event is a Tapper Event.") end

return frame:preprocess(table.concat(outText)) end

local tList = {} local used = {}

local function getCharChapter(characters, eName) for k, v in pairs(mw.text.split(characters, "%s*%$%$%s*")) do		for cName in mw.text.gsplit(v, "%s*%$%s*") do			if not tList[cName] then tList[cName] = {0, 0, 0} end if not used[cName] or used[cName] ~= eName then tList[cName][1] = tList[cName][1] + 1 used[cName] = eName end tList[cName][2] = tList[cName][2] + 1 if k == 5 then tList[cName][3] = tList[cName][3] + 1 end end end end

function p.getCharTC(frame) local tArgs = util.getArgs(frame)

local pagename = tArgs[1] or mw.title.getCurrentTitle.baseText local tOut = ""

for k, v in pairs(meData) do		if k:match("^ttc ") then if v[1] then if v[1]["C"] then getCharChapter(v[1]["C"], k)				end end if v[2] then if v[2]["C"] then getCharChapter(v[2]["C"], k)				end end if v[3] then if v[3]["C"] then getCharChapter(v[3]["C"], k)				end end end end

if not tList[pagename] then return "" end

local tOut = {	"* ", pagename, " was used in ", tList[pagename][2], " chapter", (tList[pagename][2] == 1 and "" or "s"), " in ", tList[pagename][1], " Tower Challenge", (tList[pagename][1] == 1 and "" or "s"), " including ", tList[pagename][3], " time", (tList[pagename][3] == 1 and "" or "s"), " as a Featured Character.  See the complete list... \n" }

return table.concat(tOut) end

function p.getCharTCList local ICON = require("Module:CharacterAvatar").getAvatar local tOut = {	'{| class="article-table dmk-list sortable mw-collapsible mw-collapsed" style="width: 100%;"\n', '! colspan="2"| Character \n', '! width="20%"| Tower Challenge \n', '! width="20%"| Chapter \n', '! width="20%"| Feature Character ' }

for k, v in pairs(meData) do		if k:match("^ttc ") then if v[1] then if v[1]["C"] then getCharChapter(v[1]["C"], k)				end end if v[2] then if v[2]["C"] then getCharChapter(v[2]["C"], k)				end end if v[3] then if v[3]["C"] then getCharChapter(v[3]["C"], k)				end end end end

for name, nb in pairs(tList) do      		table.insert(tOut, table.concat({'\n|-\n| id="List"|', ICON({name, nil, 25}), '\n| style="text-align: left;"|', name, '\n|', nb[1], '\n|', nb[2], '\n|', nb[3]})) end

return table.concat(tOut) .. "\n|}" end

return p