Johnny C. Lam [11-10-13 - 00:31]
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
--<private-static-properties>
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
+
+--<private-static-properties>
+local OvaleData = Ovale.OvaleData
+local OvalePaperDoll = Ovale.OvalePaperDoll
+local OvaleStance = Ovale.OvaleStance
+local OvaleState = Ovale.OvaleState
+
+local API_UnitHealth = UnitHealth
+local API_UnitHealthMax = UnitHealthMax
+--</private-static-properties>
+
+--<public-static-methods>
+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
+--</public-static-methods>
+
+--[[----------------------------------------------------------------------------
+ State machine for simulator.
+--]]----------------------------------------------------------------------------
+
+--<public-static-properties>
+OvaleCooldown.statePrototype = {
+ cd = nil,
+}
+--</public-static-properties>
+
+--<public-static-methods>
+-- 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
+--</public-static-methods>
+
+-- 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
--<private-static-properties>
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
--</public-static-properties>
@@ -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