Módulo:Conquistas
Ir para navegação
Ir para pesquisar
A documentação para este módulo pode ser criada em Módulo:Conquistas/doc
--[[
Módulo:Conquistas
Renderiza TODAS as conquistas em uma única passada, lendo o banco
Módulo:AchievementDB (carregado via mw.loadData, cacheado pelo Scribunto).
Usado pelo Widget:Conquista, que faz {{#invoke:Conquistas|renderAll}}.
Substitui a chamada antiga de 442 {{Conquista|...}} (1 #invoke por card)
por um único #invoke que emite o shell completo de painéis + cards.
Rewards usam exatamente o mesmo visual do Módulo:Reward (item-wrapper
com tooltip, ordenando berries por último).
]]
local p = {}
local Item = require("Módulo:Item")
-- require (não loadData) porque AchievementDB expõe funções (all/byTab/getById).
-- O Scribunto cacheia requires dentro do mesmo parser pass.
local AchievementDB = require("Módulo:AchievementDB")
local DEFAULT_LANG = "pt"
local DEFAULT_ICON = "conquistafoosha.png"
local TABS = {
{ id = "geral", label = "Geral" },
{ id = "personagens", label = "Personagens" },
{ id = "missao", label = "Missão" },
{ id = "bau", label = "Baú" },
{ id = "navegacao", label = "Navegação" },
{ id = "pvp", label = "PvP" },
{ id = "pve", label = "PvE" },
{ id = "coliseu", label = "Coliseu" },
{ id = "poneglyph", label = "Poneglyph" },
{ id = "indicacao", label = "Indicação" },
{ id = "celular", label = "Celular" },
{ id = "bossrush", label = "Boss Rush" },
}
local VALID_TABS = {}
for _, t in ipairs(TABS) do VALID_TABS[t.id] = true end
local function trim(s)
return mw.text.trim(s or "")
end
local function normalizeTab(tag)
local t = trim(tag):lower()
if t == "" or not VALID_TABS[t] then return "geral" end
return t
end
local function normalizeIcon(name)
local clean = trim(name)
if clean == "" then return DEFAULT_ICON end
if clean:match("%.%w+$") then return clean end
return clean .. ".png"
end
local function formatNumber(num)
num = tonumber(num) or 0
if num >= 1e9 then
return string.format("%.0f", num / 1e6) .. "KKK"
elseif num >= 1e6 then
return string.format("%.0f", num / 1e6) .. "KK"
elseif num >= 1e4 then
return string.format("%.0f", num / 1e3) .. "K"
else
local s = tostring(num)
return s:reverse():gsub("(%d%d%d)", "%1,"):reverse():gsub("^,", "")
end
end
local function resolveRewardItem(ident)
local item = Item.resolve(ident)
if item then return item end
return {
id = 0,
image = ident:match("%.%w+$") and ident or (ident .. ".png"),
names = { pt = ident, en = ident },
category = "unknown",
}
end
--[[
renderRewards: replica o output do Módulo:Reward (predefinição {{Reward}})
para uma lista estruturada [{ ident, qty }, ...].
- Mesmo wrapper .reward-wrapper
- Mesmo .reward-items
- Mesmo Item.renderOne com tooltip e count
- Berries sempre por último
]]
local function renderRewards(rewards, lang)
if not rewards or #rewards == 0 then return "" end
local wrapper = mw.html.create("div"):addClass("reward-wrapper")
local line = wrapper:tag("div"):addClass("reward-items")
local normais = {}
local berries = {}
for _, r in ipairs(rewards) do
local ident = trim(r.ident)
local qty = tonumber(r.qty) or 0
if ident ~= "" then
local item = resolveRewardItem(ident)
local img = Item.getImage(item) or ""
local isBerries = item.category == "currency"
and img:lower():find("berries")
local block = {
item = item,
qty = formatNumber(qty),
}
if isBerries then
table.insert(berries, block)
else
table.insert(normais, block)
end
end
end
local function append(b)
line:wikitext(Item.renderOne(b.item, b.qty, lang, {
showTooltip = true,
showCount = true,
}))
end
for _, b in ipairs(normais) do append(b) end
for _, b in ipairs(berries) do append(b) end
return tostring(wrapper)
end
--[[
Constrói o card de uma conquista. Retorna string HTML.
Usa dados puros (não recebe wikitext) — ideal para iteração em massa.
]]
local function renderCard(ach, lang)
local name = ""
if ach.names then
name = trim(ach.names[lang]) ~= "" and ach.names[lang]
or trim(ach.names.pt) ~= "" and ach.names.pt
or trim(ach.names.en) ~= "" and ach.names.en
or ""
end
if name == "" then name = "Titulo da Conquista" end
local desc = ""
if ach.desc then
desc = trim(ach.desc[lang]) ~= "" and ach.desc[lang]
or trim(ach.desc.pt) ~= "" and ach.desc.pt
or trim(ach.desc.en) ~= "" and ach.desc.en
or ""
end
if desc == "" then desc = "Descricao da conquista." end
local icon = normalizeIcon(ach.icon)
local tab = normalizeTab(ach.type)
local hidden = ach.hidden == true
local card = mw.html.create("div"):addClass("gla-item"):attr("data-tab", tab)
if hidden then card:addClass("is-hidden"):attr("data-hidden", "true") end
local left = card:tag("div"):addClass("gla-item-left")
left:tag("div")
:addClass("gla-item-icon")
:wikitext(string.format("[[File:%s|56px|alt=%s|link=]]", icon, name))
local textWrap = left:tag("div")
textWrap:tag("div"):addClass("gla-item-title"):wikitext(name)
textWrap:tag("div"):addClass("gla-item-desc"):wikitext(desc)
if ach.rewards and #ach.rewards > 0 then
local rewardHtml = renderRewards(ach.rewards, lang)
if rewardHtml ~= "" then
card:tag("div")
:addClass("gla-item-reward")
:wikitext("Recompensa: " .. rewardHtml)
end
end
return tostring(card)
end
local function getArgs(frame)
local args = frame.args or {}
if not next(args) and frame:getParent() then
args = frame:getParent().args or {}
end
return args
end
--[[
p.renderAll(frame): emite todos os 12 painéis com seus respectivos cards
já dentro. O Widget:Conquista cuida apenas do header/tabs e da CSS/JS de
alternância. Não há trabalho de runtime para realocar cards.
Parâmetros opcionais:
|lang = "pt" (padrão) | "en"
|only = id de uma aba — se passado, emite só ela (debug)
]]
function p.renderAll(frame)
local args = getArgs(frame)
local lang = trim(args.lang)
if lang == "" then lang = DEFAULT_LANG end
local onlyTab = trim(args.only):lower()
local list = AchievementDB.all() or {}
-- Agrupa por aba mantendo a ordem original.
local byTab = {}
for _, t in ipairs(TABS) do byTab[t.id] = {} end
for _, ach in ipairs(list) do
local tab = normalizeTab(ach.type)
table.insert(byTab[tab], ach)
end
local root = mw.html.create("div"):addClass("gla-conquistas-content")
local first = true
for _, t in ipairs(TABS) do
if onlyTab == "" or onlyTab == t.id then
local panel = root:tag("div"):addClass("gla-conquistas-panel")
:attr("data-tab-content", t.id)
if first then panel:addClass("is-active") end
first = false
local listEl = panel:tag("div"):addClass("gla-list")
local cards = byTab[t.id] or {}
for _, ach in ipairs(cards) do
listEl:wikitext(renderCard(ach, lang))
end
end
end
return tostring(root)
end
--[[
p.card(frame): mantido para compat com páginas que ainda usam
{{Conquista|name=...|type=...|...}} no estilo antigo.
Recebe rewards como string "Ident:qty;Ident:qty".
]]
local function parseLegacyRewardString(s)
local out = {}
if not s or s == "" then return out end
for entry in mw.text.gsplit(s, ";", true) do
local clean = trim(entry)
if clean ~= "" then
local ident, qtyStr = clean:match("^(.-)%s*:%s*(%-?%d+)$")
if ident and qtyStr then
ident = trim(ident)
local qty = tonumber(qtyStr)
if ident ~= "" and qty then
table.insert(out, { ident = ident, qty = qty })
end
end
end
end
return out
end
function p.card(frame)
local args = getArgs(frame)
local cardType = trim(args.type)
local ach = {
type = cardType ~= "" and cardType or args.tag,
icon = args.icon,
hidden = false,
names = { pt = trim(args.name) },
desc = { pt = trim(args.desc) },
rewards = parseLegacyRewardString(args.reward),
}
local lang = trim(args.lang)
if lang == "" then lang = DEFAULT_LANG end
return renderCard(ach, lang)
end
p.render = p.card
return p