Zum Inhalt springen


Modul:Firestone: Unterschied zwischen den Versionen

Aus Firestone Idle RPG Wiki
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 10: Zeile 10:
end
end


-- bevorzugt Parent-Args (typisch bei Vorlagen)
local function getArgs(frame)
local function getArgs(frame)
   local p = frame:getParent()
   local p = frame:getParent()
Zeile 38: Zeile 39:
end
end


local function fileTag(file, opts)
local function fileTag(file, opts) -- [[File:...]]
   if isempty(file) then return "" end
   if isempty(file) then return "" end
   local parts = { "Datei:"..file }
   local parts = { "Datei:"..file }
   if opts and opts.size  then table.insert(parts, opts.size) end
   if opts and opts.size  then table.insert(parts, opts.size) end
   if opts and opts.param  then table.insert(parts, opts.param) end
   if opts and opts.param  then table.insert(parts, opts.param) end -- z.B. "thumb|Text"
   return string.format("[[%s]]", table.concat(parts, "|"))
   return string.format("[[%s]]", table.concat(parts, "|"))
end
end
Zeile 54: Zeile 55:
     local ok2, mod = pcall(require, t)      ; if ok2 and type(mod) =="table" then I18N=mod ; return I18N end
     local ok2, mod = pcall(require, t)      ; if ok2 and type(mod) =="table" then I18N=mod ; return I18N end
   end
   end
   I18N = { i18n={}, events={ names={}, sections={default={}}, infobox={}, links={}, phrases={}, unlocks={} } }
  -- Minimal-Struktur, keine Text-Fallbacks
   I18N = { i18n={}, events={ names={}, sections={default={}}, infobox={}, links={}, units={}, unlocks={} } }
   return I18N
   return I18N
end
end
Zeile 80: Zeile 82:
   return map[norm(key)] or key
   return map[norm(key)] or key
end
end
local function tr_month(m)    return tr_simple("month", m) end
local function tr_month(m)    return tr_simple("month", m) end
local function tr_duration(d) return tr_simple("duration", d) end
local function tr_duration(d) return tr_simple("duration", d) end
Zeile 89: Zeile 92:
   return (spec[which] or def[which] or "")
   return (spec[which] or def[which] or "")
end
end
local function ev_name(evkey)
local function ev_name(evkey)
   local names = (i18n().events or {}).names or {}
   local names = (i18n().events or {}).names or {}
Zeile 101: Zeile 105:
end
end


-- nur die in der Vorlage verwendeten Keys
-- Plain fields exakt nach deinen Keys
local function event_field(ev, key, evkey)
local function event_field(ev, key, evkey)
   if key == "banner" then
   if key == "banner" then return ev.banner or ""
    return ev.banner or ""
   elseif key == "type" then
   elseif key == "type" then
     local t = ev.type or ""
     local t = ev.type or ""
     local map = ((i18n().events or {}).infobox or {}).type or {}
     local tr = (((i18n().events or {}).infobox or {}).type or {})[norm(t)]
    return map[norm(t)] or t
    return tr or t
   elseif key == "month" then
   elseif key == "month" then
     return tr_month(ev.month or ev.date or "")
     return tr_month(ev.month or ev.date or "")
Zeile 114: Zeile 117:
     return tr_duration(ev.duration or "")
     return tr_duration(ev.duration or "")
   elseif key == "character_level_10" then
   elseif key == "character_level_10" then
     local u = ((i18n().events or {}).unlocks or {})["character_level_10"]
    -- reine Übersetzung, kein Fallback-Text
     return u or ""                       -- kein Fallback-Text
     local f = (i18n().events or {}).unlocks or {}
     return f.character_level_10 or ""
   elseif key == "currency" or key == "currencies"
   elseif key == "currency" or key == "currencies"
       or key == "ex_shop" or key=="shop" or key=="shopname"
       or key == "ex_shop" or key == "shop" or key == "shopname"
       or key=="fullname" or key=="shortname"
       or key == "fullname" or key == "shortname"
       or key=="currency_exchange" or key=="avatar_exchange"
       or key == "currency_exchange" or key == "avatar_exchange"
       or key=="name" or key=="eventname" then
       or key == "name" or key == "eventname" then
     local k = (key == "eventname") and "name" or key
     local k = (key == "eventname") and "name" or key
     return ev_label(evkey, k)
     return ev_label(evkey, k)
Zeile 128: Zeile 132:
end
end


-- ==/=== Überschriften ==
local function htag(level, text)
local function htag(level, text)
   if isempty(text) then return "" end
   if isempty(text) then return "" end
Zeile 134: Zeile 139:
end
end


-- [[File:...|thumb|...]]
local function event_file(ev, evkey, which)
local function event_file(ev, evkey, which)
   if which=="deco" then
   if which=="deco" then
Zeile 153: Zeile 159:
end
end


local function event_link(ev, evkey, which)
-- History → mit Zeilenumbrüchen um Block-Markup sicher zu rendern
  if which=="type" then
    local page = (((i18n().events or {}).links or {}).type or {})[norm(ev.type or "")]
    if isempty(page) then return event_field(ev, "type", evkey) end
    return string.format("[[%s|%s]]", page, event_field(ev, "type", evkey))
  end
  return ""
end
 
local function event_history(ev)
local function event_history(ev)
   local H = ev.history or {}; if #H==0 then return "" end
   local H = ev.history
   local alt_gp = ((i18n().events or {}).phrases or {}).alt_platform or ""
  if type(H) ~= "table" or H[1] == nil then return "" end
  local t = {}
   local lines = {}
   for _,h in ipairs(H) do
   for _,h in ipairs(H) do
     local line = 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",
     if h.alt_platform and alt_gp ~= "" then
      tostring(h.year or ""), tostring(h.start or ""), tostring(h["end"] or ""))
       line = line .. string.format(" (%s %s)", tostring(h.alt_platform), alt_gp)
     if h.alt_platform then
       base = base .. " (" .. tostring(h.alt_platform) .. ")"
     end
     end
     table.insert(t, line)
     table.insert(lines, base)
   end
   end
   return "\n"..table.concat(t, "\n").."\n"
   return "\n" .. table.concat(lines, "\n") .. "\n"
end
end


-- Avatare (alle Jahre) → ebenfalls mit Newlines einrahmen
local function event_avatars(ev, evkey)
local function event_avatars(ev, evkey)
   local AV = ev.avatars or {}
   local AV = ev.avatars or {}
  if next(AV) == nil then return "" end
   local token_icon = ev.currency and ev.currency.icon or ""
   local token_icon = ev.currency and ev.currency.icon or ""
   local token_name = event_field(ev, "currencies", evkey)
   local token_name = event_field(ev, "currencies", evkey)
Zeile 199: Zeile 200:
     table.insert(out, "|}")
     table.insert(out, "|}")
   end
   end
   return table.concat(out, "\n")
   return "\n" .. table.concat(out, "\n") .. "\n"
end
end


-- Exchange-Tabellen
local function event_exchange(ev, evkey)
local function event_exchange(ev, evkey)
   local ex = ev.exchange or {}
   local ex = ev.exchange or {}
  if next(ex) == nil then return "" end
   local token_icon = (ev.currency or {}).icon or ""
   local token_icon = (ev.currency or {}).icon or ""
   local token_name = event_field(ev, "currencies", evkey)
   local token_name = event_field(ev, "currencies", evkey)


   local function table_for(list, header)
   local function table_for(list, header)
     if type(list) ~= "table" or #list==0 then return "" end
     if type(list) ~= "table" or list[1]==nil then return "" end
     local t = {}
     local t = {}
     table.insert(t, '{| class="article-table" style="font-size:14px;"')
     table.insert(t, '{| class="article-table" style="font-size:14px;"')
Zeile 229: Zeile 232:


   local parts = {}
   local parts = {}
   if ex.chests_by_level then table.insert(parts, table_for(ex.chests_by_level, "Angebot")) end
   if ex.chests_by_level then table.insert(parts, table_for(ex.chests_by_level, "Angebot")) end
   if ex.chests_by_stars then table.insert(parts, table_for(ex.chests_by_stars, "Angebot")) end
   if ex.chests_by_stars then table.insert(parts, table_for(ex.chests_by_stars, "Angebot")) end
   if ex.chests_by_oracle then table.insert(parts, table_for(ex.chests_by_oracle, "Angebot")) end
   if ex.chests_by_oracle then table.insert(parts, table_for(ex.chests_by_oracle, "Angebot")) end
   if ex.currencies     then table.insert(parts, table_for(ex.currencies,     "Angebot")) end
   if ex.currencies     then table.insert(parts, table_for(ex.currencies,     "Angebot")) end
   return table.concat(parts, "\n")
   return (#parts>0) and ("\n"..table.concat(parts, "\n").."\n") or ""
end
end


-- Shop-Angebote
local function event_offers(ev, evkey, which)
local function event_offers(ev, evkey, which)
   local list = (ev.shop or {})[which]
   local list = (ev.shop or {})[which]
   if type(list) ~= "table" or #list==0 then return "" end
   if type(list) ~= "table" or list[1]==nil then return "" end
   local token_icon = (ev.currency or {}).icon or ""
   local token_icon = (ev.currency or {}).icon or ""
   local token_name = event_field(ev, "currencies", evkey)
   local token_name = event_field(ev, "currencies", evkey)
Zeile 244: Zeile 248:
   local t = {}
   local t = {}
   table.insert(t, '{| class="article-table" style="font-size:14px;"')
   table.insert(t, '{| class="article-table" style="font-size:14px;"')
   table.insert(t, "! Angebot !! Preis")
   table.insert(t, "! Angebot !! Menge")
   for _,it in ipairs(list) do
   for _,it in ipairs(list) do
     table.insert(t, "|-")
     table.insert(t, "|-")
Zeile 256: Zeile 260:
   end
   end
   table.insert(t, "|}")
   table.insert(t, "|}")
   return table.concat(t, "\n")
   return "\n" .. table.concat(t, "\n") .. "\n"
end
end


-- ===== dispatcher =====
-- ===== main dispatcher for Event =====
local function dispatch_event(args)
local function dispatch_event(args)
   local evkey = args[2]; if isempty(evkey) then return "" end
   local evkey = args[2]; if isempty(evkey) then return "" end
Zeile 269: Zeile 273:
   end
   end


  -- plain fields & labels (inkl. 'shop')
   if a3=="banner" or a3=="type" or a3=="month" or a3=="duration"
   if a3=="banner" or a3=="type" or a3=="month" or a3=="duration"
     or a3=="character_level_10"
     or a3=="character_level_10"
Zeile 279: Zeile 284:
   end
   end


  -- file / headings
   if a3=="file" then return event_file(ev, realkey, a4 or "")
   if a3=="file" then return event_file(ev, realkey, a4 or "")
  elseif a3=="link" then return event_link(ev, realkey, a4 or "")
   elseif a3=="h2"  then return htag(2, ev_label(realkey, a4 or ""))
   elseif a3=="h2"  then return htag(2, ev_label(realkey, a4 or ""))
   elseif a3=="h3"  then return htag(3, ev_label(realkey, a4 or "")) end
   elseif a3=="h3"  then return htag(3, ev_label(realkey, a4 or "")) end


  -- composed blocks
   if a3=="history"  then return event_history(ev)
   if a3=="history"  then return event_history(ev)
   elseif a3=="avatars" then return event_avatars(ev, realkey)
   elseif a3=="avatars" then return event_avatars(ev, realkey)
   elseif a3=="exchange" then return event_exchange(ev, realkey)
   elseif a3=="exchange" then return event_exchange(ev, realkey)
   elseif a3=="offers" and (a4=="start" or a4=="more") then
   elseif a3=="offers" and (a4=="start" or a4=="more") then
Zeile 294: Zeile 300:
end
end


-- ===== hero (für Vollständigkeit) =====
local function dispatch_hero(args)
local function dispatch_hero(args)
   local name = args[2]; if isempty(name) then return "" end
   local name = args[2]; if isempty(name) then return "" end
Zeile 305: Zeile 312:
end
end


-- ===== main =====
function M.main(frame)
function M.main(frame)
   local a = getArgs(frame)
   local a = getArgs(frame)

Version vom 20. Oktober 2025, 20:00 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

-- bevorzugt Parent-Args (typisch bei Vorlagen)
local function getArgs(frame)
  local p = frame:getParent()
  local src = (p and p.args) or frame.args or {}
  local a = {}
  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 fileTag(file, opts) -- [[File:...]]
  if isempty(file) then return "" end
  local parts = { "Datei:"..file }
  if opts and opts.size   then table.insert(parts, opts.size) end
  if opts and opts.param  then table.insert(parts, opts.param) end -- z.B. "thumb|Text"
  return string.format("[[%s]]", table.concat(parts, "|"))
end

-- ========= lazy loads =========
local I18N, EVENTS, HEROES
local function i18n()
  if I18N then return I18N end
  for _,t in ipairs{ "Modul:HeroI18n", "Module:HeroI18n" } do
    local ok, data = pcall(mw.loadData, t) ; if ok and type(data)=="table" then I18N=data; return I18N end
    local ok2, mod = pcall(require, t)      ; if ok2 and type(mod) =="table" then I18N=mod ; return I18N end
  end
  -- Minimal-Struktur, keine Text-Fallbacks
  I18N = { i18n={}, events={ names={}, sections={default={}}, infobox={}, links={}, units={}, unlocks={} } }
  return I18N
end
local function events()
  if EVENTS then return EVENTS end
  for _,t in ipairs{ "Modul:EventData", "Module:EventData" } do
    local ok, data = pcall(mw.loadData, t) ; if ok and type(data)=="table" and type(data.events)=="table" then EVENTS=data.events; return EVENTS end
    local ok2, mod = pcall(require, t)     ; if ok2 and type(mod) =="table" and type(mod.events)=="table" then EVENTS=mod.events ; return EVENTS end
  end
  EVENTS = {}; return EVENTS
end
local function heroes()
  if HEROES then return HEROES end
  for _,t in ipairs{ "Modul:HeroData", "Module:HeroData" } do
    local ok, data = pcall(mw.loadData, t) ; if ok and type(data)=="table" and type(data.heroes)=="table" then HEROES=data.heroes; return HEROES end
    local ok2, mod = pcall(require, t)     ; if ok2 and type(mod) =="table" and type(mod.heroes)=="table" then HEROES=mod.heroes ; return HEROES end
  end
  HEROES = {}; return HEROES
end

-- ========= i18n helpers =========
local function tr_simple(kind, key)
  if isempty(key) then return "" end
  local map = (i18n().i18n or {})[kind] or {}
  return map[norm(key)] or key
end

local function tr_month(m)    return tr_simple("month", m) end
local function tr_duration(d) return tr_simple("duration", d) end

local function ev_label(evkey, which)
  local E = i18n().events or {}
  local spec = (E.sections and E.sections[norm(evkey)]) or {}
  local def  = (E.sections and E.sections.default) or {}
  return (spec[which] or def[which] or "")
end

local function ev_name(evkey)
  local names = (i18n().events or {}).names or {}
  return names[norm(evkey)] or evkey
end

-- ========= event core =========
local function get_event(evkey)
  local evs = events()
  local real = pick_key(evs, evkey)
  return real and evs[real] or nil, real or evkey
end

-- Plain fields exakt nach deinen Keys
local function event_field(ev, key, evkey)
  if key == "banner" then return ev.banner or ""
  elseif key == "type" then
    local t  = ev.type or ""
    local tr = (((i18n().events or {}).infobox or {}).type or {})[norm(t)]
    return tr or t
  elseif key == "month" then
    return tr_month(ev.month or ev.date or "")
  elseif key == "duration" then
    return tr_duration(ev.duration or "")
  elseif key == "character_level_10" then
    -- reine Übersetzung, kein Fallback-Text
    local f = (i18n().events or {}).unlocks or {}
    return f.character_level_10 or ""
  elseif key == "currency" or key == "currencies"
      or key == "ex_shop" or key == "shop" or key == "shopname"
      or key == "fullname" or key == "shortname"
      or key == "currency_exchange" or key == "avatar_exchange"
      or key == "name" or key == "eventname" then
    local k = (key == "eventname") and "name" or key
    return ev_label(evkey, k)
  else
    return tostring(ev[key] or "")
  end
end

-- ==/=== Überschriften ==
local function htag(level, text)
  if isempty(text) then return "" end
  local eq = level==3 and "===" or "=="
  return string.format("%s %s %s", eq, text, eq)
end

-- [[File:...|thumb|...]]
local function event_file(ev, evkey, which)
  if which=="deco" then
    local file   = ev.images and ev.images.deco or ""
    local legend = ev_label(evkey, "deco")
    return fileTag(file, { param = "thumb|"..legend })
  elseif which=="fullname" then
    local file   = ev.images and ev.images.fullname or ""
    local legend = ev_label(evkey, "fullname")
    return fileTag(file, { param = "thumb|"..legend })
  elseif which=="ex_shop" then
    local file   = ev.images and ev.images.ex_shop or ""
    local legend = ev_label(evkey, "ex_shop")
    return fileTag(file, { param = "thumb|"..legend })
  elseif which=="banner" then
    return fileTag(ev.banner, { param="thumb" })
  end
  return ""
end

-- History → mit Zeilenumbrüchen um Block-Markup sicher zu rendern
local function event_history(ev)
  local H = ev.history
  if type(H) ~= "table" or H[1] == nil then return "" end
  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 .. " (" .. tostring(h.alt_platform) .. ")"
    end
    table.insert(lines, base)
  end
  return "\n" .. table.concat(lines, "\n") .. "\n"
end

-- Avatare (alle Jahre) → ebenfalls mit Newlines einrahmen
local function event_avatars(ev, evkey)
  local AV = ev.avatars or {}
  if next(AV) == nil then return "" end
  local token_icon = ev.currency and ev.currency.icon or ""
  local token_name = event_field(ev, "currencies", evkey)
  local out, years = {}, {}
  for y,_ in pairs(AV) do table.insert(years, y) end
  table.sort(years)
  for _,year in ipairs(years) do
    table.insert(out, string.format("==== %s ====", year))
    table.insert(out, '{| class="article-table" style="font-size:14px;"')
    table.insert(out, '! colspan="2" | Avatar\n! Preis')
    for _,it in ipairs(AV[year]) do
      table.insert(out, "|-")
      table.insert(out, string.format("|%s || %s || %s %s %s",
        fileTag(it.file, { size="50px" }),
        it.title or "",
        fileTag(token_icon, { size="25px" }),
        tostring(it.cost or 0),
        token_name
      ))
    end
    table.insert(out, "|}")
  end
  return "\n" .. table.concat(out, "\n") .. "\n"
end

-- Exchange-Tabellen
local function event_exchange(ev, evkey)
  local ex = ev.exchange or {}
  if next(ex) == nil then return "" end
  local token_icon = (ev.currency or {}).icon or ""
  local token_name = event_field(ev, "currencies", evkey)

  local function table_for(list, header)
    if type(list) ~= "table" or list[1]==nil then return "" end
    local t = {}
    table.insert(t, '{| class="article-table" style="font-size:14px;"')
    table.insert(t, "! "..header.." !! Preis !! Limit")
    for _,it in ipairs(list) do
      table.insert(t, "|-")
      local offer = string.format("[[Datei:%s|30px]] %s", it.icon or "", it.title or "")
      if it.range then offer = "level "..it.range..":  "..offer end
      table.insert(t, string.format("| %s || %s %s %s || %s",
        offer,
        fileTag(token_icon, { size="25px" }),
        tostring(it.price or 0),
        token_name,
        tostring(it.limit or "")
      ))
    end
    table.insert(t, "|}")
    return table.concat(t, "\n")
  end

  local parts = {}
  if ex.chests_by_level then table.insert(parts, table_for(ex.chests_by_level, "Angebot")) end
  if ex.chests_by_stars then table.insert(parts, table_for(ex.chests_by_stars, "Angebot")) end
  if ex.chests_by_oracle then table.insert(parts, table_for(ex.chests_by_oracle, "Angebot")) end
  if ex.currencies     then table.insert(parts, table_for(ex.currencies,     "Angebot")) end
  return (#parts>0) and ("\n"..table.concat(parts, "\n").."\n") or ""
end

-- Shop-Angebote
local function event_offers(ev, evkey, which)
  local list = (ev.shop or {})[which]
  if type(list) ~= "table" or list[1]==nil then return "" end
  local token_icon = (ev.currency or {}).icon or ""
  local token_name = event_field(ev, "currencies", evkey)

  local t = {}
  table.insert(t, '{| class="article-table" style="font-size:14px;"')
  table.insert(t, "! Angebot !! Menge")
  for _,it in ipairs(list) do
    table.insert(t, "|-")
    table.insert(t, string.format("| ''%s''<br />%s || %s %s %s",
      it.name or "",
      fileTag(it.image, { size="x50px" }),
      fileTag(token_icon, { size="30px" }),
      tostring(it.token or 0),
      token_name
    ))
  end
  table.insert(t, "|}")
  return "\n" .. table.concat(t, "\n") .. "\n"
end

-- ===== main dispatcher for Event =====
local function dispatch_event(args)
  local evkey = args[2]; if isempty(evkey) then return "" end
  local ev, realkey = get_event(evkey); if not ev then return "" end

  local a3, a4 = args[3], args[4]
  if isempty(a3) or a3=="eventname" then
    return ev_name(realkey)
  end

  -- plain fields & labels (inkl. 'shop')
  if a3=="banner" or a3=="type" or a3=="month" or a3=="duration"
     or a3=="character_level_10"
     or a3=="currency" or a3=="currencies"
     or a3=="ex_shop" or a3=="shop" or a3=="shopname"
     or a3=="fullname" or a3=="shortname"
     or a3=="currency_exchange" or a3=="avatar_exchange"
     or a3=="name" then
    return event_field(ev, a3, realkey)
  end

  -- file / headings
  if a3=="file" then return event_file(ev, realkey, a4 or "")
  elseif a3=="h2"  then return htag(2, ev_label(realkey, a4 or ""))
  elseif a3=="h3"  then return htag(3, ev_label(realkey, a4 or "")) end

  -- composed blocks
  if a3=="history"  then return event_history(ev)
  elseif a3=="avatars"  then return event_avatars(ev, realkey)
  elseif a3=="exchange" then return event_exchange(ev, realkey)
  elseif a3=="offers" and (a4=="start" or a4=="more") then
    return event_offers(ev, realkey, (a4=="start") and "initial" or "after")
  end

  return ""
end

-- ===== hero (für Vollständigkeit) =====
local function dispatch_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 h = H[real]
  local path, i = {}, 3
  while args[i] do table.insert(path, args[i]); i=i+1 end
  local v = deep_get(h, path)
  return tostring(v or "")
end

-- ===== main =====
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 dispatch_event(a)
  elseif dom=="hero" then return dispatch_hero(a)
  else return "" end
end

return M