Modul:Firestone: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| Zeile 4: | Zeile 4: | ||
-- ===== helpers ===== | -- ===== helpers ===== | ||
local function isempty(v) return v==nil or v=="" end | local function isempty(v) return v==nil or v=="" end | ||
local function norm(s) | local function norm(s) if s==nil then return "" end s=mw.text.trim(tostring(s)); return mw.ustring.lower(s):gsub("%s+"," ") end | ||
end | |||
local function getArgs(frame) | local function getArgs(frame) | ||
local a = {} | local a = {} | ||
local p = frame:getParent() | local p = frame:getParent() | ||
local src = (p and p.args) or frame.args or {} | local src = (p and p.args) or frame.args or {} | ||
for k, v in pairs(src) do | for k,v in pairs(src) do if v~=nil and v~="" then a[k]=mw.text.trim(tostring(v)) end end | ||
return a | return a | ||
end | end | ||
local function pick_key(tbl, key) | local function pick_key(tbl, key) | ||
if type(tbl)~="table" then return nil end | if type(tbl)~="table" then return nil end | ||
if tbl[key]~=nil then return key end | if tbl[key]~=nil then return key end | ||
local k2 = tostring(key) | local k2 = tostring(key); if tbl[k2]~=nil then return k2 end | ||
local kn = norm(k2); for k,_ in pairs(tbl) do if norm(k)==kn then return k end end | |||
local kn = norm(k2) | |||
return nil | return nil | ||
end | end | ||
| Zeile 42: | Zeile 30: | ||
local function fileWikitext(file, size) | local function fileWikitext(file, size) | ||
if isempty(file) then return "" end | if isempty(file) then return "" end | ||
local parts = {"Datei:"..file} | local parts = {"Datei:"..file}; if not isempty(size) then table.insert(parts, size) end | ||
return string.format("[[%s]]", table.concat(parts, "|")) | return string.format("[[%s]]", table.concat(parts, "|")) | ||
end | end | ||
| Zeile 49: | Zeile 36: | ||
-- ===== lazy loads ===== | -- ===== lazy loads ===== | ||
local HEROES, EVENTS, I18N | local HEROES, EVENTS, I18N | ||
local function heroes() | local function heroes() | ||
if HEROES then return HEROES end | if HEROES then return HEROES end | ||
for _,t in ipairs{ "Module:HeroData", "Modul:HeroData" } do | for _,t in ipairs{ "Module:HeroData","Modul:HeroData" } do | ||
local ok, | local ok,d = pcall(mw.loadData,t); if ok and type(d)=="table" and type(d.heroes)=="table" then HEROES=d.heroes;return HEROES end | ||
local ok2,m=pcall(require,t); if ok2 and type(m)=="table" and type(m.heroes)=="table" then HEROES=m.heroes;return HEROES end | |||
local ok2, | end; HEROES={}; return HEROES | ||
end | |||
end | end | ||
local function events() | local function events() | ||
if EVENTS then return EVENTS end | if EVENTS then return EVENTS end | ||
for _,t in ipairs{ "Module:EventData","Modul:EventData" } do | |||
for _,t in ipairs{ "Module:EventData", "Modul:EventData" } do | local ok,d=pcall(mw.loadData,t); if ok and type(d)=="table" and type(d.events)=="table" then EVENTS=d.events;return EVENTS end | ||
local ok, | |||
end | end | ||
EVENTS = {}; return EVENTS | for _,t in ipairs{ "Module:EventData","Modul:EventData" } do | ||
local ok,m=pcall(require,t); if ok and type(m)=="table" and type(m.events)=="table" then EVENTS=m.events;return EVENTS end | |||
end; EVENTS={}; return EVENTS | |||
end | end | ||
local function i18n() | local function i18n() | ||
if I18N then return I18N end | if I18N then return I18N end | ||
for _,t in ipairs{ "Module:HeroI18n", "Modul:HeroI18n" } do | for _,t in ipairs{ "Module:HeroI18n","Modul:HeroI18n" } do | ||
local ok, | local ok,d=pcall(mw.loadData,t); if ok and type(d)=="table" then I18N=d;return I18N end | ||
local ok2,m=pcall(require,t); if ok2 and type(m)=="table" then I18N=m;return I18N end | |||
local ok2, | |||
end | end | ||
I18N = { i18n={}, events={names={},sections={},infobox={},phrases={}} } | I18N={ i18n={}, events={names={},sections={},infobox={},phrases={}} }; return I18N | ||
end | end | ||
-- ===== translations ===== | -- ===== translations & helpers ===== | ||
local function tr(kind, v) | local function tr(kind, v) if isempty(v) then return v end local map=(i18n().i18n or {})[kind] or {}; return map[norm(v)] or v end | ||
local function tr_currency(k) return tr("currency",k) end | |||
local function tr_event_name(k) local names=(i18n().events or {}).names or {}; return names[norm(k)] or k end | |||
end | |||
local function tr_currency(k) return tr("currency", k) end | |||
local function tr_event_name(k) | |||
end | |||
local function section_label(evkey, which) | local function section_label(evkey, which) | ||
local E = i18n().events or {} | local E=i18n().events or {}; local ev=(E.sections and E.sections[norm(evkey)]) or {}; local def=(E.sections and E.sections.default) or {} | ||
return (ev[which] or def[which] or "") | return (ev[which] or def[which] or "") | ||
end | end | ||
local function month_tr(s) local map=((i18n().i18n or {}).month) or {}; return map[norm(s or "")] or (s or "") end | |||
local function format_unlocked(raw) | |||
local function | local P=(i18n().events or {}).phrases or {}; local tpl=P.character_level or "Level $1" | ||
local | local n=tostring(raw or ""):match("^character_level_(%d+)$"); if n then return (tpl:gsub("%$1",n)) end | ||
local | return raw or "" | ||
return | |||
end | end | ||
local function resolve_event(key) local evs=events(); local real=pick_key(evs,key); return real and evs[real] or nil end | |||
-- | -- Drop-Block rendern | ||
- | local function render_drop(ev) | ||
local function | local D=ev.drop or {}; local P=(i18n().events or {}).phrases or {}; local token_key=ev.token and ev.token.key or ""; local lines={} | ||
local | if D.base and D.base.amount and D.base.period then | ||
table.insert(lines, "* "..(P.drop_rate_base or "Drop-Rate: $1 $2 alle $3 (Basis).") | |||
:gsub("%$1",tostring(D.base.amount)):gsub("%$2",tr_currency(token_key)):gsub("%$3",tostring(D.base.period))) | |||
end | |||
if D.boost and D.boost.amount and D.boost.period then | |||
table.insert(lines, "* "..(P.drop_rate_boost or "Drop-Rate: $1 $2 alle $3 (nach Kauf).") | |||
:gsub("%$1",tostring(D.boost.amount)):gsub("%$2",tr_currency(token_key)):gsub("%$3",tostring(D.boost.period))) | |||
end | |||
if D.base_daily_gain then | |||
if | table.insert(lines, "* "..(P.fixed_daily_gain or "Fester Zuwachs: $1 $2 pro Tag.") | ||
:gsub("%$1",tostring(D.base_daily_gain)):gsub("%$2",tr_currency(token_key))) | |||
end | |||
if D.offline_cap then | |||
table.insert(lines, "* "..(P.offline_cap or "Offline-Gewinne sind auf $1 begrenzt.") | |||
:gsub("%$1",tostring(D.offline_cap))) | |||
end | |||
- | |||
if | |||
end | end | ||
return table.concat(lines,"\n") | |||
end | end | ||
-- | -- Avatartabellen | ||
local function | local function render_avatar_year(ev, year) | ||
local list = ev.avatars and ev.avatars[year]; if type(list)~="table" then return "" end | local list = ev.avatars and ev.avatars[year]; if type(list)~="table" then return "" end | ||
local token_key=ev.token and ev.token.key or ""; local token_icon=ev.token and ev.token.icon or "" | |||
local token_key = ev.token and ev.token.key or "" | local out={} | ||
local out = {} | |||
table.insert(out, '{| class="article-table" style="font-size:14px;"') | table.insert(out, '{| class="article-table" style="font-size:14px;"') | ||
table.insert(out, '! colspan="2" | Avatar\n! Preis') | table.insert(out, '! colspan="2" | Avatar\n! Preis') | ||
| Zeile 188: | Zeile 109: | ||
table.insert(out, '|-') | table.insert(out, '|-') | ||
table.insert(out, string.format('|%s || %s || %s %s %s', | table.insert(out, string.format('|%s || %s || %s %s %s', | ||
fileWikitext(it.file, "50px"), | fileWikitext(it.file,"50px"), it.title or "", | ||
fileWikitext(token_icon,"25px"), tostring(it.cost or 0), tr_currency(token_key))) | |||
fileWikitext(token_icon, "25px"), | |||
end | end | ||
table.insert(out, '|}') | table.insert(out, '|}') | ||
| Zeile 199: | Zeile 116: | ||
end | end | ||
local function render_avatars_all(ev) | |||
local function | local A = ev.avatars or {}; local years={} | ||
local | for y,_ in pairs(A) do table.insert(years, tonumber(y) or y) end | ||
local | table.sort(years) | ||
local H = ev.history or {}; if #H==0 then return "" end | local out={} | ||
local P = (i18n().events or {}).phrases or {} | for _,y in ipairs(years) do | ||
table.insert(out, string.format("==== %s ====\n%s", tostring(y), render_avatar_year(ev, y))) | |||
local lines = {} | end | ||
return table.concat(out, "\n") | |||
end | |||
-- History | |||
local function render_history(ev) | |||
local H=ev.history or {}; if #H==0 then return "" end | |||
local P=(i18n().events or {}).phrases or {}; local alt_on_gp=P.alt_platform or "auf Google Play" | |||
local lines={} | |||
for _,h in ipairs(H) do | for _,h in ipairs(H) do | ||
local base = string.format("* %s: %s bis %s", tostring(h.year or ""), tostring(h.start or ""), tostring(h['end'] or "")) | local base = string.format("* %s: %s bis %s", tostring(h.year or ""), tostring(h.start or ""), tostring(h['end'] or "")) | ||
| Zeile 215: | Zeile 140: | ||
end | end | ||
-- ===== feature: | -- ===== feature: Event (einheitlich) ===== | ||
-- {{Firestone| | -- {{Firestone|Event|halloween|...}} | ||
local function fn_event(args) | |||
local function | local key=args[2]; if isempty(key) then return "" end | ||
local | local ev=resolve_event(key); if not ev then return "" end | ||
local | if not args[3] then return "" end | ||
if | -- Labels (Pseudo-Namespace) | ||
if args[3]=="@infobox" and args[4] then | |||
local E=i18n().events or {}; local lbl=(E.infobox and E.infobox[args[4]]) or ""; return tostring(lbl or "") | |||
end | |||
if args[3]=="@section" and args[4] then | |||
return section_label(key, args[4]) | |||
end | |||
-- Pfad/Key | |||
local path, i = {}, 3 | local path, i = {}, 3 | ||
while args[i] do table.insert(path, args[i]); i=i+1 end | while args[i] do table.insert(path,args[i]); i=i+1 end | ||
local last = norm(path[#path] or "") | local last = norm(path[#path] or "") | ||
if last=="class" then return tr("class", v) or "" | |||
elseif last=="attackstyle" then return tr("attackstyle", v) or "" | -- bequemer Alias | ||
elseif last=="specialization" then return tr("specialization", v) or "" | if last=="month" then path[#path]="date"; last="date" end | ||
elseif last=="resource" then return tr("resource", v) or "" | if last=="name" then return tr_event_name(key) or section_label(key,"name") end | ||
if last=="history" then return render_history(ev) end | |||
if last=="avatars" then | |||
local year = tonumber(path[4] or "") | |||
if year then return render_avatar_year(ev, year) else return render_avatars_all(ev) end | |||
end | |||
if last=="drop" then return render_drop(ev) end | |||
-- normaler Wert | |||
local v = deep_get(ev, path) | |||
if last=="date" then | |||
v = month_tr(v) | |||
elseif last=="unlocks_at" then | |||
v = format_unlocked(v) | |||
elseif last=="type" then | |||
local map=((i18n().events or {}).infobox or {}).type or {}; v = map[norm(v or "")] or (v or "") | |||
end | |||
if type(v)=="string" then v=mw.text.trim(v) end | |||
return tostring(v or "") | |||
end | |||
-- ===== feature: currency / hero (bleibt) ===== | |||
local function fn_currency(args) local key=args[2]; if isempty(key) then return "" end; return tostring(tr_currency(key) or "") end | |||
local function fn_hero(args) | |||
local name=args[2]; if isempty(name) then return "" end | |||
local H=heroes(); local real=pick_key(H,name); if not real then return "" end | |||
local hero=H[real]; if not hero then return "" end | |||
local path,i={},3; while args[i] do table.insert(path,args[i]); i=i+1 end | |||
local v=deep_get(hero,path); local last=norm(path[#path] or "") | |||
if last=="class" then return tr("class",v) or "" | |||
elseif last=="attackstyle" then return tr("attackstyle",v) or "" | |||
elseif last=="specialization" then return tr("specialization",v) or "" | |||
elseif last=="resource" then return tr("resource",v) or "" | |||
else return tostring(v or "") end | else return tostring(v or "") end | ||
end | end | ||
| Zeile 237: | Zeile 202: | ||
-- ===== main dispatcher ===== | -- ===== main dispatcher ===== | ||
function M.main(frame) | function M.main(frame) | ||
local a = getArgs(frame) | local a=getArgs(frame); for i=1,10 do a[i]=a[i] and tostring(a[i]) or nil end | ||
local dom=a[1] and norm(a[1]) or "" | |||
local dom = a[1] and norm(a[1]) or "" | if dom=="event" then return fn_event(a) | ||
elseif dom=="currency" then return fn_currency(a) | |||
if | elseif dom=="hero" then return fn_hero(a) | ||
else return "" end | |||
elseif dom==" | |||
elseif dom=="hero" then return fn_hero(a) | |||
else | |||
end | end | ||
return M | return M | ||
Version vom 19. Oktober 2025, 16:25 Uhr
Die Dokumentation für dieses Modul kann unter Modul:Firestone/Doku erstellt werden
-- Modul:Firestone
local M = {}
-- ===== helpers =====
local function isempty(v) return v==nil or v=="" end
local function norm(s) if s==nil then return "" end s=mw.text.trim(tostring(s)); return mw.ustring.lower(s):gsub("%s+"," ") end
local function getArgs(frame)
local a = {}
local p = frame:getParent()
local src = (p and p.args) or frame.args or {}
for k,v in pairs(src) do if v~=nil and v~="" then a[k]=mw.text.trim(tostring(v)) end end
return a
end
local function pick_key(tbl, key)
if type(tbl)~="table" then return nil end
if tbl[key]~=nil then return key end
local k2 = tostring(key); if tbl[k2]~=nil then return k2 end
local kn = norm(k2); for k,_ in pairs(tbl) do if norm(k)==kn then return k end end
return nil
end
local function deep_get(tbl, path)
local cur = tbl
for _,k in ipairs(path) do
if type(cur)~="table" then return nil end
local real = pick_key(cur, k); if not real then return nil end
cur = cur[real]
end
return cur
end
local function fileWikitext(file, size)
if isempty(file) then return "" end
local parts = {"Datei:"..file}; if not isempty(size) then table.insert(parts, size) end
return string.format("[[%s]]", table.concat(parts, "|"))
end
-- ===== lazy loads =====
local HEROES, EVENTS, I18N
local function heroes()
if HEROES then return HEROES end
for _,t in ipairs{ "Module:HeroData","Modul:HeroData" } do
local ok,d = pcall(mw.loadData,t); if ok and type(d)=="table" and type(d.heroes)=="table" then HEROES=d.heroes;return HEROES end
local ok2,m=pcall(require,t); if ok2 and type(m)=="table" and type(m.heroes)=="table" then HEROES=m.heroes;return HEROES end
end; HEROES={}; return HEROES
end
local function events()
if EVENTS then return EVENTS end
for _,t in ipairs{ "Module:EventData","Modul:EventData" } do
local ok,d=pcall(mw.loadData,t); if ok and type(d)=="table" and type(d.events)=="table" then EVENTS=d.events;return EVENTS end
end
for _,t in ipairs{ "Module:EventData","Modul:EventData" } do
local ok,m=pcall(require,t); if ok and type(m)=="table" and type(m.events)=="table" then EVENTS=m.events;return EVENTS end
end; EVENTS={}; return EVENTS
end
local function i18n()
if I18N then return I18N end
for _,t in ipairs{ "Module:HeroI18n","Modul:HeroI18n" } do
local ok,d=pcall(mw.loadData,t); if ok and type(d)=="table" then I18N=d;return I18N end
local ok2,m=pcall(require,t); if ok2 and type(m)=="table" then I18N=m;return I18N end
end
I18N={ i18n={}, events={names={},sections={},infobox={},phrases={}} }; return I18N
end
-- ===== translations & helpers =====
local function tr(kind, v) if isempty(v) then return v end local map=(i18n().i18n or {})[kind] or {}; return map[norm(v)] or v end
local function tr_currency(k) return tr("currency",k) end
local function tr_event_name(k) local names=(i18n().events or {}).names or {}; return names[norm(k)] or k end
local function section_label(evkey, which)
local E=i18n().events or {}; local ev=(E.sections and E.sections[norm(evkey)]) or {}; local def=(E.sections and E.sections.default) or {}
return (ev[which] or def[which] or "")
end
local function month_tr(s) local map=((i18n().i18n or {}).month) or {}; return map[norm(s or "")] or (s or "") end
local function format_unlocked(raw)
local P=(i18n().events or {}).phrases or {}; local tpl=P.character_level or "Level $1"
local n=tostring(raw or ""):match("^character_level_(%d+)$"); if n then return (tpl:gsub("%$1",n)) end
return raw or ""
end
local function resolve_event(key) local evs=events(); local real=pick_key(evs,key); return real and evs[real] or nil end
-- Drop-Block rendern
local function render_drop(ev)
local D=ev.drop or {}; local P=(i18n().events or {}).phrases or {}; local token_key=ev.token and ev.token.key or ""; local lines={}
if D.base and D.base.amount and D.base.period then
table.insert(lines, "* "..(P.drop_rate_base or "Drop-Rate: $1 $2 alle $3 (Basis).")
:gsub("%$1",tostring(D.base.amount)):gsub("%$2",tr_currency(token_key)):gsub("%$3",tostring(D.base.period)))
end
if D.boost and D.boost.amount and D.boost.period then
table.insert(lines, "* "..(P.drop_rate_boost or "Drop-Rate: $1 $2 alle $3 (nach Kauf).")
:gsub("%$1",tostring(D.boost.amount)):gsub("%$2",tr_currency(token_key)):gsub("%$3",tostring(D.boost.period)))
end
if D.base_daily_gain then
table.insert(lines, "* "..(P.fixed_daily_gain or "Fester Zuwachs: $1 $2 pro Tag.")
:gsub("%$1",tostring(D.base_daily_gain)):gsub("%$2",tr_currency(token_key)))
end
if D.offline_cap then
table.insert(lines, "* "..(P.offline_cap or "Offline-Gewinne sind auf $1 begrenzt.")
:gsub("%$1",tostring(D.offline_cap)))
end
return table.concat(lines,"\n")
end
-- Avatartabellen
local function render_avatar_year(ev, year)
local list = ev.avatars and ev.avatars[year]; if type(list)~="table" then return "" end
local token_key=ev.token and ev.token.key or ""; local token_icon=ev.token and ev.token.icon or ""
local out={}
table.insert(out, '{| class="article-table" style="font-size:14px;"')
table.insert(out, '! colspan="2" | Avatar\n! Preis')
for _,it in ipairs(list) do
table.insert(out, '|-')
table.insert(out, string.format('|%s || %s || %s %s %s',
fileWikitext(it.file,"50px"), it.title or "",
fileWikitext(token_icon,"25px"), tostring(it.cost or 0), tr_currency(token_key)))
end
table.insert(out, '|}')
return table.concat(out, "\n")
end
local function render_avatars_all(ev)
local A = ev.avatars or {}; local years={}
for y,_ in pairs(A) do table.insert(years, tonumber(y) or y) end
table.sort(years)
local out={}
for _,y in ipairs(years) do
table.insert(out, string.format("==== %s ====\n%s", tostring(y), render_avatar_year(ev, y)))
end
return table.concat(out, "\n")
end
-- History
local function render_history(ev)
local H=ev.history or {}; if #H==0 then return "" end
local P=(i18n().events or {}).phrases or {}; local alt_on_gp=P.alt_platform or "auf Google Play"
local lines={}
for _,h in ipairs(H) do
local base = string.format("* %s: %s bis %s", tostring(h.year or ""), tostring(h.start or ""), tostring(h['end'] or ""))
if h.alt_platform then base = base .. string.format(" (%s %s)", tostring(h.alt_platform), alt_on_gp) end
table.insert(lines, base)
end
return table.concat(lines, "\n")
end
-- ===== feature: Event (einheitlich) =====
-- {{Firestone|Event|halloween|...}}
local function fn_event(args)
local key=args[2]; if isempty(key) then return "" end
local ev=resolve_event(key); if not ev then return "" end
if not args[3] then return "" end
-- Labels (Pseudo-Namespace)
if args[3]=="@infobox" and args[4] then
local E=i18n().events or {}; local lbl=(E.infobox and E.infobox[args[4]]) or ""; return tostring(lbl or "")
end
if args[3]=="@section" and args[4] then
return section_label(key, args[4])
end
-- Pfad/Key
local path, i = {}, 3
while args[i] do table.insert(path,args[i]); i=i+1 end
local last = norm(path[#path] or "")
-- bequemer Alias
if last=="month" then path[#path]="date"; last="date" end
if last=="name" then return tr_event_name(key) or section_label(key,"name") end
if last=="history" then return render_history(ev) end
if last=="avatars" then
local year = tonumber(path[4] or "")
if year then return render_avatar_year(ev, year) else return render_avatars_all(ev) end
end
if last=="drop" then return render_drop(ev) end
-- normaler Wert
local v = deep_get(ev, path)
if last=="date" then
v = month_tr(v)
elseif last=="unlocks_at" then
v = format_unlocked(v)
elseif last=="type" then
local map=((i18n().events or {}).infobox or {}).type or {}; v = map[norm(v or "")] or (v or "")
end
if type(v)=="string" then v=mw.text.trim(v) end
return tostring(v or "")
end
-- ===== feature: currency / hero (bleibt) =====
local function fn_currency(args) local key=args[2]; if isempty(key) then return "" end; return tostring(tr_currency(key) or "") end
local function fn_hero(args)
local name=args[2]; if isempty(name) then return "" end
local H=heroes(); local real=pick_key(H,name); if not real then return "" end
local hero=H[real]; if not hero then return "" end
local path,i={},3; while args[i] do table.insert(path,args[i]); i=i+1 end
local v=deep_get(hero,path); local last=norm(path[#path] or "")
if last=="class" then return tr("class",v) or ""
elseif last=="attackstyle" then return tr("attackstyle",v) or ""
elseif last=="specialization" then return tr("specialization",v) or ""
elseif last=="resource" then return tr("resource",v) or ""
else return tostring(v or "") end
end
-- ===== main dispatcher =====
function M.main(frame)
local a=getArgs(frame); for i=1,10 do a[i]=a[i] and tostring(a[i]) or nil end
local dom=a[1] and norm(a[1]) or ""
if dom=="event" then return fn_event(a)
elseif dom=="currency" then return fn_currency(a)
elseif dom=="hero" then return fn_hero(a)
else return "" end
end
return M