Quantcast

Decorate code to identify state properties and enforce proper usage.

Johnny C. Lam [11-27-13 - 14:04]
Decorate code to identify state properties and enforce proper usage.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1223 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
OvaleAura.lua
OvaleComboPoints.lua
OvaleCooldown.lua
OvaleData.lua
OvaleEclipse.lua
OvaleFuture.lua
OvalePaperDoll.lua
OvalePower.lua
OvaleRunes.lua
OvaleState.lua
compiler.pl
diff --git a/OvaleAura.lua b/OvaleAura.lua
index abff51c..0563359 100644
--- a/OvaleAura.lua
+++ b/OvaleAura.lua
@@ -502,6 +502,17 @@ OvaleAura.statePrototype = {
 }
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleAura.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+-- Aura database: aura[guid][auraId][casterId] = aura
+statePrototype.aura = nil
+-- Age of active auras in the simulator.
+statePrototype.serial = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleAura:InitializeState(state)
@@ -545,359 +556,355 @@ end
 --</public-static-methods>

 --<state-methods>
-do
-	local statePrototype = OvaleAura.statePrototype
-
-	local function GetStateAura(state, guid, auraId, casterGUID)
-		local auraFound = GetAura(state.aura, guid, auraId, casterGUID)
-		if not state:IsActiveAura(auraFound) then
-			auraFound = GetAura(self_aura, guid, auraId, casterGUID)
-		end
-		return auraFound
+local function GetStateAura(state, guid, auraId, casterGUID)
+	local auraFound = GetAura(state.aura, guid, auraId, casterGUID)
+	if not state:IsActiveAura(auraFound) then
+		auraFound = GetAura(self_aura, guid, auraId, casterGUID)
 	end
+	return auraFound
+end

-	local function GetStateAuraAnyCaster(state, guid, auraId)
-		local auraFound = GetAuraAnyCaster(state.aura, guid, auraId)
-		local aura = GetAuraAnyCaster(self_aura, guid, auraId)
-		local now = state.currentTime
-		if OvaleAura:IsActiveAura(aura, now) then
-			if not state:IsActiveAura(auraFound, now) or auraFound.ending < aura.ending then
-				auraFound = aura
-			end
+local function GetStateAuraAnyCaster(state, guid, auraId)
+	local auraFound = GetAuraAnyCaster(state.aura, guid, auraId)
+	local aura = GetAuraAnyCaster(self_aura, guid, auraId)
+	local now = state.currentTime
+	if OvaleAura:IsActiveAura(aura, now) then
+		if not state:IsActiveAura(auraFound, now) or auraFound.ending < aura.ending then
+			auraFound = aura
 		end
-		return auraFound
 	end
+	return auraFound
+end

-	local function GetStateDebuffType(state, guid, debuffType, filter, casterGUID)
-		local auraFound = GetDebuffType(state.aura, guid, debuffType, filter, casterGUID)
-		local aura = GetDebuffType(self_aura, guid, debuffType, filter, casterGUID)
-		local now = state.currentTime
-		if OvaleAura:IsActiveAura(aura, now) then
-			if not state:IsActiveAura(auraFound, now) or auraFound.ending < aura.ending then
-				auraFound = aura
-			end
+local function GetStateDebuffType(state, guid, debuffType, filter, casterGUID)
+	local auraFound = GetDebuffType(state.aura, guid, debuffType, filter, casterGUID)
+	local aura = GetDebuffType(self_aura, guid, debuffType, filter, casterGUID)
+	local now = state.currentTime
+	if OvaleAura:IsActiveAura(aura, now) then
+		if not state:IsActiveAura(auraFound, now) or auraFound.ending < aura.ending then
+			auraFound = aura
 		end
-		return auraFound
 	end
+	return auraFound
+end

-	local function GetStateDebuffTypeAnyCaster(state, guid, debuffType, filter)
-		local auraFound = GetDebuffTypeAnyCaster(state.aura, guid, debuffType, filter)
-		local aura = GetDebuffTypeAnyCaster(self_aura, guid, debuffType, filter)
-		local now = state.currentTime
-		if OvaleAura:IsActiveAura(aura, now) then
-			if not state:IsActiveAura(auraFound, now) or auraFound.ending < aura.ending then
-				auraFound = aura
-			end
+local function GetStateDebuffTypeAnyCaster(state, guid, debuffType, filter)
+	local auraFound = GetDebuffTypeAnyCaster(state.aura, guid, debuffType, filter)
+	local aura = GetDebuffTypeAnyCaster(self_aura, guid, debuffType, filter)
+	local now = state.currentTime
+	if OvaleAura:IsActiveAura(aura, now) then
+		if not state:IsActiveAura(auraFound, now) or auraFound.ending < aura.ending then
+			auraFound = aura
 		end
-		return auraFound
 	end
+	return auraFound
+end

-	local function GetStateAuraOnGUID(state, guid, auraId, filter, mine)
-		local auraFound
-		if DEBUFF_TYPES[auraId] then
-			if mine then
-				auraFound = GetStateDebuffType(state, guid, auraId, filter, self_guid)
-			else
-				auraFound = GetStateDebuffTypeAnyCaster(state, guid, auraId, filter)
-			end
+local function GetStateAuraOnGUID(state, guid, auraId, filter, mine)
+	local auraFound
+	if DEBUFF_TYPES[auraId] then
+		if mine then
+			auraFound = GetStateDebuffType(state, guid, auraId, filter, self_guid)
 		else
-			if mine then
-				auraFound = GetStateAura(state, guid, auraId, self_guid)
-			else
-				auraFound = GetStateAuraAnyCaster(state, guid, auraId)
-			end
+			auraFound = GetStateDebuffTypeAnyCaster(state, guid, auraId, filter)
+		end
+	else
+		if mine then
+			auraFound = GetStateAura(state, guid, auraId, self_guid)
+		else
+			auraFound = GetStateAuraAnyCaster(state, guid, auraId)
 		end
-		return auraFound
 	end
+	return auraFound
+end

-	-- Print the auras matching the filter on the unit in alphabetical order.
-	do
-		local array = {}
+-- Print the auras matching the filter on the unit in alphabetical order.
+do
+	local array = {}

-		statePrototype.PrintUnitAuras = function(state, unitId, filter)
-			wipe(array)
-			local guid = OvaleGUID:GetGUID(unitId)
-			if self_aura[guid] then
-				for auraId, whoseTable in pairs(self_aura[guid]) do
-					for casterGUID in pairs(whoseTable) do
-						local aura = GetStateAura(state, guid, auraId, casterGUID)
-						if state:IsActiveAura(aura, now) and aura.filter == filter and not aura.state then
-							local name = aura.name or "Unknown spell"
-							tinsert(array, name .. ": " .. auraId)
-						end
+	statePrototype.PrintUnitAuras = function(state, unitId, filter)
+		wipe(array)
+		local guid = OvaleGUID:GetGUID(unitId)
+		if self_aura[guid] then
+			for auraId, whoseTable in pairs(self_aura[guid]) do
+				for casterGUID in pairs(whoseTable) do
+					local aura = GetStateAura(state, guid, auraId, casterGUID)
+					if state:IsActiveAura(aura, now) and aura.filter == filter and not aura.state then
+						local name = aura.name or "Unknown spell"
+						tinsert(array, name .. ": " .. auraId)
 					end
 				end
 			end
-			if state.aura[guid] then
-				for auraId, whoseTable in pairs(state.aura[guid]) do
-					for casterGUID, aura in pairs(whoseTable) do
-						if state:IsActiveAura(aura, now) and aura.filter == filter then
-							local name = aura.name or "Unknown spell"
-							tinsert(array, name .. ": " .. auraId)
-						end
+		end
+		if state.aura[guid] then
+			for auraId, whoseTable in pairs(state.aura[guid]) do
+				for casterGUID, aura in pairs(whoseTable) do
+					if state:IsActiveAura(aura, now) and aura.filter == filter then
+						local name = aura.name or "Unknown spell"
+						tinsert(array, name .. ": " .. auraId)
 					end
 				end
 			end
-			if next(array) then
-				tsort(array)
-				for _, v in ipairs(array) do
-					Ovale:Print(v)
-				end
+		end
+		if next(array) then
+			tsort(array)
+			for _, v in ipairs(array) do
+				Ovale:Print(v)
 			end
 		end
 	end
+end

-	statePrototype.IsActiveAura = function(state, aura, now)
-		now = now or state.currentTime
-		local boolean = false
-		if aura then
-			if aura.state then
-				boolean = (aura.serial == state.serial and aura.stacks > 0 and aura.start <= now and now <= aura.ending)
-			else
-				boolean = OvaleAura:IsActiveAura(aura, now)
-			end
+statePrototype.IsActiveAura = function(state, aura, now)
+	now = now or state.currentTime
+	local boolean = false
+	if aura then
+		if aura.state then
+			boolean = (aura.serial == state.serial and aura.stacks > 0 and aura.start <= now and now <= aura.ending)
+		else
+			boolean = OvaleAura:IsActiveAura(aura, now)
 		end
-		return boolean
 	end
+	return boolean
+end

-	statePrototype.ApplySpellAuras = function(state, spellId, guid, startCast, endCast, isChanneled, auraList, spellcast)
-		local unitId = OvaleGUID:GetUnitId(guid)
-		for filter, filterInfo in pairs(auraList) do
-			for auraId, spellData in pairs(filterInfo) do
-				--[[
-					For lists described by SpellAddBuff(), etc., use the following interpretation:
-						auraId=refresh		aura is refreshed, no change to stacks
-						auraId=N, N > 0		N is duration if aura has no duration SpellInfo() [deprecated].
-						auraId=N, N > 0		N is number of stacks added
-						auraId=0			aura is removed
-						auraId=N, N < 0		N is number of stacks of aura removed
-				--]]
-				local si = OvaleData.spellInfo[auraId]
-				local duration, dotDuration, tick, numTicks = state:GetDuration(auraId, spellcast)
-				local stacks = 1
-
-				if type(spellData) == "number" and spellData > 0 then
-					stacks = spellData
-					-- Deprecated after transition.
-					if not (si and si.duration) then
-						-- Aura doesn't have duration SpellInfo(), so treat spell data as duration.
-						duration = spellData
-						stacks = 1
-					end
+statePrototype.ApplySpellAuras = function(state, spellId, guid, startCast, endCast, isChanneled, auraList, spellcast)
+	local unitId = OvaleGUID:GetUnitId(guid)
+	for filter, filterInfo in pairs(auraList) do
+		for auraId, spellData in pairs(filterInfo) do
+			--[[
+				For lists described by SpellAddBuff(), etc., use the following interpretation:
+					auraId=refresh		aura is refreshed, no change to stacks
+					auraId=N, N > 0		N is duration if aura has no duration SpellInfo() [deprecated].
+					auraId=N, N > 0		N is number of stacks added
+					auraId=0			aura is removed
+					auraId=N, N < 0		N is number of stacks of aura removed
+			--]]
+			local si = OvaleData.spellInfo[auraId]
+			local duration, dotDuration, tick, numTicks = state:GetDuration(auraId, spellcast)
+			local stacks = 1
+
+			if type(spellData) == "number" and spellData > 0 then
+				stacks = spellData
+				-- Deprecated after transition.
+				if not (si and si.duration) then
+					-- Aura doesn't have duration SpellInfo(), so treat spell data as duration.
+					duration = spellData
+					stacks = 1
 				end
+			end

-				local auraFound = state:GetAuraByGUID(guid, auraId, filter, true)
-				local atTime = isChanneled and startCast or endCast
+			local auraFound = state:GetAuraByGUID(guid, auraId, filter, true)
+			local atTime = isChanneled and startCast or endCast

-				if state:IsActiveAura(auraFound, atTime) then
-					local aura
-					if auraFound.state then
-						-- Re-use existing aura in the simulator.
-						aura = auraFound
-					else
-						-- Add an aura in the simulator and copy the existing aura information over.
-						aura = state:AddAuraToGUID(guid, auraId, self_guid, filter, 0, math.huge)
-						for k, v in pairs(auraFound) do
-							aura[k] = v
-						end
-						if auraFound.snapshot then
-							aura.snapshot = OvalePaperDoll:GetSnapshot(auraFound.snapshot)
-						end
-						-- Reset the aura age relative to the state of the simulator.
-						aura.serial = state.serial
-						-- Information that needs to be set below: stacks, start, ending, duration, gain.
+			if state:IsActiveAura(auraFound, atTime) then
+				local aura
+				if auraFound.state then
+					-- Re-use existing aura in the simulator.
+					aura = auraFound
+				else
+					-- Add an aura in the simulator and copy the existing aura information over.
+					aura = state:AddAuraToGUID(guid, auraId, self_guid, filter, 0, math.huge)
+					for k, v in pairs(auraFound) do
+						aura[k] = v
 					end
-					-- Spell starts channeling before the aura expires, or spellcast ends before the aura expires.
-					if spellData == "refresh" or stacks > 0 then
-						-- Adjust stack count.
-						if spellData == "refresh" then
-							Ovale:Logf("Aura %d is refreshed.", auraId)
-						else -- if stacks > 0 then
-							local maxstacks = si.maxstacks or 1
-							aura.stacks = aura.stacks + stacks
-							if aura.stacks > maxstacks then
-								aura.stacks = maxstacks
-							end
-							Ovale:Logf("Aura %d gains %d stack(s) to %d because of spell %d.", auraId, stacks, aura.stacks, spellId)
-						end
-						-- Set start and duration for aura.
-						if aura.tick and aura.tick > 0 then
-							-- This is a periodic aura, so add new duration after the next tick is complete.
-							local ticksRemain = floor((aura.ending - atTime) / aura.tick)
-							aura.start = aura.ending - aura.tick * ticksRemain
-							if OvaleData:NeedNewSnapshot(auraId, spellId) then
-								-- Use duration and tick information based on spellcast snapshot.
-								aura.duration = dotDuration
-								aura.tick = tick
-								OvaleFuture:UpdateSnapshotFromSpellcast(aura, spellcast)
-							end
-						else
-							aura.start = atTime
-							if OvaleData:NeedNewSnapshot(auraId, spellId) then
-								aura.duration = duration
-							end
-						end
-						aura.ending = aura.start + aura.duration
-						aura.gain = atTime
-						Ovale:Logf("Aura %d now ending at %f", auraId, aura.ending)
-					elseif stacks == 0 or stacks < 0 then
-						if stacks == 0 then
-							aura.stacks = 0
-						else -- if stacks < 0 then
-							aura.stacks = aura.stacks + stacks
-							if aura.stacks < 0 then
-								aura.stacks = 0
-							end
-							Ovale:Logf("Aura %d loses %d stack(s) to %d because of spell %d.", auraId, -1 * stacks, aura.stacks, spellId)
-						end
-						-- An existing aura is losing stacks, so inherit start, duration, ending and gain information.
-						if aura.stacks == 0 then
-							Ovale:Logf("Aura %d is completely removed.", auraId)
-							-- The aura is completely removed, so set ending to the time that the aura is removed.
-							aura.ending = atTime
+					if auraFound.snapshot then
+						aura.snapshot = OvalePaperDoll:GetSnapshot(auraFound.snapshot)
+					end
+					-- Reset the aura age relative to the state of the simulator.
+					aura.serial = state.serial
+					-- Information that needs to be set below: stacks, start, ending, duration, gain.
+				end
+				-- Spell starts channeling before the aura expires, or spellcast ends before the aura expires.
+				if spellData == "refresh" or stacks > 0 then
+					-- Adjust stack count.
+					if spellData == "refresh" then
+						Ovale:Logf("Aura %d is refreshed.", auraId)
+					else -- if stacks > 0 then
+						local maxstacks = si.maxstacks or 1
+						aura.stacks = aura.stacks + stacks
+						if aura.stacks > maxstacks then
+							aura.stacks = maxstacks
 						end
+						Ovale:Logf("Aura %d gains %d stack(s) to %d because of spell %d.", auraId, stacks, aura.stacks, spellId)
 					end
-				else
-					-- Aura is not on the target.
-					if stacks > 0 then
-						-- Spellcast causes a new aura.
-						Ovale:Logf("New aura %d at %f on %s", auraId, atTime, guid)
-						-- Add an aura in the simulator and copy the existing aura information over.
-						local aura = state:AddAuraToGUID(guid, auraId, self_guid, filter, 0, math.huge)
-						-- Information that needs to be set below: stacks, start, ending, duration, gain.
-						aura.stacks = stacks
-						aura.start = atTime
-						-- Set start and duration for aura.
-						if si and si.tick then
-							-- "tick" is set explicitly in SpellInfo, so this is a known periodic aura.
+					-- Set start and duration for aura.
+					if aura.tick and aura.tick > 0 then
+						-- This is a periodic aura, so add new duration after the next tick is complete.
+						local ticksRemain = floor((aura.ending - atTime) / aura.tick)
+						aura.start = aura.ending - aura.tick * ticksRemain
+						if OvaleData:NeedNewSnapshot(auraId, spellId) then
+							-- Use duration and tick information based on spellcast snapshot.
 							aura.duration = dotDuration
 							aura.tick = tick
-							aura.ticksSeen = 0
-						else
+							OvaleFuture:UpdateSnapshotFromSpellcast(aura, spellcast)
+						end
+					else
+						aura.start = atTime
+						if OvaleData:NeedNewSnapshot(auraId, spellId) then
 							aura.duration = duration
 						end
-						aura.ending = aura.start + aura.duration
-						aura.gain = aura.start
-						OvaleFuture:UpdateSnapshotFromSpellcast(aura, spellcast)
+					end
+					aura.ending = aura.start + aura.duration
+					aura.gain = atTime
+					Ovale:Logf("Aura %d now ending at %f", auraId, aura.ending)
+				elseif stacks == 0 or stacks < 0 then
+					if stacks == 0 then
+						aura.stacks = 0
+					else -- if stacks < 0 then
+						aura.stacks = aura.stacks + stacks
+						if aura.stacks < 0 then
+							aura.stacks = 0
+						end
+						Ovale:Logf("Aura %d loses %d stack(s) to %d because of spell %d.", auraId, -1 * stacks, aura.stacks, spellId)
+					end
+					-- An existing aura is losing stacks, so inherit start, duration, ending and gain information.
+					if aura.stacks == 0 then
+						Ovale:Logf("Aura %d is completely removed.", auraId)
+						-- The aura is completely removed, so set ending to the time that the aura is removed.
+						aura.ending = atTime
 					end
 				end
+			else
+				-- Aura is not on the target.
+				if stacks > 0 then
+					-- Spellcast causes a new aura.
+					Ovale:Logf("New aura %d at %f on %s", auraId, atTime, guid)
+					-- Add an aura in the simulator and copy the existing aura information over.
+					local aura = state:AddAuraToGUID(guid, auraId, self_guid, filter, 0, math.huge)
+					-- Information that needs to be set below: stacks, start, ending, duration, gain.
+					aura.stacks = stacks
+					aura.start = atTime
+					-- Set start and duration for aura.
+					if si and si.tick then
+						-- "tick" is set explicitly in SpellInfo, so this is a known periodic aura.
+						aura.duration = dotDuration
+						aura.tick = tick
+						aura.ticksSeen = 0
+					else
+						aura.duration = duration
+					end
+					aura.ending = aura.start + aura.duration
+					aura.gain = aura.start
+					OvaleFuture:UpdateSnapshotFromSpellcast(aura, spellcast)
+				end
 			end
 		end
 	end
+end

-	statePrototype.GetAuraByGUID = function(state, guid, auraId, filter, mine)
-		local auraFound
-		if OvaleData.buffSpellList[auraId] then
-			for id in pairs(OvaleData.buffSpellList[auraId]) do
-				local aura = GetStateAuraOnGUID(state, guid, id, filter, mine)
-				if aura and (not auraFound or auraFound.ending < aura.ending) then
-					auraFound = aura
-				end
+statePrototype.GetAuraByGUID = function(state, guid, auraId, filter, mine)
+	local auraFound
+	if OvaleData.buffSpellList[auraId] then
+		for id in pairs(OvaleData.buffSpellList[auraId]) do
+			local aura = GetStateAuraOnGUID(state, guid, id, filter, mine)
+			if aura and (not auraFound or auraFound.ending < aura.ending) then
+				auraFound = aura
 			end
-		else
-			auraFound = GetStateAuraOnGUID(state, guid, auraId, filter, mine)
 		end
-		return auraFound
+	else
+		auraFound = GetStateAuraOnGUID(state, guid, auraId, filter, mine)
 	end
+	return auraFound
+end

-	statePrototype.GetAura = function(state, unitId, auraId, filter, mine)
-		local guid = OvaleGUID:GetGUID(unitId)
-		return state:GetAuraByGUID(guid, auraId, filter, mine)
-	end
+statePrototype.GetAura = function(state, unitId, auraId, filter, mine)
+	local guid = OvaleGUID:GetGUID(unitId)
+	return state:GetAuraByGUID(guid, auraId, filter, mine)
+end

-	-- Add a new aura to the unit specified by GUID.
-	statePrototype.AddAuraToGUID = function(state, guid, auraId, casterGUID, filter, start, ending, snapshot)
-		local aura = self_pool:Get()
-		aura.state = true
-		aura.serial = state.serial
-		aura.filter = filter
-		aura.mine = mine
-		aura.start = start or 0
-		aura.ending = ending or math.huge
-		aura.duration = ending - start
-		aura.gain = aura.start
-		aura.stacks = 1
-		if snapshot then
-			aura.snapshot = OvalePaperDoll:GetSnapshot(snapshot)
-		end
-		PutAura(state.aura, guid, auraId, casterGUID, aura)
-		return aura
-	end
-
-	do
-		-- The total count of the matched aura.
-		local count
-		-- The start and ending times of the first aura to expire that will change the total count.
-		local startChangeCount, endingChangeCount
-		-- The time interval over which count > 0.
-		local startFirst, endingLast
-
-		local function CountMatchingActiveAura(aura)
-			count = count + 1
-			if aura.ending < endingChangeCount then
-				startChangeCount, endingChangeCount = aura.start, aura.ending
-			end
-			if aura.start < startFirst then
-				startFirst = aura.start
-			end
-			if aura.ending > endingLast then
-				endingLast = aura.ending
-			end
+-- Add a new aura to the unit specified by GUID.
+statePrototype.AddAuraToGUID = function(state, guid, auraId, casterGUID, filter, start, ending, snapshot)
+	local aura = self_pool:Get()
+	aura.state = true
+	aura.serial = state.serial
+	aura.filter = filter
+	aura.mine = mine
+	aura.start = start or 0
+	aura.ending = ending or math.huge
+	aura.duration = ending - start
+	aura.gain = aura.start
+	aura.stacks = 1
+	if snapshot then
+		aura.snapshot = OvalePaperDoll:GetSnapshot(snapshot)
+	end
+	PutAura(state.aura, guid, auraId, casterGUID, aura)
+	return aura
+end
+
+do
+	-- The total count of the matched aura.
+	local count
+	-- The start and ending times of the first aura to expire that will change the total count.
+	local startChangeCount, endingChangeCount
+	-- The time interval over which count > 0.
+	local startFirst, endingLast
+
+	local function CountMatchingActiveAura(aura)
+		count = count + 1
+		if aura.ending < endingChangeCount then
+			startChangeCount, endingChangeCount = aura.start, aura.ending
+		end
+		if aura.start < startFirst then
+			startFirst = aura.start
+		end
+		if aura.ending > endingLast then
+			endingLast = aura.ending
 		end
+	end
+
+	--[[
+		Return the total count of the given aura across all units, the start/end times of
+		the first aura to expire that will change the total count, and the time interval
+		over which the count is more than 0.
+	--]]
+	statePrototype.AuraCount = function(state, auraId, filter, mine)
+		-- Initialize.
+		count = 0
+		startChangeCount, endingChangeCount = math.huge, math.huge
+		startFirst, endingLast = math.huge, 0
+
+		local now = state.currentTime

-		--[[
-			Return the total count of the given aura across all units, the start/end times of
-			the first aura to expire that will change the total count, and the time interval
-			over which the count is more than 0.
-		--]]
-		statePrototype.AuraCount = function(state, auraId, filter, mine)
-			-- Initialize.
-			count = 0
-			startChangeCount, endingChangeCount = math.huge, math.huge
-			startFirst, endingLast = math.huge, 0
-
-			local now = state.currentTime
-
-			-- Loop through auras not kept in the simulator that match the criteria.
-			for guid, auraTable in pairs(self_aura) do
-				if auraTable[auraId] then
-					if mine then
-						local aura = GetStateAura(state, guid, auraId, self_guid)
+		-- Loop through auras not kept in the simulator that match the criteria.
+		for guid, auraTable in pairs(self_aura) do
+			if auraTable[auraId] then
+				if mine then
+					local aura = GetStateAura(state, guid, auraId, self_guid)
+					if state:IsActiveAura(aura, now) and aura.filter == filter and not aura.state then
+						CountMatchingActiveAura(aura)
+					end
+				else
+					for casterGUID in pairs(auraTable[auraId]) do
+						local aura = GetStateAura(state, guid, auraId, casterGUID)
 						if state:IsActiveAura(aura, now) and aura.filter == filter and not aura.state then
 							CountMatchingActiveAura(aura)
 						end
-					else
-						for casterGUID in pairs(auraTable[auraId]) do
-							local aura = GetStateAura(state, guid, auraId, casterGUID)
-							if state:IsActiveAura(aura, now) and aura.filter == filter and not aura.state then
-								CountMatchingActiveAura(aura)
-							end
-						end
 					end
 				end
 			end
-			-- Loop through auras in the simulator that match the criteria.
-			for guid, auraTable in pairs(state.aura) do
-				if auraTable[auraId] then
-					if mine then
-						local aura = auraTable[auraId][self_guid]
-						if aura then
-							if state:IsActiveAura(aura, now) and aura.filter == filter then
-								CountMatchingActiveAura(aura)
-							end
+		end
+		-- Loop through auras in the simulator that match the criteria.
+		for guid, auraTable in pairs(state.aura) do
+			if auraTable[auraId] then
+				if mine then
+					local aura = auraTable[auraId][self_guid]
+					if aura then
+						if state:IsActiveAura(aura, now) and aura.filter == filter then
+							CountMatchingActiveAura(aura)
 						end
-					else
-						for casterGUID, aura in pairs(auraTable[auraId]) do
-							if state:IsActiveAura(aura, now) and aura.filter == filter then
-								CountMatchingActiveAura(aura)
-							end
+					end
+				else
+					for casterGUID, aura in pairs(auraTable[auraId]) do
+						if state:IsActiveAura(aura, now) and aura.filter == filter then
+							CountMatchingActiveAura(aura)
 						end
 					end
 				end
 			end
-
-			return count, startChangeCount, endingChangeCount, startFirst, endingLast
 		end
+
+		return count, startChangeCount, endingChangeCount, startFirst, endingLast
 	end
 end
 --</state-methods>
diff --git a/OvaleComboPoints.lua b/OvaleComboPoints.lua
index 4faae32..28ffc21 100644
--- a/OvaleComboPoints.lua
+++ b/OvaleComboPoints.lua
@@ -112,11 +112,17 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvaleComboPoints.statePrototype = {
-	combo = nil,
-}
+OvaleComboPoints.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleComboPoints.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+statePrototype.combo = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleComboPoints:InitializeState(state)
diff --git a/OvaleCooldown.lua b/OvaleCooldown.lua
index 412fa51..dfb37f3 100644
--- a/OvaleCooldown.lua
+++ b/OvaleCooldown.lua
@@ -92,11 +92,17 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvaleCooldown.statePrototype = {
-	cd = nil,
-}
+OvaleCooldown.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleCooldown.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+statePrototype.cd = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleCooldown:InitializeState(state)
@@ -174,49 +180,45 @@ end
 --</public-static-methods>

 --<state-methods>
-do
-	local statePrototype = OvaleCooldown.statePrototype
-
-	-- Return the table holding the simulator's cooldown information for the given spell.
-	statePrototype.GetCD = function(state, spellId)
-		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]
+-- Return the table holding the simulator's cooldown information for the given spell.
+statePrototype.GetCD = function(state, spellId)
+	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
-		return nil
 	end
+	return nil
+end

-	-- Return the cooldown for the spell in the simulator.
-	statePrototype.GetSpellCooldown = function(state, spellId)
-		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
+-- Return the cooldown for the spell in the simulator.
+statePrototype.GetSpellCooldown = function(state, spellId)
+	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

-	-- Force the cooldown of a spell to reset at the specified time.
-	statePrototype.ResetSpellCooldown = function(state, spellId, atTime)
-		if atTime >= state.currentTime then
-			local start, duration, enable = state:GetSpellCooldown(spellId)
-			if start + duration > state.currentTime then
-				local cd = state:GetCD(spellId)
-				if cd then
-					cd.start = state.currentTime
-					cd.duration = atTime - state.currentTime
-					cd.enable = 1
-				end
+-- Force the cooldown of a spell to reset at the specified time.
+statePrototype.ResetSpellCooldown = function(state, spellId, atTime)
+	if atTime >= state.currentTime then
+		local start, duration, enable = state:GetSpellCooldown(spellId)
+		if start + duration > state.currentTime then
+			local cd = state:GetCD(spellId)
+			if cd then
+				cd.start = state.currentTime
+				cd.duration = atTime - state.currentTime
+				cd.enable = 1
 			end
 		end
 	end
diff --git a/OvaleData.lua b/OvaleData.lua
index 07d5e2c..20b628b 100644
--- a/OvaleData.lua
+++ b/OvaleData.lua
@@ -358,55 +358,55 @@ end
 OvaleData.statePrototype = {}
 --</public-static-properties>

---<state-methods>
-do
-	local statePrototype = OvaleData.statePrototype
+--<private-static-properties>
+local statePrototype = OvaleData.statePrototype
+--</private-static-properties>

-	statePrototype.GetTickLength = function(state, auraId, snapshot)
-		local tick = 3
-		local si = OvaleData.spellInfo[auraId]
-		if si then
-			tick = si.tick or tick
-			local hasteMultiplier = 1
-			if si.haste then
-				if si.haste == "spell" then
-					hasteMultiplier = state:GetSpellHasteMultiplier(snapshot)
-				elseif si.haste == "melee" then
-					hasteMultiplier = state:GetMeleeHasteMultiplier(snapshot)
-				end
-				tick = tick / hasteMultiplier
+--<state-methods>
+statePrototype.GetTickLength = function(state, auraId, snapshot)
+	local tick = 3
+	local si = OvaleData.spellInfo[auraId]
+	if si then
+		tick = si.tick or tick
+		local hasteMultiplier = 1
+		if si.haste then
+			if si.haste == "spell" then
+				hasteMultiplier = state:GetSpellHasteMultiplier(snapshot)
+			elseif si.haste == "melee" then
+				hasteMultiplier = state:GetMeleeHasteMultiplier(snapshot)
 			end
+			tick = tick / hasteMultiplier
 		end
-		return tick
 	end
+	return tick
+end

-	-- Returns the raw duration, DoT duration, tick length, and number of ticks of an aura.
-	statePrototype.GetDuration = function(state, auraId, spellcast)
-		local snapshot, combo, holy
-		if spellcast then
-			snapshot, combo, holy = spellcast.snapshot, spellcast.combo, spellcast.holy
-		else
-			snapshot, combo, holy = state.snapshot, state.combo, state.holy
-		end
+-- Returns the raw duration, DoT duration, tick length, and number of ticks of an aura.
+statePrototype.GetDuration = function(state, auraId, spellcast)
+	local snapshot, combo, holy
+	if spellcast then
+		snapshot, combo, holy = spellcast.snapshot, spellcast.combo, spellcast.holy
+	else
+		snapshot, combo, holy = state.snapshot, state.combo, state.holy
+	end

-		local duration = math.huge
-		local tick = state:GetTickLength(auraId, snapshot)
+	local duration = math.huge
+	local tick = state:GetTickLength(auraId, snapshot)

-		local si = OvaleData.spellInfo[auraId]
-		if si and si.duration then
-			duration = si.duration
-			if si.adddurationcp and combo then
-				duration = duration + si.adddurationcp * combo
-			end
-			if si.adddurationholy and holy then
-				duration = duration + si.adddurationholy * (holy - 1)
-			end
+	local si = OvaleData.spellInfo[auraId]
+	if si and si.duration then
+		duration = si.duration
+		if si.adddurationcp and combo then
+			duration = duration + si.adddurationcp * combo
+		end
+		if si.adddurationholy and holy then
+			duration = duration + si.adddurationholy * (holy - 1)
 		end
+	end

-		local numTicks = floor(duration/tick + 0.5)
-		local dotDuration = tick * numTicks
+	local numTicks = floor(duration/tick + 0.5)
+	local dotDuration = tick * numTicks

-		return duration, dotDuration, tick, numTicks
-	end
+	return duration, dotDuration, tick, numTicks
 end
 --</state-methods>
diff --git a/OvaleEclipse.lua b/OvaleEclipse.lua
index 94a5b84..82c68d2 100644
--- a/OvaleEclipse.lua
+++ b/OvaleEclipse.lua
@@ -129,11 +129,18 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvaleEclipse.statePrototype = {
-	eclipseDirection = nil,
-}
+OvaleEclipse.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleEclipse.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+-- Direction in which the Eclipse bar is moving.
+statePrototype.eclipseDirection = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleEclipse:InitializeState(state)
diff --git a/OvaleFuture.lua b/OvaleFuture.lua
index 6012328..1baa087 100644
--- a/OvaleFuture.lua
+++ b/OvaleFuture.lua
@@ -581,11 +581,18 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvaleFuture.statePrototype = {
-	counter = nil,
-}
+OvaleFuture.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleFuture.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+-- counter[name] = count
+statePrototype.counter = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleFuture:InitializeState(state)
@@ -625,15 +632,11 @@ end
 --</public-static-methods>

 --<state-methods>
-do
-	local statePrototype = OvaleFuture.statePrototype
-
-	statePrototype.GetCounterValue = function(state, id)
-		return state.counter[id] or 0
-	end
+statePrototype.GetCounterValue = function(state, id)
+	return state.counter[id] or 0
+end

-	statePrototype.GetDamageMultiplier = function(state, spellId)
-		return GetDamageMultiplier(spellId, state)
-	end
-end
+statePrototype.GetDamageMultiplier = function(state, spellId)
+	return GetDamageMultiplier(spellId, state)
+end
 --</state-methods>
diff --git a/OvalePaperDoll.lua b/OvalePaperDoll.lua
index 5aa9710..b834ded 100644
--- a/OvalePaperDoll.lua
+++ b/OvalePaperDoll.lua
@@ -482,13 +482,22 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvalePaperDoll.statePrototype = {
-	level = nil,
-	specialization = nil,
-	snapshot = nil,
-}
+OvalePaperDoll.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvalePaperDoll.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+-- Player's level.
+statePrototype.level = nil
+-- Player's chosen specialization/mastery.
+statePrototype.specialization = nil
+-- Player's current snapshot.
+statePrototype.snapshot = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvalePaperDoll:InitializeState(state)
@@ -516,27 +525,23 @@ end
 --</public-static-methods>

 --<state-methods>
-do
-	local statePrototype = OvalePaperDoll.statePrototype
-
-	statePrototype.GetMasteryMultiplier = function(state, snapshot)
-		snapshot = snapshot or state.snapshot
-		return 1 + snapshot.masteryEffect / 100
-	end
+statePrototype.GetMasteryMultiplier = function(state, snapshot)
+	snapshot = snapshot or state.snapshot
+	return 1 + snapshot.masteryEffect / 100
+end

-	statePrototype.GetMeleeHasteMultiplier = function(state, snapshot)
-		snapshot = snapshot or state.snapshot
-		return 1 + snapshot.meleeHaste / 100
-	end
+statePrototype.GetMeleeHasteMultiplier = function(state, snapshot)
+	snapshot = snapshot or state.snapshot
+	return 1 + snapshot.meleeHaste / 100
+end

-	statePrototype.GetRangedHasteMultiplier = function(state, snapshot)
-		snapshot = snapshot or state.snapshot
-		return 1 + snapshot.rangedHaste / 100
-	end
+statePrototype.GetRangedHasteMultiplier = function(state, snapshot)
+	snapshot = snapshot or state.snapshot
+	return 1 + snapshot.rangedHaste / 100
+end

-	statePrototype.GetSpellHasteMultiplier = function(state, snapshot)
-		snapshot = snapshot or state.snapshot
-		return 1 + snapshot.spellHaste / 100
-	end
+statePrototype.GetSpellHasteMultiplier = function(state, snapshot)
+	snapshot = snapshot or state.snapshot
+	return 1 + snapshot.spellHaste / 100
 end
 --</state-methods>
diff --git a/OvalePower.lua b/OvalePower.lua
index c9dfca5..0810177 100644
--- a/OvalePower.lua
+++ b/OvalePower.lua
@@ -210,11 +210,36 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvalePower.statePrototype = {
-	powerRate = nil,
-}
+OvalePower.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvalePower.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+--[[
+	This block is here for compiler.pl to know that these properties are added to the state machine.
+
+	statePrototype.alternate = nil
+	statePrototype.burningembers = nil
+	statePrototype.chi = nil
+	statePrototype.demonicfury = nil
+	statePrototype.eclipse = nil
+	statePrototype.energy = nil
+	statePrototype.focus = nil
+	statePrototype.holy = nil
+	statePrototype.mana = nil
+	statePrototype.rage = nil
+	statePrototype.runicpower = nil
+	statePrototype.shadoworbs = nil
+	statePrototype.shards = nil
+--]]
+
+-- powerRate[powerType] = regen rate
+statePrototype.powerRate = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvalePower:InitializeState(state)
@@ -317,14 +342,10 @@ end
 --</public-static-methods>

 --<state-methods>
-do
-	local statePrototype = OvalePower.statePrototype
-
-	-- Print out the levels of each power type in the current state.
-	statePrototype.DebugPower = function(state)
-		for powerType in pairs(OvalePower.POWER_INFO) do
-			Ovale:FormatPrint("%s = %d", powerType, state[powerType])
-		end
+-- Print out the levels of each power type in the current state.
+statePrototype.DebugPower = function(state)
+	for powerType in pairs(OvalePower.POWER_INFO) do
+		Ovale:FormatPrint("%s = %d", powerType, state[powerType])
 	end
 end
---</state-methods>
\ No newline at end of file
+--</state-methods>
diff --git a/OvaleRunes.lua b/OvaleRunes.lua
index aa37d6d..f427aa8 100644
--- a/OvaleRunes.lua
+++ b/OvaleRunes.lua
@@ -179,11 +179,18 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvaleRunes.statePrototype = {
-	rune = nil,	-- indexed by slot (1 through 6)
-}
+OvaleRunes.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleRunes.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+-- indexed by slot (1 through 6)
+statePrototype.rune = nil
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleRunes:InitializeState(state)
@@ -230,124 +237,109 @@ end
 --</public-static-methods>

 --<state-methods>
-do
-	local statePrototype = OvaleRunes.statePrototype
-
-	statePrototype.DebugRunes = function(state)
-		local now = state.currentTime
-		for slot = 1, 6 do
-			local rune = self.rune[slot]
-			if rune.active then
-				Ovale:FormatPrint("rune[%d] (%s) is active.", slot, RUNE_NAME[rune.type])
-			else
-				Ovale:FormatPrint("rune[%d] (%s) comes off cooldown in %f seconds.", slot, RUNE_NAME[rune.type], rune.endCooldown - now)
-			end
+statePrototype.DebugRunes = function(state)
+	local now = state.currentTime
+	for slot = 1, 6 do
+		local rune = self.rune[slot]
+		if rune.active then
+			Ovale:FormatPrint("rune[%d] (%s) is active.", slot, RUNE_NAME[rune.type])
+		else
+			Ovale:FormatPrint("rune[%d] (%s) comes off cooldown in %f seconds.", slot, RUNE_NAME[rune.type], rune.endCooldown - now)
 		end
 	end
+end

-	-- Consume a rune of the given type.  Assume that the required runes are available.
-	statePrototype.ConsumeRune = function(state, atTime, name, snapshot)
-		--[[
-			Find a usable rune, preferring a regular rune of that rune type over death
-			runes of that rune type over death runes of any rune type.
-		--]]
-		local consumedRune
-		local runeType = RUNE_TYPE[name]
-		if runeType ~= DEATH_RUNE then
-			-- Search for an active regular rune of the given rune type.
-			for _, slot in ipairs(RUNE_SLOTS[runeType]) do
-				local rune = state.rune[slot]
-				if rune.type == runeType and rune.active then
-					consumedRune = rune
-					break
-				end
-			end
-			if not consumedRune then
-				-- Search for an active death rune of the given rune type.
-				for _, slot in ipairs(RUNE_SLOTS[runeType]) do
-					if rune.type == DEATH_RUNE and rune.active then
-						consumedRune = rune
-						break
-					end
-				end
+-- Consume a rune of the given type.  Assume that the required runes are available.
+statePrototype.ConsumeRune = function(state, atTime, name, snapshot)
+	--[[
+		Find a usable rune, preferring a regular rune of that rune type over death
+		runes of that rune type over death runes of any rune type.
+	--]]
+	local consumedRune
+	local runeType = RUNE_TYPE[name]
+	if runeType ~= DEATH_RUNE then
+		-- Search for an active regular rune of the given rune type.
+		for _, slot in ipairs(RUNE_SLOTS[runeType]) do
+			local rune = state.rune[slot]
+			if rune.type == runeType and rune.active then
+				consumedRune = rune
+				break
 			end
 		end
-		-- No runes of the right type are active, so look for any active death rune.
 		if not consumedRune then
-			for _, slot in ipairs(DEATH_RUNE_PRIORITY) do
-				local rune = state.rune[slot]
+			-- Search for an active death rune of the given rune type.
+			for _, slot in ipairs(RUNE_SLOTS[runeType]) do
 				if rune.type == DEATH_RUNE and rune.active then
 					consumedRune = rune
 					break
 				end
 			end
 		end
-		if consumedRune then
-			-- Put that rune on cooldown, starting when the other rune of that slot type comes off cooldown.
-			local k = consumedRune.slotType
-			local start = atTime
-			for _, slot in ipairs(RUNE_SLOTS[consumedRune.slotType]) do
-				local rune = state.rune[slot]
-				if rune.endCooldown > start then
-					start = rune.endCooldown
-				end
-			end
-			local duration = 10 / state:GetSpellHasteMultiplier(snapshot)
-			if OvaleStance:IsStance("death_knight_blood_presence") and OvaleSpellBook:IsKnownSpell(IMPROVED_BLOOD_PRESENCE) then
-				-- Improved Blood Presence increases rune regeneration rate by 20%.
-				duration = duration / 1.2
+	end
+	-- No runes of the right type are active, so look for any active death rune.
+	if not consumedRune then
+		for _, slot in ipairs(DEATH_RUNE_PRIORITY) do
+			local rune = state.rune[slot]
+			if rune.type == DEATH_RUNE and rune.active then
+				consumedRune = rune
+				break
 			end
-			consumedRune.startCooldown = start
-			consumedRune.endCooldown = start + duration
-			consumedRune.active = false
-
-			-- Each rune consumed generates 10 (12, if in Frost Presence) runic power.
-			local runicpower = state.runicpower
-			if OvaleStance:IsStance("death_knight_frost_presence") then
-				runicpower = runicpower + 12
-			else
-				runicpower = runicpower + 10
+		end
+	end
+	if consumedRune then
+		-- Put that rune on cooldown, starting when the other rune of that slot type comes off cooldown.
+		local k = consumedRune.slotType
+		local start = atTime
+		for _, slot in ipairs(RUNE_SLOTS[consumedRune.slotType]) do
+			local rune = state.rune[slot]
+			if rune.endCooldown > start then
+				start = rune.endCooldown
 			end
-			local maxi = OvalePower.maxPower.runicpower
-			state.runicpower = (runicpower < maxi) and runicpower or maxi
+		end
+		local duration = 10 / state:GetSpellHasteMultiplier(snapshot)
+		if OvaleStance:IsStance("death_knight_blood_presence") and OvaleSpellBook:IsKnownSpell(IMPROVED_BLOOD_PRESENCE) then
+			-- Improved Blood Presence increases rune regeneration rate by 20%.
+			duration = duration / 1.2
+		end
+		consumedRune.startCooldown = start
+		consumedRune.endCooldown = start + duration
+		consumedRune.active = false
+
+		-- Each rune consumed generates 10 (12, if in Frost Presence) runic power.
+		local runicpower = state.runicpower
+		if OvaleStance:IsStance("death_knight_frost_presence") then
+			runicpower = runicpower + 12
 		else
-			Ovale:Errorf("No %s rune available to consume!", RUNE_NAME[runeType])
+			runicpower = runicpower + 10
 		end
+		local maxi = OvalePower.maxPower.runicpower
+		state.runicpower = (runicpower < maxi) and runicpower or maxi
+	else
+		Ovale:Errorf("No %s rune available to consume!", RUNE_NAME[runeType])
 	end
+end

-	statePrototype.RuneCount = function(state, name, death)
-		local count = 0
-		local startCooldown, endCooldown = math.huge, math.huge
-		local runeType = RUNE_TYPE[name]
-		if runeType ~= DEATH_RUNE then
-			if deathCondition == "any" then
-				-- Match runes of the given type or any death runes.
-				for slot, rune in ipairs(state.rune) do
-					if rune.type == runeType or rune.type == DEATH_RUNE then
-						if rune.active then
-							count = count + 1
-						elseif rune.endCooldown < endCooldown then
-							startCooldown, endCooldown = rune.startCooldown, rune.endCooldown
-						end
-					end
-				end
-			else
-				-- Match only the runes of the given type.
-				for _, slot in ipairs(RUNE_SLOTS[runeType]) do
-					local rune = state.rune[slot]
-					if not deathCondition or (deathCondition == "none" and rune.type ~= DEATH_RUNE) then
-						if rune.active then
-							count = count + 1
-						elseif rune.endCooldown < endCooldown then
-							startCooldown, endCooldown = rune.startCooldown, rune.endCooldown
-						end
+statePrototype.RuneCount = function(state, name, death)
+	local count = 0
+	local startCooldown, endCooldown = math.huge, math.huge
+	local runeType = RUNE_TYPE[name]
+	if runeType ~= DEATH_RUNE then
+		if deathCondition == "any" then
+			-- Match runes of the given type or any death runes.
+			for slot, rune in ipairs(state.rune) do
+				if rune.type == runeType or rune.type == DEATH_RUNE then
+					if rune.active then
+						count = count + 1
+					elseif rune.endCooldown < endCooldown then
+						startCooldown, endCooldown = rune.startCooldown, rune.endCooldown
 					end
 				end
 			end
 		else
-			-- Match any requested death runes.
-			for slot, rune in ipairs(state.rune) do
-				if rune.type == DEATH_RUNE then
+			-- Match only the runes of the given type.
+			for _, slot in ipairs(RUNE_SLOTS[runeType]) do
+				local rune = state.rune[slot]
+				if not deathCondition or (deathCondition == "none" and rune.type ~= DEATH_RUNE) then
 					if rune.active then
 						count = count + 1
 					elseif rune.endCooldown < endCooldown then
@@ -356,99 +348,110 @@ do
 				end
 			end
 		end
-		return count, startCooldown, endCooldown
+	else
+		-- Match any requested death runes.
+		for slot, rune in ipairs(state.rune) do
+			if rune.type == DEATH_RUNE then
+				if rune.active then
+					count = count + 1
+				elseif rune.endCooldown < endCooldown then
+					startCooldown, endCooldown = rune.startCooldown, rune.endCooldown
+				end
+			end
+		end
 	end
+	return count, startCooldown, endCooldown
+end

-	-- Returns the number of seconds before all of the required runes are available.
-	statePrototype.GetRunesCooldown = nil
-	do
-		-- If the rune is active, then return the remaining active runes count requirement.
-		-- Also return the time of the next rune becoming active.
-		local function MatchRune(rune, count, endCooldown)
-			if count > 0 then
-				count = count - 1
-				if rune.endCooldown > endCooldown then
-					endCooldown = rune.endCooldown
-				end
-			else
-				if rune.endCooldown < endCooldown then
-					endCooldown = rune.endCooldown
-				end
+-- Returns the number of seconds before all of the required runes are available.
+statePrototype.GetRunesCooldown = nil
+do
+	-- If the rune is active, then return the remaining active runes count requirement.
+	-- Also return the time of the next rune becoming active.
+	local function MatchRune(rune, count, endCooldown)
+		if count > 0 then
+			count = count - 1
+			if rune.endCooldown > endCooldown then
+				endCooldown = rune.endCooldown
+			end
+		else
+			if rune.endCooldown < endCooldown then
+				endCooldown = rune.endCooldown
 			end
-			return count, endCooldown
 		end
+		return count, endCooldown
+	end

-		-- The remaining count requirements, indexed by rune type.
-		local runeCount = {}
-		-- The latest time till a rune of that type is off cooldown, indexed by rune type.
-		local runeEndCooldown = {}
-
-		statePrototype.GetRunesCooldown = function(state, blood, unholy, frost, death, deathCondition)
-			-- Initialize static variables.
-			runeCount[BLOOD_RUNE] = blood or 0
-			runeCount[UNHOLY_RUNE] = unholy or 0
-			runeCount[FROST_RUNE] = frost or 0
-			runeCount[DEATH_RUNE] = death or 0
-			runeEndCooldown[BLOOD_RUNE] = 0
-			runeEndCooldown[UNHOLY_RUNE] = 0
-			runeEndCooldown[FROST_RUNE] = 0
-			runeEndCooldown[DEATH_RUNE] = 0
-
-			-- Use regular runes to meet the count requirements.
+	-- The remaining count requirements, indexed by rune type.
+	local runeCount = {}
+	-- The latest time till a rune of that type is off cooldown, indexed by rune type.
+	local runeEndCooldown = {}
+
+	statePrototype.GetRunesCooldown = function(state, blood, unholy, frost, death, deathCondition)
+		-- Initialize static variables.
+		runeCount[BLOOD_RUNE] = blood or 0
+		runeCount[UNHOLY_RUNE] = unholy or 0
+		runeCount[FROST_RUNE] = frost or 0
+		runeCount[DEATH_RUNE] = death or 0
+		runeEndCooldown[BLOOD_RUNE] = 0
+		runeEndCooldown[UNHOLY_RUNE] = 0
+		runeEndCooldown[FROST_RUNE] = 0
+		runeEndCooldown[DEATH_RUNE] = 0
+
+		-- Use regular runes to meet the count requirements.
+		for slot, rune in ipairs(state.rune) do
+			if rune.type ~= DEATH_RUNE then
+				local runeType = rune.type
+				local count, endCooldown = MatchRune(rune, runeCount[runeType], runeEndCooldown[runeType])
+				runeCount[runeType] = count
+				runeEndCooldown[runeType] = endCooldown
+			end
+		end
+		-- Use death runes of the matching rune type to meet the count requirements.
+		if deathCondition ~= "none" then
 			for slot, rune in ipairs(state.rune) do
-				if rune.type ~= DEATH_RUNE then
-					local runeType = rune.type
+				if rune.type == DEATH_RUNE then
+					local runeType = rune.slotType
 					local count, endCooldown = MatchRune(rune, runeCount[runeType], runeEndCooldown[runeType])
 					runeCount[runeType] = count
 					runeEndCooldown[runeType] = endCooldown
 				end
 			end
-			-- Use death runes of the matching rune type to meet the count requirements.
-			if deathCondition ~= "none" then
-				for slot, rune in ipairs(state.rune) do
-					if rune.type == DEATH_RUNE then
-						local runeType = rune.slotType
-						local count, endCooldown = MatchRune(rune, runeCount[runeType], runeEndCooldown[runeType])
-						runeCount[runeType] = count
-						runeEndCooldown[runeType] = endCooldown
-					end
-				end
-			end
+		end

-			-- Remaining rune requirements that have not yet been met.
-			local remainingCount = 0
-			for runeType = 1, 4 do
-				remainingCount = remainingCount + runeCount[runeType]
-			end
+		-- Remaining rune requirements that have not yet been met.
+		local remainingCount = 0
+		for runeType = 1, 4 do
+			remainingCount = remainingCount + runeCount[runeType]
+		end

-			-- Use death runes of any type to meet any remaining count requirements.
-			if deathCondition == "any" then
-				for _, slot in ipairs(DEATH_RUNE_PRIORITY) do
-					local rune = state.rune[slot]
-					local runeType = DEATH_RUNE
-					local count, endCooldown = MatchRune(rune, remainingCount, runeEndCooldown[runeType])
-					remainingCount = count
-					runeEndCooldown[runeType] = endCooldown
-				end
+		-- Use death runes of any type to meet any remaining count requirements.
+		if deathCondition == "any" then
+			for _, slot in ipairs(DEATH_RUNE_PRIORITY) do
+				local rune = state.rune[slot]
+				local runeType = DEATH_RUNE
+				local count, endCooldown = MatchRune(rune, remainingCount, runeEndCooldown[runeType])
+				remainingCount = count
+				runeEndCooldown[runeType] = endCooldown
 			end
+		end

-			-- This shouldn't happen because it means the rune requirements will never be met.
-			if remainingCount > 0 then
-				Ovale:Logf("Impossible rune count requirements: blood=%d, unholy=%d, frost=%d, death=%d", blood, unholy, frost, death)
-				return math.huge
-			end
+		-- This shouldn't happen because it means the rune requirements will never be met.
+		if remainingCount > 0 then
+			Ovale:Logf("Impossible rune count requirements: blood=%d, unholy=%d, frost=%d, death=%d", blood, unholy, frost, death)
+			return math.huge
+		end

-			local maxEndCooldown = 0
-			for runeType = 1, 4 do
-				if runeEndCooldown[runeType] > maxEndCooldown then
-					maxEndCooldown = runeEndCooldown[runeType]
-				end
+		local maxEndCooldown = 0
+		for runeType = 1, 4 do
+			if runeEndCooldown[runeType] > maxEndCooldown then
+				maxEndCooldown = runeEndCooldown[runeType]
 			end
-			if maxEndCooldown > 0 then
-				return maxEndCooldown - state.currentTime
-			end
-			return 0
 		end
+		if maxEndCooldown > 0 then
+			return maxEndCooldown - state.currentTime
+		end
+		return 0
 	end
 end
 --</state-methods>
diff --git a/OvaleState.lua b/OvaleState.lua
index e162cce..a074bc9 100644
--- a/OvaleState.lua
+++ b/OvaleState.lua
@@ -175,26 +175,32 @@ end
 --]]----------------------------------------------------------------------------

 --<public-static-properties>
-OvaleState.statePrototype = {
-	-- Whether the state of the simulator has been initialized.
-	isInitialized = nil,
-	-- The current time in the simulator.
-	currentTime = nil,
-	-- The spell being cast in the simulator.
-	currentSpellId = nil,
-	-- The starting cast time of the spell being cast in the simulator.
-	startCast = nil,
-	-- The ending cast time of the spell being cast in the simulator.
-	endCast = nil,
-	-- The time at which the next GCD spell can be cast in the simulator.
-	nextCast = nil,
-	-- Whether the player is channeling a spell in the simulator at the current time.
-	isChanneling = nil,
-	-- The previous spell cast in the simulator.
-	lastSpellId = nil,
-}
+OvaleState.statePrototype = {}
 --</public-static-properties>

+--<private-static-properties>
+local statePrototype = OvaleState.statePrototype
+--</private-static-properties>
+
+--<state-properties>
+-- Whether the state of the simulator has been initialized.
+statePrototype.isInitialized = nil
+-- The current time in the simulator.
+statePrototype.currentTime = nil
+-- The spell being cast in the simulator.
+statePrototype.currentSpellId = nil
+-- The starting cast time of the spell being cast in the simulator.
+statePrototype.startCast = nil
+-- The ending cast time of the spell being cast in the simulator.
+statePrototype.endCast = nil
+-- The time at which the next GCD spell can be cast in the simulator.
+statePrototype.nextCast = 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
+--</state-properties>
+
 --<public-static-methods>
 -- Initialize the state.
 function OvaleState:InitializeState(state)
diff --git a/compiler.pl b/compiler.pl
index cc1260a..07b03ce 100644
--- a/compiler.pl
+++ b/compiler.pl
@@ -17,6 +17,9 @@
 --<public-properties>
 --</public-properties>

+--<state-properties>
+--</state-properties>
+
 --<state-methods>
 --</state-methods>
 =cut
@@ -257,6 +260,15 @@ sub ParseDirectory
 				}
 			}

+			if ($content =~ m/<state-properties>(.*)<\/state-properties>/s)
+			{
+				my $p = $1;
+				while ($p =~ m/statePrototype\.(\w+)/g)
+				{
+					$smp{$1} = true;
+				}
+			}
+
 			if ($content =~ m/<state-methods>(.*)<\/state-methods>/s)
 			{
 				my $p = $1;
@@ -282,6 +294,14 @@ sub ParseDirectory
 				}
 			}

+			while ($content =~ m/\bstate\.(\w+)/g)
+			{
+				unless ($smp{$1})
+				{
+					$smp{$1} = $class;
+				}
+			}
+
 			while ($content =~ m/\bstate\:(\w+)/g)
 			{
 				unless ($smm{$1})
@@ -327,7 +347,7 @@ for my $class (keys %sm)
 	{
 		unless ($sm{$class}{$method} eq true)
 		{
-			print "public static $class:$method $sm{$class}{$method}\n";
+			print "public static $class:$method used in $sm{$class}{$method}\n";
 		}
 	}
 }
@@ -338,7 +358,7 @@ for my $class (keys %m)
 	{
 		unless ($m{$class}{$method} eq true)
 		{
-			print "public $class:$method $m{$class}{$method}\n";
+			print "public $class:$method used in $m{$class}{$method}\n";
 		}
 	}
 }
@@ -349,15 +369,23 @@ for my $class (keys %sp)
 	{
 		unless ($sp{$class}{$prop} eq true)
 		{
-			print "public static $class.$prop $sp{$class}{$prop}\n";
+			print "public static $class.$prop used in $sp{$class}{$prop}\n";
 		}
 	}
 }

+for my $prop (keys %smp)
+{
+	unless ($smp{$prop} eq true)
+	{
+		print "state machine property state.$prop used in $smp{$prop}\n";
+	}
+}
+
 for my $method (keys %smm)
 {
 	unless ($smm{$method} eq true)
 	{
-		print "state matchine state:$method $smm{$method}\n";
+		print "state machine method state:$method used in $smm{$method}\n";
 	}
 }