Johnny C. Lam [07-19-13 - 05:33]
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)