Quantcast

Major changes to OvaleFuture to properly handle spellcast event sequence.

Johnny C. Lam [07-19-13 - 05:33]
Major changes to OvaleFuture to properly handle spellcast event sequence.

* Fix long-standing bug regarding UNIT_SPELLCAST_* events.  The proper
  order order of events is actually:

	SENT > START > SUCCEEDED (cast-time spells)
	SENT > SUCCEEDED (instant-cast spells)

  Save the target, spell and lineID info from the SENT event to identify
  later events regarding the same spellcast.

* Save the most recent spellcast information in Ovale.lastSpellcast, which
  includes a snapshot of the stats that are active for that spellcast.
  Copy this snapshot information into DoT auras applied by the spellcast.
  This assumes that the DoT being applied was caused by the most recent
  spellcast.

* Auras changes that are simultaneous with a spellcast actually occur
  slightly after the UNIT_SPELLCAST_SUCCEEDED event and before the CLEU
  SPELL_DAMAGE (or other spell result) event.  Capture new snapshots and
  adjust the spellcast snapshot information accordingly to ensure
  accuracy.

This should fix the following tickets:

* Ticket 260 where target.Debuff*() and Last*() script conditions don't
  always show the same player stats for the same spell.  Both now pull
  from the same source so they show the same information.

* Ticket 262 where the DebuffComboPoints() condition was always returning
  zero since previously OvaleAura didn't have access to combo point
  information.  The combo point information is now saved with the
  spellcast snapshot that is copied into the DoT aura.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@980 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Ovale.lua
OvaleAura.lua
OvaleCondition.lua
OvaleFuture.lua
OvalePaperDoll.lua
OvaleState.lua
diff --git a/Ovale.lua b/Ovale.lua
index 66cc6df..d52e132 100644
--- a/Ovale.lua
+++ b/Ovale.lua
@@ -40,8 +40,8 @@ local OVALE_TRUE_STRING = tostring(true)
 Ovale.L = L
 --The current time, updated once per frame refresh.
 Ovale.now = API_GetTime()
--- The spell ID of the most recent spell cast.
-Ovale.lastSpellId = nil
+-- The most recent spell cast.
+Ovale.lastSpellcast = {}
 --The table of check boxes definition
 Ovale.casesACocher = {}
 --the frame with the icons
@@ -173,6 +173,13 @@ function Ovale:ToggleOptions()
 	self.frame:ToggleOptions()
 end

+function Ovale:UpdateLastSpellcast(spellcast)
+	wipe(self.lastSpellcast)
+	for k, v in pairs(spellcast) do
+		self.lastSpellcast[k] = v
+	end
+end
+
 function Ovale:UpdateVisibility()
 	local profile = OvaleOptions:GetProfile()

diff --git a/OvaleAura.lua b/OvaleAura.lua
index 61f0471..7a9456b 100644
--- a/OvaleAura.lua
+++ b/OvaleAura.lua
@@ -139,8 +139,8 @@ local function UnitGainedAura(event, guid, spellId, filter, casterGUID, icon, co
 	)
 	local addAura = not existingAura or not auraIsUnchanged
 	if addAura then
-		Ovale:DebugPrintf(OVALE_AURA_DEBUG, "%s: Adding %s %s (%s) to %s, aura.serial=%d",
-			event, filter, name, spellId, guid, aura.serial)
+		Ovale:DebugPrintf(OVALE_AURA_DEBUG, "%s: Adding %s %s (%s) to %s at %f, aura.serial=%d",
+			event, filter, name, spellId, guid, Ovale.now, aura.serial)
 		aura.icon = icon
 		aura.stacks = count
 		aura.debuffType = debuffType
@@ -158,20 +158,22 @@ local function UnitGainedAura(event, guid, spellId, filter, casterGUID, icon, co
 		aura.name = name
 		aura.value = value

+		-- Snapshot stats for DoTs.
 		if mine then
 			local si = OvaleData.spellInfo[spellId]
-			if si then
+			if si and si.tick then
 				-- Only set the initial tick information for new auras.
-				if not existingAura and si.tick then
+				if not existingAura then
 					aura.ticksSeen = 0
 					aura.tick = OvaleData:GetTickLength(spellId)
 				end
 				-- Determine whether to snapshot player stats for the aura or to keep the existing stats.
-				if Ovale.lastSpellId and OvaleData:NeedNewSnapshot(spellId, Ovale.lastSpellId) then
-					Ovale:DebugPrintf(OVALE_AURA_DEBUG, "%s: Snapshot stats for %s %s (%s) on %s at %f, gain=%f, aura.serial=%d",
-						event, filter, name, spellId, guid, Ovale.now, aura.gain, aura.serial)
-					OvalePaperDoll:SnapshotStats(aura)
-					aura.damageMultiplier = self:GetDamageMultiplier(spellId)
+				local lastSpellcast = Ovale.lastSpellcast
+				local lastSpellId = lastSpellcast and lastSpellcast.spellId
+				if lastSpellId and OvaleData:NeedNewSnapshot(spellId, lastSpellId) then
+					Ovale:DebugPrintf(OVALE_AURA_DEBUG, "%s: Snapshot stats for %s %s (%s) on %s from %f, now=%f, aura.serial=%d",
+						event, filter, name, spellId, guid, lastSpellcast.snapshotTime, Ovale.now, aura.serial)
+					OvalePaperDoll:SnapshotStats(aura, Ovale.lastSpellcast)
 				end
 			end
 		end
@@ -185,9 +187,10 @@ local function UnitGainedAura(event, guid, spellId, filter, casterGUID, icon, co
 end

 local function RemoveAuraIfExpired(guid, spellId, filter, aura, serial)
+	local self = OvaleAura
 	if aura and serial and aura.serial ~= serial then
-		Ovale:DebugPrintf(OVALE_AURA_DEBUG, "Removing expired %s %s (%s) from %s, serial=%d aura.serial=%d",
-			filter, aura.name, spellId, guid, serial, aura.serial)
+		Ovale:DebugPrintf(OVALE_AURA_DEBUG, "Removing expired %s %s (%s) from %s at %f, serial=%d aura.serial=%d",
+			filter, aura.name, spellId, guid, Ovale.now, serial, aura.serial)
 		self:SendMessage("Ovale_AuraRemoved", guid, spellId, aura.source)
 		self_pool:Release(aura)
 		return true
@@ -332,7 +335,7 @@ local function UpdateAuraTick(guid, spellId, timestamp)
 		aura.lastTickTime = timestamp
 		aura.tick = tick
 		aura.ticksSeen = ticksSeen
-		Ovale:DebugPrintf(OVALE_AURA_DEBUG, "Updating %s %s (%s) on %s, tick=%f", filter, aura.name, spellId, guid, tick)
+		Ovale:DebugPrintf(OVALE_AURA_DEBUG, "Updating %s %s (%s) on %s at %f, tick=%f", filter, aura.name, spellId, guid, Ovale.now, tick)
 	end
 end
 --</private-static-methods>
diff --git a/OvaleCondition.lua b/OvaleCondition.lua
index ea735b0..b11c796 100644
--- a/OvaleCondition.lua
+++ b/OvaleCondition.lua
@@ -622,7 +622,7 @@ OvaleCondition.conditions.debuffrangedattackpower = OvaleCondition.conditions.bu
 OvaleCondition.conditions.buffcombopoints = function(condition)
 	self_auraFound.comboPoints = nil
 	local start, ending = GetAura(condition, self_auraFound)
-	local comboPoints = self_auraFound.comboPoints or 0
+	local comboPoints = self_auraFound.comboPoints or 1
 	if start and ending and start <= ending then
 		return start, ending, comboPoints, start, 0
 	else
diff --git a/OvaleFuture.lua b/OvaleFuture.lua
index 4029d3d..7128c42 100644
--- a/OvaleFuture.lua
+++ b/OvaleFuture.lua
@@ -26,6 +26,7 @@ local ipairs = ipairs
 local pairs = pairs
 local select = select
 local tinsert = table.insert
+local tostring = tostring
 local tremove = table.remove
 local API_UnitCastingInfo = UnitCastingInfo
 local API_UnitChannelInfo = UnitChannelInfo
@@ -40,14 +41,20 @@ local self_activeSpellcast = {}
 local self_lastSpellcast = {}
 local self_pool = OvalePool:NewPool("OvaleFuture_pool")

--- Used to track the most recent target of a spellcast matching self_lastLineID.
-local self_lastTarget = nil
+-- Used to track the most recent spellcast started with UNIT_SPELLCAST_SENT.
 local self_lastLineID = nil
+local self_lastSpell = nil
+local self_lastTarget = nil
+
+-- Time at which a player aura was last added.
+local self_timeAuraAdded = nil

 -- The spell requests that have been sent to the server and are awaiting a reply.
 -- self_sentSpellcast[lineId] = timestamp
 local self_sentSpellcast = {}

+local OVALE_UNKNOWN_GUID = 0
+
 -- These CLEU events are eventually received after a successful spellcast.
 local OVALE_CLEU_SPELLCAST_RESULTS = {
 	SPELL_AURA_APPLIED = true,
@@ -71,8 +78,10 @@ OvaleFuture.traceSpellId = nil
 --<private-static-methods>
 local function TracePrintf(spellId, ...)
 	local self = OvaleFuture
-	if self.traceSpellId and self.traceSpellId == spellId then
-		Ovale:FormatPrint(...)
+	if self.traceSpellId then
+		if (self.traceSpellId == spellId) or (type(spellId) == "string" and OvaleData:GetSpellName(self.traceSpellId) == spellId) then
+			Ovale:FormatPrint(...)
+		end
 	end
 end

@@ -98,9 +107,9 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a
 	spellcast.stop = endTime
 	spellcast.channeled = channeled
 	spellcast.allowRemove = allowRemove
-	--TODO unable to know what is the real target
-	if lineId == self_lastLineID and self_lastTarget then
-		-- Ovale:FormatPrint("found lineId %d, target is %s", lineId, self_lastTarget)
+
+	-- Set the target from the data taken from UNIT_SPELLCAST_SENT if it's the same spellcast.
+	if lineId == self_lastLineID and OvaleData:GetSpellName(spellId) == self_lastSpell then
 		spellcast.target = self_lastTarget
 	else
 		spellcast.target = API_UnitGUID("target")
@@ -109,10 +118,8 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a
 		Ovale.now, OvaleData:GetSpellName(spellId), spellId, lineId, startTime, endTime, spellcast.target)

 	-- Snapshot the current stats for the spellcast.
-	Ovale.lastSpellId = spellId
 	OvalePaperDoll:SnapshotStats(spellcast)
 	spellcast.damageMultiplier = OvaleAura:GetDamageMultiplier(spellId)
-	tinsert(self_activeSpellcast, spellcast)

 	local si = OvaleData.spellInfo[spellId]
 	if si then
@@ -157,6 +164,8 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a
 		spellcast.removeOnSuccess = true
 	end

+	tinsert(self_activeSpellcast, spellcast)
+
 	ScoreSpell(spellId)
 	Ovale.refreshNeeded["player"] = true
 end
@@ -174,20 +183,41 @@ local function RemoveSpellFromQueue(spellId, lineId)
 	Ovale.refreshNeeded["player"] = true
 end

+-- UpdateLastSpellInfo() is called at the end of the event handler for OVALE_CLEU_SPELLCAST_RESULTS[].
+-- It saves the given spellcast as the most recent one on its target and ensures that the spellcast
+-- snapshot values are correctly adjusted for buffs that are added or cleared simultaneously with the
+-- spellcast.
 local function UpdateLastSpellInfo(spellcast)
-	if spellcast then
-		local targetGUID = spellcast.target
-		local spellId = spellcast.spellId
-		if targetGUID and spellId then
-			if not self_lastSpellcast[targetGUID] then
-				self_lastSpellcast[targetGUID] = {}
-			end
-			local oldSpellcast = self_lastSpellcast[targetGUID][spellId]
-			if oldSpellcast then
-				self_pool:Release(oldSpellcast)
+	local targetGUID = spellcast.target
+	local spellId = spellcast.spellId
+	if targetGUID and spellId then
+		if not self_lastSpellcast[targetGUID] then
+			self_lastSpellcast[targetGUID] = {}
+		end
+		local oldSpellcast = self_lastSpellcast[targetGUID][spellId]
+		if oldSpellcast then
+			self_pool:Release(oldSpellcast)
+		end
+		self_lastSpellcast[targetGUID][spellId] = spellcast
+
+		--[[
+			If any auras have been added between the start of the spellcast and this event,
+			then take a more recent snapshot of the player stats for this spellcast.
+
+			This is needed to see any auras that were applied at the same time as the
+			spellcast, e.g., potions or other on-use abilities or items.
+		]]--
+		if self_timeAuraAdded then
+			if self_timeAuraAdded >= spellcast.start and self_timeAuraAdded - spellcast.stop < 1 then
+				OvalePaperDoll:SnapshotStats(spellcast)
+				spellcast.damageMultiplier = OvaleAura:GetDamageMultiplier(spellId)
+				TracePrintf(spellId, "    Updated spell info for %s (%d) to snapshot from %f.",
+					OvaleData:GetSpellName(spellId), spellId, spellcast.snapshotTime)
 			end
-			self_lastSpellcast[targetGUID][spellId] = spellcast
 		end
+
+		-- Save this most recent spellcast.
+		Ovale:UpdateLastSpellcast(spellcast)
 	end
 end
 --</private-static-methods>
@@ -203,6 +233,7 @@ function OvaleFuture:OnEnable()
 	self:RegisterEvent("UNIT_SPELLCAST_SENT")
 	self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
 	self:RegisterEvent("UNIT_SPELLCAST_START")
+	self:RegisterMessage("Ovale_AuraAdded")
 	self:RegisterMessage("Ovale_InactiveUnit")
 end

@@ -215,17 +246,20 @@ function OvaleFuture:OnDisable()
 	self:UnregisterEvent("UNIT_SPELLCAST_SENT")
 	self:UnregisterEvent("UNIT_SPELLCAST_START")
 	self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED")
+	self:UnregisterMessage("Ovale_AuraAdded")
 	self:UnregisterMessage("Ovale_InactiveUnit")
 end

 function OvaleFuture:PLAYER_ENTERING_WORLD(event)
 	-- Empty out self_lastSpellcast.
-	for guid, spellTable in pairs(self_lastSpellcast) do
-		for spellId, spellcast in pairs(spellTable) do
-			spellTable[spellId] = nil
-			self_pool:Release(spellcast)
-		end
-		self_lastSpellcast[guid] = nil
+	for guid in pairs(self_lastSpellcast) do
+		self:Ovale_InactiveUnit(event, guid)
+	end
+end
+
+function OvaleFuture:Ovale_AuraAdded(event, guid, spellId, caster)
+	if guid == OvaleGUID:GetGUID("player") then
+		self_timeAuraAdded = Ovale.now
 	end
 end

@@ -275,43 +309,54 @@ function OvaleFuture:UNIT_SPELLCAST_INTERRUPTED(event, unit, name, rank, lineId,
 	end
 end

--- UNIT_SPELLCAST_SENT is triggered when the spellcast has finished.
--- Look up the active spellcast and fix up the target of the spell.
+-- UNIT_SPELLCAST_SENT is triggered when the spellcast is sent to the server.
+-- This is sent before all other UNIT_SPELLCAST_* events for the same spellcast.
 function OvaleFuture:UNIT_SPELLCAST_SENT(event, unit, spell, rank, target, lineId)
 	if unit == "player" then
+		self_lastLineID = lineId
+		self_lastSpell = spell
+
 		-- UNIT_TARGET may arrive out of order with UNIT_SPELLCAST* events, so we can't track
 		-- the target in an event handler.
-		local targetGUID
-		if target == API_UnitName("target") then
-			targetGUID = API_UnitGUID("target")
-		else
-			targetGUID = OvaleGUID:GetGUIDForName(target)
-		end
-		self_lastTarget = targetGUID
-		self_lastLineID = lineId
-		TracePrintf(spellId, "%s: %f %s, lineId=%d, targetGUID=%s", event, Ovale.now, spell, lineId, targetGUID)
-		for _, spellcast in ipairs(self_activeSpellcast) do
-			if spellcast.lineId == lineId then
-				spellcast.target = targetGUID
-				-- Update spellcast stats to the latest snapshot of the player's stats.
-				OvalePaperDoll:SnapshotStats(spellcast)
-				spellcast.damageMultiplier = OvaleAura:GetDamageMultiplier(spellId)
+		if target then
+			if target == API_UnitName("target") then
+				self_lastTarget = API_UnitGUID("target")
+			else
+				self_lastTarget = OvaleGUID:GetGUIDForName(target)
 			end
+		else
+			self_lastTarget = OVALE_UNKNOWN_GUID
 		end
+		TracePrintf(spell, "%s: %f %s on %s, lineId=%d", event, Ovale.now, spell, self_lastTarget, lineId)
 		self_sentSpellcast[lineId] = Ovale.now
 	end
 end

+-- UNIT_SPELLCAST_SUCCEEDED is triggered when a spellcast successfully completes.
+--[[
+	For a cast-time spell:
+		UNIT_SPELLCAST_SENT
+		UNIT_SPELLCAST_START
+		UNIT_SPELLCAST_SUCCEEDED
+	For an instant-cast spell:
+		UNIT_SPELLCAST_SENT
+		UNIT_SPELLCAST_SUCCEEDED
+]]--
 function OvaleFuture:UNIT_SPELLCAST_SUCCEEDED(event, unit, name, rank, lineId, spellId)
 	if unit == "player" then
 		TracePrintf(spellId, "%s: %f %d, lineId=%d", event, Ovale.now, spellId, lineId)
+
 		-- Search for a cast-time spell matching this spellcast that was added by UNIT_SPELLCAST_START.
 		for _, spellcast in ipairs(self_activeSpellcast) do
 			if spellcast.lineId == lineId then
 				spellcast.allowRemove = true
+				-- Take a more recent snapshot of the player stats for this cast-time spell.
+				OvalePaperDoll:SnapshotStats(spellcast)
+				spellcast.damageMultiplier = OvaleAura:GetDamageMultiplier(spellId)
 				return
 			end
 		end
+
 		--[[
 			This spell was an instant-cast spell, but only add it to the queue if it's not part
 			of a channeled spell.  A channeled spell is actually two separate spells, an
@@ -382,7 +427,7 @@ function OvaleFuture:COMBAT_LOG_EVENT_UNFILTERED(event, ...)
 	if sourceGUID == OvaleGUID:GetGUID("player") then
 		if OVALE_CLEU_SPELLCAST_RESULTS[event] then
 			local spellId, spellName = select(12, ...)
-			TracePrintf(spellId, "%s: %f %s (%d), lineId=%d", event, Ovale.now, spellName, spellId, lineId)
+			TracePrintf(spellId, "%s: %f %s (%d)", event, Ovale.now, spellName, spellId)
 			for index, spellcast in ipairs(self_activeSpellcast) do
 				if spellcast.allowRemove and (spellcast.spellId == spellId or spellcast.auraSpellId == spellId) then
 					if not spellcast.channeled and (spellcast.removeOnSuccess or event ~= "SPELL_CAST_SUCCESS") then
@@ -415,7 +460,7 @@ function OvaleFuture:ApplyInFlightSpells(now, ApplySpell)
 				ApplySpell(spellcast.spellId, spellcast.start, spellcast.stop, spellcast.stop, spellcast.nocd, spellcast.target, spellcast)
 			else
 				tremove(self_activeSpellcast, index)
-				UpdateLastSpellInfo(spellcast)
+				self_pool:Release(spellcast)
 				-- Decrement current index since item was removed and rest of items shifted up.
 				index = index - 1
 			end
diff --git a/OvalePaperDoll.lua b/OvalePaperDoll.lua
index 467f671..ed6f708 100644
--- a/OvalePaperDoll.lua
+++ b/OvalePaperDoll.lua
@@ -319,32 +319,40 @@ function OvalePaperDoll:SnapshotStats(t, source)
 		source = self.stat
 	end
 	for k in pairs(self.stat) do
-		t[k] = source[k]
+		if source[k] then
+			t[k] = source[k]
+		end
+	end
+	-- Copy other properties that are relevant for auras that might be present.
+	-- TODO: Holy power?
+	if source.comboPoints then
+		t.comboPoints = source.comboPoints
 	end
 end

-function OvalePaperDoll:Debug()
+function OvalePaperDoll:Debug(stat)
+	stat = stat or self.stat
 	Ovale:FormatPrint("Class: %s", self.class)
 	Ovale:FormatPrint("Level: %d", self.level)
 	Ovale:FormatPrint("Specialization: %s", self.specialization)
-	Ovale:FormatPrint("Agility: %d", self.stat.agility)
-	Ovale:FormatPrint("Intellect: %d", self.stat.intellect)
-	Ovale:FormatPrint("Spirit: %d", self.stat.spirit)
-	Ovale:FormatPrint("Stamina: %d", self.stat.stamina)
-	Ovale:FormatPrint("Strength: %d", self.stat.strength)
-	Ovale:FormatPrint("AP: %d", self.stat.attackPower)
-	Ovale:FormatPrint("RAP: %d", self.stat.rangedAttackPower)
-	Ovale:FormatPrint("Spell bonus damage: %d", self.stat.spellBonusDamage)
-	Ovale:FormatPrint("Spell bonus healing: %d", self.stat.spellBonusHealing)
-	Ovale:FormatPrint("Spell critical strike effect: %f%%", self.stat.spellCrit)
-	Ovale:FormatPrint("Spell haste effect: %f%%", self.stat.spellHaste)
-	Ovale:FormatPrint("Melee critical strike effect: %f%%", self.stat.meleeCrit)
-	Ovale:FormatPrint("Melee haste effect: %f%%", self.stat.meleeHaste)
-	Ovale:FormatPrint("Ranged critical strike effect: %f%%", self.stat.rangedCrit)
-	Ovale:FormatPrint("Ranged haste effect: %f%%", self.stat.rangedHaste)
-	Ovale:FormatPrint("Mastery effect: %f%%", self.stat.masteryEffect)
-	Ovale:FormatPrint("Damage multiplier: %f", self.stat.damageMultiplier)
-	Ovale:FormatPrint("Weapon damage (mainhand): %f", self.stat.mainHandWeaponDamage)
-	Ovale:FormatPrint("Weapon damage (offhand): %f", self.stat.offHandWeaponDamage)
+	Ovale:FormatPrint("Agility: %d", stat.agility)
+	Ovale:FormatPrint("Intellect: %d", stat.intellect)
+	Ovale:FormatPrint("Spirit: %d", stat.spirit)
+	Ovale:FormatPrint("Stamina: %d", stat.stamina)
+	Ovale:FormatPrint("Strength: %d", stat.strength)
+	Ovale:FormatPrint("Attack power: %d", stat.attackPower)
+	Ovale:FormatPrint("Ranged attack power: %d", stat.rangedAttackPower)
+	Ovale:FormatPrint("Spell bonus damage: %d", stat.spellBonusDamage)
+	Ovale:FormatPrint("Spell bonus healing: %d", stat.spellBonusHealing)
+	Ovale:FormatPrint("Spell critical strike effect: %f%%", stat.spellCrit)
+	Ovale:FormatPrint("Spell haste effect: %f%%", stat.spellHaste)
+	Ovale:FormatPrint("Melee critical strike effect: %f%%", stat.meleeCrit)
+	Ovale:FormatPrint("Melee haste effect: %f%%", stat.meleeHaste)
+	Ovale:FormatPrint("Ranged critical strike effect: %f%%", stat.rangedCrit)
+	Ovale:FormatPrint("Ranged haste effect: %f%%", stat.rangedHaste)
+	Ovale:FormatPrint("Mastery effect: %f%%", stat.masteryEffect)
+	Ovale:FormatPrint("Damage multiplier: %f", stat.damageMultiplier)
+	Ovale:FormatPrint("Weapon damage (mainhand): %f", stat.mainHandWeaponDamage)
+	Ovale:FormatPrint("Weapon damage (offhand): %f", stat.offHandWeaponDamage)
 end
 --</public-static-methods>
diff --git a/OvaleState.lua b/OvaleState.lua
index 4949f00..75f1467 100644
--- a/OvaleState.lua
+++ b/OvaleState.lua
@@ -153,7 +153,7 @@ function OvaleState:UpdatePowerRates()
 end

 function OvaleState:Reset()
-	self.lastSpellId = Ovale.lastSpellId
+	self.lastSpellId = Ovale.lastSpellcast and Ovale.lastSpellcast.spellId
 	self.serial = self.serial + 1
 	self.currentTime = self.maintenant
 	Ovale:Logf("Reset state with current time = %f", self.currentTime)