Mudanças entre as edições de "Módulo:Item"
Ir para navegação
Ir para pesquisar
m |
m |
||
| Linha 171: | Linha 171: | ||
--[[ | --[[ | ||
Tooltip codificada: corpo vazio no HTML + data-tip ( | Tooltip codificada: corpo vazio no HTML + data-tip (base64 UTF-8). | ||
Widget:Item decodifica no hover e limpa no mouseout. | Widget:Item decodifica no hover e limpa no mouseout. | ||
]] | ]] | ||
local | local function base64_encode(data) | ||
local b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" | |||
local | return ((data:gsub(".", function(x) | ||
local r, byte = "", x:byte() | |||
return | for i = 8, 1, -1 do | ||
r = r .. (byte % 2 ^ i - byte % 2 ^ (i - 1) > 0 and "1" or "0") | |||
end | |||
return r | |||
end) .. "0000"):gsub("%d%d%d?%d?%d?%d?", function(x) | |||
if #x < 6 then return "" end | |||
local c = 0 | |||
for i = 1, 6 do | |||
c = c + (x:sub(i, i) == "1" and 2 ^ (6 - i) or 0) | |||
end | |||
return b:sub(c + 1, c + 1) | |||
end) .. ({ "", "==", "=" })[#data % 3 + 1]) | |||
end | end | ||
local function encodePayload(obj) | local function encodePayload(obj) | ||
local json = mw.text.jsonEncode(obj) | local json = mw.text.jsonEncode(obj) | ||
return "b64:" .. base64_encode(json) | |||
end | end | ||
Edição das 22h01min de 28 de maio de 2026
A documentação para este módulo pode ser criada em Módulo:Item/doc
local Item = {}
local ItemDB = require("Módulo:ItemDB")
local DEFAULT_LANG = "pt-br"
local FALLBACK_LANG = "en"
local DEFAULT_FRAME_SIZE = 32
-- Categorias alinhadas ao jogo (ItemDB / editor). Sem duplicata coin/currency nem gem_currency.
local CATEGORY_LABELS = {
general_item = { en = "General Item", pt = "Item geral" },
special_item = { en = "Special Item", pt = "Item especial" },
mission_item = { en = "Mission Item", pt = "Item de Missão" },
currency = { en = "Currency", pt = "Moeda" },
cosmetic = { en = "Cosmetic", pt = "Cosmético" },
weapon = { en = "Weapon", pt = "Arma" },
head = { en = "Head", pt = "Cabeça" },
body = { en = "Body", pt = "Corpo" },
legs = { en = "Legs", pt = "Perna" },
accessory = { en = "Accessory", pt = "Acessório" },
emblem = { en = "Emblem", pt = "Emblema" },
ship_style = { en = "Ship Style", pt = "Estilo de navio" },
costume = { en = "Costume", pt = "Traje" },
navigation = { en = "Navigation", pt = "Navegação" },
consumable = { en = "Consumable", pt = "Consumível" },
gem = { en = "Gem", pt = "Gema" },
crystal = { en = "Crystal", pt = "Cristal" },
awakening_stone = { en = "Awakening Stone", pt = "Pedra do Despertar" },
headstone = { en = "Headstone", pt = "Lápide" },
den_den_mushi = { en = "Den Den Mushi", pt = "Den Den Mushi" },
}
local function normalizeLang(lang)
local lg = mw.ustring.lower(mw.text.trim(tostring(lang or DEFAULT_LANG)))
lg = lg:gsub("_", "-")
if lg == "" then return "pt" end
if lg == "pt" or lg == "pt-br" then return "pt" end
if lg == "en" or lg == "en-us" or lg == "en-gb" then return "en" end
return lg
end
local function formatDots(n)
local s = tostring(n)
local pos = #s % 3
if pos == 0 then pos = 3 end
local parts = { s:sub(1, pos) }
for i = pos + 1, #s, 3 do
parts[#parts + 1] = s:sub(i, i + 2)
end
return table.concat(parts, ".")
end
local function normalizeForMatch(s)
if not s then return "" end
return mw.ustring.lower(mw.text.trim(tostring(s)))
end
local function isBerriesItem(item)
if not item then return false end
local image = normalizeForMatch(item.image)
if image ~= "" and image:find("berr", 1, true) then
return true
end
local namePt = item.names and normalizeForMatch(item.names.pt) or ""
local nameEn = item.names and normalizeForMatch(item.names.en) or ""
if namePt:find("berr", 1, true) or nameEn:find("berr", 1, true) then
return true
end
if item.aliases and type(item.aliases) == "table" then
for _, alias in ipairs(item.aliases) do
local norm = normalizeForMatch(alias)
if norm:find("berr", 1, true) then
return true
end
end
end
return item.category == "currency"
end
function Item.resolve(query)
if not query or query == "" then return nil end
return ItemDB.get(query)
end
function Item.getName(item, lang)
if not item or not item.names then return "" end
lang = normalizeLang(lang)
return item.names[lang]
or item.names[FALLBACK_LANG]
or item.names.pt
or item.image or ""
end
function Item.getDesc(item, lang)
if not item or not item.desc then return nil end
lang = normalizeLang(lang)
return item.desc[lang]
or item.desc[FALLBACK_LANG]
or item.desc.pt
end
function Item.getValue(item)
if not item then return nil end
return item.value
end
function Item.getLevel(item)
if not item then return nil end
return item.level
end
function Item.getImage(item)
if not item then return nil end
return item.image
end
function Item.getSpriteSize(item)
if item and item.sprite then
return item.sprite.frameWidth or DEFAULT_FRAME_SIZE,
item.sprite.frameHeight or DEFAULT_FRAME_SIZE
end
return DEFAULT_FRAME_SIZE, DEFAULT_FRAME_SIZE
end
function Item.getCategoryLabel(item, lang)
if not item or not item.category then return nil end
local entry = CATEGORY_LABELS[item.category]
if not entry then return nil end
lang = normalizeLang(lang)
return entry[lang] or entry[FALLBACK_LANG] or entry.pt or nil
end
local function getPassiveLine(item, key, lang)
if not item or not item[key] or type(item[key]) ~= "table" then return nil end
local p = item[key]
lang = normalizeLang(lang)
local function pick(lg)
local t = p[lg]
if t and mw.text.trim(tostring(t)) ~= "" then return mw.text.trim(tostring(t)) end
return nil
end
return pick(lang) or pick(DEFAULT_LANG) or pick(FALLBACK_LANG)
end
--[[
Tooltip codificada (data-tip). Widget:Item decodifica no hover.
]]
local function shouldShowPassiveBlock(item, passive1, passive2)
if not (passive1 or passive2) then
return false
end
local f = item and item.equipment_special
if f == false then
return false
end
if f == true or f == 1 then
return true
end
if type(f) == "string" then
local s = mw.ustring.lower(mw.text.trim(f))
if s == "true" or s == "1" then
return true
end
end
-- flag ausente (nil): ainda há texto de passiva → mostrar
return f == nil
end
--[[
Tooltip codificada: corpo vazio no HTML + data-tip (base64 UTF-8).
Widget:Item decodifica no hover e limpa no mouseout.
]]
local function base64_encode(data)
local b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
return ((data:gsub(".", function(x)
local r, byte = "", x:byte()
for i = 8, 1, -1 do
r = r .. (byte % 2 ^ i - byte % 2 ^ (i - 1) > 0 and "1" or "0")
end
return r
end) .. "0000"):gsub("%d%d%d?%d?%d?%d?", function(x)
if #x < 6 then return "" end
local c = 0
for i = 1, 6 do
c = c + (x:sub(i, i) == "1" and 2 ^ (6 - i) or 0)
end
return b:sub(c + 1, c + 1)
end) .. ({ "", "==", "=" })[#data % 3 + 1])
end
local function encodePayload(obj)
local json = mw.text.jsonEncode(obj)
return "b64:" .. base64_encode(json)
end
local function buildTooltipPayload(item, lang)
lang = normalizeLang(lang)
local nome = Item.getName(item, lang)
local desc = Item.getDesc(item, lang)
local catLabel = Item.getCategoryLabel(item, lang)
local value = Item.getValue(item)
local level = Item.getLevel(item)
local passive1 = getPassiveLine(item, "passive1", lang)
local passive2 = getPassiveLine(item, "passive2", lang)
local showPassives = shouldShowPassiveBlock(item, passive1, passive2)
local payload = {
n = nome or "",
c = catLabel or "",
sp = showPassives and 1 or 0,
}
if level then
payload.lv = (lang == "pt") and ("Nível: " .. tostring(level))
or ("Level: " .. tostring(level))
end
if showPassives then
if passive1 then payload.p1 = passive1 end
if passive2 then payload.p2 = passive2 end
elseif desc then
payload.d = desc
end
if value then
payload.v = "$" .. formatDots(value)
end
return payload
end
function Item.renderTooltip(item, lang)
if not item then return "" end
local encoded = encodePayload(buildTooltipPayload(item, lang))
local tip = mw.html.create("div")
:addClass("item-tooltip")
:addClass("item-tooltip-enc")
:attr("data-tip", encoded)
tip:tag("div"):addClass("item-tooltip-body")
tip:tag("div"):addClass("item-tooltip-arrow")
return tostring(tip)
end
function Item.tooltip(frame)
-- Via API parse (#invoke direto): parâmetros em frame.args
-- Via predefinição pai: parâmetros em getParent().args
local direct = frame.args or {}
local parent = frame:getParent().args or {}
local key = mw.text.trim(direct.key or direct[1] or parent.key or parent[1] or "")
local lang = direct.lang or parent.lang or DEFAULT_LANG
if key == "" then return "" end
local item = Item.resolve(key)
if not item then return "" end
return Item.renderTooltip(item, lang)
end
function Item.renderOne(item, qty, lang, options)
options = options or {}
lang = normalizeLang(lang)
if not item then return "" end
local image = Item.getImage(item)
local w, h = Item.getSpriteSize(item)
local wrapper = mw.html.create("div")
:addClass("item-wrapper")
:css("width", w .. "px")
:css("height", h .. "px")
if image and mw.text.trim(image) ~= "" then
wrapper:tag("span")
:wikitext(string.format("[[Arquivo:%s|%dx%dpx|link=]]", image, w, h))
else
wrapper:tag("span")
:addClass("item-icon-placeholder")
:wikitext("")
end
if qty and options.showCount ~= false then
local countSpan = wrapper:tag("span"):addClass("item-count")
local isBerries = isBerriesItem(item)
if not isBerries then
countSpan:tag("span"):addClass("item-count-x"):wikitext("x")
end
countSpan:wikitext(tostring(qty))
end
if options.showTooltip ~= false then
wrapper:wikitext(Item.renderTooltip(item, lang))
end
return tostring(wrapper)
end
function Item.renderLine(itemList, lang, options)
options = options or {}
lang = normalizeLang(lang)
if not itemList or #itemList == 0 then return "" end
local container = mw.html.create("div")
:addClass("reward-items")
for _, entry in ipairs(itemList) do
container:wikitext(Item.renderOne(entry.item, entry.qty, lang, options))
end
return tostring(container)
end
return Item