Quantcast

- added scoring (with Recount)

Sidoine De Wispelaere [10-04-09 - 17:29]
- added scoring (with Recount)
- added prediction beyond first spell (experimental, don't work)
- some fixes with DK and Shadow priest

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@106 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Condition.lua
Ovale.lua
Ovale.toc
OvaleCompile.lua
OvaleFrame.lua
OvaleIcone.lua
OvaleIcone.xml
OvaleRecount.lua
defaut/Chaman.lua
defaut/Chasseur.lua
defaut/Chevalier.lua
defaut/Demoniste.lua
defaut/Druide.lua
defaut/Guerrier.lua
defaut/Mage.lua
defaut/Paladin.lua
defaut/Pretre.lua
defaut/Voleur.lua
diff --git a/Condition.lua b/Condition.lua
index cdf756c..9c38b9c 100644
--- a/Condition.lua
+++ b/Condition.lua
@@ -162,6 +162,12 @@ local function getTarget(condition)
 end

 local function GetTargetAura(condition, filter, target)
+	if (not target) then
+		target=condition.target
+		if (not target) then
+			target="target"
+		end
+	end
 	local spellId = condition[1]
 	local auraName, auraRank, auraIcon = Ovale:GetSpellInfoOrNil(spellId)
 	local i=1;
@@ -182,14 +188,23 @@ local function GetTargetAura(condition, filter, target)
 		i = i + 1;
 	end

-	if (Ovale.currentSpellInfo and spellId and Ovale.currentSpellInfo[target][filter] and
-		Ovale.currentSpellInfo[target][filter][spellId]) then
-		if (not timeLeft or timeLeft < Ovale.attenteFinCast) then
-			stacksLeft = 1
-		else
-			stacksLeft = stacksLeft + 1
+	if spellId then
+		for k=1,Ovale.spellStack.length do
+			local newSpell = Ovale.spellStack[k]
+			if (newSpell.info and newSpell.info[target] and newSpell.info[target][filter] and newSpell.info[target][filter][spellId]) then
+				local duration = newSpell.info[target][filter][spellId]
+				if duration>0 then
+					if (not timeLeft or timeLeft < newSpell.attenteFinCast) then
+						stacksLeft = 1
+					else
+						stacksLeft = stacksLeft + 1
+					end
+					timeLeft = duration + newSpell.attenteFinCast
+				else
+					timeLeft = nil
+				end
+			end
 		end
-		timeLeft = Ovale.currentSpellInfo[target][filter][spellId] + Ovale.attenteFinCast
 	end
 	return timeLeft, stacksLeft
 end
@@ -295,7 +310,7 @@ Ovale.conditions=
 	-- 1 : "less" or "more"
 	-- 2 : the limit
 	ComboPoints = function(condition)
-		local points = GetComboPoints("player")
+		local points = Ovale.state.combo
 		return compare(points, condition[1], condition[2])
 	end,
 	DebuffExpires = function(condition)
@@ -432,17 +447,17 @@ Ovale.conditions=
 		local maxCD = nil
 		local minCD = nil
 		for i=1,6 do
-			if (GetRuneType(i) == type or GetRuneType(i) == 4) then
-				local start, duration, runeReady = GetRuneCooldown(i)
-				if (runeReady) then
+			local rune = Ovale.state.rune[i]
+			if (rune.type == type or rune.type == 4) then
+				if (rune.cd == 0) then
 					nombre = nombre + 1
 				else
 					nombreCD = nombreCD + 1
-					if (maxCD == nil or start<maxCD) then
-						maxCD = start
+					if (maxCD == nil or rune.cd>maxCD) then
+						maxCD = rune.cd
 					end
-					if (minCD == nil or start>minCD) then
-						minCD = start
+					if (minCD == nil or rune.cd<minCD) then
+						minCD = rune.cd
 					end
 				end
 			end
@@ -453,10 +468,10 @@ Ovale.conditions=
 		elseif (nombre + nombreCD < wanted) then
 			return nil
 		elseif (wanted == nombre + 1) then
-			return Ovale.maintenant - minCD
+			return minCD
 		else
 			-- Il ne peut y avoir que deux runes sur CD de toute façon
-			return Ovale.maintenant - maxCD
+			return maxCD
 		end
 	end,
 	-- Test if the player is in a given stance
@@ -483,7 +498,7 @@ Ovale.conditions=
 	-- 1 : buff spell id
 	-- stacks : how many stacks
 	TargetBuffPresent = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HELPFUL", "target")
+		local timeLeft, stacksLeft = GetTargetAura(condition, "HELPFUL")
 		local tempsMin = avecHate(condition[2], condition.haste)

 		if (timeLeft and (condition[2]==nil or timeLeft>tempsMin)) then
@@ -531,7 +546,7 @@ Ovale.conditions=
 	-- stacks : how many stacks
 	-- mine : 1 means that if the debuff is not ours, the debuff is ignored
 	TargetDebuffExpires = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL", "target")
+		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL")
 		local tempsMax = avecHate(condition[2], condition.haste)
 		if (not timeLeft or timeLeft<tempsMax) then
 			return 0
@@ -546,7 +561,7 @@ Ovale.conditions=
 	-- stacks : how many stacks
 	-- mine : 1 means that the debuff must be yours
 	TargetDebuffPresent = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL", "target")
+		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL")
 		local tempsMin = avecHate(condition[2], condition.haste)

 		if (timeLeft and (condition[2]==nil or timeLeft>tempsMin)) then
diff --git a/Ovale.lua b/Ovale.lua
index 2cd3f37..794514e 100644
--- a/Ovale.lua
+++ b/Ovale.lua
@@ -1,6 +1,7 @@
 local L = LibStub("AceLocale-3.0"):GetLocale("Ovale")

 Ovale = LibStub("AceAddon-3.0"):NewAddon("Ovale", "AceEvent-3.0", "AceConsole-3.0")
+local Recount = Recount

 Ovale.defaut = {}
 Ovale.action = {}
@@ -26,8 +27,11 @@ Ovale.aura = { player = {}, target = {}}
 Ovale.possibleAura = { player = {}, target = {}}
 Ovale.targetGUID = nil
 Ovale.spellInfo = {}
-Ovale.currentSpellInfo = nil
+Ovale.spellStack = {}
 Ovale.buff = {}
+Ovale.className = nil
+Ovale.state = {rune={}, cd = {}}
+Ovale.scoreSpell = {}

 Ovale.arbre = {}

@@ -157,6 +161,14 @@ local options =
 					get = function(info) return Ovale.db.profile.apparence.vertical end,
 					set = function(info, value) Ovale.db.profile.apparence.vertical = value; Ovale:UpdateFrame() end
 				},
+				predictif =
+				{
+					order = 10,
+					type = "toggle",
+					name = "Predictive (EXPERIMENTAL)",
+					get = function(info) return Ovale.db.profile.apparence.predictif end,
+					set = function(info, value) Ovale.db.profile.apparence.predictif = value; Ovale:UpdateFrame() end
+				},

 			}
 		},
@@ -298,7 +310,6 @@ function Ovale:PLAYER_TARGET_CHANGED()
 	end
 end

-
 function Ovale:UNIT_AURA(event, unit)
 	if (unit == "player") then
 		local hateBase = GetCombatRatingBonus(18)
@@ -352,6 +363,7 @@ function Ovale:UNIT_AURA(event, unit)

 		self.spellHaste = hateBase + hateCommune + hateSorts + hateHero + hateClasse
 		self.meleeHaste = hateBase + hateCommune + hateCaC + hateHero + hateClasse
+--		self.rangedHaste = hateBase + hateCommune + hateHero + hateClasse -- TODO ajouter le bidule du chasseur en spé bête
 --		print("spellHaste = "..self.spellHaste)
 	end
 end
@@ -383,10 +395,11 @@ function Ovale:FirstInit()
 	-- self:InitEcranOption()

 	local playerClass, englishClass = UnitClass("player")
-	if (englishClass == "ROGUE") then
-		self.gcd = 1
-	else
-		self.gcd = 1.5
+	self.className = englishClass
+	if self.className == "DEATHKNIGHT" then
+		for i=1,6 do
+			self.state.rune[i] = {}
+		end
 	end
 	-- OvaleFrame_Update(OvaleFrame)
 	-- OvaleFrame:Show()
@@ -435,9 +448,8 @@ function Ovale:OnEnable()
     self:RegisterEvent("UPDATE_BINDINGS");
     self:RegisterEvent("UNIT_AURA");
     self:RegisterEvent("ACTIONBAR_PAGE_CHANGED")
-
+    self:RegisterEvent("UNIT_SPELLCAST_SENT")
     self:RegisterEvent("PLAYER_TARGET_CHANGED")
-    -- self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")

 	if (not self.firstInit) then
 		self:FirstInit()
@@ -446,15 +458,47 @@ function Ovale:OnEnable()
 	self:UpdateVisibility()
 end

+function Ovale:UNIT_SPELLCAST_SENT(event,unit,name,rank,target)
+	-- self:Print("UNIT_SPELLCAST_SENT"..event.." unit="..unit.." name="..name.." tank="..rank.." target="..target)
+	if unit=="player" and self.enCombat then
+		-- self.lastSpellCast=name
+		if (not self.spellInfo[name] or not self.spellInfo[name].toggle) and self.scoreSpell[name] then
+			local previousAmount = 0
+			if self.maxScore>0 then
+				previousAmount = self.score/self.maxScore*1000
+			end
+			local scored = self.frame:GetScore(name)
+			self.score = self.score + scored
+			self.maxScore = self.maxScore + 1
+			local newAmount = self.score/self.maxScore*1000
+			-- self:Print(scored .. " for "..name)
+			if Recount then
+				local source =Recount.db2.combatants[UnitName("player")]
+				if source then
+				--	self:Print(previousAmount)
+				--	self:Print(newAmount)
+				--	self:Print(newAmount-previousAmount)
+					Recount:AddAmount(source,"Ovale",newAmount-previousAmount)
+				end
+			end
+		end
+	end
+end
+
 function Ovale:PLAYER_REGEN_ENABLED()
 	self.enCombat = false
 	if (Ovale.db.profile.apparence.enCombat and not Ovale.enCombat) then
 		self.frame:Hide()
 	end
+	-- if self.maxScore and self.maxScore > 0 then
+	-- 	self:Print((self.score/self.maxScore*100).."%")
+	-- end
 end

 function Ovale:PLAYER_REGEN_DISABLED()
 	self.enCombat = true
+	self.score = 0
+	self.maxScore = 0

 	if (Ovale.db.profile.apparence.enCombat and not Ovale.enCombat) then
 		self.frame:Show()
@@ -473,6 +517,7 @@ function Ovale:OnDisable()
     self:UnregisterEvent("CHARACTER_POINTS_CHANGED")
     self:UnregisterEvent("UPDATE_BINDINGS")
     self:UnregisterEvent("UNIT_AURA")
+    self:UnregisterEvent("UNIT_SPELLCAST_SENT")
     self:UnregisterEvent("PLAYER_TARGET_CHANGED")
     -- self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
     self.frame:Hide()
@@ -637,21 +682,113 @@ function Ovale:ChercherBouton(sort)
 	end
 end

+function Ovale:AddRune(time, type, value)
+	if value<0 then
+		for i=1,6 do
+			if (self.state.rune[i].type == type or self.state.rune[i].type==4)and self.state.rune[i].cd<=time then
+				self.state.rune[i].cd = time + 10
+			end
+		end
+	else
+
+	end
+end
+
+function Ovale:AddSpellToStack(spellName, startCast, endCast, nextCast)
+	self.spellStack.length = self.spellStack.length + 1
+	if not self.spellStack[self.spellStack.length] then
+		self.spellStack[self.spellStack.length] = {}
+	end
+	local newSpell = self.spellStack[self.spellStack.length]
+	newSpell.attenteFinCast = endCast
+	if spellName then
+		newSpell.info = self.spellInfo[spellName]
+	else
+		newSpell.info = nil
+	end
+	self.currentSpellName = spellName
+	self.attenteFinCast = nextCast
+	if startCast>=0 then
+		if newSpell.info then
+			if newSpell.info.combo then
+				self.state.combo = self.state.combo + newSpell.info.combo
+				if self.state.combo<0 then
+					self.state.combo = 0
+				end
+			end
+			if newSpell.info.frost then
+				self:AddRune(startCast, 3, newSpell.info.frost)
+			end
+			if newSpell.info.death then
+				self:AddRune(startCast, 4, newSpell.info.death)
+			end
+			if newSpell.info.blood then
+				self:AddRune(startCast, 1, newSpell.info.blood)
+			end
+			if newSpell.info.unholy then
+				self:AddRune(startCast, 2, newSpell.info.unholy)
+			end
+		end
+	end
+
+	if newSpell.info then
+		if newSpell.info.cd then
+			if not self.state.cd[spellName] then
+				self.state.cd[spellName] = {}
+			end
+			self.state.cd[spellName].start = startCast + self.maintenant
+			self.state.cd[spellName].duration = newSpell.info.cd
+			self.state.cd[spellName].enable = 1
+		end
+		if newSpell.info.toggle then
+			if not self.state.cd[spellName] then
+				self.state.cd[spellName] = {}
+			end
+			self.state.cd[spellName].toggled = 1
+		end
+	end
+end
+
+function Ovale:InitAllActions()
+	self.maintenant = GetTime();
+	self.gcd = self:GetGCD()
+end
+
 function Ovale:InitCalculerMeilleureAction()
 	self.attenteFinCast = 0
-	self.currentSpellInfo = nil
+	self.currentSpellName = nil
+	self.spellStack.length = 0
+	self.state.combo = GetComboPoints("player")
+	if self.className == "DEATHKNIGHT" then
+		for i=1,6 do
+			self.state.rune[i].type = GetRuneType(i)
+			local start, duration, runeReady = GetRuneCooldown(i)
+			if runeReady then
+				self.state.rune[i].cd = 0
+			else
+				self.state.rune[i].cd = duration - (self.maintenant - start)
+				if self.state.rune[i].cd<0 then
+					self.state.rune[i].cd = 0
+				end
+			end
+		end
+	end
+	for k,v in pairs(self.state.cd) do
+		v.start = nil
+		v.duration = nil
+		v.enable = 0
+		v.toggled = nil
+	end

 	-- On attend que le sort courant soit fini
 	local spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitCastingInfo("player")
 	if (spell) then
-		self.attenteFinCast = endTime/1000 - Ovale.maintenant
-		self.currentSpellInfo = self.spellInfo[spell]
+		self:AddSpellToStack(spell, startTime - Ovale.maintenant, endTime/1000 - Ovale.maintenant, endTime/1000 - Ovale.maintenant)
 	end

 	local spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitChannelInfo("player")
-	if (spell and not Ovale.canStopChannelling[spell]) then
-		self.attenteFinCast = endTime/1000 - Ovale.maintenant
-		self.currentSpellInfo = self.spellInfo[spell]
+	if (spell) then
+		self:AddSpellToStack(spell, startTime - Ovale.maintenant, endTime/1000 - Ovale.maintenant, endTime/1000 - Ovale.maintenant)
 	end
 end

@@ -663,6 +800,129 @@ local function printTime(temps)
 	end
 end

+function Ovale:GetGCD(spellName)
+	if spellName and self.spellInfo[spellName] then
+		if self.spellInfo[spellName].haste == "spell" then
+			local cd = self.spellInfo[spellName].gcd
+			if not cd then
+				cd = 1.5
+			end
+			cd = cd /(1+self.spellHaste/100)
+			if (cd<1) then
+				cd = 1
+			end
+			return cd
+		elseif self.spellInfo[spellName].gcd then
+			return self.spellInfo[spellName].gcd
+		end
+	end
+
+	-- Default value
+	if self.className == "ROGUE" or (self.className == "DRUID" and GetShapeshiftForm(true) == 3) then
+		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 /(1+self.spellHaste/100)
+		if (cd<1) then
+			cd = 1
+		end
+		return cd
+	else
+		return 1.5
+	end
+end
+
+function Ovale:GetActionInfo(element)
+	if not element then
+		return nil
+	end
+
+	local spellName
+	local action
+	local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
+		actionUsable, actionShortcut, actionIsCurrent, actionEnable
+
+	local target = element.params.target
+	if (not target) then
+		target = "target"
+	end
+
+	if (element.func == "Spell" ) then
+		spellName = self:GetSpellInfoOrNil(element.params[1])
+		action = self.actionSort[spellName]
+		if self.state.cd[spellName] and self.state.cd[spellName].start then
+			actionCooldownStart = self.state.cd[spellName].start
+			actionCooldownDuration = self.state.cd[spellName].duration
+			actionEnable = self.state.cd[spellName].enable
+		else
+			if self.spellInfo[spellName] and self.spellInfo[spellName].forcecd then
+				actionCooldownStart, actionCooldownDuration, actionEnable = GetSpellCooldown(GetSpellInfo(self.spellInfo[spellName].forcecd))
+			else
+				actionCooldownStart, actionCooldownDuration, actionEnable = GetSpellCooldown(spellName)
+			end
+		end
+
+		if (not action or not GetActionTexture(action)) then
+			actionTexture = GetSpellTexture(spellName)
+			actionInRange = IsSpellInRange(spellName, target)
+			actionUsable = IsUsableSpell(spellName)
+			actionShortcut = nil
+			local casting = UnitCastingInfo("player")
+			if (casting == spellName) then
+				actionIsCurrent = 1
+			else
+				actionIsCurrent = nil
+			end
+			-- not quite the same as IsCurrentAction. Why did they remove IsCurrentCast?
+		end
+	elseif (element.func=="Macro") then
+		action = self.actionMacro[element.params[1]]
+	elseif (element.func=="Item") then
+		local itemId
+		if (type(element.params[1]) == "number") then
+			itemId = element.params[1]
+		else
+			local _,_,id = string.find(GetInventoryItemLink("player",GetInventorySlotInfo(element.params[1])) or "","item:(%d+):%d+:%d+:%d+")
+			itemId = tonumber(id)
+		end
+		if (Ovale.trace) then
+			self:Print("Item "..itemId)
+		end
+
+		spellName = GetItemSpell(itemId)
+		actionUsable = (spellName~=nil)
+
+		action = self.actionObjet[itemId]
+		if (not action or not GetActionTexture(action)) then
+			actionTexture = GetItemIcon(itemId)
+			actionInRange = IsItemInRange(itemId, target)
+			actionCooldownStart, actionCooldownDuration, actionEnable = GetItemCooldown(itemId)
+			actionShortcut = nil
+			actionIsCurrent = nil
+		end
+	end
+
+	if (action and not actionTexture) then
+		actionTexture = GetActionTexture(action)
+		actionInRange = IsActionInRange(action, target)
+		if not actionCooldownStart then
+			actionCooldownStart, actionCooldownDuration, actionEnable = GetActionCooldown(action)
+		end
+		if (actionUsable == nil) then
+			actionUsable = IsUsableAction(action)
+		end
+		actionShortcut = self.shortCut[action]
+		actionIsCurrent = IsCurrentAction(action)
+	end
+
+	if spellName and self.state.cd[spellName] and self.state.cd[spellName].toggle then
+		actionIsCurrent = 1
+	end
+
+	return actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
+					actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName
+end
+
 function Ovale:CalculerMeilleureAction(element)
 	if (self.bug and not self.trace) then
 		return nil
@@ -672,70 +932,12 @@ function Ovale:CalculerMeilleureAction(element)
 		return nil
 	end

+	--TODO: créer un objet par type au lieu de ce if else if tout moche
 	if (element.type=="function")then
 		if (element.func == "Spell" or element.func=="Macro" or element.func=="Item") then
 			local action
 			local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-				actionUsable, actionShortcut, actionIsCurrent, actionEnable
-
-			local target = element.params.target
-			if (not target) then
-				target = "target"
-			end
-
-			if (element.func == "Spell" ) then
-				local sort = self:GetSpellInfoOrNil(element.params[1])
-				action = self.actionSort[sort]
-				if (not action or not GetActionTexture(action)) then
-					actionTexture = GetSpellTexture(sort)
-					actionInRange = IsSpellInRange(sort, target)
-					actionCooldownStart, actionCooldownDuration, actionEnable = GetSpellCooldown(sort)
-					actionUsable = IsUsableSpell(sort)
-					actionShortcut = nil
-					local casting = UnitCastingInfo("player")
-					if (casting == sort) then
-						actionIsCurrent = 1
-					else
-						actionIsCurrent = nil
-					end
-					-- not quite the same as IsCurrentAction. Why did they remove IsCurrentCast?
-				end
-			elseif (element.func=="Macro") then
-				action = self.actionMacro[element.params[1]]
-			elseif (element.func=="Item") then
-				local itemId
-				if (type(element.params[1]) == "number") then
-					itemId = element.params[1]
-				else
-					local _,_,id = string.find(GetInventoryItemLink("player",GetInventorySlotInfo(element.params[1])) or "","item:(%d+):%d+:%d+:%d+")
-					itemId = tonumber(id)
-				end
-				if (Ovale.trace) then
-					self:Print("Item "..itemId)
-				end
-
-				actionUsable = (GetItemSpell(itemId)~=nil)
-
-				action = self.actionObjet[itemId]
-				if (not action or not GetActionTexture(action)) then
-					actionTexture = GetItemIcon(itemId)
-					actionInRange = IsItemInRange(itemId, target)
-					actionCooldownStart, actionCooldownDuration, actionEnable = GetItemCooldown(itemId)
-					actionShortcut = nil
-					actionIsCurrent = nil
-				end
-			end
-
-			if (action and not actionTexture) then
-				actionTexture = GetActionTexture(action)
-				actionInRange = IsActionInRange(action, target)
-				actionCooldownStart, actionCooldownDuration, actionEnable = GetActionCooldown(action)
-				if (actionUsable == nil) then
-					actionUsable = IsUsableAction(action)
-				end
-				actionShortcut = self.shortCut[action]
-				actionIsCurrent = IsCurrentAction(action)
-			end
+				actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName = self:GetActionInfo(element)

 			if (not actionTexture) then
 				if (Ovale.trace) then
@@ -749,7 +951,7 @@ function Ovale:CalculerMeilleureAction(element)
 				end
 				return nil
 			end
-			if (element.params.doNotRepeat==1 and actionIsCurrent) then
+			if (spellName and self.spellInfo[spellName] and self.spellInfo[spellName].toggle and actionIsCurrent) then
 				if (Ovale.trace) then
 					self:Print("Action "..element.params[1].." is current action")
 				end
@@ -762,7 +964,8 @@ function Ovale:CalculerMeilleureAction(element)
 				else
 					restant = actionCooldownDuration - (self.maintenant - actionCooldownStart);
 				end
-				if (restant<self.attenteFinCast) then
+				if restant<self.attenteFinCast and (spellName==self.currentSpellName or not self.spellInfo[self.currentSpellName] or
+							not self.spellInfo[self.currentSpellName].canStopChannelling) then
 					restant = self.attenteFinCast
 				end
 				if (Ovale.trace) then
@@ -772,8 +975,7 @@ function Ovale:CalculerMeilleureAction(element)
 				if (not retourPriorite) then
 					retourPriorite = 3
 				end
-				return restant, retourPriorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-					actionUsable, actionShortcut
+				return restant, retourPriorite, element
 			else
 				if (Ovale.trace) then
 					self:Print("Action "..element.params[1].." not enabled")
@@ -837,17 +1039,14 @@ function Ovale:CalculerMeilleureAction(element)
 		if (tempsA==nil) then
 			return nil
 		end
-		local tempsB, priorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-			actionUsable, actionShortcut = Ovale:CalculerMeilleureAction(element.b)
+		local tempsB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b)
 		if (tempsB==nil) then
 			return nil
 		end
 		if (tempsB>tempsA) then
-			return  tempsB, priorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-				actionUsable, actionShortcut
+			return  tempsB, prioriteB, elementB
 		else
-			return  tempsA, priorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-				actionUsable, actionShortcut
+			return  tempsA, prioriteB, elementB
 		end
 	elseif (element.type == "unless") then
 		if (Ovale.trace) then
@@ -857,11 +1056,9 @@ function Ovale:CalculerMeilleureAction(element)
 		if (tempsA==0) then
 			return nil
 		end
-		local tempsB, priorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-			actionUsable, actionShortcut = Ovale:CalculerMeilleureAction(element.b)
+		local tempsB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b)
 		if (tempsA==nil or tempsA>tempsB) then
-			return tempsB, priorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-				actionUsable, actionShortcut
+			return tempsB, prioriteB, elementB
 		else
 			return nil
 		end
@@ -880,22 +1077,16 @@ function Ovale:CalculerMeilleureAction(element)
 			return tempsB
 		end
 	elseif (element.type == "group") then
-		local meilleurFils
 		local meilleurTempsFils
 		local meilleurePrioriteFils
-		local bestActionInRange
-		local bestActionCooldownStart
-		local bestActionCooldownDuration
-		local bestActionUsable
-		local bestActionShortCut
+		local bestElement

 		if (Ovale.trace) then
 			self:Print(element.type)
 		end

 		for k, v in ipairs(element.nodes) do
-			local nouveauTemps, priorite, action, actionInRange, actionCooldownStart, actionCooldownDuration,
-				actionUsable, actionShortcut = Ovale:CalculerMeilleureAction(v)
+			local nouveauTemps, priorite, nouveauElement = Ovale:CalculerMeilleureAction(v)
 			if (nouveauTemps) then
 				local remplacer

@@ -926,13 +1117,8 @@ function Ovale:CalculerMeilleureAction(element)
 				end
 				if (remplacer) then
 					meilleurTempsFils = nouveauTemps
-					meilleurFils = action
 					meilleurePrioriteFils = priorite
-					bestActionInRange = actionInRange
-					bestActionCooldownStart = actionCooldownStart
-					bestActionCooldownDuration = actionCooldownDuration
-					bestActionUsable = actionUsable
-					bestActionShortCut = actionShortcut
+					bestElement = nouveauElement
 				end
 			end
 		end
@@ -941,8 +1127,7 @@ function Ovale:CalculerMeilleureAction(element)
 			if (Ovale.trace) then
 				self:Print("Best action "..meilleurFils.." remains "..meilleurTempsFils)
 			end
-			return meilleurTempsFils,meilleurePrioriteFils, meilleurFils, bestActionInRange, bestActionCooldownStart,
-						bestActionCooldownDuration, bestActionUsable, bestActionShortCut
+			return meilleurTempsFils,meilleurePrioriteFils, bestElement
 		else
 			if (Ovale.trace) then printTime(nil) end
 			return nil
@@ -966,7 +1151,7 @@ function Ovale:ChargerDefaut()
 			list = {},
 			apparence = {enCombat=false, iconWidth = 64, iconHeight = 64, margin = 4,
 				smallIconWidth=28, smallIconHeight=28, raccourcis=true, numeric=false, avecCible = false,
-				verrouille = false, vertical = false},
+				verrouille = false, vertical = false, predictif=false},
 			skin = {SkinID="Blizzard", Backdrop = true, Gloss = false, Colors = {}}
 		}
 	})
@@ -1044,3 +1229,14 @@ end
 function Ovale:GetListValue(v)
 	return self.dropDowns[v] and self.dropDowns[v].value
 end
+
+function Ovale:GetSpellInfo(spell)
+	if (not self.spellInfo[spell]) then
+		self.spellInfo[spell] = { player = {}, target = {}}
+	end
+	return self.spellInfo[spell]
+end
+
+function Ovale:ResetSpellInfo()
+	self.spellInfo = {}
+end
\ No newline at end of file
diff --git a/Ovale.toc b/Ovale.toc
index 85dabdc..782e600 100644
--- a/Ovale.toc
+++ b/Ovale.toc
@@ -3,8 +3,8 @@
 ## Notes: Show the icon of the next spell to cast
 ## Notes-frFR: Affiche l'icône du prochain sort à lancer
 ## Author: Sidoine
-## Version: 3.2.5
-## OptionalDeps: Ace3, ButtonFacade
+## Version: 3.2.6
+## OptionalDeps: Ace3, ButtonFacade, Recount
 ## SavedVariables: OvaleDB
 ## SavedVariablesPerCharacter: OvaleDBPC
 ## X-Category: Combat
@@ -20,6 +20,7 @@ OvaleIcone.lua
 OvaleIcone.xml
 OvaleFrame.lua
 OvaleCompile.lua
+OvaleRecount.lua
 defaut\Chaman.lua
 defaut\Chasseur.lua
 defaut\Demoniste.lua
diff --git a/OvaleCompile.lua b/OvaleCompile.lua
index ee5375d..492b93f 100644
--- a/OvaleCompile.lua
+++ b/OvaleCompile.lua
@@ -5,7 +5,7 @@ local defines = {}

 local function ParseParameters(params)
 	local paramList = {}
-	for k,v in string.gmatch(params, "(%w+)=(%w+)") do
+	for k,v in string.gmatch(params, "(%w+)=([-%w]+)") do
 		if (string.match(v,"^%-?%d+%.?%d*$")) then
 			v = tonumber(v)
 		end
@@ -37,10 +37,7 @@ local function ParseSpellAddDebuff(params)
 	local paramList = ParseParameters(params)
 	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
 	if (spell) then
-		if (not Ovale.spellInfo[spell]) then
-			Ovale.spellInfo[spell] = { player = {}, target = {}}
-		end
-		Ovale.spellInfo[spell].player.HARMFUL = paramList
+		Ovale:GetSpellInfo(spell).player.HARMFUL = paramList
 	end
 	return ""
 end
@@ -49,10 +46,7 @@ local function ParseSpellAddBuff(params)
 	local paramList = ParseParameters(params)
 	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
 	if (spell) then
-		if (not Ovale.spellInfo[spell]) then
-			Ovale.spellInfo[spell] = { player = {}, target = {} }
-		end
-		Ovale.spellInfo[spell].player.HELPFUL = paramList
+		Ovale:GetSpellInfo(spell).player.HELPFUL = paramList
 	end
 	return ""
 end
@@ -61,14 +55,36 @@ local function ParseSpellAddTargetDebuff(params)
 	local paramList = ParseParameters(params)
 	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
 	if (spell) then
-		if (not Ovale.spellInfo[spell]) then
-			Ovale.spellInfo[spell] = { player = {}, target = {} }
+		Ovale:GetSpellInfo(spell).target.HARMFUL = paramList
+	end
+	return ""
+end
+
+local function ParseSpellInfo(params)
+	local paramList = ParseParameters(params)
+	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
+	if (spell) then
+		local spellInfo = Ovale:GetSpellInfo(spell)
+		for k,v in pairs(paramList) do
+			spellInfo[k] = v
 		end
-		Ovale.spellInfo[spell].target.HARMFUL = paramList
 	end
 	return ""
 end

+local function ParseScoreSpells(params)
+	for v in string.gmatch(params, "(%d+)") do
+		v = tonumber(v)
+
+		local spell = Ovale:GetSpellInfoOrNil(v)
+		if spell then
+			Ovale.scoreSpell[spell] = true
+		else
+			Ovale:Print("unknown spell "..v)
+		end
+	end
+end
+
 local function ParseIf(a, b)
 	local newNode = {type="if", a=node[tonumber(a)], b=node[tonumber(b)]}
 	node[#node+1] = newNode
@@ -205,7 +221,7 @@ end
 local function ParseCanStopChannelling(text)
 	local spell = Ovale:GetSpellInfoOrNil(text)
 	if (spell) then
-		Ovale.canStopChannelling[spell] = true
+		Ovale:GetSpellInfo(spell).canStopChannelling = true
 	else
 		Ovale:Print("CanStopChannelling with unknown spell "..text)
 	end
@@ -248,11 +264,13 @@ function Ovale:Compile(text)
 	text = string.gsub(text, "L%s*%(%s*(%w+)%s*%)", ParseL)

 	-- Options diverses
-	Ovale.canStopChannelling = {}
+	Ovale:ResetSpellInfo()
 	text = string.gsub(text, "CanStopChannelling%s*%(%s*(%w+)%s*%)", ParseCanStopChannelling)
 	text = string.gsub(text, "SpellAddBuff%s*%((.-)%)", ParseSpellAddBuff)
 	text = string.gsub(text, "SpellAddDebuff%s*%((.-)%)", ParseSpellAddDebuff)
 	text = string.gsub(text, "SpellAddTargetDebuff%s*%((.-)%)", ParseSpellAddTargetDebuff)
+	text = string.gsub(text, "SpellInfo%s*%((.-)%)", ParseSpellInfo)
+	text = string.gsub(text, "ScoreSpells%s*%((.-)%)", ParseScoreSpells)

 	-- On vire les espaces en trop
 	text = string.gsub(text, "\n", " ")
diff --git a/OvaleFrame.lua b/OvaleFrame.lua
index 46bb219..e1e75c8 100644
--- a/OvaleFrame.lua
+++ b/OvaleFrame.lua
@@ -21,7 +21,6 @@ do
 		this.obj:Hide()
 	end

-
 	local function frameOnMouseDown(this)
 		if (not Ovale.db.profile.apparence.verrouille) then
 			this:StartMoving()
@@ -43,30 +42,23 @@ do
 		if (Ovale.db.profile.left~=this:GetLeft() or Ovale.db.profile.top ~=this:GetTop()) then
 			Ovale.db.profile.left = this:GetLeft()
 			Ovale.db.profile.top = this:GetTop()
-	--	else
-	--		this.obj:ToggleOptions()
 		end
 	end

 	local function frameOnEnter(this)
-		--for i,child in ipairs(this.obj.children) do
-		--	child.frame:Show()
-		--end
-	--	this.obj.content:Show()
 		if (not Ovale.db.profile.apparence.verrouille) then
 			this.obj.barre:Show()
 		end
 	end

-
 	local function frameOnLeave(this)
-		--for i,child in ipairs(this.obj.children) do
-		--	child.frame:Hide()
-		--end
-		--this.obj.content:Hide()
 		this.obj.barre:Hide()
 	end

+	local function frameOnUpdate(self)
+		self.obj:OnUpdate()
+	end
+
 	local function Hide(self)
 		self.frame:Hide()
 	end
@@ -104,8 +96,6 @@ do
 	end

 	local function OnLayoutFinished(self, width, height)
-		-- self.content:SetWidth(width)
-		-- self.content:SetHeight(height)
 		if (not width) then
 			width = self.content:GetWidth()
 		end
@@ -114,18 +104,97 @@ do
 	end

 	local function OnSkinChanged(self, skinID, gloss, backdrop, colors)
-		-- for k, icon in pairs(self.icone) do
-		--	icon:UpdateSkin(skinID, gloss, backdrop, colors)
-		-- end
 		Ovale.db.profile.SkinID = skinID
 		Ovale.db.profile.Gloss = gloss
 		Ovale.db.profile.Backdrop = backdrop
 		Ovale.db.profile.Colors = colors
 	end

+	local function GetScore(self, spellName)
+		for k,action in pairs(self.actions) do
+			if action.spellName == spellName then
+				if not action.waitStart then
+					return 1
+				else
+					if Ovale.maintenant - action.waitStart>1.5 then
+						return 0
+					else
+						return 1-(Ovale.maintenant - action.waitStart)/1.5
+					end
+				end
+			end
+		end
+		return 0
+	end
+
+	local function OnUpdate(self)
+		Ovale:InitAllActions()
+		for k,node in pairs(Ovale.masterNodes) do
+			Ovale:InitCalculerMeilleureAction()
+			local minAttente, priorite, element = Ovale:CalculerMeilleureAction(node)
+
+			local action = self.actions[k]
+
+			local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
+					actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName = Ovale:GetActionInfo(element)
+
+			if (node.params.nocd and node.params.nocd == 1 and minAttente~=nil and minAttente>1.5) then
+				action.icons[1]:Update(nil)
+			else
+				action.icons[1]:Update(minAttente, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
+					actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName)
+			end
+
+			action.spellName = spellName
+
+			if minAttente == 0 and actionUsable then
+				if not action.waitStart then
+					action.waitStart = Ovale.maintenant
+				end
+			else
+				action.waitStart = nil
+			end
+
+			if (node.params.size ~= "small" and not node.params.nocd and Ovale.db.profile.apparence.predictif) then
+				if minAttente then
+					local top=1-(Ovale.maintenant - action.icons[1].debutAction)/(action.icons[1].finAction-action.icons[1].debutAction)
+					if top<0 then
+						top = 0
+					elseif top>1 then
+						top = 1
+					end
+
+					action.icons[1]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",action.left + top*action.dx,action.top - top*action.dy)
+					action.icons[2]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",action.left + (top+1)*action.dx,action.top - (top+1)*action.dy)
+					local castTime=0
+					if spellName then
+						local _, _, _, _, _, _, _castTime = GetSpellInfo(spellName)
+						if _castTime then
+							castTime = _castTime/1000
+						end
+					end
+					local gcd = Ovale:GetGCD(spellName)
+					local nextCast
+					if (castTime>gcd) then
+						nextCast = minAttente + castTime
+					else
+						nextCast = minAttente + gcd
+					end
+					Ovale:AddSpellToStack(spellName, minAttente, minAttente + castTime, nextCast)
+					minAttente, priorite, element = Ovale:CalculerMeilleureAction(node)
+					action.icons[2]:Update(minAttente, Ovale:GetActionInfo(element))
+				else
+					action.icons[2]:Update(nil)
+				end
+			end
+		end
+	end
+
 	local function UpdateIcons(self)
-		for k, icon in pairs(self.icone) do
-			icon:Hide()
+		for k, action in pairs(self.actions) do
+			for i, icon in pairs(action.icons) do
+				icon:Hide()
+			end
 		end

 		local left = 0
@@ -142,41 +211,61 @@ do
 		local margin =  Ovale.db.profile.apparence.margin

 		for k,node in pairs(Ovale.masterNodes) do
-			if (not self.icone[k]) then
-				-- self.icone[k] = CreateFrame("Frame", "Icon"..k,self.frame,"OvaleIcone");
-				self.icone[k] = CreateFrame("CheckButton", "Icon"..k,self.frame,"OvaleIcone");
+			if not self.actions[k] then
+				self.actions[k] = {icons={}}
 			end
-			-- self.icone[k]:SetFrameLevel(1)
-			self.icone[k].masterNode = node
+			local action = self.actions[k]
+
 			local width, height
+			local nbIcons
 			if (node.params.size == "small") then
 				width = Ovale.db.profile.apparence.smallIconWidth + margin
 				height = Ovale.db.profile.apparence.smallIconHeight + margin
+				nbIcons = 1
 			else
 				width = Ovale.db.profile.apparence.iconWidth + margin
 				height = Ovale.db.profile.apparence.iconHeight + margin
+				if Ovale.db.profile.apparence.predictif then
+					nbIcons = 2
+				else
+					nbIcons = 1
+				end
 			end
 			if (top + height > Ovale.db.profile.apparence.iconHeight + margin) then
 				top = 0
 				left = maxWidth
 			end
+
+			action.width = width - margin
+			action.height = height - margin
 			if (Ovale.db.profile.apparence.vertical) then
-				self.icone[k]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",top,-left-BARRE-margin)
+				action.left = top
+				action.top = -left-BARRE-margin
+				action.dx = action.width
+				action.dy = 0
 			else
-				self.icone[k]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",left,-top-BARRE-margin)
-			end
-			self.icone[k]:SetWidth(width - margin)
-			self.icone[k]:SetHeight(height - margin)
-			if (not LBF) then
-				self.icone[k].normalTexture:SetWidth((width - margin)*66/36)
-				self.icone[k].normalTexture:SetHeight((height - margin)*66/36)
-				self.icone[k].shortcut:SetWidth(width-margin)
-				self.icone[k].remains:SetWidth(width-margin)
+				action.left = left
+				action.top = -top-BARRE-margin
+				action.dx = 0
+				action.dy = action.height
 			end
-			if LBF then
-				self.icone[k]:SetSkinGroup(self.skinGroup)
+
+			for l=1,nbIcons do
+				if (not action.icons[l]) then
+					action.icons[l] = CreateFrame("CheckButton", "Icon"..k.."n"..l,self.frame,"OvaleIcone");
+				end
+				local icon = action.icons[l]
+				icon:SetPoint("TOPLEFT",self.frame,"TOPLEFT",action.left + (l-1)*action.dx,action.top - (l-1)*action.dy)
+				icon:SetSize(action.width, action.height)
+
+				if LBF then
+					icon:SetSkinGroup(self.skinGroup)
+				end
+				if l==1 then
+					icon:Show();
+				end
 			end
-			self.icone[k]:Show();
+
 			top = top + height
 			if (top> maxHeight) then
 				maxHeight = top
@@ -205,8 +294,6 @@ do
 		local frame = CreateFrame("Frame",nil,UIParent)
 		local self = {}

-		-- self.optionsVisible = false
-
 		self.type = "Frame"

 		self.Hide = Hide
@@ -218,9 +305,11 @@ do
 		self.UpdateIcons = UpdateIcons
 		self.OnSkinChanged = OnSkinChanged
 		self.ToggleOptions = ToggleOptions
+		self.OnUpdate = OnUpdate
+		self.GetScore = GetScore

 		self.localstatus = {}
-		self.icone = {}
+		self.actions = {}

 		self.frame = frame
 		frame.obj = self
@@ -229,13 +318,12 @@ do
 		frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
 		frame:EnableMouse()
 		frame:SetMovable(true)
-		--frame:SetResizable(true)
 		frame:SetFrameStrata("BACKGROUND")
 		frame:SetScript("OnMouseDown", frameOnMouseDown)
 		frame:SetScript("OnMouseUp", frameOnMouseUp)
 		frame:SetScript("OnEnter", frameOnEnter)
 		frame:SetScript("OnLeave", frameOnLeave)
-
+		frame:SetScript("OnUpdate", frameOnUpdate)
 		frame:SetScript("OnHide",frameOnClose)

 		self.barre = self.frame:CreateTexture();
@@ -247,11 +335,8 @@ do
 		local content = CreateFrame("Frame",nil,frame)
 		self.content = content
 		content.obj = self
-		content.test = "test"
 		content:SetWidth(200)
 		content:SetHeight(100)
-		--content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
-		-- content:EnableMouse()
 		content:Hide()

 		AceGUI:RegisterAsContainer(self)
diff --git a/OvaleIcone.lua b/OvaleIcone.lua
index c5be895..4853a17 100644
--- a/OvaleIcone.lua
+++ b/OvaleIcone.lua
@@ -1,13 +1,11 @@
-function OvaleIcone_OnUpdate(self)
-	Ovale.maintenant = GetTime();
-
+local LBF = LibStub("LibButtonFacade", true)
+
+local function Update(self, minAttente, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
+				actionUsable, actionShortcut)
+
 	if (not Ovale.bug) then
 		Ovale.traced = false
 	end
-
-	Ovale:InitCalculerMeilleureAction()
-	local minAttente, priorite, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
-		actionUsable, actionShortcut = Ovale:CalculerMeilleureAction(self.masterNode)

 	if (Ovale.trace) then
 		Ovale.trace=false
@@ -16,13 +14,7 @@

 	if (Ovale.bug and not Ovale.traced) then
 		Ovale.trace = true
-	end
-
-
-	if (self.masterNode.params.nocd and
-		self.masterNode.params.nocd == 1 and minAttente~=nil and minAttente>1.5) then
-		minAttente = nil
-	end
+	end

 	if (minAttente~=nil and actionTexture) then

@@ -52,12 +44,12 @@
 		if (actionUsable) then
 			self.icone:SetAlpha(1.0)
 		else
-			self.icone:SetAlpha(0.25)
+			self.icone:SetAlpha(0.33)
 		end

 		if (Ovale.maintenant + minAttente > actionCooldownStart + actionCooldownDuration + 0.01 and minAttente > 0
 			and minAttente>Ovale.attenteFinCast) then
-			self.icone:SetVertexColor(0.75,0,0)
+			self.icone:SetVertexColor(0.75,0.2,0.2)
 		else
 			self.icone:SetVertexColor(1,1,1)
 		end
@@ -99,6 +91,7 @@
 		self.shortcut:Hide()
 		self.remains:Hide()
 	end
+	return minAttente,element
 end

 local function SetSkinGroup(self, _skinGroup)
@@ -106,6 +99,17 @@ local function SetSkinGroup(self, _skinGroup)
 	self.skinGroup:AddButton(self)
 end

+local function SetSize(self, width, height)
+	self:SetWidth(width)
+	self:SetHeight(height)
+	if (not LBF) then
+		self.normalTexture:SetWidth(width*66/36)
+		self.normalTexture:SetHeight(height*66/36)
+		self.shortcut:SetWidth(width)
+		self.remains:SetWidth(width)
+	end
+end
+
 function OvaleIcone_OnClick(self)
 	Ovale:ToggleOptions()
 	self:SetChecked(0)
@@ -123,5 +127,6 @@ function OvaleIcone_OnLoad(self)

 	self:RegisterForClicks("LeftButtonUp")
 	self.SetSkinGroup = SetSkinGroup
-	self.UpdateSkin = UpdateSkin
+	self.Update = Update
+	self.SetSize = SetSize
 end
diff --git a/OvaleIcone.xml b/OvaleIcone.xml
index 0178686..3bbeb3f 100644
--- a/OvaleIcone.xml
+++ b/OvaleIcone.xml
@@ -2,7 +2,7 @@

   <CheckButton name="OvaleIcone" virtual="true" inherits="ActionButtonTemplate">
     <Scripts>
-      <OnUpdate>OvaleIcone_OnUpdate(self);</OnUpdate>
+      <!--<OnUpdate>OvaleIcone_OnUpdate(self);</OnUpdate>-->
       <OnLoad>OvaleIcone_OnLoad(self);</OnLoad>
       <OnClick>OvaleIcone_OnClick(self)</OnClick>
     </Scripts>
diff --git a/OvaleRecount.lua b/OvaleRecount.lua
new file mode 100644
index 0000000..2c0a3aa
--- /dev/null
+++ b/OvaleRecount.lua
@@ -0,0 +1,22 @@
+local Recount = Recount
+local RL = LibStub("AceLocale-3.0"):GetLocale("Recount")
+
+local function DataModes(self,data, num)
+	if not data then return 0, 0 end
+	if num == 1 then
+		return (data.Fights[Recount.db.profile.CurDataSet].Ovale or 0)
+	end
+	return (data.Fights[Recount.db.profile.CurDataSet].Ovale or 0), nil --{{}}
+end
+
+local function TooltipFuncs(self,name,data)
+	local SortedData,total
+	GameTooltip:ClearLines()
+	GameTooltip:AddLine(name)
+	-- Recount:AddSortedTooltipData(RL["Top 3"].." Ovale",data and data.Fights[Recount.db.profile.CurDataSet] and data.Fights[Recount.db.profile.CurDataSet].Ovale,3)
+	-- GameTooltip:AddLine("<"..RL["Click for more Details"]..">",0,0.9,0)
+end
+
+if Recount then
+	Recount:AddModeTooltip("Ovale",DataModes,TooltipFuncs,nil,nil,nil,nil)
+end
\ No newline at end of file
diff --git a/defaut/Chaman.lua b/defaut/Chaman.lua
index 2d069a0..7814c80 100644
--- a/defaut/Chaman.lua
+++ b/defaut/Chaman.lua
@@ -62,6 +62,13 @@ AddListItem(earth stone SpellName(STONESKINTOTEM))
 AddListItem(earth strength SpellName(STRENGTHOFEARTHTOTEM))
 AddListItem(earth tremor SpellName(TREMORTOTEM))

+SpellInfo(LAVABURST cd=8)
+SpellInfo(CHAINLIGHTNING cd=6)
+SpellAddBuff(LIGHTNINGBOLT MAELSTROMWEAPON=0)
+SpellAddBuff(CHAINLIGHTNING MAELSTROMWEAPON=0)
+ScoreSpells(WATERSHIELD FLAMESHOCK LAVABURST CHAINLIGHTNING LIGHTNINGBOLT LAVALASH EARTHSHOCK LIGHTNINGSHIELD
+	STORMSTRIKE)
+
 AddIcon
 {
 	unless CheckBoxOn(melee)
@@ -69,12 +76,12 @@ AddIcon
 	#	if BuffExpires(FLAMETHONG 2) Spell(FLAMETHONG)
 		if BuffExpires(WATERSHIELD 2) Spell(WATERSHIELD)
 		if TargetDebuffExpires(FLAMESHOCK 0 mine=1) Spell(FLAMESHOCK)
-		Spell(LAVABURST doNotRepeat=1)
-		if CheckBoxOn(aoe) Spell(CHAINLIGHTNING doNotRepeat=1)
+		Spell(LAVABURST)
+		if CheckBoxOn(aoe) Spell(CHAINLIGHTNING)

 		if CheckBoxOn(chain)
 		{
-			unless 1.4s before Spell(LAVABURST doNotRepeat=1) Spell(LIGHTNINGBOLT)
+			unless 1.4s before Spell(LAVABURST) Spell(LIGHTNINGBOLT)

 			Spell(CHAINLIGHTNING)
 		}
@@ -89,8 +96,8 @@ AddIcon
 		if BuffExpires(LIGHTNINGSHIELD 0) Spell(LIGHTNINGSHIELD)
 		Spell(STORMSTRIKE)
 		if TargetDebuffPresent(FLAMESHOCK 1.5 haste=spell mine=1) Spell(LAVALASH)
-		if CheckBoxOn(aoe) and BuffPresent(MAELSTROMWEAPON stacks=5) Spell(CHAINLIGHTNING doNotRepeat=1)
-		if BuffPresent(MAELSTROMWEAPON stacks=5) Spell(LIGHTNINGBOLT doNotRepeat=1)
+		if CheckBoxOn(aoe) and BuffPresent(MAELSTROMWEAPON stacks=5) Spell(CHAINLIGHTNING)
+		if BuffPresent(MAELSTROMWEAPON stacks=5) Spell(LIGHTNINGBOLT)
 	}
 }

diff --git a/defaut/Chasseur.lua b/defaut/Chasseur.lua
index ce6b4ab..8e277b1 100644
--- a/defaut/Chasseur.lua
+++ b/defaut/Chasseur.lua
@@ -18,6 +18,7 @@ Define(CALLOFTHEWILD 53434)
 Define(CHIMERASHOT 53209)

 AddCheckBox(multi SpellName(MULTISHOT))
+ScoreSpells(HUNTERSMARK BLACKARROW SERPENTSTING CHIMERASHOT AIMEDSHOT MULTISHOT ARCANESHOT KILLSHOT STEADYSHOT)

 AddIcon
 {
diff --git a/defaut/Chevalier.lua b/defaut/Chevalier.lua
index e461740..f0080aa 100644
--- a/defaut/Chevalier.lua
+++ b/defaut/Chevalier.lua
@@ -33,6 +33,14 @@ Define(TALENTABOMINATIONMIGHT 2105)
 Define(RAISEDEAD 46584)

 AddCheckBox(rolldes SpellName(GLYPHDISEASE))
+SpellAddTargetDebuff(ICYTOUCH FROSTFEVER=15)
+SpellAddTargetDebuff(PLAGUESTRIKE BLOODPLAGUE=15)
+SpellInfo(ICYTOUCH frost=-1 forcecd=DEATHCOIL)
+SpellInfo(PLAGUESTRIKE unholy=-1 forcecd=DEATHCOIL)
+SpellInfo(DEATHSTRIKE unholy=-1 frost=-1)
+SpellInfo(HEARTSTRIKE blood=-1)
+ScoreSpells(HOWLINGBLAST HEARTSTRIKE BLOODSTRIKE DEATHSTRIKE SCOURGESTRIKE OBLITERATE HEARTSTRIKE
+				PESTILENCE ICYTOUCH PLAGUESTRIKE FROSTSTRIKE DEATHCOIL RAISEDEAD)

 AddIcon
 {
diff --git a/defaut/Demoniste.lua b/defaut/Demoniste.lua
index 8c17d51..63eae91 100644
--- a/defaut/Demoniste.lua
+++ b/defaut/Demoniste.lua
@@ -33,18 +33,24 @@ AddListItem(curse doom SpellName(CURSEDOOM))
 AddListItem(curse tongues SpellName(CURSETONGUES))
 AddListItem(curse weakness SpellName(CURSEWEAKNESS))

+SpellInfo(HAUNT cd=8)
+SpellInfo(CONFLAGRATE cd=10)
+SpellAddTargetDebuff(UNSTABLEAFFLICTION UNSTABLEAFFLICTION=15)
+SpellAddTargetDebuff(IMMOLATE IMMOLATE=15)
+ScoreSpells(CURSEELEMENTS SHADOWBOLT HAUNT UNSTABLEAFFLICTION IMMOLATE CONFLAGRATE CURSEDOOM CURSETONGUES CURSEWEAKNESS
+	CURSEAGONY CORRUPTION SOULFIRE DRAINSOUL INCINERATE SHADOWBOLT)

 AddIcon
 {
 if List(curse elements) and TargetDebuffExpires(CURSEELEMENTS 2) Spell(CURSEELEMENTS)
 if TalentPoints(TALENTSHADOWEMBRACE more 0) and TargetDebuffExpires(SHADOWEMBRACE 0) Spell(SHADOWBOLT)
-if TargetDebuffExpires(HAUNT 1.5 mine=1) Spell(HAUNT doNotRepeat=1)
-if TargetDebuffExpires(UNSTABLEAFFLICTION 1.5 mine=1 haste=spell) Spell(UNSTABLEAFFLICTION doNotRepeat=1)
+if TargetDebuffExpires(HAUNT 1.5 mine=1) Spell(HAUNT)
+if TargetDebuffExpires(UNSTABLEAFFLICTION 1.5 mine=1 haste=spell) Spell(UNSTABLEAFFLICTION)
 if TalentPoints(TALENTBACKDRAFT more 0) and TargetDebuffExpires(IMMOLATE 3 mine=1)
-   and TargetDebuffPresent(IMMOLATE mine=1) Spell(CONFLAGRATE doNotRepeat=1)
+   and TargetDebuffPresent(IMMOLATE mine=1) Spell(CONFLAGRATE)
 if TargetDebuffExpires(IMMOLATE 1.5 mine=1 haste=spell) and
 		{TargetLifePercent(more 25) or TalentPoints(TALENTDECIMATION more 0)}
-			Spell(IMMOLATE doNotRepeat=1)
+			Spell(IMMOLATE)
 if List(curse doom) and TargetDebuffExpires(CURSEDOOM 0 mine=1) Spell(CURSEDOOM)
 if List(curse tongues) and TargetDebuffExpires(CURSETONGUES 2) Spell(CURSETONGUES)
 if List(curse weakness) and TargetDebuffExpires(CURSEWEAKNESS 2) Spell(CURSEWEAKNESS)
diff --git a/defaut/Druide.lua b/defaut/Druide.lua
index fce9e29..07786ab 100644
--- a/defaut/Druide.lua
+++ b/defaut/Druide.lua
@@ -32,6 +32,12 @@ AddCheckBox(demo SpellName(DEMOROAR))
 AddCheckBox(lucioles SpellName(FAERIEFIRE))
 AddCheckBox(wrath SpellName(WRATH))

+ScoreSpells(FAERIEFERAL DEMOROAR MANGLEBEAR LACERATE SAVAGEROAR RIP
+		TIGERSFURY MANGLECAT RAKE SHRED FEROCIOUSBITE INSECTSWARM MOONFIRE
+		WRATH STARFIRE)
+
+SpellInfo(MAUL toggle=1)
+
 AddIcon
 {
 	if Stance(1) # bear
@@ -115,7 +121,7 @@ AddIcon
 {
   if Stance(1)
   {
-       Spell(MAUL doNotRepeat=1)
+       Spell(MAUL)
   }
 }

diff --git a/defaut/Guerrier.lua b/defaut/Guerrier.lua
index c06a693..51900e1 100644
--- a/defaut/Guerrier.lua
+++ b/defaut/Guerrier.lua
@@ -42,6 +42,19 @@ AddListItem(shout none L(None))
 AddListItem(shout battle SpellName(BATTLESHOUT))
 AddListItem(shout command SpellName(COMMANDSHOUT))

+SpellAddTargetDebuff(THUNDERCLAP THUNDERCLAP=30)
+SpellAddTargetDebuff(DEMOSHOUT DEMOSHOUT=45)
+SpellAddTargetDebuff(REND REND=15)
+SpellAddBuff(BATTLESHOUT BATTLESHOUT=120)
+SpellAddBuff(COMMANDSHOUT COMMANDSHOUT=120)
+SpellAddBuff(SLAM SLAMBUFF=0)
+SpellInfo(WHIRLWIND cd=8)
+SpellInfo(BLOODTHIRST cd=4)
+SpellInfo(DEATHWISH cd=180)
+SpellInfo(HEROICSTRIKE toggle=1)
+SpellInfo(CLEAVE toggle=1)
+ScoreSpells(WHIRLWIND BLOODTHIRST SLAM REND MORTALSTRIKE EXECUTE SHIELDSLAM REVENGE)
+
 AddIcon
 {
      if List(shout command) and
@@ -134,16 +147,16 @@ AddIcon
 		if Stance(2)
 		{
 			if Mana(more 66)
-				Spell(HEROICSTRIKE doNotRepeat=1)
+				Spell(HEROICSTRIKE)
 		}
 		unless Stance(2)
 		{
 			if Mana(more 66) and TargetLifePercent(more 20)
-				Spell(HEROICSTRIKE doNotRepeat=1)
+				Spell(HEROICSTRIKE)
 		}
 	}
     if Mana(more 50) and CheckBoxOn(multi)
-		Spell(CLEAVE doNotRepeat=1)
+		Spell(CLEAVE)
  }

 AddIcon
diff --git a/defaut/Mage.lua b/defaut/Mage.lua
index 031a3c3..f77eb0c 100644
--- a/defaut/Mage.lua
+++ b/defaut/Mage.lua
@@ -30,6 +30,7 @@ AddCheckBox(scorch SpellName(SCORCH))
 SpellAddDebuff(ARCANEBLAST ARCANEBLAST=10)
 SpellAddTargetDebuff(SCORCH IMPROVEDSCORCH=30)
 SpellAddTargetDebuff(LIVINGBOMB LIVINGBOMB=12)
+ScoreSpells(SCORCH PYROBLAST LIVINGBOMB FROSTFIREBOLT FIREBALL SUMMONWATERELEMENTAL FROSTBOLT ARCANEBLAST ARCANEMISSILES)

 AddIcon
 {
diff --git a/defaut/Paladin.lua b/defaut/Paladin.lua
index 1cdf2b1..c43a3b1 100644
--- a/defaut/Paladin.lua
+++ b/defaut/Paladin.lua
@@ -28,6 +28,8 @@ AddListItem(jugement sagesse SpellName(JUDGEWISDOM))
 AddCheckBox(consecration SpellName(CONSECRATE))
 AddCheckBox(tempete SpellName(DIVINESTORM))
 AddCheckBox(coleredivine SpellName(HOLYWRATH))
+ScoreSpells(SEALRIGHTEOUSNESS SEALCOMMAND SEALVENGEANCE SEALCORRUPTION HOLYSHIELD HAMMEROFTHERIGHTEOUS CRUSADERSTRIKE
+	HAMMEROFWRATH JUDGELIGHT JUDGEWISDOM DIVINESTORM CONSECRATE EXORCISM HOLYWRATH HOLYSHOCK SHIELDOFRIGHTEOUSNESS)

 AddIcon
 {
diff --git a/defaut/Pretre.lua b/defaut/Pretre.lua
index 22e35e1..6d18a4a 100644
--- a/defaut/Pretre.lua
+++ b/defaut/Pretre.lua
@@ -13,18 +13,28 @@ Define(IF 48168) # Inner Fire
 Define(Focus 14751) # Inner Focus
 Define(Dispersion 47585)
 Define(Shadowfiend 34433)
-CanStopChannelling(MF) # Mind Flay's channeling can be interrupted if needed

 # Spells with cast time that add buff or debuff
-SpellAddTargetDebuff(VT SW=15 VT=15)
-SpellAddTargetDebuff(MF SW=15)
-SpellAddTargetDebuff(MB SW=15)
+SpellAddTargetDebuff(SWP SWP=18)
+SpellAddBuff(SWP SW=15)
+SpellAddTargetDebuff(VT VT=15)
+SpellAddBuff(VT SW=15)
+SpellInfo(MF canStopChannelling=1)
+SpellAddBuff(MF SW=15)
+SpellInfo(MB cd=5.5)
+SpellAddBuff(MB SW=15)
+SpellAddBuff(IF IF=1800)
+SpellAddTargetDebuff(DP DP=24)
+SpellInfo(Focus cd=180)
+SpellInfo(Dispersion cd=120)
+SpellInfo(Shadowfiend cd=300)
+ScoreSpells(MB SWP VT DP MF)

 # Add main monitor
 AddIcon {

 #Check shadowform is up
-if BuffExpires(SF 0)
+unless BuffPresent(SF)
     Spell(SF)

 # Refresh inner fire
@@ -33,7 +43,7 @@ if BuffExpires(IF 60)

 #if inner focus is active, cast mind blast
 if BuffPresent(Focus)
-    Spell(MB doNotRepeat=1)
+    Spell(MB)

 # Check if Shadow Weave is stacked 5 times
 # before suggesting Shadow Word: Pain
@@ -47,7 +57,7 @@ if TargetDebuffExpires(VT 1.4 mine=1 haste=spell)
    Spell(VT)

 #cast MB if up
-Spell(MB doNotRepeat=1)
+Spell(MB)

 #Refresh devouring plague
 if TargetDebuffExpires(DP 0 mine=1)
@@ -68,7 +78,7 @@ AddIcon
 AddIcon {

 #if up, launch focus (and then MB since it's the first priority)
-Spell(Focus doNotRepeat=1 usable=1)
+Spell(Focus usable=1)

 #Regain mana if needed and if shadowfiend is not already out
 if Mana(less 4000) and PetPresent(no)
diff --git a/defaut/Voleur.lua b/defaut/Voleur.lua
index 43bc957..17b372d 100644
--- a/defaut/Voleur.lua
+++ b/defaut/Voleur.lua
@@ -20,6 +20,8 @@ Define(PREPARATION 14185)
 Define(TRICKSOFTHETRADE 57934)
 Define(CLOACKOFSHADOWS 31224)

+ScoreSpells(SLICEANDDICE HUNGERFORBLOOD ENVENOM RUPTURE EVISCERATE MUTILATE SINISTERSTRIKE)
+
 AddIcon
 {
 	unless BuffPresent(SLICEANDDICE)