456 lignes
13 KiB
Lua
456 lignes
13 KiB
Lua
|
|
local GetTime = QuestHelper_GetTime
|
|
|
|
QuestHelper_File["db_get.lua"] = "4.0.1.$svnversion$"
|
|
QuestHelper_Loadtime["db_get.lua"] = GetTime()
|
|
|
|
local dev_mode = (QuestHelper_File["db_get.lua"] == "Development Version")
|
|
QHDB_Export = {}
|
|
local export = false
|
|
-- yoink
|
|
--[[
|
|
local QHDB_temp = QHDB
|
|
QHDB = nil
|
|
local QHDB = QHDB_temp]]
|
|
QuestHelper: Assert(#QHDB == 4, "Please make sure that you are loading a locale.")
|
|
|
|
local weak_v = { __mode = 'v' }
|
|
local weak_k = { __mode = 'k' }
|
|
|
|
local cache = {}
|
|
|
|
local frequencies = setmetatable({}, weak_k)
|
|
|
|
-- guhhh just want this to work
|
|
local freq_group = setmetatable({}, weak_k)
|
|
local freq_id = setmetatable({}, weak_k)
|
|
|
|
local function DBC_Get(group, id)
|
|
if not cache[group] then return end
|
|
return cache[group][id]
|
|
end
|
|
|
|
local function DBC_Put(group, id, item)
|
|
if not cache[group] then cache[group] = setmetatable({}, weak_v) end
|
|
QuestHelper: Assert(not cache[group][id])
|
|
cache[group][id] = item
|
|
|
|
--DB_how_many_are_used()
|
|
end
|
|
|
|
local function mark(tab, tomark)
|
|
for k, v in pairs(tab) do
|
|
if k ~= "__owner" and type(v) == "table" then
|
|
mark(v, tomark)
|
|
end
|
|
end
|
|
tab.__owner = tomark
|
|
end
|
|
|
|
local function read_adaptint(data, offset)
|
|
local stx = 0
|
|
local acu = 1
|
|
while true do
|
|
local v = strbyte(data, offset)
|
|
QuestHelper: Assert(v, string.format("%d %d", #data, offset))
|
|
stx = stx + acu * math.floor(v / 2)
|
|
offset = offset + 1
|
|
acu = acu * 128
|
|
if mod(v, 2) == 0 then break end
|
|
end
|
|
return stx, offset
|
|
end
|
|
|
|
local function search_index(index, data, item)
|
|
--[[Header format:
|
|
|
|
Itemid (0 for endnode)
|
|
Offset
|
|
Length
|
|
Rightlink]]
|
|
|
|
local cofs = 1
|
|
--[[ assert(index and type(index) == "string") ]]
|
|
--[[ assert(data and type(data) == "string") ]]
|
|
|
|
while true do
|
|
local idx, ofs, len, rlink
|
|
idx, cofs = read_adaptint(index, cofs)
|
|
if idx == 0 then return end
|
|
ofs, cofs = read_adaptint(index, cofs)
|
|
len, cofs = read_adaptint(index, cofs)
|
|
rlink, cofs = read_adaptint(index, cofs)
|
|
|
|
if idx == item then
|
|
return strsub(data, ofs, ofs + len)
|
|
end
|
|
|
|
if idx < item then cofs = cofs + rlink end
|
|
end
|
|
end
|
|
|
|
local initted = false
|
|
function DB_Init()
|
|
QuestHelper: Assert(not initted)
|
|
for _, db in ipairs(QHDB) do
|
|
for _, v in pairs(db) do
|
|
--print("db", not not v.__dictionary, not not v.__tokens)
|
|
if v.__dictionary and v.__tokens then
|
|
local redictix = v.__dictionary
|
|
if not redictix:find("\"") then redictix = redictix .. "\"" end
|
|
if not redictix:find(",") then redictix = redictix .. "," end
|
|
if not redictix:find("\\") then redictix = redictix .. "\\" end
|
|
local tokens = loadstring("return {" .. QH_LZW_Decompress_Dicts_Arghhacky(v.__tokens, redictix) .. "}")()
|
|
QuestHelper: Assert(tokens)
|
|
|
|
local _, _, prep = QH_LZW_Prepare_Arghhacky(v.__dictionary, tokens)
|
|
QuestHelper: Assert(prep)
|
|
|
|
QuestHelper: Assert(type(prep) == "table")
|
|
|
|
v.__tokens = prep
|
|
end
|
|
end
|
|
end
|
|
initted = true
|
|
QH_UpdateQuests() -- just in case it's been waiting on us (it has almost certainly been waiting on us)
|
|
end
|
|
|
|
function DB_Ready()
|
|
return initted
|
|
end
|
|
|
|
function DB_HasItem(group, id)
|
|
QuestHelper: Assert(initted)
|
|
|
|
if group == "quest" then
|
|
if type(id) == "number" and id > 0 then return true
|
|
else return false
|
|
end
|
|
end
|
|
|
|
for _, db in ipairs(QHDB) do
|
|
if db[group] then
|
|
if db[group][id] then
|
|
return true
|
|
end
|
|
|
|
if type(id) == "number" and id > 0 and db[group].__serialize_index and db[group].__serialize_data and search_index(db[group].__serialize_index, db[group].__serialize_data, id) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
local function GetBlizzardQuestInfoFrameMainLoop(qid)
|
|
local POIFrame, questFrame
|
|
QuestMapUpdateAllQuests()
|
|
QuestPOIUpdateIcons()
|
|
WorldMapFrame_UpdateQuests()
|
|
|
|
for i = 1, MAX_NUM_QUESTS do
|
|
questFrame = _G["WorldMapQuestFrame" .. i]
|
|
if questFrame then
|
|
if questFrame.questId == qid then
|
|
POIFrame = questFrame.poiIcon
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
return questFrame, POIFrame
|
|
end
|
|
|
|
local function GetBlizzardQuestInfoFrame(qid, map)
|
|
if map then SetMapByID(map) end
|
|
QuestMapUpdateAllQuests()
|
|
QuestPOIUpdateIcons()
|
|
WorldMapFrame_UpdateQuests()
|
|
|
|
local POIFrame
|
|
local questFrame
|
|
local dLvl
|
|
|
|
if map and GetNumDungeonMapLevels() > 0 then -- Suspicion is that each dungeon level has to be iterated.
|
|
for i = 1, GetNumDungeonMapLevels() do
|
|
SetDungeonMapLevel(i)
|
|
questFrame, POIFrame = GetBlizzardQuestInfoFrameMainLoop(qid)
|
|
if POIFrame then
|
|
dLvl = i
|
|
break
|
|
end
|
|
end
|
|
else -- Only need to call once
|
|
questFrame, POIFrame = GetBlizzardQuestInfoFrameMainLoop(qid)
|
|
end
|
|
|
|
return questFrame, POIFrame, dLvl or 0
|
|
end
|
|
|
|
local function GetBlizzardQuestInfo(qid)
|
|
local questFrame, POIFrame, qdLvl = GetBlizzardQuestInfoFrame(qid)
|
|
local mapId = GetCurrentMapAreaID()
|
|
local c, z
|
|
local dLvl = false
|
|
local qMapId
|
|
|
|
if GetNumDungeonMapLevels() > 0 then dLvl = GetCurrentMapDungeonLevel() end
|
|
|
|
if not POIFrame then
|
|
-- Iterate over all maps to try and find it (we are of course assuming that the player has the quest, otherwise we will be SOL.
|
|
local maps = QuestHelper.LibMapData:GetAllMapIDs()
|
|
for _, map in pairs(maps) do
|
|
if map >= 0 and not QuestHelper.LibMapData:IsContinentMap(map) then
|
|
|
|
questFrame, POIFrame, qdLvl = GetBlizzardQuestInfoFrame(qid, map)
|
|
|
|
if POIFrame then
|
|
qMapId = map
|
|
break
|
|
end
|
|
end
|
|
end
|
|
c, z = GetCurrentMapContinent(), GetCurrentMapZone()
|
|
SetMapByID(mapId)
|
|
if not POIFrame then return nil end -- At this point we either have the quest or we are SOL.
|
|
else
|
|
qMapId = mapId
|
|
c, z = GetCurrentMapContinent(), GetCurrentMapZone()
|
|
end
|
|
|
|
local _, _, _, x, y = POIFrame:GetPoint()
|
|
|
|
if not x or not y then return nil end
|
|
|
|
local frame = WorldMapDetailFrame
|
|
local width, height = frame:GetWidth(), frame:GetHeight()
|
|
local wm_scale, poi_scale = frame:GetScale(), POIFrame:GetScale()
|
|
|
|
-- Convert from yards to %
|
|
local cx = ((x / (wm_scale / poi_scale)) / width)
|
|
local cy = ((-y / (wm_scale / poi_scale)) / height)
|
|
|
|
|
|
if cx < 0 or cx > 1 or cy < 0 or cy > 1 then return nil end
|
|
|
|
-- Now we want to convert to proper format for QH.
|
|
-- Look at WoWPro:findBlizzCoords(qid) for remainder
|
|
local _, contX, contY = QuestHelper.Astrolabe:GetAbsoluteContinentPosition(c, z, cx, cy)
|
|
--contX, contY = contX / QuestHelper.Astrolabe:GetZoneWidth(c, 0), contY / QuestHelper.Astrolabe:GetZoneHeight(c, 0)
|
|
|
|
local solid = { ["continent"] = c, contX - 10, contY - 10, contX + 10, contY - 10, contX + 10, contY + 10, contX - 10, contY + 10 }
|
|
local ret = {}
|
|
|
|
ret.solid = solid
|
|
ret.criteria = {}
|
|
|
|
local questIdx = GetQuestLogIndexByID(qid)
|
|
local numCrit = GetNumQuestLeaderBoards(questIdx)
|
|
local loc = { ["loc"] = { { ["p"] = qMapId, ["x"] = contX, ["y"] = contY} } }
|
|
for i = 1, numCrit do
|
|
table.insert(ret.criteria, loc)
|
|
end
|
|
|
|
ret.name = GetQuestLogTitle(questIdx)
|
|
ret.Blizzard = true
|
|
return ret
|
|
end
|
|
|
|
local function GetLightHeadedQuestInfo(qid)
|
|
if not LightHeaded or type(LightHeaded) ~= "table" then return nil end -- LH not loaded
|
|
|
|
local npcid, npcname, stype
|
|
local coords = {}
|
|
|
|
_, _, _, _, _, _, _, stype, npcname, npcid = LightHeaded:GetQuestInfo(qid)
|
|
|
|
-- Note: If we want the quest giver, we need fields 5, 6 and 7 above, rather than what we have gotten.
|
|
--
|
|
if stype == "npc" then
|
|
local data = LightHeaded:LoadNPCData(tonumber(npcid))
|
|
if not data then return end -- LightHeaded has no clue about the given NPC, despite giving us the id.
|
|
for zid,x,y in data:gmatch("([^,]+),([^,]+),([^:]+):") do
|
|
table.insert(coords, {["p"] = zid, ["x"] = x, ["y"] = y})
|
|
end
|
|
end
|
|
|
|
--can't return coordinates until we know more about what we are getting and then convert accordingly.
|
|
for k, v in pairs(coords) do for k1, v1 in pairs(v) do print(k, k1, v1) end end
|
|
--return coords
|
|
return nil
|
|
end
|
|
|
|
local function GetSelfQuestInfo(qid)
|
|
return nil
|
|
end
|
|
|
|
-- Returns x and y in yards relative to something... Continent?
|
|
local function GetQuestInfo(qid)
|
|
assert(type(qid) == "number")
|
|
local coords = GetSelfQuestInfo(qid)
|
|
--if not coords then coords = GetLightHeadedQuestInfo(qid) end
|
|
if not coords then
|
|
coords = GetBlizzardQuestInfo(qid)
|
|
end
|
|
|
|
return coords -- Might still be nil, but if we don't have anything from Blizz, prolly nothing can be done.
|
|
end
|
|
|
|
function DB_GetItem(group, id, silent, register)
|
|
QuestHelper: Assert(initted)
|
|
|
|
QuestHelper: Assert(group, string.format("%s %s", tostring(group), tostring(id)))
|
|
QuestHelper: Assert(id, string.format("%s %s", tostring(group), tostring(id)))
|
|
local ite = DBC_Get(group, id)
|
|
|
|
if not ite and group == "flightpaths" then return nil end
|
|
|
|
if not ite and group == "quest" then
|
|
-- Loop over zones AND floors
|
|
-- see QuestRouterLite.lua for specific calls.
|
|
-- In the end, the item returned MUST be "formatted" the same as a true QHDB item.
|
|
ite = GetQuestInfo(id)
|
|
end
|
|
|
|
if not ite then
|
|
if type(id) == "string" then QuestHelper: Assert(not id:match("__.*")) end
|
|
|
|
--QuestHelper:TextOut(string.format("%s %d", group, id))
|
|
|
|
for _, db in ipairs(QHDB) do
|
|
--print(db, db[group], db[group] and db[group][id], type(group), type(id))
|
|
if db[group] then
|
|
local dat
|
|
if db[group][id] then
|
|
dat = db[group][id]
|
|
end
|
|
|
|
--print(not dat, type(id), id, not not db[group].__serialize_index, not not db[group].__serialize_index)
|
|
if not dat and type(id) == "number" and id > 0 and db[group].__serialize_index and db[group].__serialize_data then
|
|
dat = search_index(db[group].__serialize_index, db[group].__serialize_data, id)
|
|
end
|
|
|
|
if dat then
|
|
if not ite then ite = QuestHelper:CreateTable("db") end
|
|
|
|
local srctab
|
|
|
|
if type(dat) == "string" then
|
|
QuestHelper: Assert(db[group].__tokens == nil or type(db[group].__tokens) == "table")
|
|
srctab = loadstring("return {" .. (db[group].__prefix or "") .. QH_LZW_Decompress_Dicts_Prepared_Arghhacky(dat, db[group].__dictionary, nil, db[group].__tokens) .. (db[group].__suffix or "") .. "}")()
|
|
elseif type(dat) == "table" then
|
|
srctab = dat
|
|
else
|
|
QuestHelper: Assert()
|
|
end
|
|
|
|
for k, v in pairs(srctab) do
|
|
QuestHelper: Assert(not ite[k] or k == "used")
|
|
ite[k] = v
|
|
if export then
|
|
if not QHDB_Export[group] then QHDB_Export[group] = {} end
|
|
if not QHDB_Export[group][id] then QHDB_Export[group][id] = {} end
|
|
QHDB_Export[group][id][k] = v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if ite then
|
|
--print("marking", group, id, silent, register)
|
|
mark(ite, ite)
|
|
--print("done marking")
|
|
|
|
DBC_Put(group, id, ite)
|
|
|
|
freq_group[ite] = group
|
|
freq_id[ite] = id
|
|
else
|
|
if not silent then
|
|
QuestHelper:TextOut(string.format("Tried to get %s/%s, failed", tostring(group), tostring(id)))
|
|
end
|
|
end
|
|
end
|
|
|
|
if ite then
|
|
frequencies[ite] = (frequencies[ite] or 0) + (register and 1 or 1000000000) -- effectively infinity
|
|
end
|
|
|
|
return ite
|
|
end
|
|
|
|
local function incinerate(ite, crunchy)
|
|
if dev_mode then return end -- wellllp
|
|
|
|
if not crunchy[ite] then
|
|
crunchy[ite] = true
|
|
|
|
for k, v in pairs(ite) do
|
|
if type(k) == "table" then incinerate(k, crunchy) end
|
|
if type(v) == "table" then incinerate(v, crunchy) end
|
|
end
|
|
end
|
|
end
|
|
|
|
function DB_ReleaseItem(ite)
|
|
QuestHelper: Assert(ite)
|
|
frequencies[ite] = frequencies[ite] - 1
|
|
|
|
if frequencies[ite] == 0 then
|
|
--print("incinerating", freq_group[ite], freq_id[ite])
|
|
if cache[freq_group[ite]] then
|
|
cache[freq_group[ite]][freq_id[ite]] = nil
|
|
end
|
|
freq_group[ite] = nil
|
|
freq_id[ite] = nil
|
|
|
|
local incin = QuestHelper:CreateTable("incinerate")
|
|
incinerate(ite, incin)
|
|
for k, _ in pairs(incin) do
|
|
QuestHelper:ReleaseTable(k)
|
|
end -- burn baby burn
|
|
QuestHelper:ReleaseTable(incin)
|
|
end
|
|
end
|
|
|
|
function DB_ListItems(group)
|
|
local tab = {}
|
|
for _, db in ipairs(QHDB) do
|
|
if db[group] then
|
|
QuestHelper: Assert(not db.__serialize_index and not db.__serialize_data)
|
|
for k, _ in pairs(db[group]) do
|
|
if type(k) ~= "string" or not k:match("__.*") then
|
|
tab[k] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local rv = {}
|
|
for k, _ in pairs(tab) do
|
|
table.insert(rv, k)
|
|
end
|
|
|
|
return rv
|
|
end
|
|
|
|
function DB_how_many_are_used()
|
|
local count = 0
|
|
for k, v in pairs(cache) do
|
|
for k2, v2 in pairs(v) do
|
|
count = count + 1
|
|
end
|
|
end
|
|
print(count)
|
|
end
|
|
|
|
function DB_DumpItems()
|
|
local dt = {}
|
|
for k, v in pairs(freq_group) do
|
|
dt[string.format("%s/%s", freq_group[k], tostring(freq_id[k]))] = true
|
|
end
|
|
return dt
|
|
end
|