Mudanças entre as edições de "Módulo:Conquistas"

De Wiki Gla
Ir para navegação Ir para pesquisar
m
m
Linha 1: Linha 1:
--[[
  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 p = {}
local Item = require("Módulo:Item")
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 VALID_TAGS = {
local DEFAULT_LANG = "pt"
     geral      = true,
local DEFAULT_ICON = "conquistafoosha.png"
     personagens = true,
 
     missao      = true,
local TABS = {
     bau        = true,
     { id = "geral",       label = "Geral" },
     navegacao  = true,
     { id = "personagens", label = "Personagens" },
     pvp        = true,
     { id = "missao",     label = "Missão" },
     pve        = true,
     { id = "bau",         label = "Baú" },
     coliseu    = true,
     { id = "navegacao",   label = "Navegação" },
     poneglyph  = true,
     { id = "pvp",         label = "PvP" },
     indicacao  = true,
     { id = "pve",         label = "PvE" },
     celular    = true,
     { id = "coliseu",     label = "Coliseu" },
     bossrush    = true,
     { 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)
local function trim(s)
Linha 21: Linha 45:
end
end


local function normalizeTag(tag)
local function normalizeTab(tag)
     local t = trim(tag):lower()
     local t = trim(tag):lower()
     if t == "" or not VALID_TAGS[t] then
     if t == "" or not VALID_TABS[t] then return "geral" end
        return "geral"
    end
     return t
     return t
end
end


local function normalizeImageName(name)
local function normalizeIcon(name)
     local clean = trim(name)
     local clean = trim(name)
     if clean == "" then return "conquistafoosha.png" end
     if clean == "" then return DEFAULT_ICON end
     if clean:match("%.%w+$") then return clean end
     if clean:match("%.%w+$") then return clean end
     return clean .. ".png"
     return clean .. ".png"
end
local function parseRewardString(s)
    local entries = {}
    s = trim(s)
    if s == "" then return entries end
    for entry in mw.text.gsplit(s, ";", true) do
        local clean = trim(entry)
        if clean ~= "" then
            local ident, qtdStr = clean:match("^(.-)%s*:%s*(%-?%d+)$")
            if ident and qtdStr then
                ident = trim(ident)
                local qtd = tonumber(qtdStr)
                if ident ~= "" and qtd then
                    table.insert(entries, { ident = ident, qtd = qtd })
                end
            end
        end
    end
    return entries
end
end


Linha 74: Linha 74:
local function resolveRewardItem(ident)
local function resolveRewardItem(ident)
     local item = Item.resolve(ident)
     local item = Item.resolve(ident)
     if item then
     if item then return item end
        return item
    end
 
     return {
     return {
         id = 0,
         id = 0,
         image = ident:match("%.%w+$") and ident or (ident .. ".png"),
         image = ident:match("%.%w+$") and ident or (ident .. ".png"),
         names = { pt = ident, en = ident },
         names = { pt = ident, en = ident },
         category = "unknown"
         category = "unknown",
     }
     }
end
end


local function renderReward(entries, lang)
--[[
     if not entries or #entries == 0 then
  renderRewards: replica o output do Módulo:Reward (predefinição {{Reward}})
        return ""
  para uma lista estruturada [{ ident, qty }, ...].
    end
 
  - 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 wrapper = mw.html.create("div"):addClass("reward-wrapper")
     local line = wrapper:tag("div"):addClass("reward-items")
     local line = wrapper:tag("div"):addClass("reward-items")


     local normal = {}
     local normais = {}
     local berries = {}
     local berries = {}


     for _, e in ipairs(entries) do
     for _, r in ipairs(rewards) do
         local item = resolveRewardItem(e.ident)
         local ident = trim(r.ident)
         local block = {
         local qty = tonumber(r.qty) or 0
             item = item,
        if ident ~= "" then
             qty = formatNumber(e.qtd)
             local item = resolveRewardItem(ident)
        }
            local img = Item.getImage(item) or ""
             local isBerries = item.category == "currency"
                and img:lower():find("berries")


        local image = Item.getImage(item) or ""
            local block = {
        local isBerries = item.category == "currency" and image:lower():find("berries")
                item = item,
        if isBerries then
                qty = formatNumber(qty),
            table.insert(berries, block)
            }
        else
 
            table.insert(normal, block)
            if isBerries then
                table.insert(berries, block)
            else
                table.insert(normais, block)
            end
         end
         end
     end
     end


     local function appendBlock(b)
     local function append(b)
        -- Tooltip desligado aqui para reduzir custo de parse em páginas enormes.
         line:wikitext(Item.renderOne(b.item, b.qty, lang, {
         line:wikitext(Item.renderOne(b.item, b.qty, lang, {
             showTooltip = false,
             showTooltip = true,
             showCount = true
             showCount = true,
         }))
         }))
     end
     end


     for _, b in ipairs(normal) do
     for _, b in ipairs(normais) do append(b) end
         appendBlock(b)
    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
     end
     for _, b in ipairs(berries) do
     if name == "" then name = "Titulo da Conquista" end
        appendBlock(b)
 
    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
     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")


     return tostring(wrapper)
    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
end


Linha 139: Linha 196:
end
end


function p.card(frame)
--[[
    local args    = getArgs(frame)
  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.


    local name    = trim(args.name)
  Parâmetros opcionais:
     local cardType = trim(args.type)
     |lang  = "pt" (padrão) | "en"
    local tag      = normalizeTag(cardType ~= "" and cardType or args.tag)
     |only  = id de uma aba — se passado, emite só ela (debug)
     local icon    = normalizeImageName(args.icon)
]]
    local desc    = trim(args.desc)
function p.renderAll(frame)
     local reward  = trim(args.reward)
     local args = getArgs(frame)
     local lang     = trim(args.lang)
     local lang = trim(args.lang)
     if lang == "" then lang = "pt" end
     if lang == "" then lang = DEFAULT_LANG end
    local onlyTab = trim(args.only):lower()


     if name == "" then name = "Titulo da Conquista" end
     local list = AchievementDB.all() or {}
    if desc == "" then desc = "Descricao da conquista." end


     local card = mw.html.create("div")
    -- Agrupa por aba mantendo a ordem original.
         :addClass("gla-item")
     local byTab = {}
         :attr("data-tab", tag)
    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 left = card:tag("div"):addClass("gla-item-left")
     local root = mw.html.create("div"):addClass("gla-conquistas-content")


     left:tag("div")
     local first = true
        :addClass("gla-item-icon")
    for _, t in ipairs(TABS) do
        :wikitext(string.format("[[File:%s|56px|alt=%s|link=]]", icon, name))
        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 textWrap = left:tag("div")
            local listEl = panel:tag("div"):addClass("gla-list")
    textWrap:tag("div"):addClass("gla-item-title"):wikitext(name)
            local cards = byTab[t.id] or {}
    textWrap:tag("div"):addClass("gla-item-desc"):wikitext(desc)
            for _, ach in ipairs(cards) do
                listEl:wikitext(renderCard(ach, lang))
            end
        end
    end


     local rewardList = parseRewardString(reward)
     return tostring(root)
    if #rewardList > 0 then
end
        local rewardHtml = renderReward(rewardList, lang)


        card:tag("div")
--[[
             :addClass("gla-item-reward")
  p.card(frame): mantido para compat com páginas que ainda usam
             :wikitext("Recompensa: " .. rewardHtml)
  {{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
     end
    return out
end
function p.card(frame)
    local args = getArgs(frame)


     return tostring(card)
    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
end


-- Compatibilidade com chamadas antigas
p.render = p.card
p.render = p.card


return p
return p

Edição das 01h35min de 15 de maio de 2026

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