Welcome to the Umamusume Wiki! If you want to contribute, please read the guidelines.
Module:Game/Skills
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Game/Skills/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/Skills/Data")
local Cargo = require("Module:Cargo")
local Utils = require("Module:Utils")
---Generate lists of arguments for the Game Skill/tooltip template
---Use to batch create lots of skill links for pages that need them
---@param skillIds string[]
---@return any[] templateArgs keyed by support ID
function p.generateSkillLinks(skillIds)
local skillIdsInsert = table.concat(skillIds, ',')
local results = Cargo.query {
from = 'Game_Skills',
fields = { '_pageName=skillPage', 'skill_id', 'name_ro', 'name_ww', 'description_en' },
where = string.format('skill_id IN (%s)', skillIdsInsert),
limit = #skillIds
}
local skillDatas = Data.getBatch(skillIds)
local merged = Utils.pairObjects(skillDatas, 'id', results, 'skill_id', true)
local datas = {}
for _, pair in ipairs(merged) do
local cargoData, skillData = pair[2], pair[1] ---@type any
if not cargoData then
-- Generate expected page name for easy creation if the page does not exist
cargoData = {
skillPage = string.format("Game:Skills/%s", skillData.id)
}
end
local templateArgs = {
icon = skillData.iconPage,
link = cargoData.skillPage,
name_jp = skillData.nameJP,
name_ro = cargoData.name_ro,
name_ww = skillData.nameEN or cargoData.name_ww,
description_jp = table.concat(skillData.descriptionJP, ""),
description_en = skillData.descriptionEN and table.concat(skillData.descriptionEN, "") or
cargoData.description_en,
}
datas[skillData.id] = templateArgs
end
return datas
end
function p.skillTooltip(frame)
local skillId = Utils.normalString(mw.text.decode(frame.args[1]))
if not skillId then return end
local templateData = p.generateSkillLinks({ skillId })[skillId]
if not templateData then return end
local tooltipText = frame:expandTemplate {
title = "Game Skill/tooltip",
args = templateData
}
local text = string.format('[[File:%s|22px]] %s', templateData.icon, tooltipText)
return text
end
function p.skillListTable(frame)
local tableType = mw.text.decode(frame.args[1])
local wheres = {
['ults'] = 'skill_type = "ult" OR skill_type = "ult_2"',
['inherited_ults'] = 'skill_type = "ult_inherit"',
['basic'] = 'skill_type = "basic"',
['debuff'] = 'skill_type = "debuff"',
['rare'] = 'skill_type = "rare"',
['evolved'] = 'skill_type = "upgraded_scenario" OR skill_type = "upgraded_card"'
}
local results = Cargo.query {
from = 'Game_Skills',
fields = { '_pageName=skillPage', 'skill_id', 'name_ro', 'name_ww', 'description_en' },
where = wheres[tableType],
limit = '9999',
orderBy = 'sort_value'
}
local skillIds = {}
for _, data in ipairs(results) do
table.insert(skillIds, tostring(data.skill_id))
end
local skillDatas = Data.getBatch(skillIds)
local paired = Utils.pairObjects(results, 'skill_id', skillDatas, 'id')
local mwtable = mw.html.create('table'):addClass('wikitable'):addClass('sortable'):addClass('mw-collapsible')
local headerRow = mw.html.create('tr')
local headerTexts = { 'Icon', 'Skill Names', 'Description', 'Skill Points', 'Eval. Points', 'Point Ratio' }
for _, value in ipairs(headerTexts) do
headerRow:node(mw.html.create('th'):wikitext(value))
end
mwtable:node(headerRow)
for _, pair in ipairs(paired) do
local cargoData, skillData = pair[1], pair[2] ---@type any
local mainName = skillData.nameEN or cargoData.name_ww or cargoData.name_ro
local subName = skillData.nameJP ---@type string|nil
if mainName == nil or mainName == '' then
mainName = skillData.nameJP
subName = nil
end
local description = table.concat(skillData.descriptionJP, "")
if skillData.descriptionEN ~= nil then
description = table.concat(skillData.descriptionEN, "")
elseif cargoData.description_en ~= nil and cargoData.description_en ~= '' then
description = cargoData.description_en
end
local mainLink = string.format("'''[[%s|%s]]'''", cargoData.skillPage, mainName)
if not skillData.availableEN then
mainLink = mainLink .. frame:expandTemplate {
title = "tooltip",
args = { "<sup>JP</sup>", "Only on the Japanese version" }
}
end
local nameText = (subName == nil or subName == '') and mainLink or
string.format("%s<br/>''%s''", mainLink, subName)
local row = mw.html.create('tr')
local renderTexts = {
'[[File:' .. skillData.iconPage .. '|48px]]',
nameText,
description,
skillData.skillPointCost and (skillData.skillPointCost + (skillData.skillPointCostAddl or 0)) or '-',
skillData.evalPoint or '-',
skillData.valueRatio and string.format("%.2f", skillData.valueRatio) or '-',
}
for _, value in ipairs(renderTexts) do
row:node(mw.html.create('td'):wikitext(value))
end
mwtable:node(row)
end
return tostring(mwtable)
end
function p.skillPage(frame)
local skillId = mw.text.decode(frame.args[1])
if not skillId then return end
local skillData = Data.getSkill(skillId)
if not skillData then return end
local isExternal = frame.args[2] == 'external'
local link = nil
local nameRO = frame.args['name_ro']
local nameWW = frame.args['name_ww']
local descriptionEN = frame.args['description_en']
if isExternal then
local results = Cargo.query {
from = 'Game_Skills',
fields = { '_pageName=skillPage', 'name_ro', 'name_ww', 'description_en' },
where = string.format('skill_id = "%s"', skillId),
limit = '1',
}
local cargoData = results[1]
if cargoData then
link = cargoData.skillPage
nameRO = cargoData.name_ro
nameWW = cargoData.name_ww
descriptionEN = cargoData.description_en
end
end
local templateArgs = {
skill_id = skillId,
page_link = link,
icon = skillData.iconPage,
name_jp = skillData.nameJP,
name_ro = nameRO or '',
name_ww = skillData.nameEN or nameWW or '',
description_jp = table.concat(skillData.descriptionJP, ""),
description_en = skillData.descriptionEN and table.concat(skillData.descriptionEN) or descriptionEN,
available_en = skillData.availableEN,
skill_point = skillData.skillPointCost,
skill_point_addl = skillData.skillPointCostAddl or '',
eval_point = skillData.evalPoint,
eval_ratio = skillData.valueRatio and string.format("%.2f", skillData.valueRatio) or '',
upgrades_from = skillData.upgradedFrom or '',
upgrades_to = skillData.upgradedTo or '',
evolves_from = skillData.evolvedFrom or '',
evolves_from_card = skillData.evolvedForCard or '',
ult_for_card = skillData.ultForCard or '',
}
local text = frame:expandTemplate {
title = "Game Skill Definition/page",
args = templateArgs
}
return text
end
function p.createConditionsTable(frame, tableElement, conditionsHeader, conditionsList, numRows, hasThird)
local firstRow = mw.html.create('tr')
local conditionsHead = mw.html.create('th'):wikitext(conditionsHeader)
firstRow:node(conditionsHead)
if numRows > 1 or hasThird then
conditionsHead:attr('rowspan', numRows)
local orText = mw.html.create('td'):wikitext(numRows > 1 and "'''OR'''" or ""):attr('rowspan', numRows)
firstRow:node(orText)
end
tableElement:node(firstRow)
for j, condOr in ipairs(conditionsList) do
local conditionText = mw.html.create('td')
for k, condAnd in ipairs(condOr) do
if k > 1 then
conditionText:wikitext(" '''AND''' ")
end
if condAnd.condition and condAnd.compare and condAnd.value then
local text = string.format('%s %s %s', condAnd.condition, condAnd.compare, condAnd.value)
if condAnd.hint then
conditionText:wikitext(frame:expandTemplate {
title = "Tooltip",
args = { text, condAnd.hint }
})
else
conditionText:wikitext(text)
end
end
end
if j > 1 then
local newRow = mw.html.create('tr')
newRow:node(conditionText)
tableElement:node(newRow)
else
firstRow:node(conditionText)
end
end
end
function p.effectsTables(frame)
local skillId = mw.text.decode(frame.args[1])
if not skillId then return end
local skillData = Data.getSkill(skillId)
if not skillData then return end
local render = ''
for i, effect in ipairs(skillData.effects) do
local wrapperDiv = mw.html.create('div'):addClass('skill-effect-wrapper'):addClass('fit-content')
local effectKeys = {}
local effectValues = {}
if effect.cooldown then
table.insert(effectKeys, 'Cooldown')
table.insert(effectValues, { value = string.format("%.1fs", effect.cooldown) })
end
if effect.duration then
table.insert(effectKeys, 'Duration')
local val = { value = string.format("%.1fs", effect.duration) }
if effect.durationScaling ~= nil then
val['valueTooltip'] = string.format("Scaled By: %s", effect.durationScaling)
end
table.insert(effectValues, val)
end
for _, ability in ipairs(effect.abilities) do
table.insert(effectKeys, ability.ability)
local val = {}
if ability.valueFormat == 'pct' then
val['value'] = tonumber(string.format("%.2f", ability.value * 100)) .. '%'
elseif ability.valueFormat == 'dec' then
val['value'] = tonumber(string.format("%f", ability.value))
else
val['value'] = nil
end
if ability.target then
val['tooltip'] = string.format("Targets: %s", ability.target.target)
end
if ability.valueScaling then
val['valueTooltip'] = string.format("Scaled By: %s", ability.valueScaling)
end
table.insert(effectValues, val)
end
local basicTable = mw.html.create('table'):addClass('wikitable')
for index, key in ipairs(effectKeys) do
local values = effectValues[index]
local value = values['value']
if values['tooltip'] then
key = frame:expandTemplate {
title = "Tooltip",
args = { key, values['tooltip'] }
}
end
if values['valueTooltip'] then
value = frame:expandTemplate {
title = "Tooltip",
args = { value, values['valueTooltip'] }
}
end
local row = mw.html.create('tr')
local th = mw.html.create('th'):wikitext(key)
local td = mw.html.create('td'):wikitext(value)
row:node(th)
row:node(td)
basicTable:node(row)
end
local conditionsTable = mw.html.create('table'):addClass('wikitable')
local numRowsPre = 0
if effect.preconditions then
for _, _ in pairs(effect.preconditions) do numRowsPre = numRowsPre + 1 end
end
local numRows = 0
for _, _ in pairs(effect.conditions) do numRows = numRows + 1 end
local hasThird = numRowsPre > 1 or numRows > 1
if effect.preconditions then
p.createConditionsTable(frame, conditionsTable, frame:expandTemplate {
title = "Tooltip",
args = { "Preconditions", "Must be valid at least once at any point in the race before the skill can activate" }
},
effect.preconditions, numRowsPre, hasThird)
end
if effect.conditions then
p.createConditionsTable(frame, conditionsTable, frame:expandTemplate {
title = "Tooltip",
args = { "Conditions", "When valid, skill has a chance to activate" }
}, effect.conditions, numRows, hasThird)
end
wrapperDiv:node(basicTable)
wrapperDiv:node(conditionsTable)
if i > 1 then render = render .. '\n\n' end
render = render .. tostring(wrapperDiv)
end
return render
end
return p