Welcome to the Umamusume Wiki! If you want to contribute, please read the guidelines.
Module:Game/Cards/Data
< Module:Game | Cards
Documentation for this module may be created at Module:Game/Cards/Data/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 Data = {}
local Game = require("Module:Game")
local Utils = require("Module:Utils")
local BannerUtils = require("Module:Game/Banners/Utils")
local SkillGroups = require("Module:Game/Skills/Data/Groups")
local SkillEvolved = require("Module:Game/Skills/Data/Evolved")
---@class CardData
---@field id string
---@field characterId string
---@field nameJP string
---@field displayNameJP string
---@field nameEN string|nil
---@field displayNameEN string|nil
---@field availableEN boolean
---@field releaseDateJP string|nil
---@field releaseDateEN string|nil
---@field rarities CardDataRarity[]
---@field defaultRarity string
---@field skillRanks CardDataRank[]
---@field boons CardDataStatTable
---@field defaultRunningStyle string
---@field iconPage string
---@field standPage string
---@class CardDataRarity
---@field rarity string
---@field ultimateSkillId string
---@field outfitId string
---@field baseStats CardDataStatTable
---@field aptitudes CardDataAptitudes
---@class CardDataRank
---@field rank string
---@field skillIds string[]
---@field evolutions CardEvolvedSkill[]
---@class CardDataStatTable
---@field speed number
---@field stamina number
---@field power number
---@field guts number
---@field wit number
---@class CardDataAptitudes
---@field groundTurf string
---@field groundDirt string
---@field distanceShort string
---@field distanceMile string
---@field distanceMid string
---@field distanceLong string
---@field styleFront string
---@field stylePace string
---@field styleLate string
---@field styleEnd string
---Get card data by its ID
---@param cardId string
---@return CardData|nil
function Data.getCard(cardId)
local card_data = Game.queryMaster {
from = "card_data",
where = string.format("id = %s", cardId),
limit = 1
}
if #card_data == 0 then return nil end
return Data._mapDatas(card_data)[Utils.normalString(cardId)]
end
---Get a batch of cards by list of IDs
---@param cardIds string[]
---@return CardData[]
function Data.getBatch(cardIds)
local cardIdsInsert = table.concat(cardIds, ",")
local card_datas = Game.queryMaster {
from = "card_data",
where = string.format("id IN (%s)", cardIdsInsert)
}
local mapped = Data._mapDatas(card_datas)
local datas = {}
for _, cardId in ipairs(cardIds) do
table.insert(datas, mapped[Utils.normalString(cardId)])
end
return datas
end
---@param card_datas table[]
---@return CardData[]
function Data._mapDatas(card_datas)
local cardIds = {}
local cardSkillSetIdPairs = {}
for _, card_data in ipairs(card_datas) do
table.insert(cardIds, card_data.id)
table.insert(cardSkillSetIdPairs, { card_data.id, card_data.available_skill_set_id })
end
local cardIdsInsert = table.concat(cardIds, ",")
local namesJP = Game.getJPText(5, cardIds)
local displayNamesJP = Game.getJPText(4, cardIds)
local namesEN = Game.getENText(5, cardIds)
local displayNamesEN = Game.getENText(4, cardIds)
local rarityDataMap = Data._mapRarityDatas(cardIds)
local rankDataMap = Data._mapRankDatas(cardSkillSetIdPairs)
local card_datas_en = Game.queryMasterEN {
from = "card_data",
where = string.format("id IN (%s)", cardIdsInsert),
data = { "id" }
}
local availabilityEN = {}
for _, card_data in ipairs(card_datas_en) do
if card_data[1] ~= nil then -- single results will mess up the iteration
availabilityEN[card_data[1]] = true
end
end
-- Get release dates for cards from gacha data
local releaseDatesJP = BannerUtils.getReleaseDates(cardIds, "card", "JP")
local releaseDatesEN = BannerUtils.getReleaseDates(cardIds, "card", "EN")
local runningStyleMap = {
['1'] = "Front Runner",
['2'] = "Pace Chaser",
['3'] = "Late Surger",
['4'] = "End Closer"
}
local datas = {}
for _, card_data in ipairs(card_datas) do
local nameJP = namesJP[card_data.id] or ''
local displayNameJP = displayNamesJP[card_data.id] or ''
local nameEN = namesEN[card_data.id]
local displayNameEN = displayNamesEN[card_data.id]
local releaseDateJP = releaseDatesJP[card_data.id] -- stores Unix timestamp
local releaseDateEN = releaseDatesEN[card_data.id] -- stores Unix timestamp
local rarityData = rarityDataMap[card_data.id]
local rankData = rankDataMap[card_data.id]
local dressId = rarityData['3'].outfitId
local data = { ---@type CardData
id = card_data.id,
characterId = card_data.chara_id,
nameJP = nameJP,
displayNameJP = displayNameJP,
nameEN = nameEN,
displayNameEN = displayNameEN,
availableEN = availabilityEN[card_data.id] == true,
releaseDateJP = releaseDateJP,
releaseDateEN = releaseDateEN,
rarities = rarityData,
defaultRarity = card_data.default_rarity,
skillRanks = rankData,
boons = {
speed = tonumber(card_data.talent_speed) or 0,
stamina = tonumber(card_data.talent_stamina) or 0,
power = tonumber(card_data.talent_pow) or 0,
guts = tonumber(card_data.talent_guts) or 0,
wit = tonumber(card_data.talent_wiz) or 0
},
defaultRunningStyle = runningStyleMap[card_data.running_style],
iconPage = string.format("Game Playable Icon %s.png", card_data.id),
standPage = string.format("Game Asset chara stand %s %06d.png", card_data.chara_id, dressId),
}
datas[card_data.id] = data
end
return datas
end
---@param cardIds string[]
---@return CardDataRarity[][]
function Data._mapRarityDatas(cardIds)
local cardIdsInsert = table.concat(cardIds, ",")
local card_rarity_datas = Game.queryMaster {
from = "card_rarity_data",
where = string.format("card_id IN (%s)", cardIdsInsert)
}
local skillSets = {}
for _, card_rarity_data in ipairs(card_rarity_datas) do
table.insert(skillSets, card_rarity_data.skill_set)
end
local skillSetMap = SkillGroups.getSkillSets(skillSets)
local aptitudeMap = {
['1'] = "G",
['2'] = "F",
['3'] = "E",
['4'] = "D",
['5'] = "C",
['6'] = "B",
['7'] = "A",
['8'] = "S"
}
local datas = {}
for _, card_rarity_data in ipairs(card_rarity_datas) do
if datas[card_rarity_data.card_id] == nil then datas[card_rarity_data.card_id] = {} end
local skillSet = skillSetMap[card_rarity_data.skill_set]
local firstSkillSet = skillSet[1]
local ultimateId = firstSkillSet and firstSkillSet[1] or nil
local data = { ---@type CardDataRarity
rarity = card_rarity_data.rarity,
ultimateSkillId = ultimateId,
outfitId = card_rarity_data.race_dress_id,
baseStats = {
speed = card_rarity_data.speed,
stamina = card_rarity_data.stamina,
power = card_rarity_data.pow,
guts = card_rarity_data.guts,
wit = card_rarity_data.wiz
},
aptitudes = {
groundTurf = aptitudeMap[card_rarity_data.proper_ground_turf],
groundDirt = aptitudeMap[card_rarity_data.proper_ground_dirt],
distanceShort = aptitudeMap[card_rarity_data.proper_distance_short],
distanceMile = aptitudeMap[card_rarity_data.proper_distance_mile],
distanceMid = aptitudeMap[card_rarity_data.proper_distance_middle],
distanceLong = aptitudeMap[card_rarity_data.proper_distance_long],
styleFront = aptitudeMap[card_rarity_data.proper_running_style_nige],
stylePace = aptitudeMap[card_rarity_data.proper_running_style_senko],
styleLate = aptitudeMap[card_rarity_data.proper_running_style_sashi],
styleEnd = aptitudeMap[card_rarity_data.proper_running_style_oikomi]
},
}
datas[card_rarity_data.card_id][card_rarity_data.rarity] = data
end
return datas
end
---@param cardSkillSetIdPairs [string, string][]
---@return CardDataRank[]
function Data._mapRankDatas(cardSkillSetIdPairs)
local cardIds = {}
local skillSetIds = {}
local skillSetIdCardIdMap = {}
for _, cardSkillSetIdPair in ipairs(cardSkillSetIdPairs) do
table.insert(cardIds, cardSkillSetIdPair[1])
table.insert(skillSetIds, cardSkillSetIdPair[2])
skillSetIdCardIdMap[cardSkillSetIdPair[2]] = cardSkillSetIdPair[1]
end
local skillSetIdsInsert = table.concat(skillSetIds, ",")
local available_skill_sets = Game.queryMaster {
from = "available_skill_set",
where = string.format("available_skill_set_id IN (%s)", skillSetIdsInsert)
}
local evolvedSkillMap = SkillEvolved.getEvolvedSkillsForCards(cardIds)
local datas = {}
for _, available_skill_set in ipairs(available_skill_sets) do
local cardId = skillSetIdCardIdMap[available_skill_set.available_skill_set_id]
if datas[cardId] == nil then datas[cardId] = {} end
local rank = available_skill_set.need_rank
if rank == '0' then rank = '1' end -- rank 0 is equivalent to rank 1
if datas[cardId][rank] ~= nil then
table.insert(datas[cardId][rank].skillIds, available_skill_set.skill_id)
else
local evolutions = {}
for _, evolvedSkill in ipairs(evolvedSkillMap[cardId]) do
if evolvedSkill.rank == rank then
table.insert(evolutions, evolvedSkill)
end
end
datas[cardId][rank] = { ---@type CardDataRank
rank = rank,
skillIds = { available_skill_set.skill_id },
evolutions = evolutions
}
end
end
return datas
end
return Data