Quantcast

Add new module OvaleCooldown that manages cooldown information.

Johnny C. Lam [11-10-13 - 00:31]
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
Filename
Ovale.toc
OvaleBestAction.lua
OvaleCooldown.lua
OvaleData.lua
OvaleFrame.lua
OvaleState.lua
conditions/GCD.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
 --<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