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

Module:Game/Supports/Data/Leveled

From Umamusume Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Game/Supports/Data/Leveled/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 Leveled = {}
local Game = require("Module:Game")
local Utils = require("Module:Utils")
local Effects = require("Module:Game/Supports/Data/Effects")

---@class SupportDataEffectLeveled
---@field typeId string
---@field values SupportDataEffectLeveledEntry[]

---@class SupportDataEffectLeveledEntry
---@field level number
---@field value number|nil

---@class SupportDataEffectCalculated
---@field typeId string
---@field typeNameJP string
---@field typeDescriptionJP string
---@field typeNameEN string|nil
---@field typeDescriptionEN string|nil
---@field typePrettyName string
---@field levels SupportDataEffectCalculatedLevel[]

---@class SupportDataEffectCalculatedLevel
---@field level number
---@field base number|nil
---@field unique number|nil

---@param support_datas table[]
---@return SupportDataEffectLeveled[][]
function Leveled.getSupportLevels(support_datas)
    local supportIds = {}
    local effectTableIds = {}
    for _, support_data in ipairs(support_datas) do
        table.insert(supportIds, support_data.id)
        table.insert(effectTableIds, support_data.effect_table_id)
    end
    local effectTableIdsInsert = table.concat(effectTableIds, ',')

    local maxLevels = {
        ['1'] = 40,
        ['2'] = 45,
        ['3'] = 50,
    }

    local effectTableMap = {}
    local support_card_effect_tables = Game.queryMaster {
        from = "support_card_effect_table",
        where = string.format("id IN (%s)", effectTableIdsInsert)
    }
    for _, support_card_effect_table in ipairs(support_card_effect_tables) do
        local key = support_card_effect_table.id
        if effectTableMap[key] == nil then effectTableMap[key] = {} end
        table.insert(effectTableMap[key], support_card_effect_table)
    end

    local datas = {}
    for _, support_data in ipairs(support_datas) do
        local effectTables = effectTableMap[support_data.id]

        local maxLevel = maxLevels[support_data.rarity]

        local effects = {}
        for _, effectTable in ipairs(effectTables) do
            local segments = {} ---@type SupportDataEffectLeveledEntry[]

            local init = tonumber(effectTable.init) or -1
            table.insert(segments, { level = 0, value = (init > -1) and init or nil })
            for i = 5, maxLevel, 5 do
                local val = tonumber(effectTable[string.format("limit_lv%s", i)]) or -1
                table.insert(segments, { level = i, value = (val > -1) and val or nil })
            end

            local values = {}

            local lastValue = segments[1]
            for i, segment in ipairs(segments) do
                local value = segment.value
                if value ~= nil then
                    lastValue = segment
                elseif lastValue.value ~= nil then
                    --- no value listed, interpolate between last and next valid segments
                    local nextValue = nil
                    for j = i + 1, #segments do
                        if segments[j].value ~= nil then
                            nextValue = segments[j]
                            break
                        end
                    end

                    if nextValue ~= nil then
                        local levelScale = (segment.level - lastValue.level) /
                            (nextValue.level - lastValue.level)
                        local valueScale = nextValue.value - lastValue.value

                        value = math.floor(valueScale * levelScale) + lastValue.value
                    else
                        value = lastValue.value
                    end
                end
                table.insert(values, { level = segment.level, value = value })
            end

            local effect = { ---@type SupportDataEffectLeveled
                typeId = effectTable.type,
                values = values
            }
            table.insert(effects, effect)
        end

        datas[support_data.id] = effects
    end
    return datas
end

---@param uniqueMap SupportDataEffectUnique[]
---@param leveledMap SupportDataEffectLeveled[][]
---@return SupportDataEffectCalculated[][]
function Leveled.getCalculatedLevels(uniqueMap, leveledMap)
    local supportIds = {}
    local allTypeIds = {}
    local typeIdsMap = {}
    local maxLevelMap = {}
    for id, leveled in pairs(leveledMap) do
        table.insert(supportIds, id)
        typeIdsMap[id] = {}
        maxLevelMap[id] = 0
        for _, level in ipairs(leveled) do
            table.insert(allTypeIds, level.typeId)
            table.insert(typeIdsMap[id], level.typeId)
            for _, entry in ipairs(level.values) do
                if entry.level > maxLevelMap[id] then maxLevelMap[id] = entry.level end
            end
        end
    end
    --- add type ids from unique effects if they do not appear in leveling
    for id, unique in pairs(uniqueMap) do
        for _, bonus in ipairs(unique.bonuses) do
            table.insert(allTypeIds, bonus.typeId)
            table.insert(typeIdsMap[id], bonus.typeId)
        end
        typeIdsMap[id] = Utils.dedupe(typeIdsMap[id])
    end
    allTypeIds = Utils.dedupe(allTypeIds)

    local typeNamesJP = Game.getJPText(151, allTypeIds)
    local typeDescriptionsJP = Game.getJPText(154, allTypeIds)

    local typeNamesEN = Game.getENText(151, allTypeIds)
    local typeDescriptionsEN = Game.getENText(154, allTypeIds)

    local datas = {}
    for _, supportId in ipairs(supportIds) do
        local unique = uniqueMap[supportId]
        local leveled = leveledMap[supportId]

        local maxLevel = maxLevelMap[supportId]
        local typeIds = typeIdsMap[supportId]
        table.sort(typeIds, function(a, b) return tonumber(a) < tonumber(b) end)

        local calculated = {}
        for _, typeId in ipairs(typeIds) do
            local typeNameJP = typeNamesJP[typeId] or ''
            local typeDescriptionJP = typeDescriptionsJP[typeId] or ''

            local typeNameEN = typeNamesEN[typeId]
            local typeDescriptionEN = typeDescriptionsEN[typeId]

            local typedBonus = nil ---@type SupportDataEffectUniqueBonus|nil
            if unique ~= nil then
                for _, bonus in ipairs(unique.bonuses) do
                    if bonus.typeId == typeId then
                        typedBonus = bonus
                        break
                    end
                end
            end
            local typedLevels = {} ---@type SupportDataEffectLeveledEntry[]
            for _, level in ipairs(leveled) do
                if level.typeId == typeId then
                    typedLevels = level.values
                    break
                end
            end

            local levels = {}
            for lvl = 0, maxLevel, 5 do
                local baseVal = nil
                local uniqueVal = nil

                for _, typedLevel in ipairs(typedLevels) do
                    if typedLevel.level == lvl then
                        baseVal = typedLevel.value
                    end
                end

                if unique ~= nil and typedBonus ~= nil and lvl >= unique.level then
                    uniqueVal = typedBonus.value
                end

                local level = { ---@type SupportDataEffectCalculatedLevel
                    level = lvl,
                    base = baseVal,
                    unique = uniqueVal
                }
                table.insert(levels, level)
            end

            local data = { ---@type SupportDataEffectCalculated
                typeId = typeId,
                typeNameJP = typeNameJP,
                typeDescriptionJP = typeDescriptionJP,
                typeNameEN = typeNameEN,
                typeDescriptionEN = typeDescriptionEN,
                typePrettyName = Effects.getPrettyName(typeId),
                levels = levels
            }
            table.insert(calculated, data)
        end
        datas[supportId] = calculated
    end
    return datas
end

return Leveled