Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fc4dbc4fb3 | |||
| 7b57a45a1b | |||
| a5633fd9e2 |
@@ -6,7 +6,7 @@ RelationshipsAttune = RelationshipsAttune or {}
|
|||||||
local RA = RelationshipsAttune
|
local RA = RelationshipsAttune
|
||||||
local L = RelationshipsAttune_L
|
local L = RelationshipsAttune_L
|
||||||
|
|
||||||
RA.VERSION = "1.4.3"
|
RA.VERSION = "1.4.4"
|
||||||
RA.COMM_PREFIX = "RATTUNE"
|
RA.COMM_PREFIX = "RATTUNE"
|
||||||
|
|
||||||
RA.playerName = nil
|
RA.playerName = nil
|
||||||
@@ -183,6 +183,75 @@ function RA:ScanQuestLog()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------
|
||||||
|
-- Completed-quest scan (server-side completed quest cache).
|
||||||
|
--
|
||||||
|
-- Turtle WoW / OctoWoW backport QueryQuestsCompleted() +
|
||||||
|
-- GetQuestsCompleted(t), which return every quest the character has
|
||||||
|
-- ever turned in -- including quests completed BEFORE the addon was
|
||||||
|
-- installed. Without this, the addon can only see quests that are
|
||||||
|
-- currently in the log (or that were "complete" in a previous scan
|
||||||
|
-- and then vanished), so a player who is already half-way through a
|
||||||
|
-- chain shows no progress until they accept the next quest.
|
||||||
|
--
|
||||||
|
-- We pcall everything so stock 1.12 clients that don't expose these
|
||||||
|
-- APIs simply skip the scan and keep the existing behaviour.
|
||||||
|
-- ---------------------------------------------------------------
|
||||||
|
function RA:ScanCompletedQuests()
|
||||||
|
-- Build the set of quest ids we actually care about so we don't
|
||||||
|
-- pollute the DB with thousands of unrelated turn-ins.
|
||||||
|
if not RelationshipsAttune_Data then return end
|
||||||
|
local wanted = {}
|
||||||
|
for i = 1, table.getn(RelationshipsAttune_Data) do
|
||||||
|
local att = RelationshipsAttune_Data[i]
|
||||||
|
if att and att.steps then
|
||||||
|
for j = 1, table.getn(att.steps) do
|
||||||
|
local s = att.steps[j]
|
||||||
|
if s and s.type == "quest" and s.id then
|
||||||
|
wanted[s.id] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local completed = {}
|
||||||
|
local haveAny = false
|
||||||
|
|
||||||
|
-- Preferred: bulk table fill.
|
||||||
|
if type(GetQuestsCompleted) == "function" then
|
||||||
|
local ok = pcall(GetQuestsCompleted, completed)
|
||||||
|
if ok then
|
||||||
|
for _ in pairs(completed) do haveAny = true break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Fallback: per-id check (Turtle exposes IsQuestCompleted on some builds).
|
||||||
|
if not haveAny and type(IsQuestCompleted) == "function" then
|
||||||
|
for qid in pairs(wanted) do
|
||||||
|
local ok, res = pcall(IsQuestCompleted, qid)
|
||||||
|
if ok and res then
|
||||||
|
completed[qid] = true
|
||||||
|
haveAny = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not haveAny then
|
||||||
|
-- Kick the server to populate the cache; the QUEST_QUERY_COMPLETE
|
||||||
|
-- event handler will re-run this scan when the reply arrives.
|
||||||
|
if type(QueryQuestsCompleted) == "function" then
|
||||||
|
pcall(QueryQuestsCompleted)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for qid in pairs(wanted) do
|
||||||
|
if completed[qid] and RelationshipsAttuneCharDB.quests[qid] ~= "turnedin" then
|
||||||
|
RelationshipsAttuneCharDB.quests[qid] = "turnedin"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function RA:MarkQuestTurnedIn(questId)
|
function RA:MarkQuestTurnedIn(questId)
|
||||||
if not questId then return end
|
if not questId then return end
|
||||||
@@ -610,12 +679,27 @@ function RA:MarkDirty() RA._dirty = true end
|
|||||||
-- Full periodic rescan (quest log + bags + recompute + UI refresh).
|
-- Full periodic rescan (quest log + bags + recompute + UI refresh).
|
||||||
function RA:AutoScan()
|
function RA:AutoScan()
|
||||||
RA:ScanQuestLog()
|
RA:ScanQuestLog()
|
||||||
|
RA:ScanCompletedQuests()
|
||||||
RA:ScanBags()
|
RA:ScanBags()
|
||||||
RA:RecomputeAll()
|
RA:RecomputeAll()
|
||||||
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
||||||
end
|
end
|
||||||
|
|
||||||
function RA:_OnUpdate(elapsed)
|
function RA:_OnUpdate(elapsed)
|
||||||
|
-- Elapsed can arrive as a function argument, as the global arg1, or
|
||||||
|
-- (on some 1.12 builds) not at all. Fall back to GetTime() deltas so
|
||||||
|
-- the periodic auto-scan always advances.
|
||||||
|
if type(elapsed) ~= "number" then elapsed = nil end
|
||||||
|
if not elapsed and type(arg1) == "number" then elapsed = arg1 end
|
||||||
|
if not elapsed and GetTime then
|
||||||
|
local now = GetTime()
|
||||||
|
if RA._lastUpdate then
|
||||||
|
elapsed = now - RA._lastUpdate
|
||||||
|
else
|
||||||
|
elapsed = 0
|
||||||
|
end
|
||||||
|
RA._lastUpdate = now
|
||||||
|
end
|
||||||
elapsed = elapsed or 0
|
elapsed = elapsed or 0
|
||||||
RA._throttle = RA._throttle + elapsed
|
RA._throttle = RA._throttle + elapsed
|
||||||
RA._periodic = RA._periodic + elapsed
|
RA._periodic = RA._periodic + elapsed
|
||||||
@@ -637,6 +721,7 @@ function RA:_OnUpdate(elapsed)
|
|||||||
end
|
end
|
||||||
if fired then
|
if fired then
|
||||||
RA:WarmItemCache()
|
RA:WarmItemCache()
|
||||||
|
RA:ScanCompletedQuests()
|
||||||
RA:ScanBags()
|
RA:ScanBags()
|
||||||
RA:RecomputeAll()
|
RA:RecomputeAll()
|
||||||
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
||||||
@@ -726,13 +811,13 @@ local function slashHandler(msg)
|
|||||||
if RA.Comm then RA.Comm:RequestSync() end
|
if RA.Comm then RA.Comm:RequestSync() end
|
||||||
print(L.MSG_SYNC_SENT)
|
print(L.MSG_SYNC_SENT)
|
||||||
elseif msg == "scan" then
|
elseif msg == "scan" then
|
||||||
RA:ScanQuestLog(); RA:ScanBags(); RA:RecomputeAll()
|
RA:ScanQuestLog(); RA:ScanCompletedQuests(); RA:ScanBags(); RA:RecomputeAll()
|
||||||
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
||||||
print(L.MSG_SCANNED)
|
print(L.MSG_SCANNED)
|
||||||
elseif msg == "reset" then
|
elseif msg == "reset" then
|
||||||
RelationshipsAttuneCharDB = nil
|
RelationshipsAttuneCharDB = nil
|
||||||
RA:InitDB()
|
RA:InitDB()
|
||||||
RA:ScanQuestLog(); RA:ScanBags(); RA:RecomputeAll()
|
RA:ScanQuestLog(); RA:ScanCompletedQuests(); RA:ScanBags(); RA:RecomputeAll()
|
||||||
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
||||||
print(L.MSG_RESET)
|
print(L.MSG_RESET)
|
||||||
elseif msg == "debug" or string.find(msg, "^find") then
|
elseif msg == "debug" or string.find(msg, "^find") then
|
||||||
@@ -808,6 +893,7 @@ pcall(function() ef:RegisterEvent("ITEM_PUSH") end)
|
|||||||
pcall(function() ef:RegisterEvent("PLAYER_XP_UPDATE") end)
|
pcall(function() ef:RegisterEvent("PLAYER_XP_UPDATE") end)
|
||||||
pcall(function() ef:RegisterEvent("ZONE_CHANGED_NEW_AREA") end)
|
pcall(function() ef:RegisterEvent("ZONE_CHANGED_NEW_AREA") end)
|
||||||
pcall(function() ef:RegisterEvent("SKILL_LINES_CHANGED") end)
|
pcall(function() ef:RegisterEvent("SKILL_LINES_CHANGED") end)
|
||||||
|
pcall(function() ef:RegisterEvent("QUEST_QUERY_COMPLETE") end)
|
||||||
|
|
||||||
ef:SetScript("OnEvent", function()
|
ef:SetScript("OnEvent", function()
|
||||||
local e = event
|
local e = event
|
||||||
@@ -819,8 +905,15 @@ ef:SetScript("OnEvent", function()
|
|||||||
RA.playerFaction = UnitFactionGroup("player") or "Neutral"
|
RA.playerFaction = UnitFactionGroup("player") or "Neutral"
|
||||||
RA:BuildNameIndex()
|
RA:BuildNameIndex()
|
||||||
RA:WarmItemCache()
|
RA:WarmItemCache()
|
||||||
RA:ScanQuestLog(); RA:ScanBags(); RA:RecomputeAll()
|
-- ScanCompletedQuests seeds the "already turned-in" state from the
|
||||||
RA._retryAt = { GetTime() + 3, GetTime() + 10 }
|
-- server's completed-quest cache so mid-chain attunements show the
|
||||||
|
-- player's actual current step immediately at load, instead of
|
||||||
|
-- waiting until the next quest in the chain is accepted.
|
||||||
|
RA:ScanQuestLog(); RA:ScanCompletedQuests(); RA:ScanBags(); RA:RecomputeAll()
|
||||||
|
-- The completed-quest cache is often empty on first login until
|
||||||
|
-- QueryQuestsCompleted() round-trips to the server. Schedule extra
|
||||||
|
-- rescans so the UI catches up as soon as the cache is populated.
|
||||||
|
RA._retryAt = { GetTime() + 2, GetTime() + 5, GetTime() + 10 }
|
||||||
if RA.Comm and RA.Comm.Init then RA.Comm:Init() end
|
if RA.Comm and RA.Comm.Init then RA.Comm:Init() end
|
||||||
if RA.UI and RA.UI.Init then RA.UI:Init() end
|
if RA.UI and RA.UI.Init then RA.UI:Init() end
|
||||||
if RA.Minimap and RA.Minimap.Init then RA.Minimap:Init() end
|
if RA.Minimap and RA.Minimap.Init then RA.Minimap:Init() end
|
||||||
@@ -849,6 +942,13 @@ ef:SetScript("OnEvent", function()
|
|||||||
elseif e == "QUEST_TURNED_IN" then
|
elseif e == "QUEST_TURNED_IN" then
|
||||||
if arg1 then RA:MarkQuestTurnedIn(arg1) end
|
if arg1 then RA:MarkQuestTurnedIn(arg1) end
|
||||||
|
|
||||||
|
elseif e == "QUEST_QUERY_COMPLETE" then
|
||||||
|
if RA.initialized then
|
||||||
|
RA:ScanCompletedQuests()
|
||||||
|
RA:RecomputeAll()
|
||||||
|
if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end
|
||||||
|
end
|
||||||
|
|
||||||
elseif e == "CHAT_MSG_ADDON" then
|
elseif e == "CHAT_MSG_ADDON" then
|
||||||
if arg1 == RA.COMM_PREFIX and RA.Comm and RA.Comm.OnMessage then
|
if arg1 == RA.COMM_PREFIX and RA.Comm and RA.Comm.OnMessage then
|
||||||
RA.Comm:OnMessage(arg2, arg3, arg4)
|
RA.Comm:OnMessage(arg2, arg3, arg4)
|
||||||
@@ -856,7 +956,12 @@ ef:SetScript("OnEvent", function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
ef:SetScript("OnUpdate", function()
|
ef:SetScript("OnUpdate", function(_self, _elapsed)
|
||||||
if not RA.initialized then return end
|
if not RA.initialized then return end
|
||||||
RA:_OnUpdate(arg1)
|
-- Vanilla 1.12 delivers elapsed via the global arg1; some private-server
|
||||||
|
-- builds pass it as a positional parameter instead. Try both.
|
||||||
|
local e = arg1
|
||||||
|
if type(e) ~= "number" then e = _elapsed end
|
||||||
|
if type(e) ~= "number" then e = _self end
|
||||||
|
RA:_OnUpdate(e)
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -209,16 +209,16 @@ RelationshipsAttune_Data = {
|
|||||||
{ type = "level", level = 60, name = "Reach Level 60", icon = ICON_LEVEL },
|
{ type = "level", level = 60, name = "Reach Level 60", icon = ICON_LEVEL },
|
||||||
{ type = "rep", faction = "Argent Dawn", standing = 5,
|
{ type = "rep", faction = "Argent Dawn", standing = 5,
|
||||||
name = "Honored with the Argent Dawn", icon = ICON_REP,
|
name = "Honored with the Argent Dawn", icon = ICON_REP,
|
||||||
desc = "Required to purchase the Naxxramas attunement from Archmage Angela Dosantos. Higher rep reduces the gold cost (60g Honored, 40g Revered, 20g Exalted).",
|
desc = "Required to purchase the Naxxramas attunement from Archmage Angela Dosantos. Higher rep with the Argent Dawn drastically reduces the material cost (see steps below).",
|
||||||
start = "Turn in Scourgestones / Minion's Scourgestones to Argent Dawn quartermasters at Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
start = "Turn in Scourgestones / Minion's Scourgestones to Argent Dawn quartermasters at Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
||||||
{ type = "quest", id = 9121, name = "The Dread Citadel - Naxxramas! (Honored, 60g)", icon = ICON_ACTIVE, final = true,
|
{ type = "quest", id = 9121, name = "The Dread Citadel - Naxxramas! (Honored)", icon = ICON_ACTIVE, final = true,
|
||||||
desc = "Pay 60g to Angela Dosantos - available at Honored with Argent Dawn.",
|
desc = "Honored cost: 60 gold, 5 Arcane Crystals, 2 Nexus Crystals, and 1 Righteous Orb. Turn in to Archmage Angela Dosantos.",
|
||||||
start = "Archmage Angela Dosantos, Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
start = "Archmage Angela Dosantos, Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
||||||
{ type = "quest", id = 9122, name = "The Dread Citadel - Naxxramas! (Revered, 40g)", icon = ICON_ACTIVE, final = true,
|
{ type = "quest", id = 9122, name = "The Dread Citadel - Naxxramas! (Revered)", icon = ICON_ACTIVE, final = true,
|
||||||
desc = "Discounted Naxx attunement offered at Revered with Argent Dawn.",
|
desc = "Revered cost: 30 gold, 2 Arcane Crystals, and 1 Nexus Crystal. Turn in to Archmage Angela Dosantos.",
|
||||||
start = "Archmage Angela Dosantos, Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
start = "Archmage Angela Dosantos, Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
||||||
{ type = "quest", id = 9123, name = "The Dread Citadel - Naxxramas! (Exalted, 20g)", icon = ICON_ACTIVE, final = true,
|
{ type = "quest", id = 9123, name = "The Dread Citadel - Naxxramas! (Exalted)", icon = ICON_ACTIVE, final = true,
|
||||||
desc = "Cheapest Naxx attunement, offered only at Exalted with Argent Dawn.",
|
desc = "Exalted cost: completely free. Turn in to Archmage Angela Dosantos.",
|
||||||
start = "Archmage Angela Dosantos, Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
start = "Archmage Angela Dosantos, Light's Hope Chapel, Eastern Plaguelands (76, 53)." },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
## Title: Relationships Attune
|
## Title: Relationships Attune
|
||||||
## Notes: Track Vanilla and Turtle/Octo WoW attunement progress
|
## Notes: Track Vanilla and Turtle/Octo WoW attunement progress
|
||||||
## Author: Relationship
|
## Author: Relationship
|
||||||
## Version: 1.8
|
## Version: 1.9
|
||||||
## X-Category: Quest
|
## X-Category: Quest
|
||||||
## SavedVariables: RelationshipsAttuneDB
|
## SavedVariables: RelationshipsAttuneDB
|
||||||
## SavedVariablesPerCharacter: RelationshipsAttuneCharDB
|
## SavedVariablesPerCharacter: RelationshipsAttuneCharDB
|
||||||
|
|||||||
Reference in New Issue
Block a user