Module:Character

-- -- Lua Templating for all Character related info. local p = {}

local common = require( 'Module:Common' ) local data = mw.loadData( 'Module:Character/Data' )

-- Retrieve any arbitrary field of Character data -- Usage: function p.Data( frame ) return data[frame.args[1]][frame.args[2]] or "" end

function p.Name( frame ) return data[frame.args[1]]["name"] or "" end

function p.Subtitle( frame ) return data[frame.args[1]]["subtitle"] or "" end

function p.NameAndSubtitle( frame ) local codexId = frame.args[1] local charData = data[codexId] return NameAndSubtitleUnprocessed(codexId, charData) end

function p.Profile( frame ) local codexId = frame.args[1] local charData = data[codexId]

local boxes = { charData["leader_skill"] and frame:expandTemplate{title = "Box", args = { tag  = "Leader Skill", title = charData["leader_skill"]["name"], text = charData["leader_skill"]["effect"], }}           or "", charData["active_skill"] and frame:expandTemplate{title = "Box", args = { tag  = "Active Skill", title = charData["active_skill"]["name"], text = string.format("%s Cooldown: %s turns",                    charData["active_skill"]["effect"],                    charData["active_skill"]["cooldown"]), }}           or "", charData["sub_skill1"] and frame:expandTemplate{title = "Box", args = { tag  = "Subskill 1", title = charData["sub_skill1"]["name"], text = charData["sub_skill1"]["effect"], }}           or "", charData["sub_skill2"] and frame:expandTemplate{title = "Box", args = { tag  = "Subskill 2", title = charData["sub_skill2"]["name"], text = charData["sub_skill2"]["effect"], }}           or "", charData["memo"] and frame:expandTemplate{title = "Box", args = { tag  = "Memo", text = charData["memo"], }}           or "", }   return table.concat(boxes) end

function p.Infobox( frame ) local codexId = frame.args[1] local charData = data[codexId] local args = { no         = codexId, no_en      = CodexEn(charData), name       = charData["name"], title      = charData["subtitle"], rarity     = charData["rarity"], attribute  = charData["affinity"], type       = charData["type"], acquisition = charData["acquisition"], affiliation = charData["affiliation"], hp_base    = charData["hp_base"], atk_base   = charData["atk_base"], hp_max     = charData["hp_max"], atk_max    = charData["atk_max"], }   if charData["has_alt"] then args["image"] = frame:preprocess([=[            full.png|Regular             alt full.png|Released]=]) else args["image"] = frame:preprocess(" full.png") end return frame:expandTemplate{ title = "Character Infobox", args = args } or "" end

function p.Quotes( frame ) local codexId = frame.args[1] local charData = data[codexId] local quotes = charData["quotes"] return quotes and frame:expandTemplate{ title = "Quotes", args = { voiced = charData["voiced"], ["home1-jp"]      = quotes["home1_jp"], home1             = quotes["home1"], ["home2-jp"]      = quotes["home2_jp"], home2             = quotes["home2"], ["home3-jp"]      = quotes["home3_jp"], home3             = quotes["home3"], ["battlestart-jp"] = quotes["battlestart_jp"], battlestart       = quotes["battlestart"], ["activeskill-jp"] = quotes["activeskill_jp"], activeskill       = quotes["activeskill"], ["special-jp"]    = quotes["special_jp"], special           = quotes["special"], ["followup-jp"]   = quotes["followup_jp"], followup          = quotes["followup"], ["nextwave-jp"]   = quotes["nextwave_jp"], nextwave          = quotes["nextwave"], ["battleend-jp"]  = quotes["battleend_jp"], battleend         = quotes["battleend"], ["gameover-jp"]   = quotes["gameover_jp"], gameover          = quotes["gameover"], ["powerup-jp"]    = quotes["powerup_jp"], powerup           = quotes["powerup"], }}       or "" end

-- Renders a full Character page -- Usage: function p.Page( frame ) local codexId = frame.args[1] local charData = data[codexId] if not isReleased(charData) then return "" end return table.concat({       frame:preprocess(AwakeningHeader(codexId)),        p.Infobox(frame),        p.Profile(frame),        -- Do not render quotes for UR characters        (charData["rarity"] ~= "UR") and p.Quotes(frame) or "",        frame:expandTemplate{ title = "Gallery"},    }) end

-- Renders the Characters list -- Usage: -- Usage w/ filters: function p.List( frame ) local filters = ParseFilters(frame.args[1]) local header = [=[{| class="article-table sortable" style="margin: 20px 8px 0px;" !style="white-space: nowrap;"| Rarity !style="white-space: nowrap;"| # (JP) !style="white-space: nowrap;"| # (EN) !style="width: 50%;"        | Name !style="white-space: nowrap;"| Affinity !style="white-space: nowrap;"| Type !style="white-space: nowrap;"| Max HP !style="white-space: nowrap;"| Max ATK ]=]   local row = [=[|- %s local rows = {} for id, charData in common.sortedPairs(data, --desctrue) do       if isReleased(charData) and inFilter(filters, charData) then rows[#rows+1] = string.format(row,               FilterDataAttributes(charData),                charData["rarity"],                id.." "..charData["name"], id,                CodexEn(charData),                NameAndSubtitleUnprocessed(id, charData),                charData["affinity"] or "",                charData["type"] or "",                charData["hp_max"] or "",                charData["atk_max"] or "") end end return frame:preprocess(header..table.concat(rows, "\n").."\n|}") end
 * data-sort-value="%s"| || %s || %s || %s || %s || %s || %s || %s]=]

-- Renders the Characters grid -- Usage: function p.Grid( frame ) local row = local entries = {} for id, charData in common.sortedPairs(data, --desctrue) do       if isReleased(charData) then local pageName = id.." "..charData["name"] entries[#entries+1] = string.format(row,               FilterDataAttributes(charData),                pageName,                pageName,                NameAndSubtitleUnprocessed(id, charData),                charData["affinity"] or "",                charData["rarity"] or "",                charData["type"] or ""            ) end end return table.concat(entries, "\n") end

-- Renders the Skills list -- Usage: function p.Skills( frame ) local typeMap = { Leader = "leader_skill", Active = "active_skill", Sub = "sub_skill", }   local skillType = typeMap[frame.args[1]] local header = [=[{| class="article-table sortable" ! style="white-space: nowrap;" | Rarity ! style="white-space: nowrap;" | No. ! style="width:200px;" | Name ! style="white-space: nowrap;" | Attr ! Effect ]=]   local row = [=[|- %s local rows = {} if skillType == "sub_skill" then local twoSubRow = [=[|- %s for id, charData in common.sortedPairs(data, --desctrue) do           if isReleased(charData) then local effect2 = charData["sub_skill2"]["effect"] local dataAtts = FilterDataAttributes(charData) if effect2 == "" then rows[#rows+1] = string.format(row,                     dataAtts,                      charData["rarity"],                      id.." "..charData["name"], id,                      NameAndSubtitleUnprocessed(id, charData),                      charData["affinity"],                      charData["sub_skill1"]["effect"]) else rows[#rows+1] = string.format(twoSubRow,                     dataAtts,                      charData["rarity"],                      id.." "..charData["name"], id,                      NameAndSubtitleUnprocessed(id, charData),                      charData["affinity"],                      charData["sub_skill1"]["effect"],                      dataAtts,                      effect2) end end end else for id, charData in common.sortedPairs(data, --desctrue) do           if isReleased(charData) then rows[#rows+1] = string.format(row,                 FilterDataAttributes(charData),                  charData["rarity"],                  id.." "..charData["name"], id,                  NameAndSubtitleUnprocessed(id, charData),                  charData["affinity"],                  charData[skillType]["effect"]) end end end return frame:preprocess(header..table.concat(rows, "\n").."\n|}") end
 * data-sort-value="%s" | || %s || %s || %s || %s]=]
 * rowspan="2" data-sort-value="%s" |
 * rowspan="2" | %s
 * rowspan="2" | %s
 * rowspan="2" | %s
 * %s
 * - %s
 * %s]=]

-- Gets a single Skill description -- Usage: function p.Skill( frame ) local typeMap = { Leader = "leader_skill", Active = "active_skill", Sub1 = "sub_skill1", Sub2 = "sub_skill2", }   local skillType = typeMap[frame.args[1]] local codexId = frame.args[2] local charData = data[codexId] return charData[skillType]["effect"] end

-- Utility functions function isReleased( charData ) return isReleasedInternal(       charData["release_date"] and charData["release_date"]["jp"] or "") end

function isReleasedInternal( release_date ) local year, month, day, hour, minute = string.match(       release_date, "(%d+)%-(%d+)%-(%d+) (%d+):(%d+)")

if not year then return true end local release_date = os.time({       year = year, month = month, day = day,        hour = hour, min = minute}) - 32400 -- Subtract 9 hours for JST time conversion

return os.time > release_date end

-- Evaluates if Character is released in EN version and returns an empty string if unreleased. function CodexEn( charData ) if isReleasedInternal(       charData["release_date"] and charData["release_date"]["en"] or "") then return charData["codex_en"] or "" end return "" end

function inFilter( filters, charData ) local allmatch = true for filter,values in pairs(filters) do       local match = false for _,value in ipairs(values) do           if charData[filter] == value then match = true break end end if not match then allmatch = false break end end return allmatch end

function ParseFilters( filterString ) if not filterString then return {} end local filters = {} for s in string.gmatch(filterString, '[^;]+') do       local filter,valueString = string.match(s, '(.*):(.*)') local values = {} for v in string.gmatch(valueString, '[^,]+') do           values[#values+1] = v        end filters[filter] = values end return filters end

function FilterDataAttributes( charData ) return string.format(       'class="character-entry" data-rarity="%s" data-affinity="%s" data-type="%s" data-org="%s" data-name="%s" data-gender="%s" data-global="%s"',        charData["rarity"] or "",        charData["affinity"] or "",        charData["type"] or "",        charData["affiliation"] or "",        charData["name"] or "",        charData["gender"] or "",        CodexEn(charData) == "" and "JP" or "EN"    ) end

function AwakeningHeader( codexId ) local charData = data[codexId] local thumb = "" if charData["awakening_chain"] then local entries = {} for i, id in ipairs(charData["awakening_chain"]) do           if i > 1 then entries[#entries+1] = " &rarr; " end entries[#entries+1] = string.format(thumb,               id, data[id]["name"]) end return " "..table.concat(entries, "").." " else return "" end end

function NameAndSubtitleUnprocessed( codexId, charData ) return string.format(       "%s %s ",        codexId,        charData["name"],        charData["name"],        charData["subtitle"] or ""        ) end

return p --