Dateien nach "/" hochladen

This commit is contained in:
2026-10-27 14:09:50 +00:00
parent 8b8dc62603
commit 1cff53eef1
3 changed files with 1371 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
-- Freewood-OctoWoW-Codex: Gebiete mit Stufenspanne, berechnet aus den gesammelten Kreaturen.
--
-- Jede Kreatur zaehlt mit ihren Sichtungen (Zellen) in den Karten, in denen sie gesehen wurde, Instanzen mit ihrer
-- Instanz-ID (negative Zone). Pro Gebiet:
-- lo, hi typische Spanne: alle Stufen, die mindestens 5 % des Gewichts normaler Kreaturen haben
-- avg gewichteter Durchschnitt innerhalb der Spanne
-- out Ausreisser: normale Kreaturen ausserhalb der Spanne
-- special Elite / Selten / Boss usw. (fliessen nicht in die Spanne ein)
-- few zu wenig Daten (weniger als MIN_UNITS normale Kreaturen): Spanne nur grob
-- manual Spanne von Berechtigten von Hand gesetzt (db.ied, siehe Codex.ZoneEdID)
-- Wird mit den geteilten Kreaturdaten berechnet, daher sehen alle dasselbe.
local ADDON, NS = ...
local FW = _G.Freewood
if not FW or not FW:RequireAPI(1, ADDON) then
return
end
local Codex = NS and NS.Codex
if not Codex then
return
end
local Zones = {}
Codex.Zones = Zones
local GRID = Codex.GRID or 200
local MIN_UNITS = 3 -- weniger normale Kreaturen: "zu wenig Daten"
local LEVEL_SHARE = 0.05 -- Mindestanteil einer Stufe am Gewicht, damit sie zur typischen Spanne gehoert
local WEIGHT_CAP = 30 -- eine haeufig gesehene Kreatur zaehlt hoechstens so viel
local MAP_SHARE = 0.10 -- Karte zaehlt fuer eine Kreatur erst ab diesem Anteil ihrer Sichtungen
local CACHE_SECS = 5
local cache, cacheAt, dirty = nil, 0, true
function Zones.Invalidate()
dirty = true
end
FW:On("CODEX_CHANGED", function() dirty = true end, Zones)
local function Now()
return GetTime and GetTime() or 0
end
-- Gewichte einer Kreatur je Gebiet: { [zoneKey] = Gewicht }
local function Spread(u)
local out = {}
if type(u.ez) == "table" and #u.ez > 0 then
local each = 1 / #u.ez
local total = 0
for _, n in pairs(u.cells or {}) do total = total + n end
total = math.max(1, total)
for _, m in ipairs(u.ez) do out[m] = total * each end
return out
end
if type(u.iz) == "table" and next(u.iz) and u.dg ~= false then
for id, n in pairs(u.iz) do out[-id] = n end
return out
end
local per, total = {}, 0
for key, n in pairs(u.cells or {}) do
local m = math.floor(key / (GRID * GRID))
per[m] = (per[m] or 0) + n
total = total + n
end
for m, n in pairs(per) do
if total > 0 and n / total >= MAP_SHARE then out[m] = n end
end
return out
end
local function ManualRange(ied, key)
local rec = ied and ied[Codex.ZoneEdID(key)]
if not rec then return nil end
local l1 = rec.l1 or (rec.ed and rec.ed.l1)
local l2 = rec.l2 or (rec.ed and rec.ed.l2)
if l1 then return l1, l2 or l1 end
return nil
end
local function Compute()
local V = Codex.V()
local zones = {}
local function Zone(key)
local z = zones[key]
if not z then
z = { id = key, normal = {}, special = {}, out = {} }
zones[key] = z
end
return z
end
for id, u in pairs(V.units or {}) do
if u.l1 and u.bad ~= true then
local special = u.c ~= nil and u.c ~= false
local l2 = u.l2 or u.l1
for key, n in pairs(Spread(u)) do
local w = math.max(1, math.min(WEIGHT_CAP, n))
local entry = { id = id, l1 = u.l1, l2 = l2, w = w, c = special and u.c or nil, mid = (u.l1 + l2) / 2 }
local z = Zone(key)
if special then
z.special[#z.special + 1] = entry
else
z.normal[#z.normal + 1] = entry
end
end
end
end
for key, z in pairs(zones) do
local byLevel, total = {}, 0
local minL, maxL
for _, e in ipairs(z.normal) do
-- eine Kreatur mit Spanne (Stufe 3-4) zaehlt je zur Haelfte fuer beide Stufen
local a, b = e.l1, e.l2
local half = e.w / ((b > a) and 2 or 1)
byLevel[a] = (byLevel[a] or 0) + half
if b > a then byLevel[b] = (byLevel[b] or 0) + half end
total = total + e.w
minL = minL and math.min(minL, a) or a
maxL = maxL and math.max(maxL, b) or b
end
z.units = #z.normal
z.few = z.units < MIN_UNITS
local lo, hi
if total > 0 then
for lv, w in pairs(byLevel) do
if w / total >= LEVEL_SHARE then
lo = lo and math.min(lo, lv) or lv
hi = hi and math.max(hi, lv) or lv
end
end
lo, hi = lo or minL, hi or maxL
elseif #z.special > 0 then
for _, e in ipairs(z.special) do
minL = minL and math.min(minL, e.l1) or e.l1
maxL = maxL and math.max(maxL, e.l2) or e.l2
end
lo, hi = minL, maxL
z.few = true
end
local ml, mh = ManualRange(V.ied, key)
if ml then
lo, hi = ml, mh
z.manual = true
z.few = false
end
z.lo, z.hi = lo, hi
local sum, wsum = 0, 0
for _, e in ipairs(z.normal) do
if lo and e.mid >= lo and e.mid <= hi then
sum, wsum = sum + e.mid * e.w, wsum + e.w
end
end
z.avg = wsum > 0 and sum / wsum or ((lo and hi) and (lo + hi) / 2 or nil)
for _, e in ipairs(z.normal) do
if lo and (e.l2 < lo or e.l1 > hi) then z.out[#z.out + 1] = e end
end
z.dungeon = key < 0
z.minL, z.maxL = minL, maxL
end
-- von Hand gesetzte Spannen auch fuer Gebiete ohne Kreaturdaten
for edID, rec in pairs(V.ied or {}) do
local key = Codex.ZoneFromEdID(edID)
if key and not zones[key] then
local l1, l2 = ManualRange(V.ied, key)
if l1 then
zones[key] = { id = key, normal = {}, special = {}, out = {}, units = 0, lo = l1, hi = l2, avg = (l1 + l2) / 2,
manual = true, dungeon = key < 0 }
end
end
end
return zones
end
-- Alle Gebiete: { [zoneKey] = Daten }. Kurz zwischengespeichert.
function Zones.All()
local t = Now()
if not cache or (dirty and t - cacheAt >= CACHE_SECS) or t < cacheAt then
local ok, res = pcall(Compute)
cache = ok and res or cache or {}
cacheAt, dirty = t, false
end
return cache
end
-- Sofort neu berechnen (zum Beispiel nach einer Aenderung im Fenster oder in Tests)
function Zones.Refresh()
dirty = true
cacheAt = -1e9
return Zones.All()
end
function Zones.Get(key)
return Zones.All()[key]
end
-- Eine Kreatur gehoert zu einem Gebiet: Liste fuer die Detailansicht, nach Stufe sortiert
function Zones.Members(key)
local z = Zones.Get(key)
if not z then return {} end
local list = {}
local outSet = {}
for _, e in ipairs(z.out) do outSet[e] = true end
for _, e in ipairs(z.normal) do
list[#list + 1] = { id = e.id, l1 = e.l1, l2 = e.l2, w = e.w, out = outSet[e] or nil }
end
for _, e in ipairs(z.special) do
list[#list + 1] = { id = e.id, l1 = e.l1, l2 = e.l2, w = e.w, c = e.c }
end
table.sort(list, function(a, b)
if a.l1 ~= b.l1 then return a.l1 < b.l1 end
if a.l2 ~= b.l2 then return a.l2 < b.l2 end
return a.id < b.id
end)
return list
end
-- Passt die Stufe zum Gebiet? Rueckgabe: "in" (Stufe liegt in der Spanne), "below" (Spanne ist niedriger),
-- "above" (Spanne ist hoeher), nil (keine Daten). tol = Toleranz in Stufen.
function Zones.Compare(key, level, tol)
local z = Zones.Get(key)
if not z or not z.lo or z.few and not z.manual then return nil end
tol = tol or 0
if level < z.lo - tol then return "above" end
if level > z.hi + tol then return "below" end
return "in"
end
-- Gebiete, deren typische Spanne die Stufe enthaelt (mit Toleranz), mit genug Daten
function Zones.ForLevel(level, tol)
local out = {}
for key, z in pairs(Zones.All()) do
if Zones.Compare(key, level, tol) == "in" then out[#out + 1] = z end
end
return out
end
+41
View File
@@ -0,0 +1,41 @@
## Interface: 11200
## Title: Freewood |cffc89b3cCodex|r
## Notes: Learns quests, creatures and drops while you play: who gives and takes a quest, rewards, objectives, drop chances.
## Notes-deDE: Lernt beim Spielen Quests, Kreaturen und Beute: wer eine Quest vergibt und annimmt, Belohnungen, Ziele, Drop-Chancen.
## Author: Lacustat
## Version: 0.1.148
## Dependencies: Freewood-OctoWoW-Core
## OptionalDeps: Freewood-OctoWoW-CodexData, Freewood-OctoWoW-ForeverData
Locales.lua
Codex.lua
CodexOwners.lua
CodexTrust.lua
CodexNames.lua
CodexSeed.lua
CodexRoles.lua
CodexRecipes.lua
CodexTime.lua
CodexShare.lua
CodexZones.lua
CodexPath.lua
CodexMapAPI.lua
CodexPathMap.lua
CodexTaxi.lua
CodexTaxiUI.lua
CodexTransport.lua
CodexSpots.lua
CodexForever.lua
CodexAvail.lua
CodexCatalog.lua
CodexQuestProbe.lua
CodexWdbChain.lua
CodexMapScan.lua
CodexSync.lua
CodexLookup.lua
CodexMap.lua
CodexUI.lua
CodexHints.lua
CodexFavUI.lua
CodexNameUI.lua
CodexShareUI.lua
+1093
View File
File diff suppressed because it is too large Load Diff