Quantcast

Use reference-counted table pool to manage auras.

Johnny C. Lam [11-17-13 - 16:30]
Use reference-counted table pool to manage auras.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1191 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
OvaleAura.lua
OvaleCooldown.lua
OvaleFuture.lua
conditions/BuffAmount.lua
conditions/BuffComboPoints.lua
conditions/BuffDamageMultiplier.lua
conditions/BuffDuration.lua
conditions/BuffExpires.lua
conditions/BuffGain.lua
conditions/BuffRemains.lua
conditions/BuffSnapshot.lua
conditions/BuffStacks.lua
conditions/NextTick.lua
conditions/StaggerRemains.lua
conditions/TickTime.lua
conditions/Ticks.lua
conditions/TicksAdded.lua
conditions/TicksRemain.lua
diff --git a/OvaleAura.lua b/OvaleAura.lua
index ae79fad..289fe06 100644
--- a/OvaleAura.lua
+++ b/OvaleAura.lua
@@ -17,6 +17,7 @@ Ovale.OvaleAura = OvaleAura

 --<private-static-properties>
 local OvalePool = Ovale.OvalePool
+local OvalePoolRefCount = Ovale.OvalePoolRefCount

 -- Forward declarations for module dependencies.
 local OvaleData = nil
@@ -36,7 +37,7 @@ local API_GetTime = GetTime
 local API_UnitAura = UnitAura

 -- aura pool
-local self_pool = OvalePool("OvaleAura_pool")
+local self_pool = OvalePoolRefCount("OvaleAura_pool")
 do
 	self_pool.Clean = function(self, aura)
 		-- Release reference-counted snapshot before wiping.
@@ -397,7 +398,7 @@ function OvaleAura:Ovale_InactiveUnit(event, guid)
 	RemoveAurasForGUID(guid)
 end

-function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
+function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId)
 	if not guid then
 		Ovale:Log("nil guid does not exist in OvaleAura")
 		return nil
@@ -421,7 +422,7 @@ function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
 		end
 	end

-	local aura
+	local auraFound
 	local serial = self_serial[guid]

 	if type(spellId) == "number" then
@@ -433,17 +434,17 @@ function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
 						if RemoveAuraIfExpired(guid, spellId, filter, whoseTable[self_guid], serial) then
 							whoseTable[self_guid] = nil
 						end
-						aura = whoseTable[self_guid]
+						auraFound = whoseTable[self_guid]
 					else
 						for k, v in pairs(whoseTable) do
 							if RemoveAuraIfExpired(guid, spellId, filter, v, serial) then
 								whoseTable[k] = nil
 							end
-							aura = whoseTable[k]
-							if aura then break end
+							auraFound = whoseTable[k]
+							if auraFound then break end
 						end
 					end
-					if aura then break end
+					if auraFound then break end
 				end
 			end
 		end
@@ -456,8 +457,8 @@ function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
 							if RemoveAuraIfExpired(guid, auraId, filter, aura, serial) then
 								whoseTable[caster] = nil
 							end
-							aura = whoseTable[caster]
-							if aura and aura.debuffType == spellId then
+							auraFound = whoseTable[caster]
+							if auraFound and auraFound.debuffType == spellId then
 								-- Stop after finding the first aura of the given debuff type.
 								break
 							end
@@ -468,45 +469,22 @@ function OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
 		end
 	end

-	if aura then
-		-- If auraFound is a table, then copy the found aura into auraFound.
-		if auraFound then
-			for k, v in pairs(aura) do
-				auraFound[k] = v
-			end
-		end
-		return aura.start, aura.ending, aura.stacks, aura.gain
-	else
-		return nil
-	end
+	return auraFound
 end

-function OvaleAura:GetAura(unitId, spellId, filter, mine, auraFound)
+function OvaleAura:GetAura(unitId, spellId, filter, mine)
 	local guid = OvaleGUID:GetGUID(unitId)
 	if OvaleData.buffSpellList[spellId] then
-		local newAura, newStart, newEnding, newStacks, newGain
+		local auraFound
 		for auraId in pairs(OvaleData.buffSpellList[spellId]) do
-			local aura = self_pool:Get()
-			local start, ending, stacks, gain = self:GetAuraByGUID(guid, auraId, filter, mine, unitId, aura)
-			if start and (not newStart or stacks > newStacks) then
-				if newAura then
-					self_pool:Release(newAura)
-				end
-				newAura = aura
-				newStart = start
-				newEnding = ending
-				newStacks = stacks
-				newGain = gain
-			end
-		end
-		if auraFound then
-			for k, v in pairs(newAura) do
-				auraFound[k] = v
+			local aura = self:GetAuraByGUID(guid, auraId, filter, mine, unitId)
+			if aura and (not auraFound or aura.stacks > auraFound.stacks) then
+				auraFound = aura
 			end
 		end
-		return newStart, newEnding, newStacks, newGain
+		return auraFound
 	else
-		return self:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
+		return self:GetAuraByGUID(guid, spellId, filter, mine, unitId)
 	end
 end

@@ -601,6 +579,7 @@ function OvaleAura:GetTickLength(spellId)
 			return tick
 		end
 	end
+	return math.huge
 end

 function OvaleAura:Debug()
@@ -704,7 +683,7 @@ do
 					duration = state:GetDuration(auraId)
 				end

-				local start, ending, currentStacks, tick = state:GetAuraByGUID(guid, auraId, filter, true, target)
+				local aura = state:GetAuraByGUID(guid, auraId, filter, true, target)
 				local newAura = state:NewAura(guid, auraId, filter, state.currentTime)
 				newAura.mine = true

@@ -718,16 +697,17 @@ do
 				if type(stacks) == "number" and stacks == 0 then
 					Ovale:Logf("Aura %d is completely removed", auraId)
 					newAura.stacks = 0
-					newAura.start = start
-					newAura.ending = atTime
-				elseif ending and ((isChanneled and startCast < ending) or (not isChanneled and endCast <= ending)) then
+					newAura.start = aura and aura.start or 0
+					newAura.ending = aura and atTime or 0
+				elseif aura and ((isChanneled and startCast < aura.ending) or (not isChanneled and endCast <= aura.ending)) then
+					local start, ending, tick = aura.start, aura.ending, aura.tick
 					-- Spell starts channeling before the aura expires, or spellcast ends before the aura expires.
 					if stacks == "refresh" or stacks > 0 then
 						if stacks == "refresh" then
 							Ovale:Logf("Aura %d is refreshed", auraId)
-							newAura.stacks = currentStacks
+							newAura.stacks = aura.stacks
 						else -- if stacks > 0 then
-							newAura.stacks = currentStacks + stacks
+							newAura.stacks = aura.stacks + stacks
 							Ovale:Logf("Aura %d gains a stack to %d because of spell %d (ending was %s)", auraId, newAura.stacks, spellId, ending)
 						end
 						newAura.start = start
@@ -743,7 +723,7 @@ do
 						end
 						Ovale:Logf("Aura %d ending is now %f", auraId, newAura.ending)
 					elseif stacks < 0 then
-						newAura.stacks = currentStacks + stacks
+						newAura.stacks = aura.stacks + stacks
 						newAura.start = start
 						newAura.ending = ending
 						Ovale:Logf("Aura %d loses %d stack(s) to %d because of spell %d", auraId, -1 * stacks, newAura.stacks, spellId)
@@ -768,9 +748,9 @@ do
 		end
 	end

-	function statePrototype:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
+	function statePrototype:GetAuraByGUID(guid, spellId, filter, mine, unitId)
 		local state = self
-		local aura
+		local auraFound
 		if mine then
 			local auraTable = state.aura[guid]
 			if auraTable then
@@ -778,13 +758,13 @@ do
 					local auraList = auraTable[filter]
 					if auraList then
 						if auraList[spellId] and auraList[spellId].serial == state.serial then
-							aura = auraList[spellId]
+							auraFound = auraList[spellId]
 						end
 					end
 				else
 					for auraFilter, auraList in pairs(auraTable) do
 						if auraList[spellId] and auraList[spellId].serial == state.serial then
-							aura = auraList[spellId]
+							auraFound = auraList[spellId]
 							filter = auraFilter
 							break
 						end
@@ -792,59 +772,33 @@ do
 				end
 			end
 		end
-		if aura then
-			if aura.stacks > 0 then
+		if auraFound then
+			if auraFound.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
-			if auraFound then
-				for k, v in pairs(aura) do
-					auraFound[k] = v
-				end
-			end
-			return aura.start, aura.ending, aura.stacks, aura.gain
+			return auraFound
 		else
 			Ovale:Logf("Aura %s not found in state for %s", spellId, guid)
-			return OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
-		end
-	end
-
-	do
-		local aura = {}
-		local newAura = {}
-
-		function statePrototype:GetAura(unitId, spellId, filter, mine, auraFound)
-			local state = self
-			local guid = OvaleGUID:GetGUID(unitId)
-			if OvaleData.buffSpellList[spellId] then
-				if auraFound then wipe(newAura) end
-				local newStart, newEnding, newStacks, newGain
-				for auraId in pairs(OvaleData.buffSpellList[spellId]) do
-					if auraFound then wipe(aura) end
-					local start, ending, stacks, gain = state:GetAuraByGUID(guid, auraId, filter, mine, unitId, aura)
-					if start and (not newStart or stacks > newStacks) then
-						newStart = start
-						newEnding = ending
-						newStacks = stacks
-						newGain = gain
-						if auraFound then
-							wipe(newAura)
-							for k, v in pairs(aura) do
-								newAura[k] = v
-							end
-						end
-					end
-				end
-				if auraFound then
-					for k, v in pairs(newAura) do
-						auraFound[k] = v
-					end
+			return OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId)
+		end
+	end
+
+	function statePrototype:GetAura(unitId, spellId, filter, mine)
+		local state = self
+		local guid = OvaleGUID:GetGUID(unitId)
+		if OvaleData.buffSpellList[spellId] then
+			local auraFound
+			for auraId in pairs(OvaleData.buffSpellList[spellId]) do
+				local aura = state:GetAuraByGUID(guid, auraId, filter, mine, unitId)
+				if aura and (not auraFound or aura.stacks > auraFound.stacks) then
+					auraFound = aura
 				end
-				return newStart, newEnding, newStacks, newGain
-			else
-				return state:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound)
 			end
+			return auraFound
+		else
+			return state:GetAuraByGUID(guid, spellId, filter, mine, unitId)
 		end
 	end

@@ -902,11 +856,11 @@ do
 				local playerGUID = OvaleGUID:GetGUID("player")
 				for filter, auraList in pairs(si.damageAura) do
 					for auraSpellId, multiplier in pairs(auraList) do
-						local count = select(3, state:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player"))
-						if count and count > 0 then
+						local aura = state:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player")
+						if aura and aura.stacks > 0 then
 							local auraSpellInfo = OvaleData.spellInfo[auraSpellId]
 							if auraSpellInfo.stacking and auraSpellInfo.stacking > 0 then
-								multiplier = 1 + (multiplier - 1) * count
+								multiplier = 1 + (multiplier - 1) * aura.stacks
 							end
 							damageMultiplier = damageMultiplier * multiplier
 						end
diff --git a/OvaleCooldown.lua b/OvaleCooldown.lua
index 51ecb18..8712fa4 100644
--- a/OvaleCooldown.lua
+++ b/OvaleCooldown.lua
@@ -128,10 +128,10 @@ function OvaleCooldown:ApplySpellAfterCast(state, spellId, startCast, endCast, n
 			else
 				-- There is no cooldown if the buff named by "buffnocd" parameter is present.
 				if si.buffnocd then
-					local start, ending, stacks = state:GetAura("player", si.buffnocd)
-					if start and stacks and stacks > 0 then
-						Ovale:Logf("buffnocd stacks = %s, start = %s, ending = %s, startCast = %f", stacks, start, ending, startCast)
-						if start <= startCast and startCast < ending then
+					local aura = state:GetAura("player", si.buffnocd)
+					if aura and aura.stacks > 0 then
+						Ovale:Logf("buffnocd stacks = %s, start = %s, ending = %s, startCast = %f", aura.stacks, aura.start, aura.ending, startCast)
+						if aura.start <= startCast and startCast < aura.ending then
 							cd.duration = 0
 						end
 					end
diff --git a/OvaleFuture.lua b/OvaleFuture.lua
index 3a02fa4..f2f7ac7 100644
--- a/OvaleFuture.lua
+++ b/OvaleFuture.lua
@@ -112,11 +112,11 @@ local function GetDamageMultiplier(spellId)
 			local playerGUID = OvaleGUID:GetGUID("player")
 			for filter, auraList in pairs(si.damageAura) do
 				for auraSpellId, multiplier in pairs(auraList) do
-					local count = select(3, OvaleAura:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player"))
-					if count and count > 0 then
+					local aura = OvaleAura:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player")
+					if aura and aura.stacks > 0 then
 						local auraSpellInfo = OvaleData.spellInfo[auraSpellId]
 						if auraSpellInfo.stacking and auraSpellInfo.stacking > 0 then
-							multiplier = 1 + (multiplier - 1) * count
+							multiplier = 1 + (multiplier - 1) * aura.stacks
 						end
 						damageMultiplier = damageMultiplier * multiplier
 					end
diff --git a/conditions/BuffAmount.lua b/conditions/BuffAmount.lua
index 71a1b16..1f9b77d 100644
--- a/conditions/BuffAmount.lua
+++ b/conditions/BuffAmount.lua
@@ -13,11 +13,10 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the value of a buff as a number.  Not all buffs return an amount.
 	-- @name BuffAmount
 	-- @paramsig number
@@ -53,10 +52,13 @@ do
 		elseif value == 3 then
 			statName = "value3"
 		end
-		auraFound[statName] = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local value = auraFound[statName] or 0
-		return TestValue(start, ending, value, start, 0, comparator, limit)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local value = aura[statName] or 0
+			return TestValue(start, ending, value, start, 0, comparator, limit)
+		end
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffamount", false, BuffAmount)
diff --git a/conditions/BuffComboPoints.lua b/conditions/BuffComboPoints.lua
index 534013b..ca3bbac 100644
--- a/conditions/BuffComboPoints.lua
+++ b/conditions/BuffComboPoints.lua
@@ -13,11 +13,10 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the player's combo points for the given aura at the time the aura was applied on the target.
 	-- @name BuffComboPoints
 	-- @paramsig number or boolean
@@ -37,10 +36,13 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.combo = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local value = auraFound.combo or 1
-		return TestValue(start, ending, value, start, 0, comparator, limit)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local value = aura and aura.combo or 0
+			return TestValue(start, ending, value, start, 0, comparator, limit)
+		end
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffcombopoints", false, BuffComboPoints)
diff --git a/conditions/BuffDamageMultiplier.lua b/conditions/BuffDamageMultiplier.lua
index 5f7985b..6c5264d 100644
--- a/conditions/BuffDamageMultiplier.lua
+++ b/conditions/BuffDamageMultiplier.lua
@@ -13,11 +13,10 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the player's damage multiplier for the given aura at the time the aura was applied on the target.
 	-- @name BuffDamageMultiplier
 	-- @paramsig number or boolean
@@ -37,16 +36,15 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.snapshot = nil
-		auraFound.damageMultiplier = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local baseDamageMultiplier = 1
-		if auraFound.snapshot and auraFound.snapshot.baseDamageMultiplier then
-			baseDamageMultiplier = auraFound.snapshot.baseDamageMultiplier
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local baseDamageMultiplier = aura.snapshot and aura.snapshot.baseDamageMultiplier or 1
+			local damageMultiplier = aura.damageMultiplier or 1
+			local value = baseDamageMultiplier * damageMultiplier
+			return TestValue(start, ending, value, start, 0, comparator, limit)
 		end
-		local damageMultiplier = auraFound.damageMultiplier or 1
-		local value = baseDamageMultiplier * damageMultiplier
-		return TestValue(start, ending, value, start, 0, comparator, limit)
+		return Compare(1, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffdamagemultiplier", false, BuffDamageMultiplier)
diff --git a/conditions/BuffDuration.lua b/conditions/BuffDuration.lua
index 0d79627..ee6fdb7 100644
--- a/conditions/BuffDuration.lua
+++ b/conditions/BuffDuration.lua
@@ -13,6 +13,7 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

@@ -33,11 +34,13 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		local start, ending = state:GetAura(target, auraId, filter, mine)
-		start = start or 0
-		ending = ending or math.huge
-		value = ending - start
-		return TestValue(start, ending, value, start, 0, comparator, limit)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local value = ending - start
+			return TestValue(start, ending, value, start, 0, comparator, limit)
+		end
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffduration", false, BuffDuration)
diff --git a/conditions/BuffExpires.lua b/conditions/BuffExpires.lua
index 4531dab..5234d6e 100644
--- a/conditions/BuffExpires.lua
+++ b/conditions/BuffExpires.lua
@@ -60,16 +60,17 @@ do
 		local auraId, seconds = condition[1], condition[2]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		local start, ending = state:GetAura(target, auraId, filter, mine)
-		if not start or not ending then
-			return 0, math.huge
-		end
-		seconds = TimeWithHaste(seconds or 0, condition.haste)
-		if ending - seconds <= start then
-			return start, math.huge
-		else
-			return ending - seconds, math.huge
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			seconds = TimeWithHaste(seconds or 0, condition.haste)
+			if ending - seconds <= start then
+				return start, math.huge
+			else
+				return ending - seconds, math.huge
+			end
 		end
+		return 0, math.huge
 	end

 	OvaleCondition:RegisterCondition("buffexpires", false, BuffExpires)
@@ -102,16 +103,17 @@ do
 		local auraId, seconds = condition[1], condition[2]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		local start, ending = state:GetAura(target, auraId, filter, mine)
-		if not start or not ending then
-			return nil
-		end
-		seconds = TimeWithHaste(seconds or 0, condition.haste)
-		if ending - seconds <= start then
-			return nil
-		else
-			return start, ending - seconds
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			seconds = TimeWithHaste(seconds or 0, condition.haste)
+			if ending - seconds <= start then
+				return nil
+			else
+				return start, ending - seconds
+			end
 		end
+		return nil
 	end

 	OvaleCondition:RegisterCondition("buffpresent", false, BuffPresent)
diff --git a/conditions/BuffGain.lua b/conditions/BuffGain.lua
index 68c3e8f..80daca6 100644
--- a/conditions/BuffGain.lua
+++ b/conditions/BuffGain.lua
@@ -13,11 +13,10 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the time elapsed since the aura was last gained on the target.
 	-- @paramsig number or boolean
 	-- @param id The spell ID of the aura or the name of a spell list.
@@ -37,14 +36,16 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.gain = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local gain = auraFound.gain or 0
-		if true then
-			Ovale:Error("not implemented")
-			return nil
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local gain = aura.gain or 0
+			if true then
+				Ovale:Error("not implemented")
+				return nil
+			end
+			return TestValue(gain, math.huge, 0, gain, 1, comparator, limit)
 		end
-		return TestValue(gain, math.huge, 0, gain, 1, comparator, limit)
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffgain", false, BuffGain)
diff --git a/conditions/BuffRemains.lua b/conditions/BuffRemains.lua
index d458299..d5b2f07 100644
--- a/conditions/BuffRemains.lua
+++ b/conditions/BuffRemains.lua
@@ -40,12 +40,12 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		local start, ending = state:GetAura(target, auraId, filter, mine)
-		if not start or not ending then
-			return Compare(0, comparator, limit)
-		else
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
 			return TestValue(start, ending, ending - start, start, -1, comparator, limit)
 		end
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffremains", false, BuffRemains)
diff --git a/conditions/BuffSnapshot.lua b/conditions/BuffSnapshot.lua
index 3347347..39f624c 100644
--- a/conditions/BuffSnapshot.lua
+++ b/conditions/BuffSnapshot.lua
@@ -13,23 +13,22 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	-- Return the value of the stat from the aura snapshot at the time the aura was applied.
 	local function BuffSnapshot(statName, defaultValue, condition)
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.snapshot = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local value = defaultValue
-		if auraFound.snapshot and auraFound.snapshot[statName] then
-			value = auraFound.snapshot[statName]
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local value = aura.snapshot and aura.snapshot[statName] or defaultValue
+			return TestValue(start, ending, value, start, 0, comparator, limit)
 		end
-		return TestValue(start, ending, value, start, 0, comparator, limit)
+		return Compare(defaultValue, comparator, limit)
 	end

 	-- Return the value of the given critical strike chance from the aura snapshot at the time the aura was applied.
@@ -37,16 +36,17 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound[statName] = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local value = defaultValue
-		if auraFound.snapshot and auraFound.snapshot[statName] then
-			value = auraFound.snapshot[statName]
-		end
-		if condition.unlimited ~= 1 and value > 100 then
-			value = 100
+		local aura = state:GetAura(target, auraId, filter, mine)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local value = aura.snapshot and aura.snapshot[statName] or defaultValue
+			if condition.unlimited ~= 1 and value > 100 then
+				value = 100
+			end
+			return TestValue(start, ending, value, start, 0, comparator, limit)
 		end
-		return TestValue(start, ending, value, start, 0, comparator, limit)
+		return Compare(defaultValue, comparator, limit)
 	end

 	--- Get the player's attack power at the time the given aura was applied on the target.
diff --git a/conditions/BuffStacks.lua b/conditions/BuffStacks.lua
index f2c96d3..a786a69 100644
--- a/conditions/BuffStacks.lua
+++ b/conditions/BuffStacks.lua
@@ -13,6 +13,7 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

@@ -41,9 +42,13 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		local start, ending, stacks = state:GetAura(target, auraId, filter, mine)
-		stacks = stacks or 0
-		return TestValue(start, ending, stacks, start, 0, comparator, limit)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending = aura.start, aura.ending
+			local value = aura.stacks or 0
+			return TestValue(start, ending, value, start, 0, comparator, limit)
+		end
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("buffstacks", false, BuffStacks)
diff --git a/conditions/NextTick.lua b/conditions/NextTick.lua
index 4e83761..4eb4db0 100644
--- a/conditions/NextTick.lua
+++ b/conditions/NextTick.lua
@@ -13,11 +13,10 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the number of seconds until the next tick of a periodic aura on the target.
 	-- @name NextTick
 	-- @paramsig number or boolean
@@ -38,16 +37,17 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.tick = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local tick = auraFound.tick
-		if ending and ending < math.huge and tick then
-			while ending - tick > state.currentTime do
-				ending = ending - tick
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending, tick = aura.start, aura.ending, aura.tick
+			if ending < math.huge and tick then
+				while ending - tick > state.currentTime do
+					ending = ending - tick
+				end
+				return TestValue(0, ending, 0, ending, -1, comparator, limit)
 			end
-			return TestValue(0, ending, 0, ending, -1, comparator, limit)
 		end
-		return nil
+		return Compare(math.huge, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("nexttick", false, NextTick)
diff --git a/conditions/StaggerRemains.lua b/conditions/StaggerRemains.lua
index 24bd3ed..5666d67 100644
--- a/conditions/StaggerRemains.lua
+++ b/conditions/StaggerRemains.lua
@@ -39,17 +39,18 @@ do
 		local comparator, limit = condition[1], condition[2]
 		local target = ParseCondition(condition)
 		local state = OvaleState.state
-		local start, ending, stacks
-		start, ending, stacks = state:GetAura(target, HEAVY_STAGGER, "HARMFUL")
-		if not stacks or stacks == 0 then
-			start, ending, stacks = state:GetAura(target, MODERATE_STAGGER, "HARMFUL")
+		local aura = state:GetAura(target, HEAVY_STAGGER, "HARMFUL")
+		if not aura or aura.stacks == 0 then
+			aura = state:GetAura(target, MODERATE_STAGGER, "HARMFUL")
 		end
-		if not stacks or stacks == 0 then
-			start, ending, stacks = state:GetAura(target, LIGHT_STAGGER, "HARMFUL")
+		if not aura or aura.stacks == 0 then
+			aura = state:GetAura(target, LIGHT_STAGGER, "HARMFUL")
 		end
-		if start and ending then
+		if aura and aura.stacks > 0 then
+			local start, ending = aura.start, aura.ending
 			local stagger = API_UnitStagger(target)
-			return TestValue(start, ending, 0, ending, -1 * stagger / (ending - start), comparator, limit)
+			local rate = -1 * stagger / (ending - start)
+			return TestValue(start, ending, 0, ending, rate, comparator, limit)
 		end
 		return Compare(0, comparator, limit)
 	end
diff --git a/conditions/TickTime.lua b/conditions/TickTime.lua
index 4df956a..aface98 100644
--- a/conditions/TickTime.lua
+++ b/conditions/TickTime.lua
@@ -18,8 +18,6 @@ do
 	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition

-	local auraFound = {}
-
 	--- Get the number of seconds between ticks of a periodic aura on a target.
 	-- @name TickTime
 	-- @paramsig number or boolean
@@ -40,14 +38,12 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.tick = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local value = auraFound.tick
-		value = value or OvaleAura:GetTickLength(auraId)
-		if value then
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local value = aura.tick or OvaleAura:GetTickLength(auraId)
 			return Compare(value, comparator, limit)
 		end
-		return nil
+		return Compare(math.huge, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("ticktime", false, TickTime)
diff --git a/conditions/Ticks.lua b/conditions/Ticks.lua
index ca0740e..38e620f 100644
--- a/conditions/Ticks.lua
+++ b/conditions/Ticks.lua
@@ -15,11 +15,10 @@ do
 	local OvaleState = Ovale.OvaleState

 	local floor = math.floor
+	local select = select
 	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition

-	local auraFound = {}
-
 	--- Get the total number of ticks of a periodic aura.
 	-- @name Ticks
 	-- @paramsig number or boolean
@@ -34,23 +33,20 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.tick = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local tick = auraFound.tick
-		local duration, numTicks
-		if start then
-			-- Aura exists on the target
-			if ending and tick and tick > 0 then
-				duration = ending - start
-				numTicks = floor(duration / tick + 0.5)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		local numTicks
+		if aura then
+			local start, ending, tick = aura.start, aura.ending, aura.tick
+			if tick and tick > 0 then
+				numTicks = floor((ending - start) / tick + 0.5)
 			end
 		else
-			duration, tick, numTicks = state:GetDuration(auraId)
+			numTicks = select(3, state:GetDuration(auraId))
 		end
 		if numTicks then
 			return Compare(numTicks, comparator, limit)
 		end
-		return nil
+		return Compare(math.huge, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("ticks", false, Ticks)
diff --git a/conditions/TicksAdded.lua b/conditions/TicksAdded.lua
index fa4c4b4..43a336f 100644
--- a/conditions/TicksAdded.lua
+++ b/conditions/TicksAdded.lua
@@ -14,11 +14,10 @@ do
 	local OvaleCondition = Ovale.OvaleCondition
 	local OvaleState = Ovale.OvaleState

+	local Compare = OvaleCondition.Compare
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the number of ticks that would be added if the dot were refreshed.
 	-- Not implemented, always returns 0.
 	-- @name TicksAdded
@@ -33,10 +32,12 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.tick = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local tick = auraFound.tick
-		return TestValue(start, ending, 0, start, 0, comparator, limit)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending, tick = aura.start, aura.ending, aura.tick
+			return TestValue(start, ending, 0, start, 0, comparator, limit)
+		end
+		return Compare(0, comparator, limit)
 	end

 	OvaleCondition:RegisterCondition("ticksadded", false, TicksAdded)
diff --git a/conditions/TicksRemain.lua b/conditions/TicksRemain.lua
index e15bb42..35d9705 100644
--- a/conditions/TicksRemain.lua
+++ b/conditions/TicksRemain.lua
@@ -18,8 +18,6 @@ do
 	local ParseCondition = OvaleCondition.ParseCondition
 	local TestValue = OvaleCondition.TestValue

-	local auraFound = {}
-
 	--- Get the remaining number of ticks of a periodic aura on a target.
 	-- @name TicksRemain
 	-- @paramsig number or boolean
@@ -43,11 +41,12 @@ do
 		local auraId, comparator, limit = condition[1], condition[2], condition[3]
 		local target, filter, mine = ParseCondition(condition)
 		local state = OvaleState.state
-		auraFound.tick = nil
-		local start, ending = state:GetAura(target, auraId, filter, mine, auraFound)
-		local tick = auraFound.tick
-		if ending and tick and tick > 0 then
-			return TestValue(start, ending, 1, ending, -1/tick, comparator, limit)
+		local aura = state:GetAura(target, auraId, filter, mine)
+		if aura then
+			local start, ending, tick = aura.start, aura.ending, aura.tick
+			if tick and tick > 0 then
+				return TestValue(start, ending, 1, ending, -1/tick, comparator, limit)
+			end
 		end
 		return Compare(0, comparator, limit)
 	end