Quantcast

Implement OvalePaperDoll class that tracks the in-game paper doll stats.

Johnny C. Lam [02-22-13 - 09:21]
Implement OvalePaperDoll class that tracks the in-game paper doll stats.

OvalePaperDoll caches the current player stats when it receives events
noting that the stats have changed.  Use OvalePaperDoll properties instead
of Blizzard API when referencing player stats.  This avoids a lot of
unnecessary Blizzard API calls.

The current stats cached by OvalePaperDoll are:

   * Primary stats: Agility, Intellect, Stamina, Strength, Spirit
   * Attack Power, Ranged Attack Power
   * Spellpower: bonus damage, bonus healing
   * Melee haste percent increase
   * Spell haste percent increase
   * Mastery effect percent increase

Remove haste-tracking from OvaleAura as it is now maintained in
OvalePaperDoll.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@699 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Ovale.toc
OvaleAura.lua
OvaleBestAction.lua
OvaleCondition.lua
OvaleData.lua
OvaleFuture.lua
OvalePaperDoll.lua
OvaleState.lua
diff --git a/Ovale.toc b/Ovale.toc
index 6e7f593..d9bb70f 100644
--- a/Ovale.toc
+++ b/Ovale.toc
@@ -39,6 +39,7 @@ OvaleGUID.lua
 OvaleIcone.lua
 OvaleIcone.xml
 OvaleOptions.lua
+OvalePaperDoll.lua
 OvaleRecount.lua
 OvaleSkada.lua
 OvaleSpellDamage.lua
diff --git a/OvaleAura.lua b/OvaleAura.lua
index baea4c3..e241bee 100644
--- a/OvaleAura.lua
+++ b/OvaleAura.lua
@@ -15,8 +15,6 @@ OvaleAura = LibStub("AceAddon-3.0"):NewAddon("OvaleAura", "AceEvent-3.0")
 --<public-static-properties>
 OvaleAura.aura = {}
 OvaleAura.serial = 0
-OvaleAura.spellHaste = 1
-OvaleAura.meleeHaste = 1
 OvaleAura.playerGUID = nil
 --</public-static-properties>

@@ -58,7 +56,7 @@ function OvaleAura:COMBAT_LOG_EVENT_UNFILTERED(event, ...)
 			if sourceGUID == self.playerGUID and (event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" or event == "SPELL_AURA_APPLIED_DOSE") then
 				local aura = self:GetAuraByGUID(destGUID, spellId, true)
 				if aura then
-					aura.spellHaste = self.spellHaste
+					aura.spellHaste = OvalePaperDoll.spellHaste
 				end
 			end
 		end
@@ -132,12 +130,6 @@ end
 function OvaleAura:UpdateAuras(unitId, unitGUID)
 	self.serial = self.serial + 1

-	local hateBase
-	local hateCommune
-	local hateSorts
-	local hateCaC
-	local hateHero
-	local hateClasse
 	local damageMultiplier

 	if not unitId then
@@ -154,12 +146,6 @@ function OvaleAura:UpdateAuras(unitId, unitGUID)
 	end

 	if unitId == "player" then
-		hateBase = GetCombatRatingBonus(18)
-		hateCommune = 0
-		hateSorts = 0
-		hateCaC = 0
-		hateHero = 0
-		hateClasse = 0
 		damageMultiplier = 1
 	end

@@ -193,15 +179,6 @@ function OvaleAura:UpdateAuras(unitId, unitGUID)
 			end

 			if unitId == "player" then
-				if OvaleData.buffSpellList.spell_haste[spellId] then
-					hateSorts = 5
-				elseif OvaleData.buffSpellList.melee_haste[spellId] then
-					hateCaC = 10
-				elseif OvaleData.buffSpellList.burst_haste[spellId] then
-					hateHero = 30
-				elseif OvaleData.selfHasteBuff[spellId] then
-					hateClasse = OvaleData.selfHasteBuff[spellId]
-				end
 				if OvaleData.selfDamageBuff[spellId] then
 					damageMultiplier = damageMultiplier * OvaleData.selfDamageBuff[spellId]
 				end
@@ -230,10 +207,7 @@ function OvaleAura:UpdateAuras(unitId, unitGUID)
 		self.aura[unitGUID] = nil
 	end

-	--Update player haste
 	if unitId == "player" then
-		self.spellHaste = (1 + hateBase/100) * (1 + hateCommune/100) * (1 + hateSorts/100) * (1 + hateHero/100) * (1 + hateClasse/100)
-		self.meleeHaste = (1 + hateBase/100) * (1 + hateCommune/100) * (1 + hateCaC/100) * (1 + hateHero/100) * (1 + hateClasse/100)
 		baseDamageMultiplier = damageMultiplier
 	end

diff --git a/OvaleBestAction.lua b/OvaleBestAction.lua
index 45e6f71..7dc55f1 100644
--- a/OvaleBestAction.lua
+++ b/OvaleBestAction.lua
@@ -272,7 +272,7 @@ function OvaleBestAction:Compute(element)
 					else
 						--TODO: pas exact, parce que si ce sort est report de par exemple 0,5s par un debuff
 						--a tombera entre deux ticks
-						local ticks = floor(OvaleAura.spellHaste * OvaleData.spellInfo[OvaleState.currentSpellId].canStopChannelling + 0.5)
+						local ticks = floor(OvalePaperDoll.spellHaste * OvaleData.spellInfo[OvaleState.currentSpellId].canStopChannelling + 0.5)
 						local tickLength = (OvaleState.attenteFinCast - OvaleState.startCast) / ticks
 						local tickTime = OvaleState.startCast + tickLength
 						if (Ovale.trace) then
diff --git a/OvaleCondition.lua b/OvaleCondition.lua
index 971cd95..8ad6e00 100644
--- a/OvaleCondition.lua
+++ b/OvaleCondition.lua
@@ -46,11 +46,11 @@ local lastSPD = {}
 local floor, pairs, select, strfind, tostring = math.floor, pairs, select, string.find, tostring
 local GetGlyphSocketInfo, GetInventoryItemID, GetInventoryItemLink = GetGlyphSocketInfo, GetInventoryItemID, GetInventoryItemLink
 local GetInventorySlotInfo, GetItemCooldown, GetItemCount = GetInventorySlotInfo, GetItemCooldown, GetItemCount
-local GetItemInfo, GetMasteryEffect, GetRune = GetItemInfo, GetMasteryEffect, GetRune
-local GetRuneCount, GetSpellBonusDamage, GetSpellCharges = GetRuneCount, GetSpellBonusDamage, GetSpellCharges
+local GetItemInfo, GetRune = GetItemInfo, GetRune
+local GetRuneCount, GetSpellCharges = GetRuneCount, GetSpellCharges
 local GetSpellInfo, GetTotemInfo, GetTrackingInfo = GetSpellInfo, GetTotemInfo, GetTrackingInfo
 local GetUnitSpeed, HasFullControl, IsSpellInRange = GetUnitSpeed, HasFullControl, IsSpellInRange
-local IsStealthed, IsUsableSpell, UnitAttackPower = IsStealthed, IsUsableSpell, UnitAttackPower
+local IsStealthed, IsUsableSpell = IsStealthed, IsUsableSpell
 local UnitCastingInfo, UnitChannelInfo, UnitClass = UnitCastingInfo, UnitChannelInfo, UnitClass
 local UnitClassification, UnitCreatureFamily, UnitCreatureType = UnitClassification, UnitCreatureFamily, UnitCreatureType
 local UnitDebuff, UnitDetailedThreatSituation, UnitExists = UnitDebuff, UnitDetailedThreatSituation, UnitExists
@@ -83,9 +83,9 @@ local function avecHate(temps, hate)
 	if (not hate) then
 		return temps
 	elseif (hate == "spell") then
-		return temps/OvaleAura.spellHaste
+		return temps/(1 + OvalePaperDoll.spellHaste)
 	elseif (hate == "melee") then
-		return temps/OvaleAura.meleeHaste
+		return temps/(1 + OvalePaperDoll.meleeHaste)
 	else
 		return temps
 	end
@@ -478,8 +478,7 @@ end
 -- if AttackPower(more 10000) Spell(rake)

 OvaleCondition.conditions.attackpower = function(condition)
-	local base, posBuff, negBuff = UnitAttackPower("player")
-	return compare(base + posBuff + negBuff, condition[1], condition[2])
+	return compare(OvalePaperDoll.attackPower, condition[1], condition[2])
 end

 --- Get the total count of the given aura across all targets.
@@ -1009,7 +1008,7 @@ end

 OvaleCondition.conditions.damage = function(condition)
 	local spellId = condition[1]
-	local ret = OvaleData:GetDamage(spellId, UnitAttackPower("player"), GetSpellBonusDamage(2), OvaleState.state.combo)
+	local ret = OvaleData:GetDamage(spellId, OvalePaperDoll.attackPower, OvalePaperDoll.spellBonusDamage, OvaleState.state.combo)
 	return 0, nil, ret * OvaleAura:GetDamageMultiplier(spellId), 0, 0
 end

@@ -1874,11 +1873,7 @@ end
 --     Spell(rake)

 OvaleCondition.conditions.mastery = function(condition)
-	local mastery = 0
-	if OvaleData.level >= 80 then
-		mastery = GetMasteryEffect()
-	end
-	return compare(mastery, condition[1], condition[2])
+	return compare(OvalePaperDoll.masteryEffect, condition[1], condition[2])
 end

 --- Get the amount of health points of the target when it is at full health.
@@ -2347,7 +2342,7 @@ end
 --     Spell(living_bomb)

 OvaleCondition.conditions.spellpower = function(condition)
-	return compare(GetSpellBonusDamage(2), condition[1], condition[2])
+	return compare(OvalePaperDoll.spellBonusDamage, condition[1], condition[2])
 end

 --- Test if the player is in a given stance.
@@ -2472,7 +2467,7 @@ OvaleCondition.auraConditions.tickvalue = true
 OvaleCondition.conditions.ticks = function(condition)
 	-- TODO: extend to allow checking an existing DoT (how to get DoT duration?)
 	local spellId = condition[1]
-	local duration, tickLength = OvaleData:GetDuration(spellId, OvaleAura.spellHaste, OvaleState.state.combo, OvaleState.state.holy)
+	local duration, tickLength = OvaleData:GetDuration(spellId, OvalePaperDoll.spellHaste, OvaleState.state.combo, OvaleState.state.holy)
 	if tickLength then
 		local numTicks = floor(duration / tickLength + 0.5)
 		return compare(numTicks, condition[2], condition[3])
@@ -2538,7 +2533,7 @@ OvaleCondition.auraConditions.ticksremain = true
 OvaleCondition.conditions.ticktime = function(condition)
 	local start, ending, _, spellHaste = GetTargetAura(condition, getTarget(condition.target))
 	if not start or not ending or start > OvaleState.currentTime or ending < OvaleState.currentTime then
-		spellHaste = OvaleAura.spellHaste
+		spellHaste = OvalePaperDoll.spellHaste
 	end
 	local tickLength = OvaleData:GetTickLength(condition[1], spellHaste)
 	if tickLength then
diff --git a/OvaleData.lua b/OvaleData.lua
index 9c5cbb3..12c5098 100644
--- a/OvaleData.lua
+++ b/OvaleData.lua
@@ -503,7 +503,7 @@ function OvaleData:GetGCD(spellId)
 			if not cd then
 				cd = 1.5
 			end
-			cd = cd / OvaleAura.spellHaste
+			cd = cd / (1 + OvalePaperDoll.spellHaste)
 			if (cd<1) then
 				cd = 1
 			end
@@ -518,7 +518,7 @@ function OvaleData:GetGCD(spellId)
 		return 1.0
 	elseif self.className == "MAGE" or self.className == "WARLOCK" or self.className == "PRIEST" or
 			(self.className == "DRUID" and GetShapeshiftForm(true) ~= 1) then
-		local cd = 1.5 / OvaleAura.spellHaste
+		local cd = 1.5 / (1 + OvalePaperDoll.spellHaste)
 		if (cd<1) then
 			cd = 1
 		end
@@ -586,7 +586,7 @@ function OvaleData:GetDuration(spellId, spellHaste, combo, holy)
 	local si = self.spellInfo[spellId]
 	if si and si.duration then
 		local duration = si.duration
-		spellHaste = spellHaste or 1
+		spellHaste = spellHaste or 0
 		combo = combo or 0
 		holy = holy or 1
 		if si.adddurationcp then
@@ -611,10 +611,12 @@ end
 function OvaleData:GetTickLength(spellId, spellHaste)
 	local si = self.spellInfo[spellId]
 	if si then
-		if si.haste ~= "spell" then
-			return si.tick or 3
+		local tick = si.tick or 3
+		local haste = spellHaste or 0
+		if si.haste == "spell" then
+			return tick / (1 + haste)
 		else
-			return (si.tick or 3) / (spellHaste or 1)
+			return tick
 		end
 	else
 		return nil
diff --git a/OvaleFuture.lua b/OvaleFuture.lua
index d1135e8..88af9bd 100644
--- a/OvaleFuture.lua
+++ b/OvaleFuture.lua
@@ -12,9 +12,12 @@
 OvaleFuture = LibStub("AceAddon-3.0"):NewAddon("OvaleFuture", "AceEvent-3.0")

 --<private-static-properties>
-local ipairs, pairs, strfind, tremove = ipairs, pairs, string.find, table.remove
-local GetMasteryEffect, GetSpellBonusDamage = GetMasteryEffect, GetSpellBonusDamage
-local GetSpellInfo, UnitAttackPower, UnitBuff = GetSpellInfo, UnitAttackPower, UnitBuff
+local ipairs = ipairs
+local pairs = pairs
+local strfind = string.find
+local tremove = table.remove
+local GetSpellInfo = GetSpellInfo
+local UnitBuff = UnitBuff
 local UnitGUID = UnitGUID
 --</private-static-properties>

@@ -236,14 +239,10 @@ function OvaleFuture:AddSpellToList(spellId, lineId, startTime, endTime, channel
 	local si = OvaleData.spellInfo[spellId]

 	self.lastSpellId = spellId
-	self.lastSpellAP[spellId] = UnitAttackPower("player")
-	self.lastSpellSP[spellId] = GetSpellBonusDamage(2)
+	self.lastSpellAP[spellId] = OvalePaperDoll.attackPower
+	self.lastSpellSP[spellId] = OvalePaperDoll.spellBonusDamage
 	self.lastSpellDM[spellId] = OvaleAura:GetDamageMultiplier(spellId)
-	if OvaleData.level < 80 then
-		self.lastSpellMastery[spellId] = 0
-	else
-		self.lastSpellMastery[spellId] = GetMasteryEffect()
-	end
+	self.lastSpellMastery[spellId] = OvalePaperDoll.masteryEffect
 	self.lastSpell[#self.lastSpell+1] = newSpell
 	--Ovale:Print("on ajoute "..spellId..": ".. newSpell.start.." to "..newSpell.stop.." ("..tostring(OvaleState.maintenant)..")" ..#self.lastSpell .. " " ..tostring(newSpell.target))

diff --git a/OvalePaperDoll.lua b/OvalePaperDoll.lua
new file mode 100644
index 0000000..8af05ed
--- /dev/null
+++ b/OvalePaperDoll.lua
@@ -0,0 +1,161 @@
+--[[--------------------------------------------------------------------
+    Ovale Spell Priority
+    Copyright (C) 2013 Johnny C. Lam
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License in the LICENSE
+    file accompanying this program.
+--]]--------------------------------------------------------------------
+
+-- This addon tracks the player's stats as available on the in-game paper doll.
+
+OvalePaperDoll = LibStub("AceAddon-3.0"):NewAddon("OvalePaperDoll", "AceEvent-3.0")
+
+--<private-static-properties>
+local Ovale = LibStub("AceAddon-3.0"):GetAddon("Ovale")
+
+local GetMasteryEffect = GetMasteryEffect
+local GetMeleeHaste = GetMeleeHaste
+local GetSpellBonusDamage = GetSpellBonusDamage
+local GetSpellBonusHealing = GetSpellBonusHealing
+local UnitAttackPower = UnitAttackPower
+local UnitClass = UnitClass
+local UnitRangedAttackPower = UnitRangedAttackPower
+local UnitSpellHaste = UnitSpellHaste
+local UnitStat = UnitStat
+--</private-static-properties>
+
+--<public-static-properties>
+-- primary stats
+OvalePaperDoll.agility = 0
+OvalePaperDoll.intellect = 0
+OvalePaperDoll.spirit = 0
+OvalePaperDoll.stamina = 0
+OvalePaperDoll.strength = 0
+
+-- secondary stats
+OvalePaperDoll.attackPower = 0
+OvalePaperDoll.rangedAttackPower = 0
+-- percent increase of effect due to mastery
+OvalePaperDoll.masteryEffect = 0
+-- percent increase to melee haste
+OvalePaperDoll.meleeHaste = 0
+-- percent increase to spell haste
+OvalePaperDoll.spellHaste = 0
+-- spellpower
+OvalePaperDoll.spellBonusDamage = 0
+OvalePaperDoll.spellBonusHealing = 0
+--</public-static-properties>
+
+--<public-static-methods>
+function OvalePaperDoll:OnEnable()
+	self:RegisterEvent("MASTERY_UPDATE")
+	self:RegisterEvent("PLAYER_ENTERING_WORLD")
+	self:RegisterEvent("UNIT_ATTACK_POWER")
+	self:RegisterEvent("UNIT_RANGED_ATTACK_POWER")
+	self:RegisterEvent("UNIT_SPELL_HASTE")
+	self:RegisterEvent("UNIT_SPELL_POWER")
+	self:RegisterEvent("UNIT_STATS")
+end
+
+function OvalePaperDoll:OnDisable()
+	self:UnregisterEvent("MASTERY_UPDATE")
+	self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+	self:UnregisterEvent("UNIT_ATTACK_POWER")
+	self:UnregisterEvent("UNIT_RANGED_ATTACK_POWER")
+	self:UnregisterEvent("UNIT_SPELL_HASTE")
+	self:UnregisterEvent("UNIT_SPELL_POWER")
+	self:UnregisterEvent("UNIT_STATS")
+end
+
+function OvalePaperDoll:MASTERY_UPDATE(event)
+	if OvaleData.level < 80 then
+		self.masteryEffect = 0
+	else
+		self.masteryEffect = GetMasteryEffect()
+	end
+end
+
+function OvalePaperDoll:PLAYER_ENTERING_WORLD(event)
+	self:MASTERY_UPDATE(event)
+	self:UNIT_ATTACK_POWER(event, "player")
+	self:UNIT_RANGED_ATTACK_POWER(event, "player")
+	self:UNIT_SPELL_HASTE(event, "player")
+	self:UNIT_SPELL_POWER(event, "player")
+	self:UNIT_STATS(event, "player")
+end
+
+function OvalePaperDoll:UNIT_ATTACK_POWER(event, unitId)
+	if unitId ~= "player" then return end
+	local base, posBuff, negBuff = UnitAttackPower(unitId)
+	self.attackPower = base + posBuff + negBuff
+end
+
+function OvalePaperDoll:UNIT_RANGED_ATTACK_POWER(event, unitId)
+	if unitId ~= "player" then return end
+	local base, posBuff, negBuff = UnitRangedAttackPower(unitId)
+	self.rangedAttackPower = base + posBuff + negBuff
+end
+
+function OvalePaperDoll:UNIT_SPELL_HASTE(event, unitId)
+	if unitId ~= "player" then return end
+	self.meleeHaste = GetMeleeHaste()
+	self.spellHaste = UnitSpellHaste(unitId)
+end
+
+local _, className = UnitClass("player")
+local classToSchool = {
+	DEATHKNIGHT = 4, -- Nature
+	DRUID = 4, -- Nature
+	HUNTER = 4, -- Nature
+	MAGE = 5, -- Frost
+	MONK = 4, -- Nature
+	PALADIN = 2, -- Holy
+	PRIEST = 2, -- Holy
+	ROGUE = 4, -- Nature
+	SHAMAN = 4, -- Nature
+	WARLOCK = 6, -- Shadow
+	WARRIOR = 4, -- Nature
+}
+local isHealingClass = {
+	DRUID = true,
+	MONK = true,
+	PALADIN = true,
+	PRIEST = true,
+	SHAMAN = true,
+}
+
+function OvalePaperDoll:UNIT_SPELL_POWER(event, unitId)
+	if unitId ~= "player" then return end
+	self.spellBonusDamage = GetSpellBonusDamage(classToSchool[className])
+	if isHealingClass[className] then
+		self.spellBonusHealing = GetSpellBonusHealing()
+	else
+		self.spellBonusHealing = self.spellBonusDamage
+	end
+end
+
+function OvalePaperDoll:UNIT_STATS(event, unitId)
+	if unitId ~= "player" then return end
+	self.strength = UnitStat(unitId, 1)
+	self.agility = UnitStat(unitId, 2)
+	self.stamina = UnitStat(unitId, 3)
+	self.intellect = UnitStat(unitId, 4)
+	self.spirit = UnitStat(unitId, 5)
+end
+
+function OvalePaperDoll:Debug()
+	Ovale:Print("Agility: " ..self.agility)
+	Ovale:Print("Intellect: " ..self.intellect)
+	Ovale:Print("Spirit: " ..self.spirit)
+	Ovale:Print("Stamina: " ..self.stamina)
+	Ovale:Print("Strength: " ..self.strength)
+	Ovale:Print("AP: " ..self.attackPower)
+	Ovale:Print("RAP: " ..self.rangedAttackPower)
+	Ovale:Print("Spell bonus damage: " ..self.spellBonusDamage)
+	Ovale:Print("Spell bonus healing: " ..self.spellBonusHealing)
+	Ovale:Print("Spell haste effect: " ..self.spellHaste.. "%")
+	Ovale:Print("Melee haste effect: " ..self.meleeHaste.. "%")
+	Ovale:Print("Mastery effect: " ..self.masteryEffect.. "%")
+end
+--</public-static-methods>
diff --git a/OvaleState.lua b/OvaleState.lua
index d11b018..c229943 100644
--- a/OvaleState.lua
+++ b/OvaleState.lua
@@ -52,7 +52,7 @@ function OvaleState:UpdatePowerRates()
 		self.powerRate[k] = 0
 	end

-	self.powerRate.energy = 10 * OvaleAura.meleeHaste
+	self.powerRate.energy = 10 * OvalePaperDoll.meleeHaste

 	if OvaleData.className == "MONK" then
 		-- Ascension (monk)
@@ -71,7 +71,7 @@ function OvaleState:UpdatePowerRates()
 		self.powerRate.energy = self.powerRate.energy * 2
 	end

-	self.powerRate.focus = 4 * OvaleAura.meleeHaste
+	self.powerRate.focus = 4 * OvalePaperDoll.meleeHaste
 end

 function OvaleState:Reset()
@@ -318,7 +318,7 @@ function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd,

 							-- Set the duration to the proper length if it's a DoT.
 							if auraSpellInfo and auraSpellInfo.duration then
-								duration = OvaleData:GetDuration(auraSpellId, OvaleAura.spellHaste, self.state.combo, self.state.holy)
+								duration = OvaleData:GetDuration(auraSpellId, OvalePaperDoll.spellHaste, self.state.combo, self.state.holy)
 							end

 							-- If aura is specified with a duration, then assume stacks == 1.
@@ -350,7 +350,7 @@ function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd,
 										local tickLength = OvaleData:GetTickLength(auraSpellId, previousAura.spellHaste)
 										local k = floor((previousAura.ending - endCast) / tickLength)
 										newAura.ending = previousAura.ending - tickLength * k + duration
-										newAura.spellHaste = OvaleAura.spellHaste
+										newAura.spellHaste = OvalePaperDoll.spellHaste
 									else
 										newAura.ending = endCast + duration
 									end
@@ -375,7 +375,7 @@ function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd,
 								newAura.start = endCast
 								newAura.ending = endCast + duration
 								if isDoT then
-									newAura.spellHaste = OvaleAura.spellHaste
+									newAura.spellHaste = OvalePaperDoll.spellHaste
 								end
 							end
 						end