Welcome to the Umamusume Wiki! If you want to contribute, please read the guidelines.

Module:Game/Supports

From Umamusume Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Game/Supports/doc

--[[
    !! THIS PAGE IS MANAGED BY GITLAB !!
    ANY EDITS TO PAGE CONTENT WILL BE OVERWRITTEN
    TO MAKE CHANGES, PLEASE SUBMIT A MERGE REQUEST AT https://gitlab.com/umamusume-wiki/lua-modules
]]

local p = {}
local Data = require("Module:Game/Supports/Data")
local Characters = require("Module:Game/Characters")
local Effects = require("Module:Game/Supports/Data/Effects")
local Cargo = require("Module:Cargo")
local Utils = require("Module:Utils")
local Game = require("Module:Game")

---Generate lists of arguments for the Game Support/link template
---Use to batch create lots of support links for pages that need them
---@param supportIds string[]
---@return any[] templateArgs keyed by support ID
function p.generateSupportLinks(supportIds)
    local results = {}
    if #supportIds > 0 then
        local supportIdsInsert = table.concat(supportIds, ',')
        results = Cargo.query {
            from = 'Game_Supports',
            fields = { '_pageName=supportPage', 'support_id', 'name_ro', 'name_ww' },
            where = string.format('support_id IN (%s)', supportIdsInsert),
            limit = #supportIds
        }
    end

    local supportDatas = Data.getBatch(supportIds)

    local merged = Utils.pairObjects(supportDatas, 'id', results, 'support_id', true)

    -- fetch required character info (no page exists or need for display name)
    local charIds = {}
    for _, pair in ipairs(merged) do
        local cargoData, supportData = pair[2], pair[1] ---@type any
        if not cargoData or (not (supportData.displayNameEN or cargoData.name_ww) and supportData.groupCharacterIds == nil) then
            table.insert(charIds, supportData.characterId)
        end
    end
    local charInfos = Characters.getCharacterInfos(charIds)

    local datas = {}
    for _, pair in ipairs(merged) do
        local cargoData, supportData = pair[2], pair[1] ---@type any

        local charData = charInfos[supportData.characterId]
        if not cargoData then
            -- Generate expected page name for easy creation if the page does not exist
            cargoData = {
                supportPage = string.format("Game:%s %s (%s)", supportData.rarity,
                    charData and charData.nameEN or '',
                    string.gsub(supportData.nameEN or supportData.nameJP, "[%[%]]", ""))
            }
        end

        local displayName = supportData.displayNameEN or cargoData.name_ww
        if displayName == nil then
            if supportData.groupCharacterIds ~= nil then
                displayName = supportData.displayNameJP
            else
                local charName = (charData and charData.nameEN) or ''
                local romanName = cargoData.name_ro and string.format("[%s]", cargoData.name_ro) or nil
                displayName = string.format("%s %s", romanName or supportData.nameJP, charName)
            end
        end
        displayName = supportData.rarity .. ' ' .. displayName

        local templateArgs = {
            icon = supportData.iconPage,
            page = cargoData.supportPage,
            display = displayName,
            type = supportData.attribute
        }
        datas[supportData.id] = templateArgs
    end
    return datas
end

function p.supportLink(frame)
    local supportId = Utils.normalString(mw.text.decode(frame.args[1]))
    if not supportId then return end

    local templateArgs = p.generateSupportLinks({ supportId })[supportId]
    if not templateArgs then return end

    local text = frame:expandTemplate {
        title = "Game Support/link",
        args = templateArgs
    }
    return text
end

function p.characterSupportLinks(frame)
    local charId = Utils.normalString(mw.text.decode(frame.args[1]))
    if not charId then return end

    local support_card_datas = Game.queryMaster {
        from = "support_card_data",
        where = string.format("chara_id = %s and support_card_type <> 3", charId),
        data = {
            id = "id"
        }
    }

    local supportIds = {}
    for _, support_card_data in ipairs(support_card_datas) do
        table.insert(supportIds, support_card_data.id)
    end
    table.sort(supportIds)

    local supportLinks = p.generateSupportLinks(supportIds)

    local text = ''
    for _, supportId in ipairs(supportIds) do
        local templateArgs = supportLinks[supportId]
        text = text .. frame:expandTemplate {
            title = "Game Support/link",
            args = templateArgs
        } .. '\n\n'
    end
    if #text == 0 then
        return "''None.''"
    end
    return mw.text.trim(text)
end

function p.supportPage(frame)
    local supportId = mw.text.decode(frame.args[1])
    if not supportId then return end
    local supportData = Data.getSupport(supportId)
    if not supportData then return end

    local charIds = { supportData.characterId }
    if supportData.groupCharacterIds ~= nil then
        charIds = supportData.groupCharacterIds or {}
    end
    local charInfos = Characters.getCharacterInfos(charIds)

    local nameRO = frame.args['name_ro']
    local nameWW = frame.args['name_ww']

    local displayEN = nil
    if #nameRO > 0 then displayEN = nameRO end
    if #nameWW > 0 then displayEN = nameWW end
    if supportData.displayNameEN then displayEN = supportData.displayNameEN end

    local function wrapEpisode(textList)
        local text = table.concat(textList, "\n")
        text = string.gsub(text, "\n", "<br/>")
        text = string.gsub(string.gsub(text, "<I>", "''"), "</I>", "''")
        return tostring(mw.html.create('div'):addClass('episode-text'):wikitext(text))
    end
    local function wrapNowiki(text)
        if text == nil then return nil end
        return tostring(frame:preprocess(string.format("<nowiki>%s</nowiki>", text)))
    end

    local templateArgs = {
        support_id = supportData.id,
        name_jp = wrapNowiki(supportData.displayNameJP),
        name_en = wrapNowiki(displayEN),
        available_en = supportData.availableEN,
        release_date_jp = supportData.releaseDateJP,
        release_date_en = supportData.releaseDateEN,
        rarity = supportData.rarity,
        type = supportData.attribute,
        full_page = supportData.fullPage,
        episode_jp = wrapEpisode(supportData.episodeJP),
        episode_en = supportData.episodeEN and wrapEpisode(supportData.episodeEN) or nil
    }

    local unique = supportData.effects.unique
    if unique ~= nil then
        templateArgs.unique_level = unique.level
        local description = unique.descriptionEN or unique.descriptionJP
        templateArgs.unique_description = table.concat(description, "")

        for i, bonus in ipairs(unique.bonuses) do
            local prettyName = Effects.getPrettyName(bonus.typeId)
            templateArgs['unique_effect_' .. i] = prettyName
            local val = tostring(bonus.value)
            if bonus.hint ~= nil then
                val = string.format("%s (%s)", val, bonus.hint)
            end
            templateArgs['unique_val_' .. i] = val
        end
    end

    local c = 1
    for _, char in pairs(charInfos) do
        templateArgs["character_" .. c] = char.pageName
        c = c + 1
    end

    for i, hint in ipairs(supportData.hintSkillIds) do
        templateArgs["hint_" .. i] = hint
    end

    local text = frame:expandTemplate {
        title = "Game Support Definition/page",
        args = templateArgs
    }
    return text
end

function p.supportList(frame)
    local results = Cargo.query {
        from = 'Game_Supports',
        fields = { '_pageName=supportPage', 'support_id', 'name_ro', 'name_ww' },
        orderBy = "support_id",
        limit = '9999',
    }

    local supportIds = {}
    for _, data in ipairs(results) do
        table.insert(supportIds, tostring(data.support_id))
    end
    local supportDatas = Data.getBatch(supportIds)
    local paired = Utils.pairObjects(results, 'support_id', supportDatas, 'id')

    local groups = {}

    for _, pair in ipairs(paired) do
        local cargoData, supportData = pair[1], pair[2] ---@type any

        local text = string.format("[[File:%s|100px|link=%s]]", supportData.cardPage, cargoData.supportPage)

        if groups[supportData.rarity] == nil then groups[supportData.rarity] = {} end
        local rarityGroup = groups[supportData.rarity]
        if rarityGroup[supportData.attribute] == nil then rarityGroup[supportData.attribute] = {} end
        local attribGroup = rarityGroup[supportData.attribute]

        table.insert(attribGroup, text)
    end

    local raritiesOrder = { 'SSR', 'SR', 'R' }
    local attribsOrder = { 'Speed', 'Stamina', 'Power', 'Guts', 'Wit', 'Pal', 'Group' }

    local text = ''
    for _, rarity in ipairs(raritiesOrder) do
        local rarityGroup = groups[rarity]
        if rarityGroup ~= nil then
            text = text .. string.format('== %s Supports ==\n\n', rarity)
            for _, attrib in ipairs(attribsOrder) do
                local attribGroup = rarityGroup[attrib]
                if attribGroup ~= nil and #attribGroup > 0 then
                    text = text .. string.format('=== %s ===\n\n', attrib)

                    local root = mw.html.create('div'):cssText('display:flex; flex-flow:row wrap; gap: 10px;')
                    for _, cardText in ipairs(attribGroup) do
                        root:wikitext(cardText)
                    end
                    text = text .. tostring(root) .. '\n\n'
                end
            end
        end
    end

    return text
end

function p.bonusTable(frame)
    local supportId = mw.text.decode(frame.args[1])
    if not supportId then return end
    local supportData = Data.getSupport(supportId)
    if not supportData then return end

    local levels = {}
    local minLevel = 30
    local maxLevel = 50
    if supportData.rarity == 'SR' then
        minLevel = 25
        maxLevel = 45
    end
    if supportData.rarity == 'R' then
        minLevel = 20
        maxLevel = 40
    end
    for i = minLevel, maxLevel, 5 do
        table.insert(levels, i)
    end

    local nodeTable = mw.html.create('table'):addClass('wikitable'):addClass('uma-theme')
    local nodeCaption = mw.html.create('caption'):wikitext('Bonuses')
    nodeTable:node(nodeCaption)

    -- Create Header Row
    local nodeRowHead = mw.html.create('tr')
    local headerText = { "Effect" }
    for _, level in ipairs(levels) do
        table.insert(headerText, "Lv" .. level)
    end
    for _, txt in ipairs(headerText) do
        nodeRowHead:node(mw.html.create('th'):wikitext(txt))
    end
    nodeTable:node(nodeRowHead)

    -- Create Effects Rows
    for _, calc in ipairs(supportData.effects.calculated) do
        local nodeRow = mw.html.create('tr')

        local effectName = calc.typeNameEN or calc.typePrettyName
        local effectDesc = calc.typeDescriptionEN or calc.typeDescriptionJP
        local rowHeadText = frame:expandTemplate { title = "Tooltip", args = { effectName, effectDesc } }
        local nodeHead = mw.html.create('th'):wikitext(rowHeadText)
        nodeRow:node(nodeHead)

        for _, lvl in ipairs(levels) do
            for _, data in ipairs(calc.levels) do
                if data.level == lvl then
                    local text = data.base or '-'
                    if data.unique ~= nil then
                        local add = string.format('(+%d)', data.unique)
                        if data.base ~= nil then
                            text = text .. ' ' .. add
                        else
                            text = add
                        end
                    end

                    local nodeData = mw.html.create('td'):wikitext(text)
                    nodeRow:node(nodeData)
                end
            end
        end

        nodeTable:node(nodeRow)
    end

    return nodeTable
end

return p