Modul:HeroCard: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| Zeile 3: | Zeile 3: | ||
-- ======= CONFIG / DEFAULTS ======= | -- ======= CONFIG / DEFAULTS ======= | ||
local CFG = { | local CFG = { | ||
-- | -- Haupt-/Erweiterte Attribute: Labels & Default-Icons (DE) | ||
main_order = { "damage", "hp", "armor" }, | main_order = { "damage", "hp", "armor" }, | ||
main_meta = { | main_meta = { | ||
damage = { label = "Schaden", icon = "AttackIcon.png" }, | damage = { label = "Schaden", icon = "AttackIcon.png" }, | ||
hp = { label = " | hp = { label = "Gesundheit", icon = "HealthIcon.png" }, | ||
armor = { label = "Rüstung", icon = "ArmorIcon.png" }, | armor = { label = "Rüstung", icon = "ArmorIcon.png" }, | ||
}, | }, | ||
adv_order = { "precision", "bonus_damage", "speed", "dodge" }, | adv_order = { "precision", "bonus_damage", "speed", "dodge" }, | ||
adv_meta = { | adv_meta = { | ||
precision = { label = " | precision = { label = "Krit.-Chance", icon = "CriticalChanceIcon.png" }, | ||
bonus_damage = { label = " | bonus_damage = { label = "Kritischer Schaden", icon = "CriticalDamageIcon.png" }, | ||
speed = { label = " | speed = { label = "Angriffsgeschwindigkeit", icon = "AttackSpeedIcon.png" }, | ||
dodge = { label = "Ausweichen", icon = "DodgeIcon.png" }, | dodge = { label = "Ausweichen", icon = "DodgeIcon.png" }, | ||
}, | }, | ||
| Zeile 39: | Zeile 39: | ||
["all main attributes"] = "AllAttributes.png", | ["all main attributes"] = "AllAttributes.png", | ||
prestigious = "Prestigious.png", | prestigious = "Prestigious.png", | ||
} | |||
}, | |||
-- DE-Übersetzung der Werte aus HeroData | |||
i18n = { | |||
class = { | |||
warrior="Krieger", paladin="Paladin", rouge="Schurke", | |||
mage="Magier", druid="Druide", ranger="Waldläufer" | |||
}, | |||
attackstyle = { | |||
melee="Nahkampf", ranged="Fernkampf", spellcaster="Zauberwirker" | |||
}, | |||
specialization = { healer="Heiler", damage="Schaden", tank="Tank" }, | |||
resource = { mana="Mana", rage="Wut", energy="Energie" }, | |||
awakening_bonus = { | |||
["raining gold"]="Goldregen", | |||
["all main attributes"]="Alle Hauptattribute", | |||
prestigious="Prestigevoll" | |||
} | } | ||
} | } | ||
| Zeile 45: | Zeile 63: | ||
-- ======= HELPERS ======= | -- ======= HELPERS ======= | ||
local function isempty(v) return v == nil or v == "" end | local function isempty(v) return v == nil or v == "" end | ||
local function pick(...) | local function pick(...) | ||
local n = select('#', ...) | local n = select('#', ...) | ||
| Zeile 54: | Zeile 71: | ||
return nil | return nil | ||
end | end | ||
local function norm(s) | local function norm(s) | ||
if isempty(s) then return "" end | if isempty(s) then return "" end | ||
return mw.ustring.lower(mw.text.trim(s)):gsub("%s+", " ") | |||
end | end | ||
local function getArgs(frame) | local function getArgs(frame) | ||
local args, f1, f2 = {}, frame.args or {}, (frame:getParent() and frame:getParent().args) or {} | local args, f1, f2 = {}, frame.args or {}, (frame:getParent() and frame:getParent().args) or {} | ||
| Zeile 67: | Zeile 81: | ||
return args | return args | ||
end | end | ||
local function loadHeroes() | local function loadHeroes() | ||
local tried, lastErr = {}, nil | local tried, lastErr = {}, nil | ||
| Zeile 81: | Zeile 93: | ||
return nil, { ok=false, tried=tried, err=lastErr } | return nil, { ok=false, tried=tried, err=lastErr } | ||
end | end | ||
local function fileWikitext(filename, opts) | local function fileWikitext(filename, opts) | ||
if isempty(filename) then return "" end | if isempty(filename) then return "" end | ||
| Zeile 91: | Zeile 102: | ||
return string.format("[[%s]]", table.concat(parts, "|")) | return string.format("[[%s]]", table.concat(parts, "|")) | ||
end | end | ||
local function mapIcon(kind, value, override) | local function mapIcon(kind, value, override) | ||
if not isempty(override) then return override end | if not isempty(override) then return override end | ||
local t = CFG.icon_map[kind] or {} | local t = CFG.icon_map[kind] or {} | ||
return t[norm(value)] | return t[norm(value)] | ||
end | |||
local function tr(kind, value) | |||
if isempty(value) then return value end | |||
local m = CFG.i18n[kind] or {} | |||
return m[norm(value)] or value | |||
end | end | ||
-- Pill/Adv | -- Pill/Adv: Icon 36px, Label nur als Tooltip/hover | ||
local function pill(htmlParent, label, val, icon) | local function pill(htmlParent, label, val, icon, showLabels) | ||
if isempty(val) then return end | if isempty(val) then return end | ||
local box = htmlParent:tag("div"):addClass("kr-hc-pill") | local box = htmlParent:tag("div"):addClass("kr-hc-pill"):attr("title", label or "") | ||
local left = box:tag("div"):addClass("kr-hc-pill-icon") | 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 | 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 text = box:tag("div"):addClass("kr-hc-pill-text") | ||
text:tag("div"):addClass("kr-hc-pill-label"):wikitext(label or "") | 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) | text:tag("div"):addClass("kr-hc-pill-value"):wikitext(val) | ||
end | end | ||
local function adv(htmlParent, label, val, icon, showLabels) | |||
local function adv(htmlParent, label, val, icon) | |||
if isempty(val) then return end | if isempty(val) then return end | ||
local box = htmlParent:tag("div"):addClass("kr-hc-adv") | local box = htmlParent:tag("div"):addClass("kr-hc-adv"):attr("title", label or "") | ||
local left = box:tag("div"):addClass("kr-hc-adv-icon") | 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 | 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 main = box:tag("div"):addClass("kr-hc-adv-main") | ||
main:tag("div"):addClass("kr-hc-adv-label"):wikitext(label or "") | 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) | main:tag("div"):addClass("kr-hc-adv-value"):wikitext(val) | ||
end | end | ||
local function | -- Freischaltung → sauberer DE-Text | ||
if | local function unlock_text_de(s) | ||
local | if s == nil or s == "" then return nil end | ||
local t = mw.ustring.lower(mw.text.trim(s)):gsub("%s+", " ") | |||
return 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 | |||
-- Wenn es wie ein vollständiger eigener Satz aussieht → unverändert anzeigen | |||
if s:match("[%.%!%?]$") or t:find(" ") then | |||
return s | |||
end | |||
-- Neutraler Fallback | |||
return "Freischaltung: " .. s | |||
end | end | ||
-- ======= RENDER ======= | -- ======= RENDER ======= | ||
| Zeile 135: | Zeile 163: | ||
local debugWanted = norm(args.debug) == "1" or norm(args.debug) == "yes" | local debugWanted = norm(args.debug) == "1" or norm(args.debug) == "yes" | ||
local showLabels = norm(args.show_labels) == "1" or norm(args.show_labels) == "yes" | |||
-- Basics (Werte) | -- Basics (Werte aus Data, ins DE übersetzen) | ||
local class = pick(args.class, data.class) | local class = tr("class", pick(args.class, data.class)) | ||
local | local attackstyleRaw = pick(args.attackstyle, data.attackstyle) | ||
local | local specializationRaw = pick(args.specialization, data.specialization) | ||
local | local resourceRaw = pick(args.resource, data.resource) | ||
local unlock_at = pick(args.unlock_at, | local attackstyle = tr("attackstyle", attackstyleRaw) | ||
local | local specialization = tr("specialization", specializationRaw) | ||
local resource = tr("resource", resourceRaw) | |||
local unlock_at = pick(args.unlock_at, data.unlock_at) | |||
local awakening_bonusRaw = pick(args.awakening_bonus, data.awakening_bonus) | |||
local awakening_bonus = tr("awakening_bonus", awakening_bonusRaw) | |||
-- Icons (kein Icon für class) | -- Icons (kein Icon für class) | ||
local attackstyle_icon = mapIcon("attackstyle", | local attackstyle_icon = mapIcon("attackstyle", attackstyleRaw, pick(args.attackstyle_icon, data.attackstyle_icon)) | ||
local specialization_icon = mapIcon("specialization", | local specialization_icon = mapIcon("specialization", specializationRaw, pick(args.specialization_icon, data.specialization_icon)) | ||
local resource_icon = mapIcon("resource", | local resource_icon = mapIcon("resource", resourceRaw, pick(args.resource_icon, data.resource_icon)) | ||
local awakening_bonus_icon= mapIcon("awakening_bonus", | local awakening_bonus_icon= mapIcon("awakening_bonus",awakening_bonusRaw,pick(args.awakening_bonus_icon,data.awakening_bonus_icon)) | ||
-- Bilder/Links | -- Bilder/Links | ||
| Zeile 155: | Zeile 188: | ||
local root = mw.html.create("div"):addClass("kr-hero-card") | local root = mw.html.create("div"):addClass("kr-hero-card") | ||
if showLabels then root:addClass("kr-show-labels") end | |||
-- Avatar (links) – skaliert, lazy | -- Avatar (links) – skaliert, lazy | ||
| Zeile 163: | Zeile 197: | ||
local content = root:tag("div"):addClass("kr-hc-content") | local content = root:tag("div"):addClass("kr-hc-content") | ||
-- Titel: Name verlinkt + (Unlock) | -- Titel: Name verlinkt + (Unlock DE) | ||
if not isempty(name) then | if not isempty(name) then | ||
local h = content:tag("h2"):addClass("kr-hc-name") | local h = content:tag("h2"):addClass("kr-hc-name") | ||
local unlock_text = | local unlock_text = unlock_text_de(unlock_at) | ||
h:wikitext(string.format("[[%s|%s]]%s", | h:wikitext(string.format("[[%s|%s]]%s", | ||
linkto, name, | linkto, name, | ||
| Zeile 173: | Zeile 207: | ||
end | end | ||
if (not info or not info.ok) and debugWanted then | if (not info or not info.ok) and debugWanted then | ||
content:tag("div"):addClass("kr-hc-debug") | content:tag("div"):addClass("kr-hc-debug") | ||
:wikitext("<strong>HeroData not loaded.</strong> | :wikitext("<strong>HeroData not loaded.</strong>") | ||
end | end | ||
-- | -- Basics 2×2 (Icon rechts) | ||
local basicsGrid = content:tag("div"):addClass("kr-hc-basics2") | local basicsGrid = content:tag("div"):addClass("kr-hc-basics2") | ||
local function pair(label, value, icon) | local function pair(label, value, icon) | ||
| Zeile 193: | Zeile 225: | ||
end | end | ||
end | end | ||
pair("Klasse:", | pair("Klasse:", class, nil) | ||
pair("Spezialisierung:", specialization, specialization_icon) | pair("Spezialisierung:", specialization, specialization_icon) | ||
pair("Angriffsart:", | pair("Angriffsart:", attackstyle, attackstyle_icon) | ||
pair("Ressource:", | pair("Ressource:", resource, resource_icon) | ||
-- | -- Hauptattribute | ||
content:tag("h3"):addClass("kr-hc-h"):wikitext("Hauptattribute") | content:tag("h3"):addClass("kr-hc-h"):wikitext("Hauptattribute") | ||
local mains = content:tag("div"):addClass("kr-hc-main-attrs") | local mains = content:tag("div"):addClass("kr-hc-main-attrs") | ||
| Zeile 205: | Zeile 237: | ||
local meta = CFG.main_meta[key] | local meta = CFG.main_meta[key] | ||
local val = pick(args["main"..i.."_val"], heroMain[key]) | local val = pick(args["main"..i.."_val"], heroMain[key]) | ||
pill(mains, meta.label, val, pick(args["main"..i.."_icon"], meta.icon), showLabels) | |||
end | end | ||
-- | -- Erweiterte Attribute | ||
content:tag("h3"):addClass("kr-hc-h"):wikitext("Erweiterte Attribute") | content:tag("h3"):addClass("kr-hc-h"):wikitext("Erweiterte Attribute") | ||
local advs = content:tag("div"):addClass("kr-hc-adv-attrs") | local advs = content:tag("div"):addClass("kr-hc-adv-attrs") | ||
| Zeile 217: | Zeile 247: | ||
local meta = CFG.adv_meta[key] | local meta = CFG.adv_meta[key] | ||
local val = pick(args["adv"..i.."_val"], heroAdv[key]) | local val = pick(args["adv"..i.."_val"], heroAdv[key]) | ||
adv(advs, meta.label, val, pick(args["adv"..i.."_icon"], meta.icon), showLabels) | |||
end | end | ||
for i = #CFG.adv_order + 1, 8 do | for i = #CFG.adv_order + 1, 8 do | ||
local val = args["adv"..i.."_val"] | local val = args["adv"..i.."_val"] | ||
if isempty(val) then break end | if isempty(val) then break end | ||
adv(advs, args["adv"..i.."_label"] or "", val, args["adv"..i.."_icon"]) | adv(advs, args["adv"..i.."_label"] or "", val, args["adv"..i.."_icon"], showLabels) | ||
end | end | ||
-- | -- Erweckungsbonus (Icon 64px) – nur Icon + Wert (Label per Hover) | ||
if not isempty(awakening_bonus) then | if not isempty(awakening_bonus) then | ||
content:tag("h3"):addClass("kr-hc-h"):wikitext("Erweckungsbonus") | content:tag("h3"):addClass("kr-hc-h"):wikitext("Erweckungsbonus") | ||
local awk = content:tag("div"):addClass("kr-hc-awakening") | local awk = content:tag("div"):addClass("kr-hc-awakening") | ||
local box = awk:tag("div"):addClass("kr-hc-adv") | local box = awk:tag("div"):addClass("kr-hc-adv"):attr("title", "Erweckungsbonus") | ||
if not isempty(awakening_bonus_icon) then | if not isempty(awakening_bonus_icon) then | ||
box:tag("div"):addClass("kr-hc-adv-icon") | box:tag("div"):addClass("kr-hc-adv-icon") | ||
| Zeile 237: | Zeile 265: | ||
end | end | ||
local main = box:tag("div"):addClass("kr-hc-adv-main") | local main = box:tag("div"):addClass("kr-hc-adv-main") | ||
main:tag("div"):addClass("kr-hc-adv-label"):wikitext(" | local lab = main:tag("div"):addClass("kr-hc-adv-label"):wikitext("Erweckungsbonus") | ||
if not showLabels then lab:addClass("is-hidden") end | |||
main:tag("div"):addClass("kr-hc-adv-value"):wikitext(awakening_bonus) | main:tag("div"):addClass("kr-hc-adv-value"):wikitext(awakening_bonus) | ||
end | end | ||
- | -- Debug | ||
if debugWanted then | if debugWanted then | ||
content:tag("pre"):addClass("kr-hc-debug") | content:tag("pre"):addClass("kr-hc-debug") | ||
:wikitext(mw.text.nowiki(mw.dumpObject({ | :wikitext(mw.text.nowiki(mw.dumpObject({name=name, data=data, module=info}))) | ||
end | end | ||
| Zeile 257: | Zeile 284: | ||
local out = mw.html.create("div") | local out = mw.html.create("div") | ||
if not (info and info.ok) then | if not (info and info.ok) then | ||
out:tag("p"):wikitext("HeroData NOT loaded. | out:tag("p"):wikitext("HeroData NOT loaded.") | ||
return tostring(out) | return tostring(out) | ||
end | end | ||
out:tag("p"):wikitext("HeroData loaded from: " .. info.from) | out:tag("p"):wikitext("HeroData loaded from: " .. info.from) | ||
local ul = out:tag("ul"); for | local ul = out:tag("ul"); for n,_ in pairs(heroes) do ul:tag("li"):wikitext(n) end | ||
return tostring(out) | return tostring(out) | ||
end | end | ||
return p | return p | ||
Version vom 9. Oktober 2025, 10:29 Uhr
Die Dokumentation für dieses Modul kann unter Modul:HeroCard/Doku erstellt werden
local p = {}
-- ======= CONFIG / DEFAULTS =======
local CFG = {
-- Haupt-/Erweiterte Attribute: Labels & Default-Icons (DE)
main_order = { "damage", "hp", "armor" },
main_meta = {
damage = { label = "Schaden", icon = "AttackIcon.png" },
hp = { label = "Gesundheit", icon = "HealthIcon.png" },
armor = { label = "Rüstung", icon = "ArmorIcon.png" },
},
adv_order = { "precision", "bonus_damage", "speed", "dodge" },
adv_meta = {
precision = { label = "Krit.-Chance", icon = "CriticalChanceIcon.png" },
bonus_damage = { label = "Kritischer Schaden", icon = "CriticalDamageIcon.png" },
speed = { label = "Angriffsgeschwindigkeit", icon = "AttackSpeedIcon.png" },
dodge = { label = "Ausweichen", icon = "DodgeIcon.png" },
},
-- Icon-Mapping nach Wert (case-/whitespace-insensitiv)
icon_map = {
attackstyle = {
melee = "MeleeIcon.png",
spellcaster = "SpellcasterIcon.png",
ranged = "RangedIcon.png",
},
specialization = {
healer = "HealerIcon.png",
damage = "DamageIcon.png",
tank = "TankIcon.png",
},
resource = {
mana = "ManaIcon.png",
rage = "RageIcon.png",
energy = "EnergyIcon.png",
},
awakening_bonus = {
["raining gold"] = "RainingGold.png",
["all main attributes"] = "AllAttributes.png",
prestigious = "Prestigious.png",
}
},
-- DE-Übersetzung der Werte aus HeroData
i18n = {
class = {
warrior="Krieger", paladin="Paladin", rouge="Schurke",
mage="Magier", druid="Druide", ranger="Waldläufer"
},
attackstyle = {
melee="Nahkampf", ranged="Fernkampf", spellcaster="Zauberwirker"
},
specialization = { healer="Heiler", damage="Schaden", tank="Tank" },
resource = { mana="Mana", rage="Wut", energy="Energie" },
awakening_bonus = {
["raining gold"]="Goldregen",
["all main attributes"]="Alle Hauptattribute",
prestigious="Prestigevoll"
}
}
}
-- ======= 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 (v == nil or v == "") then return v end
end
return nil
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
local function loadHeroes()
local tried, lastErr = {}, nil
for _,title in ipairs{ "Modul:HeroData", "Module:HeroData" } do
local ok, mod = pcall(require, title)
if ok and type(mod) == "table" and type(mod.heroes) == "table" then
return mod.heroes, { ok=true, from=title }
else
table.insert(tried, title); lastErr = mod
end
end
return nil, { ok=false, tried=tried, err=lastErr }
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
if opts and opts.lazy then table.insert(parts, "loading=lazy") end
return string.format("[[%s]]", table.concat(parts, "|"))
end
local function mapIcon(kind, value, override)
if not isempty(override) then return override end
local t = CFG.icon_map[kind] or {}
return t[norm(value)]
end
local function tr(kind, value)
if isempty(value) then return value end
local m = CFG.i18n[kind] or {}
return m[norm(value)] or value
end
-- Pill/Adv: Icon 36px, Label nur als Tooltip/hover
local function pill(htmlParent, label, val, icon, showLabels)
if isempty(val) then return end
local box = htmlParent:tag("div"):addClass("kr-hc-pill"):attr("title", label or "")
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)
end
local function adv(htmlParent, label, val, icon, showLabels)
if isempty(val) then return end
local box = htmlParent:tag("div"):addClass("kr-hc-adv"):attr("title", label or "")
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)
end
-- Freischaltung → sauberer DE-Text
local function unlock_text_de(s)
if s == nil or s == "" then return nil end
local t = mw.ustring.lower(mw.text.trim(s)):gsub("%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
-- Wenn es wie ein vollständiger eigener Satz aussieht → unverändert anzeigen
if s:match("[%.%!%?]$") or t:find(" ") then
return s
end
-- Neutraler Fallback
return "Freischaltung: " .. s
end
-- ======= RENDER =======
function p.render(frame)
local args = getArgs(frame)
local name = pick(args.name, args[1]) or ""
local heroes, info = loadHeroes()
local data = (heroes and (heroes[name] or heroes[mw.ustring.gsub(name or "", "_", " ")])) or {}
local debugWanted = norm(args.debug) == "1" or norm(args.debug) == "yes"
local showLabels = norm(args.show_labels) == "1" or norm(args.show_labels) == "yes"
-- Basics (Werte aus Data, ins DE übersetzen)
local class = tr("class", pick(args.class, data.class))
local attackstyleRaw = pick(args.attackstyle, data.attackstyle)
local specializationRaw = pick(args.specialization, data.specialization)
local resourceRaw = pick(args.resource, data.resource)
local attackstyle = tr("attackstyle", attackstyleRaw)
local specialization = tr("specialization", specializationRaw)
local resource = tr("resource", resourceRaw)
local unlock_at = pick(args.unlock_at, data.unlock_at)
local awakening_bonusRaw = pick(args.awakening_bonus, data.awakening_bonus)
local awakening_bonus = tr("awakening_bonus", awakening_bonusRaw)
-- Icons (kein Icon für class)
local attackstyle_icon = mapIcon("attackstyle", attackstyleRaw, pick(args.attackstyle_icon, data.attackstyle_icon))
local specialization_icon = mapIcon("specialization", specializationRaw, pick(args.specialization_icon, data.specialization_icon))
local resource_icon = mapIcon("resource", resourceRaw, pick(args.resource_icon, data.resource_icon))
local awakening_bonus_icon= mapIcon("awakening_bonus",awakening_bonusRaw,pick(args.awakening_bonus_icon,data.awakening_bonus_icon))
-- Bilder/Links
local linkto = pick(args.linkto, name)
local avatar = pick(args.avatar, (not isempty(name) and (name .. ".png")) or nil)
local root = mw.html.create("div"):addClass("kr-hero-card")
if showLabels then root:addClass("kr-show-labels") end
-- Avatar (links) – skaliert, lazy
root:tag("div"):addClass("kr-hc-avatar")
:wikitext(fileWikitext(avatar, { class="kr-hc-avatar-img", link=linkto, lazy=true }))
-- Content (rechts)
local content = root:tag("div"):addClass("kr-hc-content")
-- Titel: Name verlinkt + (Unlock DE)
if not isempty(name) then
local h = content:tag("h2"):addClass("kr-hc-name")
local unlock_text = unlock_text_de(unlock_at)
h:wikitext(string.format("[[%s|%s]]%s",
linkto, name,
unlock_text and (" <span class=\"kr-hc-unlock\">(" .. unlock_text .. ")</span>") or ""
))
end
if (not info or not info.ok) and debugWanted then
content:tag("div"):addClass("kr-hc-debug")
:wikitext("<strong>HeroData not loaded.</strong>")
end
-- Basics 2×2 (Icon rechts)
local basicsGrid = content:tag("div"):addClass("kr-hc-basics2")
local function pair(label, value, icon)
if isempty(value) then return end
local it = basicsGrid:tag("div"):addClass("kr-hc-basic")
it:tag("span"):addClass("label"):wikitext(label)
local v = it:tag("span"):addClass("value")
v:wikitext(value)
if not isempty(icon) then
v:tag("span"):addClass("value-icon")
:wikitext(fileWikitext(icon, { size="24x24px", link="", lazy=true }))
end
end
pair("Klasse:", class, nil)
pair("Spezialisierung:", specialization, specialization_icon)
pair("Angriffsart:", attackstyle, attackstyle_icon)
pair("Ressource:", resource, resource_icon)
-- Hauptattribute
content:tag("h3"):addClass("kr-hc-h"):wikitext("Hauptattribute")
local mains = content:tag("div"):addClass("kr-hc-main-attrs")
local heroMain= type(data.main) == "table" and data.main or {}
for i, key in ipairs(CFG.main_order) do
local meta = CFG.main_meta[key]
local val = pick(args["main"..i.."_val"], heroMain[key])
pill(mains, meta.label, val, pick(args["main"..i.."_icon"], meta.icon), showLabels)
end
-- Erweiterte Attribute
content:tag("h3"):addClass("kr-hc-h"):wikitext("Erweiterte Attribute")
local advs = content:tag("div"):addClass("kr-hc-adv-attrs")
local heroAdv= type(data.adv) == "table" and data.adv or {}
for i, key in ipairs(CFG.adv_order) do
local meta = CFG.adv_meta[key]
local val = pick(args["adv"..i.."_val"], heroAdv[key])
adv(advs, meta.label, val, pick(args["adv"..i.."_icon"], meta.icon), showLabels)
end
for i = #CFG.adv_order + 1, 8 do
local val = args["adv"..i.."_val"]
if isempty(val) then break end
adv(advs, args["adv"..i.."_label"] or "", val, args["adv"..i.."_icon"], showLabels)
end
-- Erweckungsbonus (Icon 64px) – nur Icon + Wert (Label per Hover)
if not isempty(awakening_bonus) then
content:tag("h3"):addClass("kr-hc-h"):wikitext("Erweckungsbonus")
local awk = content:tag("div"):addClass("kr-hc-awakening")
local box = awk:tag("div"):addClass("kr-hc-adv"):attr("title", "Erweckungsbonus")
if not isempty(awakening_bonus_icon) then
box:tag("div"):addClass("kr-hc-adv-icon")
:wikitext(fileWikitext(awakening_bonus_icon, { size="64x64px", 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("Erweckungsbonus")
if not showLabels then lab:addClass("is-hidden") end
main:tag("div"):addClass("kr-hc-adv-value"):wikitext(awakening_bonus)
end
-- Debug
if debugWanted then
content:tag("pre"):addClass("kr-hc-debug")
:wikitext(mw.text.nowiki(mw.dumpObject({name=name, data=data, module=info})))
end
return tostring(root)
end
-- Selbsttest
function p.selftest()
local heroes, info = loadHeroes()
local out = mw.html.create("div")
if not (info and info.ok) then
out:tag("p"):wikitext("HeroData NOT loaded.")
return tostring(out)
end
out:tag("p"):wikitext("HeroData loaded from: " .. info.from)
local ul = out:tag("ul"); for n,_ in pairs(heroes) do ul:tag("li"):wikitext(n) end
return tostring(out)
end
return p