Quantcast

Translate SimulationCraft's "prev" and "prev_gcd" operands.

Johnny C. Lam [12-27-14 - 20:07]
Translate SimulationCraft's "prev" and "prev_gcd" operands.

Enhance OvaleFuture to track the previous GCD spell cast in addition to
the previous spell cast.
Filename
Future.lua
SimulationCraft.lua
conditions.lua
diff --git a/Future.lua b/Future.lua
index 371fcbd..0fc4b68 100644
--- a/Future.lua
+++ b/Future.lua
@@ -128,6 +128,8 @@ OvaleFuture.combatStartTime = nil
 OvaleFuture.counter = {}
 -- Most recent spellcast.
 OvaleFuture.lastSpellcast = nil
+-- Most recent GCD spellcast.
+OvaleFuture.lastGCDSpellcast = nil
 -- Debugging: spells to trace
 OvaleFuture.traceSpellList = nil
 --</public-static-properties>
@@ -362,6 +364,11 @@ local function UpdateLastSpellcast(spellcast)
 		end
 		self_lastSpellcast[targetGUID][spellId] = spellcast
 		self.lastSpellcast = spellcast
+		local unitId = OvaleGUID:GetUnitId(targetGUID)
+		local gcd = OvaleData:GetSpellInfoProperty(spellId, "gcd", unitId)
+		if not gcd or gcd > 0 then
+			self.lastGCDSpellcast = spellcast
+		end

 		--[[
 			If any auras have been added between the start of the spellcast and this event,
@@ -684,7 +691,7 @@ function OvaleFuture:LastInFlightSpell()
 	if #self_activeSpellcast > 0 then
 		return self_activeSpellcast[#self_activeSpellcast]
 	end
-	return self.lastSpellcast
+	return self.lastGCDSpellcast
 end

 function OvaleFuture:UpdateFromSpellcast(dest, spellcast)
@@ -773,12 +780,14 @@ statePrototype.startCast = nil
 statePrototype.endCast = nil
 -- The time at which the next GCD spell can be cast in the simulator.
 statePrototype.nextCast = nil
+-- The most recent time the spell was cast in the simulator.
+statePrototype.lastCast = nil
 -- Whether the player is channeling a spell in the simulator at the current time.
 statePrototype.isChanneling = nil
 -- The previous spell cast in the simulator.
 statePrototype.lastSpellId = nil
--- The most recent time the spell was cast in the simulator.
-statePrototype.lastCast = nil
+-- The previous GCD spell cast in the simulator.
+statePrototype.lastGCDSpellId = nil
 -- counter[name] = count
 statePrototype.counter = nil
 --</state-properties>
@@ -800,6 +809,7 @@ function OvaleFuture:ResetState(state)
 	state.inCombat = self.inCombat
 	state.combatStartTime = self.combatStartTime or 0
 	state.lastSpellId = self.lastSpellcast and self.lastSpellcast.spellId
+	state.lastGCDSpellId = self.lastGCDSpellcast and self.lastGCDSpellcast.spellId
 	state.currentSpellId = nil
 	state.isChanneling = false
 	state.nextCast = now
@@ -823,6 +833,7 @@ function OvaleFuture:CleanState(state)
 	state.nextCast = nil
 	state.isChanneling = nil
 	state.lastSpellId = nil
+	state.lastGCDSpellId = nil

 	for k in pairs(state.lastCast) do
 		state.lastCast[k] = nil
@@ -885,11 +896,12 @@ end
 statePrototype.ApplySpell = function(state, spellId, targetGUID, startCast, endCast, nextCast, isChanneled, spellcast)
 	OvaleFuture:StartProfiling("OvaleFuture_state_ApplySpell")
 	if spellId and targetGUID then
+		local target = OvaleGUID:GetUnitId(targetGUID)
+		local gcd = state:GetGCD(spellId, target)
+
 		-- Handle missing start/end/next cast times.
 		if not startCast or not endCast or not nextCast then
-			local target = OvaleGUID:GetUnitId(targetGUID)
 			local castTime = OvaleSpellBook:GetCastTime(spellId) or 0
-			local gcd = state:GetGCD(spellId, target)
 			startCast = startCast or state.nextCast
 			endCast = endCast or (startCast + castTime)
 			nextCast = (castTime > gcd) and endCast or (startCast + gcd)
@@ -901,8 +913,11 @@ statePrototype.ApplySpell = function(state, spellId, targetGUID, startCast, endC
 		state.endCast = endCast
 		state.nextCast = nextCast
 		state.isChanneling = isChanneled
-		state.lastSpellId = spellId
 		state.lastCast[spellId] = endCast
+		state.lastSpellId = spellId
+		if gcd > 0 then
+			state.lastGCDSpellId = spellId
+		end

 		-- Set the current time in the simulator to *slightly* after the start of the current cast,
 		-- or to now if in the past.
diff --git a/SimulationCraft.lua b/SimulationCraft.lua
index 9646d15..d75f7c2 100644
--- a/SimulationCraft.lua
+++ b/SimulationCraft.lua
@@ -1084,6 +1084,7 @@ local EmitOperandDisease = nil
 local EmitOperandDot = nil
 local EmitOperandGlyph = nil
 local EmitOperandPet = nil
+local EmitOperandPreviousSpell = nil
 local EmitOperandRaidEvent = nil
 local EmitOperandRune = nil
 local EmitOperandSeal = nil
@@ -1954,6 +1955,8 @@ EmitOperand = function(parseNode, nodeList, annotation, action)
 			ok, node = EmitOperandGlyph(operand, parseNode, nodeList, annotation, action)
 		elseif token == "pet" then
 			ok, node = EmitOperandPet(operand, parseNode, nodeList, annotation, action)
+		elseif token == "prev" or token == "prev_gcd" then
+			ok, node = EmitOperandPreviousSpell(operand, parseNode, nodeList, annotation, action)
 		elseif token == "seal" then
 			ok, node = EmitOperandSeal(operand, parseNode, nodeList, annotation, action)
 		elseif token == "set_bonus" then
@@ -2512,6 +2515,33 @@ EmitOperandPet = function(operand, parseNode, nodeList, annotation, action)
 	return ok, node
 end

+EmitOperandPreviousSpell = function(operand, parseNode, nodeList, annotation, action)
+	local ok = true
+	local node
+
+	local tokenIterator = gmatch(operand, OPERAND_TOKEN_PATTERN)
+	local token = tokenIterator()
+	if token == "prev" or token == "prev_gcd" then
+		local name = tokenIterator()
+		name = Disambiguate(name, annotation.class, annotation.specialization)
+		local code
+		if token == "prev" then
+			code = format("PreviousSpell(%s)", name)
+		else -- if token == "prev_gcd" then
+			code = format("PreviousGCDSpell(%s)", name)
+		end
+		if ok and code then
+			annotation.astAnnotation = annotation.astAnnotation or {}
+			node = OvaleAST:ParseCode("expression", code, nodeList, annotation.astAnnotation)
+			AddSymbol(annotation, name)
+		end
+	else
+		ok = false
+	end
+
+	return ok, node
+end
+
 EmitOperandRaidEvent = function(operand, parseNode, nodeList, annotation, action)
 	local ok = true
 	local node
diff --git a/conditions.lua b/conditions.lua
index 902d974..f736b1c 100644
--- a/conditions.lua
+++ b/conditions.lua
@@ -4122,6 +4122,25 @@ do
 end

 do
+	--- Test if the previous spell cast that invoked the GCD matches the given spell.
+	-- @name PreviousGCDSpell
+	-- @paramsig boolean
+	-- @param id The spell ID.
+	-- @param yesno Optional. If yes, then return true if there is a match. If no, then return true if it doesn't match.
+	--     Default is yes.
+	--     Valid values: yes, no.
+	-- @return A boolean value.
+
+	local function PreviousGCDSpell(condition, state)
+		local spellId, yesno = condition[1], condition[2]
+		local boolean = (spellId == state.lastGCDSpellId)
+		return TestBoolean(boolean, yesno)
+	end
+
+	OvaleCondition:RegisterCondition("previousgcdspell", true, PreviousGCDSpell)
+end
+
+do
 	--- Test if the previous spell cast matches the given spell.
 	-- @name PreviousSpell
 	-- @paramsig boolean