Mudanças entre as edições de "Módulo:I.Skills"
Ir para navegação
Ir para pesquisar
m Etiqueta: Revertido |
m Etiqueta: Revertido |
||
| Linha 223: | Linha 223: | ||
subObj.desc_i18n = nil | subObj.desc_i18n = nil | ||
end | end | ||
-- RECURSÃO NATIVA: processa sub-subskills (e sub-sub-subskills, etc.) | -- RECURSÃO NATIVA: processa sub-subskills (e sub-sub-subskills, etc.) | ||
| Linha 424: | Linha 423: | ||
if type(sk.subskills) == "table" and type(sk.suborder) == "table" then | if type(sk.subskills) == "table" and type(sk.suborder) == "table" then | ||
skillObj.subs = processSubskills(sk.subskills, sk.suborder, mainSkillsById, mainSkillsByName, skillObj | skillObj.subs = processSubskills(sk.subskills, sk.suborder, mainSkillsById, mainSkillsByName, skillObj | ||
.id, moduleName) | |||
skillObj.suborder = sk.suborder | skillObj.suborder = sk.suborder | ||
end | end | ||
Edição das 04h39min de 4 de janeiro de 2026
A documentação para este módulo pode ser criada em Módulo:I.Skills/doc
-- Módulo:I.Skills — skill(), skin() com suporte nativo a subskills recursivas
local p = {}
local utils = require("Módulo:I.Utils")
local trim = utils.trim
local colorize = utils.colorize
-- Fallback se colorize não existir
if not colorize or type(colorize) ~= "function" then
colorize = function(txt)
if not txt or txt == "" then
return ""
end
-- Versão simplificada sem colorização
return tostring(txt)
end
end
local cUtils = require("Módulo:C.Utils")
local requireCharModule = cUtils.requireCharModule
-- FASE 2: Normaliza descrição para formato i18n
-- Aceita desc (table com pt/en/es/pl) ou campos legados (descPt, descEn, etc)
-- Sempre retorna desc_i18n no formato { pt: "...", en: "...", ... }
local function normalizeDesc(desc, descPt, descEn, descEs, descPl)
local desc_i18n = {}
-- Se desc é uma table, processa diretamente
if desc and type(desc) == "table" then
for code, text in pairs(desc) do
if type(text) == "string" and text ~= "" then
desc_i18n[code] = colorize(text)
end
end
elseif type(desc) == "string" and desc ~= "" then
-- Se desc é string, assume português
desc_i18n.pt = colorize(desc)
end
-- Processa campos legados (descPt, descEn, etc) se existirem
if descPt and type(descPt) == "string" and descPt ~= "" then
desc_i18n.pt = colorize(descPt)
end
if descEn and type(descEn) == "string" and descEn ~= "" then
desc_i18n.en = colorize(descEn)
end
if descEs and type(descEs) == "string" and descEs ~= "" then
desc_i18n.es = colorize(descEs)
end
if descPl and type(descPl) == "string" and descPl ~= "" then
desc_i18n.pl = colorize(descPl)
end
return next(desc_i18n) and desc_i18n or nil
end
-- Processa descrição (desc table → desc_i18n)
-- Mantido para compatibilidade, agora usa normalizeDesc internamente
local function processDesc(desc)
if not desc then return nil end
return normalizeDesc(desc)
end
-- Processa weapon (aplica colorize nas descrições)
local function processWeapon(weapon)
if not weapon or type(weapon) ~= "table" then
return weapon
end
local processed = {}
-- Copia todos os campos do weapon
for k, v in pairs(weapon) do
processed[k] = v
end
-- FASE 2: Processa descrição do weapon usando normalizeDesc (normaliza campos legados)
if weapon.desc or weapon.descPt or weapon.descEn or weapon.descEs or weapon.descPl then
processed.desc_i18n = normalizeDesc(weapon.desc, weapon.descPt, weapon.descEn, weapon.descEs, weapon.descPl)
-- Remove campos legados se desc_i18n foi criado (para evitar duplicação)
if processed.desc_i18n then
processed.desc = nil
processed.descPt = nil
processed.descEn = nil
processed.descEs = nil
processed.descPl = nil
end
end
-- Se o weapon processado estiver vazio (sem campos), retorna nil
-- Isso evita que weapons vazios {} sejam considerados válidos
if next(processed) == nil then
return nil
end
return processed
end
-- Processa subskills recursivamente (suporte ilimitado a níveis)
-- parentSkillsById: mapa de skills principais por ID (moduleName.skillName)
-- parentSkillsByName: mapa de skills principais por nome (compatibilidade)
-- parentPath: caminho hierárquico para gerar IDs únicos (ex: "skill1.subskill2")
-- moduleName: nome do módulo para gerar IDs únicos
local function processSubskills(subskills, suborder, parentSkillsById, parentSkillsByName, parentPath, moduleName)
if not subskills or not suborder or type(subskills) ~= "table" or type(suborder) ~= "table" then
return nil
end
local arr = {}
for idx, subName in ipairs(suborder) do
local sub = subskills[subName]
if type(sub) == "table" then
-- Gera ID único baseado no caminho hierárquico
-- Se parentPath existe, usa "parentPath.subName", senão usa apenas "subName"
-- Adiciona índice para garantir unicidade mesmo com nomes duplicados
local uniqueId = parentPath and (parentPath .. "." .. subName .. "." .. tostring(idx)) or
(subName .. "." .. tostring(idx))
-- FASE 1: Herança explícita com suporte a ID
-- inherit_from_id: ID da skill para herdar (prioridade)
-- inherit_from: Nome da skill para herdar (fallback legado)
-- inherit_fields: O QUE herdar (array de campos, obrigatório para herdar)
-- Se não especificar ambos, não herda nada (mais seguro)
local inheritFromId = sub.inherit_from_id -- ID da skill (prioridade)
local inheritFrom = sub.inherit_from -- Nome da skill (fallback legado)
local inheritFields = sub.inherit_fields or {} -- O QUE herdar (array)
-- Converte inheritFields para set para busca rápida
local inheritFieldsSet = {}
if type(inheritFields) == "table" then
for _, field in ipairs(inheritFields) do
if type(field) == "string" then
inheritFieldsSet[field] = true
end
end
end
-- FASE 1: Busca skill principal por ID primeiro, depois por nome (fallback)
local parentSkill = nil
if inheritFromId and parentSkillsById and type(parentSkillsById) == "table" then
parentSkill = parentSkillsById[inheritFromId]
end
-- Fallback legado: busca por nome
if not parentSkill and inheritFrom and parentSkillsByName and type(parentSkillsByName) == "table" then
parentSkill = parentSkillsByName[inheritFrom]
end
-- Função auxiliar: verifica se um campo DEVE ser herdado
-- Só herda se inherit_from E inherit_fields estiverem definidos E o campo estiver na lista
local function shouldInheritField(fieldName)
if not inheritFrom or not parentSkill then
return false -- Sem inherit_from ou parentSkill, não herda
end
return inheritFieldsSet[fieldName] == true -- Só herda se estiver em inherit_fields
end
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
-- Flags herdam apenas se "flags" estiver em inherit_fields
local subFlags = (sub.flags ~= nil) and sub.flags or
(shouldInheritField("flags") and parentSkill and parentSkill.flags)
local validSubFlags = (type(subFlags) == "table" and #subFlags > 0) and subFlags or nil
-- Cria o objeto da subskill, herdando apenas campos explicitamente listados em inherit_fields
local subObj = {
id = uniqueId, -- ID único para evitar colisão de nomes
display_name = subName, -- Nome para exibição (sem função lógica)
name = subName, -- Mantido para compatibilidade
n = subName, -- Mantido para compatibilidade
-- Herda icon apenas se "icon" estiver em inherit_fields
icon = sub.icon or (shouldInheritField("icon") and parentSkill and parentSkill.icon) or "",
-- Herda level apenas se "level" estiver em inherit_fields
level = sub.level or (shouldInheritField("level") and parentSkill and parentSkill.level) or "",
-- Herda energy apenas se "energy" estiver em inherit_fields
energy = (sub.energy ~= nil) and sub.energy or
(shouldInheritField("energy") and parentSkill and parentSkill.energy),
-- Herda powerpve apenas se "powerpve" estiver em inherit_fields
powerpve = (sub.powerpve ~= nil) and sub.powerpve or
(shouldInheritField("powerpve") and parentSkill and parentSkill.powerpve),
-- Herda powerpvp apenas se "powerpvp" estiver em inherit_fields
powerpvp = (sub.powerpvp ~= nil) and sub.powerpvp or
(shouldInheritField("powerpvp") and parentSkill and parentSkill.powerpvp),
-- Herda cooldown apenas se "cooldown" estiver em inherit_fields
cooldown = (sub.cooldown ~= nil) and sub.cooldown or
(shouldInheritField("cooldown") and parentSkill and parentSkill.cooldown),
-- Video sempre vem da subskill (nunca herda)
video = sub.video or "",
-- Descrição: será processada depois, herda apenas se "desc" estiver em inherit_fields
desc_i18n = nil, -- Será definido depois
-- Flags: herda apenas se "flags" estiver em inherit_fields
flags = validSubFlags,
-- Herda weapon apenas se "weapon" estiver em inherit_fields
weapon = (sub.weapon and processWeapon(sub.weapon)) or
(shouldInheritField("weapon") and parentSkill and processWeapon(parentSkill.weapon)),
-- Herda back apenas se "back" estiver em inherit_fields
back = (sub.back ~= nil) and sub.back or
(shouldInheritField("back") and parentSkill and parentSkill.back),
-- Inclui campos de herança para o frontend
inherit_from_id = inheritFromId or inheritFrom, -- ID ou nome (compatibilidade)
inherit_from = inheritFrom, -- Mantido para compatibilidade
inherit_fields = inheritFields
}
-- FASE 2: Processa descrição usando normalizeDesc (normaliza campos legados)
-- Herda apenas se "desc" estiver em inherit_fields
-- PROTEÇÃO TOTAL: Se "desc" NÃO está em inherit_fields, desc_i18n NUNCA herda
-- PRIORIDADE: Sempre processa descrição da subskill se existir (mesmo que "desc" esteja em inherit_fields)
if sub.desc ~= nil or sub.descPt ~= nil or sub.descEn ~= nil or sub.descEs ~= nil or sub.descPl ~= nil then
-- Sempre processa descrição da subskill se existir (prioridade máxima)
-- Normaliza campos legados (descPt, descEn, etc) para desc_i18n
subObj.desc_i18n = normalizeDesc(sub.desc, sub.descPt, sub.descEn, sub.descEs, sub.descPl)
elseif shouldInheritField("desc") and parentSkill then
-- Herda descrição apenas se "desc" estiver em inherit_fields
-- Normaliza campos legados do parentSkill também
-- Se parentSkill já tem desc_i18n processado, usa diretamente; senão normaliza
if parentSkill.desc_i18n then
subObj.desc_i18n = parentSkill.desc_i18n
else
subObj.desc_i18n = normalizeDesc(parentSkill.desc, parentSkill.descPt, parentSkill.descEn,
parentSkill.descEs, parentSkill.descPl)
end
else
-- PROTEÇÃO: Se não tem desc na subskill e "desc" NÃO está em inherit_fields, desc_i18n é nil
-- GARANTE que não há herança quando "desc" não está em inherit_fields
subObj.desc_i18n = nil
end
-- RECURSÃO NATIVA: processa sub-subskills (e sub-sub-subskills, etc.)
-- Passa parentSkillsById e parentSkillsByName para recursão (herança sempre vem das skills principais)
-- Passa uniqueId como parentPath para manter unicidade na hierarquia
if type(sub.subskills) == "table" and type(sub.suborder) == "table" then
subObj.subs = processSubskills(sub.subskills, sub.suborder, parentSkillsById, parentSkillsByName,
uniqueId, moduleName)
subObj.suborder = sub.suborder
end
table.insert(arr, subObj)
end
end
return #arr > 0 and arr or nil
end
-- Gera JSON de skills a partir do módulo
function p.skill(frame)
local parent = frame:getParent() or frame
local args = parent.args or {}
local moduleName = trim(args.module or "")
if moduleName == "" then
return "[]"
end
local data = requireCharModule(moduleName) or {}
if not data.order or not data.skills then
return "[]"
end
local skillsArr = {}
-- Se houver forms, obtém a primeira forma disponível (genérico)
local firstForm = nil
local firstFormName = nil
if type(data.forms) == "table" then
-- Pega a primeira forma disponível (ordem não garantida em pairs, mas pega a primeira válida)
for formName, formData in pairs(data.forms) do
if type(formData) == "table" and type(formData.skills) == "table" and type(formData.order) == "table" then
firstForm = formData
firstFormName = formName
break
end
end
end
-- Encontra a skill com form_switch = true (genérico)
local formSwitchSkillName = nil
local nextFixedSkillAfterFormSwitch = nil
if type(data.skills) == "table" then
for skillName, sk in pairs(data.skills) do
if type(sk) == "table" and sk.form_switch == true then
formSwitchSkillName = skillName
break
end
end
-- Encontra a próxima skill fixa depois do form_switch no order
if formSwitchSkillName and type(data.order) == "table" then
local foundFormSwitch = false
for _, skillName in ipairs(data.order) do
if foundFormSwitch then
-- Esta é a próxima skill fixa depois do form_switch
nextFixedSkillAfterFormSwitch = skillName
break
end
if skillName == formSwitchSkillName then
foundFormSwitch = true
end
end
end
end
-- Se houver forms, insere a primeira skill da forma ANTES da skill com form_switch
if firstForm and type(firstForm.skills) == "table" and type(firstForm.order) == "table" and #firstForm.order > 0 then
local firstSkillName = firstForm.order[1]
local formSk = firstForm.skills[firstSkillName]
if type(formSk) == "table" then
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
local formFlags = nil
if type(formSk.flags) == "table" and #formSk.flags > 0 then
formFlags = formSk.flags
end
local formSkillObj = {
id = "form." .. firstSkillName, -- ID único para skills de forma
display_name = firstSkillName, -- Nome para exibição
name = firstSkillName, -- Mantido para compatibilidade
n = firstSkillName, -- Mantido para compatibilidade
icon = (formSk.icon and formSk.icon ~= "") and formSk.icon or "Nada.png",
level = formSk.level or "NIVEL",
energy = formSk.energy,
powerpve = formSk.powerpve,
powerpvp = formSk.powerpvp,
cooldown = formSk.cooldown,
video = formSk.video or "",
desc_i18n = normalizeDesc(formSk.desc, formSk.descPt, formSk.descEn, formSk.descEs, formSk.descPl),
flags = formFlags,
weapon = processWeapon(formSk.weapon)
}
if type(formSk.subskills) == "table" and type(formSk.suborder) == "table" then
-- Para skills de forma, usa data.skills como fallback (ainda não processadas)
-- Isso será corrigido quando as skills principais forem processadas
local formSkillsById = {}
local formSkillsByName = {}
for sn, s in pairs(data.skills) do
if type(s) == "table" then
formSkillsById["form." .. sn] = s
formSkillsByName[sn] = s
end
end
formSkillObj.subs = processSubskills(formSk.subskills, formSk.suborder, formSkillsById, formSkillsByName,
formSkillObj.id, "form")
formSkillObj.suborder = formSk.suborder
end
table.insert(skillsArr, formSkillObj)
end
end
-- FASE 1: Cria mapa de IDs das skills principais para lookup por ID
-- Este mapa será populado DEPOIS que as skills forem processadas
local mainSkillsById = {}
local mainSkillsByName = {}
-- Itera sobre order para manter ordem correta (skills fixas)
local nextFixedSkillIndex = -1
for idx, skillName in ipairs(data.order) do
local sk = data.skills[skillName]
if type(sk) == "table" then
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
-- Proteção extra: verifica se flags é uma tabela válida e serializável
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
-- Simplificado: se é uma tabela válida com strings, inclui diretamente
local validFlags = nil
if type(sk.flags) == "table" and #sk.flags > 0 then
-- Verifica se todos os elementos são strings válidas
local allValid = true
for i, flag in ipairs(sk.flags) do
if type(flag) ~= "string" or flag == "" then
allValid = false
break
end
end
if allValid then
validFlags = sk.flags
else
-- Se houver elementos inválidos, cria uma cópia limpa
local cleanFlags = {}
for i, flag in ipairs(sk.flags) do
if type(flag) == "string" and flag ~= "" then
table.insert(cleanFlags, flag)
end
end
if #cleanFlags > 0 then
validFlags = cleanFlags
end
end
end
-- FASE 1: ID único obrigatório para skills principais
-- Usa moduleName como prefixo para garantir unicidade global
local skillId = moduleName .. "." .. skillName
local skillObj = {
id = skillId, -- ID único global (moduleName.skillName)
display_name = skillName, -- Nome para exibição (sem função lógica)
name = skillName, -- Mantido para compatibilidade
n = skillName, -- Mantido para compatibilidade
icon = (sk.icon and sk.icon ~= "") and sk.icon or "Nada.png",
level = sk.level or "NIVEL",
energy = sk.energy,
powerpve = sk.powerpve,
powerpvp = sk.powerpvp,
cooldown = sk.cooldown,
video = sk.video or "",
desc_i18n = normalizeDesc(sk.desc, sk.descPt, sk.descEn, sk.descEs, sk.descPl),
flags = validFlags,
weapon = processWeapon(sk.weapon),
weaponicon = data.weaponicon,
form_switch = sk.form_switch,
form_videos = sk.form_videos -- Vídeos específicos para transições de forma
}
-- Valida flags antes de inserir no array (proteção extra)
if skillObj.flags and (type(skillObj.flags) ~= "table" or #skillObj.flags == 0) then
skillObj.flags = nil
end
-- FASE 1: Popula mapa de IDs com skill processada ANTES de processar subskills
-- Isso garante que as subskills possam herdar dos objetos processados (com desc_i18n)
mainSkillsById[skillId] = skillObj
mainSkillsByName[skillName] = skillObj
-- Processa subskills recursivamente (suporte nativo ilimitado)
-- Passa mainSkillsById e mainSkillsByName para lookup por ID ou nome
-- Passa skillObj.id como parentPath para gerar IDs únicos para subskills
if type(sk.subskills) == "table" and type(sk.suborder) == "table" then
skillObj.subs = processSubskills(sk.subskills, sk.suborder, mainSkillsById, mainSkillsByName, skillObj
.id, moduleName)
skillObj.suborder = sk.suborder
end
table.insert(skillsArr, skillObj)
-- Se for a skill com form_switch e houver forms, adiciona a terceira skill da forma logo após
if skillName == formSwitchSkillName and firstForm and type(firstForm.skills) == "table" and type(firstForm.order) == "table" and #firstForm.order >= 2 then
local thirdSkillName = firstForm.order[2] -- Segunda na ordem = terceira skill (1, 2, 3)
local formSk = firstForm.skills[thirdSkillName]
if type(formSk) == "table" then
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
local formFlags3 = nil
if type(formSk.flags) == "table" and #formSk.flags > 0 then
formFlags3 = formSk.flags
end
local formSkillObj = {
id = "form." .. thirdSkillName, -- ID único para skills de forma
display_name = thirdSkillName, -- Nome para exibição
name = thirdSkillName, -- Mantido para compatibilidade
n = thirdSkillName, -- Mantido para compatibilidade
icon = (formSk.icon and formSk.icon ~= "") and formSk.icon or "Nada.png",
level = formSk.level or "NIVEL",
energy = formSk.energy,
powerpve = formSk.powerpve,
powerpvp = formSk.powerpvp,
cooldown = formSk.cooldown,
video = formSk.video or "",
desc_i18n = normalizeDesc(formSk.desc, formSk.descPt, formSk.descEn, formSk.descEs, formSk
.descPl),
flags = formFlags3,
weapon = processWeapon(formSk.weapon)
}
if type(formSk.subskills) == "table" and type(formSk.suborder) == "table" then
formSkillObj.subs = processSubskills(formSk.subskills, formSk.suborder, mainSkillsById,
mainSkillsByName, formSkillObj.id, "form")
formSkillObj.suborder = formSk.suborder
end
table.insert(skillsArr, formSkillObj)
end
end
-- Guarda índice da próxima skill fixa depois do form_switch para inserir a quinta skill depois
if skillName == nextFixedSkillAfterFormSwitch then
nextFixedSkillIndex = #skillsArr
end
-- Se for a próxima skill fixa depois do form_switch e houver forms, adiciona a quinta skill da forma logo após
if skillName == nextFixedSkillAfterFormSwitch and firstForm and type(firstForm.skills) == "table" and type(firstForm.order) == "table" and #firstForm.order >= 3 then
local fifthSkillName = firstForm.order[3] -- Terceira na ordem = quinta skill (1, 2, 3)
local formSk = firstForm.skills[fifthSkillName]
if type(formSk) == "table" then
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
local formFlags5 = nil
if type(formSk.flags) == "table" and #formSk.flags > 0 then
formFlags5 = formSk.flags
end
local formSkillObj = {
id = "form." .. fifthSkillName, -- ID único para skills de forma
display_name = fifthSkillName, -- Nome para exibição
name = fifthSkillName, -- Mantido para compatibilidade
n = fifthSkillName, -- Mantido para compatibilidade
icon = (formSk.icon and formSk.icon ~= "") and formSk.icon or "Nada.png",
level = formSk.level or "NIVEL",
energy = formSk.energy,
powerpve = formSk.powerpve,
powerpvp = formSk.powerpvp,
cooldown = formSk.cooldown,
video = formSk.video or "",
desc_i18n = normalizeDesc(formSk.desc, formSk.descPt, formSk.descEn, formSk.descEs, formSk
.descPl),
flags = formFlags5,
weapon = processWeapon(formSk.weapon)
}
if type(formSk.subskills) == "table" and type(formSk.suborder) == "table" then
formSkillObj.subs = processSubskills(formSk.subskills, formSk.suborder, mainSkillsById,
mainSkillsByName, formSkillObj.id, "form")
formSkillObj.suborder = formSk.suborder
end
table.insert(skillsArr, formSkillObj)
end
end
end
end
-- Proteção contra erros no jsonEncode (especialmente para flags)
-- Limpa flags problemáticas ANTES de tentar serializar
-- NOTA: Não remove flags válidas, apenas valida e limpa flags inválidas
for _, skill in ipairs(skillsArr) do
if skill.flags then
if type(skill.flags) ~= "table" or #skill.flags == 0 then
skill.flags = nil
else
-- Limpa flags inválidas (não strings ou vazias)
local cleanFlags = {}
for i, flag in ipairs(skill.flags) do
if type(flag) == "string" and flag ~= "" then
table.insert(cleanFlags, flag)
end
end
if #cleanFlags > 0 then
skill.flags = cleanFlags
else
skill.flags = nil
end
end
end
-- Limpa flags em subskills também
if skill.subs and type(skill.subs) == "table" then
for _, sub in ipairs(skill.subs) do
if sub.flags then
if type(sub.flags) ~= "table" or #sub.flags == 0 then
sub.flags = nil
else
local cleanSubFlags = {}
for i, flag in ipairs(sub.flags) do
if type(flag) == "string" and flag ~= "" then
table.insert(cleanSubFlags, flag)
end
end
if #cleanSubFlags > 0 then
sub.flags = cleanSubFlags
else
sub.flags = nil
end
end
end
end
end
end
local ok, jsonResult = pcall(function()
return mw.text.jsonEncode(skillsArr)
end)
if ok and jsonResult then
return jsonResult
else
-- Última tentativa: remove TODAS as flags
for _, skill in ipairs(skillsArr) do
skill.flags = nil
if skill.subs and type(skill.subs) == "table" then
for _, sub in ipairs(skill.subs) do
sub.flags = nil
end
end
end
return mw.text.jsonEncode(skillsArr)
end
end
-- Gera JSON de forms a partir do módulo
function p.forms(frame)
local parent = frame:getParent() or frame
local args = parent.args or {}
local moduleName = trim(args.module or "")
if moduleName == "" then
return "{}"
end
local data = requireCharModule(moduleName) or {}
if not data.forms or type(data.forms) ~= "table" then
return "{}"
end
local formsData = {}
for formName, formData in pairs(data.forms) do
if type(formData) == "table" and type(formData.skills) == "table" and type(formData.order) == "table" then
local formSkills = {}
for _, skillName in ipairs(formData.order) do
local sk = formData.skills[skillName]
if type(sk) == "table" then
-- Valida flags: deve ser uma tabela com pelo menos um elemento, senão nil
local formSkillFlags = nil
if type(sk.flags) == "table" and #sk.flags > 0 then
formSkillFlags = sk.flags
end
local skillObj = {
name = skillName,
n = skillName,
icon = (sk.icon and sk.icon ~= "") and sk.icon or "Nada.png",
level = sk.level or "NIVEL",
energy = sk.energy,
powerpve = sk.powerpve,
powerpvp = sk.powerpvp,
cooldown = sk.cooldown,
video = sk.video or "",
desc_i18n = normalizeDesc(sk.desc, sk.descPt, sk.descEn, sk.descEs, sk.descPl),
flags = formSkillFlags,
weapon = processWeapon(sk.weapon)
}
-- Processa subskills se houver
-- Passa data.skills para herança automática quando subskill tem mesmo nome que skill principal
if type(sk.subskills) == "table" and type(sk.suborder) == "table" then
skillObj.subs = processSubskills(sk.subskills, sk.suborder, data.skills)
skillObj.suborder = sk.suborder
end
table.insert(formSkills, skillObj)
end
end
formsData[formName] = {
order = formData.order,
skills = formSkills
}
end
end
return mw.text.jsonEncode(formsData)
end
-- Gera JSON de skins a partir do módulo
function p.skin(frame)
local parent = frame:getParent() or frame
local args = parent.args or {}
local moduleName = trim(args.module or "")
if moduleName == "" then
return "[]"
end
local data = requireCharModule(moduleName) or {}
if not data.skins or type(data.skins) ~= "table" then
return "[]"
end
-- Processa skins do módulo
local skinsArr = {}
for _, skin in ipairs(data.skins) do
if type(skin) == "table" then
local skinObj = {
name = skin.name or "",
sprite = skin.sprite or "",
tooltip = skin.tooltip or "",
offset_x = skin.offset_x,
tile = skin.tile or "",
tile_x = skin.tile_x,
tile_y = skin.tile_y,
youtube = skin.youtube
}
-- Se tooltip é table, converte para JSON string
if type(skin.tooltip) == "table" then
skinObj.tooltip = mw.text.jsonEncode(skin.tooltip)
end
table.insert(skinsArr, skinObj)
end
end
return mw.text.jsonEncode(skinsArr)
end
return p