Quantcast

- two spells are correctly displayed (need script support)

Sidoine De Wispelaere [11-28-09 - 20:39]
- two spells are correctly displayed (need script support)
- added TimeInCombat() function
- all BuffPresent() functions use the same syntax as BuffExpires() now, and should work better

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@141 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Condition.lua
Locale-enUS.lua
Locale-frFR.lua
Ovale.lua
Ovale.toc
OvaleCompile.lua
OvaleFrame.lua
OvaleIcone.lua
defaut/Chaman.lua
defaut/Chasseur.lua
defaut/Demoniste.lua
diff --git a/Condition.lua b/Condition.lua
index 0f8bf1c..3c5265a 100644
--- a/Condition.lua
+++ b/Condition.lua
@@ -111,6 +111,9 @@ local function isDebuffInList(list)
 end

 local function avecHate(temps, hate)
+	if not temps then
+		temps = 0
+	end
 	if (not hate) then
 		return temps
 	elseif (hate == "spell") then
@@ -162,6 +165,33 @@ local function getTarget(condition)
 	end
 end

+local function addTime(time1, duration)
+	if not time1 then
+		return nil
+	else
+		return time1 + duration
+	end
+end
+
+local function addOrSubTime(time1, operator, duration)
+	if operator == "more" then
+		return addTime(time1, -duration)
+	else
+		return addTime(time1, duration)
+	end
+end
+
+local function nilstring(text)
+	if text == nil then
+		return "nil"
+	else
+		return text
+	end
+end
+
+
+-- Recherche un aura sur la cible et récupère sa durée et le nombre de stacks
+-- return start, ending, stacks
 local function GetTargetAura(condition, filter, target)
 	if (not target) then
 		target=condition.target
@@ -169,10 +199,26 @@ local function GetTargetAura(condition, filter, target)
 			target="target"
 		end
 	end
+	local stacks = condition.stacks
+	if not stacks then
+		stacks = 1
+	end
 	local spellId = condition[1]
-	local auraName, auraRank, auraIcon = Ovale:GetSpellInfoOrNil(spellId)
+	local aura = Ovale:GetAura(target, filter, spellId)
+	if Ovale.trace then
+		Ovale:Print("GetTargetAura = start = ".. nilstring(aura.start) .. " end = "..nilstring(aura.ending).." stacks = " ..nilstring(aura.stacks).."/"..stacks)
+	end
+	if (not condition.mine or aura.mine) and aura.stacks>=stacks then
+		return aura.start, aura.ending
+	else
+		return nil, 0
+	end
+end
+
+--[[	local auraName, auraRank, auraIcon = Ovale:GetSpellInfoOrNil(spellId)
 	local i=1;
-	local timeLeft = nil
+	local startTime = nil
+	local endTime = nil
 	local stacksLeft = nil
 	while (true) do
 		local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable =  UnitAura(target, i, filter);
@@ -181,7 +227,8 @@ local function GetTargetAura(condition, filter, target)
 		end
 		if (not condition.mine or unitCaster=="player") then
 			if (name == auraName and icon == auraIcon) then
-				timeLeft = expirationTime - Ovale.maintenant
+				startTime = expirationTime - duration
+				endTime = expirationTime - Ovale.maintenant
 				stacksLeft = count
 				break
 			end
@@ -195,20 +242,20 @@ local function GetTargetAura(condition, filter, target)
 			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
+					if (not endTime or endTime < newSpell.attenteFinCast) then
 						stacksLeft = 1
 					else
 						stacksLeft = stacksLeft + 1
 					end
-					timeLeft = duration + newSpell.attenteFinCast
+					endTime = duration + newSpell.attenteFinCast
 				else
-					timeLeft = nil
+					endTime = nil
 				end
 			end
 		end
 	end
-	return timeLeft, stacksLeft
-end
+	return endTime, stacksLeft
+end]]

 local lastSaved
 local savedHealth
@@ -234,7 +281,7 @@ local function getTargetDead()
 		end
 	end
 	-- Rough estimation
-	return newHealth * lastSPD
+	return Ovale.maintenant + newHealth * lastSPD
 end

 Ovale.conditions=
@@ -269,13 +316,13 @@ Ovale.conditions=
 	-- 1 : buff spell id
 	-- 2 : expiration time
 	BuffExpires = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HELPFUL", "player")
+		local start, ending = GetTargetAura(condition, "HELPFUL", "player")
 		local timeBefore = avecHate(condition[2], condition.haste)
-		if (not timeLeft or timeLeft<timeBefore) then
-			return 0
-		else
-			return timeLeft-timeBefore
+		if Ovale.trace then
+			Ovale:Print("timeBefore = " .. timeBefore)
+			Ovale:Print("start = " .. ending)
 		end
+		return addTime(ending, -timeBefore)
 	end,
 	-- Test if a time has elapsed since the last buff gain
 	-- 1 : buff spell id
@@ -287,29 +334,29 @@ Ovale.conditions=
 				return 0
 			end
 			local timeGain = Ovale.buff[spell].gain
-			if (not timeGain or (Ovale.maintenant > timeGain + condition[2]) or Ovale.buff[spell].icon~=icon) then
-				return 0
-			else
-				return timeGain + condition[2] - Ovale.maintenant
+			if (not timeGain or Ovale.buff[spell].icon~=icon) then
+				timeGain = 0
 			end
+
+			return timeGain + condition[2]
 		end
-		return nil
+		return 0
 	end,
 	-- Test if a buff is active
 	-- 1 : the buff spell id
 	-- stacks : minimum number of stacks
 	BuffPresent = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HELPFUL", "player")
-
-		return testbool(timeLeft and (not condition.stacks or stacksLeft>=condition.stacks),condition[2])
+		local start, ending = GetTargetAura(condition, "HELPFUL", "player")
+		local timeBefore = avecHate(condition[2], condition.haste)
+		return start, addTime(ending, -timeBefore)
 	end,
 	Casting = function(condition)
-		local spell = UnitCastingInfo("player")
+		local spell, rank, name, icon, start, ending = UnitCastingInfo("player")
 		if (not spell) then
 			return nil
 		end
 		if (Ovale:GetSpellInfoOrNil(condition[1])==spell) then
-			return 0
+			return start/1000, ending/1000
 		else
 			return nil
 		end
@@ -342,24 +389,14 @@ Ovale.conditions=
 		return compare(points, condition[1], condition[2])
 	end,
 	DebuffExpires = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL", "player")
+		local start, ending = GetTargetAura(condition, "HARMFUL", "player")
 		local tempsMax = avecHate(condition[2], condition.haste)
-		if (not timeLeft or timeLeft<tempsMax) then
-			return 0
-		elseif (stacksLeft~=0 and condition.stacks and stacksLeft<condition.stacks) then
-			return 0
-		else
-			return timeLeft-tempsMax
-		end
+		return addTime(ending, -tempsMax)
 	end,
 	DebuffPresent = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL", "player")
-
-		if (timeLeft and (not condition.stacks or stacksLeft>=condition.stacks)) then
-			return 0
-		else
-			return nil
-		end
+		local start, ending = GetTargetAura(condition, "HARMFUL", "player")
+		local timeBefore = avecHate(condition[2], condition.haste)
+		return start, addTime(ending, -timeBefore)
 	end,
 	Glyph = function(condition)
 		local present = false
@@ -470,7 +507,7 @@ Ovale.conditions=
 			local maxTime = condition[3] or 10
 			local minTime
 			for k,v in pairs(otherDebuff) do
-				local diff = v - Ovale.maintenant
+				local diff = v
 				if diff<-maxTime then
 					-- Ovale:Print("enlève obsolète sur "..k)
 					otherDebuff[k] = nil
@@ -482,9 +519,6 @@ Ovale.conditions=
 				return nil
 			end
 			minTime = minTime - timeBefore
-			if minTime<0 then
-				minTime = 0
-			end
 			return minTime
 		end
 	end,
@@ -493,8 +527,8 @@ Ovale.conditions=
 		local otherDebuff = Ovale.otherDebuffs[GetSpellInfo(condition[1])]
 		if otherDebuff then
 			for target,expireTime in pairs(otherDebuff) do
-				if target~=UnitGUID("target") and expireTime>Ovale.maintenant then
-					return 0
+				if target~=UnitGUID("target") then
+					return 0, expireTime
 				end
 			end
 		end
@@ -564,18 +598,9 @@ Ovale.conditions=
 	-- 1 : buff spell id
 	-- stacks : how many stacks
 	TargetBuffPresent = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HELPFUL")
+		local start, ending = GetTargetAura(condition, "HELPFUL")
 		local tempsMin = avecHate(condition[2], condition.haste)
-
-		if (timeLeft and (condition[2]==nil or timeLeft>tempsMin)) then
-			if (stacksLeft~=0 and condition.stacks and stacksLeft<condition.stacks) then
-				return nil
-			else
-				return 0
-			end
-		else
-			return nil
-		end
+		return start, addTime(ending, -tempsMin)
 	end,
 	TargetClass = function(condition)
 		local loc, noloc = UnitClass("target")
@@ -606,7 +631,12 @@ Ovale.conditions=
 		return nil
 	end,
 	TargetDeadIn = function(condition)
-		return compare(getTargetDead(), condition[1], condition[2])
+		local deadAt = getTargetDead()
+		if condition[1] == "more" then
+			return 0, addTime(deadAt, -condition[2])
+		else
+			return addTime(deadAt, -condition[2]), nil
+		end
 	end,
 	-- Test if a debuff will expire on the target after a given time, or if there is less than the
 	-- given number of stacks (if stackable)
@@ -615,33 +645,18 @@ 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")
+		local start, ending = GetTargetAura(condition, "HARMFUL")
 		local tempsMax = avecHate(condition[2], condition.haste)
-		if (not timeLeft or timeLeft<tempsMax) then
-			return 0
-		elseif (stacksLeft~=0 and condition.stacks and stacksLeft<condition.stacks) then
-			return 0
-		else
-			return timeLeft-tempsMax
-		end
+		return addTime(ending, -tempsMax)
 	end,
 	-- Test if a debuff is present on the target
 	-- 1 : debuff spell id
 	-- stacks : how many stacks
 	-- mine : 1 means that the debuff must be yours
 	TargetDebuffPresent = function(condition)
-		local timeLeft, stacksLeft = GetTargetAura(condition, "HARMFUL")
+		local start, ending = GetTargetAura(condition, "HARMFUL")
 		local tempsMin = avecHate(condition[2], condition.haste)
-
-		if (timeLeft and (condition[2]==nil or timeLeft>tempsMin)) then
-			if (stacksLeft~=0 and condition.stacks and stacksLeft<condition.stacks) then
-				return nil
-			else
-				return 0
-			end
-		else
-			return nil
-		end
+		return start, addTime(ending, -tempsMin)
 	end,
 	TargetInRange = function(condition)
 		return testbool(IsSpellInRange(Ovale:GetSpellInfoOrNil(condition[1]),getTarget(condition.target))==1,condition[2])
@@ -682,6 +697,13 @@ Ovale.conditions=
 	TargetTargetIsPlayer = function(condition)
 		return testbool(UnitIsUnit("player","targettarget"), condition[1])
 	end,
+	TimeInCombat = function(condition)
+		if condition[1] == "more" then
+			return Ovale.combatStartTime + condition[2]
+		else
+			return 0, Ovale.combatStartTime + condition[2]
+		end
+	end,
 	TotemExpires = function(condition)
 		local haveTotem, totemName, startTime, duration = GetTotemInfo(totemType[condition[1]])
 		if (totemName==nil) then
@@ -707,7 +729,7 @@ Ovale.conditions=
 			if (condition[2] >= mainHandExpiration) then
 				return 0
 			else
-				return mainHandExpiration - condition[2]
+				return Ovale.maintenant + mainHandExpiration - condition[2]
 			end
 		else
 			if (not hasOffHandEnchant) then
@@ -717,7 +739,7 @@ Ovale.conditions=
 			if (condition[2] >= offHandExpiration) then
 				return 0
 			else
-				return offHandExpiration - condition[2]
+				return Ovale.maintenant + offHandExpiration - condition[2]
 			end
 		end
 	end,
diff --git a/Locale-enUS.lua b/Locale-enUS.lua
index 407e303..5ce7c41 100644
--- a/Locale-enUS.lua
+++ b/Locale-enUS.lua
@@ -36,4 +36,8 @@ L["aoe"] = "Multiple targets Attack"
 L["mana"] = "Mana gain"
 L["Cliquer pour afficher/cacher les options"] = "Click to hide/show options"
 L["Illuminer l'icône"] = "Highlight icon"
-L["Illuminer l'icône quand la technique doit être spammée"] = "Hightlight icon when ability should be spammed"
\ No newline at end of file
+L["Illuminer l'icône quand la technique doit être spammée"] = "Hightlight icon when ability should be spammed"
+L["Prédictif"] = "Two abilities"
+L["Affiche les deux prochains sorts et pas uniquement le suivant"] = "Display two abilities and not only one"
+L["Défilement"] = "Scrolling"
+L["Les icônes se déplacent"] = "Scroll the icons"
\ No newline at end of file
diff --git a/Locale-frFR.lua b/Locale-frFR.lua
index 0cb920e..9f17e35 100644
--- a/Locale-frFR.lua
+++ b/Locale-frFR.lua
@@ -36,4 +36,8 @@ L["aoe"] = "Attaque multi-cible"
 L["mana"] = "Regain de mana"
 L["Cliquer pour afficher/cacher les options"] = true
 L["Illuminer l'icône"] = true
-L["Illuminer l'icône quand la technique doit être spammée"] = true
\ No newline at end of file
+L["Illuminer l'icône quand la technique doit être spammée"] = true
+L["Prédictif"] = "Deux sorts"
+L["Affiche les deux prochains sorts et pas uniquement le suivant"] = true
+L["Défilement"] = true
+L["Les icônes se déplacent"] = true
\ No newline at end of file
diff --git a/Ovale.lua b/Ovale.lua
index 1c8c4cb..ffa6ff0 100644
--- a/Ovale.lua
+++ b/Ovale.lua
@@ -24,7 +24,6 @@ Ovale.enCombat = false
 Ovale.spellHaste = 0
 Ovale.meleeHaste = 0
 Ovale.aura = { player = {}, target = {}}
-Ovale.possibleAura = { player = {}, target = {}}
 Ovale.targetGUID = nil
 Ovale.spellInfo = {}
 Ovale.spellStack = {}
@@ -35,6 +34,7 @@ Ovale.scoreSpell = {}
 Ovale.otherDebuffs = {}
 Ovale.score = 0
 Ovale.maxScore = 0
+Ovale.serial = 0

 Ovale.arbre = {}

@@ -168,21 +168,31 @@ local options =
 				{
 					order = 10,
 					type = "toggle",
-					name = "Predictive (EXPERIMENTAL)",
+					name = L["Prédictif"],
+					desc = L["Affiche les deux prochains sorts et pas uniquement le suivant"],
 					get = function(info) return Ovale.db.profile.apparence.predictif end,
 					set = function(info, value) Ovale.db.profile.apparence.predictif = value; Ovale:UpdateFrame() end
 				},
-				hideEmpty =
+				moving =
 				{
 					order = 11,
 					type = "toggle",
+					name = L["Défilement"],
+					desc = L["Les icônes se déplacent"],
+					get = function(info) return Ovale.db.profile.apparence.moving end,
+					set = function(info, value) Ovale.db.profile.apparence.moving = value; Ovale:UpdateFrame() end
+				},
+				hideEmpty =
+				{
+					order = 12,
+					type = "toggle",
 					name = L["Cacher bouton vide"],
 					get = function(info) return Ovale.db.profile.apparence.hideEmpty end,
 					set = function(info, value) Ovale.db.profile.apparence.hideEmpty = value; Ovale:UpdateFrame() end
 				},
 				targetHostileOnly =
 				{
-					order = 11,
+					order = 13,
 					type = "toggle",
 					name = L["Cacher si cible amicale ou morte"],
 					get = function(info) return Ovale.db.profile.apparence.targetHostileOnly end,
@@ -190,7 +200,7 @@ local options =
 				},
 				highlightIcon =
 				{
-					order = 11,
+					order = 14,
 					type = "toggle",
 					name = L["Illuminer l'icône"],
 					desc = L["Illuminer l'icône quand la technique doit être spammée"],
@@ -541,7 +551,7 @@ function Ovale:CHAT_MSG_ADDON(event, prefix, msg, type, author)

     local value, max = strsplit(";", msg)
     Recount:AddAmount(author, "Ovale", value)
-    Recount:AddAmount(author, "Ovale", max)
+    Recount:AddAmount(author, "OvaleMax", max)
 end

 function Ovale:PLAYER_REGEN_ENABLED()
@@ -559,6 +569,7 @@ function Ovale:PLAYER_REGEN_DISABLED()
 	self.enCombat = true
 	self.score = 0
 	self.maxScore = 0
+	self.combatStartTime = self.maintenant

 	self:UpdateVisibility()
 end
@@ -752,59 +763,144 @@ function Ovale:AddRune(time, type, value)
 	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] = {}
+function Ovale:GetAura(target, filter, spellId)
+	if not self.aura[target] then
+		self.aura[target] = {}
+	end
+	if not self.aura[target][filter] then
+		self.aura[target][filter] = {}
+	end
+	if not self.aura[target][filter][spellId] then
+		self.aura[target][filter][spellId] = {}
+	end
+	local myAura = self.aura[target][filter][spellId]
+	if myAura.serial == Ovale.serial then
+		return myAura
+	end
+
+	myAura.mine = false
+	myAura.start = nil
+	myAura.ending = nil
+	myAura.stacks = 0
+	myAura.serial = Ovale.serial
+
+	local i = 1
+	local auraName, auraRank, auraIcon = self:GetSpellInfoOrNil(spellId)
+
+	while (true) do
+		local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable =  UnitAura(target, i, filter);
+		if not name then
+			break
+		end
+		if (unitCaster=="player" or not myAura.mine) and name == auraName and icon==auraIcon then
+			myAura.mine = (unitCaster == "player")
+			myAura.start = expirationTime - duration
+			myAura.ending = expirationTime
+			if count and count>0 then
+				myAura.stacks = count
+			else
+				myAura.stacks = 1
+			end
+			if myAura.mine then
+				break
+			end
+		end
+		i = i + 1;
 	end
-	local newSpell = self.spellStack[self.spellStack.length]
-	newSpell.attenteFinCast = endCast
+	return myAura
+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
+
+	local newSpellInfo = nil
 	if spellName then
-		newSpell.info = self.spellInfo[spellName]
-	else
-		newSpell.info = nil
+		newSpellInfo = self.spellInfo[spellName]
 	end
+
+	self.attenteFinCast = nextCast
 	self.currentSpellName = spellName
 	self.startCast = startCast
-	self.attenteFinCast = nextCast
+	self.currentTime = nextCast
+
+	if Ovale.trace then
+		Ovale:Print("add spell "..spellName.." at "..startCast.." currentTime = "..nextCast)
+	end
+
 	if startCast>=0 then
-		if newSpell.info then
-			if newSpell.info.combo then
-				self.state.combo = self.state.combo + newSpell.info.combo
+		if newSpellInfo then
+			if newSpellInfo.combo then
+				self.state.combo = self.state.combo + newSpellInfo.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)
+			if newSpellInfo.frost then
+				self:AddRune(startCast, 3, newSpellInfo.frost)
 			end
-			if newSpell.info.death then
-				self:AddRune(startCast, 4, newSpell.info.death)
+			if newSpellInfo.death then
+				self:AddRune(startCast, 4, newSpellInfo.death)
 			end
-			if newSpell.info.blood then
-				self:AddRune(startCast, 1, newSpell.info.blood)
+			if newSpellInfo.blood then
+				self:AddRune(startCast, 1, newSpellInfo.blood)
 			end
-			if newSpell.info.unholy then
-				self:AddRune(startCast, 2, newSpell.info.unholy)
+			if newSpellInfo.unholy then
+				self:AddRune(startCast, 2, newSpellInfo.unholy)
 			end
 		end
 	end

-	if newSpell.info then
-		if newSpell.info.cd then
+	if newSpellInfo then
+		if newSpellInfo.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].start = startCast
+			self.state.cd[spellName].duration = newSpellInfo.cd
 			self.state.cd[spellName].enable = 1
 		end
-		if newSpell.info.toggle then
+		if newSpellInfo.toggle then
 			if not self.state.cd[spellName] then
 				self.state.cd[spellName] = {}
 			end
 			self.state.cd[spellName].toggled = 1
 		end
+		if newSpellInfo.aura then
+			for target, targetInfo in pairs(newSpellInfo.aura) do
+				for filter, filterInfo in pairs(targetInfo) do
+					for spell, spellData in pairs(filterInfo) do
+						local newAura = self:GetAura(target, filter, spell)
+						newAura.mine = true
+						local duration = spellData
+						local spellName = self:GetSpellInfoOrNil(spell)
+						if spellName and self.spellInfo[spellName] and self.spellInfo[spellName].duration then
+							duration = self.spellInfo[spellName].duration
+						end
+						if newAura.ending and newAura.ending >= endCast then
+							newAura.ending = endCast + duration
+							newAura.stacks = newAura.stacks + 1
+						else
+							newAura.start = endCast
+							newAura.ending = endCast + duration
+							newAura.stacks = 1
+						end
+						if Ovale.trace then
+							self:Print("adding aura "..spellName.." to "..target.." "..newAura.start..","..newAura.ending)
+						end
+					end
+				end
+			end
+		end
 	end
 end

@@ -814,8 +910,10 @@ function Ovale:InitAllActions()
 end

 function Ovale:InitCalculerMeilleureAction()
-	self.attenteFinCast = 0
+	self.serial = self.serial + 1
+	self.currentTime = Ovale.maintenant
 	self.currentSpellName = nil
+	self.attenteFinCast = Ovale.maintenant
 	self.spellStack.length = 0
 	self.state.combo = GetComboPoints("player")
 	if self.className == "DEATHKNIGHT" then
@@ -842,12 +940,12 @@ function Ovale:InitCalculerMeilleureAction()
 	-- On attend que le sort courant soit fini
 	local spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitCastingInfo("player")
 	if (spell) then
-		self:AddSpellToStack(spell, startTime/1000 - Ovale.maintenant, endTime/1000 - Ovale.maintenant, endTime/1000 - Ovale.maintenant)
+		self:AddSpellToStack(spell, startTime/1000, endTime/1000, endTime/1000)
 	end

 	local spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitChannelInfo("player")
 	if (spell) then
-		self:AddSpellToStack(spell, startTime/1000 - Ovale.maintenant, endTime/1000 - Ovale.maintenant, endTime/1000 - Ovale.maintenant)
+		self:AddSpellToStack(spell, startTime/1000, endTime/1000, endTime/1000)
 	end
 end

@@ -987,6 +1085,30 @@ function Ovale:GetActionInfo(element)
 					actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName, target, element.params.nored
 end

+local function nilstring(text)
+	if text == nil then
+		return "nil"
+	else
+		return text
+	end
+end
+
+local function addTime(time1, duration)
+	if not time1 then
+		return nil
+	else
+		return time1 + duration
+	end
+end
+
+local function isBefore(time1, time2)
+	return time1 and (not time2 or time1<time2)
+end
+
+local function isAfter(time1, time2)
+	return not time1 or (time2 and time1>time2)
+end
+
 function Ovale:CalculerMeilleureAction(element)
 	if (self.bug and not self.trace) then
 		return nil
@@ -1026,7 +1148,7 @@ function Ovale:CalculerMeilleureAction(element)
 				if (not actionCooldownDuration or actionCooldownStart==0) then
 					restant = 0
 				else
-					restant = actionCooldownDuration - (self.maintenant - actionCooldownStart);
+					restant = actionCooldownDuration + actionCooldownStart
 				end

 				if restant<self.attenteFinCast then
@@ -1058,7 +1180,7 @@ function Ovale:CalculerMeilleureAction(element)
 				if (not retourPriorite) then
 					retourPriorite = 3
 				end
-				return restant, retourPriorite, element
+				return restant, nil, retourPriorite, element
 			else
 				if (Ovale.trace) then
 					self:Print("Action "..element.params[1].." not enabled")
@@ -1071,31 +1193,20 @@ function Ovale:CalculerMeilleureAction(element)
 				self:Print("Function "..element.func.." not found")
 				return nil
 			end
-			local temps = classe(element.params)
+			local start, ending = classe(element.params)

 			if (Ovale.trace) then
-				if (temps==nil) then
-					self:Print("Function "..element.func.." returned nil")
-				else
-					self:Print("Function "..element.func.." returned "..temps)
-				end
+				self:Print("Function "..element.func.." returned "..nilstring(start)..","..nilstring(ending))
 			end

-			return temps
+			return start, ending
 		end
 	elseif (element.type == "before") then
 		if (Ovale.trace) then
 			self:Print(element.time.."s before")
 		end
-		local tempsA = Ovale:CalculerMeilleureAction(element.a)
-		if (tempsA==nil) then
-			return nil
-		end
-		if (tempsA<element.time) then
-			return 0
-		else
-			return tempsA - element.time
-		end
+		local startA, endA = Ovale:CalculerMeilleureAction(element.a)
+		return addTime(startA, -element.time), addTime(endA, -element.time)
 	elseif (element.type == "between") then
 		if (Ovale.trace) then
 			self:Print(element.time.."s between")
@@ -1118,49 +1229,66 @@ function Ovale:CalculerMeilleureAction(element)
 		if (Ovale.trace) then
 			self:Print(element.type)
 		end
-		local tempsA = Ovale:CalculerMeilleureAction(element.a)
-		if (tempsA==nil) then
+		local startA, endA = Ovale:CalculerMeilleureAction(element.a)
+		if (startA==nil) then
 			return nil
 		end
-		local tempsB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b)
-		if (tempsB==nil) then
+		local startB, endB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b)
+		if isAfter(startB, endA) or isAfter(startA, endB) then
+			if Ovale.trace then Ovale:Print(element.type.." return nil") end
 			return nil
 		end
-		if (tempsB>tempsA) then
-			return  tempsB, prioriteB, elementB
-		else
-			return  tempsA, prioriteB, elementB
+		if isBefore(startB, startA) then
+			startB = startA
+		end
+		if isAfter(endB, endA) then
+			endB = endA
+		end
+		if Ovale.trace then
+			Ovale:Print(element.type.." return "..nilstring(startB)..","..nilstring(endB))
 		end
+		return startB, endB, prioriteB, elementB
 	elseif (element.type == "unless") then
 		if (Ovale.trace) then
 			self:Print(element.type)
 		end
-		local tempsA = Ovale:CalculerMeilleureAction(element.a)
-		if (tempsA==0) then
+		local startA, endA = Ovale:CalculerMeilleureAction(element.a)
+		local startB, endB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b)
+
+		if isBefore(startA, startB) and isAfter(endA, endB) then
 			return nil
 		end
-		local tempsB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b)
-		if (tempsA==nil or tempsA>tempsB) then
-			return tempsB, prioriteB, elementB
-		else
-			return nil
+
+		if isAfter(startA, startB) and isBefore(endA, endB) then
+			return endA, endB, prioriteB, elementB
 		end
+
+		if isAfter(startA, startB) and isBefore(startA, endB) then
+			endB = startA
+		end
+
+		if isAfter(endA, startB) and isBefore(endA, endB) then
+			startB = endA
+		end
+
+		return startB, endB, prioriteB, elementB
 	elseif (element.type == "or") then
 		if (Ovale.trace) then
 			self:Print(element.type)
 		end

-		local tempsA = Ovale:CalculerMeilleureAction(element.a)
-		local tempsB = Ovale:CalculerMeilleureAction(element.b)
-		if (tempsB==nil or (tempsA~=nil and tempsB>tempsA)) then
-			if (Ovale.trace) then printTime(tempsA) end
-			return tempsA
-		else
-			if (Ovale.trace) then printTime(tempsB) end
-			return tempsB
+		local startA, endA = Ovale:CalculerMeilleureAction(element.a)
+		local startB, endB = Ovale:CalculerMeilleureAction(element.b)
+		if isBefore(startA, startB) then
+			startB = startA
+		end
+		if isAfter(endA, endB) then
+			endB = endA
 		end
+		return startB, endB
 	elseif (element.type == "group") then
 		local meilleurTempsFils
+		local bestEnd
 		local meilleurePrioriteFils
 		local bestElement

@@ -1169,8 +1297,12 @@ function Ovale:CalculerMeilleureAction(element)
 		end

 		for k, v in ipairs(element.nodes) do
-			local nouveauTemps, priorite, nouveauElement = Ovale:CalculerMeilleureAction(v)
-			if (nouveauTemps) then
+			local newStart, newEnd, priorite, nouveauElement = Ovale:CalculerMeilleureAction(v)
+			if newStart and newStart<Ovale.currentTime then
+				newStart = Ovale.currentTime
+			end
+
+			if newStart and (not newEnd or newStart<=newEnd) then
 				local remplacer

 				if (not meilleurTempsFils) then
@@ -1194,14 +1326,15 @@ function Ovale:CalculerMeilleureAction(element)
 					else
 						maxEcart = -0.01
 					end
-					if (nouveauTemps-meilleurTempsFils < maxEcart) then
+					if (newStart-meilleurTempsFils < maxEcart) then
 						remplacer = true
 					end
 				end
 				if (remplacer) then
-					meilleurTempsFils = nouveauTemps
+					meilleurTempsFils = newStart
 					meilleurePrioriteFils = priorite
 					bestElement = nouveauElement
+					bestEnd = newEnd
 				end
 			end
 		end
@@ -1210,7 +1343,7 @@ function Ovale:CalculerMeilleureAction(element)
 			if (Ovale.trace) then
 				self:Print("Best action "..bestElement.params[1].." remains "..meilleurTempsFils)
 			end
-			return meilleurTempsFils,meilleurePrioriteFils, bestElement
+			return meilleurTempsFils, bestEnd, meilleurePrioriteFils, bestElement
 		else
 			if (Ovale.trace) then printTime(nil) end
 			return nil
@@ -1330,7 +1463,7 @@ end

 function Ovale:GetSpellInfo(spell)
 	if (not self.spellInfo[spell]) then
-		self.spellInfo[spell] = { player = {}, target = {}}
+		self.spellInfo[spell] = { aura = {player = {}, target = {}} }
 	end
 	return self.spellInfo[spell]
 end
diff --git a/Ovale.toc b/Ovale.toc
index 3cc8b03..3cfde88 100644
--- a/Ovale.toc
+++ b/Ovale.toc
@@ -3,7 +3,7 @@
 ## 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.19
+## Version: 3.2.20
 ## OptionalDeps: Ace3, ButtonFacade, Recount
 ## SavedVariables: OvaleDB
 ## SavedVariablesPerCharacter: OvaleDBPC
diff --git a/OvaleCompile.lua b/OvaleCompile.lua
index 8da8a35..3f1a402 100644
--- a/OvaleCompile.lua
+++ b/OvaleCompile.lua
@@ -37,7 +37,7 @@ local function ParseSpellAddDebuff(params)
 	local paramList = ParseParameters(params)
 	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
 	if (spell) then
-		Ovale:GetSpellInfo(spell).player.HARMFUL = paramList
+		Ovale:GetSpellInfo(spell).aura.player.HARMFUL = paramList
 	end
 	return ""
 end
@@ -46,7 +46,7 @@ local function ParseSpellAddBuff(params)
 	local paramList = ParseParameters(params)
 	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
 	if (spell) then
-		Ovale:GetSpellInfo(spell).player.HELPFUL = paramList
+		Ovale:GetSpellInfo(spell).aura.player.HELPFUL = paramList
 	end
 	return ""
 end
@@ -55,7 +55,7 @@ local function ParseSpellAddTargetDebuff(params)
 	local paramList = ParseParameters(params)
 	local spell = Ovale:GetSpellInfoOrNil(paramList[1])
 	if (spell) then
-		Ovale:GetSpellInfo(spell).target.HARMFUL = paramList
+		Ovale:GetSpellInfo(spell).aura.target.HARMFUL = paramList
 	end
 	return ""
 end
diff --git a/OvaleFrame.lua b/OvaleFrame.lua
index 0399cd2..bdfea13 100644
--- a/OvaleFrame.lua
+++ b/OvaleFrame.lua
@@ -142,24 +142,27 @@ do
 	local function OnUpdate(self)
 		Ovale:InitAllActions()
 		for k,node in pairs(Ovale.masterNodes) do
+			if Ovale.trace then
+				Ovale:Print("****Master Node "..k)
+			end
 			Ovale:InitCalculerMeilleureAction()
-			local minAttente, priorite, element = Ovale:CalculerMeilleureAction(node)
+			local start, ending, priorite, element = Ovale:CalculerMeilleureAction(node)

 			local action = self.actions[k]

 			local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
 					actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName, actionTarget, noRed = Ovale:GetActionInfo(element)

-			if (node.params.nocd and node.params.nocd == 1 and minAttente~=nil and minAttente>1.5) then
+			if (node.params.nocd and node.params.nocd == 1 and start~=nil and start>Ovale.maintenant+1.5) then
 				action.icons[1]:Update(nil)
 			else
-				action.icons[1]:Update(minAttente, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
+				action.icons[1]:Update(start, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
 					actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName, actionTarget, noRed)
 			end

 			action.spellName = spellName

-			if minAttente == 0 and actionUsable then
+			if start == Ovale.maintenant and actionUsable then
 				if not action.waitStart then
 					action.waitStart = Ovale.maintenant
 				end
@@ -167,39 +170,63 @@ do
 				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)
+			if Ovale.db.profile.apparence.moving 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)
+				if action.icons[2] then
 					action.icons[2]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",action.left + (top+1)*action.dx,action.top - (top+1)*action.dy)
+				end
+			end
+
+			if (node.params.size ~= "small" and not node.params.nocd and Ovale.db.profile.apparence.predictif) then
+				if start then
 					local castTime=0
 					if spellName then
 						local _, _, _, _, _, _, _castTime = GetSpellInfo(spellName)
-						if _castTime then
+						if _castTime and _castTime>0 then
 							castTime = _castTime/1000
 						end
 					end
 					local gcd = Ovale:GetGCD(spellName)
 					local nextCast
 					if (castTime>gcd) then
-						nextCast = minAttente + castTime
+						nextCast = start + castTime
 					else
-						nextCast = minAttente + gcd
+						nextCast = start + gcd
 					end
-					Ovale:AddSpellToStack(spellName, minAttente, minAttente + castTime, nextCast)
-					minAttente, priorite, element = Ovale:CalculerMeilleureAction(node)
-					action.icons[2]:Update(minAttente, Ovale:GetActionInfo(element))
+					if Ovale.trace then
+						Ovale:Print("****Second icon")
+					end
+					Ovale:AddSpellToStack(spellName, start, start + castTime, nextCast)
+					start, ending, priorite, element = Ovale:CalculerMeilleureAction(node)
+					action.icons[2]:Update(start, Ovale:GetActionInfo(element))
 				else
 					action.icons[2]:Update(nil)
 				end
 			end
 		end
+
+		if (not Ovale.bug) then
+			Ovale.traced = false
+		end
+
+		if (Ovale.trace) then
+			Ovale.trace=false
+			Ovale.traced = true
+		end
+
+		if (Ovale.bug and not Ovale.traced) then
+			Ovale.trace = true
+		end
+
+		if noRed then
+			minAttente = actionCooldownStart + actionCooldownDuration
+		end
 	end

 	local function UpdateIcons(self)
diff --git a/OvaleIcone.lua b/OvaleIcone.lua
index 4f9dd85..a9106bd 100644
--- a/OvaleIcone.lua
+++ b/OvaleIcone.lua
@@ -4,35 +4,19 @@ local L = LibStub("AceLocale-3.0"):GetLocale("Ovale")
 local function Update(self, minAttente, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration,
 				actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellName, actionTarget, noRed)

-	if (not Ovale.bug) then
-		Ovale.traced = false
-	end
-
-	if (Ovale.trace) then
-		Ovale.trace=false
-		Ovale.traced = true
-	end
-
-	if (Ovale.bug and not Ovale.traced) then
-		Ovale.trace = true
-	end
-
-	if noRed then
-		minAttente = actionCooldownStart + actionCooldownDuration - Ovale.maintenant
-	end

 	if (minAttente~=nil and actionTexture) then

 		if (actionTexture~=self.actionCourante or self.ancienneAttente==nil or
-			(minAttente~=0 and minAttente>self.ancienneAttente+0.01) or
-			(Ovale.maintenant + minAttente < self.finAction-0.01)) then
+			(minAttente~=Ovale.maintenant and minAttente>self.ancienneAttente+0.01) or
+			(minAttente < self.finAction-0.01)) then
 			if (actionTexture~=self.actionCourante or self.ancienneAttente==nil or
-					(minAttente~=0 and minAttente>self.ancienneAttente+0.01)) then
+					(minAttente~=Ovale.maintenant and minAttente>self.ancienneAttente+0.01)) then
 				self.debutAction = Ovale.maintenant
 			end
 			self.actionCourante = actionTexture
-			self.finAction = minAttente + Ovale.maintenant
-			if (minAttente == 0) then
+			self.finAction = minAttente
+			if (minAttente == Ovale.maintenant) then
 				self.cd:Hide()
 			else
 				self.cd:Show()
@@ -53,7 +37,7 @@ local function Update(self, minAttente, actionTexture, actionInRange, actionCool
 		end

 		local red
-		if (Ovale.maintenant + minAttente > actionCooldownStart + actionCooldownDuration + 0.01 and minAttente > 0
+		if (minAttente > actionCooldownStart + actionCooldownDuration + 0.01 and minAttente > Ovale.maintenant
 			and minAttente>Ovale.attenteFinCast) then
 			self.icone:SetVertexColor(0.75,0.2,0.2)
 			red = true
@@ -61,15 +45,15 @@ local function Update(self, minAttente, actionTexture, actionInRange, actionCool
 			self.icone:SetVertexColor(1,1,1)
 		end

-		if (minAttente==0) then
+		if (minAttente==Ovale.maintenant) then
 			self.cd:Hide()
 		end

 		-- La latence
-		if minAttente>0 and Ovale.db.profile.apparence.highlightIcon and not red then
+		if minAttente>Ovale.maintenant and Ovale.db.profile.apparence.highlightIcon and not red then
 			local lag = 0.6
 			local newShouldClick
-			if minAttente<lag then
+			if minAttente<Ovale.maintenant + lag then
 				newShouldClick = true
 			else
 				newShouldClick = false
diff --git a/defaut/Chaman.lua b/defaut/Chaman.lua
index 1eef4ac..057f322 100644
--- a/defaut/Chaman.lua
+++ b/defaut/Chaman.lua
@@ -67,6 +67,7 @@ SpellInfo(LAVABURST cd=8)
 SpellInfo(CHAINLIGHTNING cd=6)
 SpellAddBuff(LIGHTNINGBOLT MAELSTROMWEAPON=0)
 SpellAddBuff(CHAINLIGHTNING MAELSTROMWEAPON=0)
+SpellAddTargetDebuff(FLAMESHOCK FLAMESHOCK=18)
 ScoreSpells(WATERSHIELD FLAMESHOCK LAVABURST CHAINLIGHTNING LIGHTNINGBOLT LAVALASH EARTHSHOCK LIGHTNINGSHIELD
 	STORMSTRIKE)

diff --git a/defaut/Chasseur.lua b/defaut/Chasseur.lua
index ec808c1..c158794 100644
--- a/defaut/Chasseur.lua
+++ b/defaut/Chasseur.lua
@@ -17,6 +17,19 @@ Define(TALENTEXPLOSIVESHOT 2145)
 Define(CALLOFTHEWILD 53434)
 Define(CHIMERASHOT 53209)

+SpellAddTargetDebuff(EXPLOSIVESHOT EXPLOSIVESHOT=2)
+SpellInfo(EXPLOSIVESHOT cd=6)
+SpellAddTargetDebuff(SERPENTSTING SERPENTSTING=15)
+SpellAddTargetDebuff(BLACKARROW BLACKARROW=15)
+SpellInfo(BLACKARROW cd=26)
+SpellInfo(KILLSHOT cd=15)
+SpellInfo(AIMEDSHOT cd=10)
+SpellInfo(CHIMERASHOT cd=10)
+SpellInfo(RAPIDFIRE cd=300)
+SpellInfo(KILLCOMMAND cd=60)
+SpellInfo(BESTIALWRATH cd=120)
+SpellAddTargetDebuff(HUNTERSMARK HUNTERSMARK=300)
+
 AddCheckBox(multi SpellName(MULTISHOT))
 ScoreSpells(HUNTERSMARK BLACKARROW SERPENTSTING CHIMERASHOT AIMEDSHOT MULTISHOT ARCANESHOT KILLSHOT STEADYSHOT)

@@ -32,7 +45,7 @@ AddIcon help=main
 	unless TalentPoints(TALENTEXPLOSIVESHOT more 0) Spell(ARCANESHOT)
 	if TargetLifePercent(less 20) Spell(KILLSHOT)
 	if TargetDebuffExpires(HUNTERSMARK 2) Spell(HUNTERSMARK nored=1)
-	unless TargetDebuffPresent(EXPLOSIVESHOT mine=1) and {2s before Spell(EXPLOSIVESHOT)} Spell(STEADYSHOT)
+	unless 1.5s before Spell(EXPLOSIVESHOT) Spell(STEADYSHOT)
 }

 AddIcon help=cd
diff --git a/defaut/Demoniste.lua b/defaut/Demoniste.lua
index 8b0eb10..12dc885 100644
--- a/defaut/Demoniste.lua
+++ b/defaut/Demoniste.lua
@@ -37,8 +37,13 @@ AddListItem(curse weakness SpellName(CURSEWEAKNESS))
 SpellInfo(HAUNT cd=8)
 SpellInfo(CONFLAGRATE cd=10)
 SpellInfo(CHAOSBOLT cd=12)
+SpellAddTargetDebuff(CORRUPTION CORRUPTION=18)
+SpellAddTargetDebuff(CURSEAGONY CURSEAGONY=24)
+SpellAddTargetDebuff(CURSEELEMENTS CURSEELEMENTS=300)
+SpellAddTargetDebuff(CURSEDOOM CURSEDOOM=60)
 SpellAddTargetDebuff(UNSTABLEAFFLICTION UNSTABLEAFFLICTION=15)
 SpellAddTargetDebuff(IMMOLATE IMMOLATE=15)
+SpellAddBuff(SHADOWBOLT SHADOWEMBRACE=12)
 ScoreSpells(CURSEELEMENTS SHADOWBOLT HAUNT UNSTABLEAFFLICTION IMMOLATE CONFLAGRATE CURSEDOOM CURSETONGUES CURSEWEAKNESS
 	CURSEAGONY CORRUPTION SOULFIRE DRAINSOUL INCINERATE SHADOWBOLT)