Welcome to the Umamusume Wiki! If you want to contribute, please read the guidelines.
Module:Game/Cards
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Game/Cards/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/Cards/Data")
local Characters = require("Module:Game/Characters")
local Cargo = require("Module:Cargo")
local Utils = require("Module:Utils")
local Game = require("Module:Game")
---Generate lists of arguments for the Game Card/link template
---Use to batch create lots of card links for pages that need them
---@param cardIds string[]
---@return any[] templateArgs keyed by card ID
function p.generateCardLinks(cardIds)
local results = {}
if #cardIds > 0 then
local cardIdsInsert = table.concat(cardIds, ',')
results = Cargo.query {
from = 'Game_Cards',
fields = { '_pageName=cardPage', 'card_id', 'name_ro', 'name_ww' },
where = string.format('Game_Cards.card_id IN (%s)', cardIdsInsert),
limit = #cardIds,
}
end
local cardDatas = Data.getBatch(cardIds)
local merged = Utils.pairObjects(cardDatas, 'id', results, 'card_id', true)
-- fetch required character info (no page exists or need for display name)
local charIds = {}
for _, pair in ipairs(merged) do
local cargoData, cardData = pair[2], pair[1] ---@type any
if not cargoData or not (cardData.displayNameEN or cargoData.name_ww) then
table.insert(charIds, cardData.characterId)
end
end
local charInfos = Characters.getCharacterInfos(charIds)
local datas = {}
for _, pair in ipairs(merged) do
local cargoData, cardData = pair[2], pair[1] ---@type any
local charData = charInfos[cardData.characterId]
if not cargoData then
-- Generate expected page name for easy creation if the page does not exist
cargoData = {
cardPage = string.format("Game:%s (%s)", charData and charData.nameEN or '',
string.gsub(cardData.nameEN or cardData.nameJP, "[%[%]]", ""))
}
end
local displayName = cardData.displayNameEN or cargoData.name_ww
if displayName == nil then
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 cardData.nameJP, charName)
end
local templateArgs = {
icon = cardData.iconPage,
page = cargoData.cardPage,
display = displayName
}
datas[cardData.id] = templateArgs
end
return datas
end
function p.cardLink(frame)
local cardId = Utils.normalString(mw.text.decode(frame.args[1]))
if not cardId then return end
local templateArgs = p.generateCardLinks({ cardId })[cardId]
if not templateArgs then return end
local text = frame:expandTemplate {
title = "Game Card/link",
args = templateArgs
}
return text
end
function p.characterCardLinks(frame)
local charId = Utils.normalString(mw.text.decode(frame.args[1]))
if not charId then return end
local card_datas = Game.queryMaster {
from = "card_data",
where = string.format("chara_id = %s AND id < 9000000", charId),
data = {
id = "id"
}
}
local cardIds = {}
for _, card_data in ipairs(card_datas) do
table.insert(cardIds, card_data.id)
end
table.sort(cardIds)
local cardLinks = p.generateCardLinks(cardIds)
local text = ''
for _, cardId in ipairs(cardIds) do
local templateArgs = cardLinks[cardId]
text = text .. frame:expandTemplate {
title = "Game Card/link",
args = templateArgs
} .. '\n\n'
end
if #text == 0 then
return "''None.''"
end
return mw.text.trim(text)
end
function p.cardPage(frame)
local cardId = mw.text.decode(frame.args[1])
if not cardId then return end
local cardData = Data.getCard(cardId)
if not cardData then return end
local charData = Characters.getCharacterInfo(cardData.characterId)
if not charData then return end
local nameRO = frame.args['name_ro']
local nameWW = frame.args['name_ww']
local function boonText(number)
if number > 0 then return tostring(number) end
return ''
end
local displayEN = nil
if #nameRO > 0 then displayEN = nameRO end
if #nameWW > 0 then displayEN = nameWW end
local baseRarity = cardData.rarities['3']
local defaultRarity = cardData.rarities[cardData.defaultRarity]
local templateArgs = {
image_page = cardData.standPage,
name_jp = cardData.nameJP,
name_full_jp = cardData.displayNameJP,
name_en = cardData.nameEN or (displayEN and string.format("[%s]", displayEN) or ''),
release_date_jp = cardData.releaseDateJP,
release_date_en = cardData.releaseDateEN, -- timestamp
available_en = cardData.availableEN,
char_link = charData.pageName,
rarity = cardData.defaultRarity,
rank_turf = baseRarity.aptitudes.groundTurf,
rank_dirt = baseRarity.aptitudes.groundDirt,
rank_sprint = baseRarity.aptitudes.distanceShort,
rank_mile = baseRarity.aptitudes.distanceMile,
rank_middle = baseRarity.aptitudes.distanceMid,
rank_long = baseRarity.aptitudes.distanceLong,
rank_front = baseRarity.aptitudes.styleFront,
rank_pace = baseRarity.aptitudes.stylePace,
rank_late = baseRarity.aptitudes.styleLate,
rank_end = baseRarity.aptitudes.styleEnd,
boon_speed = boonText(cardData.boons.speed),
boon_stamina = boonText(cardData.boons.stamina),
boon_power = boonText(cardData.boons.power),
boon_guts = boonText(cardData.boons.guts),
boon_wit = boonText(cardData.boons.wit),
skill_ult = baseRarity.ultimateSkillId,
lower_skill_ult = (defaultRarity.ultimateSkillId ~= baseRarity.ultimateSkillId) and defaultRarity
.ultimateSkillId or nil
}
for key, rarity in pairs(cardData.rarities) do
templateArgs["stats_speed_" .. key] = tostring(rarity.baseStats.speed)
templateArgs["stats_stamina_" .. key] = tostring(rarity.baseStats.stamina)
templateArgs["stats_power_" .. key] = tostring(rarity.baseStats.power)
templateArgs["stats_guts_" .. key] = tostring(rarity.baseStats.guts)
templateArgs["stats_wit_" .. key] = tostring(rarity.baseStats.wit)
end
for key, rank in pairs(cardData.skillRanks) do
for i, skillId in ipairs(rank.skillIds) do
templateArgs["skill_" .. key .. "_" .. i] = skillId
end
for i, evo in ipairs(rank.evolutions) do
templateArgs["skill_" .. key .. "_evo_" .. i] = evo.skillId
end
end
local text = frame:expandTemplate {
title = "Game Card Definition/page",
args = templateArgs
}
return text
end
function p.cardListTable(frame)
local results = Cargo.query {
from = 'Game_Cards',
fields = { '_pageName=cardPage', 'card_id', 'name_ro', 'name_ww' },
orderBy = "card_id",
limit = '9999',
}
local cardIds = {}
for _, data in ipairs(results) do
table.insert(cardIds, tostring(data.card_id))
end
local cardDatas = Data.getBatch(cardIds)
local paired = Utils.pairObjects(results, 'card_id', cardDatas, 'id')
local mwtable = mw.html.create('table'):addClass('wikitable'):addClass('sortable'):addClass('mw-collapsible')
local headerRow = mw.html.create('tr')
local headerTexts = { 'Icon', 'Name', 'Character', 'Release Date (JP)', 'Release Date (EN)', 'Rarity', 'Speed%',
'Stamina%', 'Power%', 'Guts%', 'Wit%', 'Turf',
'Dirt', 'Sprint', 'Mile', 'Middle', 'Long', 'Front', 'Pace', 'Late', 'End' }
for _, value in ipairs(headerTexts) do
headerRow:node(mw.html.create('th'):wikitext(value))
end
mwtable:node(headerRow)
local charIds = {}
for _, pair in ipairs(paired) do
table.insert(charIds, pair[2].characterId)
end
charIds = Utils.dedupe(charIds)
local charDatas = Characters.getCharacterInfos(charIds)
for _, pair in ipairs(paired) do
local cargoData, cardData = pair[1], pair[2] ---@type any
local charData = charDatas[cardData.characterId]
local baseRarity = cardData.rarities['3'] --- @type CardDataRarity
local nameMain = cardData.nameEN or cargoData.name_ww or cargoData.name_ro ---@type string|nil
local nameSub = cardData.nameJP ---@type string|nil
if nameMain == nil then
nameMain = nameSub
nameSub = nil
end
nameMain = string.gsub(nameMain or '', "[%[%]]", "")
if nameSub ~= nil then nameSub = string.gsub(nameSub, "[%[%]]", "") end
local mainLink = string.format("'''[[%s|%s]]'''", cargoData.cardPage, nameMain)
if not cardData.availableEN then
mainLink = mainLink .. frame:expandTemplate {
title = "tooltip",
args = { "<sup>JP</sup>", "Only on the Japanese version" }
}
end
local row = mw.html.create('tr')
local lang = mw.language.getContentLanguage()
local renderTexts = {
'[[File:' .. cardData.iconPage .. '|48px]]',
nameSub and string.format("%s<br/>''%s''", mainLink, nameSub) or mainLink,
string.format("[[%s|%s]]", charData.pageName, charData.nameEN),
cardData.releaseDateJP and lang:formatDate('Y-m-d', '@' .. cardData.releaseDateJP) or 'N/A',
cardData.releaseDateEN and lang:formatDate('Y-m-d', '@' .. cardData.releaseDateEN) or 'N/A',
cardData.defaultRarity == '1' and '★' or (cardData.defaultRarity == '2' and '★★' or '★★★'),
cardData.boons.speed,
cardData.boons.stamina,
cardData.boons.power,
cardData.boons.guts,
cardData.boons.wit
}
local renderValues = {
0, -- Icon
0, -- Name
0, -- Character
tonumber(cardData.releaseDateJP) or 0, -- Release Date JP
tonumber(cardData.releaseDateEN) or 0, -- Release Date EN
tonumber(cardData.defaultRarity), -- Rarity
0, -- Speed%
0, -- Stamina%
0, -- Power%
0, -- Guts%
0 -- Wit%
}
local function addAptitude(value)
local sortVals = {
['S'] = 8,
['A'] = 7,
['B'] = 6,
['C'] = 5,
['D'] = 4,
['E'] = 3,
['F'] = 2,
['G'] = 1,
}
table.insert(renderTexts, string.format("[[File:Rank %s.png|28px]]", value))
table.insert(renderValues, sortVals[value])
end
local aptitudes = baseRarity.aptitudes
addAptitude(aptitudes.groundTurf)
addAptitude(aptitudes.groundDirt)
addAptitude(aptitudes.distanceShort)
addAptitude(aptitudes.distanceMile)
addAptitude(aptitudes.distanceMid)
addAptitude(aptitudes.distanceLong)
addAptitude(aptitudes.styleFront)
addAptitude(aptitudes.stylePace)
addAptitude(aptitudes.styleLate)
addAptitude(aptitudes.styleEnd)
for i, value in ipairs(renderTexts) do
local nodeTd = mw.html.create('td'):wikitext(value)
if renderValues[i] > 0 then
nodeTd = nodeTd:attr('data-sort-value', renderValues[i])
end
row:node(nodeTd)
end
mwtable:node(row)
end
return tostring(mwtable)
end
return p