------------------------------------------------------------------------------------------------------
-- Necrosis LdC
--
-- Créateur initial (US) : Infernal (http://www.revolvus.com/games/interface/necrosis/)
-- Implémentation de base (FR) : Tilienna Thorondor
-- Reprise du projet : Lomig & Nyx des Larmes de Cenarius, Kael'Thas
-- 
-- Skins et voix Françaises : Eliah, Ner'zhul
-- Version Allemande par Arne Meier
-- Remerciements spéciaux pour Sadyre (JoL)
-- Version 11.01.2005-1
------------------------------------------------------------------------------------------------------

-- Configuration par défaut
-- Se charge en cas d'absence de configuration ou de changement de version
Default_NecrosisConfig = {
	Version = NecrosisData.Version;
	SoulshardContainer = 4;
	SoulshardSort = true;
	SoulshardDestroy = false;
	ShadowTranceAlert = true;
	ShowSpellTimers = true;
	AntiFearAlert = true;
	NecrosisLockServ = true;
	NecrosisAngle = 180;
	StonePosition = {true, true, true, true, true, true, true};
	NecrosisToolTip = true;
	NoDragAll = false;
	PetMenuPos = 34;
	BuffMenuPos = 34;
	ChatMsg = true;
	ChatType = true;
	NecrosisLanguage = GetLocale();
	ShowCount = true;
	CountType = 1;
	ShadowTranceScale = 100;
	NecrosisButtonScale = 100;
	NecrosisColor = "Rose";
	Sound = true;
	SpellTimerPos = 23;
	SpellTimerJust = "LEFT";
	Circle = 1;
};

NecrosisConfig = {};
local Debug = false;
local Loaded = false;

-- Initialisation des variables utilisées par Necrosis
local SpellCastName = nil;
local SpellTargetName = nil;
local SpellTargetLevel = nil;
local SpellCastTime = 0;

-- Initialisation du tableau qui comportera les Timers
local SpellTimer = {
	Name = {},
	Time = {},
	TimeMax = {},
	Type = {},
	Target = {},
	TargetLevel = {},
	Group = {}
};
local SpellGroup = {
	Name = {"Rez", "Main", "Cooldown"},
	SubName = {" ", " ", " "},
	Visible = {true, true, true}
};

-- Permet la disparition du menu des pets (transparence)
local AlphaPetMenu = 1;
local AlphaPetVar = 0;
local PetVisible = false;

-- Permet la disparition du menu des buffs (transparence)
local AlphaBuffMenu = 1;
local AlphaBuffVar = 0;
local BuffVisible = false;

local PetMenuCreate = {};
local BuffMenuCreate = {};

local lOriginal_GameTooltip_ClearMoney;
local MountAvailable = false;
local NecrosisMounted = false;

local NecrosisRL = true;
local ShadowTrance = false;
local AntiFearInUse = false;
local ShadowTranceID = -1;

local Soulshards = 0;
local SoulshardContainer = 4;
local SoulshardSlot = {};
local SoulshardSlotID = 1;
local SoulshardMP = 0;
local SoulshardTime = 0;

local InfernalStone = 0;
local DemoniacStone = 0;


local StoneIDInSpellTable = {0, 0, 0, 0}
local SoulstoneUsedOnTarget = false;
local SoulstoneOnHand = false;
local SoulstoneLocation = {nil,nil};
local SoulstoneMode = 1;
local SoulstonePreMode = 1;
local HealthstoneOnHand = false;
local HealthstoneLocation = {nil,nil};
local HealthstoneMode = 1;
local FirestoneOnHand = false;
local FirestoneLocation = {nil,nil};
local FirestoneMode = 1;
local SpellstoneOnHand = false;
local SpellstoneLocation = {nil,nil};
local SpellstoneMode = 1;
local HearthstoneOnHand = false;
local HearthstoneLocation = {nil,nil};
local ItemswitchLocation = {nil,nil};
local ItemOnHand = false;

local DemonType = nil;
local DemonEnslaved = false;
local Demon = {
	Spell = {},
	Time = {},
	Cooldown = {}
}

local AFblink1, AFBlink2 = 0;
local AFImageType = { "", "Immu", "Prot"}; -- Fear warning button filename variations
local AFCurrentTargetImmune = false;

local PetMenuShow = false;
local BuffMenuShow = false;

local NecrosisTradeRequest = false;
local Trading = false;
local TradingNow = 0;


------------------------------------------------------------------------------------------------------
-- FONCTIONS NECROSIS
------------------------------------------------------------------------------------------------------


-- Fonction appliquée au chargement
function Necrosis_OnLoad()
	
	-- Permet de repérer les sorts lancés A L'APPUI SUR LE RACCOURCI
	Necrosis_Hook("UseAction", "Necrosis_UseAction", "before");
	
	-- Enregistrement des événements interceptés par Necrosis
	this:RegisterEvent("UNIT_NAME_UPDATE");
	this:RegisterEvent("BAG_UPDATE");
	this:RegisterEvent("CHAT_MSG_MONSTER_EMOTE");
	this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS");
	this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_SELF");
	this:RegisterEvent("CHAT_MSG_SPELL_BREAK_AURA");
	this:RegisterEvent("PLAYER_REGEN_DISABLED");
	this:RegisterEvent("PLAYER_REGEN_ENABLED");
	this:RegisterEvent("UNIT_PET");
	this:RegisterEvent("SPELLCAST_START");
	this:RegisterEvent("SPELLCAST_FAILED");
	this:RegisterEvent("SPELLCAST_INTERRUPTED");
	this:RegisterEvent("SPELLCAST_STOP");
	this:RegisterEvent("UNIT_COMBAT");
	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("LEARNED_SPELL_IN_TAB");
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE");
	this:RegisterEvent("PLAYER_TARGET_CHANGED");
	this:RegisterEvent("TRADE_REQUEST");
	this:RegisterEvent("TRADE_REQUEST_CANCEL");
	this:RegisterEvent("TRADE_SHOW");
	this:RegisterEvent("TRADE_CLOSED");
	
	-- Enregistrement des composants graphiques
	NecrosisButton:RegisterForDrag("LeftButton");
	NecrosisButton:RegisterForClicks("LeftButtonUp", "RightButtonUp");
	NecrosisButton:SetFrameLevel(1);

	-- Enregistrement de la commande console
	SlashCmdList["NecrosisCommand"] = Necrosis_SlashHandler;
	SLASH_NecrosisCommand1 = "/necro";
end

function Necrosis_LoadVariables()
	if Loaded or UnitClass("player") ~= NECROSIS_UNIT_WARLOCK then
		return
	end
	
	Necrosis_Initialize();
	Loaded = true ;

	-- Détection du type de démon présent à la connexion
	DemonType = UnitCreatureFamily("pet");
	if (DemonType) then
		Demon.Spell = NecrosisDemon[DemonType].Spell;
		Demon.Time = NecrosisDemon[DemonType].Time;
		Demon.Cooldown = NecrosisDemon[DemonType].Cooldown;
	end
end

-- Fonction lancée à la mise à jour de l'interface (main) -- toutes les 0,1 secondes environ
function Necrosis_OnUpdate()
	-- La fonction n'est utilisée que si Necrosis est initialisé et le joueur un Démoniste
	if (not Loaded) and UnitClass("player") ~= NECROSIS_UNIT_WARLOCK then
		return;
	end
	
	-- Gestion des fragments d'âme : Tri des fragment toutes les secondes
	local curTime = GetTime();
	if ((curTime-SoulshardTime) >= 1) then
		SoulshardTime = curTime;
		if (SoulshardMP > 0) then
			Necrosis_SoulshardSwitch("MOVE");
		end
	end

	-- Gestion des sorts du Démoniste
	----------------------------------------------------------
	
	-- Gestion du menu d'invocation des démons
	if NecrosisPetMenu2:IsVisible() then
		if GetTime() >= AlphaPetVar and AlphaPetMenu > 0 and (not PetVisible) then
			AlphaPetVar = GetTime() + 0.1;
			NecrosisPetMenu1:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu2:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu3:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu4:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu5:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu6:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu7:SetAlpha(AlphaPetMenu);
			NecrosisPetMenu8:SetAlpha(AlphaPetMenu);
			AlphaPetMenu = AlphaPetMenu - 0.1;
		end
		if AlphaPetMenu <= 0 then
			Necrosis_PetMenu();
		end
	end

	-- Gestion du menu des Buffs
	if NecrosisBuffMenu1:IsVisible() then
		if GetTime() >= AlphaBuffVar and AlphaBuffMenu > 0 and (not BuffVisible) then
			AlphaBuffVar = GetTime() + 0.1;
			NecrosisBuffMenu1:SetAlpha(AlphaBuffMenu);
			NecrosisBuffMenu2:SetAlpha(AlphaBuffMenu);
			NecrosisBuffMenu3:SetAlpha(AlphaBuffMenu);
			NecrosisBuffMenu4:SetAlpha(AlphaBuffMenu);
			NecrosisBuffMenu5:SetAlpha(AlphaBuffMenu);
			NecrosisBuffMenu6:SetAlpha(AlphaBuffMenu);
			NecrosisBuffMenu7:SetAlpha(AlphaBuffMenu);
			AlphaBuffMenu = AlphaBuffMenu - 0.1;
		end
		if AlphaBuffMenu <= 0 then
			Necrosis_BuffMenu();
		end
	end
	
	-- Gestion du talent "Crépuscule"
	if NecrosisConfig.ShadowTranceAlert then
		local Actif = false;
		local TimeLeft = 0;
		Necrosis_UnitHasTrance();
   		if ShadowTranceID ~= -1 then Actif = true; end
		if Actif and not ShadowTrance then
			ShadowTrance = true;
			Necrosis_Msg(NECROSIS_NIGHTFALL_TEXT.Message, "USER");
			if NecrosisConfig.Sound then PlaySoundFile(NECROSIS_SOUND.ShadowTrance); end
			local ShadowTranceIndex, cancel = GetPlayerBuff(ShadowTranceID,"HELPFUL|HARMFUL|PASSIVE");
			TimeLeft = floor(GetPlayerBuffTimeLeft(ShadowTranceIndex));
			NecrosisShadowTranceTimer:SetText(TimeLeft);
			ShowUIPanel(NecrosisShadowTranceButton);
		end
		if not Actif and ShadowTrance then
			HideUIPanel(NecrosisShadowTranceButton);
			ShadowTrance = false;
		end
		if Actif and ShadowTrance then
			local ShadowTranceIndex, cancel = GetPlayerBuff(ShadowTranceID,"HELPFUL|HARMFUL|PASSIVE");
			TimeLeft = floor(GetPlayerBuffTimeLeft(ShadowTranceIndex));
			NecrosisShadowTranceTimer:SetText(TimeLeft);
		end
	end

	-- Gestion des Antifears
		-- Gestion des Antifears
	if NecrosisConfig.AntiFearAlert then
		local Actif = false; -- must be False, or a number from 1 to AFImageType[] max element.
		
		-- Checking if we have a target. Any fear need a target to be casted on
		if UnitExists("target") then
			-- Checking if the target has natural immunity (only NPC target)
			if not UnitIsPlayer("target") then 				
				for index=1, table.getn(NECROSIS_ANTI_FEAR_UNIT), 1 do
					if (UnitCreatureType("target") == NECROSIS_ANTI_FEAR_UNIT[index] ) then
						Actif = 2; -- Immun
						break;
					end
				end
			end
				
			-- We'll start to parse the target buffs, as his class doesn't give him natural permanent immunity
			if not Actif then
				for index=1, table.getn(NECROSIS_ANTI_FEAR_SPELL.Buff), 1 do
					if Necrosis_UnitHasBuff("target",NECROSIS_ANTI_FEAR_SPELL.Buff[index]) then
						Actif = 3; -- Prot
						break;
					end
				end
				
				-- No buff found, let's try the debuffs
				for index=1, table.getn(NECROSIS_ANTI_FEAR_SPELL.Debuff), 1 do
					if Necrosis_UnitHasEffect("target",NECROSIS_ANTI_FEAR_SPELL.Debuff[index]) then
						Actif = 3; -- Prot
						break;
					end
				end
			end
			
			-- an immunity has been detected before, but we still don't know why => show the button anyway
			if AFCurrentTargetImmune and not Actif then 
				Actif = 1;	
			end
		end
		
		if Actif and not UnitIsDead("target") then
			-- Antifear button is currently not visible, we have to change that
			if not AntiFearInUse then
				AntiFearInUse = true;
				Necrosis_Msg(NECROSIS_MESSAGE.Information.FearProtect, "USER");
				NecrosisAntiFearButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\AntiFear"..AFImageType[Actif].."-02");
				if NecrosisConfig.Sound then PlaySoundFile(NECROSIS_SOUND.Fear); end
				ShowUIPanel(NecrosisAntiFearButton);
				AFBlink1 = GetTime() + 0.6;
				AFBlink2 = 2;
			
			-- Timer to make the button blink
			elseif GetTime() >= AFBlink1 then
				if AFBlink2 == 1 then
					AFBlink2 = 2;
				else
					AFBlink2 = 1;
				end
				AFBlink1 = GetTime() + 0.4;
				NecrosisAntiFearButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\AntiFear"..AFImageType[Actif].."-0"..AFBlink2);
			end
			
		elseif AntiFearInUse then	-- No antifear on target, but the button is still visible => gonna hide it
			AntiFearInUse = false;
			HideUIPanel(NecrosisAntiFearButton);
		end
	end

	-- Gestion du Timer des sorts
	if (NecrosisConfig.ShowSpellTimers) then
		if (not NecrosisSpellTimerButton:IsVisible()) then
			ShowUIPanel(NecrosisSpellTimerButton);
		end
		local display = "";
		if NecrosisConfig.CountType == 3 then
			NecrosisShardCount:SetText("");
		end
		local update = false;
		if ((curTime - SpellCastTime) >= 1) then
			SpellCastTime = curTime;
			update = true;
		end

		-- On met à jour les boutons toutes les secondes
		-- On accepte le trade de la pierre de soin si transfert en cours
		if update then
			if Trading then
				TradingNow = TradingNow - 1;
				if TradingNow == 0 then
					AcceptTrade();
					Trading = false;
				end
			end
			Necrosis_UpdateIcons();
		end
		
		-- Parcours du tableau des Timers
		if SpellTimer.Name ~= nil then
			for index=1, table.getn(SpellTimer.Name), 1 do
				if SpellTimer.TimeMax[index] then
					if (GetTime() <= SpellTimer.TimeMax[index]) then
						-- Création de l'affichage des timers
						display, SpellGroup = Necrosis_DisplayTimer(display, index, SpellGroup, SpellTimer);
						-- Action toutes les secondes
						if (update) and SpellTimer.TimeMax[index] ~= nil then
							-- On enlève les timers terminés
							local TimeLocal = GetTime();
							if TimeLocal >= (SpellTimer.TimeMax[index] - 0.5) then
								-- Si le timer était celui de la Pierre d'âme, on prévient le Démoniste
								if SpellTimer.Name[index] == NECROSIS_SPELL_TABLE.Name[11] then
									SpellTimer.TimeMax[index] = -1;
									Necrosis_Msg(NECROSIS_MESSAGE.Information.SoulstoneEnd, "USER");
									if NecrosisConfig.Sound then PlaySoundFile(NECROSIS_SOUND.SoulstoneEnd); end
									if NecrosisConfig.Circle == 2 then NecrosisButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Rose\\Shard0"); end
									-- SpellTimer = Necrosis_RetraitTimerParIndex(index, Spelltimer);
									-- On met à jour l'apparence du bouton de la pierre d'âme
									Necrosis_UpdateIcons();
								-- Sinon on enlève le timer silencieusement (mais pas en cas d'enslave)
								elseif SpellTimer.Name[index] ~= NECROSIS_SPELL_TABLE.Name[10] then
									SpellTimer = Necrosis_RetraitTimerParIndex(index, SpellTimer);
								end
							end
							-- Si le Démoniste n'est plus sous l'emprise du Sacrifice
							if SpellTimer.Name[index] == NECROSIS_SPELL_TABLE.Name[17] then -- Sacrifice
								if not Necrosis_UnitHasEffect("player", SpellTimer.Name[index]) and SpellTimer.TimeMax[index] ~= nil then
									SpellTimer = Necrosis_RetraitTimerParIndex(index, SpellTimer);
								end
							end
							-- Si la cible visée n'est plus atteinte par un sort lancé [résists]
							if (SpellTimer.Type[index] == 4 or SpellTimer.Type[index] == 5)
								and SpellTimer.Target[index] == UnitName("target")
								then
								-- On triche pour laisser le temps au mob de bien sentir qu'il est débuffé ^^
								if TimeLocal >= ((SpellTimer.TimeMax[index] - SpellTimer.Time[index]) + 1.5) then
									if not Necrosis_UnitHasEffect("target", SpellTimer.Name[index]) then
										SpellTimer = Necrosis_RetraitTimerParIndex(index, SpellTimer);
									end
								end
							end
						end
					elseif SpellTimer.Name[index] == NECROSIS_SPELL_TABLE.Name[11] then
						SpellTimer.TimeMax[index] = -1;
					end
				end
			end
		end
		-- Coloration de l'affichage des timers
		display = Necrosis_MsgAddColor(display);
		-- Affichage des timers
		NecrosisListSpells:SetText(display);
		for i = 4, table.getn(SpellGroup.Name) do
			SpellGroup.Visible[i] = false;
		end
	else
		if (NecrosisSpellTimerButton:IsVisible()) then
			NecrosisListSpells:SetText("");
			HideUIPanel(NecrosisSpellTimerButton);
		end
	end
end

-- Fonction lancée selon l'événement intercepté
function Necrosis_OnEvent(event)

	-- Traditionnel test : Le joueur est-il bien Démoniste ?
	if (not Loaded) or UnitClass("player") ~= NECROSIS_UNIT_WARLOCK then 
		return;
	end

	-- Si le contenu des sacs a changé, on vérifie que les Fragments d'âme sont toujours dans le bon sac
	if (event == "BAG_UPDATE") then
		if (NecrosisConfig.SoulshardSort) then
			Necrosis_SoulshardSwitch("CHECK");
		else
			Necrosis_SoulshardTotal();
		end

	-- Flag si une fenetre de Trade est ouverte, afin de pouvoir trader automatiquement les pierres de soin
	elseif event == "TRADE_REQUEST" or event == "TRADE_SHOW" then
		NecrosisTradeRequest = true;
	elseif event == "TRADE_REQUEST_CANCEL" or event == "TRADE_CLOSED" then
		NecrosisTradeRequest = false;
	
	-- AntiFear button hide on target change
	elseif event == "PLAYER_TARGET_CHANGED" then
		if NecrosisConfig.AntiFearAlert and AFCurrentTargetImmune then
			AFCurrentTargetImmune = false;
		end
		
	-- AntiFear immunity on cast detection
	elseif event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
		if NecrosisConfig.AntiFearAlert then
			for spell, creatureName in string.gfind(arg1, NECROSIS_ANTI_FEAR_SRCH) do			
				-- We check if the casted spell on the immune target is Fear or Death Coil
				if spell == NECROSIS_SPELL_TABLE.Name[13] or spell == NECROSIS_SPELL_TABLE.Name[19] then
					AFCurrentTargetImmune = true;
					break;
				end
			end
		end
	
	-- Si le Démoniste apprend un nouveau sort / rang de sort, on récupère la nouvelle liste des sorts
	-- Si le Démoniste apprend un nouveau sort de buff ou d'invocation, on recrée les boutons
	elseif (event == "LEARNED_SPELL_IN_TAB") then
		Necrosis_SpellSetup();
		Necrosis_CreateMenu();
		Necrosis_ButtonSetup();
	
	-- Au début du combat, on signal que le joueur est en combat (permission d'afficher la trance :P)
	elseif event == "PLAYER_REGEN_DISABLED" then
		
	-- A la fin du combat, on arrête de signaler le Crépuscule, et on enlève les timers de sorts
	elseif (event == "PLAYER_REGEN_ENABLED") then
		SpellGroup, SpellTimer = Necrosis_RetraitTimerCombat(SpellGroup, SpellTimer);
		
	-- Quand le démoniste change de démon
	elseif (event == "UNIT_PET" and arg1 == "player") then

		-- Si le nouveau démon est un démon asservi, on place un timer de 5 minutes
		if (Necrosis_UnitHasEffect("pet", NECROSIS_SPELL_TABLE.Name[10])) then
			if (not DemonEnslaved) then
				DemonEnslaved = true;
				SpellGroup, SpellTimer = Necrosis_InsertTimerParTable(10, "","", SpellGroup, SpellTimer);
			end
		else
			-- Quand le démon asservi est perdu, on retire le Timer et on prévient le Démoniste
			if (DemonEnslaved) then
				DemonEnslaved = false;
				SpellTimer = Necrosis_RetraitTimerParNom(NECROSIS_SPELL_TABLE.Name[10], SpellTimer);
				if NecrosisConfig.Sound then PlaySoundFile(NECROSIS_SOUND.EnslaveEnd); end
				Necrosis_Msg(NECROSIS_MESSAGE.Information.EnslaveBreak, "USER");
			end
		end
		
		-- Si le démon n'est pas asservi
		DemonType = UnitCreatureFamily("pet");
		if (DemonType) then
			Demon.Spell = NecrosisDemon[DemonType].Spell;
			Demon.Time = NecrosisDemon[DemonType].Time;
			Demon.Cooldown = NecrosisDemon[DemonType].Cooldown;
		end
		
	-- Quand le démoniste commence à incanter un sort, on intercepte le nom de celui-ci
	elseif (event == "SPELLCAST_START") then
		SpellCastName = arg1;
		SpellTargetName = UnitName("target");
		if not SpellTargetName then
			SpellTargetName = "";
		end
		SpellTargetLevel = UnitLevel("target");
		if not SpellTargetLevel then
			SpellTargetLevel = "";
		end
	
	-- Quand le démoniste stoppe son incantation, on relache le nom de celui-ci
	elseif (event == "SPELLCAST_FAILED") or (event == "SPELLCAST_INTERRUPTED") then
		SpellCastName = nil;
	
	-- Actions personnelles -- "Buffs"
	elseif (event == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS") then
		-- Insertion d'un timer quand le Démoniste subit "Sacrifice"
		if arg1 == NECROSIS_TRANSLATION.SacrificeGain then
			SpellGroup, SpellTimer = Necrosis_InsertTimerParTable(17, "", "", SpellGroup, SpellTimer);
		end
		-- Chargement du bouton de monture quand le Démoniste chevauche
		if string.find(arg1, NECROSIS_SPELL_TABLE.Name[1]) or  string.find(arg1, NECROSIS_SPELL_TABLE.Name[2]) then
			NecrosisMounted = true;
			NecrosisMountButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\MountButton-02");
		end
		-- Chargement du bouton de la domination corrompue si celle-ci est activée + Timer de cooldown
		if  string.find(arg1, NECROSIS_SPELL_TABLE.Name[15]) and NECROSIS_SPELL_TABLE.ID[15] ~= nil then
			NecrosisPetMenu1:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Domination-02");
			SpellGroup, SpellTimer = Necrosis_InsertTimerParTable(15, "", "", SpellGroup, SpellTimer);
		end
	
	-- Actions personnelles -- "Debuffs"
	elseif event == "CHAT_MSG_SPELL_AURA_GONE_SELF" or event == "CHAT_MSG_SPELL_BREAK_AURA" then
		-- Changement du bouton de monture quand le Démoniste est démonté
		if string.find(arg1, NECROSIS_SPELL_TABLE.Name[1]) or  string.find(arg1, NECROSIS_SPELL_TABLE.Name[2]) then
			NecrosisMounted = false;
			NecrosisMountButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\MountButton-01");
		end
		-- Changement du bouton de Domination quand le Démoniste n'est plus sous son emprise
		if  string.find(arg1, NECROSIS_SPELL_TABLE.Name[15]) and NECROSIS_SPELL_TABLE.ID[15] ~= nil then
			NecrosisPetMenu1:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Domination-01");
		end
	
	-- Gestion de la fin de l'incantation des sorts
	elseif (event == "SPELLCAST_STOP") then

		-- Gestion des autres sorts
		local SortActif = false;
		if (SpellCastName) then
			-- Si le sort lancé à été une Résurrection de Pierre d'âme, on place un timer
			if (SpellCastName == NECROSIS_SPELL_TABLE.Name[11]) then
				if SpellTargetName == UnitName("player") then
					SpellTargetName = "";
				end
				-- Si les messages sont actifs et que la pierre est posée sur un joueur ciblé, hop, message !
				if NecrosisConfig.ChatMsg and SoulstoneUsedOnTarget then
					tempnum = random(1, (table.getn(NECROSIS_SOULSTONE_ALERT_MESSAGE)) / 2) * 2;
					Necrosis_Msg(NECROSIS_SOULSTONE_ALERT_MESSAGE[tempnum]..tostring(UnitName("target"))..NECROSIS_SOULSTONE_ALERT_MESSAGE[tempnum+1], "WORLD");
				end
				SpellGroup, SpellTimer = Necrosis_InsertTimerParTable(11, SpellTargetName, "", SpellGroup, SpellTimer);
			-- Si le sort était un rituel d'invocation, alors on écrit une phrase a caractère informatif aux joueurs
			elseif (SpellCastName == NECROSIS_TRANSLATION.SummoningRitual) and NecrosisConfig.ChatMsg then
				tempnum = random(1, (table.getn(NECROSIS_INVOCATION_MESSAGES)) / 2) * 2;
			Necrosis_Msg(NECROSIS_INVOCATION_MESSAGES[tempnum]..tostring(UnitName("target"))..NECROSIS_INVOCATION_MESSAGES[tempnum+1], "WORLD");
			-- Pour les autres sorts castés, tentative de timer si valable
			else
				for spell=1, table.getn(NECROSIS_SPELL_TABLE.Name), 1 do
					if SpellCastName == NECROSIS_SPELL_TABLE.Name[spell] and not (spell == 10) then
						-- Si le timer existe déjà sur la cible, on le met à jour
						for thisspell=1, table.getn(SpellTimer.Name), 1 do
							if SpellTimer.Name[thisspell] == SpellCastName
								and SpellTimer.Target[thisspell] == SpellTargetName
								and SpellTimer.TargetLevel[thisspell] == SpellTargetLevel
								then
								-- Si c'est sort lancé déjà présent sur un mob, on remet le timer à fond
								if spell ~= 9 or (spell == 9 and not Necrosis_UnitHasEffect("target", SpellCastName)) then
									SpellTimer.Time[thisspell] = NECROSIS_SPELL_TABLE.Length[spell];
									SpellTimer.TimeMax[thisspell] = floor(GetTime() + NECROSIS_SPELL_TABLE.Length[spell]);
								end
								SortActif = true;
								break;
							end
							-- Si c'est un banish sur une nouvelle cible, on supprime le timer précédent
							if SpellTimer.Name[thisspell] == SpellCastName and spell == 9
								and
									(SpellTimer.Target[thisspell] ~= SpellTargetName
									or SpellTimer.TargetLevel[thisspell] ~= SpellTargetLevel)
								then
								SpellTimer = Necrosis_RetraitTimerParIndex(thisspell, SpellTimer);
								SortActif = false;
								break;
							end	
							
							-- Si c'est un fear, on supprime le timer du fear précédent
							if SpellTimer.Name[thisspell] == SpellCastName and spell == 13 then
								SpellTimer = Necrosis_RetraitTimerParIndex(thisspell, SpellTimer);
								SortActif = false;
								break;
							end
							if SortActif then break; end
						end
						-- Si le timer est une malédiction, on enlève la précédente malédiction sur la cible
						if (NECROSIS_SPELL_TABLE.Type[spell] == 4) or (spell == 16) then
							for thisspell=1, table.getn(SpellTimer.Name), 1 do
								-- Mais on garde le cooldown de la malédiction funeste
								if SpellTimer.Name[thisspell] == NECROSIS_SPELL_TABLE.Name[16] then
									SpellTimer.Target[thisspell] = "";
									SpellTimer.TargetLevel[thisspell] = "";
								end
								if SpellTimer.Type[thisspell] == 4
									and SpellTimer.Target[thisspell] == SpellTargetName
									and SpellTimer.TargetLevel[thisspell] == SpellTargetLevel
									then
									SpellTimer = Necrosis_RetraitTimerParIndex(thisspell, SpellTimer);
									break;
								end
							end
						end
						if not SortActif
							and spell ~= 10
							and spell ~= StoneIDInSpellTable[1]
							and spell ~= StoneIDInSpellTable[2]
							and spell ~= StoneIDInSpellTable[3]
							and spell ~= StoneIDInSpellTable[4]
							then
							SpellGroup, SpellTimer = Necrosis_InsertTimerParTable(spell, SpellTargetName, SpellTargetLevel, SpellGroup, SpellTimer);
							break;
						end
					end
				end
			end
		end
		SpellCastName = nil;
	end
end


------------------------------------------------------------------------------------------------------
-- FONCTIONS DE L'INTERFACE -- LIENS XML
------------------------------------------------------------------------------------------------------

-- En cliquant droit sur Necrosis, on affiche ou masque les deux panneaux de configurations
function Necrosis_Toggle(button)
	if button == "LeftButton" then return; end
	if (NecrosisGeneralFrame:IsVisible()) then
		HideUIPanel(NecrosisGeneralFrame);
	else
		ShowUIPanel(NecrosisGeneralFrame);
		NecrosisGeneralTab_OnClick(1);
	end
end

-- Fonction permettant le déplacement d'éléments de Necrosis sur l'écran
function Necrosis_OnDragStart(button)
	if (button == "NecrosisIcon") then GameTooltip:Hide(); end
	button:StartMoving();
end

-- Fonction arrêtant le déplacement d'éléments de Necrosis sur l'écran
function Necrosis_OnDragStop(button)
	if (button == "NecrosisIcon") then Necrosis_BuildTooltip("OVERALL"); end
	button:StopMovingOrSizing();
end

-- Fonction gérant les bulles d'aide
function Necrosis_BuildTooltip(button, type, anchor)
	-- Ca c'est de la triche : Comme la fonction est lancée à chaque fois que le curseur passe au dessus d'un bouton
	-- J'en profite pour réinitialiser l'affichage de ceci...
	-- Pour ceux qui veulent savoir pourquoi, utilisez donc Nécrosis pour placer une Pierre d'âme sur quelqu'un, et
	-- arrêtez de caster : Necrosis "perd" de vue la Pierre d'âme qu'il pense utilisée...
	Necrosis_SoulshardTotal();

	-- Si l'affichage des bulles d'aide est désactivé, Bye bye !
	if not NecrosisConfig.NecrosisToolTip then
		return;
	end

	-- Création des bulles d'aides....
	GameTooltip:SetOwner(button, anchor);
	GameTooltip:SetText(NecrosisTooltipData[type].Label);
	-- ..... pour le bouton principal
	if (type == "Main") then
		GameTooltip:AddLine(NecrosisTooltipData.Main.Soulshard..Soulshards);
		GameTooltip:AddLine(NecrosisTooltipData.Main.InfernalStone..InfernalStone);
		GameTooltip:AddLine(NecrosisTooltipData.Main.DemoniacStone..DemoniacStone);
		GameTooltip:AddLine(NecrosisTooltipData.Main.Soulstone..NecrosisTooltipData[type].Stone[SoulstoneOnHand]);
		GameTooltip:AddLine(NecrosisTooltipData.Main.Healthstone..NecrosisTooltipData[type].Stone[HealthstoneOnHand]);
		-- On vérifie si une pierre de sort n'est pas équipée
		NecrosisTooltip:SetInventoryItem("player", 17);
		local rightHand = tostring(NecrosisTooltipTextLeft1:GetText());
		if string.find(rightHand, NECROSIS_ITEM.Spellstone) then SpellstoneOnHand = true; end
		GameTooltip:AddLine(NecrosisTooltipData.Main.Spellstone..NecrosisTooltipData[type].Stone[SpellstoneOnHand]);
		-- De même pour la pierre de feu
		if string.find(rightHand, NECROSIS_ITEM.Firestone) then FirestoneOnHand = true; end
		GameTooltip:AddLine(NecrosisTooltipData.Main.Firestone..NecrosisTooltipData[type].Stone[FirestoneOnHand]);
		-- Affichage du nom du démon, ou s'il est asservi, ou "Aucun" si aucun démon n'est présent
		if (DemonType) then
			GameTooltip:AddLine(NecrosisTooltipData.Main.CurrentDemon..DemonType);
		elseif DemonEnslaved then
			GameTooltip:AddLine(NecrosisTooltipData.Main.EnslavedDemon);
		else
			GameTooltip:AddLine(NecrosisTooltipData.Main.NoCurrentDemon);
		end
	-- ..... pour les boutons de pierre
	elseif (string.find(type, "stone")) then
		-- Pierre d'âme
		if (type == "Soulstone") then
			-- On affiche le nom de la pierre et l'action que produira le clic sur le bouton
			-- Et aussi le Temps de recharge
			if SoulstoneMode == 1 or SoulstoneMode == 3 then
				GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[StoneIDInSpellTable[1]].." Mana");
			end
			Necrosis_MoneyToggle();
			NecrosisTooltip:SetBagItem(SoulstoneLocation[1], SoulstoneLocation[2]);
			local itemName = tostring(NecrosisTooltipTextLeft6:GetText());
			Necrosis_MoneyToggle();
			GameTooltip:AddLine(NecrosisTooltipData[type].Text[SoulstoneMode]);
			if string.find(itemName, NECROSIS_TRANSLATION.Cooldown) then
			GameTooltip:AddLine(itemName);
			end
		-- Pierre de vie
		elseif (type == "Healthstone") then
			-- Idem
			if HealthstoneMode == 1 then
				GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[StoneIDInSpellTable[2]].." Mana");
			end
			Necrosis_MoneyToggle();
			NecrosisTooltip:SetBagItem(HealthstoneLocation[1], HealthstoneLocation[2]);
			local itemName = tostring(NecrosisTooltipTextLeft6:GetText());
			Necrosis_MoneyToggle();
			GameTooltip:AddLine(NecrosisTooltipData[type].Text[HealthstoneMode]);
			if string.find(itemName, NECROSIS_TRANSLATION.Cooldown) then
				GameTooltip:AddLine(itemName);
			end
		-- Pierre de sort
		elseif (type == "Spellstone") then
			-- Eadem
			if SpellstoneMode == 1 then
				GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[StoneIDInSpellTable[3]].." Mana");
			end
			Necrosis_MoneyToggle();
			NecrosisTooltip:SetInventoryItem("player", 17);
			local itemName = tostring(NecrosisTooltipTextLeft9:GetText());
			local itemStone = tostring(NecrosisTooltipTextLeft1:GetText());
			Necrosis_MoneyToggle();
			GameTooltip:AddLine(NecrosisTooltipData[type].Text[SpellstoneMode]);
			if (string.find(itemStone, NECROSIS_ITEM.Spellstone)
				and string.find(itemName, NECROSIS_TRANSLATION.Cooldown)) then
			GameTooltip:AddLine(itemName);
			end
		-- Pierre de feu
		elseif (type == "Firestone") then
			-- Idem, mais sans le cooldown
			if FirestoneMode == 1 then
				GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[StoneIDInSpellTable[4]].." Mana");
			end
			GameTooltip:AddLine(NecrosisTooltipData[type].Text[FirestoneMode]);
		end
	-- ..... pour le bouton des Timers
	elseif (type == "SpellTimer") then
		Necrosis_MoneyToggle();
		NecrosisTooltip:SetBagItem(HearthstoneLocation[1], HearthstoneLocation[2]);
		local itemName = tostring(NecrosisTooltipTextLeft5:GetText());
		Necrosis_MoneyToggle();
		GameTooltip:AddLine(NecrosisTooltipData[type].Text);
		if string.find(itemName, NECROSIS_TRANSLATION.Cooldown) then
			GameTooltip:AddLine(NECROSIS_TRANSLATION.Hearth.." - "..itemName);
		else
			GameTooltip:AddLine(NecrosisTooltipData[type].Right);
		end
		
	-- ..... pour le bouton de la Transe de l'ombre
	elseif (type == "ShadowTrance") then
		local rank = Necrosis_FindSpellAttribute("Name", NECROSIS_NIGHTFALL.BoltName, "Rank");
		GameTooltip:SetText(NecrosisTooltipData[type].Label.."          |CFF808080Rank "..rank.."|r");
	-- ..... pour les autres buffs et démons, le coût en mana...
	elseif (type == "Enslave") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[10].." Mana");
		if Soulshards == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.Soulshard..Soulshards.."|r");
		end
	elseif (type == "Mount") then
		if NECROSIS_SPELL_TABLE.ID[2] then
			GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[2].." Mana");
		elseif NECROSIS_SPELL_TABLE.ID[1] then
			GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[1].." Mana");
		end
	elseif (type == "Armor") then
		if NECROSIS_SPELL_TABLE.ID[31] then
			GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[31].." Mana");
		else
			GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[36].." Mana");
		end
	elseif (type == "Invisible") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[33].." Mana");
	elseif (type == "Aqua") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[32].." Mana");
	elseif (type == "Kilrogg") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[34].." Mana");
	elseif (type == "Banish") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[9].." Mana");
	elseif (type == "TP") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[37].." Mana");
		if Soulshards == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.Soulshard..Soulshards.."|r");
		end
	elseif (type == "SoulLink") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[38].." Mana");
	elseif (type == "Imp") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[3].." Mana");
	elseif (type == "Void") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[4].." Mana");
		if Soulshards == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.Soulshard..Soulshards.."|r");
		end
	elseif (type == "Succubus") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[5].." Mana");
		if Soulshards == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.Soulshard..Soulshards.."|r");
		end
	elseif (type == "Fel") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[6].." Mana");
		if Soulshards == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.Soulshard..Soulshards.."|r");
		end
	elseif (type == "Infernal") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[8].." Mana");
		if InfernalStone == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.InfernalStone..InfernalStone.."|r");
		else
			GameTooltip:AddLine(NecrosisTooltipData.Main.InfernalStone..InfernalStone);
		end
	elseif (type == "Doom") then
		GameTooltip:AddLine(NECROSIS_SPELL_TABLE.Mana[30].." Mana");
		if DemoniacStone == 0 then
			GameTooltip:AddLine("|c00FF4444"..NecrosisTooltipData.Main.DemoniacStone..DemoniacStone.."|r");
		else
			GameTooltip:AddLine(NecrosisTooltipData.Main.DemoniacStone..DemoniacStone);
		end
	end
	-- Et hop, affichage !
	GameTooltip:Show();
end

-- Fonction mettant à jour les boutons Necrosis et donnant l'état du bouton de la pierre d'âme
function Necrosis_UpdateIcons()
	-- Pierre d'âme
	-----------------------------------------------
	
	-- On se renseigne pour savoir si une pierre d'âme a été utilisée --> vérification dans les timers
	local SoulstoneInUse = false;
	if SpellTimer.Name[1] then
		for index=1, table.getn(SpellTimer.Name), 1 do
			if (SpellTimer.Name[index] == NECROSIS_SPELL_TABLE.Name[11]) and SpellTimer.TimeMax[index] > 0 then
				SoulstoneInUse = true;
				break;
			end
		end
	end

	-- Si la Pierre n'a pas été utilisée, et qu'il n'y a pas de pierre en inventaire -> Mode 1
	if not (SoulstoneOnHand or SoulstoneInUse) then
		SoulstoneMode = 1;
		SoulstonePreMode = 1;
	end

	-- Si la Pierre n'a pas été utilisée, mais qu'il y a une pierre en inventaire
	if SoulstoneOnHand and (not SoulstoneInUse) then
		-- Si la pierre en inventaire contient un timer, et qu'on sort d'un RL --> Mode 4
		local start, duration = GetContainerItemCooldown(SoulstoneLocation[1],SoulstoneLocation[2]);
		if NecrosisRL and start > 0 and duration > 0 then
			SpellGroup, SpellTimer = Necrosis_InsertTimerStone("Soulstone", start, duration, SpellGroup, SpellTimer);
			SoulstoneMode = 4;
			SoulstonePreMode = 4;
			NecrosisRL = false;
		-- Si la pierre ne contient pas de timer, ou qu'on ne sort pas d'un RL --> Mode 2
		else
			SoulstoneMode = 2;
			SoulstonePreMode = 2;
			NecrosisRL = false;
		end
	end

	-- Si la Pierre a été utilisée mais qu'il n'y a pas de pierre en inventaire --> Mode 3
	if (not SoulstoneOnHand) and SoulstoneInUse then
		SoulstoneMode = 3;
		SoulstonePreMode = 3;
	end

	-- Si la Pierre a été utilisée et qu'il y a une pierre en inventaire
	if SoulstoneOnHand and SoulstoneInUse then
		-- Si précédement on avait un Timer mais pas de Pierre ou si la situation était déjà telle quelle avant --> Mode 4
		if (SoulstonePreMode == 3) or (SoulstonePreMode == 4) then
			SoulstoneMode = 4;
			SoulstonePreMode = 4;
		-- Si précédemment on avait pas de Timer, c'est qu'un Timer a été créé par erreur (marcher pendant le cast)
		-- Dans ce cas --> Mode 2
		else
			SpellTimer = Necrosis_RetraitTimerParNom(NECROSIS_SPELL_TABLE.Name[11], SpellTimer);
			SoulstoneMode = 2;
			SoulstonePreMode = 2;
		end
	end

	-- Affichage de l'icone liée au mode
	NecrosisSoulstoneButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\SoulstoneButton-0"..SoulstoneMode);

	-- Pierre de vie
	-----------------------------------------------

	-- Mode "j'en ai une" (2) / "j'en ai pas" (1)
	if (HealthstoneOnHand) then
		HealthstoneMode = 2;
	else
		HealthstoneMode = 1;
	end

	-- Affichage de l'icone liée au mode
	NecrosisHealthstoneButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\HealthstoneButton-0"..HealthstoneMode);

	-- Pierre de sort
	-----------------------------------------------

	-- Si la pierre est équipée, mode 3
	local rightHand = GetInventoryItemTexture("player", 17);
	if (rightHand == "Interface\\Icons\\INV_Misc_Gem_Sapphire_01" and not SpellstoneOnHand) then
		SpellstoneMode = 3;
	else
		-- Pierre dans l'inventaire, mode 2
		if (SpellstoneOnHand) then
			SpellstoneMode = 2;
		-- Pierre inexistante, mode 1
		else
			SpellstoneMode = 1;
		end
	end

	-- Affichage de l'icone liée au mode
	NecrosisSpellstoneButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\SpellstoneButton-0"..SpellstoneMode);

	-- Pierre de feu
	-----------------------------------------------

	-- Pierre équipée = mode 3
	if (rightHand == "Interface\\Icons\\INV_Misc_Gem_Bloodstone_02" and not FirestoneOnHand) then
		FirestoneMode = 3;
	-- Pierre dans l'inventaire = mode 2
	elseif (FirestoneOnHand) then
		FirestoneMode = 2;
	-- Pierre inexistante = mode 1
	else
		FirestoneMode = 1;
	end

	-- Affichage de l'icone liée au mode
	NecrosisFirestoneButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\FirestoneButton-0"..FirestoneMode);


	-- Bouton des démons
	-----------------------------------------------
	local pettype = UnitCreatureFamily("pet");
	local mana = UnitMana("player");
	
	local ManaPet = {"1", "1", "1", "1", "1", "1"};

	if mana ~= nil then
	-- Coloration du bouton en grisé si pas assez de mana
		if NECROSIS_SPELL_TABLE.ID[3] then
			if NECROSIS_SPELL_TABLE.Mana[3] > mana then
				for i = 1, 6, 1 do
					ManaPet[i] = "3";
				end
			elseif NECROSIS_SPELL_TABLE.ID[4] then
				if NECROSIS_SPELL_TABLE.Mana[4] > mana then
					for i = 2, 6, 1 do
						ManaPet[i] = "3";
					end
				elseif NECROSIS_SPELL_TABLE.ID[8] then
					if NECROSIS_SPELL_TABLE.Mana[8] > mana then
						for i = 5, 6, 1 do
							ManaPet[i] = "3";
						end
					elseif NECROSIS_SPELL_TABLE.ID[30] then
						if NECROSIS_SPELL_TABLE.Mana[30] > mana then
							ManaPet[6] = "3";
						end
					end
				end
			end
		end
	end

	-- Coloration du bouton en grisé si pas de pierre pour l'invocation
	if Soulshards == 0 then
		for i = 2, 4, 1 do
			ManaPet[i] = "3";
		end
	end
	if InfernalStone == 0 then
		ManaPet[5] = "3";
	end
	if DemoniacStone == 0 then
		ManaPet[6] = "3";
	end

	-- Texturage des boutons de pet
	if pettype == NECROSIS_PET_LOCAL_NAME.Imp then
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-02");
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-0"..ManaPet[2]);
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-0"..ManaPet[3]);
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-0"..ManaPet[4]);
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-0"..ManaPet[5]);
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-0"..ManaPet[6]);
	elseif pettype == NECROSIS_PET_LOCAL_NAME.Void then
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-0"..ManaPet[1]);
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-02");
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-0"..ManaPet[3]);
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-0"..ManaPet[4]);
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-0"..ManaPet[5]);
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-0"..ManaPet[6]);
	elseif pettype == NECROSIS_PET_LOCAL_NAME.Succubus then
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-0"..ManaPet[1]);
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-0"..ManaPet[2]);
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-02");
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-0"..ManaPet[4]);
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-0"..ManaPet[5]);
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-0"..ManaPet[6]);
	elseif pettype == NECROSIS_PET_LOCAL_NAME.Fel then
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-0"..ManaPet[1]);
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-0"..ManaPet[2]);
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-0"..ManaPet[3]);
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-02");
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-0"..ManaPet[5]);
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-0"..ManaPet[6]);
	elseif pettype == NECROSIS_PET_LOCAL_NAME.Inferno then
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-0"..ManaPet[1]);
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-0"..ManaPet[2]);
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-0"..ManaPet[3]);
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-0"..ManaPet[4])
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-02");
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-0"..ManaPet[6]);
	elseif pettype == NECROSIS_PET_LOCAL_NAME.Doomguard then
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-0"..ManaPet[1]);
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-0"..ManaPet[2]);
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-0"..ManaPet[3]);
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-0"..ManaPet[4])
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-0"..ManaPet[5]);
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-02");
	else
		NecrosisPetMenu2:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Imp-0"..ManaPet[1]);
		NecrosisPetMenu3:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Voidwalker-0"..ManaPet[2]);
		NecrosisPetMenu4:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Succubus-0"..ManaPet[3]);
		NecrosisPetMenu5:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Felhunter-0"..ManaPet[4])
		NecrosisPetMenu6:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Infernal-0"..ManaPet[5]);
		NecrosisPetMenu7:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\Doomguard-0"..ManaPet[6]);
	end 
		

	-- Bouton des buffs
	-----------------------------------------------
	
	if mana ~= nil then
	-- Coloration du bouton en grisé si pas assez de mana
		if MountAvailable and not NecrosisMounted then
			if NECROSIS_SPELL_TABLE.ID[2] then
				if NECROSIS_SPELL_TABLE.Mana[2] > mana then
					NecrosisMountButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\MountButton-03");
				else
					NecrosisMountButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\MountButton-01");
				end
			else
				if NECROSIS_SPELL_TABLE.Mana[1] > mana then
					NecrosisMountButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\MountButton-03");
				else
					NecrosisMountButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\MountButton-01");
				end
			end
		end
		if NECROSIS_SPELL_TABLE.ID[35] then
			if NECROSIS_SPELL_TABLE.Mana[35] > mana or Soulshards == 0 then
				NecrosisPetMenu8:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Enslave-03");
			else
				NecrosisPetMenu8:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Enslave-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[31] then
			if NECROSIS_SPELL_TABLE.Mana[31] > mana then
				NecrosisBuffMenu1:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\ArmureDemo-03");
			else
				NecrosisBuffMenu1:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\ArmureDemo-01");
			end
		elseif NECROSIS_SPELL_TABLE.ID[36] then
			if NECROSIS_SPELL_TABLE.Mana[36] > mana then
				NecrosisBuffMenu1:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\ArmureDemo-03");
			else
				NecrosisBuffMenu1:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\ArmureDemo-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[32] then
			if NECROSIS_SPELL_TABLE.Mana[32] > mana then
				NecrosisBuffMenu2:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Aqua-03");
			else
				NecrosisBuffMenu2:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Aqua-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[33] then
			if NECROSIS_SPELL_TABLE.Mana[33] > mana then
				NecrosisBuffMenu3:SetNormalTexture("Interface\\AddOns\\Necrosis\\\UI\\Invisible-03");
			else
				NecrosisBuffMenu3:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Invisible-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[34] then
			if NECROSIS_SPELL_TABLE.Mana[34] > mana then
				NecrosisBuffMenu4:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Kilrogg-03");
			else
				NecrosisBuffMenu4:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\Kilrogg-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[9] then
			if NECROSIS_SPELL_TABLE.Mana[9] > mana then
				NecrosisBuffMenu5:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\BuffMenuButton-03");
			else
				NecrosisBuffMenu5:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\BuffMenuButton-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[37] then
			if NECROSIS_SPELL_TABLE.Mana[37] > mana or Soulshards == 0 then
				NecrosisBuffMenu6:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\TPButton-05");
			else
				NecrosisBuffMenu6:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\TPButton-01");
			end
		end
		if NECROSIS_SPELL_TABLE.ID[38] then
			if NECROSIS_SPELL_TABLE.Mana[38] > mana then
				NecrosisBuffMenu7:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\PetMenuButton-03");
			else
				NecrosisBuffMenu7:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\PetMenuButton-01");
			end
		end
	end

	-- Bouton des Timers
	-----------------------------------------------
	if HearthstoneLocation[1] then
		local start, duration, enable = GetContainerItemCooldown(HearthstoneLocation[1], HearthstoneLocation[2]);
		if duration > 20 and start > 0 then
			NecrosisSpellTimerButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\SpellTimerButton-Cooldown");
		else
			NecrosisSpellTimerButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\SpellTimerButton-Normal");
		end
	end
end

------------------------------------------------------------------------------------------------------
-- FONCTIONS DES PIERRES ET DES FRAGMENTS
------------------------------------------------------------------------------------------------------


-- T'AS QU'A SAVOIR OU T'AS MIS TES AFFAIRES !
function Necrosis_SoulshardSetup()
	SoulshardSlotID = 1;
	for slot=1, table.getn(SoulshardSlot), 1 do
		table.remove(SoulshardSlot, slot);
	end
	for slot=1, GetContainerNumSlots(NecrosisConfig.SoulshardContainer), 1 do
		table.insert(SoulshardSlot, nil);
	end
end


-- Fonction qui fait l'inventaire des éléments utilisés en démonologie : Pierres, Fragments, Composants d'invocation
function Necrosis_SoulshardTotal()
	local soulshards = Soulshards;
	Soulshards = 0;
	InfernalStone = 0;
	DemoniacStone = 0;
	SoulstoneOnHand = false;
	HealthstoneOnHand = false;
	FirestoneOnHand = false;
	SpellstoneOnHand = false;
	HearthstoneOnHand = false;
	ItemOnHand = false;
	-- Parcours des sacs
	for container=0, 4, 1 do
		-- Parcours des emplacements des sacs
		for slot=1, GetContainerNumSlots(container), 1 do
			Necrosis_MoneyToggle();
			NecrosisTooltip:SetBagItem(container, slot);
			local itemName = tostring(NecrosisTooltipTextLeft1:GetText());
			local itemSwitch = tostring(NecrosisTooltipTextLeft3:GetText());
			local itemSwitch2 = tostring(NecrosisTooltipTextLeft4:GetText());
			Necrosis_MoneyToggle();
			-- Si le sac est le sac défini pour les fragments
			-- hop la valeur du Tableau qui représente le slot du Sac = nil (pas de Shard)
			if (container == NecrosisConfig.SoulshardContainer) then
				if itemName ~= NECROSIS_ITEM.Soulshard then
					SoulshardSlot[slot] = nil;
				end
			end
			-- Dans le cas d'un emplacement non vide
			if itemName then
				-- On prend le nombre d'item en stack sur le slot
				local _, ItemCount = GetContainerItemInfo(container, slot);
				-- Si c'est un fragment ou une pierre infernale, alors on rajoute la qté au nombre de pierres
				if itemName == NECROSIS_ITEM.Soulshard then Soulshards = Soulshards + 1; end
				if itemName == NECROSIS_ITEM.InfernalStone then InfernalStone = InfernalStone + ItemCount; end
				if itemName == NECROSIS_ITEM.DemoniacStone then DemoniacStone = DemoniacStone + ItemCount; end
				-- Si c'est une pierre d'âme, on note son existence et son emplacement
				if string.find(itemName, NECROSIS_ITEM.Soulstone) then
					SoulstoneOnHand = true;
					SoulstoneLocation = {container,slot};
				end
				-- Même chose pour une pierre de soin
				if string.find(itemName, NECROSIS_ITEM.Healthstone) then
					HealthstoneOnHand = true;
					HealthstoneLocation = {container,slot};
				end
				-- Et encore pour la pierre de sort
				if string.find(itemName, NECROSIS_ITEM.Spellstone) then
					SpellstoneOnHand = true;
					SpellstoneLocation = {container,slot};
				end
				-- La pierre de feu maintenant
				if string.find(itemName, NECROSIS_ITEM.Firestone) then
					FirestoneOnHand = true;
					FirestoneLocation = {container,slot};
				end
				-- et enfin la pierre de foyer
				if string.find(itemName, NECROSIS_ITEM.Hearthstone) then
					HearthstoneOnHand = true;
					HearthstoneLocation = {container,slot};
				end

				-- On note aussi la présence ou non des objets "main gauche"
				-- Plus tard ce sera utilisé pour remplacer automatiquement une pierre absente			
				if itemSwitch == NECROSIS_ITEM.Offhand or itemSwitch2 == NECROSIS_ITEM.Offhand then
					ItemOnHand = true;
					ItemswitchLocation = {container, slot};
				end
			end
		end
	end
	
	-- Affichage du bouton principal de Necrosis
	if NecrosisConfig.Circle == 1 then
		if (Soulshards <= 32) then
			NecrosisButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\"..NecrosisConfig.NecrosisColor.."\\Shard"..Soulshards);
		else
			NecrosisButton:SetNormalTexture("Interface\\AddOns\\Necrosis\\UI\\"..NecrosisConfig.NecrosisColor.."\\Shard32");
		end
	end
	if NecrosisConfig.ShowCount then
		if NecrosisConfig.CountType == 2 then
			NecrosisShardCount:SetText(InfernalStone.." / "..DemoniacStone);
		elseif NecrosisConfig.CountType == 1 then
			if Soulshards < 10 then
				NecrosisShardCount:SetText("0"..Soulshards);
			else
				NecrosisShardCount:SetText(Soulshards);
			end
		end
	else
		NecrosisShardCount:SetText("");
	end
	-- Et on met le tout à jour !
	Necrosis_UpdateIcons();

	-- S'il y a plus de fragment que d'emplacements dans le sac défini, on affiche un message d'avertissement
	if (Soulshards > soulshards and Soulshards == GetContainerNumSlots(NecrosisConfig.SoulshardContainer)) then
		if (SoulshardDestroy) then
			Necrosis_Msg(NECROSIS_MESSAGE.Bag.FullPrefix..GetBagName(NecrosisConfig.SoulshardContainer)..NECROSIS_MESSAGE.Bag.FullDestroySuffix);
		else
			Necrosis_Msg(NECROSIS_MESSAGE.Bag.FullPrefix..GetBagName(NecrosisConfig.SoulshardContainer)..NECROSIS_MESSAGE.Bag.FullSuffix);
		end
	end
end

-- Fonction qui permet de trouver / ranger les fragments dans les sacs
function Necrosis_SoulshardSwitch(type)
	if (type == "CHECK") then SoulshardMP = 0; end
	for container = 0, 4, 1 do
		local BagIsSoulPouch = false;
		for i = 1, 3, 1 do
			if GetBagName(container) ~= NECROSIS_ITEM.SoulPouch[i] then
				BagIsSoulPouch = true;
				break;
			end
		end
		if not BagIsSoulPouch and container ~= NecrosisConfig.SoulshardContainer then
			for slot=1, GetContainerNumSlots(container), 1 do
				Necrosis_MoneyToggle();
				NecrosisTooltip:SetBagItem(container, slot);
				local itemInfo = tostring(NecrosisTooltipTextLeft1:GetText());
				Necrosis_MoneyToggle();
				if string.find(itemInfo, NECROSIS_ITEM.Soulshard) then
					if (type == "CHECK") then
						SoulshardMP = SoulshardMP + 1;
					elseif (type == "MOVE") then
						Necrosis_FindSlot(container, slot);
						SoulshardMP = SoulshardMP - 1;
					end
				end
			end
		end
	end
	-- Après avoir tout déplacer, il faut retrouver les emplacements des pierres, etc, etc...
	Necrosis_SoulshardTotal();
end

-- Pendant le déplacement des fragments, il faut trouver un nouvel emplacement aux objets déplacés :)
function Necrosis_FindSlot(shardIndex, shardSlot)
	local full = true;
	for slot=1, GetContainerNumSlots(NecrosisConfig.SoulshardContainer), 1 do
		Necrosis_MoneyToggle();
 		NecrosisTooltip:SetBagItem(NecrosisConfig.SoulshardContainer, slot);
 		local itemInfo = tostring(NecrosisTooltipTextLeft1:GetText());
		Necrosis_MoneyToggle();
		if string.find(itemInfo, NECROSIS_ITEM.Soulshard) == nil then
			PickupContainerItem(shardIndex, shardSlot);
			PickupContainerItem(NecrosisConfig.SoulshardContainer, slot);
			SoulshardSlot[SoulshardSlotID] = slot;
			SoulshardSlotID = SoulshardSlotID + 1
			if (CursorHasItem()) then
				if container == 0 then 
					PutItemInBackpack();
				else
					PutItemInBag(19 + container);
				end
			end
			full = false;
			break;
		end
	end
	-- Destruction des fragments en sur-nombre si l'option est activée
	if (full and NecrosisConfig.SoulshardDestroy) then
		PickupContainerItem(shardIndex, shardSlot);
		if (CursorHasItem()) then DeleteCursorItem(); end
	end
end

------------------------------------------------------------------------------------------------------
-- FONCTIONS DES SORTS
------------------------------------------------------------------------------------------------------



-- Affiche ou masque les boutons de sort à chaque nouveau sort appris
function Necrosis_ButtonSetup()
	if NecrosisConfig.NecrosisLockServ then
		Necrosis_NoDrag();
		Necrosis_UpdateButtonsScale();
	else
		HideUIPanel(NecrosisPetMenuButton);
		HideUIPanel(NecrosisBuffMenuButton);
		HideUIPanel(NecrosisMountButton);
		HideUIPanel(NecrosisFirestoneButton);
		HideUIPanel(NecrosisSpellstoneButton);
		HideUIPanel(NecrosisHealthstoneButton);
		HideUIPanel(NecrosisSoulstoneButton);
		if (NecrosisConfig.StonePosition[1]) and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[4]] then
			ShowUIPanel(NecrosisFirestoneButton);
		end
		if (NecrosisConfig.StonePosition[2]) and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[3]] then
			ShowUIPanel(NecrosisSpellstoneButton);
		end
		if (NecrosisConfig.StonePosition[3]) and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[2]] then
			ShowUIPanel(NecrosisHealthstoneButton);
		end
		if (NecrosisConfig.StonePosition[4]) and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[1]] then
			ShowUIPanel(NecrosisSoulstoneButton);
		end
		if (NecrosisConfig.StonePosition[5]) and BuffMenuCreate ~= {} then
			ShowUIPanel(NecrosisBuffMenuButton);
		end
		if (NecrosisConfig.StonePosition[6]) and MountAvailable then
			ShowUIPanel(NecrosisMountButton);
		end
		if (NecrosisConfig.StonePosition[7]) and PetMenuCreate ~= {} then
			ShowUIPanel(NecrosisPetMenuButton);
		end
	end
end



-- Ma fonction préférée ! Elle fait la liste des sorts connus par le démo, et les classe par rang.
-- Pour les pierres, elle sélectionne le plus haut rang connu
function Necrosis_SpellSetup()
	local StoneType = {NECROSIS_ITEM.Soulstone, NECROSIS_ITEM.Healthstone, NECROSIS_ITEM.Spellstone, NECROSIS_ITEM.Firestone};
	local StoneMaxRank = {0, 0, 0, 0};

	local CurrentStone = {
		ID = {},
		Name = {},
		subName = {}
	};

	local CurrentSpells = {
		ID = {},
		Name = {},
		subName = {}
	};
	
	local spellID = 1;
	local Invisible = 0;
	local InvisibleID = 0;

	-- On va parcourir tous les sorts possedés par le Démoniste
	while true do
		local spellName, subSpellName = GetSpellName(spellID, BOOKTYPE_SPELL);
		
		if not spellName then
			do break end
		end
		
		if (spellName) then
			-- Pour les sorts avec des rangs numérotés, on compare pour chaque sort les rangs 1 à 1
			-- Le rang supérieur est conservé
			if (string.find(subSpellName, NECROSIS_TRANSLATION.Rank)) then
				local found = false;
				local rank = tonumber(strsub(subSpellName, 6, strlen(subSpellName)));
				for index=1, table.getn(CurrentSpells.Name), 1 do
					if (CurrentSpells.Name[index] == spellName) then
				found = true;
						if (CurrentSpells.subName[index] < rank) then
							CurrentSpells.ID[index] = spellID;
							CurrentSpells.subName[index] = rank;
						end
						break;
					end
				end
				-- Les plus grands rangs de chacun des sorts à rang numérotés sont insérés dans la table
				if (not found) then
					table.insert(CurrentSpells.ID, spellID);
					table.insert(CurrentSpells.Name, spellName);
					table.insert(CurrentSpells.subName, rank);
				end
			end

			-- Test du Rang de la détection d'invisibilité
			if (string.find(spellName, NECROSIS_TRANSLATION.Invisible)) and Invisible ~= 3 then
				local StringOK = false;
				if string.find(spellName, NECROSIS_TRANSLATION.LesserInvisible)	and Invisible ~= 2 then
					StringOK = true;
					Invisible = 1;
					InvisibleID = spellID;
				end
				if (not StringOK) and Invisible ~=3 then
					Invisible = 2;
					InvisibleID = spellID;
				end
				if string.find(spellName, NECROSIS_TRANSLATION.GreaterInvisible) then
					Invisible = 3;
					InvisibleID = spellID;
				end
			end
			
			-- Les pierres n'ont pas de rang numéroté, l'attribut de rang fait partie du nom du sort
			-- Pour chaque type de pierre, on va donc faire....
			for stoneID=1, table.getn(StoneType), 1 do
				-- Si le sort étudié est bien une invocation de ce type de pierre et qu'on n'a pas
				-- déjà assigné un rang maximum à cette dernière
				if (string.find(spellName, StoneType[stoneID]))
					and StoneMaxRank[stoneID] ~= table.getn(NECROSIS_STONE_RANK)
					then					
					-- Récupération de la fin du nom de la pierre, contenant son rang
					local stoneSuffix = string.sub(spellName, string.find(spellName, StoneType[stoneID]) + string.len(StoneType[stoneID]));
					if Debug then Necrosis_Msg("Stone : "..spellName.." suffix :"..stoneSuffix,"USER");end
					-- Reste à trouver la correspondance de son rang
					for rankID=1,table.getn(NECROSIS_STONE_RANK),1 do
						-- Ne pas oublier de gérer dans la verification le fait qu'un des rangs
						-- n'a pas de suffixe, il est donc vide et d'une longueur nulle
						-- On doit donc chercher un rang non vide ou un rang vide si le suffixe
						-- est lui aussi vide
						if (string.find(string.lower(stoneSuffix), string.lower(NECROSIS_STONE_RANK[rankID]))
								and string.len(NECROSIS_STONE_RANK[rankID]) ~=0)
							or (string.len(NECROSIS_STONE_RANK[rankID])== 0
								and string.len(stoneSuffix)==0)
							then
							-- On a une pierre, on a son rang, reste à vérifier si c'est la plus puissante,
							-- et si oui, l'enregistrer
							if rankID>StoneMaxRank[stoneID] then
								StoneMaxRank[stoneID] = rankID;
								CurrentStone.Name[stoneID] = spellName;
								CurrentStone.subName[stoneID] = NECROSIS_STONE_RANK[rankID];
								CurrentStone.ID[stoneID] = spellID;
							end
							break
						end
					end
				end
			end
		end
		spellID = spellID + 1;
	end

	-- On insère dans la table les pierres avec le plus grand rang
	for stoneID=1, table.getn(StoneType), 1 do
		if StoneMaxRank[stoneID] ~= 0 then
			table.insert(NECROSIS_SPELL_TABLE.ID, CurrentStone.ID[stoneID]);
			table.insert(NECROSIS_SPELL_TABLE.Rank, 0);
			table.insert(NECROSIS_SPELL_TABLE.Name, CurrentStone.Name[stoneID]);
			table.insert(NECROSIS_SPELL_TABLE.CastTime, 0);
			table.insert(NECROSIS_SPELL_TABLE.Length, 0);
			StoneIDInSpellTable[stoneID] = table.getn(NECROSIS_SPELL_TABLE.Name);
		end
	end
	-- On met à jour la liste des sorts avec les nouveaux rangs
	for spell=1, table.getn(NECROSIS_SPELL_TABLE.Name), 1 do
		for index=1, table.getn(CurrentSpells.Name), 1 do
			if (NECROSIS_SPELL_TABLE.Name[spell] == CurrentSpells.Name[index]) then
				NECROSIS_SPELL_TABLE.ID[spell] = CurrentSpells.ID[index];
				NECROSIS_SPELL_TABLE.Rank[spell] = CurrentSpells.subName[index];
			end
		end
	end

	-- On met à jour la durée de chaque sort en fonction de son rang
	for index=1, table.getn(NECROSIS_SPELL_TABLE.Name), 1 do
		if (index == 9) then -- si Bannish
			if NECROSIS_SPELL_TABLE.ID[index] ~= nil then
				NECROSIS_SPELL_TABLE.Length[index] = NECROSIS_SPELL_TABLE.Rank[index]*10 + 10;
			end
		end
		if (index == 13)  then -- si Fear
			if NECROSIS_SPELL_TABLE.ID[index] ~= nil then
				NECROSIS_SPELL_TABLE.Length[index] = NECROSIS_SPELL_TABLE.Rank[index]*5 + 5;
			end
		end
		if (index == 14) then -- si Corruption
			if NECROSIS_SPELL_TABLE.ID[index] ~= nil and NECROSIS_SPELL_TABLE.Rank[index] < 3 then
				NECROSIS_SPELL_TABLE.Length[index] = NECROSIS_SPELL_TABLE.Rank[index]*3 + 9;		
			end
		end
	end
	for index=1, table.getn(NECROSIS_SPELL_TABLE.Name), 1 do
		NECROSIS_SPELL_TABLE.ID[index] = nil;
	end
	for spellID=1, MAX_SPELLS, 1 do
        local spellName, subSpellName = GetSpellName(spellID, "spell");
		if (spellName) then
			for index=1, table.getn(NECROSIS_SPELL_TABLE.Name), 1 do
				if NECROSIS_SPELL_TABLE.Name[index] == spellName then
					Necrosis_MoneyToggle();
					NecrosisTooltip:SetSpell(spellID, 1);
					local _, _, ManaCost = string.find(NecrosisTooltipTextLeft2:GetText(), "(%d+)");
					Necrosis_MoneyToggle();
					NECROSIS_SPELL_TABLE.ID[index] = spellID;
					NECROSIS_SPELL_TABLE.Mana[index] = tonumber(ManaCost);
				end
			end
		end
	end
	if NECROSIS_SPELL_TABLE.ID[1] or NECROSIS_SPELL_TABLE.ID[2] then
		MountAvailable = true;
	else
		MountAvailable = false;
	end

	-- Insertion du plus haut rang de détection d'invisibilité connu
	if Invisible >= 1 then
		NECROSIS_SPELL_TABLE.ID[33] = InvisibleID;
		NECROSIS_SPELL_TABLE.Rank[33] = 0;
		NECROSIS_SPELL_TABLE.CastTime[33] = 0;
		NECROSIS_SPELL_TABLE.Length[33] = 0;
		Necrosis_MoneyToggle();
		NecrosisTooltip:SetSpell(InvisibleID, 1);
		local _, _, ManaCost = string.find(NecrosisTooltipTextLeft2:GetText(), "(%d+)");
		Necrosis_MoneyToggle();
		NECROSIS_SPELL_TABLE.Mana[33] = tonumber(ManaCost);
	end
end

-- Fonction d'extraction d'attribut de sort
-- F(type=string, string, int) -> Spell=table
function Necrosis_FindSpellAttribute(type, attribute, array)
	for index=1, table.getn(NECROSIS_SPELL_TABLE.Name), 1 do
		if string.find(NECROSIS_SPELL_TABLE[type][index], attribute) then return NECROSIS_SPELL_TABLE[array][index]; end
	end
	return nil;
end

-- Fonction pour caster un Eclat d'ombre depuis le bouton de la Transe de l'Ombre
-- L'éclat doit avoir le rang le plus haut
function Necrosis_CastShadowBolt()
	local spellID = Necrosis_FindSpellAttribute("Name", NECROSIS_NIGHTFALL.BoltName, "ID");
	if (spellID) then
		CastSpell(spellID, "spell");
	else
		Necrosis_Msg(NECROSIS_NIGHTFALL_TEXT.NoBoltSpell, "USER");
	end
end

------------------------------------------------------------------------------------------------------
-- FONCTIONS DIVERSES
------------------------------------------------------------------------------------------------------

-- Fonction pour savoir si une unité subit un effet
-- F(string, string)->bool
function Necrosis_UnitHasEffect(unit, effect)
	local index = 1;
	while UnitDebuff(unit, index) do
		Necrosis_MoneyToggle();
		NecrosisTooltip:SetUnitDebuff(unit, index);
		local DebuffName = tostring(NecrosisTooltipTextLeft1:GetText());
		Necrosis_MoneyToggle();
   		if (string.find(DebuffName, effect)) then
			return true;
		end
		index = index+1;
	end
	return false;
end

-- Function to check the presence of a buff on the unit.
-- Strictly identical to UnitHasEffect, but as WoW distinguishes Buff and DeBuff, so we have to.
function Necrosis_UnitHasBuff(unit, effect)
	local index = 1;
	while UnitBuff(unit, index) do
	-- Here we'll cheat a little. checking a buff or debuff return the internal spell name, and not the name we give at start
		-- So we use an API widget that will use the internal name to return the known name.
		-- For example, the "Curse of Agony" spell is internaly known as "Spell_Shadow_CurseOfSargeras". Much easier to use the first one than the internal one.
		Necrosis_MoneyToggle();
		NecrosisTooltip:SetUnitBuff(unit, index);
		local BuffName = tostring(NecrosisTooltipTextLeft1:GetText());
		Necrosis_MoneyToggle();
   		if (string.find(BuffName, effect)) then
			return true;
		end
		index = index+1;
	end
	return false;
end


-- Permet de reconnaitre quand le joueur gagne Crépuscule / Transe de l'ombre
function Necrosis_UnitHasTrance()
	local ID = -1;
	for buffID = 0, 24, 1 do
		local buffTexture = GetPlayerBuffTexture(buffID);
		if buffTexture == nil then break end
		if strfind(buffTexture, "Spell_Shadow_Twilight") then
			ID = buffID;
			break
		end
	end
	ShadowTranceID = ID;
end

-- Fonction pour gérer les actions effectuées par Necrosis au clic sur un bouton
function Necrosis_UseItem(type,button)
	Necrosis_MoneyToggle();
	NecrosisTooltip:SetBagItem("player", 17);
	local rightHand = tostring(NecrosisTooltipTextLeft1:GetText());
	Necrosis_MoneyToggle();

	-- Fonction pour utiliser une pierre de foyer dans l'inventaire
	-- soit il y en a une dans l'inventaire, et si c'était un click droit
	if type == "Hearthstone" and button == "RightButton" then
		if (HearthstoneOnHand) then
		-- on l'utilise
		UseContainerItem(HearthstoneLocation[1], HearthstoneLocation[2]);
		-- soit il n'y en a pas dans l'inventaire, on affiche un message d'erreur
		else
		Necrosis_Msg(NECROSIS_MESSAGE.Error.NoHearthStone, "USER");
		end
	end

	-- Si on clique sur le bouton de la pierre d'âme
	-- On met à jour le bouton pour savoir quel est le mode
	if (type == "Soulstone") then
		Necrosis_UpdateIcons();
		-- Si le mode = 2 (une pierre dans l'inventaire, pas de pierre utilisée)
		-- alors on l'utilise
		if (SoulstoneMode == 2) then
			-- Si un joueur est ciblé, sur le joueur (avec message d'alerte)
			-- Si un joueur n'est pas ciblé, sur le Démoniste (sans message)
			if UnitIsPlayer("target") then
				SoulstoneUsedOnTarget = true;
			else
				SoulstoneUsedOnTarget = false;
				TargetUnit("player");
			end
			UseContainerItem(SoulstoneLocation[1], SoulstoneLocation[2]);
			-- Pas besoin de faire un long test sur les sacs pour savoir que maintenant
			-- Il n'y a plus de pierre d'âme dans le sac (puisqu'on vient de l'utiliser)
			SoulstoneOnHand = false;
			-- Maintenant que l'on crée un timer sur la seesion, nous ne sortons plus d'un RL
			NecrosisRL = false;
			-- Et hop, on remet à jour l'affichage des boutons :)
			Necrosis_UpdateIcons();
		-- si il n'y a pas de pierre d'âme dans l'inventaire, alors on crée la pierre d'âme de rang le plus grand :)
		elseif (SoulstoneMode == 1) or (SoulstoneMode == 3) then
				if NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[1]] then
					CastSpell(NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[1]], "spell");
				else
					Necrosis_Msg(NECROSIS_MESSAGE.Error.NoSoulStoneSpell, "USER");
				end
			
		end
	-- Si on clique sur le bouton de la pierre de vie :
	elseif (type == "Healthstone") then
		-- soit il y en a une dans l'inventaire
		if HealthstoneOnHand then
			-- Dans ce cas si un pj allié est sélectionné, on lui donne la pierre
			-- Sinon, on l'utilise
			if NecrosisTradeRequest then
				PickupContainerItem(HealthstoneLocation[1], HealthstoneLocation[2]);
				ClickTradeButton(1);
				NecrosisTradeRequest = false;
				Trading = true;
				TradingNow = 3;
				return;
			elseif (UnitExists("target") and UnitIsPlayer("target") and UnitIsFriend("player", "target") and UnitName("target") ~= UnitName("player")) then
				PickupContainerItem(HealthstoneLocation[1], HealthstoneLocation[2]);
	        		if ( CursorHasItem() ) then
	            			DropItemOnUnit("target");
					Trading = true;
					TradingNow = 3;
				end
				return;
			end
			if (UnitHealth("player") == UnitHealthMax("player")) then
				Necrosis_Msg(NECROSIS_MESSAGE.Error.FullHealth, "USER");
			else
				SpellStopCasting();
				UseContainerItem(HealthstoneLocation[1], HealthstoneLocation[2]);
				local HealthstoneInUse = false
				if Necrosis_TimerExisteDeja(NECROSIS_COOLDOWN.Healthstone, SpellTimer) then
					HealthstoneInUse = true;
				end
				if not HealthstoneInUse then
					SpellGroup, SpellTimer = Necrosis_InsertTimerStone(type, nil, nil, SpellGroup, SpellTimer);
				end
			end
		-- soit il n'y en a pas dans l'inventaire, et la pierre de plus haut rang est créée
		else
			if NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[2]] then
					CastSpell(NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[2]], "spell");
			else
				Necrosis_Msg(NECROSIS_MESSAGE.Error.NoHealthStoneSpell, "USER");
			end
		end
	-- Au tour de la pierre de sort
	elseif (type == "Spellstone") then
		-- Si la pierre est équipée ou dans l'inventaire, un clic droit l'équipe / la déséquipe
		if (SpellstoneMode ~= 1 and button == "RightButton")
			-- Si la pierre n'est pas équipée, le raccourci clavier équipe la pierre
			or (SpellstoneMode == 2 and button == "Binding") then
			Necrosis_SwitchOffHand(type);
		-- Si la pierre est équipée, un clic gauche utilise la pierre	
		elseif SpellstoneMode == 3 then
				local start, duration, enable = GetInventoryItemCooldown("player", 17) ;
				UseInventoryItem(17);
				if duration == 0 or start == 0 then Necrosis_SwitchOffHand("Off-hand"); end
		-- sinon on crée la pierre :)
		elseif (SpellstoneMode == 1) then
			if NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[3]] then
					CastSpell(NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[3]], "spell");
			else
				Necrosis_Msg(NECROSIS_MESSAGE.Error.NoSpellStoneSpell, "USER");
			end
		end
	-- Meme chose pour la pierre de feu
	elseif (type == "Firestone") then
		-- Si la pierre n'existe pas, elle est créée
		if (FirestoneMode == 1) then
			if NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[4]] then
				CastSpell(NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[4]], "spell");
			else
				Necrosis_Msg(NECROSIS_MESSAGE.Error.NoFireStoneSpell, "USER");
			end
		-- Si la pierre existe, un clic droit l'équipe / la déséquiper
		elseif button ~= "LeftButton" then
			Necrosis_SwitchOffHand(type);
		end
	-- Si on clic sur le bouton de monture
	elseif (type == "Mount") then
		-- Soit c'est la monture épique
		if NECROSIS_SPELL_TABLE.ID[2] ~= nil then
			CastSpell(NECROSIS_SPELL_TABLE.ID[2], "spell");
			Necrosis_OnUpdate();
		-- Soit c'est la monture classique
		elseif NECROSIS_SPELL_TABLE.ID[1] ~= nil then
			CastSpell(NECROSIS_SPELL_TABLE.ID[1], "spell");
			Necrosis_OnUpdate();
		-- (Soit c'est rien :) )
		else
			Necrosis_Msg(NECROSIS_MESSAGE.Error.NoRiding, "USER");
		end
	end
end

-- Fonction permettant de permutter un objet main-gauche équipé avec un objet main-gauche de l'inventaire
function Necrosis_SwitchOffHand(type)
	if (type == "Spellstone") then
		if SpellstoneMode == 3 then
			if ItemOnHand then
				Necrosis_Msg("Equipe "..GetContainerItemLink(ItemswitchLocation[1],ItemswitchLocation[2])..NECROSIS_MESSAGE.SwitchMessage..GetInventoryItemLink("player",17), "USER");
				PickupInventoryItem(17);
				PickupContainerItem(ItemswitchLocation[1],ItemswitchLocation[2]);
			end
			return;
		else
			PickupContainerItem(SpellstoneLocation[1], SpellstoneLocation[2]);
			PickupInventoryItem(17);
			-- Le switch avec une pierre de sort implique un cooldown porté au timer
			if Necrosis_TimerExisteDeja(NECROSIS_COOLDOWN.Spellstone, SpellTimer) then
				SpellTimer = Necrosis_RetraitTimerParNom(NECROSIS_COOLDOWN.Spellstone, SpellTimer);
			end
			SpellGroup, SpellTimer = Necrosis_InsertTimerStone(type, nil, nil, SpellGroup, SpellTimer);
			return;
		end
	elseif (type == "Firestone") then
		if FirestoneMode == 3 then
			if ItemOnHand then
				PickupInventoryItem(17);
				PickupContainerItem(ItemswitchLocation[1],ItemswitchLocation[2]);
				Necrosis_Msg(NECROSIS_MESSAGE.EquipMessage..GetContainerItemLink(ItemswitchLocation[1],ItemswitchLocation[2])..NECROSIS_MESSAGE.SwitchMessage..GetInventoryItemLink("player",17), "USER");
			end
			return;
		else
			PickupContainerItem(FirestoneLocation[1], FirestoneLocation[2]);
			PickupInventoryItem(17);
			return;
		end
	end
	if (type == "OffHand") and UnitClass("player") == NECROSIS_UNIT_WARLOCK then
		if ItemswitchLocation[1] ~= nil and ItemswitchLocation[2] ~= nil then
			PickupContainerItem(ItemswitchLocation[1],ItemswitchLocation[2]);
			PickupInventoryItem(17);
		end
	end
end

function Necrosis_MoneyToggle()
    if( lOriginal_GameTooltip_ClearMoney ) then
		local text = getglobal("NecrosisTooltipTextLeft1");
		local itemString = text:GetText();
		if (itemString) then text:SetText(nil); end
		text = getglobal("NecrosisTooltipTextRight1");
		itemString = text:GetText();
		if (itemString) then text:SetText(nil); end
		GameTooltip_ClearMoney = lOriginal_GameTooltip_ClearMoney;
        lOriginal_GameTooltip_ClearMoney = nil;
    else
        lOriginal_GameTooltip_ClearMoney = GameTooltip_ClearMoney;
        GameTooltip_ClearMoney = Necrosis_GameTooltip_ClearMoney;
    end
end

function Necrosis_GameTooltip_ClearMoney()
    -- Intentionally empty; don't clear money while we use hidden tooltips
end


-- Fonction pour placer les boutons autour de Necrosis (et pour grossir / retracir l'interface...)
function Necrosis_UpdateButtonsScale()
	local NBRScale = (100 + (NecrosisConfig.NecrosisButtonScale - 85)) / 100;
	if NecrosisConfig.NecrosisButtonScale <= 95 then
		NBRScale = 1.1;
	end
	if NecrosisConfig.NecrosisLockServ then
		Necrosis_ClearAllPoints();
		HideUIPanel(NecrosisPetMenuButton);
		HideUIPanel(NecrosisBuffMenuButton);
		HideUIPanel(NecrosisMountButton);
		HideUIPanel(NecrosisFirestoneButton);
		HideUIPanel(NecrosisSpellstoneButton);
		HideUIPanel(NecrosisHealthstoneButton);
		HideUIPanel(NecrosisSoulstoneButton);
		local indexScale = -18;
		for index=1, 7, 1 do
			if NecrosisConfig.StonePosition[index] then
				if index == 1 and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[4]] then
					NecrosisFirestoneButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisFirestoneButton);
					indexScale = indexScale + 36;
				end
				if index == 2 and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[3]] then
					NecrosisSpellstoneButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisSpellstoneButton);
					indexScale = indexScale + 36;
				end
				if index == 3 and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[2]] then
					NecrosisHealthstoneButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisHealthstoneButton);
					indexScale = indexScale + 36;
				end
				if index == 4 and NECROSIS_SPELL_TABLE.ID[StoneIDInSpellTable[1]] then
					NecrosisSoulstoneButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisSoulstoneButton);
					indexScale = indexScale + 36;
				end	
				if index == 5 and BuffMenuCreate ~= {} then
					NecrosisBuffMenuButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisBuffMenuButton);
					indexScale = indexScale + 36;
				end
				if index == 6 and MountAvailable then
					NecrosisMountButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisMountButton);
					indexScale = indexScale + 36;
				end
				if index == 7 and PetMenuCreate ~= {} then
					NecrosisPetMenuButton:SetPoint("CENTER", "NecrosisButton", "CENTER", ((40 * NBRScale) * cos(NecrosisConfig.NecrosisAngle-indexScale)), ((40 * NBRScale) * sin(NecrosisConfig.NecrosisAngle-indexScale)));
					ShowUIPanel(NecrosisPetMenuButton);
					indexScale = indexScale + 36;
				end
			end
		end
	end
end 



-- Fonction (XML) pour rétablir les points d'attache par défaut des boutons
function Necrosis_ClearAllPoints()
	NecrosisFirestoneButton:ClearAllPoints();
	NecrosisSpellstoneButton:ClearAllPoints();
	NecrosisHealthstoneButton:ClearAllPoints();
	NecrosisSoulstoneButton:ClearAllPoints();
	NecrosisMountButton:ClearAllPoints();
	NecrosisPetMenuButton:ClearAllPoints();
	NecrosisBuffMenuButton:ClearAllPoints();
end

-- Fonction (XML) pour étendre la propriété NoDrag() du bouton principal de Necrosis sur tout ses boutons
function Necrosis_NoDrag()
	NecrosisFirestoneButton:RegisterForDrag("");
	NecrosisSpellstoneButton:RegisterForDrag("");
	NecrosisHealthstoneButton:RegisterForDrag("");
	NecrosisSoulstoneButton:RegisterForDrag("");
	NecrosisMountButton:RegisterForDrag("");
	NecrosisPetMenuButton:RegisterForDrag("");
	NecrosisBuffMenuButton:RegisterForDrag("");
end

-- Fonction (XML) inverse de celle du dessus
function Necrosis_Drag()
	NecrosisFirestoneButton:RegisterForDrag("LeftButton");
	NecrosisSpellstoneButton:RegisterForDrag("LeftButton");
	NecrosisHealthstoneButton:RegisterForDrag("LeftButton");
	NecrosisSoulstoneButton:RegisterForDrag("LeftButton");
	NecrosisMountButton:RegisterForDrag("LeftButton");
	NecrosisPetMenuButton:RegisterForDrag("LeftButton");
	NecrosisBuffMenuButton:RegisterForDrag("LeftButton");
end

-- Ouverture du menu des buffs
function Necrosis_BuffMenu(button)
	BuffMenuShow = not BuffMenuShow;
	if not BuffMenuShow then
		BuffVisible = false;
		NecrosisBuffMenuButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\BuffMenuButton-01");
		HideUIPanel(NecrosisBuffMenu1);
		HideUIPanel(NecrosisBuffMenu2);
		HideUIPanel(NecrosisBuffMenu3);
		HideUIPanel(NecrosisBuffMenu4);
		HideUIPanel(NecrosisBuffMenu5);
		HideUIPanel(NecrosisBuffMenu6);
		HideUIPanel(NecrosisBuffMenu7);
		NecrosisBuffMenu1:SetAlpha(1);
		NecrosisBuffMenu2:SetAlpha(1);
		NecrosisBuffMenu3:SetAlpha(1);
		NecrosisBuffMenu4:SetAlpha(1);
		NecrosisBuffMenu5:SetAlpha(1);
		NecrosisBuffMenu6:SetAlpha(1);
		NecrosisBuffMenu7:SetAlpha(1);
		AlphaBuffMenu = 1;
	else
		NecrosisBuffMenuButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\BuffMenuButton-02");
		-- Si clic droit, le menu de buff reste ouvert
		if button == "RightButton" then
			BuffVisible = true;
		end
		-- S'il n'existe aucun buff on ne fait rien
		if BuffMenuCreate == nil then
			return;
		end
		-- Sinon on affiche les icones
		for i = 1, table.getn(BuffMenuCreate), 1 do
			ShowUIPanel(BuffMenuCreate[i]);
		end
		AlphaBuffVar = GetTime() + 6;
	end
end

-- Ouverture du menu des démons
function Necrosis_PetMenu(button)
	PetMenuShow = not PetMenuShow;
	if not PetMenuShow then
		PetVisible = false;
		NecrosisPetMenuButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\PetMenuButton-01");
		HideUIPanel(NecrosisPetMenu1);
		HideUIPanel(NecrosisPetMenu2);
		HideUIPanel(NecrosisPetMenu3);
		HideUIPanel(NecrosisPetMenu4);
		HideUIPanel(NecrosisPetMenu5);
		HideUIPanel(NecrosisPetMenu6);
		HideUIPanel(NecrosisPetMenu7);
		HideUIPanel(NecrosisPetMenu8);
		NecrosisPetMenu1:SetAlpha(1);
		NecrosisPetMenu2:SetAlpha(1);
		NecrosisPetMenu3:SetAlpha(1);
		NecrosisPetMenu4:SetAlpha(1);
		NecrosisPetMenu5:SetAlpha(1);
		NecrosisPetMenu6:SetAlpha(1);
		NecrosisPetMenu7:SetAlpha(1);
		NecrosisPetMenu8:SetAlpha(1);
		AlphaPetMenu = 1;
	else
		NecrosisPetMenuButton:SetNormalTexture("Interface\\Addons\\Necrosis\\UI\\PetMenuButton-02");
		-- Si clic droit, le menu de pet reste ouvert
		if button == "RightButton" then
			PetVisible = true;
		end
		-- S'il n'existe aucun sort d'invocation on ne fait rien
		if PetMenuCreate == nil then
			return;
		end
		-- Sinon on affiche les icones
		for i = 1, table.getn(PetMenuCreate), 1 do
			ShowUIPanel(PetMenuCreate[i]);
		end
		AlphaPetVar = GetTime() + 3;
	end
end

-- A chaque changement du livre des sorts, au démarrage du mod, ainsi qu'au changement de sens du menu on reconstruit les menus des sorts
function Necrosis_CreateMenu()
	PetMenuCreate = {};
	BuffMenuCreate = {};
	local menutypep = nil;
	local indexposp = 5;
	local menutypeb = nil;
	local indexposb = 5;
	
	-- Si le sort de Domination corrompue existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[15] then
		menutypep = getglobal("NecrosisPetMenu1");
		menutypep:ClearAllPoints();
		menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
		indexposp = indexposp + NecrosisConfig.PetMenuPos;
		table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'invocation du Diablotin existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[3] then
			menutypep = getglobal("NecrosisPetMenu2");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			indexposp = indexposp + NecrosisConfig.PetMenuPos;
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'invocation du Marcheur existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[4] then
			menutypep = getglobal("NecrosisPetMenu3");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			indexposp = indexposp + NecrosisConfig.PetMenuPos;
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'invocation du Succube existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[5] then
			menutypep = getglobal("NecrosisPetMenu4");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			indexposp = indexposp + NecrosisConfig.PetMenuPos;
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'invocation du Felhunter existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[6] then
			menutypep = getglobal("NecrosisPetMenu5");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			indexposp = indexposp + NecrosisConfig.PetMenuPos;
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'invocation de l'Infernal existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[8] then
			menutypep = getglobal("NecrosisPetMenu6");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			indexposp = indexposp + NecrosisConfig.PetMenuPos;
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'invocation du Doomguard existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[30] then
			menutypep = getglobal("NecrosisPetMenu7");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			indexposp = indexposp + NecrosisConfig.PetMenuPos;
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'asservissement existe, on affiche le bouton dans le menu des pets
	if NECROSIS_SPELL_TABLE.ID[35] then
			menutypep = getglobal("NecrosisPetMenu8");
			menutypep:ClearAllPoints();
			menutypep:SetPoint("CENTER", "NecrosisPetMenuButton", "CENTER",indexposp + ((36 / NecrosisConfig.PetMenuPos) * 26) ,26);
			table.insert(PetMenuCreate, menutypep);
	end
	-- Si l'Armure Démoniaque existe, on affiche le bouton dans le menu des buffs
		if NECROSIS_SPELL_TABLE.ID[31] or NECROSIS_SPELL_TABLE.ID[36] then
				menutypeb = getglobal("NecrosisBuffMenu1");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				indexposb = indexposb + NecrosisConfig.BuffMenuPos;
				table.insert(BuffMenuCreate, menutypeb);
		end
		-- Si la respiration interminable existe, on affiche le bouton dans le menu des buffs
		if NECROSIS_SPELL_TABLE.ID[32] then
				menutypeb = getglobal("NecrosisBuffMenu2");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				indexposb = indexposb + NecrosisConfig.BuffMenuPos;
				table.insert(BuffMenuCreate, menutypeb);
		end
		-- Si la détection de l'invisibilité existe, on affiche le bouton dans le menu des buffs (au plus haut rang)
		if NECROSIS_SPELL_TABLE.ID[33] then
				menutypeb = getglobal("NecrosisBuffMenu3");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				indexposb = indexposb + NecrosisConfig.BuffMenuPos;
				table.insert(BuffMenuCreate, menutypeb);
		end
		-- Si la respiration interminable existe, on affiche le bouton dans le menu des buffs
		if NECROSIS_SPELL_TABLE.ID[34] then
				menutypeb = getglobal("NecrosisBuffMenu4");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				indexposb = indexposb + NecrosisConfig.BuffMenuPos;
				table.insert(BuffMenuCreate, menutypeb);
		end
		-- Si le banissement existe, on affiche le bouton dans le menu des buffs
		if NECROSIS_SPELL_TABLE.ID[9] then
				menutypeb = getglobal("NecrosisBuffMenu5");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				indexposb = indexposb + NecrosisConfig.BuffMenuPos;
				table.insert(BuffMenuCreate, menutypeb);
		end
		-- Si l'invocation de joueur existe, on affiche le bouton dans le menu des buffs
		if NECROSIS_SPELL_TABLE.ID[37] then
				menutypeb = getglobal("NecrosisBuffMenu6");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				indexposb = indexposb + NecrosisConfig.BuffMenuPos;
				table.insert(BuffMenuCreate, menutypeb);
		end
		-- Si le Lien Spirituel existe, on affiche le bouton dans le menu des buffs
		if NECROSIS_SPELL_TABLE.ID[38] then
				menutypeb = getglobal("NecrosisBuffMenu7");
				menutypeb:ClearAllPoints();
				menutypeb:SetPoint("CENTER", "NecrosisBuffMenuButton", "CENTER", indexposb + ((36 / NecrosisConfig.BuffMenuPos) * 26) ,26);
				table.insert(BuffMenuCreate, menutypeb);
		end
end

-- Gestion des casts du menu des buffs
function Necrosis_BuffCast(type)
	local TargetEnemy = false;
	if (not (UnitIsFriend("player","target"))) and type ~= 9 then
		TargetUnit("player");
		TargetEnemy = true;
	end
	-- Si le Démoniste possède la peau de démon mais pas l'armure démoniaque
	if not NECROSIS_SPELL_TABLE.ID[type] then
		CastSpell(NECROSIS_SPELL_TABLE.ID[36], "spell");
	else
		CastSpell(NECROSIS_SPELL_TABLE.ID[type], "spell");
	end
	if TargetEnemy then TargetLastTarget(); end
	AlphaBuffMenu = 1;
	AlphaBuffVar = GetTime() + 3;
end

-- Gestion des casts du menu des démons
function Necrosis_PetCast(type)
	if type == 8 and InfernalStone == 0 then
		Necrosis_Msg(NECROSIS_MESSAGE.Error.InfernalStoneNotPresent, "USER");
		return;
	elseif type == 30 and DemoniacStone == 0 then
		Necrosis_Msg(NECROSIS_MESSAGE.Error.DemoniacStoneNotPresent, "USER");
		return;
	elseif type ~= 15 and type ~= 3 and type ~= 8 and type ~= 30 and Soulshards == 0 then
		Necrosis_Msg(NECROSIS_MESSAGE.Error.SoulShardNotPresent, "USER");
		return;
	end
	CastSpell(NECROSIS_SPELL_TABLE.ID[type], "spell");
	AlphaPetMenu = 1;
	AlphaPetVar = GetTime() + 3;
end

-- Fonction permettant l'affichage des différentes pages du livre des configurations
function NecrosisGeneralTab_OnClick(id)
	local TabName;
	for index=1, 4, 1 do
		TabName = getglobal("NecrosisGeneralTab"..index);
		if index == id then
			TabName:SetChecked(1);
		else
			TabName:SetChecked(nil);
		end
	end
	if id == 1 then
		ShowUIPanel(NecrosisShardMenu);
		HideUIPanel(NecrosisMessageMenu);
		HideUIPanel(NecrosisButtonMenu);
		HideUIPanel(NecrosisGraphOptionMenu);
		NecrosisGeneralIcon:SetTexture("Interface\\QuestFrame\\UI-QuestLog-BookIcon");
		NecrosisGeneralPageText:SetText(NECROSIS_CONFIGURATION.Menu1);
	elseif id == 2 then
		HideUIPanel(NecrosisShardMenu);
		ShowUIPanel(NecrosisMessageMenu);
		HideUIPanel(NecrosisButtonMenu);
		HideUIPanel(NecrosisGraphOptionMenu);
		NecrosisGeneralIcon:SetTexture("Interface\\QuestFrame\\UI-QuestLog-BookIcon");
		NecrosisGeneralPageText:SetText(NECROSIS_CONFIGURATION.Menu2);
	elseif id == 3 then
		HideUIPanel(NecrosisShardMenu);
		HideUIPanel(NecrosisMessageMenu);
		ShowUIPanel(NecrosisButtonMenu);
		HideUIPanel(NecrosisGraphOptionMenu);
		NecrosisGeneralIcon:SetTexture("Interface\\QuestFrame\\UI-QuestLog-BookIcon");
		NecrosisGeneralPageText:SetText(NECROSIS_CONFIGURATION.Menu3);
	elseif id == 4 then
		HideUIPanel(NecrosisShardMenu);
		HideUIPanel(NecrosisMessageMenu);
		HideUIPanel(NecrosisButtonMenu);
		ShowUIPanel(NecrosisGraphOptionMenu);
		NecrosisGeneralIcon:SetTexture("Interface\\QuestFrame\\UI-QuestLog-BookIcon");
		NecrosisGeneralPageText:SetText(NECROSIS_CONFIGURATION.Menu4);
	end
end



-- Bon, pour pouvoir utiliser le Timer sur les sorts instants, j'ai été obligé de m'inspirer de Cosmos
-- Comme je ne voulais pas rendre le mod dépendant de Sea, j'ai repris ses fonctions
-- Apparemment, la version Stand-Alone de ShardTracker a fait pareil :) :)
Necrosis_Hook = function (orig,new,type)
	if(not type) then type = "before"; end
	if(not Hx_Hooks) then Hx_Hooks = {}; end
	if(not Hx_Hooks[orig]) then
		Hx_Hooks[orig] = {}; Hx_Hooks[orig].before = {}; Hx_Hooks[orig].before.n = 0; Hx_Hooks[orig].after = {}; Hx_Hooks[orig].after.n = 0; Hx_Hooks[orig].hide = {}; Hx_Hooks[orig].hide.n = 0; Hx_Hooks[orig].replace = {}; Hx_Hooks[orig].replace.n = 0; Hx_Hooks[orig].orig = getglobal(orig);
	else
		for key,value in Hx_Hooks[orig][type] do if(value == getglobal(new)) then return; end end
	end
	Necrosis_Push(Hx_Hooks[orig][type],getglobal(new)); setglobal(orig,function(...) Necrosis_HookHandler(orig,arg); end);
end

Necrosis_HookHandler = function (name,arg)
	local called = false; local continue = true; local retval;
	for key,value in Hx_Hooks[name].hide do
		if(type(value) == "function") then if(not value(unpack(arg))) then continue = false; end called = true; end
	end
	if(not continue) then return; end
	for key,value in Hx_Hooks[name].before do
		if(type(value) == "function") then value(unpack(arg)); called = true; end
	end
	continue = false;
	local replacedFunction = false;
	for key,value in Hx_Hooks[name].replace do
		if(type(value) == "function") then
			replacedFunction = true; if(value(unpack(arg))) then continue = true; end called = true;
		end
	end
	if(continue or (not replacedFunction)) then retval = Hx_Hooks[name].orig(unpack(arg)); end
	for key,value in Hx_Hooks[name].after do
		if(type(value) == "function") then value(unpack(arg)); called = true;end
	end
	if(not called) then setglobal(name,Hx_Hooks[name].orig); Hx_Hooks[name] = nil; end
	return retval;
end

function Necrosis_Push (table,val)
	if(not table or not table.n) then return nil; end
	table.n = table.n+1;
	table[table.n] = val;
end

function Necrosis_UseAction(id, number, onSelf)
	Necrosis_MoneyToggle();
	NecrosisTooltip:SetAction(id);
	local tip = tostring(NecrosisTooltipTextLeft1:GetText());
	Necrosis_MoneyToggle();
	if tip then
		SpellCastName = tip;
		SpellTargetName = UnitName("target");
		if not SpellTargetName then
			SpellTargetName = "";
		end
		SpellTargetLevel = UnitLevel("target");
		if not SpellTargetLevel then
			SpellTargetLevel = "";
		end
	end
end
