Dateien nach "/" hochladen
This commit is contained in:
+237
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user