Modul:HeroCard: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| Zeile 102: | Zeile 102: | ||
end | end | ||
-- Awakening-Desc | -- Awakening-Desc: NUR englische Keys (wie in HeroData) | ||
local function awakeningDesc(raw_value, override) | local function awakeningDesc(raw_value, override) | ||
if not isempty(override) then return override end | if not isempty(override) then return override end | ||
| Zeile 185: | Zeile 185: | ||
local content = table.concat(panels, "\n|-|\n") | local content = table.concat(panels, "\n|-|\n") | ||
return frame:extensionTag('tabber', content) | return frame:extensionTag('tabber', content) | ||
end | |||
-- ===== Profile-Auswahl aus HeroConfig ===== | |||
local function pickProfile(cfg, entity) | |||
local profiles = cfg.profiles or {} | |||
local base = profiles.default or {} | |||
local key = "default" | |||
if entity == "guardian" then key = "guardian" | |||
elseif entity == "wm" then key = "wm" | |||
-- mercenary/god → default | |||
end | |||
local over = profiles[key] or {} | |||
local P = {} | |||
P.main_order = over.main_order or base.main_order or {} | |||
P.main_meta = over.main_meta or base.main_meta or {} | |||
P.adv_order = over.adv_order or base.adv_order or {} | |||
P.adv_meta = over.adv_meta or base.adv_meta or {} | |||
-- Guardian: Chaos-Rift | |||
P.tabs = (over.tabs or {}) | |||
P.chaos_main_order = over.chaos_main_order or {} | |||
P.chaos_main_meta = over.chaos_main_meta or {} | |||
P.chaos_adv_order = over.chaos_adv_order or {} | |||
P.chaos_adv_meta = over.chaos_adv_meta or {} | |||
return P | |||
end | |||
-- ===== Hilfsrenderer für das 3er-Grid ===== | |||
local function render_grid(opts) | |||
local profile, data, args, L, showLabels, isWM = opts.profile, opts.data, opts.args, opts.L, opts.showLabels, opts.isWM | |||
local mode = opts.mode or "default" -- "default" | "chaos" | |||
local grid = mw.html.create("div"):addClass("kr-g3") | |||
-- -------- Spalte 1: Hauptattribute -------- | |||
do | |||
local col = grid:tag("div"):addClass("kr-quad") | |||
col:tag("h3"):addClass("kr-hc-h"):wikitext("Hauptattribute") | |||
local mains = col:tag("div"):addClass("kr-hc-main-attrs") | |||
local src = (mode=="chaos") | |||
and ((type(data.chaos)=="table" and (data.chaos.main or data.chaos)) or (data.chaos_main or {})) | |||
or (type(data.main)=="table" and data.main or {}) | |||
local order = (mode=="chaos") and profile.chaos_main_order or profile.main_order | |||
local metaT = (mode=="chaos") and profile.chaos_main_meta or profile.main_meta | |||
for i, key in ipairs(order) do | |||
local meta = metaT[key] or { label = key } | |||
local val = (mode=="chaos") and pick(args["chaos_"..key], src[key]) or pick(args["main"..i.."_val"], src[key]) | |||
pill(mains, meta.label, val, meta.icon, showLabels, meta.desc) | |||
end | |||
end | |||
-- -------- Spalte 2: Fortschrittsattribute -------- | |||
do | |||
local col = grid:tag("div"):addClass("kr-quad") | |||
col:tag("h3"):addClass("kr-hc-h"):wikitext("Fortschrittsattribute") | |||
local advs = col:tag("div"):addClass("kr-hc-adv-attrs") | |||
local src = (mode=="chaos") | |||
and ((type(data.chaos)=="table" and (data.chaos.adv or data.chaos)) or (data.chaos_adv or {})) | |||
or (type(data.adv)=="table" and data.adv or {}) | |||
local order = (mode=="chaos") and profile.chaos_adv_order or profile.adv_order | |||
local metaT = (mode=="chaos") and profile.chaos_adv_meta or profile.adv_meta | |||
for i, key in ipairs(order) do | |||
local meta = metaT[key] or { label = key } | |||
local val = (mode=="chaos") and pick(args["chaos_"..key], src[key]) or pick(args["adv"..i.."_val"], src[key]) | |||
adv(advs, meta.label, val, meta.icon, showLabels, meta.desc) | |||
end | |||
end | |||
-- -------- Spalte 3: Aura / Fähigkeit -------- | |||
do | |||
local col = grid:tag("div"):addClass("kr-quad") | |||
col:tag("h3"):addClass("kr-hc-h"):wikitext(L.awakening) | |||
local aura_val = (mode=="chaos") | |||
and pick(args.chaos_guardian_aura, args.chaos_aura, (type(opts.data.chaos)=="table" and opts.data.chaos.aura), opts.awakening_bonus) | |||
or opts.awakening_bonus | |||
if not isempty(aura_val) then | |||
local box = col:tag("div"):addClass("kr-hc-awakening kr-hc-adv") | |||
if isWM then | |||
box:addClass("kr-no-icon") -- WM: ohne Icon + ohne Tooltip | |||
else | |||
box:addClass("kr-tip") | |||
addTooltip(box, aura_val, opts.awakening_desc) | |||
if opts.awakening_icon then | |||
box:tag("div"):addClass("kr-hc-adv-icon") | |||
:wikitext(fileWikitext(opts.awakening_icon, {size="64x64px", link="", lazy=true})) | |||
end | |||
end | |||
local main = box:tag("div"):addClass("kr-hc-adv-main") | |||
local lab = main:tag("div"):addClass("kr-hc-adv-label"):wikitext(L.awakening) | |||
if not showLabels then lab:addClass("is-hidden") end | |||
main:tag("div"):addClass("kr-hc-adv-value"):wikitext(aura_val) | |||
end | |||
end | |||
return tostring(grid) | |||
end | end | ||
| Zeile 197: | Zeile 300: | ||
local showLabels = norm(args.show_labels) == "yes" or norm(args.show_labels) == "1" | local showLabels = norm(args.show_labels) == "yes" or norm(args.show_labels) == "1" | ||
-- UI-Labels & | -- UI-Labels & Entity | ||
local UI = (loadI18n().ui or {}) | local UI = (loadI18n().ui or {}) | ||
local entity = norm(pick(args.entity, data.entity)) | local entity = norm(pick(args.entity, data.entity)) | ||
local isGuardian = (entity == "guardian") | local isGuardian = (entity == "guardian") | ||
or norm(pick(args.guardian, data.guardian)) == "1" | or norm(pick(args.guardian, data.guardian)) == "1" | ||
or pick(args.is_guardian, data.is_guardian) == true | or pick(args.is_guardian, data.is_guardian) == true | ||
local isWM = (entity == "wm") | if isGuardian then entity = "guardian" end | ||
local isWM = (entity == "wm") | |||
local isMercenary = (entity == "mercenary") | |||
local isGod = (entity == "god") | |||
local isHero = (entity == "" or entity == "hero") or (not isGuardian and not isWM and not isMercenary and not isGod) | |||
-- Root | |||
local root = mw.html.create("div"):addClass("kr-hero-card kr-layout") | |||
if isGuardian then root:addClass("is-guardian") | |||
elseif isWM then root:addClass("is-wm") | |||
elseif isMercenary then root:addClass("is-mercenary") | |||
elseif isGod then root:addClass("is-god") | |||
else root:addClass("is-hero") end | |||
if showLabels then root:addClass("kr-show-labels") end | |||
-- Labels für UI | |||
local labelsHero = (UI.labels and UI.labels.hero) or { class="Klasse:", awakening="Erweckungsbonus" } | local labelsHero = (UI.labels and UI.labels.hero) or { class="Klasse:", awakening="Erweckungsbonus" } | ||
local labelsGuardian = (UI.labels and UI.labels.guardian) or { class="Typ:", awakening="Wächteraura" } | local labelsGuardian = (UI.labels and UI.labels.guardian) or { class="Typ:", awakening="Wächteraura" } | ||
local labelsWM = (UI.labels and UI.labels.wm) or { awakening="Fähigkeit" } | local labelsWM = (UI.labels and UI.labels.wm) or { awakening="Fähigkeit" } | ||
local L = isGuardian and labelsGuardian or labelsHero | local L = isGuardian and labelsGuardian or labelsHero | ||
if isWM then | if isWM then | ||
| Zeile 214: | Zeile 330: | ||
end | end | ||
-- Daten + Übersetzungen | -- Daten + Übersetzungen (Basics ohne Icons) | ||
local class | local class = tr("class", pick(args.class, data.class)) | ||
local | local attackstyle = tr("attackstyle", pick(args.attackstyle, data.attackstyle)) | ||
local | local specialization = tr("specialization", pick(args.specialization, data.specialization)) | ||
local | local resource = tr("resource", pick(args.resource, data.resource)) | ||
local unlock_at = pick(args.unlock_at, data.unlock_at) | |||
local unlock_at | |||
local awakening_bonusRaw = pick( | local awakening_bonusRaw = pick( | ||
| Zeile 233: | Zeile 345: | ||
local awakening_desc = awakeningDesc(awakening_bonusRaw, pick(args.awakening_desc, data.awakening_desc)) | local awakening_desc = awakeningDesc(awakening_bonusRaw, pick(args.awakening_desc, data.awakening_desc)) | ||
local CFGmod = loadConfig() | local CFGmod = loadConfig() | ||
local | local profile = pickProfile(CFGmod, entity) | ||
local | -- Nur Awakening-/Aura-Icon mappen | ||
local awakening_bonus_icon = ((CFGmod.icon_map or {}).awakening_bonus or {})[norm(awakening_bonusRaw)] | |||
-- | -- Avatar (links) | ||
local linkto = pick(args.linkto, name) | local linkto = pick(args.linkto, name) | ||
local avatar = defaultAvatarFile(name, data, args) | local avatar = defaultAvatarFile(name, data, args) | ||
local avatarDiv = root:tag("div"):addClass("kr-hc-avatar") | local avatarDiv = root:tag("div"):addClass("kr-hc-avatar") | ||
avatarDiv:wikitext( buildAvatar(name, linkto, avatar, data.skins, { isGuardian = isGuardian }) ) | avatarDiv:wikitext( buildAvatar(name, linkto, avatar, data.skins, { isGuardian = isGuardian }) ) | ||
| Zeile 263: | Zeile 360: | ||
local content = root:tag("div"):addClass("kr-hc-content") | local content = root:tag("div"):addClass("kr-hc-content") | ||
-- Header | -- Header + Unlock | ||
local header = content:tag("div"):addClass("kr-hc-header") | local header = content:tag("div"):addClass("kr-hc-header") | ||
if not isempty(name) then | if not isempty(name) then | ||
| Zeile 269: | Zeile 366: | ||
end | end | ||
local unlock_text = unlock_text_de(unlock_at) | local unlock_text = unlock_text_de(unlock_at) | ||
if unlock_text then | if unlock_text then header:tag("div"):addClass("kr-hc-unlockline"):wikitext("🔒 " .. unlock_text) end | ||
content:tag("div"):addClass("kr-hc-sep") | content:tag("div"):addClass("kr-hc-sep") | ||
-- Basics 2×2 ( | -- Basics 2×2 (ohne Icons) | ||
local basics = content:tag("div"):addClass("kr-hc-basics2") | local basics = content:tag("div"):addClass("kr-hc-basics2") | ||
local function pair(label, value | local function pair(label, value) | ||
if isempty(value) then return end | if isempty(value) then return end | ||
local it = basics:tag("div"):addClass("kr-hc-basic") | local it = basics:tag("div"):addClass("kr-hc-basic") | ||
it:tag("span"):addClass("label"):wikitext(label) | it:tag("span"):addClass("label"):wikitext(label) | ||
it:tag("span"):addClass("value"):wikitext(value) | |||
end | end | ||
pair(L.class, class | pair(L.class, class) | ||
pair("Spezialisierung:", specialization | pair("Spezialisierung:", specialization) | ||
pair("Angriffsart:", attackstyle | pair("Angriffsart:", attackstyle) | ||
pair("Ressource:", resource | pair("Ressource:", resource) | ||
-- ===== | -- ===== Inhalte: Hero/Wächter/WM ===== | ||
local | local frame = mw.getCurrentFrame() | ||
-- | -- ---- HERO / MERC / GOD / WM (ohne Tabs): normales Grid ---- | ||
if not isGuardian then | |||
local | local grid_html = render_grid{ | ||
profile = profile, data = data, args = args, L = L, | |||
showLabels = showLabels, isWM = isWM, | |||
awakening_bonus = awakening_bonus, awakening_desc = awakening_desc, | |||
for | awakening_icon = (not isWM and awakening_bonus_icon or nil), | ||
mode = "default", | |||
} | |||
content:wikitext(grid_html) | |||
return tostring(root) | |||
end | |||
-- ---- GUARDIAN: ggf. mit Tabber (Default ↔ Chaos) ---- | |||
-- prüfen, ob Chaos-Werte existieren | |||
local hasChaos = false | |||
local chaos = (type(data.chaos)=="table" and data.chaos) or {} | |||
-- main | |||
if profile.chaos_main_order and #profile.chaos_main_order > 0 then | |||
local src = chaos.main or chaos | |||
for _,k in ipairs(profile.chaos_main_order) do | |||
if not isempty(pick(args["chaos_"..k], src and src[k])) then hasChaos = true break end | |||
end | end | ||
end | end | ||
-- adv (falls bisher nichts gefunden) | |||
-- | if (not hasChaos) and profile.chaos_adv_order and #profile.chaos_adv_order > 0 then | ||
local src = chaos.adv or chaos | |||
for _,k in ipairs(profile.chaos_adv_order) do | |||
if not isempty(pick(args["chaos_"..k], src and src[k])) then hasChaos = true break end | |||
local | |||
for | |||
end | end | ||
end | |||
-- (optional) Chaos-Aura | |||
if (not hasChaos) and not isempty(pick(args.chaos_guardian_aura, args.chaos_aura, chaos.aura)) then | |||
hasChaos = true | |||
end | end | ||
-- | -- Default-Panel | ||
local default_html = render_grid{ | |||
profile = profile, data = data, args = args, L = L, | |||
showLabels = showLabels, isWM = false, | |||
awakening_bonus = awakening_bonus, awakening_desc = awakening_desc, | |||
awakening_icon = awakening_bonus_icon, | |||
mode = "default", | |||
} | |||
if not hasChaos then | |||
content:wikitext(default_html) | |||
return tostring(root) | |||
end | |||
-- Chaos-Panel | |||
local chaos_html = render_grid{ | |||
profile = profile, data = data, args = args, L = L, | |||
showLabels = showLabels, isWM = false, | |||
awakening_bonus = awakening_bonus, awakening_desc = awakening_desc, | |||
awakening_icon = awakening_bonus_icon, | |||
mode = "chaos", | |||
} | |||
-- TabberNeue mit Icon-Tabs | |||
local tabs = profile.tabs or {} | |||
local def_icon = tabs.default_icon or "GuardianTab_Default.png" | |||
local chs_icon = tabs.chaos_icon or "GuardianTab_Chaos.png" | |||
local size = tabs.icon_size or "28x28px" | |||
local function tabLabel(file) return fileWikitext(file, { size=size, link="", lazy=true }) end | |||
local panels = { | |||
tabLabel(def_icon) .. "=\n" .. default_html, | |||
tabLabel(chs_icon) .. "=\n" .. chaos_html, | |||
} | |||
local tabber = frame:extensionTag('tabber', table.concat(panels, "\n|-|\n")) | |||
content:wikitext(tabber) | |||
return tostring(root) | return tostring(root) | ||
end | end | ||
-- Alias | |||
p.main = p.render | |||
return p | return p | ||
Version vom 15. Oktober 2025, 04:17 Uhr
Die Dokumentation für dieses Modul kann unter Modul:HeroCard/Doku erstellt werden
-- Modul:HeroCard
local p = {}
-- ===== Helpers =====
local function isempty(v) return v == nil or v == "" end
local function pick(...) local n=select('#',...); for i=1,n do local v=select(i,...); if not isempty(v) then return v end end end
local function norm(s) if isempty(s) then return "" end return mw.ustring.lower(mw.text.trim(s)):gsub("%s+"," ") end
local function getArgs(frame)
local args, f1, f2 = {}, frame.args or {}, (frame:getParent() and frame:getParent().args) or {}
for k,v in pairs(f1) do if not isempty(v) then args[k]=v end end
for k,v in pairs(f2) do if not isempty(v) then args[k]=v end end
return args
end
-- Lazy load der ausgelagerten Module
local CFG, I18N
local function loadConfig()
if CFG then return CFG end
for _,t in ipairs{ "Modul:HeroConfig", "Module:HeroConfig" } do
local ok, mod = pcall(require, t); if ok and type(mod)=="table" then CFG=mod; return CFG end
end
error("HeroConfig not found")
end
local function loadI18n()
if I18N then return I18N end
for _,t in ipairs{ "Modul:HeroI18n", "Module:HeroI18n" } do
local ok, mod = pcall(require, t); if ok and type(mod)=="table" then I18N=mod; return I18N end
end
I18N = { i18n = {}, aw_desc = {}, ui = {} }; return I18N
end
-- HeroData (de/en)
local function loadHeroes()
for _,t in ipairs{ "Modul:HeroData", "Module:HeroData" } do
local ok, mod = pcall(require, t)
if ok and type(mod)=="table" and type(mod.heroes)=="table" then
return mod.heroes, {ok=true, from=t}
end
end
return nil, {ok=false}
end
local function fileWikitext(filename, opts)
if isempty(filename) then return "" end
local parts = { ("Datei:%s"):format(filename) }
if opts and opts.size then table.insert(parts, opts.size) end
if opts and opts.link then table.insert(parts, "link="..opts.link) end
if opts and opts.class then table.insert(parts, "class="..opts.class) end
return string.format("[[%s]]", table.concat(parts, "|"))
end
-- Übersetzen per HeroI18n
local function tr(kind, value)
if isempty(value) then return value end
local map = loadI18n().i18n[kind] or {}
return map[norm(value)] or value
end
-- Tooltip-HTML
local function addTooltip(box, title, desc)
if (isempty(title) and isempty(desc)) then return end
local tip = box:tag("span"):addClass("kr-tipbox")
if not isempty(title) then tip:tag("span"):addClass("kr-tip-title"):wikitext(title) end
if not (isempty(title) or isempty(desc)) then tip:tag("span"):addClass("kr-tip-sep") end
if not isempty(desc) then tip:tag("span"):addClass("kr-tip-desc"):wikitext(desc) end
end
-- Kleine Bausteine
local function pill(parent, label, val, icon, showLabels, desc)
if isempty(val) then return end
local box = parent:tag("div"):addClass("kr-hc-pill kr-tip")
local left = box:tag("div"):addClass("kr-hc-pill-icon")
if not isempty(icon) then left:wikitext(fileWikitext(icon, {size="36x36px", link="", lazy=true})) end
local text = box:tag("div"):addClass("kr-hc-pill-text")
local lab = text:tag("div"):addClass("kr-hc-pill-label"):wikitext(label or "")
if not showLabels then lab:addClass("is-hidden") end
text:tag("div"):addClass("kr-hc-pill-value"):wikitext(val)
addTooltip(box, label, desc)
end
local function adv(parent, label, val, icon, showLabels, desc)
if isempty(val) then return end
local box = parent:tag("div"):addClass("kr-hc-adv kr-tip")
local left = box:tag("div"):addClass("kr-hc-adv-icon")
if not isempty(icon) then left:wikitext(fileWikitext(icon, {size="36x36px", link="", lazy=true})) end
local main = box:tag("div"):addClass("kr-hc-adv-main")
local lab = main:tag("div"):addClass("kr-hc-adv-label"):wikitext(label or "")
if not showLabels then lab:addClass("is-hidden") end
main:tag("div"):addClass("kr-hc-adv-value"):wikitext(val)
addTooltip(box, label, desc)
end
-- Unlock-Text
local function unlock_text_de(s)
if isempty(s) then return nil end
local t = norm(s)
local n = t:match("stage%s*(%d+)"); if n then return "Freischaltung bei Abschnitt: " .. n end
if t:match("pirate%s*ship") then return "Wird auf dem Piratenschiff freigeschaltet." end
if s:match("[%.%!%?]$") or t:find(" ") then return s end
return "Freischaltung: " .. s
end
-- Awakening-Desc: NUR englische Keys (wie in HeroData)
local function awakeningDesc(raw_value, override)
if not isempty(override) then return override end
if isempty(raw_value) then return "Bonus, der beim Erwachen freigeschaltet wird." end
local map = loadI18n().aw_desc or {}
return map[norm(raw_value)] or "Bonus, der beim Erwachen freigeschaltet wird."
end
local function defaultAvatarFile(name, data, args)
if not isempty(args.avatar) then return args.avatar end
if not isempty(data.default_avatar) then return data.default_avatar end
if not isempty(data.default_skin) then
return string.format("%s_%s.png", name, data.default_skin)
end
if not isempty(name) then return name .. ".png" end
return nil
end
-- Avatar/Skins → TabberNeue
local function buildAvatar(name, linkto, defaultFile, skinsTable, opts)
opts = opts or {}
local isGuardian = opts.isGuardian == true
if type(skinsTable) ~= "table" or next(skinsTable) == nil then
return fileWikitext(defaultFile, { class="kr-hc-avatar-img", link=linkto, lazy=true })
end
local frame = mw.getCurrentFrame()
local defaultLabel = (loadI18n().ui and loadI18n().ui.default_skin) or "Standard"
local panels = {}
local function push(label, file)
table.insert(panels,
tostring(label) .. "=\n" ..
fileWikitext(file, { class="kr-hc-avatar-img", link=linkto, lazy=true })
)
end
if isGuardian then
push("E1", defaultFile)
else
push(defaultLabel, defaultFile)
end
if skinsTable[1] ~= nil then
local idx = 1 -- E1 war Default
for _, v in ipairs(skinsTable) do
if type(v) == "table" then
local label = v.label or v[1]
local file = v.file or (name .. "_" .. (v.filename or label) .. ".png")
idx = idx + 1
local tabLabel = isGuardian and ("E" .. idx) or label
push(tabLabel, file)
else
local label = tostring(v)
idx = idx + 1
local file = name .. "_" .. label .. ".png"
local tabLabel = isGuardian and ("E" .. idx) or label
push(tabLabel, file)
end
end
else
local tmp = {}
for k, v in pairs(skinsTable) do
if type(v) == "table" then
local label = v.label or v[1] or tostring(k)
local file = v.file or (name .. "_" .. (v.filename or label) .. ".png")
table.insert(tmp, {label=label, file=file})
else
local label = tostring(v)
table.insert(tmp, {label=label, file=(name .. "_" .. label .. ".png")})
end
end
table.sort(tmp, function(a,b) return tostring(a.label) < tostring(b.label) end)
local idx = 1
for _,it in ipairs(tmp) do
idx = idx + 1
local tabLabel = isGuardian and ("E" .. idx) or it.label
push(tabLabel, it.file)
end
end
local content = table.concat(panels, "\n|-|\n")
return frame:extensionTag('tabber', content)
end
-- ===== Profile-Auswahl aus HeroConfig =====
local function pickProfile(cfg, entity)
local profiles = cfg.profiles or {}
local base = profiles.default or {}
local key = "default"
if entity == "guardian" then key = "guardian"
elseif entity == "wm" then key = "wm"
-- mercenary/god → default
end
local over = profiles[key] or {}
local P = {}
P.main_order = over.main_order or base.main_order or {}
P.main_meta = over.main_meta or base.main_meta or {}
P.adv_order = over.adv_order or base.adv_order or {}
P.adv_meta = over.adv_meta or base.adv_meta or {}
-- Guardian: Chaos-Rift
P.tabs = (over.tabs or {})
P.chaos_main_order = over.chaos_main_order or {}
P.chaos_main_meta = over.chaos_main_meta or {}
P.chaos_adv_order = over.chaos_adv_order or {}
P.chaos_adv_meta = over.chaos_adv_meta or {}
return P
end
-- ===== Hilfsrenderer für das 3er-Grid =====
local function render_grid(opts)
local profile, data, args, L, showLabels, isWM = opts.profile, opts.data, opts.args, opts.L, opts.showLabels, opts.isWM
local mode = opts.mode or "default" -- "default" | "chaos"
local grid = mw.html.create("div"):addClass("kr-g3")
-- -------- Spalte 1: Hauptattribute --------
do
local col = grid:tag("div"):addClass("kr-quad")
col:tag("h3"):addClass("kr-hc-h"):wikitext("Hauptattribute")
local mains = col:tag("div"):addClass("kr-hc-main-attrs")
local src = (mode=="chaos")
and ((type(data.chaos)=="table" and (data.chaos.main or data.chaos)) or (data.chaos_main or {}))
or (type(data.main)=="table" and data.main or {})
local order = (mode=="chaos") and profile.chaos_main_order or profile.main_order
local metaT = (mode=="chaos") and profile.chaos_main_meta or profile.main_meta
for i, key in ipairs(order) do
local meta = metaT[key] or { label = key }
local val = (mode=="chaos") and pick(args["chaos_"..key], src[key]) or pick(args["main"..i.."_val"], src[key])
pill(mains, meta.label, val, meta.icon, showLabels, meta.desc)
end
end
-- -------- Spalte 2: Fortschrittsattribute --------
do
local col = grid:tag("div"):addClass("kr-quad")
col:tag("h3"):addClass("kr-hc-h"):wikitext("Fortschrittsattribute")
local advs = col:tag("div"):addClass("kr-hc-adv-attrs")
local src = (mode=="chaos")
and ((type(data.chaos)=="table" and (data.chaos.adv or data.chaos)) or (data.chaos_adv or {}))
or (type(data.adv)=="table" and data.adv or {})
local order = (mode=="chaos") and profile.chaos_adv_order or profile.adv_order
local metaT = (mode=="chaos") and profile.chaos_adv_meta or profile.adv_meta
for i, key in ipairs(order) do
local meta = metaT[key] or { label = key }
local val = (mode=="chaos") and pick(args["chaos_"..key], src[key]) or pick(args["adv"..i.."_val"], src[key])
adv(advs, meta.label, val, meta.icon, showLabels, meta.desc)
end
end
-- -------- Spalte 3: Aura / Fähigkeit --------
do
local col = grid:tag("div"):addClass("kr-quad")
col:tag("h3"):addClass("kr-hc-h"):wikitext(L.awakening)
local aura_val = (mode=="chaos")
and pick(args.chaos_guardian_aura, args.chaos_aura, (type(opts.data.chaos)=="table" and opts.data.chaos.aura), opts.awakening_bonus)
or opts.awakening_bonus
if not isempty(aura_val) then
local box = col:tag("div"):addClass("kr-hc-awakening kr-hc-adv")
if isWM then
box:addClass("kr-no-icon") -- WM: ohne Icon + ohne Tooltip
else
box:addClass("kr-tip")
addTooltip(box, aura_val, opts.awakening_desc)
if opts.awakening_icon then
box:tag("div"):addClass("kr-hc-adv-icon")
:wikitext(fileWikitext(opts.awakening_icon, {size="64x64px", link="", lazy=true}))
end
end
local main = box:tag("div"):addClass("kr-hc-adv-main")
local lab = main:tag("div"):addClass("kr-hc-adv-label"):wikitext(L.awakening)
if not showLabels then lab:addClass("is-hidden") end
main:tag("div"):addClass("kr-hc-adv-value"):wikitext(aura_val)
end
end
return tostring(grid)
end
-- ======= RENDER =======
function p.render(frame)
local args = getArgs(frame)
local name = pick(args.name, args[1]) or ""
local heroes = select(1, loadHeroes())
local data = (heroes and (heroes[name] or heroes[mw.ustring.gsub(name or "", "_", " ")])) or {}
local showLabels = norm(args.show_labels) == "yes" or norm(args.show_labels) == "1"
-- UI-Labels & Entity
local UI = (loadI18n().ui or {})
local entity = norm(pick(args.entity, data.entity))
local isGuardian = (entity == "guardian")
or norm(pick(args.guardian, data.guardian)) == "1"
or pick(args.is_guardian, data.is_guardian) == true
if isGuardian then entity = "guardian" end
local isWM = (entity == "wm")
local isMercenary = (entity == "mercenary")
local isGod = (entity == "god")
local isHero = (entity == "" or entity == "hero") or (not isGuardian and not isWM and not isMercenary and not isGod)
-- Root
local root = mw.html.create("div"):addClass("kr-hero-card kr-layout")
if isGuardian then root:addClass("is-guardian")
elseif isWM then root:addClass("is-wm")
elseif isMercenary then root:addClass("is-mercenary")
elseif isGod then root:addClass("is-god")
else root:addClass("is-hero") end
if showLabels then root:addClass("kr-show-labels") end
-- Labels für UI
local labelsHero = (UI.labels and UI.labels.hero) or { class="Klasse:", awakening="Erweckungsbonus" }
local labelsGuardian = (UI.labels and UI.labels.guardian) or { class="Typ:", awakening="Wächteraura" }
local labelsWM = (UI.labels and UI.labels.wm) or { awakening="Fähigkeit" }
local L = isGuardian and labelsGuardian or labelsHero
if isWM then
L = { class = L.class or (labelsHero.class or "Klasse:"), awakening = labelsWM.awakening or "Fähigkeit" }
end
-- Daten + Übersetzungen (Basics ohne Icons)
local class = tr("class", pick(args.class, data.class))
local attackstyle = tr("attackstyle", pick(args.attackstyle, data.attackstyle))
local specialization = tr("specialization", pick(args.specialization, data.specialization))
local resource = tr("resource", pick(args.resource, data.resource))
local unlock_at = pick(args.unlock_at, data.unlock_at)
local awakening_bonusRaw = pick(
args.awakening_bonus, data.awakening_bonus, -- Held
args.guardian_aura, data.guardian_aura, -- Wächter
data.aura
)
local awakening_bonus = tr("awakening_bonus", awakening_bonusRaw)
local awakening_desc = awakeningDesc(awakening_bonusRaw, pick(args.awakening_desc, data.awakening_desc))
local CFGmod = loadConfig()
local profile = pickProfile(CFGmod, entity)
-- Nur Awakening-/Aura-Icon mappen
local awakening_bonus_icon = ((CFGmod.icon_map or {}).awakening_bonus or {})[norm(awakening_bonusRaw)]
-- Avatar (links)
local linkto = pick(args.linkto, name)
local avatar = defaultAvatarFile(name, data, args)
local avatarDiv = root:tag("div"):addClass("kr-hc-avatar")
avatarDiv:wikitext( buildAvatar(name, linkto, avatar, data.skins, { isGuardian = isGuardian }) )
-- Content (rechts)
local content = root:tag("div"):addClass("kr-hc-content")
-- Header + Unlock
local header = content:tag("div"):addClass("kr-hc-header")
if not isempty(name) then
header:tag("h2"):addClass("kr-hc-name"):wikitext(string.format("[[%s|%s]]", linkto, name))
end
local unlock_text = unlock_text_de(unlock_at)
if unlock_text then header:tag("div"):addClass("kr-hc-unlockline"):wikitext("🔒 " .. unlock_text) end
content:tag("div"):addClass("kr-hc-sep")
-- Basics 2×2 (ohne Icons)
local basics = content:tag("div"):addClass("kr-hc-basics2")
local function pair(label, value)
if isempty(value) then return end
local it = basics:tag("div"):addClass("kr-hc-basic")
it:tag("span"):addClass("label"):wikitext(label)
it:tag("span"):addClass("value"):wikitext(value)
end
pair(L.class, class)
pair("Spezialisierung:", specialization)
pair("Angriffsart:", attackstyle)
pair("Ressource:", resource)
-- ===== Inhalte: Hero/Wächter/WM =====
local frame = mw.getCurrentFrame()
-- ---- HERO / MERC / GOD / WM (ohne Tabs): normales Grid ----
if not isGuardian then
local grid_html = render_grid{
profile = profile, data = data, args = args, L = L,
showLabels = showLabels, isWM = isWM,
awakening_bonus = awakening_bonus, awakening_desc = awakening_desc,
awakening_icon = (not isWM and awakening_bonus_icon or nil),
mode = "default",
}
content:wikitext(grid_html)
return tostring(root)
end
-- ---- GUARDIAN: ggf. mit Tabber (Default ↔ Chaos) ----
-- prüfen, ob Chaos-Werte existieren
local hasChaos = false
local chaos = (type(data.chaos)=="table" and data.chaos) or {}
-- main
if profile.chaos_main_order and #profile.chaos_main_order > 0 then
local src = chaos.main or chaos
for _,k in ipairs(profile.chaos_main_order) do
if not isempty(pick(args["chaos_"..k], src and src[k])) then hasChaos = true break end
end
end
-- adv (falls bisher nichts gefunden)
if (not hasChaos) and profile.chaos_adv_order and #profile.chaos_adv_order > 0 then
local src = chaos.adv or chaos
for _,k in ipairs(profile.chaos_adv_order) do
if not isempty(pick(args["chaos_"..k], src and src[k])) then hasChaos = true break end
end
end
-- (optional) Chaos-Aura
if (not hasChaos) and not isempty(pick(args.chaos_guardian_aura, args.chaos_aura, chaos.aura)) then
hasChaos = true
end
-- Default-Panel
local default_html = render_grid{
profile = profile, data = data, args = args, L = L,
showLabels = showLabels, isWM = false,
awakening_bonus = awakening_bonus, awakening_desc = awakening_desc,
awakening_icon = awakening_bonus_icon,
mode = "default",
}
if not hasChaos then
content:wikitext(default_html)
return tostring(root)
end
-- Chaos-Panel
local chaos_html = render_grid{
profile = profile, data = data, args = args, L = L,
showLabels = showLabels, isWM = false,
awakening_bonus = awakening_bonus, awakening_desc = awakening_desc,
awakening_icon = awakening_bonus_icon,
mode = "chaos",
}
-- TabberNeue mit Icon-Tabs
local tabs = profile.tabs or {}
local def_icon = tabs.default_icon or "GuardianTab_Default.png"
local chs_icon = tabs.chaos_icon or "GuardianTab_Chaos.png"
local size = tabs.icon_size or "28x28px"
local function tabLabel(file) return fileWikitext(file, { size=size, link="", lazy=true }) end
local panels = {
tabLabel(def_icon) .. "=\n" .. default_html,
tabLabel(chs_icon) .. "=\n" .. chaos_html,
}
local tabber = frame:extensionTag('tabber', table.concat(panels, "\n|-|\n"))
content:wikitext(tabber)
return tostring(root)
end
-- Alias
p.main = p.render
return p