From d80860eeb8df8cdb3cacbf4a30a025192a257425 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Sun, 7 Jul 2013 04:43:08 +0000 Subject: [PATCH] Snapshot player stats when a spell is cast and when DoTs are applied. The most recent successfully landed cast of a spell is saved in a table indexed by target and spell ID, and contains all of the information for that spellcast, including cast time and also a snapshot of the player stats. Player stats are snapshotted both at the start of a cast and when it is sent to the server so that OvaleState can approximately know the player's stats at the end an active spellcast. Player stats are also snapshotted when a DoT is applied or refreshed. Introduce a new generalized public method OvaleFuture:GetLastSpellInfo() that returns information about the last successfully landed spell. Remove the following superseded methods: GetLastAttackPower GetLastComboPoints GetLastCritChance GetLastDamageMultiplier GetLastSpellpower Change the following conditions to take a target since spellcast information is also tracked by target: LastSpellAttackPower LastSpellComboPoints LastSpellCritChance LastSpellDamageMultiplier LastSpellEstimatedDamage LastSpellMastery LastSpellSpellpower git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@941 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- OvaleAura.lua | 12 ++++-- OvaleCondition.lua | 100 +++++++++++++++++++++++++++++++--------------- OvaleFuture.lua | 113 ++++++++++++++++++++++++++++++---------------------- OvalePaperDoll.lua | 27 ++++++++++--- OvaleState.lua | 10 +++-- 5 files changed, 169 insertions(+), 93 deletions(-) diff --git a/OvaleAura.lua b/OvaleAura.lua index e61dd7a..66e7fd0 100644 --- a/OvaleAura.lua +++ b/OvaleAura.lua @@ -17,6 +17,7 @@ Ovale.OvaleAura = OvaleAura -- local OvaleData = Ovale.OvaleData local OvaleGUID = Ovale.OvaleGUID +local OvalePaperDoll = Ovale.OvalePaperDoll local OvalePool = Ovale.OvalePool local ipairs = ipairs @@ -94,7 +95,7 @@ local OVALE_CLEU_TICK_EVENTS = { -- -- -local function UnitGainedAura(guid, spellId, filter, casterGUID, icon, count, debuffType, duration, expirationTime, isStealable, name, value) +local function UnitGainedAura(event, guid, spellId, filter, casterGUID, icon, count, debuffType, duration, expirationTime, isStealable, name, value) if not self_aura[guid][filter] then self_aura[guid][filter] = {} end @@ -149,12 +150,15 @@ local function UnitGainedAura(guid, spellId, filter, casterGUID, icon, count, de aura.name = name aura.value = value - -- Only set the tick information for new auras. - if mine and not existingAura then + -- Only snapshot stats for periodic auras that have been applied or re-applied. + -- If SPELL_AURA_REFRESH didn't fire, then the aura was extended by adding ticks, + -- which doesn't re-snapshot stats. + if mine and (not existingAura or event == "SPELL_AURA_REFRESH") then local si = OvaleData.spellInfo[spellId] if si and si.tick then aura.ticksSeen = 0 aura.tick = OvaleData:GetTickLength(spellId) + OvalePaperDoll:SnapshotStats(aura.gain, aura) end end end @@ -259,7 +263,7 @@ local function ScanUnitAuras(event, unitId, guid) end else local casterGUID = OvaleGUID:GetGUID(unitCaster) - local added = UnitGainedAura(guid, spellId, filter, casterGUID, icon, count, debuffType, duration, expirationTime, isStealable, name, value1) + local added = UnitGainedAura(event, guid, spellId, filter, casterGUID, icon, count, debuffType, duration, expirationTime, isStealable, name, value1) if added then Ovale.refreshNeeded[unitId] = true end diff --git a/OvaleCondition.lua b/OvaleCondition.lua index 2f569cd..0a23a02 100644 --- a/OvaleCondition.lua +++ b/OvaleCondition.lua @@ -266,10 +266,11 @@ local function GetMine(condition) return true end -local function GetTarget(condition) +local function GetTarget(condition, defaultTarget) local target = condition.target + defaultTarget = defaultTarget or "player" if not target then - return "player" + return defaultTarget elseif target == "target" then return OvaleCondition.defaultTarget else @@ -1079,10 +1080,13 @@ OvaleCondition.conditions.critchance = function(condition) return Compare(OvalePaperDoll.stat.spellCrit, condition[1], condition[2]) end ---- Get the current estimated damage of a spell if it is a critical strike. +--- Get the current estimated damage of a spell on the target if it is a critical strike. -- @name CritDamage -- @paramsig number -- @param id The spell ID. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=player. +-- Valid values: player, target, focus, pet. -- @return The estimated critical strike damage of the given spell. -- @see Damage, LastSpellDamage, LastSpellEstimatedDamage @@ -1093,7 +1097,7 @@ OvaleCondition.conditions.critdamage = function(condition) return start, ending, critFactor * value, critFactor * origin, critFactor * rate end ---- Get the current estimated damage of a spell. +--- Get the current estimated damage of a spell on the target. -- The calculated damage takes into account the current attack power, spellpower and combo points (if used). -- The damage is computed from information for the spell set via SpellInfo(...): -- @@ -1101,13 +1105,17 @@ end -- @name Damage -- @paramsig number -- @param id The spell ID. --- @return The estimated damage of the given spell. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=player. +-- Valid values: player, target, focus, pet. +-- @return The estimated damage of the given spell on the target. -- @see CritDamage, LastSpellDamage, LastSpellEstimatedDamage -- @usage --- if {Damage(rake) / LastSpellEstimateDamage(rake)} >1.1 +-- if {target.Damage(rake) / target.LastSpellEstimateDamage(rake)} >1.1 -- Spell(rake) OvaleCondition.conditions.damage = function(condition) + -- TODO: Use target's debuffs in this calculation. local spellId = condition[1] local value, origin, rate = ComputeFunctionParam(spellId, "damage") if value then @@ -1133,7 +1141,7 @@ OvaleCondition.conditions.damagemultiplier = function(condition) return 0, nil, OvaleState:GetDamageMultiplier(condition[1]), 0, 0 end ---- Get the damage taken in the previous time interval. +--- Get the damage taken by the player in the previous time interval. -- @name DamageTaken -- @paramsig number -- @param interval The number of seconds before now. @@ -1779,7 +1787,7 @@ OvaleCondition.conditions.lastspelldamage = function(condition) return Compare(OvaleSpellDamage:Get(spellId), condition[2], condition[3]) end ---- Get the estimated damage of the most recent cast of a spell. +--- Get the estimated damage of the most recent cast of the player's spell on the target. -- The calculated damage takes into account the values of attack power, spellpower and combo points (if used) -- at the time the spell was most recent cast. -- The damage is computed from information for the spell set via SpellInfo(...): @@ -1788,108 +1796,132 @@ end -- @name LastSpellEstimatedDamage -- @paramsig number -- @param id The spell ID. --- @return The estimated damage of the most recent cast of the given spell. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. +-- @return The estimated damage of the most recent cast of the given spell by the player. -- @see Damage, LastSpellDamage -- @usage --- if {Damage(rake) / LastSpellEstimateDamage(rake)} >1.1 +-- if {Damage(rake) / target.LastSpellEstimateDamage(rake)} >1.1 -- Spell(rake) OvaleCondition.conditions.lastspellestimateddamage = function(condition) local spellId = condition[1] - local ap = OvaleFuture:GetLastAttackPower(spellId) - local sp = OvaleFuture:GetLastSpellpower(spellId) - local combo = OvaleFuture:GetLastComboPoints(spellId) - local dm = OvaleFuture:GetLastDamageMultiplier(spellId) or 1 + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + local ap = GetLastSpellInfo(guid, spellId, "attackPower") + local sp = GetLastSpellInfo(guid, spellId, "spellBonusDamage") + local combo = GetLastSpellInfo(guid, spellId, "comboPoints") + local dm = GetLastSpellInfo(guid, condition, "damageMultiplier") or 1 return 0, nil, OvaleData:GetDamage(spellId, ap, sp, combo) * dm, 0, 0 end ---- Get the damage multiplier of the most recent cast of a spell. +--- Get the damage multiplier of the most recent cast of a spell on the target. -- This currently does not take into account increased damage due to mastery. -- @name LastSpellDamageMultiplier -- @paramsig number or boolean -- @param id The spell ID. -- @param operator Optional. Comparison operator: equal, less, more. -- @param number Optional. The number to compare against. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. -- @return The previous damage multiplier. -- @return A boolean value for the result of the comparison. -- @see DamageMultiplier -- @usage --- if {DamageMultiplier(rupture) / LastSpellDamageMultiplier(rupture)} >1.1 +-- if {DamageMultiplier(rupture) / target.LastSpellDamageMultiplier(rupture)} >1.1 -- Spell(rupture) OvaleCondition.conditions.lastspelldamagemultiplier = function(condition) - return Compare(OvaleFuture:GetLastDamageMultiplier(condition[1]), condition[2], condition[3]) + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + return Compare(OvaleFuture:GetLastSpellInfo(guid, condition[1], "damageMultiplier"), condition[2], condition[3]) end ---- Get the attack power of the player during the most recent cast of a spell. +--- Get the attack power of the player during the most recent cast of a spell on the target. -- @name LastSpellAttackPower -- @paramsig number or boolean -- @param id The spell ID. -- @param operator Optional. Comparison operator: equal, less, more. -- @param number Optional. The number to compare against. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. -- @return The previous attack power. -- @return A boolean value for the result of the comparison. -- @see AttackPower -- @usage --- if {Attackpower() / LastSpellAttackPower(hemorrhage)} >1.25 +-- if {AttackPower() / target.LastSpellAttackPower(hemorrhage)} >1.25 -- Spell(hemorrhage) OvaleCondition.conditions.lastspellattackpower = function(condition) - return Compare(OvaleFuture:GetLastAttackPower(condition[1]), condition[2], condition[3]) + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + return Compare(OvaleFuture:GetLastSpellInfo(guid, condition[1], "attackPower"), condition[2], condition[3]) end ---- Get the spellpower of the player during the most recent cast of a spell. +--- Get the spellpower of the player during the most recent cast of a spell on the target. -- @name LastSpellSpellpower -- @paramsig number or boolean -- @param id The spell ID. -- @param operator Optional. Comparison operator: equal, less, more. -- @param number Optional. The number to compare against. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. -- @return The previous spellpower. -- @return A boolean value for the result of the comparison. -- @see Spellpower -- @usage --- if {Spellpower() / LastSpellSpellpower(living_bomb)} >1.25 +-- if {Spellpower() / target.LastSpellSpellpower(living_bomb)} >1.25 -- Spell(living_bomb) OvaleCondition.conditions.lastspellspellpower = function(condition) - return Compare(OvaleFuture:GetLastSpellpower(condition[1]), condition[2], condition[3]) + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + return Compare(OvaleFuture:GetLastSpellInfo(guid, condition[1], "spellBonusDamage"), condition[2], condition[3]) end ---- Get the number of combo points consumed by the most recent cast of a spell for a feral druid or a rogue. +--- Get the number of combo points consumed by the most recent cast of a spell on the target for a feral druid or a rogue. -- @name LastSpellComboPoints -- @paramsig number or boolean -- @param id The spell ID. -- @param operator Optional. Comparison operator: equal, less, more. -- @param number Optional. The number to compare against. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. -- @return The number of combo points. -- @return A boolean value for the result of the comparison. -- @see ComboPoints -- @usage --- if ComboPoints() >3 and LastComboPoints(rip) <3 +-- if ComboPoints() >3 and target.LastComboPoints(rip) <3 -- Spell(rip) OvaleCondition.conditions.lastspellcombopoints = function(condition) - return Compare(OvaleFuture:GetLastComboPoints(condition[1]), condition[2], condition[3]) + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + return Compare(OvaleFuture:GetLastSpellInfo(guid, condition[1], "comboPoints"), condition[2], condition[3]) end ---- Get the critical strike chance of the player during the most recent cast of a spell. +--- Get the critical strike chance of the player during the most recent cast of a spell on the target. -- @name LastSpellCritChance -- @paramsig number or boolean -- @param id The spell ID. -- @param operator Optional. Comparison operator: equal, less, more. -- @param number Optional. The number to compare against. --- @return The previous mastery effect. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. +-- @return The previous critical strike chance. -- @return A boolean value for the result of the comparison. -- @see Mastery -- @usage --- if {CritChance(shadow_bolt) - LastSpellCritChance(shadow_bolt)} > 1000 +-- if CritChance(shadow_bolt) > LastSpellCritChance(shadow_bolt) -- Spell(metamorphosis) OvaleCondition.conditions.lastspellcritchance = function(condition) - return Compare(OvaleFuture:GetLastCritChance(condition[1]), condition[2], condition[3]) + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + return Compare(OvaleFuture:GetLastSpellInfo(guid, condition[1], "spellCrit"), condition[2], condition[3]) end ---- Get the mastery effect of the player during the most recent cast of a spell. +--- Get the mastery effect of the player during the most recent cast of a spell on the target. -- Mastery effect is the effect of the player's mastery, typically a percent-increase to damage -- or a percent-increase to chance to trigger some effect. -- @name LastSpellMastery @@ -1897,6 +1929,9 @@ end -- @param id The spell ID. -- @param operator Optional. Comparison operator: equal, less, more. -- @param number Optional. The number to compare against. +-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition. +-- Defaults to target=target. +-- Valid values: player, target, focus, pet. -- @return The previous mastery effect. -- @return A boolean value for the result of the comparison. -- @see Mastery @@ -1905,7 +1940,8 @@ end -- Spell(metamorphosis) OvaleCondition.conditions.lastspellmastery = function(condition) - return Compare(OvaleFuture:GetLastMasteryEffect(condition[1]), condition[2], condition[3]) + local guid = OvaleGUID:GetGUID(GetTarget(condition, "target")) + return Compare(OvaleFuture:GetLastSpellInfo(guid, condition[1], "masteryEffect"), condition[2], condition[3]) end --- Get the time elapsed in seconds since the player's previous melee swing (white attack). diff --git a/OvaleFuture.lua b/OvaleFuture.lua index 5f4ed9b..8e47957 100644 --- a/OvaleFuture.lua +++ b/OvaleFuture.lua @@ -35,6 +35,8 @@ local self_playerName = nil -- The spells that the player is casting or has cast but are still in-flight toward their targets. local self_activeSpellcast = {} +-- self_lastSpellcast[targetGUID][spellId] is the most recent spell that has landed successfully on the target. +local self_lastSpellcast = {} local self_pool = OvalePool:NewPool("OvaleFuture_pool") -- Used to track the most recent target of a spellcast matching self_lastLineID. @@ -45,14 +47,6 @@ local self_lastLineID = nil -- self_sentSpellcast[lineId] = timestamp local self_sentSpellcast = {} --- relevant player stats the last time the spell was cast, indexed by spell ID -local self_lastAttackPower = {} -local self_lastComboPoints = {} -local self_lastDamageMultiplier = {} -local self_lastMasteryEffect = {} -local self_lastSpellpower = {} -local self_lastCritChance = {} - -- These CLEU events are eventually received after a successful spellcast. local OVALE_CLEU_SPELLCAST_RESULTS = { SPELL_AURA_APPLIED = true, @@ -117,11 +111,8 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a -- Snapshot the current stats for the spellcast. self.lastSpellId = spellId - self_lastAttackPower[spellId] = OvalePaperDoll.stat.attackPower - self_lastSpellpower[spellId] = OvalePaperDoll.stat.spellBonusDamage - self_lastCritChance[spellId] = OvalePaperDoll.stat.spellCrit - self_lastDamageMultiplier[spellId] = OvaleAura:GetDamageMultiplier(spellId) - self_lastMasteryEffect[spellId] = OvalePaperDoll.stat.masteryEffect + OvalePaperDoll:SnapshotStats(Ovale.now, spellcast) + spellcast.damageMultiplier = OvaleAura:GetDamageMultiplier(spellId) tinsert(self_activeSpellcast, spellcast) local si = OvaleData.spellInfo[spellId] @@ -132,7 +123,7 @@ local function AddSpellToQueue(spellId, lineId, startTime, endTime, channeled, a if si.combo == 0 then local comboPoints = OvaleComboPoints.combo if comboPoints > 0 then - self_lastComboPoints[spellId] = comboPoints + spellcast.comboPoints = comboPoints end end @@ -183,28 +174,71 @@ local function RemoveSpellFromQueue(spellId, lineId) end Ovale.refreshNeeded["player"] = true end + +local function UpdateLastSpellInfo(spellcast) + if spellcast then + local targetGUID = spellcast.target + if targetGUID then + if not self_lastSpellcast[targetGUID] then + self_lastSpellcast[targetGUID] = {} + end + local oldSpellcast = self_lastSpellcast[targetGUID][spellId] + if oldSpellcast then + self_lastSpellcast[targetGUID][spellId] = spellcast + self_pool:Release(oldSpellcast) + end + end + end +end -- -- function OvaleFuture:OnEnable() self_playerName = API_UnitName("player") - self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") - self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") - self:RegisterEvent("UNIT_SPELLCAST_START") + self:RegisterEvent("PLAYER_ENTERING_WORLD") self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") + self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") self:RegisterEvent("UNIT_SPELLCAST_SENT") + self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") + self:RegisterEvent("UNIT_SPELLCAST_START") + self:RegisterMessage("Ovale_InactiveUnit") end function OvaleFuture:OnDisable() - self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") - self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED") - self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START") + self:UnregisterEvent("PLAYER_ENTERING_WORLD") + self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START") self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") - self:UnregisterEvent("UNIT_SPELLCAST_START") + self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED") self:UnregisterEvent("UNIT_SPELLCAST_SENT") + self:UnregisterEvent("UNIT_SPELLCAST_START") + self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") + 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 + end +end + +function OvaleFuture:Ovale_InactiveUnit(event, guid) + -- Remove spellcasts for inactive units. + local spellTable = self_lastSpellcast[guid] + if spellTable then + for spellId, spellCast in pairs(spellTable) do + spellTable[spellId] = nil + self_pool:Release(spellcast) + end + self_lastSpellcast[guid] = nil + end end function OvaleFuture:UNIT_SPELLCAST_CHANNEL_START(event, unit, name, rank, lineId, spellId) @@ -259,6 +293,8 @@ function OvaleFuture:UNIT_SPELLCAST_SENT(event, unit, spell, rank, target, lineI 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(Ovale.now, spellcast) end end self_sentSpellcast[lineId] = Ovale.now @@ -343,7 +379,6 @@ function OvaleFuture:COMBAT_LOG_EVENT_UNFILTERED(event, ...) -- Called when a missile reaches or misses its target if sourceGUID == OvaleGUID:GetGUID("player") then - -- Do not use SPELL_CAST_SUCCESS because it is sent when the missile has not reached the target. 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) @@ -352,9 +387,9 @@ function OvaleFuture:COMBAT_LOG_EVENT_UNFILTERED(event, ...) if not spellcast.channeled and (spellcast.removeOnSuccess or event ~= "SPELL_CAST_SUCCESS") then TracePrintf(spellId, " Spell finished: %f %s (%d)", Ovale.now, spellName, spellId) tremove(self_activeSpellcast, index) - self_pool:Release(spellcast) + UpdateLastSpellInfo(spellcast) Ovale.refreshNeeded["player"] = true - end + end break end end @@ -376,10 +411,10 @@ function OvaleFuture:ApplyInFlightSpells(now, ApplySpell) if not (si and si.toggle) then Ovale:Logf("now = %f, spellId = %d, endCast = %f", now, spellcast.spellId, spellcast.stop) if now - spellcast.stop < 5 then - ApplySpell(spellcast.spellId, spellcast.start, spellcast.stop, spellcast.stop, spellcast.nocd, spellcast.target) + ApplySpell(spellcast.spellId, spellcast.start, spellcast.stop, spellcast.stop, spellcast.nocd, spellcast.target, spellcast) else tremove(self_activeSpellcast, index) - self_pool:Release(spellcast) + UpdateLastSpellInfo(spellcast) -- Decrement current index since item was removed and rest of items shifted up. index = index - 1 end @@ -387,28 +422,10 @@ function OvaleFuture:ApplyInFlightSpells(now, ApplySpell) end end -function OvaleFuture:GetLastAttackPower(spellId) - return self_lastAttackPower[spellId] or 0 -end - -function OvaleFuture:GetLastComboPoints(spellId) - return self_lastComboPoints[spellId] or 0 -end - -function OvaleFuture:GetLastDamageMultiplier(spellId) - return self_lastDamageMultiplier[spellId] or 1 -end - -function OvaleFuture:GetLastMasteryEffect(spellId) - return self_lastMasteryEffect[spellId] or 0 -end - -function OvaleFuture:GetLastSpellpower(spellId) - return self_lastSpellpower[spellId] or 0 -end - -function OvaleFuture:GetLastCritChance(spellId) - return self_lastCritChance[spellId] or 0 +function OvaleFuture:GetLastSpellInfo(guid, spellId, statName) + if self_lastSpellcast[guid] and self_lastSpellcast[guid][spellId] then + return self_lastSpellcast[guid][spellId][statName] + end end function OvaleFuture:InFlight(spellId) diff --git a/OvalePaperDoll.lua b/OvalePaperDoll.lua index 99ca676..4871a96 100644 --- a/OvalePaperDoll.lua +++ b/OvalePaperDoll.lua @@ -63,6 +63,9 @@ OvalePaperDoll.level = API_UnitLevel("player") OvalePaperDoll.specialization = nil OvalePaperDoll.stat = { + -- time of most recent snapshot + snapshotTime = 0, + -- primary stats agility = 0, intellect = 0, @@ -134,6 +137,7 @@ function OvalePaperDoll:COMBAT_RATING_UPDATE(event) self.stat.meleeCrit = API_GetCritChance() self.stat.rangedCrit = API_GetRangedCritChance() self.stat.spellCrit = API_GetSpellCritChance(OVALE_SPELLDAMAGE_SCHOOL[self.class]) + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:MASTERY_UPDATE(event) @@ -141,6 +145,7 @@ function OvalePaperDoll:MASTERY_UPDATE(event) self.stat.masteryEffect = 0 else self.stat.masteryEffect = API_GetMasteryEffect() + self.stat.snapshotTime = Ovale.now end end @@ -150,16 +155,19 @@ end function OvalePaperDoll:PLAYER_DAMAGE_DONE_MODS(event, unitId) self.stat.spellBonusHealing = API_GetSpellBonusHealing() + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:SPELL_POWER_CHANGED(event) self.stat.spellBonusDamage = API_GetSpellBonusDamage(OVALE_SPELLDAMAGE_SCHOOL[self.class]) + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:UNIT_ATTACK_POWER(event, unitId) if unitId ~= "player" then return end local base, posBuff, negBuff = API_UnitAttackPower(unitId) self.stat.attackPower = base + posBuff + negBuff + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:UNIT_LEVEL(event, unitId) @@ -170,18 +178,21 @@ end function OvalePaperDoll:UNIT_RANGEDDAMAGE(event, unitId) if unitId ~= "player" then return end self.stat.rangedHaste = API_GetRangedHaste() + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:UNIT_RANGED_ATTACK_POWER(event, unitId) if unitId ~= "player" then return end local base, posBuff, negBuff = API_UnitRangedAttackPower(unitId) self.stat.rangedAttackPower = base + posBuff + negBuff + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:UNIT_SPELL_HASTE(event, unitId) if unitId ~= "player" then return end self.stat.meleeHaste = API_GetMeleeHaste() self.stat.spellHaste = API_UnitSpellHaste(unitId) + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:UNIT_STATS(event, unitId) @@ -191,6 +202,7 @@ function OvalePaperDoll:UNIT_STATS(event, unitId) self.stat.stamina = API_UnitStat(unitId, 3) self.stat.intellect = API_UnitStat(unitId, 4) self.stat.spirit = API_UnitStat(unitId, 5) + self.stat.snapshotTime = Ovale.now end function OvalePaperDoll:UpdateStats(event) @@ -222,12 +234,15 @@ function OvalePaperDoll:GetSpellHasteMultiplier() return 1 + self.stat.spellHaste / 100 end -function OvalePaperDoll:SnapshotStats(t) - -- Snapshot the stats into the given table using the same keynames as self.stat. - -- Also add snapshotTime as the time that the snapshot was taken. - t.snapshotTime = Ovale.now - for k, v in pairs(self.stat) do - t.k = v +-- Snapshot the stats into the given table using the same keynames as self.stat. +-- If source is nil, then use the current player stats; otherwise, use the given stat table. +-- Only take the snapshot if the source snapshot time is older than timestamp. +function OvalePaperDoll:SnapshotStats(timestamp, t, source) + source = source or self.stat + if timestamp and timestamp >= source.snapshotTime then + for k in pairs(self.stat) do + t[k] = source[k] + end end end diff --git a/OvaleState.lua b/OvaleState.lua index 428117b..8e08af8 100644 --- a/OvaleState.lua +++ b/OvaleState.lua @@ -67,9 +67,9 @@ OvaleState.lastSpellId = nil -- -- -local function ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID) +local function ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID, stats) local self = OvaleState - self:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID) + self:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID, stats) end -- Track a new Eclipse buff that starts at endCast. @@ -213,7 +213,8 @@ end -- endCast : fin du cast -- nextCast : temps auquel le prochain sort peut être lancé (>=endCast, avec le GCD) -- nocd : le sort ne déclenche pas son cooldown -function OvaleState:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID) +-- spellcast : snapshot of player stats at the time the spell was cast +function OvaleState:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID, stats) if not spellId or not targetGUID then return end @@ -453,6 +454,8 @@ function OvaleState:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targ local remainingTicks = floor((oldEnding - endCast) / oldTick) newAura.ending = (oldEnding - oldTick * remainingTicks) + duration newAura.tick = OvaleData:GetTickLength(auraSpellId) + -- Re-snapshot stats for the DoT. + OvalePaperDoll:SnapshotStats(newAura.start, newAura, stats) else newAura.ending = endCast + duration end @@ -476,6 +479,7 @@ function OvaleState:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targ newAura.ending = endCast + duration if isDoT then newAura.tick = OvaleData:GetTickLength(auraSpellId) + OvalePaperDoll:SnapshotStats(newAura.start, newAura, stats) end end end -- 1.7.9.5