From b6be1a5858f0fdb07cec94a6f3011955d613e1a8 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Fri, 21 Sep 2012 05:01:44 +0000 Subject: [PATCH] Fix for ticket 163. * Add GetDuration(id) and GetTickLength(id, haste) methods to OvaleData to extract the correct numbers from the given spell's info. These numbers are fixed up for magic DoTs as regards to spell haste. * Modify OvaleData:GetDamage() to use named arguments to be slightly more clear. * Teach OvaleState how to properly extend a DoT by allowing the next tick of the previous DoT (at the previous spell haste) before adding the duration of the new DoT with new snapshotted stats. Right now, it is assumed that a DoT that gets refreshed by another spell gets a new snapshot of the player's stats when refreshed. * The duration calculation for OvaleState:GetTargetAura() is wrong. It doesn't take into account the spell haste of the aura and any additions to the duration through combo points or holy power, nor any DoT extensions. * Fix the nexttick, ticks, ticksremain, and ticktime conditions. git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@535 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- OvaleCondition.lua | 110 +++++++++++++++++++++++++++------------------------- OvaleData.lua | 64 +++++++++++++++++++++++++----- OvaleState.lua | 77 ++++++++++++++++++++++++------------ 3 files changed, 164 insertions(+), 87 deletions(-) diff --git a/OvaleCondition.lua b/OvaleCondition.lua index 57d1fdf..b1cefdb 100644 --- a/OvaleCondition.lua +++ b/OvaleCondition.lua @@ -280,7 +280,7 @@ local function testValue(comparator, limit, value, atTime, rate) end -- Recherche un aura sur la cible et récupère sa durée et le nombre de stacks --- return start, ending, stacks +-- return start, ending, stacks, spellHaste local function GetTargetAura(condition, target) if (not target) then target=condition.target @@ -313,12 +313,12 @@ local function GetTargetAura(condition, target) aura = OvaleState:GetAura(target, spellId, mine) else Ovale:Error("unknown buff "..spellId) - return 0,0,0 + return 0,0,0,0 end if not aura then Ovale:Log("Aura "..spellId.." not found") - return 0,0,0 + return 0,0,0,0 end if Ovale.trace then @@ -328,6 +328,7 @@ local function GetTargetAura(condition, target) if (not condition.mine or (aura.mine and condition.mine==1) or (not aura.mine and condition.mine==0)) and aura.stacks>=stacks then local ending if condition.forceduration then + --TODO: this is incorrect. if OvaleData.spellInfo[spellId] and OvaleData.spellInfo[spellId].duration then ending = aura.start + OvaleData.spellInfo[spellId].duration else @@ -336,9 +337,9 @@ local function GetTargetAura(condition, target) else ending = aura.ending end - return aura.start, ending, aura.stacks + return aura.start, ending, aura.stacks, aura.spellHaste else - return 0,0,0 + return 0,0,0,0 end end @@ -678,7 +679,12 @@ OvaleCondition.conditions= -- returns: number damage = function(condition) local spellId = condition[1] - local ret = OvaleData:GetDamage(spellId, OvaleState.state.combo, UnitAttackPower("player"), GetSpellBonusDamage(2)) + local ret = OvaleData:GetDamage(spellId, + { + combo = OvaleState.state.combo, + attackpower = UnitAttackPower("player"), + spellpower = GetSpellBonusDamage(2) + }) return 0, nil, ret * OvaleAura:GetDamageMultiplier(spellId), 0, 0 end, -- Get the current damage multiplier @@ -876,7 +882,12 @@ OvaleCondition.conditions= -- returns: number lastspellestimateddamage = function(condition) local spellId = condition[1] - local ret = OvaleData:GetDamage(spellId, OvaleFuture.lastSpellCombo[spellId], OvaleFuture.lastSpellAP[spellId], OvaleFuture.lastSpellSP[spellId]) + local ret = OvaleData:GetDamage(spellId, + { + combo = OvaleFuture.lastSpellCombo[spellId], + attackpower = OvaleFuture.lastSpellAP[spellId], + spellpower = OvaleFuture.lastSpellSP[spellId] + }) return 0, nil, ret * (OvaleFuture.lastSpellDM[spellId] or 0), 0, 0 end, -- Get the last spell damage multiplier @@ -1009,21 +1020,15 @@ OvaleCondition.conditions= -- 1: spell id -- return: number nexttick = function(condition) - local start, ending = GetTargetAura(condition, getTarget(condition.target)) - local si = OvaleData.spellInfo[condition[1]] - if not si or not si.duration then - return nil - end - local ticks = floor(OvaleAura.spellHaste * (si.duration/(si.tick or 3)) + 0.5) - local tickLength = (ending - start) / ticks - local tickTime = start + tickLength - for i=1,ticks do - if OvaleState.currentTime<=tickTime then - break + local start, ending, _, spellHaste = GetTargetAura(condition, getTarget(condition.target)) + local tickLength = OvaleData:GetTickLength(condition[1], spellHaste) + if tickLength then + while ending - tickLength > OvaleState.currentTime do + ending = ending - tickLength end - tickTime = tickTime + tickLength + return 0, nil, ending, 0, -1 end - return 0, nil, tickTime, 0, -1 + return nil end, -- Check if the aura is not on any other unit than the current target -- 1: spell id @@ -1245,52 +1250,51 @@ OvaleCondition.conditions= -- 1: spell Id -- return: bool or number ticks = function(condition) - local si = OvaleData.spellInfo[condition[1]] - if not si or not si.duration then return nil end - local baseTickTime = si.tick or 3 - local haste = OvaleAura.spellHaste - local d = si.duration - local t = floor(( baseTickTime * haste ) + 0.5 ) - local n = d/t - local num - -- banker's rounding - if n - 0.5 == floor(n) and floor(n) % 2 == 0 then - num = ceil(n - 0.5) - else - num = floor(n + 0.5) + local spellId = condition[1] + local si = OvaleData.spellInfo[spellId] + if si and si.duration then + local start, ending, _, spellHaste = GetTargetAura(condition, getTarget(condition.target)) + if not start or not ending or start > OvaleState.currentTime or ending < OvaleState.currentTime then + spellHaste = OvaleAura.spellHaste + end + local tickLength = OvaleData:GetTickLength(spellId, spellHaste) + if tickLength then + local numTicks = floor(duration / tickLength + 0.5) + return compare(numTicks, condition[2], condition[3]) + end end - return compare(num, condition[2], condition[3]) + return nil end, -- Get the remaining number of ticks -- 1: spell Id -- return: bool or number ticksremain = function(condition) - local start, ending = GetTargetAura(condition, getTarget(condition.target)) - local si = OvaleData.spellInfo[condition[1]] - if not si or not si.duration then - return nil - end - local ticks = floor(OvaleAura.spellHaste * (si.duration/(si.tick or 3)) + 0.5) - local tickLength = (ending - start) / ticks - local tickTime = start + tickLength - local remain = ticks - 1 - for i=1,ticks do - if OvaleState.currentTime<=tickTime then - break + local start, ending, _, spellHaste = GetTargetAura(condition, getTarget(condition.target)) + local tickLength = OvaleData:GetTickLength(condition[1], spellHaste) + if tickLength then + local remain = 1 + local tickTime = ending + while tickTime - tickLength > OvaleState.currentTime do + remain = remain + 1 + tickTime = tickTime - tickLength end - tickTime = tickTime + tickLength - remain = remain - 1 + return start, ending, remain, tickTime, -1/tickLength end - return start, ending, remain, tickTime, -1/tickLength + return nil end, -- Get the duration of a tick -- 1: spell id -- return: number or bool ticktime = function(condition) - --TODO not correct - local si = OvaleData.spellInfo[condition[1]] - if not si then return nil end - return compare(avecHate(si.tick or 3, "spell"), condition[2], condition[3]) + local start, ending, _, spellHaste = GetTargetAura(condition, getTarget(condition.target)) + if not start or not ending or start > OvaleState.currentTime or ending < OvaleState.currentTime then + spellHaste = OvaleAura.spellHaste + end + local tickLength = OvaleData:GetTickLength(condition[1], spellHaste) + if tickLength then + return compare(tickLength, condition[2], condition[3]) + end + return nil end, -- Get the time in combat -- return: number or bool diff --git a/OvaleData.lua b/OvaleData.lua index 136aca5..3fce9cb 100644 --- a/OvaleData.lua +++ b/OvaleData.lua @@ -454,27 +454,71 @@ function OvaleData:GetComputedSpellCD(spellId) end --Compute the damage of the given spell. -function OvaleData:GetDamage(spellId, combo, attackPower, spellpower) +function OvaleData:GetDamage(spellId, state) local si = self.spellInfo[spellId] if not si then return nil end - combo = combo or 0 - attackPower = attackPower or 0 - spellpower = spellpower or 0 - local ret = si.base or 0 + local damage = si.base or 0 + local combo, attackpower, spellpower = 1, 0, 0 + if state then + combo = state.combo or combo + attackpower = state.attackpower or attackpower + spellpower = state.spellpower or spellpower + end if si.bonuscp then - ret = ret + si.bonuscp * combo + damage = damage + si.bonuscp * combo end if si.bonusap then - ret = ret + si.bonusap * attackPower + damage = damage + si.bonusap * attackpower end if si.bonusapcp then - ret = ret + si.bonusapcp * attackPower * combo + damage = damage + si.bonusapcp * attackpower * combo end if si.bonussp then - ret = ret + si.bonussp * spellpower + damage = damage + si.bonussp * spellpower + end + return damage +end + +function OvaleData:GetDuration(spellId, state) + local si = self.spellInfo[spellId] + if si and si.duration then + local duration = si.duration + local combo, holy, spellHaste = 1, 1, 1 + if state then + combo = state.combo or combo + holy = state.holy or holy + spellHaste = state.spellHaste or spellHaste + end + if si.adddurationcp then + duration = duration + si.adddurationcp * (combo - 1) + end + if si.adddurationholy then + duration = duration + si.adddurationholy * (holy - 1) + end + if si.tick then -- DoT + --DoT duration is tickLength * numberOfTicks. + local tickLength = self:GetTickLength(spellId, spellHaste) + local numTicks = floor(duration / tickLength + 0.5) + duration = tickLength * numTicks + end + return duration + else + return nil + end +end + +function OvaleData:GetTickLength(spellId, spellHaste) + local si = self.spellInfo[spellId] + if si and si.tick then + if si.haste ~= "spell" then + return si.tick + else + return si.tick / spellHaste + end + else + return nil end - return ret end -- diff --git a/OvaleState.lua b/OvaleState.lua index 0b95445..a442270 100644 --- a/OvaleState.lua +++ b/OvaleState.lua @@ -110,6 +110,7 @@ function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd, end local newSpellInfo = OvaleData.spellInfo[spellId] + local oldState = { combo = self.state.combo, holy = self.state.holy } self.lastSpellId = spellId --On enregistre les infos sur le sort en cours @@ -269,7 +270,9 @@ function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd, for target, targetInfo in pairs(newSpellInfo.aura) do for filter, filterInfo in pairs(targetInfo) do for auraSpellId, spellData in pairs(filterInfo) do - + + local auraSpellInfo = OvaleData.spellInfo[auraSpellId] + local isDoT = auraSpellInfo and auraSpellInfo.tick local duration = spellData local stacks = duration local previousAura @@ -279,46 +282,72 @@ function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd, else auraGUID = UnitGUID(target) end - - if stacks == "refresh" then + + if stacks == "refresh" or isDoT then previousAura = self:GetAuraByGUID(auraGUID, auraSpellId, true, target) end - + if stacks ~= "refresh" or previousAura then local newAura = self:NewAura(auraGUID, auraSpellId) - + newAura.mine = true --Optionnellement, on va regarder la durée du buff - if auraSpellId and OvaleData.spellInfo[auraSpellId] and OvaleData.spellInfo[auraSpellId].duration then - duration = OvaleData.spellInfo[auraSpellId].duration - elseif stacks~="refresh" and stacks > 0 then + if auraSpellInfo and auraSpellInfo.duration then + oldState.spellHaste = OvaleAura.spellHaste + duration = OvaleData:GetDuration(auraSpellId, oldState) + elseif stacks ~= "refresh" and stacks > 0 then stacks = 1 end - if stacks=="refresh" then + + if stacks ~= "refresh" and stacks == 0 then + Ovale:Log("Aura "..auraSpellId.." is completely removed") + newAura.ending = 0 + newAura.stacks = 0 + elseif stacks == "refresh" then newAura.start = previousAura.start newAura.stacks = previousAura.stacks - newAura.ending = endCast + duration - elseif stacks<0 and newAura.ending then - --Buff are immediatly removed when the cast ended, do not need to do it again - if filter~="HELPFUL" or target~="player" or endCast>=self.maintenant then - newAura.stacks = newAura.stacks + stacks - if Ovale.trace then - Ovale:Print("removing one stack of "..auraSpellId.." because of ".. spellId.." to ".. newAura.stacks) + if isDoT then + -- TODO: check that refreshed DoTs take a new snapshot of player stats. + local tickLength = OvaleData:GetTickLength(auraSpellId, previousAura.spellHaste) + local k = floor((previousAura.ending - endCast) / tickLength) + newAura.ending = previousAura.ending - tickLength * k + duration + newAura.spellHaste = OvaleAura.spellHaste + else + newAura.ending = endCast + duration + end + elseif newAura.ending then + if stacks < 0 then + --Buff are immediatly removed when the cast ended, do not need to do it again + if filter ~= "HELPFUL" or target ~= "player" or endCast >= self.maintenant then + newAura.stacks = newAura.stacks + stacks + if Ovale.trace then + Ovale:Print("removing one stack of "..auraSpellId.." because of ".. spellId.." to ".. newAura.stacks) + end + --Plus de stacks, on supprime l'aura + if newAura.stacks <= 0 then + Ovale:Log("Aura is completly removed") + newAura.stacks = 0 + newAura.ending = 0 + end end - --Plus de stacks, on supprime l'aura - if newAura.stacks<=0 then - Ovale:Log("Aura is completly removed") - newAura.stacks = 0 - newAura.ending = 0 + elseif newAura.ending >= endCast then + if isDoT then + local tickLength = OvaleData:GetTickLength(auraSpellId, newAura.spellHaste) + local k = floor((newAura.ending - endCast) / tickLength) + newAura.ending = newAura.ending - tickLength * k + duration + newAura.spellHaste = OvaleAura.spellHaste + else + newAura.ending = endCast + duration end + newAura.stacks = newAura.stacks + stacks end - elseif newAura.ending and newAura.ending >= endCast then - newAura.ending = endCast + duration - newAura.stacks = newAura.stacks + stacks else newAura.start = endCast newAura.ending = endCast + duration newAura.stacks = stacks + if isDoT then + newAura.spellHaste = OvaleAura.spellHaste + end end if Ovale.trace then if auraSpellId then -- 1.7.9.5