Files
2026-10-27 14:08:32 +00:00

215 lines
8.0 KiB
Lua

-- Freewood-OctoWoW-Codex: mitgelieferte Startdaten (Addon Freewood-OctoWoW-ForeverData)
--
-- ForeverData enthaelt, was Spieler in Forever bereits erfasst haben: Quests mit Geber, Abgabe, Zielen, Belohnungen und Ketten,
-- Kreaturen, Objekte, Beute, Wegenetz, Verkehrsverbindungen, Ortspunkte. Die Daten bilden die unterste Schicht:
-- eigene Daten > empfangene Daten > ForeverData > Classic-Vorlage (Freewood-OctoWoW-CodexData)
-- Sie liegen nur im Speicher (nichts davon wird gespeichert oder weitergesendet) und gehen durch dieselbe Pruefung
-- (Share.Sanitize) wie empfangene Datensaetze. Abschalten: /fwforever aus
local ADDON, NS = ...
local FW = _G.Freewood
local Codex = NS and NS.Codex
if not FW or not Codex then
return
end
local Forever = { loaded = false, count = 0 }
Codex.Forever = Forever
NS.Forever = Forever
local DATA_ADDON = "Freewood-OctoWoW-ForeverData"
function Forever.Disabled()
local db = Codex.db
return db and db.settings and db.settings.noForever == true or false
end
-- Zusatztabellen (Item-Qualitaet, Item-Werte, Anzeige-IDs, Namen, Rezepte): nur fehlende Eintraege werden ergaenzt,
-- eigene Werte gehen vor. Einmal je Datenstand (db.foreverRev).
local function FillTable(dst, src, check)
if type(dst) ~= "table" or type(src) ~= "table" then return end
for k, v in pairs(src) do
if dst[k] == nil and check(k, v) then dst[k] = v end
end
end
local function IsId(k) return type(k) == "number" and k >= 1 and k == math.floor(k) and k < 1e9 end
local EXTRAS = {
iq = function(k, v) return IsId(k) and type(v) == "number" and v >= 0 and v <= 8 end,
disp = function(k, v) return IsId(k) and type(v) == "number" and v > 0 end,
vfac = function(k, v) return IsId(k) and (v == "A" or v == "H") end,
wrq = function(k, v) return IsId(k) and type(v) == "table" end,
names = function(k, v) return IsId(k) and type(v) == "string" and #v <= 80 end,
istats = function(k, v)
if not IsId(k) or type(v) ~= "table" then return false end
for sk, sv in pairs(v) do
if sk == "_fx" then
if type(sv) ~= "table" then return false end
elseif type(sk) ~= "string" or #sk > 60 or (type(sv) ~= "number" and type(sv) ~= "string" and type(sv) ~= "boolean") then return false end
end
return true
end,
}
local function MergeExtras(g)
local db = Codex.db
if not db or not g.extra or db.foreverRev == g.rev then return end
for name, check in pairs(EXTRAS) do
if type(g.extra[name]) == "table" then
db[name] = db[name] or {}
FillTable(db[name], g.extra[name], check)
end
end
if type(g.extra.recipes) == "table" then
db.recipes = db.recipes or {}
for prof, list in pairs(g.extra.recipes) do
if type(prof) == "string" and type(list) == "table" then
db.recipes[prof] = db.recipes[prof] or {}
FillTable(db.recipes[prof], list, function(k, v) return type(k) == "string" and #k <= 80 and type(v) == "table" end)
end
end
end
if type(g.extra.qd) == "table" then
db.cat = db.cat or {}
db.cat.qd = db.cat.qd or {}
FillTable(db.cat.qd, g.extra.qd, function(k, v) return IsId(k) and type(v) == "table" end)
if Codex.Catalog then Codex.Catalog.rev = (Codex.Catalog.rev or 0) + 1 end
end
-- Karten-Scan (Karten, Gebiete, Gebiete je Karte, Trigger, Flugpunkte): nur fehlende Eintraege, eigener Scan geht vor
if type(g.extra.scan) == "table" then
db.cat = db.cat or {}
for _, name in ipairs({ "m", "a", "ma", "t", "x" }) do
if type(g.extra.scan[name]) == "table" then
db.cat[name] = db.cat[name] or {}
FillTable(db.cat[name], g.extra.scan[name], function(k, v)
return type(k) == "number" and (type(v) == "string" or type(v) == "table")
end)
end
end
end
db.foreverRev = g.rev
end
-- Daten des Addons laden (bei Bedarf wird das Addon geladen). Rueckgabe: true, wenn Daten da sind
function Forever.Load()
if Forever.loaded then return true end
if Forever.Disabled() or not Codex.Share or not Codex.Share.SetBuiltin then return false end
local g = _G.FreewoodForeverData
if not (g and g.ready) then
local load = (_G.C_AddOns and _G.C_AddOns.LoadAddOn) or _G.LoadAddOn
if type(load) == "function" then pcall(load, DATA_ADDON) end
g = _G.FreewoodForeverData
end
if not (g and g.ready and type(g.list) == "table") then
Forever.missing = true
return false
end
if Forever.loading then return false end
Forever.loading = true
local list = g.list
local total, slice, from = #list, 600, 1
Codex.Share.BuiltinBegin()
Forever.count = 0
local function Finish()
Codex.Share.BuiltinDone()
pcall(MergeExtras, g)
Forever.version, Forever.rev = g.version, g.rev
Forever.loaded = true
Forever.loading = false
Forever.missing = false
if Codex.chainRev then Codex.chainRev = Codex.chainRev + 1 end
FW:Fire("CODEX_CHANGED", "forever")
end
local function Step()
if not Forever.loading then return end -- zwischendurch ausgeschaltet
local to = math.min(total, from + slice - 1)
Forever.count = Forever.count + Codex.Share.BuiltinAdd(list, from, to)
from = to + 1
if from > total then
Finish()
elseif _G.C_Timer and _G.C_Timer.After then
_G.C_Timer.After(0.05, Step)
else
Step()
end
end
Step()
return true
end
-- Quellen eines Items aus den Startdaten: { u = { {id, chance} }, o = { ... }, v = { Haendler-IDs } } oder nil
local itemCache = {}
function Forever.Item(id)
if not Forever.loaded or Forever.Disabled() then return nil end
local g = _G.FreewoodForeverData
local s = g and type(g.src) == "table" and g.src[id]
if type(s) ~= "string" then return nil end
local c = itemCache[id]
if c then return c end
c = { u = {}, o = {}, v = {} }
for part in s:gmatch("[^;]+") do
local tag, body = part:sub(1, 1), part:sub(2)
if tag == "u" or tag == "o" then
for k, v in body:gmatch("(%d+)=([%d%.]+)") do
local t = c[tag]
t[#t + 1] = { id = tonumber(k), chance = tonumber(v) }
end
elseif tag == "v" then
for k in body:gmatch("%d+") do c.v[#c.v + 1] = tonumber(k) end
end
end
itemCache[id] = c
return c
end
-- Alle Item-IDs mit Quellen in den Startdaten (Tabelle id -> Text; nur lesen)
function Forever.ItemIds()
if not Forever.loaded or Forever.Disabled() then return {} end
local g = _G.FreewoodForeverData
return (g and type(g.src) == "table") and g.src or {}
end
function Forever.ItemHasVendor(id)
local it = Forever.Item(id)
return it ~= nil and #it.v > 0
end
-- Schalter: an = Startdaten nutzen (Standard)
function Forever.SetEnabled(on)
local db = Codex.db
if not db then return end
db.settings.noForever = (not on) or nil
if on then
Forever.Load()
elseif Forever.loading then
Forever.loading = false
Codex.Share.SetBuiltin({})
Forever.count = 0
elseif Forever.loaded then
Codex.Share.SetBuiltin({})
Forever.loaded, Forever.count = false, 0
if Codex.chainRev then Codex.chainRev = Codex.chainRev + 1 end
FW:Fire("CODEX_CHANGED", "forever")
end
end
function Forever.Status()
local L = FW.L
if Forever.Disabled() then return L.CODEX_FOREVER_OFF end
if Forever.loaded then return string.format(L.CODEX_FOREVER_ON, Forever.count, tostring(Forever.version or "?")) end
return L.CODEX_FOREVER_MISSING
end
SLASH_FREEWOODFOREVER1 = "/fwforever"
SlashCmdList["FREEWOODFOREVER"] = function(msg)
msg = (msg or ""):lower():gsub("^%s+", ""):gsub("%s+$", "")
if msg == "aus" or msg == "off" then
Forever.SetEnabled(false)
elseif msg == "an" or msg == "on" then
Forever.SetEnabled(true)
end
FW:Print(Forever.Status())
end