215 lines
8.0 KiB
Lua
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
|