Quantcast

Refactor power code into a new module OvalePower.

Johnny C. Lam [09-28-13 - 12:49]
Refactor power code into a new module OvalePower.

- Split out power code from OvalePaperDoll and OvaleData into a separate
  module OvalePower.

- Enhance power code to track the maximum power of all power types.

- Add conditions Max<Power>() that return the maximum power of that power
  type, e.g., MaxRage, MaxEnergy, MaxChi, etc.  This closes ticket 291.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1035 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Ovale.toc
OvaleBestAction.lua
OvaleCondition.lua
OvaleData.lua
OvalePaperDoll.lua
OvalePower.lua
OvaleState.lua
diff --git a/Ovale.toc b/Ovale.toc
index 762d809..294f457 100644
--- a/Ovale.toc
+++ b/Ovale.toc
@@ -38,6 +38,7 @@ OvaleGUID.lua
 OvaleLatency.lua
 OvalePool.lua
 OvalePoolGC.lua
+OvalePower.lua
 OvaleQueue.lua
 OvaleRecount.lua
 OvaleSkada.lua
diff --git a/OvaleBestAction.lua b/OvaleBestAction.lua
index 80f9740..751cdc2 100644
--- a/OvaleBestAction.lua
+++ b/OvaleBestAction.lua
@@ -18,6 +18,7 @@ local OvaleCondition = Ovale.OvaleCondition
 local OvaleData = Ovale.OvaleData
 local OvaleEquipement = Ovale.OvaleEquipement
 local OvalePaperDoll = Ovale.OvalePaperDoll
+local OvalePower = Ovale.OvalePower
 local OvaleSpellBook = Ovale.OvaleSpellBook
 local OvaleStance = Ovale.OvaleStance
 local OvaleState = Ovale.OvaleState
@@ -771,8 +772,8 @@ function OvaleBestAction:GetActionInfo(element)
 			if si.combo == 0 and OvaleState.state.combo == 0 then
 				return nil
 			end
-			for k,v in pairs(OvaleData.secondaryPower) do
-				if si[v] and si[v] > OvaleState.state[v] then
+			for _, power in pairs(OvalePower.SECONDARY_POWER) do
+				if si[power] and si[power] > OvaleState.state[power] then
 					return nil
 				end
 			end
diff --git a/OvaleCondition.lua b/OvaleCondition.lua
index 68a6449..b2ed0d8 100644
--- a/OvaleCondition.lua
+++ b/OvaleCondition.lua
@@ -26,6 +26,7 @@ local OvaleFuture = Ovale.OvaleFuture
 local OvaleGUID = Ovale.OvaleGUID
 local OvaleLatency = Ovale.OvaleLatency
 local OvalePaperDoll = Ovale.OvalePaperDoll
+local OvalePower = Ovale.OvalePower
 local OvaleSpellBook = Ovale.OvaleSpellBook
 local OvaleSpellDamage = Ovale.OvaleSpellDamage
 local OvaleStance = Ovale.OvaleStance
@@ -72,6 +73,7 @@ local API_UnitLevel = UnitLevel
 local API_UnitPower = UnitPower
 local API_UnitPowerMax = UnitPowerMax
 local API_UnitStagger = UnitStagger
+local SPELL_POWER_MANA = SPELL_POWER_MANA

 -- static property for GetRunesCooldown(), indexed by rune name
 local self_runes = {}
@@ -85,9 +87,6 @@ local self_lastTTDdps = {}
 -- static property for conditions that use GetAura()
 local self_auraFound = {}

-local OVALE_POWERTYPE_ENERGY = OvaleData.power.energy.id
-local OVALE_POWERTYPE_MANA = OvaleData.power.mana.id
-
 local OVALE_RUNETYPE =
 {
 	blood = 1,
@@ -2385,7 +2384,7 @@ OvaleCondition.conditions.mana = function(condition)
 	if target == "player" then
 		return TestValue(condition[1], condition[2], OvaleState.state.mana, OvaleState.currentTime, OvaleState.powerRate.mana)
 	else
-		return Compare(API_UnitPower(target, OVALE_POWERTYPE_MANA), condition[1], condition[2])
+		return Compare(API_UnitPower(target, SPELL_POWER_MANA), condition[1], condition[2])
 	end
 end

@@ -2405,15 +2404,16 @@ end

 OvaleCondition.conditions.manapercent = function(condition)
 	local target = GetTarget(condition)
-	local powerMax = API_UnitPowerMax(target, OVALE_POWERTYPE_MANA) or 0
-	if powerMax == 0 then
-		return nil
-	end
-	if target == "player "then
-		local conversion = 100 / powerMax
-		return TestValue(condition[1], condition[2], OvaleState.state.mana * conversion, OvaleState.currentTime, OvaleState.powerRate.mana * conversion)
+	if target == "player" then
+		local powerMax = OvalePower.maxPower.mana or 0
+		if powerMax > 0 then
+			local conversion = 100 / powerMax
+			return TestValue(condition[1], condition[2], OvaleState.state.mana * conversion, OvaleState.currentTime, OvaleState.powerRate.mana * conversion)
+		end
 	else
-		return Compare(API_UnitPower(target, OVALE_POWERTYPE_MANA) * 100 / powerMax, condition[1], condition[2])
+		local powerMax = API_UnitPowerMax(target, SPELL_POWER_MANA) or 0
+		local conversion = 100 / powerMax
+		return Compare(API_UnitPower(target, SPELL_POWER_MANA) * conversion, condition[1], condition[2])
 	end
 end

@@ -2454,7 +2454,131 @@ OvaleCondition.conditions.maxhealth = function(condition)
 	return Compare(API_UnitHealthMax(target), condition[1], condition[2])
 end

---- Get the level of mana of the target when it is at full mana.
+-- Return the maximum power of the given power type on the target.
+local function MaxPowerConditionHelper(target, power)
+	local maxi
+	if target == "player" then
+		maxi = OvalePower.maxPower[power]
+	else
+		maxi = API_UnitPowerMax(target, OvalePower.POWER[power].id, OvalePower.POWER[power].segments)
+	end
+	return maxi
+end
+
+--- Get the maximum amount of alternate power of the target.
+-- Alternate power is the resource tracked by the alternate power bar in certain boss fights.
+-- @name MaxAlternatePower
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxalternatepower = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "alternate")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of burning embers of the target.
+-- @name MaxBurningEmbers
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxburningembers = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "burningembers")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of Chi of the target.
+-- @name MaxChi
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxchi = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "chi")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of Demonic Fury of the target.
+-- @name MaxDemonicFury
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxdemonicfury = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "demonicfury")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of energy of the target.
+-- @name MaxEnergy
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxenergy = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "energy")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of focus of the target.
+-- @name MaxFocus
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxfocus = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "maxfocus")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of Holy Power of the target.
+-- @name MaxHolyPower
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxholypower = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "holy")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of mana of the target.
 -- @name MaxMana
 -- @paramsig number or boolean
 -- @param operator Optional. Comparison operator: equal, less, more.
@@ -2462,13 +2586,78 @@ end
 -- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
 --     Defaults to target=player.
 --     Valid values: player, target, focus, pet.
--- @return The maximum mana.
+-- @return The maximum value.
 -- @return A boolean value for the result of the comparison.
 -- @usage
 -- if {MaxMana() - Mana()} > 12500 Item(mana_gem)

 OvaleCondition.conditions.maxmana = function(condition)
-	return Compare(API_UnitPowerMax(GetTarget(condition), OVALE_POWERTYPE_MANA), condition[1], condition[2])
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "mana")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of rage of the target.
+-- @name MaxRage
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxrage = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "rage")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of Runic Power of the target.
+-- @name MaxRunicPower
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxrunicpower = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "runicpower")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of Shadow Orbs of the target.
+-- @name MaxShadowOrbs
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxshadoworbs = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "shadoworbs")
+	return Compare(maxi, condition[1], condition[2])
+end
+
+--- Get the maximum amount of Soul Shards of the target.
+-- @name MaxSoulShards
+-- @paramsig number or boolean
+-- @param operator Optional. Comparison operator: equal, less, more.
+-- @param number Optional. The number to compare against.
+-- @param target Optional. Sets the target to check. The target may also be given as a prefix to the condition.
+--     Defaults to target=player.
+--     Valid values: player, target, focus, pet.
+-- @return The maximum value.
+-- @return A boolean value for the result of the comparison.
+
+OvaleCondition.conditions.maxsoulshards = function(condition)
+	local maxi = MaxPowerConditionHelper(GetTarget(condition), "shards")
+	return Compare(maxi, condition[1], condition[2])
 end

 --- Get the current melee critical strike chance of the player.
@@ -3382,7 +3571,7 @@ OvaleCondition.conditions.timetolifepercent = OvaleCondition.conditions.timetohe

 OvaleCondition.conditions.timetopowerfor = function(condition)
 	local cost, _, powerType = select(4, API_GetSpellInfo(condition[1]))
-	local power = OvaleData.powerType[powerType]
+	local power = OvalePower.POWER_TYPE[powerType]
 	local currentPower = OvaleState.state[power]
 	local powerRate = OvaleState.powerRate[power]
 	cost = cost or 0
@@ -3412,7 +3601,7 @@ OvaleCondition.spellbookConditions.timetopowerfor = true
 -- if TimeToMaxEnergy() < 1.2 Spell(sinister_strike)

 OvaleCondition.conditions.timetomaxenergy = function(condition)
-	local maxEnergy = API_UnitPowerMax("player", OVALE_POWERTYPE_ENERGY) or 0
+	local maxEnergy = OvalePower.maxPower.energy or 0
 	local t = OvaleState.currentTime + (maxEnergy - OvaleState.state.energy) / OvaleState.powerRate.energy
 	return 0, nil, 0, t, -1
 end
diff --git a/OvaleData.lua b/OvaleData.lua
index 4280f5e..054aca1 100644
--- a/OvaleData.lua
+++ b/OvaleData.lua
@@ -13,22 +13,7 @@ local OvaleData = {}
 Ovale.OvaleData = OvaleData

 --<private-static-properties>
-local floor = math.floor
-local pairs = pairs
 local API_GetSpellCooldown = GetSpellCooldown
-local SPELL_POWER_ALTERNATE_POWER = SPELL_POWER_ALTERNATE_POWER
-local SPELL_POWER_BURNING_EMBERS = SPELL_POWER_BURNING_EMBERS
-local SPELL_POWER_CHI = SPELL_POWER_CHI
-local SPELL_POWER_DEMONIC_FURY = SPELL_POWER_DEMONIC_FURY
-local SPELL_POWER_ECLIPSE = SPELL_POWER_ECLIPSE
-local SPELL_POWER_ENERGY = SPELL_POWER_ENERGY
-local SPELL_POWER_FOCUS = SPELL_POWER_FOCUS
-local SPELL_POWER_HOLY_POWER = SPELL_POWER_HOLY_POWER
-local SPELL_POWER_MANA = SPELL_POWER_MANA
-local SPELL_POWER_RAGE = SPELL_POWER_RAGE
-local SPELL_POWER_RUNIC_POWER = SPELL_POWER_RUNIC_POWER
-local SPELL_POWER_SHADOW_ORBS = SPELL_POWER_SHADOW_ORBS
-local SPELL_POWER_SOUL_SHARDS = SPELL_POWER_SOUL_SHARDS

 -- Auras that are refreshed by spells that don't trigger a new snapshot.
 self_buffNoSnapshotSpellList =
@@ -63,30 +48,6 @@ OvaleData.spellInfo = {}
 --spells that count for scoring
 OvaleData.scoreSpell = {}

-OvaleData.power =
-{
-	mana = { id = SPELL_POWER_MANA, mini = 0 },
-	rage = { id = SPELL_POWER_RAGE, mini = 0, maxi = 100 },
-	focus = { id = SPELL_POWER_FOCUS, mini = 0, maxi = 100 },
-	energy = { id = SPELL_POWER_ENERGY, mini = 0, maxi = 100 },
-	runicpower = { id = SPELL_POWER_RUNIC_POWER, mini = 0, maxi = 100 },
-	shards = { id = SPELL_POWER_SOUL_SHARDS, mini = 0 },
-	eclipse = { id = SPELL_POWER_ECLIPSE, mini = -100, maxi = 100 },
-	holy = { id = SPELL_POWER_HOLY_POWER, mini = 0, maxi = 5 },
-	alternate = { id = SPELL_POWER_ALTERNATE_POWER, mini = 0 },
-	chi = { id = SPELL_POWER_CHI, mini = 0, maxi = 4 },
-	shadoworbs = { id = SPELL_POWER_SHADOW_ORBS, mini = 0, maxi = 3 },
-	burningembers = { id = SPELL_POWER_BURNING_EMBERS, mini = 0, segments = true },
-	demonicfury = { id = SPELL_POWER_DEMONIC_FURY, mini = 0 }
-}
-OvaleData.secondaryPower = {"rage", "focus", "shards", "holy", "chi", "shadoworbs", "burningembers", "demonicfury"}
-OvaleData.powerType = {}
-do
-	for k,v in pairs(OvaleData.power) do
-		OvaleData.powerType[v.id] = k
-	end
-end
-
 OvaleData.buffSpellList =
 {
 	-- Debuffs
diff --git a/OvalePaperDoll.lua b/OvalePaperDoll.lua
index d5c4762..65c13ce 100644
--- a/OvalePaperDoll.lua
+++ b/OvalePaperDoll.lua
@@ -24,7 +24,6 @@ local tonumber = tonumber
 local API_GetCritChance = GetCritChance
 local API_GetMasteryEffect = GetMasteryEffect
 local API_GetMeleeHaste = GetMeleeHaste
-local API_GetPowerRegen = GetPowerRegen
 local API_GetRangedCritChance = GetRangedCritChance
 local API_GetRangedHaste = GetRangedHaste
 local API_GetSpecialization = GetSpecialization
@@ -37,7 +36,6 @@ local API_UnitAttackSpeed = UnitAttackSpeed
 local API_UnitClass = UnitClass
 local API_UnitDamage = UnitDamage
 local API_UnitLevel = UnitLevel
-local API_UnitPowerType = UnitPowerType
 local API_UnitRangedAttackPower = UnitRangedAttackPower
 local API_UnitSpellHaste = UnitSpellHaste
 local API_UnitStat = UnitStat
@@ -112,11 +110,6 @@ OvalePaperDoll.class = select(2, API_UnitClass("player"))
 OvalePaperDoll.level = API_UnitLevel("player")
 -- Player's current specialization.
 OvalePaperDoll.specialization = nil
--- Player's current power type (see API_UnitPowerType for values).
-OvalePaperDoll.powerType = nil
--- Player's current power regeneration rate.
-OvalePaperDoll.activeRegen = 0
-OvalePaperDoll.inactiveRegen = 0
 -- Most recent snapshot.
 OvalePaperDoll.stat = nil
 --</public-static-properties>
@@ -166,14 +159,13 @@ function OvalePaperDoll:OnEnable()
 	self:RegisterEvent("SPELL_POWER_CHANGED")
 	self:RegisterEvent("UNIT_ATTACK_POWER")
 	self:RegisterEvent("UNIT_DAMAGE", "UpdateDamage")
-	self:RegisterEvent("UNIT_DISPLAYPOWER")
 	self:RegisterEvent("UNIT_LEVEL")
 	self:RegisterEvent("UNIT_RANGEDDAMAGE")
 	self:RegisterEvent("UNIT_RANGED_ATTACK_POWER")
 	self:RegisterEvent("UNIT_SPELL_HASTE")
 	self:RegisterEvent("UNIT_STATS")
 	self:RegisterMessage("Ovale_EquipmentChanged", "UpdateDamage")
-	self:RegisterMessage("Ovale_StanceChanged")
+	self:RegisterMessage("Ovale_StanceChanged", "UpdateDamage")

 	local now = API_GetTime()
 	self.stat = GetSnapshot(now)
@@ -192,7 +184,6 @@ function OvalePaperDoll:OnDisable()
 	self:UnregisterEvent("SPELL_POWER_CHANGED")
 	self:UnregisterEvent("UNIT_ATTACK_POWER")
 	self:UnregisterEvent("UNIT_DAMAGE")
-	self:UnregisterEvent("UNIT_DISPLAYPOWER")
 	self:UnregisterEvent("UNIT_LEVEL")
 	self:UnregisterEvent("UNIT_RANGEDDAMAGE")
 	self:UnregisterEvent("UNIT_RANGED_ATTACK_POWER")
@@ -263,13 +254,6 @@ function OvalePaperDoll:UNIT_ATTACK_POWER(event, unitId)
 	end
 end

-function OvalePaperDoll:UNIT_DISPLAYPOWER(event, unitId)
-	if unitId == "player" then
-		self.powerType = API_UnitPowerType(unitId)
-		Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: power type = %d", event, self.powerType)
-	end
-end
-
 function OvalePaperDoll:UNIT_LEVEL(event, unitId)
 	if unitId == "player" then
 		self.level = API_UnitLevel(unitId)
@@ -308,7 +292,6 @@ function OvalePaperDoll:UNIT_SPELL_HASTE(event, unitId)
 		Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, "    %s = %f%%", OVALE_SNAPSHOT_STATS.meleeHaste, self.stat.meleeHaste)
 		Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, "    %s = %f%%", OVALE_SNAPSHOT_STATS.spellHaste, self.stat.spellHaste)
 		self:UpdateDamage(event)
-		self:UpdatePowerRegen(event)
 	end
 end

@@ -395,7 +378,6 @@ function OvalePaperDoll:UpdateStats(event)
 	self:PLAYER_DAMAGE_DONE_MODS(event, "player")
 	self:SPELL_POWER_CHANGED(event)
 	self:UNIT_ATTACK_POWER(event, "player")
-	self:UNIT_DISPLAYPOWER(event, "player")
 	self:UNIT_RANGEDDAMAGE(event, "player")
 	self:UNIT_RANGED_ATTACK_POWER(event, "player")
 	self:UNIT_SPELL_HASTE(event, "player")
@@ -403,18 +385,6 @@ function OvalePaperDoll:UpdateStats(event)
 	self:UpdateDamage(event)
 end

-function OvalePaperDoll:UpdatePowerRegen(event)
-	self.inactiveRegen, self.activeRegen = API_GetPowerRegen()
-	Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s", event)
-	Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, "    %s = %f", "active regen", self.activeRegen)
-	Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, "    %s = %f", "inactive regen", self.inactiveRegen)
-end
-
-function OvalePaperDoll:Ovale_StanceChanged(event)
-	self:UpdateDamage(event)
-	self:UpdatePowerRegen(event)
-end
-
 function OvalePaperDoll:GetMasteryMultiplier()
 	return 1 + self.stat.masteryEffect / 100
 end
@@ -468,9 +438,6 @@ function OvalePaperDoll:Debug(stat)
 	Ovale:FormatPrint("Class: %s", self.class)
 	Ovale:FormatPrint("Level: %d", self.level)
 	Ovale:FormatPrint("Specialization: %s", self.specialization)
-	Ovale:FormatPrint("Power type: %d", self.powerType)
-	Ovale:FormatPrint("Active regen: %f", self.activeRegen)
-	Ovale:FormatPrint("Inactive regen: %f", self.inactiveRegen)
 	Ovale:FormatPrint("Snapshot time: %f", stat.snapshotTime)
 	Ovale:FormatPrint("%s: %d", OVALE_SNAPSHOT_STATS.agility, stat.agility)
 	Ovale:FormatPrint("%s: %d", OVALE_SNAPSHOT_STATS.intellect, stat.intellect)
diff --git a/OvalePower.lua b/OvalePower.lua
new file mode 100644
index 0000000..ac6c85f
--- /dev/null
+++ b/OvalePower.lua
@@ -0,0 +1,164 @@
+--[[--------------------------------------------------------------------
+    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 OvalePower = Ovale:NewModule("OvalePower", "AceEvent-3.0")
+Ovale.OvalePower = OvalePower
+
+--<private-static-properties>
+local pairs = pairs
+local API_GetPowerRegen = GetPowerRegen
+local API_UnitPowerMax = UnitPowerMax
+local API_UnitPowerType = UnitPowerType
+local SPELL_POWER_ALTERNATE_POWER = SPELL_POWER_ALTERNATE_POWER
+local SPELL_POWER_BURNING_EMBERS = SPELL_POWER_BURNING_EMBERS
+local SPELL_POWER_CHI = SPELL_POWER_CHI
+local SPELL_POWER_DEMONIC_FURY = SPELL_POWER_DEMONIC_FURY
+local SPELL_POWER_ECLIPSE = SPELL_POWER_ECLIPSE
+local SPELL_POWER_ENERGY = SPELL_POWER_ENERGY
+local SPELL_POWER_FOCUS = SPELL_POWER_FOCUS
+local SPELL_POWER_HOLY_POWER = SPELL_POWER_HOLY_POWER
+local SPELL_POWER_MANA = SPELL_POWER_MANA
+local SPELL_POWER_RAGE = SPELL_POWER_RAGE
+local SPELL_POWER_RUNIC_POWER = SPELL_POWER_RUNIC_POWER
+local SPELL_POWER_SHADOW_ORBS = SPELL_POWER_SHADOW_ORBS
+local SPELL_POWER_SOUL_SHARDS = SPELL_POWER_SOUL_SHARDS
+--</private-static-properties>
+
+--<public-static-properties>
+-- Player's current power type (key for POWER table).
+OvalePower.power = nil
+-- Player's current max power; maxPower[power] = number.
+OvalePower.maxPower = {}
+-- Player's current power regeneration rate for the active power type.
+OvalePower.activeRegen = 0
+OvalePower.inactiveRegen = 0
+
+OvalePower.POWER =
+{
+	alternate = { id = SPELL_POWER_ALTERNATE_POWER, token = "ALTERNATE_RESOURCE_TEXT", mini = 0 },
+	burningembers = { id = SPELL_POWER_BURNING_EMBERS, token = "BURNING_EMBERS", mini = 0, segments = true },
+	chi = { id = SPELL_POWER_CHI, token = "CHI", mini = 0 },
+	demonicfury = { id = SPELL_POWER_DEMONIC_FURY, token = "DEMONIC_FURY", mini = 0 },
+	eclipse = { id = SPELL_POWER_ECLIPSE, token = "ECLIPSE", mini = -100, maxi = 100 },
+	energy = { id = SPELL_POWER_ENERGY, token = "ENERGY", mini = 0 },
+	focus = { id = SPELL_POWER_FOCUS, token = "FOCUS", mini = 0 },
+	holy = { id = SPELL_POWER_HOLY_POWER, token = "HOLY_POWER", mini = 0 },
+	mana = { id = SPELL_POWER_MANA, token = "MANA", mini = 0 },
+	rage = { id = SPELL_POWER_RAGE, token = "RAGE", mini = 0 },
+	runicpower = { id = SPELL_POWER_RUNIC_POWER, token = "RUNIC_POWER", mini = 0 },
+	shadoworbs = { id = SPELL_POWER_SHADOW_ORBS, token = "SHADOW_ORBS", mini = 0 },
+	shards = { id = SPELL_POWER_SOUL_SHARDS, token = "SOUL_SHARDS_POWER", mini = 0 },
+}
+OvalePower.SECONDARY_POWER = {
+	"burningembers",
+	"chi",
+	"demonicfury",
+	"focus",
+	"holy",
+	"rage",
+	"shadoworbs",
+	"shards",
+}
+OvalePower.POWER_TYPE = {}
+do
+	for power, v in pairs(OvalePower.POWER) do
+		OvalePower.POWER_TYPE[v.id] = power
+		OvalePower.POWER_TYPE[v.token] = power
+	end
+end
+--</public-static-properties>
+
+--<public-static-methods>
+function OvalePower:OnEnable()
+	self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED", "EventHandler")
+	self:RegisterEvent("PLAYER_ALIVE", "EventHandler")
+	self:RegisterEvent("PLAYER_ENTERING_WORLD", "EventHandler")
+	self:RegisterEvent("PLAYER_LEVEL_UP", "EventHandler")
+	self:RegisterEvent("PLAYER_TALENT_UPDATE", "EventHandler")
+	self:RegisterEvent("UNIT_DISPLAYPOWER")
+	self:RegisterEvent("UNIT_LEVEL")
+	self:RegisterEvent("UNIT_MAXPOWER")
+	self:RegisterEvent("UNIT_RANGEDDAMAGE", "PowerRegenEventHandler")
+	self:RegisterEvent("UNIT_SPELL_HASTE", "PowerRegenEventHandler")
+	self:RegisterMessage("Ovale_StanceChanged", "EventHandler")
+end
+
+function OvalePower:OnDisable()
+	self:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
+	self:UnregisterEvent("PLAYER_ALIVE")
+	self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+	self:UnregisterEvent("PLAYER_LEVEL_UP")
+	self:UnregisterEvent("PLAYER_TALENT_UPDATE")
+	self:UnregisterEvent("UNIT_DISPLAYPOWER")
+	self:UnregisterEvent("UNIT_LEVEL")
+	self:UnregisterEvent("UNIT_MAXPOWER")
+	self:UnregisterEvent("UNIT_RANGEDDAMAGE")
+	self:UnregisterEvent("UNIT_SPELL_HASTE")
+	self:UnregisterMessage("Ovale_StanceChanged")
+end
+
+function OvalePower:EventHandler(event)
+	self:MaxPowerEventHandler(event)
+	self:UpdatePowerRegen()
+end
+
+function OvalePower:MaxPowerEventHandler(event)
+	self:UNIT_DISPLAYPOWER(event, "player")
+	for _, powerInfo in pairs(self.POWER) do
+		self:UNIT_MAXPOWER(event, "player", powerInfo.token)
+	end
+end
+
+function OvalePower:PowerRegenEventHandler(event, unitId)
+	if unitId == "player" then
+		self:UpdatePowerRegen()
+	end
+end
+
+function OvalePower:UNIT_DISPLAYPOWER(event, unitId)
+	if unitId == "player" then
+		local currentType, currentToken = API_UnitPowerType(unitId)
+		self.power = self.POWER_TYPE[currentType]
+		self:UNIT_MAXPOWER(event, unitId, currentToken)
+	end
+end
+
+function OvalePower:UNIT_LEVEL(event, unitId)
+	if unitId == "player" then
+		self:EventHandler(event)
+	end
+end
+
+function OvalePower:UNIT_MAXPOWER(event, unitId, powerToken)
+	if unitId == "player" then
+		local power = self.POWER_TYPE[powerToken]
+		if power then
+			local powerInfo = self.POWER[power]
+			if powerInfo then
+				self.maxPower[power] = API_UnitPowerMax(unitId, powerInfo.id, powerInfo.segments)
+			end
+		end
+	end
+end
+
+function OvalePower:UpdatePowerRegen()
+	self.inactiveRegen, self.activeRegen = API_GetPowerRegen()
+end
+
+function OvalePower:Debug()
+	Ovale:FormatPrint("Power type: %s", self.power)
+	for k, v in pairs(self.maxPower) do
+		Ovale:FormatPrint("Max power (%s): %d", k, v)
+	end
+	Ovale:FormatPrint("Active regen: %f", self.activeRegen)
+	Ovale:FormatPrint("Inactive regen: %f", self.inactiveRegen)
+end
+--</public-static-methods>
\ No newline at end of file
diff --git a/OvaleState.lua b/OvaleState.lua
index 483815a..afc25c9 100644
--- a/OvaleState.lua
+++ b/OvaleState.lua
@@ -22,6 +22,7 @@ local OvaleEquipement = Ovale.OvaleEquipement
 local OvaleFuture = Ovale.OvaleFuture
 local OvaleGUID = Ovale.OvaleGUID
 local OvalePaperDoll = Ovale.OvalePaperDoll
+local OvalePower = Ovale.OvalePower
 local OvaleSpellBook = Ovale.OvaleSpellBook
 local OvaleStance = Ovale.OvaleStance

@@ -96,8 +97,8 @@ function OvaleState:StartNewFrame()
 end

 function OvaleState:UpdatePowerRates()
-	for k,v in pairs(OvaleData.power) do
-		self.powerRate[k] = 0
+	for power in pairs(OvalePower.POWER) do
+		self.powerRate[power] = 0
 	end

 	-- Energy regeneration for druids and monks out of DPS stance.
@@ -129,9 +130,9 @@ function OvaleState:UpdatePowerRates()

 	-- Power regeneration for current power type.
 	if Ovale.enCombat then
-		self.powerRate[OvaleData.powerType[OvalePaperDoll.powerType]] = OvalePaperDoll.activeRegen
+		self.powerRate[OvalePower.power] = OvalePower.activeRegen
 	else
-		self.powerRate[OvaleData.powerType[OvalePaperDoll.powerType]] = OvalePaperDoll.inactiveRegen
+		self.powerRate[OvalePower.power] = OvalePower.inactiveRegen
 	end
 end

@@ -143,8 +144,8 @@ function OvaleState:Reset()
 	self.currentSpellId = nil
 	self.attenteFinCast = self.maintenant
 	self.state.combo = OvaleComboPoints.combo
-	for k,v in pairs(OvaleData.power) do
-		self.state[k] = API_UnitPower("player", v.id, v.segments)
+	for power, v in pairs(OvalePower.POWER) do
+		self.state[power] = API_UnitPower("player", v.id, v.segments)
 	end

 	self:UpdatePowerRates()
@@ -231,37 +232,33 @@ function OvaleState:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targ
 	if endCast >= self.maintenant then
 		--Mana
 		local _, _, _, cost, _, powerType = API_GetSpellInfo(spellId)
-		local power = OvaleData.powerType[powerType]
+		local power = OvalePower.POWER_TYPE[powerType]
 		if cost and power and (not si or not si[power]) then
 			self.state[power] = self.state[power] - cost
 		end

 		if si then
 			-- Update power state, except for eclipse, combo, and runes.
-			for k,v in pairs(OvaleData.power) do
-				if si[k] and k ~= "eclipse" then
-					if si[k] == 0 then
-						self.state[k] = 0
+			for power, v in pairs(OvalePower.POWER) do
+				if si[power] and power ~= "eclipse" then
+					if si[power] == 0 then
+						self.state[power] = 0
 					else
-						self.state[k] = self.state[k] - si[k]
+						self.state[power] = self.state[power] - si[power]
 					end
 					-- Add extra resource generated by presence of a buff.
-					local buffParam = "buff_" .. tostring(k)
+					local buffParam = "buff_" .. tostring(power)
 					local buffAmoumtParam = buffParam .. "_amount"
-					if si[k] < 0 and si[buffParam] and self:GetAura("player", si[buffParam], nil, true) then
+					if si[power] < 0 and si[buffParam] and self:GetAura("player", si[buffParam], nil, true) then
 						local buffAmount = si[buffAmountParam] or 1
-						self.state[k] = self.state[k] + buffAmount
+						self.state[power] = self.state[power] + buffAmount
 					end
-					if self.state[k] < v.mini then
-						self.state[k] = v.mini
+					if self.state[power] < v.mini then
+						self.state[power] = v.mini
 					end
-					if v.maxi and self.state[k] > v.maxi then
-						self.state[k] = v.maxi
-					else
-						local maxi = API_UnitPowerMax("player", v.id, v.segments)
-						if maxi and self.state[k] > maxi then
-							self.state[k] = maxi
-						end
+					local maxi = v.maxi or OvalePower.maxPower[power]
+					if maxi and self.state[power] > maxi then
+						self.state[power] = maxi
 					end
 				end
 			end
@@ -835,8 +832,8 @@ end

 -- Print out the levels of each power type in the current state.
 function OvaleState:DebugPower()
-	for powerType in pairs(OvaleData.power) do
-		Ovale:FormatPrint("%s = %d", powerType, self.state[powerType])
+	for power in pairs(OvalePower.POWER) do
+		Ovale:FormatPrint("%s = %d", power, self.state[power])
 	end
 end
 --</public-static-methods>