Quantcast

Extend tracking of auras cast by others to track all auras.

Johnny C. Lam [07-07-13 - 04:42]
Extend tracking of auras cast by others to track all auras.

The assumption is that it's not possible for one caster to put more than
one aura of a given ID on a target, which should be true.

Change GetMyAuraOnAnyTarget to GetAuraOnAnyTarget, which allows for
specifying whether to check for only "my" auras or auras cast by anyone.
With the associated change to extend aura tracking above, the following
script conditions should provide more accurate answers:

    BuffCount, DebuffCount
    OtherBuffExpires, OtherDebuffExpires
    OtherBuffPresent, OtherDebuffPresent
    OtherBuffRemains, OtherDebuffRemains

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@938 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
OvaleAura.lua
OvaleCondition.lua
OvaleState.lua
diff --git a/OvaleAura.lua b/OvaleAura.lua
index 189aca2..c1197c4 100644
--- a/OvaleAura.lua
+++ b/OvaleAura.lua
@@ -17,7 +17,6 @@ Ovale.OvaleAura = OvaleAura
 --<private-static-properties>
 local OvaleData = Ovale.OvaleData
 local OvaleGUID = Ovale.OvaleGUID
-local OvalePaperDoll = Ovale.OvalePaperDoll
 local OvalePool = Ovale.OvalePool

 local ipairs = ipairs
@@ -32,11 +31,16 @@ local API_UnitAura = UnitAura
 local self_pool = OvalePool:NewPool("OvaleAura_pool")
 -- self_aura[guid] pool
 local self_aura_pool = OvalePool:NewPool("OvaleAura_aura_pool")
+-- player's GUID
+local self_player_guid = nil
 -- self_aura[guid][filter][spellId]["mine" or "other"] = { aura properties }
+-- self_aura[guid][filter][spellId][casterGUID] = { aura properties }
 local self_aura = {}
 -- self_serial[guid] = aura age
 local self_serial = {}

+local OVALE_UNKNOWN_GUID = 0
+
 local OVALE_AURA_DEBUG = "aura"
 -- Units for which UNIT_AURA is known to fire.
 local OVALE_UNIT_AURA_UNITS = {}
@@ -91,26 +95,16 @@ local function UnitGainedAura(guid, spellId, filter, casterGUID, icon, count, de
 		self_aura[guid][filter][spellId] = {}
 	end

-	local mine = (casterGUID == OvaleGUID:GetGUID("player"))
+	casterGUID = casterGUID or OVALE_UNKNOWN_GUID
+	local mine = (casterGUID == self_player_guid)
 	local existingAura, aura
-	if mine then
-		existingAura = self_aura[guid][filter][spellId].mine
-		if existingAura then
-			aura = existingAura
-		else
-			aura = self_pool:Get()
-			aura.gain = Ovale.now
-			self_aura[guid][filter][spellId].mine = aura
-		end
+	existingAura = self_aura[guid][filter][spellId][casterGUID]
+	if existingAura then
+		aura = existingAura
 	else
-		existingAura = self_aura[guid][filter][spellId].other
-		if existingAura then
-			aura = existingAura
-		else
-			aura = self_pool:Get()
-			aura.gain = Ovale.now
-			self_aura[guid][filter][spellId].other = aura
-		end
+		aura = self_pool:Get()
+		aura.gain = Ovale.now
+		self_aura[guid][filter][spellId][casterGUID] = aura
 	end

 	aura.serial = self_serial[guid]
@@ -280,11 +274,11 @@ local function UpdateAuraTick(guid, spellId, timestamp)
 		local serial = self_serial[guid]
 		filter = "HARMFUL"
 		while true do
-			if self_aura[guid][filter] and self_aura[guid][filter][spellId] and self_aura[guid][filter][spellId].mine then
-				if RemoveAuraIfExpired(guid, spellId, filter, self_aura[guid][filter][spellId].mine, serial) then
-					self_aura[guid][filter][spellId].mine = nil
+			if self_aura[guid][filter] and self_aura[guid][filter][spellId] and self_aura[guid][filter][spellId][self_player_guid] then
+				if RemoveAuraIfExpired(guid, spellId, filter, self_aura[guid][filter][spellId][self_player_guid], serial) then
+					self_aura[guid][filter][spellId][self_player_guid] = nil
 				end
-				aura = self_aura[guid][filter][spellId].mine
+				aura = self_aura[guid][filter][spellId][self_player_guid]
 			end
 			if aura then break end
 			if filter == "HARMFUL" then
@@ -319,6 +313,7 @@ end

 --<public-static-methods>
 function OvaleAura:OnEnable()
+	self_player_guid = OvaleGUID:GetGUID("player")
 	self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
 	self:RegisterEvent("PLAYER_ENTERING_WORLD")
 	self:RegisterEvent("UNIT_AURA")
@@ -344,7 +339,7 @@ function OvaleAura:COMBAT_LOG_EVENT_UNFILTERED(event, ...)
 		if unitId and not OVALE_UNIT_AURA_UNITS[unitId] then
 			ScanUnitAuras(event, unitId, destGUID)
 		end
-	elseif OVALE_CLEU_TICK_EVENTS[event] and sourceGUID == OvaleGUID:GetGUID("player") then
+	elseif OVALE_CLEU_TICK_EVENTS[event] and sourceGUID == self_player_guid then
 		-- Periodic aura cast by the player.
 		-- Update the latest tick time of the aura.
 		local spellId, spellName, spellSchool = select(12, ...)
@@ -403,10 +398,10 @@ function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId)
 			local whoseTable = auraList[spellId]
 			if whoseTable then
 				if mine then
-					if RemoveAuraIfExpired(guid, spellId, filter, whoseTable.mine, serial) then
-						whoseTable.mine = nil
+					if RemoveAuraIfExpired(guid, spellId, filter, whoseTable[self_player_guid], serial) then
+						whoseTable[self_player_guid] = nil
 					end
-					aura = whoseTable.mine
+					aura = whoseTable[self_player_guid]
 				else
 					for k, v in pairs(whoseTable) do
 						if RemoveAuraIfExpired(guid, spellId, filter, v, serial) then
@@ -460,25 +455,27 @@ function OvaleAura:GetStealable(unitId)
 	local start, ending
 	local serial = self_serial[guid]
 	for spellId, whoseTable in pairs(auraList) do
-		if RemoveAuraIfExpired(guid, spellId, "HELPFUL", whoseTable.other, serial) then
-			whoseTable.other = nil
-		end
-		local aura = whoseTable.other
-		if aura and aura.stealable then
-			if aura.start and (not start or aura.start < start) then
-				start = aura.start
+		for caster, aura in pairs(whoseTable) do
+			if RemoveAuraIfExpired(guid, spellId, "HELPFUL", aura, serial) then
+				whoseTable[caster] = nil
 			end
-			if aura.ending and (not ending or aura.ending > ending) then
-				ending = aura.ending
+			aura = whoseTable[caster]
+			if aura and aura.stealable then
+				if aura.start and (not start or aura.start < start) then
+					start = aura.start
+				end
+				if aura.ending and (not ending or aura.ending > ending) then
+					ending = aura.ending
+				end
 			end
 		end
 	end
 	return start, ending
 end

--- Look for my aura on any target.
+-- Look for an aura on any target, excluding the given GUID.
 -- Returns the earliest start time, the latest ending time, and the number of auras seen.
-function OvaleAura:GetMyAuraOnAnyTarget(spellId, filter, excludingGUID)
+function OvaleAura:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID)
 	local start, ending
 	local count = 0
 	for guid, auraTable in pairs(self_aura) do
@@ -486,19 +483,24 @@ function OvaleAura:GetMyAuraOnAnyTarget(spellId, filter, excludingGUID)
 			local serial = self_serial[guid]
 			for auraFilter, auraList in pairs(auraTable) do
 				if not filter or auraFilter == filter then
-					if auraList[spellId] then
-						if RemoveAuraIfExpired(guid, spellId, filter, auraList[spellId].mine, serial) then
-							auraList[spellId].mine = nil
-						end
-						local aura = auraList[spellId].mine
-						if aura then
-							if aura.start and (not start or aura.start < start) then
-								start = aura.start
-							end
-							if aura.ending and (not ending or aura.ending > ending) then
-								ending = aura.ending
+					local whoseTable = auraList[spellId]
+					if whoseTable then
+						for caster, aura in pairs(whoseTable) do
+							if not mine or caster == self_player_guid then
+								if RemoveAuraIfExpired(guid, spellId, filter, aura, serial) then
+									whoseTable[caster] = nil
+								end
+								aura = whoseTable[caster]
+								if aura then
+									if aura.start and (not start or aura.start < start) then
+										start = aura.start
+									end
+									if aura.ending and (not ending or aura.ending > ending) then
+										ending = aura.ending
+									end
+									count = count + 1
+								end
 							end
-							count = count + 1
 						end
 					end
 				end
@@ -511,9 +513,8 @@ end
 function OvaleAura:GetDamageMultiplier(spellId)
 	-- Calculate the base damage multiplier for all spells.
 	local damageMultiplier = 1
-	local playerGUID = OvaleGUID:GetGUID("player")
 	for auraSpellId, multiplier in pairs(OvaleData.selfDamageBuff) do
-		local count = select(3, self:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player"))
+		local count = select(3, self:GetAuraByGUID(self_player_guid, auraSpellId, filter, nil, "player"))
 		if count and count > 0 then
 			-- Try to account for a stacking aura.
 			-- multiplier = 1 + (multiplier - 1) * count
@@ -527,7 +528,7 @@ function OvaleAura:GetDamageMultiplier(spellId)
 		if si and si.damageAura then
 			for filter, auraList in pairs(si.damageAura) do
 				for auraSpellId, multiplier in pairs(auraList) do
-					count = select(3, self:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player"))
+					count = select(3, self:GetAuraByGUID(self_player_guid, auraSpellId, filter, nil, "player"))
 					if count and count > 0 then
 						-- Try to account for a stacking aura.
 						-- multiplier = 1 + (multiplier - 1) * count
diff --git a/OvaleCondition.lua b/OvaleCondition.lua
index 2f96be5..062e2d7 100644
--- a/OvaleCondition.lua
+++ b/OvaleCondition.lua
@@ -344,11 +344,12 @@ local function GetAura(condition)
 	return start, ending, stacks, tick, value, gain
 end

--- Front-end for OvaleState:GetMyAuraOnAnyTarget() using condition parameters.
+-- Front-end for OvaleState:GetAuraOnAnyTarget() using condition parameters.
 -- return start, ending, count
-local function GetMyAuraOnAnyTarget(condition, excludingUnit)
+local function GetAuraOnAnyTarget(condition, excludingUnit)
 	local spellId = condition[1]
 	local filter = GetFilter(condition)
+	local mine = GetMine(condition)
 	if excludingUnit then
 		excludingUnit = OvaleGUID:GetGUID(excludingUnit)
 	end
@@ -356,13 +357,13 @@ local function GetMyAuraOnAnyTarget(condition, excludingUnit)
 		Ovale:Log("GetAura: nil spellId")
 		return nil
 	end
-	local start, ending, count = OvaleState:GetMyAuraOnAnyTarget(spellId, filter, excludingUnit)
+	local start, ending, count = OvaleState:GetAuraOnAnyTarget(spellId, filter, mine, excludingUnit)

 	if not start then
-		Ovale:Logf("GetMyAuraOnAnyTarget: aura %s not found, filter=%s excludingUnit=%s", spellId, filter, excludingUnit)
+		Ovale:Logf("GetAuraOnAnyTarget: aura %s not found, filter=%s mine=%s excludingUnit=%s", spellId, filter, mine, excludingUnit)
 		return nil
 	end
-	Ovale:Logf("GetMyAuraOnAnyTarget: aura %s found, start=%s ending=%s count=%d", spellId, start, ending, stacks, count)
+	Ovale:Logf("GetAuraOnAnyTarget: aura %s found, start=%s ending=%s count=%d", spellId, start, ending, stacks, count)
 	return start, ending, count
 end

@@ -558,7 +559,7 @@ end
 -- @see DebuffCount

 OvaleCondition.conditions.buffcount = function(condition)
-	local start, ending, count = GetMyAuraOnAnyTarget(condition)
+	local start, ending, count = GetAuraOnAnyTarget(condition)
 	return start, ending, count, start, 0
 end
 OvaleCondition.conditions.debuffcount = OvaleCondition.conditions.buffcount
@@ -2136,7 +2137,7 @@ end
 --     Spell(thunder_clap)

 OvaleCondition.conditions.otherdebuffexpires = function(condition)
-	local start, ending = GetMyAuraOnAnyTarget(condition, "target")
+	local start, ending = GetAuraOnAnyTarget(condition, "target")
 	local timeBefore = TimeWithHaste(condition[2], condition.haste)
 	if not start then
 		ending = 0
@@ -2162,7 +2163,7 @@ OvaleCondition.conditions.otherbuffexpires = OvaleCondition.conditions.otherdebu
 --     Spell(devouring_plague)

 OvaleCondition.conditions.otherdebuffpresent = function(condition)
-	local start, ending = GetMyAuraOnAnyTarget(condition, "target")
+	local start, ending = GetAuraOnAnyTarget(condition, "target")
 	if not start then
 		return nil
 	end
@@ -2185,7 +2186,7 @@ OvaleCondition.conditions.otherbuffpresent = OvaleCondition.conditions.otherdebu
 --     Spell(devouring_plague)

 OvaleCondition.conditions.otherdebuffremains = function(condition)
-	local start, ending = GetMyAuraOnAnyTarget(condition, "target")
+	local start, ending = GetAuraOnAnyTarget(condition, "target")
 	if start and ending and start <= ending then
 		return start, ending, ending - start, start, -1
 	else
diff --git a/OvaleState.lua b/OvaleState.lua
index 9fa6e60..6cc2f51 100644
--- a/OvaleState.lua
+++ b/OvaleState.lua
@@ -565,7 +565,11 @@ function OvaleState:GetAuraByGUID(guid, spellId, filter, mine, unitId)
 		end
 	end
 	if aura then
-		Ovale:Logf("Found %s aura %s on %s", filter, spellId, guid)
+		if aura.stacks > 0 then
+			Ovale:Logf("Found %s aura %s on %s", filter, spellId, guid)
+		else
+			Ovale:Logf("Found %s aura %s on %s (removed)", filter, spellId, guid)
+		end
 		return aura.start, aura.ending, aura.stacks, aura.tick, aura.value, aura.gain
 	else
 		Ovale:Logf("Aura %s not found in state for %s", spellId, guid)
@@ -596,10 +600,11 @@ function OvaleState:GetAura(unitId, spellId, filter, mine)
 	end
 end

--- Look for my aura on any target.
+-- Look for an aura on any target, excluding the given GUID.
 -- Returns the earliest start time, the latest ending time, and the number of auras seen.
-function OvaleState:GetMyAuraOnAnyTarget(spellId, filter, excludingGUID)
-	local start, ending, count = OvaleAura:GetMyAuraOnAnyTarget(spellId, filter, excludingGUID)
+function OvaleState:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID)
+	local start, ending, count = OvaleAura:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID)
+	-- TODO: This is broken because it doesn't properly account for removed auras in the current frame.
 	for guid, auraTable in pairs(self.aura) do
 		if guid ~= excludingGUID then
 			for auraFilter, auraList in pairs(auraTable) do