From cf50949130bd75fcb7849f1d176331256d6011db Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Sun, 10 Nov 2013 00:31:58 +0000 Subject: [PATCH] Add new module OvaleCooldown that manages cooldown information. Move GCD and spell cooldown state tracked in OvaleState into OvaleCooldown. git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1152 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- Ovale.toc | 1 + OvaleBestAction.lua | 8 ++- OvaleCooldown.lua | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++ OvaleData.lua | 11 +-- OvaleFrame.lua | 3 +- OvaleState.lua | 190 +------------------------------------------------ conditions/GCD.lua | 4 +- 7 files changed, 213 insertions(+), 200 deletions(-) create mode 100644 OvaleCooldown.lua diff --git a/Ovale.toc b/Ovale.toc index 3e075e7..9d77abc 100644 --- a/Ovale.toc +++ b/Ovale.toc @@ -42,6 +42,7 @@ OvaleState.lua # OvaleAura.lua OvaleComboPoints.lua +OvaleCooldown.lua OvalePower.lua OvaleRecount.lua OvaleScripts.lua diff --git a/OvaleBestAction.lua b/OvaleBestAction.lua index c1a11d6..c900aa5 100644 --- a/OvaleBestAction.lua +++ b/OvaleBestAction.lua @@ -15,6 +15,7 @@ Ovale.OvaleBestAction = OvaleBestAction -- local OvaleActionBar = Ovale.OvaleActionBar local OvaleCondition = Ovale.OvaleCondition +local OvaleCooldown = Ovale.OvaleCooldown local OvaleData = Ovale.OvaleData local OvaleEquipement = Ovale.OvaleEquipement local OvaleFuture = Ovale.OvaleFuture @@ -513,8 +514,9 @@ local function ComputeGroup(element) if currentElement then currentCastTime = currentElement.castTime end - if not currentCastTime or currentCastTime < OvaleState.gcd then - currentCastTime = OvaleState.gcd + local gcd = OvaleCooldown:GetGCD() + if not currentCastTime or currentCastTime < gcd then + currentCastTime = gcd end local replace = false @@ -724,7 +726,7 @@ function OvaleBestAction:GetActionInfo(element) actionTexture = actionTexture or API_GetSpellTexture(spellId) actionInRange = API_IsSpellInRange(OvaleSpellBook:GetSpellName(spellId), target) - actionCooldownStart, actionCooldownDuration, actionEnable = OvaleState:GetComputedSpellCD(spellId) + actionCooldownStart, actionCooldownDuration, actionEnable = OvaleState.state:GetSpellCooldown(spellId) -- Verify that the spell may be cast given restrictions specified in SpellInfo(). local si = OvaleData.spellInfo[spellId] diff --git a/OvaleCooldown.lua b/OvaleCooldown.lua new file mode 100644 index 0000000..c98bcd6 --- /dev/null +++ b/OvaleCooldown.lua @@ -0,0 +1,196 @@ +--[[-------------------------------------------------------------------- + Ovale Spell Priority + Copyright (C) 2012 Sidoine + Copyright (C) 2012, 2013 Johnny C. Lam + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License in the LICENSE + file accompanying this program. +--]]-------------------------------------------------------------------- + +local _, Ovale = ... +local OvaleCooldown = Ovale:NewModule("OvaleCooldown") +Ovale.OvaleCooldown = OvaleCooldown + +-- +local OvaleData = Ovale.OvaleData +local OvalePaperDoll = Ovale.OvalePaperDoll +local OvaleStance = Ovale.OvaleStance +local OvaleState = Ovale.OvaleState + +local API_UnitHealth = UnitHealth +local API_UnitHealthMax = UnitHealthMax +-- + +-- +function OvaleCooldown:OnEnable() + OvaleState:RegisterState(self, self.statePrototype) +end + +function OvaleCooldown:OnDisable() + OvaleState:UnregisterState(self) +end + +-- Return the GCD after the given spellId is cast. +-- If no spellId is given, then returns the GCD after a "yellow-hit" ability has been cast. +function OvaleCooldown:GetGCD(spellId) + -- Base global cooldown. + local class = OvalePaperDoll.class + local isCaster = false + if class == "DEATHKNIGHT" then + cd = 1.0 + elseif class == "DRUID" and OvaleStance:IsStance("druid_cat_form") then + cd = 1.0 + elseif class == "MONK" then + cd = 1.0 + elseif class == "ROGUE" then + cd = 1.0 + else + isCaster = true + cd = 1.5 + end + + -- Use SpellInfo() information if available. + if spellId and OvaleData.spellInfo[spellId] then + local si = OvaleData.spellInfo[spellId] + if si.gcd then + cd = si.gcd + end + if si.haste then + if si.haste == "melee" then + cd = cd / OvalePaperDoll:GetMeleeHasteMultiplier() + elseif si.haste == "spell" then + cd = cd / OvalePaperDoll:GetSpellHasteMultiplier() + end + end + elseif isCaster then + cd = cd / OvalePaperDoll:GetSpellHasteMultiplier() + end + + -- Clamp GCD at 1s. + cd = (cd > 1) and cd or 1 + return cd +end +-- + +--[[---------------------------------------------------------------------------- + State machine for simulator. +--]]---------------------------------------------------------------------------- + +-- +OvaleCooldown.statePrototype = { + cd = nil, +} +-- + +-- +-- Initialize the state. +function OvaleCooldown:InitializeState(state) + state.cd = {} +end + +-- Reset the state to the current conditions. +function OvaleCooldown:ResetState(state) + for _, cd in pairs(state.cd) do + cd.start = nil + cd.duration = nil + cd.enable = 0 + cd.toggled = nil + end +end + +-- Apply the effects of the spell on the player's state, assuming the spellcast completes. +function OvaleCooldown:ApplySpellOnPlayer(state, spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) + -- If the spellcast has already ended, then the effects on the player have already occurred. + if endCast <= OvaleState.now then + return + end + + local si = OvaleData.spellInfo[spellId] + if si then + local cd = state:GetCD(spellId) + if cd then + cd.start = startCast + cd.duration = si.cd or 0 + + -- Test for no cooldown. + if nocd then + cd.duration = 0 + 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) + -- XXX Shouldn't this be (not ending or ending > endCast)? + -- XXX The spellcast needs to finish before the buff expires. + if start <= startCast and (not ending or ending > startCast) then + cd.duration = 0 + end + end + end + + -- There is no cooldown if the target's health percent is below what's specified + -- with the "targetlifenocd" parameter. + if si.targetlifenocd then + local healthPercent = API_UnitHealth("target") / API_UnitHealthMax("target") * 100 + if healthPercent < si.targetlifenocd then + cd.duration = 0 + end + end + end + + -- Adjust cooldown duration if it is affected by haste: "cd_haste=melee" or "cd_haste=spell". + if cd.duration > 0 and si.cd_haste then + if si.cd_haste == "melee" then + cd.duration = cd.duration / OvalePaperDoll:GetMeleeHasteMultiplier() + elseif si.cd_haste == "spell" then + cd.duration = cd.duration / OvalePaperDoll:GetSpellHasteMultiplier() + end + end + + cd.enable = 1 + if si.toggle then + cd.toggled = 1 + end + Ovale:Logf("Spell %d cooldown info: start=%f, duration=%f", spellId, cd.start, cd.duration) + end + end +end +-- + +-- Mix-in methods for simulator state. +do + local statePrototype = OvaleCooldown.statePrototype + + -- Return the table holding the simulator's cooldown information for the given spell. + function statePrototype:GetCD(spellId) + local state = self + if spellId then + local si = OvaleData.spellInfo[spellId] + if si and si.cd then + local cdname = si.sharedcd and si.sharedcd or spellId + if not state.cd[cdname] then + state.cd[cdname] = {} + end + return state.cd[cdname] + end + end + return nil + end + + -- Return the cooldown for the given spell in the simulator. + function statePrototype:GetSpellCooldown(spellId) + local state = self + local start, duration, enable + local cd = state:GetCD(spellId) + if cd and cd.start then + start = cd.start + duration = cd.duration + enable = cd.enable + else + start, duration, enable = OvaleData:GetSpellCooldown(spellId) + end + return start, duration, enable + end +end diff --git a/OvaleData.lua b/OvaleData.lua index 8663824..55681cf 100644 --- a/OvaleData.lua +++ b/OvaleData.lua @@ -269,12 +269,13 @@ function OvaleData:NeedNewSnapshot(auraSpellId, spellId) end --Compute the spell Cooldown -function OvaleData:GetSpellCD(spellId) - local actionCooldownStart, actionCooldownDuration, actionEnable = API_GetSpellCooldown(spellId) - if self.spellInfo[spellId] and self.spellInfo[spellId].forcecd then - actionCooldownStart, actionCooldownDuration = API_GetSpellCooldown(self.spellInfo[spellId].forcecd) +function OvaleData:GetSpellCooldown(spellId) + local start, duration, enable = API_GetSpellCooldown(spellId) + local si = self.spellInfo[spellId] + if si and si.forcecd then + start, duration = API_GetSpellCooldown(si.forcecd) end - return actionCooldownStart, actionCooldownDuration, actionEnable + return start, duration, enable end --Compute the damage of the given spell. diff --git a/OvaleFrame.lua b/OvaleFrame.lua index 1ea2b5e..992e6bb 100644 --- a/OvaleFrame.lua +++ b/OvaleFrame.lua @@ -18,6 +18,7 @@ do local OvaleBestAction = Ovale.OvaleBestAction local OvaleCompile = Ovale.OvaleCompile local OvaleCondition = Ovale.OvaleCondition + local OvaleCooldown = Ovale.OvaleCooldown local OvaleGUID = Ovale.OvaleGUID local OvaleOptions = Ovale.OvaleOptions local OvaleState = Ovale.OvaleState @@ -259,7 +260,7 @@ do castTime = _castTime/1000 end end - local gcd = OvaleState:GetGCD(spellId) + local gcd = OvaleCooldown:GetGCD(spellId) local nextCast if (castTime>gcd) then nextCast = start + castTime diff --git a/OvaleState.lua b/OvaleState.lua index c340c8e..98c45e5 100644 --- a/OvaleState.lua +++ b/OvaleState.lua @@ -9,6 +9,7 @@ --]]-------------------------------------------------------------------- -- Keep the current state in the simulation +-- XXX Split out Eclipse and Runes modules (Druid and DeathKnight modules?). local _, Ovale = ... local OvaleState = Ovale:NewModule("OvaleState") @@ -16,26 +17,16 @@ Ovale.OvaleState = OvaleState -- local OvaleData = Ovale.OvaleData -local OvaleGUID = Ovale.OvaleGUID local OvalePaperDoll = Ovale.OvalePaperDoll local OvaleQueue = Ovale.OvaleQueue local OvaleSpellBook = Ovale.OvaleSpellBook -local OvaleStance = Ovale.OvaleStance -local floor = math.floor local pairs = pairs local select = select -local tinsert = table.insert -local tremove = table.remove -local tostring = tostring -local type = type -local wipe = table.wipe local API_GetEclipseDirection = GetEclipseDirection local API_GetRuneCooldown = GetRuneCooldown local API_GetRuneType = GetRuneType local API_GetTime = GetTime -local API_UnitHealth = UnitHealth -local API_UnitHealthMax = UnitHealthMax local self_statePrototype = {} local self_stateModules = OvaleQueue:NewQueue("OvaleState_stateModules") @@ -65,7 +56,6 @@ OvaleState.currentTime = nil OvaleState.nextCast = nil OvaleState.startCast = nil OvaleState.endCast = nil -OvaleState.gcd = 1.5 OvaleState.lastSpellId = nil -- @@ -124,7 +114,6 @@ function OvaleState:StartNewFrame() self:InitializeState() end self.now = API_GetTime() - self.gcd = self:GetGCD() end function OvaleState:InitializeState() @@ -165,12 +154,6 @@ function OvaleState:Reset() end end end - for k,v in pairs(self.state.cd) do - v.start = nil - v.duration = nil - v.enable = 0 - v.toggled = nil - end end --[[ @@ -232,9 +215,6 @@ function OvaleState:ApplySpellOnPlayer(spellId, startCast, endCast, nextCast, no so only consider spells that have not yet finished casting in the simulator. --]] if endCast > self.now then - -- Adjust the spell's cooldown. - self:ApplySpellCooldown(spellId, startCast, endCast, nocd) - -- Adjust the player's resources. self:ApplySpellCost(spellId, startCast, endCast) end @@ -245,60 +225,6 @@ function OvaleState:ApplySpellOnTarget(spellId, startCast, endCast, nextCast, no self:InvokeMethod("ApplySpellOnTarget", spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) end --- Adjust a spell cooldown in the simulator. -function OvaleState:ApplySpellCooldown(spellId, startCast, endCast, nocd) - local si = OvaleData.spellInfo[spellId] - if si then - local cd = self:GetCD(spellId) - if cd then - cd.start = startCast - cd.duration = si.cd or 0 - - -- Test for no cooldown. - if nocd then - cd.duration = 0 - else - -- There is no cooldown if the buff named by "buffnocd" parameter is present. - if si.buffnocd then - local start, ending, stacks = self: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) - -- XXX Shouldn't this be (not ending or ending > endCast)? - -- XXX The spellcast needs to finish before the buff expires. - if start <= startCast and (not ending or ending > startCast) then - cd.duration = 0 - end - end - end - - -- There is no cooldown if the target's health percent is below what's specified - -- with the "targetlifenocd" parameter. - if si.targetlifenocd then - local healthPercent = API_UnitHealth("target") / API_UnitHealthMax("target") * 100 - if healthPercent < si.targetlifenocd then - cd.duration = 0 - end - end - end - - -- Adjust cooldown duration if it is affected by haste: "cd_haste=melee" or "cd_haste=spell". - if cd.duration > 0 and si.cd_haste then - if si.cd_haste == "melee" then - cd.duration = cd.duration / OvalePaperDoll:GetMeleeHasteMultiplier() - elseif si.cd_haste == "spell" then - cd.duration = cd.duration / OvalePaperDoll:GetSpellHasteMultiplier() - end - end - - cd.enable = 1 - if si.toggle then - cd.toggled = 1 - end - Ovale:Logf("Spell %d cooldown info: start=%f, duration=%f", spellId, cd.start, cd.duration) - end - end -end - -- Adjust the player's resources in the simulator from casting the given spell. function OvaleState:ApplySpellCost(spellId, startCast, endCast) local si = OvaleData.spellInfo[spellId] @@ -354,120 +280,6 @@ function OvaleState:ApplySpellCost(spellId, startCast, endCast) end end --- Return the GCD after the given spellId is cast. --- If no spellId is given, then returns the GCD after a "yellow-hit" ability has been cast. -function OvaleState:GetGCD(spellId) - -- Use SpellInfo() information if available. - if spellId and OvaleData.spellInfo[spellId] then - local si = OvaleData.spellInfo[spellId] - if si.haste then - local cd = si.gcd or 1.5 - if si.haste == "melee" then - cd = cd / OvalePaperDoll:GetMeleeHasteMultiplier() - elseif si.haste == "spell" then - cd = cd / OvalePaperDoll:GetSpellHasteMultiplier() - end - if cd < 1 then - cd = 1 - end - return cd - elseif si.gcd then - return si.gcd - end - end - - -- Default value. - local class = OvalePaperDoll.class - local isCaster = false - if class == "DRUID" and not (OvaleStance:IsStance("druid_bear_form") or OvaleStance:IsStance("druid_cat_form")) then - isCaster = true - elseif class == "MAGE" then - isCaster = true - elseif class == "PRIEST" then - isCaster = true - elseif class == "SHAMAN" then - isCaster = true - elseif class == "WARLOCK" then - isCaster = true - end - if isCaster then - local cd = 1.5 / OvalePaperDoll:GetSpellHasteMultiplier() - if cd < 1 then - cd = 1 - end - return cd - elseif class == "DEATHKNIGHT" then - return 1.0 - elseif class == "DRUID" and OvaleStance:IsStance("druid_cat_form") then - return 1.0 - elseif class == "MONK" then - return 1.0 - elseif class == "ROGUE" then - return 1.0 - else - return 1.5 - end -end - -function OvaleState:GetCD(spellId) - if not spellId then - return nil - end - local si = OvaleData.spellInfo[spellId] - if si and si.cd then - local cdname - if si.sharedcd then - cdname = si.sharedcd - else - cdname = spellId - end - if not self.state.cd[cdname] then - self.state.cd[cdname] = {} - end - return self.state.cd[cdname] - else - return nil - end -end - ---Compute the spell Cooldown -function OvaleState:GetComputedSpellCD(spellId) - local actionCooldownStart, actionCooldownDuration, actionEnable - local cd = self:GetCD(spellId) - if cd and cd.start then - actionCooldownStart = cd.start - actionCooldownDuration = cd.duration - actionEnable = cd.enable - else - actionCooldownStart, actionCooldownDuration, actionEnable = OvaleData:GetSpellCD(spellId) - end - return actionCooldownStart, actionCooldownDuration, actionEnable -end - -function OvaleState:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) - return self.state:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) -end - -function OvaleState:GetAura(unitId, spellId, filter, mine, auraFound) - return self.state:GetAura(unitId, spellId, filter, mine, auraFound) -end - -function OvaleState:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) - return self.state:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) -end - -function OvaleState:NewAura(guid, spellId, filter) - return self.state:NewAura(guid, spellId, filter) -end - -function OvaleState:GetDamageMultiplier(spellId) - return self.state:GetDamageMultiplier(spellId) -end - -function OvaleState:GetDuration(auraSpellId) - return self.state:GetDuration(auraSpellId) -end - -- Returns 1 if moving toward Solar or -1 if moving toward Lunar. function OvaleState:GetEclipseDir() local stacks = select(3, self:GetAura("player", SOLAR_ECLIPSE, "HELPFUL", true)) diff --git a/conditions/GCD.lua b/conditions/GCD.lua index 266dbe5..eaeaf43 100644 --- a/conditions/GCD.lua +++ b/conditions/GCD.lua @@ -11,7 +11,7 @@ local _, Ovale = ... do local OvaleCondition = Ovale.OvaleCondition - local OvaleState = Ovale.OvaleState + local OvaleCooldown = Ovale.OvaleCooldown local Compare = OvaleCondition.Compare @@ -28,7 +28,7 @@ do local function GCD(condition) local comparator, limit = condition[1], condition[2] - local value = OvaleState.gcd + local value = OvaleCooldown:GetGCD() return Compare(value, comparator, limit) end -- 1.7.9.5