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

De Wiki Gla
Ir para navegação Ir para pesquisar
 
(45 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
-- Módulo:CalculadoraTier
-- Calculadora de custos para evolução de tiers/estrelas
-- Compatível com MediaWiki + Scribunto
local p = {}
local p = {}


-- \u26a0\ufe0f EDITÁVEL: Tabela de custos padrão
function p.main(frame)
-- Defina aqui os custos para cada estrela alcançada (1..5) em cada tier,
     local args = frame:getParent().args
-- e o custo para subir de um tier para o próximo.
local COSTS = {
  tiers = {"bronze", "prata", "ouro", "diamante"},
 
  -- Custo para alcançar CADA estrela (ex.: STAR[1] = custo para ir de 0 -> 1 estrela)
  star = {
    bronze = {
      [1] = { berry = 100, frag = 1 },
      [2] = { berry = 200, frag = 1 },
      [3] = { berry = 300, frag = 2 },
      [4] = { berry = 450, frag = 2 },
      [5] = { berry = 600, frag = 3 },
    },
    prata = {
      [1] = { berry = 200, frag = 1 },
      [2] = { berry = 300, frag = 2 },
      [3] = { berry = 450, frag = 2 },
      [4] = { berry = 650, frag = 3 },
      [5] = { berry = 900, frag = 4 },
    },
    ouro = {
      [1] = { berry = 400, frag = 2 },
      [2] = { berry = 600, frag = 2 },
      [3] = { berry = 900, frag = 3 },
      [4] = { berry = 1300, frag = 4 },
      [5] = { berry = 1800, frag = 5 },
    },
    diamante = {
      [1] = { berry = 800, frag = 3 },
      [2] = { berry = 1200, frag = 4 },
      [3] = { berry = 1700, frag = 5 },
      [4] = { berry = 2300, frag = 6 },
      [5] = { berry = 3000, frag = 8 },
    },
  },
 
  -- Custo de mudar de tier (ex.: BRONZE -> PRATA). Não altera estrelas (reinicia para 0).
  tierUp = {
    bronze  = { berry = 2000, frag = 5 },  -- custo para BRONZE -> PRATA
    prata    = { berry = 6000, frag = 10 }, -- custo para PRATA -> OURO
    ouro    = { berry = 15000, frag = 20 },-- custo para OURO -> DIAMANTE
    diamante = nil,                          -- não há próximo tier
  },
}
 
-- Normaliza texto (case-insensitive, acentos ignorados simples)
local function norm(s)
  if type(s) ~= 'string' then return nil end
  s = mw.ustring.lower(s)
  s = s:gsub("á", "a"):gsub("â", "a"):gsub("ã", "a")
      :gsub("é", "e"):gsub("ê", "e")
      :gsub("í", "i")
      :gsub("ó", "o"):gsub("ô", "o")
      :gsub("ú", "u")
  return s
end
 
local function tierIndex(name)
  local n = norm(name)
  for i, t in ipairs(COSTS.tiers) do
     if n == t then return i end
  end
  return nil
end
 
local function getTierName(idx)
  return COSTS.tiers[idx]
end
 
-- Soma custos (protege nil)
local function addCost(a, b)
  a = a or { berry = 0, frag = 0 }
  b = b or { berry = 0, frag = 0 }
  return { berry = (a.berry or 0) + (b.berry or 0), frag = (a.frag or 0) + (b.frag or 0) }
end
 
-- Obtém custo para subir 1 estrela dentro do tier
local function starCost(tierName, starTo)
  local t = COSTS.star[tierName]
  return t and t[starTo] or { berry = 0, frag = 0 }
end
 
-- Obtém custo para subir de tier
local function tierUpCost(tierName)
  local c = COSTS.tierUp[tierName]
  return c or { berry = 0, frag = 0 }
end
 
-- Caminho de evolução do estado (tierIdx, star) até (tierIdx2, star2)
local function computePath(ti, si, tf, sf)
  local steps = {}
  local total = { berry = 0, frag = 0 }
 
  local iTier, iStar = ti, si
 
  local function push(step)
    table.insert(steps, step)
    total = addCost(total, step.custo)
  end
 
  while (iTier < tf) or (iTier == tf and iStar < sf) do
    if iStar < 5 and (iTier < tf or (iTier == tf and iStar < sf)) then
      -- subir estrela dentro do tier atual
      local tierName = getTierName(iTier)
      local toStar = iStar + 1
      local c = starCost(tierName, toStar)
      push({ tipo = "estrela", tier = tierName, de = iStar, para = toStar, custo = c })
      iStar = toStar
    else
      -- já está com 5 estrelas -> tentar subir de tier
      if iTier >= #COSTS.tiers then
        -- não há próximo tier, evitar loop
        break
      end
      local fromTier = getTierName(iTier)
      local c = tierUpCost(fromTier)
      push({ tipo = "tier", de = fromTier, para = getTierName(iTier + 1), custo = c })
      iTier = iTier + 1
      iStar = 0 -- ao subir de tier, reinicia estrelas
    end
  end
 
  return steps, total
end
 
-- Renderização em wikitext/HTML
local function render(steps, total, opts)
  local h = mw.html.create('div'):addClass('calc-tier')
 
  if opts.titulo then
    h:tag('h3'):wikitext(opts.titulo)
  end
 
  if opts.mostrarTabela ~= false then
    local tbl = h:tag('table'):addClass('wikitable'):css('width', '100%')
    local thead = tbl:tag('tr')
    thead:tag('th'):wikitext('Passo')
    thead:tag('th'):wikitext('Ação')
    thead:tag('th'):wikitext('Custo (Berry)')
    thead:tag('th'):wikitext('Custo (Fragmentos)')
 
    for i, st in ipairs(steps) do
      local tr = tbl:tag('tr')
      tr:tag('td'):wikitext(i)
      if st.tipo == 'estrela' then
        tr:tag('td'):wikitext(string.format('Tier **%s**: %d → %d estrelas', st.tier, st.de, st.para))
      else
        tr:tag('td'):wikitext(string.format('Subir de **%s** → **%s**', st.de, st.para))
      end
      tr:tag('td'):wikitext(st.custo.berry or 0)
      tr:tag('td'):wikitext(st.custo.frag or 0)
    end
  end
 
  local box = h:tag('div'):addClass('calc-tier-total'):css('margin-top','8px')
  box:wikitext(string.format("'''Total:''' %d Berry • %d Fragmentos", total.berry or 0, total.frag or 0))


  return tostring(h)
    local normal_nivel    = mw.text.trim(args['normal_nivel']    or '140')
end
    local normal_equip    = mw.text.trim(args['normal_equip']    or 'Set +8')
    local hard_personagem = mw.text.trim(args['hard_personagem'] or 'personagem 4 ou 5 estrelas (Diamante)')
    local hard_equip      = mw.text.trim(args['hard_equip']      or 'Set +16')


local function parseInt(v, default)
    local root = mw.html.create('div')
  local n = tonumber(v)
    root:addClass('gb-wrap')
  if not n then return default end
  n = math.floor(n)
  return n
end


-- Entrada pública via #invoke
    -- CSS via TemplateStyles (recomendado) ou inline
function p.calcular(frame)
    -- Botões (tabs)
  local args = frame:getParent() and frame:getParent().args or frame.args
    local btns = root:tag('div'):addClass('gb-btns')


  local inicioTier = args.inicio_tier or args.de_tier or args.tier_inicial
    btns:tag('button')
  local fimTier    = args.fim_tier    or args.ate_tier or args.tier_final
        :addClass('gb-btn'):addClass('active')
  local inicioEst  = parseInt(args.inicio_estrela or args.de_estrela or args.estrelas_iniciais or 0, 0)
        :attr('onclick', "gbSwitch('n',this)")
  local fimEst    = parseInt(args.fim_estrela    or args.ate_estrela  or args.estrelas_finais  or 0, 0)
        :wikitext('Normal ')
        :tag('span'):addClass('gb-badge'):addClass('badge-n')
        :wikitext('Nível ' .. normal_nivel)


  -- Opções
    btns:tag('button')
  local titulo = args.titulo
        :addClass('gb-btn')
  local mostrarTabela = (tostring(args.mostrar_tabela or 'sim') ~= 'nao')
        :attr('onclick', "gbSwitch('h',this)")
        :wikitext('Hard ')
        :tag('span'):addClass('gb-badge'):addClass('badge-h')
        :wikitext(hard_equip)


  if not inicioTier or not fimTier then
    -- Painel Normal
     return "Erro: defina 'inicio_tier' e 'fim_tier'."
    local pn = root:tag('div'):addClass('gb-panel'):addClass('active'):attr('id', 'gbpanel-n')
  end
    pn:tag('div'):addClass('gb-title'):wikitext('Requisitos — Normal')
    local ln = pn:tag('ul'):addClass('gb-list')
    ln:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-n'):done()
        :tag('span'):wikitext('Nível mínimo: '):tag('b'):wikitext(normal_nivel)
     ln:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-n'):done()
        :tag('span'):wikitext('Equipamento recomendado: '):tag('b'):wikitext(normal_equip)


  local ti = tierIndex(inicioTier)
    -- Painel Hard
  local tf = tierIndex(fimTier)
    local ph = root:tag('div'):addClass('gb-panel'):attr('id', 'gbpanel-h')
  if not ti or not tf then
    ph:tag('div'):addClass('gb-title'):wikitext('Requisitos — Hard')
     return "Erro: tier inválido. Use: bronze, prata, ouro, diamante."
    local lh = ph:tag('ul'):addClass('gb-list')
  end
    lh:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-h'):done()
        :tag('span'):wikitext('Recomendado utilizar um '):tag('b'):wikitext(hard_personagem)
     lh:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-h'):done()
        :tag('span'):wikitext('Equipamento recomendado: '):tag('b'):wikitext(hard_equip)


  -- Sanitiza limites de estrela (0..5)
    -- Script
  if inicioEst < 0 then inicioEst = 0 end
    local script = mw.html.create('script')
  if inicioEst > 5 then inicioEst = 5 end
    script:wikitext([[
  if fimEst < 0 then fimEst = 0 end
function gbSwitch(tab,btn){
  if fimEst > 5 then fimEst = 5 end
['n','h'].forEach(function(t){document.getElementById('gbpanel-'+t).classList.remove('active');});
document.querySelectorAll('.gb-btn').forEach(function(b){b.classList.remove('active');});
document.getElementById('gbpanel-'+tab).classList.add('active');
btn.classList.add('active');
}]])


  -- Se o tier inicial já é maior que o final, invertido
    -- CSS inline
  if (ti > tf) or (ti == tf and inicioEst > fimEst) then
    local style = mw.html.create('style')
    return "Erro: o alvo precisa ser maior que o estado inicial."
    style:wikitext([[
  end
.gb-wrap{font-family:sans-serif;max-width:600px}
.gb-btns{display:flex;border-bottom:2px solid #a2a9b1;margin-bottom:0}
.gb-btn{padding:8px 22px;font-size:14px;font-weight:bold;color:#54595d;background:transparent;border:none;border-bottom:3px solid transparent;margin-bottom:-2px;cursor:pointer;display:flex;align-items:center;gap:6px}
.gb-btn:hover{color:#202122}
.gb-btn.active{color:#202122;border-bottom-color:#3680b0}
.gb-badge{font-size:11px;padding:2px 8px;border-radius:20px;font-weight:bold}
.badge-n{background:#ddeeff;color:#185FA5}
.badge-h{background:#fce8e8;color:#a32d2d}
.gb-panel{display:none;padding:14px 2px}
.gb-panel.active{display:block}
.gb-title{font-size:11px;font-weight:bold;color:#72777d;text-transform:uppercase;letter-spacing:.06em;margin-bottom:10px}
.gb-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px}
.gb-list li{display:flex;align-items:flex-start;gap:8px;font-size:14px;color:#202122;line-height:1.5}
.gb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;margin-top:5px}
.dot-n{background:#3680b0}
.dot-h{background:#e24b4a}
@media(max-width:480px){.gb-btn{padding:8px 14px;font-size:13px}}]])


  local steps, total = computePath(ti, inicioEst, tf, fimEst)
    return tostring(style) .. tostring(root) .. tostring(script)
  return render(steps, total, { titulo = titulo, mostrarTabela = mostrarTabela })
end
end


return p
return p

Edição atual tal como às 04h47min de 17 de março de 2026

A documentação para este módulo pode ser criada em Módulo:Gb/doc

local p = {}

function p.main(frame)
    local args = frame:getParent().args

    local normal_nivel    = mw.text.trim(args['normal_nivel']    or '140')
    local normal_equip    = mw.text.trim(args['normal_equip']    or 'Set +8')
    local hard_personagem = mw.text.trim(args['hard_personagem'] or 'personagem 4 ou 5 estrelas (Diamante)')
    local hard_equip      = mw.text.trim(args['hard_equip']      or 'Set +16')

    local root = mw.html.create('div')
    root:addClass('gb-wrap')

    -- CSS via TemplateStyles (recomendado) ou inline
    -- Botões (tabs)
    local btns = root:tag('div'):addClass('gb-btns')

    btns:tag('button')
        :addClass('gb-btn'):addClass('active')
        :attr('onclick', "gbSwitch('n',this)")
        :wikitext('Normal ')
        :tag('span'):addClass('gb-badge'):addClass('badge-n')
        :wikitext('Nível ' .. normal_nivel)

    btns:tag('button')
        :addClass('gb-btn')
        :attr('onclick', "gbSwitch('h',this)")
        :wikitext('Hard ')
        :tag('span'):addClass('gb-badge'):addClass('badge-h')
        :wikitext(hard_equip)

    -- Painel Normal
    local pn = root:tag('div'):addClass('gb-panel'):addClass('active'):attr('id', 'gbpanel-n')
    pn:tag('div'):addClass('gb-title'):wikitext('Requisitos — Normal')
    local ln = pn:tag('ul'):addClass('gb-list')
    ln:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-n'):done()
        :tag('span'):wikitext('Nível mínimo: '):tag('b'):wikitext(normal_nivel)
    ln:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-n'):done()
        :tag('span'):wikitext('Equipamento recomendado: '):tag('b'):wikitext(normal_equip)

    -- Painel Hard
    local ph = root:tag('div'):addClass('gb-panel'):attr('id', 'gbpanel-h')
    ph:tag('div'):addClass('gb-title'):wikitext('Requisitos — Hard')
    local lh = ph:tag('ul'):addClass('gb-list')
    lh:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-h'):done()
        :tag('span'):wikitext('Recomendado utilizar um '):tag('b'):wikitext(hard_personagem)
    lh:tag('li')
        :tag('span'):addClass('gb-dot'):addClass('dot-h'):done()
        :tag('span'):wikitext('Equipamento recomendado: '):tag('b'):wikitext(hard_equip)

    -- Script
    local script = mw.html.create('script')
    script:wikitext([[
function gbSwitch(tab,btn){
['n','h'].forEach(function(t){document.getElementById('gbpanel-'+t).classList.remove('active');});
document.querySelectorAll('.gb-btn').forEach(function(b){b.classList.remove('active');});
document.getElementById('gbpanel-'+tab).classList.add('active');
btn.classList.add('active');
}]])

    -- CSS inline
    local style = mw.html.create('style')
    style:wikitext([[
.gb-wrap{font-family:sans-serif;max-width:600px}
.gb-btns{display:flex;border-bottom:2px solid #a2a9b1;margin-bottom:0}
.gb-btn{padding:8px 22px;font-size:14px;font-weight:bold;color:#54595d;background:transparent;border:none;border-bottom:3px solid transparent;margin-bottom:-2px;cursor:pointer;display:flex;align-items:center;gap:6px}
.gb-btn:hover{color:#202122}
.gb-btn.active{color:#202122;border-bottom-color:#3680b0}
.gb-badge{font-size:11px;padding:2px 8px;border-radius:20px;font-weight:bold}
.badge-n{background:#ddeeff;color:#185FA5}
.badge-h{background:#fce8e8;color:#a32d2d}
.gb-panel{display:none;padding:14px 2px}
.gb-panel.active{display:block}
.gb-title{font-size:11px;font-weight:bold;color:#72777d;text-transform:uppercase;letter-spacing:.06em;margin-bottom:10px}
.gb-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px}
.gb-list li{display:flex;align-items:flex-start;gap:8px;font-size:14px;color:#202122;line-height:1.5}
.gb-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;margin-top:5px}
.dot-n{background:#3680b0}
.dot-h{background:#e24b4a}
@media(max-width:480px){.gb-btn{padding:8px 14px;font-size:13px}}]])

    return tostring(style) .. tostring(root) .. tostring(script)
end

return p