Quantcast

Remove Eclipse handling in OvaleState in favor of an OvaleEclipse module.

Johnny C. Lam [11-10-13 - 00:32]
Remove Eclipse handling in OvaleState in favor of an OvaleEclipse module.

OvaleEclipse properly tracks the current Eclipse information as well as
keeps Eclipse state for the simulator.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1157 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Ovale.toc
OvaleEclipse.lua
OvalePower.lua
OvaleState.lua
conditions/EclipseDir.lua
diff --git a/Ovale.toc b/Ovale.toc
index 8b1514e..b34e42c 100644
--- a/Ovale.toc
+++ b/Ovale.toc
@@ -52,6 +52,7 @@ OvaleSpellDamage.lua
 OvaleSwing.lua
 #
 OvaleCompile.lua
+OvaleEclipse.lua
 OvaleFuture.lua
 OvaleIcone.lua
 OvaleIcone.xml
diff --git a/OvaleEclipse.lua b/OvaleEclipse.lua
new file mode 100644
index 0000000..2459d9d
--- /dev/null
+++ b/OvaleEclipse.lua
@@ -0,0 +1,200 @@
+--[[--------------------------------------------------------------------
+    Ovale Spell Priority
+    Copyright (C) 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.
+--]]--------------------------------------------------------------------
+
+--[[
+	This addon tracks Eclipse energy information on druids.
+--]]
+
+local _, Ovale = ...
+local OvaleEclipse = Ovale:NewModule("OvaleEclipse", "AceEvent-3.0")
+Ovale.OvaleEclipse = OvaleEclipse
+
+--<private-static-properties>
+local OvaleAura = Ovale.OvaleAura
+local OvaleData = Ovale.OvaleData
+local OvaleGUID = Ovale.OvaleGUID
+local OvalePower = Ovale.OvalePower
+local OvaleSpellBook = Ovale.OvaleSpellBook
+local OvaleState = Ovale.OvaleState
+local SPELL_POWER_ECLIPSE = SPELL_POWER_ECLIPSE
+
+local select = select
+local API_GetEclipseDirection = GetEclipseDirection
+local API_UnitClass = UnitClass
+local API_UnitPower = UnitPower
+
+-- Player's GUID.
+local self_guid = nil
+-- Player's class.
+local self_class = select(2, API_UnitClass("player"))
+
+local LUNAR_ECLIPSE = ECLIPSE_BAR_LUNAR_BUFF_ID
+local SOLAR_ECLIPSE = ECLIPSE_BAR_SOLAR_BUFF_ID
+local CELESTIAL_ALIGNMENT = 112071
+local EUPHORIA = 81062
+local STARFALL = 48505
+--</private-static-properties>
+
+--<public-static-properties>
+-- Direction that the eclipse status is moving: -1 = "lunar", 0 = "none", 1 = "solar".
+OvaleEclipse.eclipse = 0
+OvaleEclipse.eclipseDirection = 0
+--<public-static-properties>
+
+--<public-static-methods>
+function OvaleEclipse:OnEnable()
+	if self_class == "DRUID" then
+		self_guid = OvaleGUID:GetGUID("player")
+		self:RegisterEvent("ECLIPSE_DIRECTION_CHANGE", "UpdateEclipseDirection")
+		self:RegisterEvent("UNIT_POWER")
+		self:RegisterEvent("UNIT_POWER_FREQUENT", "UNIT_POWER")
+		self:RegisterMessage("Ovale_SpecializationChanged", "UpdateEclipseDirection")
+		self:RegisterMessage("Ovale_StanceChanged", "Update")
+		self:RegisterMessage("Ovale_AuraAdded")
+		OvaleState:RegisterState(self, self.statePrototype)
+	end
+end
+
+function OvaleEclipse:OnDisable()
+	if self_class == "DRUID" then
+		OvaleState:UnregisterState(self)
+		self:UnregisterEvent("ECLIPSE_DIRECTION_CHANGE")
+		self:UnregisterEvent("UNIT_POWER")
+		self:UnregisterEvent("UNIT_POWER_FREQUENT")
+		self:UnregisterMessage("Ovale_AuraAdded")
+		self:UnregisterMessage("Ovale_SpecializationChanged")
+		self:UnregisterMessage("Ovale_StanceChanged")
+	end
+end
+
+function OvaleEclipse:UNIT_POWER(event, unitId, powerToken)
+	if unitId == "player" and powerToken == "ECLIPSE" then
+		self:Update()
+	end
+end
+
+function OvaleEclipse:Ovale_AuraAdded(event, timestamp, guid, spellId, caster)
+	if guid == self_guid then
+		if spellId == LUNAR_ECLIPSE or spellId == SOLAR_ECLIPSE then
+			self:UpdateEclipseDirection()
+		end
+	end
+end
+
+function OvaleEclipse:Update()
+	self:UpdateEclipse()
+	self:UpdateEclipseDirection()
+end
+
+function OvaleEclipse:UpdateEclipse()
+	self.eclipse = API_UnitPower("player", SPELL_POWER_ECLIPSE)
+end
+
+function OvaleEclipse:UpdateEclipseDirection()
+	local direction = API_GetEclipseDirection()
+	if direction == "moon" then
+		self.eclipseDirection = -1
+	elseif direction == "sun" then
+		self.eclipseDirection = 1
+	else -- if direction == "none" then
+		if self.eclipse < 0 then
+			self.eclipseDirection = -1
+		elseif self.eclipse > 0 then
+			self.eclipseDirection = 1
+		else -- if self.eclipse == 0 then
+			self.eclipseDirection = 0
+		end
+	end
+end
+--</public-static-methods>
+
+--[[----------------------------------------------------------------------------
+	State machine for simulator.
+--]]----------------------------------------------------------------------------
+
+--<public-static-properties>
+OvaleEclipse.statePrototype = {
+	eclipseDirection = nil,
+}
+--</public-static-properties>
+
+--<public-static-methods>
+-- Initialize the state.
+function OvaleEclipse:InitializeState(state)
+	state.eclipseDirection = nil
+end
+
+-- Reset the state to the current conditions.
+function OvaleEclipse:ResetState(state)
+	state.eclipse = self.eclipse or 0
+	state.eclipseDirection = self.eclipseDirection
+end
+
+-- Apply the effects of the spell on the player's state, assuming the spellcast completes.
+function OvaleEclipse: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 and si.eclipse then
+		local eclipse = state.eclipse
+		local direction = state.eclipseDirection
+		local energy = si.eclipse
+
+		if energy == 0 then
+			-- Spell resets Eclipse energy to zero, but leaves the Eclipse direction intact.
+			eclipse = 0
+		else -- if energy ~= 0 then
+			-- If there is no Eclipse direction yet, then start moving in the direction generated
+			-- by the energy of the spellcast.
+			if direction == 0 then
+				direction = (energy < 0) and -1 or 1
+			end
+			if si.eclipsedir then
+				energy = energy * direction
+			end
+			if state:GetAura("player", CELESTIAL_ALIGNMENT, "HELPFUL", true) then
+				-- Celestial Alignment prevents gaining Eclipse energy during its duration.
+				energy = 0
+			elseif OvaleSpellBook:IsKnownSpell(EUPHORIA)
+						and not state:GetAura("player", LUNAR_ECLIPSE, "HELPFUL", true)
+						and not state:GetAura("player", SOLAR_ECLIPSE, "HELPFUL", true) then
+				-- Euphoria: While not in an Eclipse state, your spells generate double the normal
+				-- amount of Solar or Lunar energy.
+				energy = energy * 2
+			end
+			-- Only adjust Eclipse energy if the spell moves the Eclipse bar in the right direction.
+			if (direction <= 0 and energy < 0) or (direction >= 0 and energy > 0) then
+				eclipse = eclipse + energy
+			end
+			-- Clamp Eclipse energy to min/max values and note that an Eclipse state will be reached after the spellcast.
+			if eclipse <= -100 then
+				eclipse = -100
+				direction = 1
+				state:AddEclipse(endCast, LUNAR_ECLIPSE)
+				-- Reaching Lunar Eclipse resets the cooldown of Starfall.
+				local cd = state:GetCD(STARFALL)
+				if cd then
+					cd.start = 0
+					cd.duration = 0
+					cd.enable = 0
+				end
+			elseif eclipse >= 100 then
+				eclipse = 100
+				direction = -1
+				state:AddEclipse(endCast, SOLAR_ECLIPSE)
+			end
+		end
+		state.eclipse = eclipse
+		state.eclipseDirection = direction
+	end
+end
+--</public-static-methods>
diff --git a/OvalePower.lua b/OvalePower.lua
index 1b993cc..6b5f232 100644
--- a/OvalePower.lua
+++ b/OvalePower.lua
@@ -252,7 +252,7 @@ function OvalePower:ApplySpellOnPlayer(state, spellId, startCast, endCast, nextC
 	end

 	if si then
-		-- Update power state except for eclipse energy.
+		-- Update power state except for eclipse energy (handled by OvaleEclipse).
 		for powerType, powerInfo in pairs(self.POWER_INFO) do
 			if powerType ~= "eclipse" then
 				local cost = si[powerType]
diff --git a/OvaleState.lua b/OvaleState.lua
index 85eb824..9eda4dd 100644
--- a/OvaleState.lua
+++ b/OvaleState.lua
@@ -9,7 +9,7 @@
 --]]--------------------------------------------------------------------

 -- Keep the current state in the simulation
--- XXX Split out Eclipse and Runes modules (Druid and DeathKnight modules?).
+-- XXX Split out Runes module.

 local _, Ovale = ...
 local OvaleState = Ovale:NewModule("OvaleState")
@@ -18,11 +18,9 @@ Ovale.OvaleState = OvaleState
 --<private-static-properties>
 local OvaleData = Ovale.OvaleData
 local OvaleQueue = Ovale.OvaleQueue
-local OvaleSpellBook = Ovale.OvaleSpellBook

 local pairs = pairs
 local select = select
-local API_GetEclipseDirection = GetEclipseDirection
 local API_GetRuneCooldown = GetRuneCooldown
 local API_GetRuneType = GetRuneType
 local API_GetTime = GetTime
@@ -38,12 +36,6 @@ local self_runesCD = {}
 local self_class = select(2, API_UnitClass("player"))
 -- Whether the state of the simulator has been initialized.
 local self_stateIsInitialized = false
-
--- Aura IDs for Eclipse buffs.
-local LUNAR_ECLIPSE = 48518
-local SOLAR_ECLIPSE = 48517
--- Spell ID for Starfall (Balance specialization spell).
-local STARFALL = 48505
 --</private-static-properties>

 --<public-static-properties>
@@ -212,93 +204,28 @@ 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 player's resources.
-		self:ApplySpellCost(spellId, startCast, endCast)
-	end
-end
-
--- Apply the effects of the spell on the target's state when it lands on the target.
-function OvaleState:ApplySpellOnTarget(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast)
-	self:InvokeMethod("ApplySpellOnTarget", spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast)
-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]
-
-	if si then
-		-- Eclipse
-		if si.eclipse then
-			local energy = si.eclipse
-			local direction = self:GetEclipseDir()
-			if si.eclipsedir then
-				energy = energy * direction
+		local si = OvaleData.spellInfo[spellId]
+		if si then
+			-- Runes
+			if si.blood and si.blood < 0 then
+				AddRune(startCast, 1, si.blood)
 			end
-			-- Euphoria: While not in an Eclipse state, your spells generate double the normal amount of Solar or Lunar energy.
-			if OvaleSpellBook:IsKnownSpell(81062)
-					and not self.state:GetAura("player", LUNAR_ECLIPSE, "HELPFUL", true)
-					and not self.state:GetAura("player", SOLAR_ECLIPSE, "HELPFUL", true) then
-				energy = energy * 2
+			if si.unholy and si.unholy < 0 then
+				AddRune(startCast, 2, si.unholy)
 			end
-			-- Only adjust Eclipse energy if the spell moves the Eclipse bar in the right direction.
-			if (direction < 0 and energy < 0) or (direction > 0 and energy > 0) then
-				self.state.eclipse = self.state.eclipse + energy
+			if si.frost and si.frost < 0 then
+				AddRune(startCast, 3, si.frost)
 			end
-			-- Clamp Eclipse energy to min/max values and note that an Eclipse state will be reached after the spellcast.
-			if self.state.eclipse <= -100 then
-				self.state.eclipse = -100
-				self.state:AddEclipse(endCast, LUNAR_ECLIPSE)
-				-- Reaching Lunar Eclipse resets the cooldown of Starfall.
-				local cd = self.state:GetCD(STARFALL)
-				if cd then
-					cd.start = 0
-					cd.duration = 0
-					cd.enable = 0
-				end
-			elseif self.state.eclipse >= 100 then
-				self.state.eclipse = 100
-				self.state:AddEclipse(endCast, SOLAR_ECLIPSE)
+			if si.death and si.death < 0 then
+				AddRune(startCast, 4, si.death)
 			end
 		end
-
-		-- Runes
-		if si.blood and si.blood < 0 then
-			AddRune(startCast, 1, si.blood)
-		end
-		if si.unholy and si.unholy < 0 then
-			AddRune(startCast, 2, si.unholy)
-		end
-		if si.frost and si.frost < 0 then
-			AddRune(startCast, 3, si.frost)
-		end
-		if si.death and si.death < 0 then
-			AddRune(startCast, 4, si.death)
-		end
 	end
 end

--- Returns 1 if moving toward Solar or -1 if moving toward Lunar.
-function OvaleState:GetEclipseDir()
-	local stacks = select(3, self.state:GetAura("player", SOLAR_ECLIPSE, "HELPFUL", true))
-	if stacks and stacks > 0 then
-		return -1
-	else
-		stacks = select(3, self.state:GetAura("player", LUNAR_ECLIPSE, "HELPFUL", true))
-		if stacks and stacks > 0 then
-			return 1
-		elseif self.state.eclipse < 0 then
-			return -1
-		elseif self.state.eclipse > 0 then
-			return 1
-		else
-			local direction = API_GetEclipseDirection()
-			if direction == "moon" then
-				return -1
-			else -- direction == "sun" then
-				return 1
-			end
-		end
-	end
+-- Apply the effects of the spell on the target's state when it lands on the target.
+function OvaleState:ApplySpellOnTarget(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast)
+	self:InvokeMethod("ApplySpellOnTarget", spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast)
 end

 -- Returns the cooldown time before all of the required runes are available.
diff --git a/conditions/EclipseDir.lua b/conditions/EclipseDir.lua
index 2cdf664..4a7352b 100644
--- a/conditions/EclipseDir.lua
+++ b/conditions/EclipseDir.lua
@@ -18,6 +18,7 @@ do
 	--- Get the current direction of the Eclipse status on the Eclipse bar for balance druids.
 	-- A negative number means heading toward Lunar Eclipse.
 	-- A positive number means heading toward Solar Eclipse.
+	-- Zero means it can head in either direction.
 	-- @name EclipseDir
 	-- @paramsig number or boolean
 	-- @param operator Optional. Comparison operator: less, atMost, equal, atLeast, more.
@@ -31,7 +32,7 @@ do

 	local function EclipseDir(condition)
 		local comparator, limit = condition[1], condition[2]
-		local value = OvaleState:GetEclipseDir()
+		local value = OvaleState.state.eclipseDirection
 		return Compare(value, comparator, limit)
 	end