//::///////////////////////////////////////////////
//:: Detect Magic : On Enter
//:: jx_sp_detectmagica.nss
//:://////////////////////////////////////////////
/*
	The caster tries to detect magic in the area in front
	of him. It takes three rounds. If he performs another
	action instead of concentrating, he starts again.
	Round 1 : Detect the presence or absence of a magic.
			  Locate Dead Magic zones.
	Round 2 : Detect the number of magical aura and the
			  strength of the most powerful.
			  Detect the presence of Wild Magic zones.
	Round 3 : Detect the strength of each aura. A
			  successful Spellcraft craft permits to
			  discover the spell school of auras that are
			  in line of sight, and even to identify
			  magical items.
			  Locate Wild Magic zones.
*/
//:://////////////////////////////////////////////
//:: Created By: jallaix
//:: Created On: Aug 12, 2006
//:://////////////////////////////////////////////

#include "jx_inc_magic"
#include "jx_inc_magic_ident"
#include "x0_i0_position"



int DetectAuraPresence(object oCaster);
int DetectAuraNumber(object oCaster);
void DetectAuraPower(object oCaster);
int DetectWildMagicPresence(object oCaster);
void DetectWildMagicLocation(object oCaster);
void DetectDeadMagicZone(object oCaster);
void DetectMagicByRound(int iRoundCount, object oCaster, location lCaster, int iOperation = 0);



// For performance reasons, only look for the first 10 items in containers
const int JX_MAX_ITEMS_CONTAINED = 10;

// Messages
string MSG_AURA_PRESENT			= GetStringByStrRef(17079421);
string MSG_AURA_ABSENT			= GetStringByStrRef(17079422);
string MSG_AURA_NUMBER			= GetStringByStrRef(17079423);
string MSG_AURA_STRENGTH		= GetStringByStrRef(17079424);
string MSG_AURA_SCHOOL			= GetStringByStrRef(17079425);
string MSG_AURA_IDENTIFIED		= GetStringByStrRef(17079426);
string MSG_WILDMAGIC_DETECTED	= GetStringByStrRef(17079427);
string MSG_WILDMAGIC_LOCATED	= GetStringByStrRef(17079428);
string MSG_DEADDMAGIC_LOCATED	= GetStringByStrRef(17079429);
string MSG_WILDMAGIC_NOTLOCATED	= GetStringByStrRef(17079430);

// Detection of wild/dead magic zones
string TAG_WILDMAGIC = "jx_pl_wildmagic_border";
string TAG_DEADMAGIC = "jx_pl_deadmagic_border";


// Saved magical auras and wild magic boundaries informations
string sAurasDetected;
string sWildDetected;

// Update auras informations
void AddObjectAura(object oCaster, object oVisible, object oDetected, struct jx_magic_aura aura)
{
	if (sAurasDetected != "") sAurasDetected += ";";
	sAurasDetected += IntToString(ObjectToInt(oVisible)) + "," +
					  IntToString(ObjectToInt(oDetected)) + "," +
					  IntToString(aura.strength) + "," +
					  IntToString(aura.school);
}


//------------------------------------------------------------------
// Detect Magic (round 1) : Presence or absence of magical auras and
//                          Wild Magic zones
// * Returns  : 0 if no magical presence detected
//              1 if a magical aura is detected
//              2 if a wild magic zone is detected
//              3 if a magical aura & a wild magic zone are detected
//------------------------------------------------------------------
int DetectAuraPresence(object oCaster)
{
	int bAuraDetected = FALSE;
	int bWildMagicDetected = FALSE;

	object oItemContained;		// For items in containers
	int iItemCount;				// To count the number of items in containers

	// Loop objects in the cone area
	location lTarget = GetAheadLocation(oCaster, 18.3);
	object oDetected = GetFirstObjectInShape(SHAPE_CONE, 5.0, lTarget, FALSE,
	 OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, GetPosition(oCaster));
	while (GetIsObjectValid(oDetected))
	{
		if (oDetected != oCaster)
		{
			// Test if the item has a magical aura
			if (GetObjectType(oDetected) == OBJECT_TYPE_ITEM)
			{
				// Detect the item's magical aura
				if (JXGetMagicalAura(oDetected).strength != JX_AURASTRENGTH_NONE)
					bAuraDetected = TRUE;
				else if (GetHasInventory(oDetected))
				{
					// If the item is a container, loop items inside
					iItemCount = 1;
					oItemContained = GetFirstItemInInventory(oDetected);
					while (GetIsObjectValid(oItemContained) && (iItemCount <= JX_MAX_ITEMS_CONTAINED))
					{
						// Detect the contained item's magical aura
						if (JXGetMagicalAura(oItemContained).strength != JX_AURASTRENGTH_NONE)
						{
							bAuraDetected = TRUE;
							break;
						}
						iItemCount++;
						oItemContained = GetNextItemInInventory(oDetected);
					}
				}
			}

			// Test if a creature holds a magical aura
			else if (GetObjectType(oDetected) == OBJECT_TYPE_CREATURE)
			{
				// Detect the creature's magical aura
				if (JXGetMagicalAura(oDetected).strength != JX_AURASTRENGTH_NONE)
					bAuraDetected = TRUE;
				else
				{
					// Loop all items the creature holds (not in her inventory, for performance reasons)
					object oItemHeld; int iLoop;
					for (iLoop = 0; iLoop < 14; iLoop++)
					{
						oItemHeld = GetItemInSlot(iLoop, oDetected);
						if (GetIsObjectValid(oItemHeld))
							// Detect the held item's magical aura
							if (JXGetMagicalAura(oItemHeld).strength != JX_AURASTRENGTH_NONE)
							{
								bAuraDetected = TRUE;
								break;
							}
					}
				}
			}

			// Test if a placeable is a container that contains magical items
			else if (GetObjectType(oDetected) == OBJECT_TYPE_PLACEABLE)
			{
				// Wild Magic zone detected
				if (GetTag(oDetected) == TAG_WILDMAGIC)
					bWildMagicDetected = TRUE;
			 	else if (GetHasInventory(oDetected))
				{
					// Loop all items in the container
					iItemCount = 1;
					oItemContained = GetFirstItemInInventory(oDetected);
					while (GetIsObjectValid(oItemContained) && (iItemCount <= JX_MAX_ITEMS_CONTAINED))
					{
						// Detect the contained item's magical aura
						if (JXGetMagicalAura(oItemContained).strength != JX_AURASTRENGTH_NONE)
						{
							bAuraDetected = TRUE;
							break;
						}
						iItemCount++;
						oItemContained = GetNextItemInInventory(oDetected);
					}
				}
			}
		}

		oDetected = GetNextObjectInShape(SHAPE_CONE, 5.0, lTarget, FALSE,
		 OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, GetPosition(oCaster));
	}

	// No magic present
	if (!bAuraDetected && !bWildMagicDetected)
	{
		FloatingTextStringOnCreature(MSG_AURA_ABSENT, oCaster);
		return 0;
	}
	else
		FloatingTextStringOnCreature(MSG_AURA_PRESENT, oCaster);

	// Magical aura present
	if (bAuraDetected && !bWildMagicDetected)
		return 1;
	// Wild Magic present
	else if (!bAuraDetected && bWildMagicDetected)
		return 2;
	// Magical aura & Wild Magic present
	else
		return 3;

	return 0;
}


//-----------------------------------------------------------------------------------
// Detect Magic (round 2) : Number of magical auras and strength of the most powerful
//-----------------------------------------------------------------------------------
int DetectAuraNumber(object oCaster)
{
	// Variables used to hold auras and their associated objects
	object oBestAuraObject;						// Object associated with the best aura in the area
	object oBestLocalAuraObject;				// Object associated with the best aura from an object and what it contains
	struct jx_magic_aura auraBest;				// Contains the best aura in the area
	struct jx_magic_aura auraBestLocal;			// Contains the best aura from an object and what it contains

	// Variables of work
	int iAuraCount = 0;							// Number of auras detected
	struct jx_magic_aura aura;					// Temporary aura holder
	int iAuraAlreadyDetected;					// To avoid detecting more than 1 aura on an object
	object oItemContained;						// For items in containers
	int iItemCount;								// To count the number of items in containers

	// Initialize the variable that contains the list of detected auras
	sAurasDetected = "";
	// Initialize the variable that will contain the best aura found in the area
	auraBest.strength = JX_AURASTRENGTH_NONE;
	auraBest.school = SPELL_SCHOOL_GENERAL;

	// Loop objects in the cone area
	location lTarget = GetAheadLocation(oCaster, 18.3);
	object oDetected = GetFirstObjectInShape(SHAPE_CONE, 5.0, lTarget, TRUE,
	 OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, GetPosition(oCaster));
	while (GetIsObjectValid(oDetected))
	{
		if (oDetected != oCaster)
		{
			// Initialize variables associated on the current object
			iAuraAlreadyDetected = FALSE;
			auraBestLocal.strength = JX_AURASTRENGTH_NONE;
			auraBestLocal.school = SPELL_SCHOOL_GENERAL;
			oBestLocalAuraObject = OBJECT_INVALID;

			// Test if the item has a magical aura and detect its strength
			if (GetObjectType(oDetected) == OBJECT_TYPE_ITEM)
			{
				// Detect the item's magical aura
				aura = JXGetMagicalAura(oDetected);
				if (aura.strength != JX_AURASTRENGTH_NONE)
				{
					iAuraCount++; iAuraAlreadyDetected = TRUE;
					// Most powerful aura detected in the area
					if (aura.strength > auraBest.strength)
					{
						oBestAuraObject = oDetected;
						auraBest = aura;
					}
					// Most powerful aura detected on the item
					if (aura.strength > auraBestLocal.strength)
					{
						oBestLocalAuraObject = oDetected;
						auraBestLocal = aura;
					}
				}
				if (GetHasInventory(oDetected))
				{
					// If the item is a container, loop all items inside
					iItemCount = 1;
					oItemContained = GetFirstItemInInventory(oDetected);
					while (GetIsObjectValid(oItemContained) && (iItemCount <= JX_MAX_ITEMS_CONTAINED))
					{
						// Detect the contained item's magical aura
						aura = JXGetMagicalAura(oItemContained);
						if (aura.strength != JX_AURASTRENGTH_NONE)
						{
							// Increase the aura counter only if another one hasn't been previously detected on the item
							if (!iAuraAlreadyDetected) { iAuraCount++; iAuraAlreadyDetected = TRUE; }
							// Most powerful aura detected in the area
							if (aura.strength > auraBest.strength)
							{
								// If the aura is better than the one of the container,
								// do like if the aura comes from the container
								oBestAuraObject = oDetected;
								auraBest = aura;
							}
							// Most powerful aura detected on the item
							if (aura.strength > auraBestLocal.strength)
							{
								oBestLocalAuraObject = oItemContained;
								auraBestLocal = aura;
							}
						}
						iItemCount++;
						oItemContained = GetNextItemInInventory(oDetected);
					}
				}
				AddObjectAura(oCaster, oDetected, oBestLocalAuraObject, auraBestLocal);
			}

			// Test if a creature holds a magical aura and detect its strength
			else if (GetObjectType(oDetected) == OBJECT_TYPE_CREATURE)
			{
				// Detect the creature's magical aura
				aura = JXGetMagicalAura(oDetected);
				if (aura.strength != JX_AURASTRENGTH_NONE)
				{
					iAuraCount++; iAuraAlreadyDetected = TRUE;
					// Most powerful aura detected in the area
					if (aura.strength > auraBest.strength)
					{
						oBestAuraObject = oDetected;
						auraBest = aura;
					}
					// Most powerful aura detected on the creature
					if (aura.strength > auraBestLocal.strength)
					{
						oBestLocalAuraObject = oDetected;
						auraBestLocal = aura;
					}
				}
				// Loop all items the creature holds (not in her inventory, for performance reasons)
				object oItemHeld; int iLoop;
				for (iLoop = 0; iLoop < 14; iLoop++)
				{
					oItemHeld = GetItemInSlot(iLoop, oDetected);
					if (GetIsObjectValid(oItemHeld))
					{
						// Detect the held item's magical aura
						aura = JXGetMagicalAura(oItemHeld);
						if (aura.strength != JX_AURASTRENGTH_NONE)
						{
							// Increase the aura counter only if another one hasn't been previously detected on the creature
							if (!iAuraAlreadyDetected) { iAuraCount++; iAuraAlreadyDetected = TRUE; }
							// Most powerful aura detected in the area
							if (aura.strength > auraBest.strength)
							{
								// If the aura is better than the one of the creature,
								// do like if the aura comes from the creature
								oBestAuraObject = oDetected;
								auraBest = aura;
							}
							// Most powerful aura detected on the item
							if (aura.strength > auraBestLocal.strength)
							{
								oBestLocalAuraObject = oItemHeld;
								auraBestLocal = aura;
							}
						}
					}
				}
				AddObjectAura(oCaster, oDetected, oBestLocalAuraObject, auraBestLocal);
			}

			// Test if a placeable is a container that contains magical items
			else if ((GetObjectType(oDetected) == OBJECT_TYPE_PLACEABLE) && GetHasInventory(oDetected))
			{
				// Loop all items in the container
				iItemCount = 1;
				oItemContained = GetFirstItemInInventory(oDetected);
				while (GetIsObjectValid(oItemContained) && (iItemCount <= JX_MAX_ITEMS_CONTAINED))
				{
					// Detect the contained item's magical aura
					aura = JXGetMagicalAura(oItemContained);
					if (aura.strength != JX_AURASTRENGTH_NONE)
					{
						// Increase the aura counter only if another one hasn't been previously detected inside the placeable
						if (!iAuraAlreadyDetected) { iAuraCount++; iAuraAlreadyDetected = TRUE; }
						// Most powerful aura detected in the area
						if (aura.strength > auraBest.strength)
						{
							// If the aura is better than the one of the creature,
							// do like if the aura comes from the placeable
							oBestAuraObject = oDetected;
							auraBest = aura;
						}
						// Most powerful aura detected on the item
						if (aura.strength > auraBestLocal.strength)
						{
							oBestLocalAuraObject = oItemContained;
							auraBestLocal = aura;
						}
					}
					iItemCount++;
					oItemContained = GetNextItemInInventory(oDetected);
				}
				AddObjectAura(oCaster, oDetected, oBestLocalAuraObject, auraBestLocal);
			}
		}

		oDetected = GetNextObjectInShape(SHAPE_CONE, 5.0, lTarget, TRUE,
		 OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, GetPosition(oCaster));
	}

	// Print a message only visible to the caster and his party : Number of magical auras and strength of the most powerful
	if (iAuraCount > 0)
	{
		string messageTemp = JXStringReplaceToken(MSG_AURA_NUMBER, 850, IntToString(iAuraCount));
		messageTemp = JXStringReplaceToken(messageTemp, 851, JXGetMagicalAuraStrengthName(auraBest.strength));
		FloatingTextStringOnCreature(messageTemp, oCaster, TRUE);
		return TRUE;
	}
	else
		return FALSE;
}


//------------------------------------------------------------------
// Detect Magic (round 3) : Strength and school of each magical aura
//------------------------------------------------------------------
void DetectAuraPower(object oCaster)
{
	// Aura information
	object oVisible;
	object oDetected;
	string sAura;
	struct jx_magic_aura aura;
	int iSpellSchoolDetected;
	int iItemIdentified;

	// Get the objects and auras previously saved
	int iCount = JXStringSplitCount(sAurasDetected, ";");
	int iLoop;
	for (iLoop = 0; iLoop < iCount; iLoop++)
	{
		iSpellSchoolDetected = FALSE;
		iItemIdentified = FALSE;

		// Find the informations about an aura
		sAura = JXStringSplit(sAurasDetected, ";", iLoop);
		oVisible = IntToObject(StringToInt(JXStringSplit(sAura, ",", 0)));
		oDetected = IntToObject(StringToInt(JXStringSplit(sAura, ",", 1)));
		aura.strength = StringToInt(JXStringSplit(sAura, ",", 2));
		aura.school = StringToInt(JXStringSplit(sAura, ",", 3));

		// Object in line of sight => Try to identify the aura's spell school
		if (oVisible == oDetected)
		{
			// No spell school detection if the caster hasn't trained his Spellcraft skill
            int iSpellcraftRank = GetSkillRank(SKILL_SPELLCRAFT, oCaster);
			if (iSpellcraftRank > 0)
			{
	            // Make a spellcraft roll
	            int iSpellcraftRoll = iSpellcraftRank + d20();

				// Magical aura from a creature
				if (GetObjectType(oDetected) == OBJECT_TYPE_CREATURE)
				{
					//Fire cast spell at event for the target
					SignalEvent(oDetected, EventSpellCastAt(oCaster, JX_SPELL_DETECTMAGIC, FALSE));

					int iBestSpellId = -1;
					int iBestSpellLevel = -1;
					
					// Look for the best spell effect on the creature
					int iSpellIdTemp;
					int iSpellLevelTemp;
					effect eSpellTemp = GetFirstEffect(oDetected);
					while (GetIsEffectValid(eSpellTemp))
					{
						iSpellIdTemp = GetEffectSpellId(eSpellTemp);
						if (iSpellIdTemp > -1)
						{
							iSpellLevelTemp = GetSpellLevel(iSpellIdTemp);
							if (iSpellLevelTemp > iBestSpellLevel)
							{
								iBestSpellId = iSpellIdTemp;
								iBestSpellLevel = iSpellLevelTemp;
							}
						}
						eSpellTemp = GetNextEffect(oDetected);
					}
				
				    // Make a spellcraft check to determine the aura's spell school
					if (iSpellcraftRoll >= (15 + iBestSpellLevel))
						iSpellSchoolDetected = TRUE;
				}
	
				// Magical aura from an item
				else if (GetObjectType(oDetected) == OBJECT_TYPE_ITEM)
				{
					//Fire cast spell at event for the target
					SignalEvent(oDetected, EventSpellCastAt(oCaster, JX_SPELL_DETECTMAGIC, FALSE));

					// Find the item caster level
					string sMagicalProperties = GetLocalString(oDetected, JX_ITEM_MAGICAL_PROPERTIES);
					int iItemCasterLevel = JXGetItemCasterLevel(oDetected, sMagicalProperties);
			
				    // Make a spellcraft check to determine the aura's spell school
					if (iSpellcraftRoll >= (15 + iItemCasterLevel / 2))
					{
						iSpellSchoolDetected = TRUE;
	
					    // If the spellcraft check bypass the DC by 10, the item is identified
					    if (iSpellcraftRoll >= (25 + iItemCasterLevel / 2))
						{
							JXIdentifyItem(oDetected);
							iItemIdentified = TRUE;
						}
					}
				}
			}
		}

		string sMessage;
		// Give the aura informations to the caster
		if (!iSpellSchoolDetected)
		{
			sMessage = JXStringReplaceToken(MSG_AURA_STRENGTH, 850, JXGetMagicalAuraStrengthName(aura.strength));
			AssignCommand(oVisible, SpeakString(sMessage));
		}
		// Spell School detected
		else
		{
			if (iItemIdentified)
			{
				sMessage = JXStringReplaceToken(MSG_AURA_IDENTIFIED, 850, GetName(oVisible));
				sMessage = JXStringReplaceToken(sMessage, 851, JXGetMagicalAuraStrengthName(aura.strength));
				sMessage = JXStringReplaceToken(sMessage, 852, JXGetSpellSchoolName(aura.school));
			}
			else
			{
				sMessage = JXStringReplaceToken(MSG_AURA_SCHOOL, 850, JXGetMagicalAuraStrengthName(aura.strength));
				sMessage = JXStringReplaceToken(sMessage, 851, JXGetSpellSchoolName(aura.school));
			}
			AssignCommand(oVisible, SpeakString(sMessage));
		}
	}
}


//-------------------------------------------------------------
// Detect Wild Magic : Detect the presence of a Wild Magic zone
//-------------------------------------------------------------
int DetectWildMagicPresence(object oCaster)
{
	int bWildMagicDetected = FALSE;

	sWildDetected = "";

	// Loop placeables in the cone area
	location lTarget = GetAheadLocation(oCaster, 18.3);
	vector vCaster = GetPosition(oCaster);
	object oDetected = GetFirstObjectInShape(SHAPE_CONE, 5.0, lTarget, FALSE, OBJECT_TYPE_PLACEABLE, vCaster);
	while (GetIsObjectValid(oDetected))
	{
		// Wild magic border detected
		if (GetTag(oDetected) == TAG_WILDMAGIC)
		{
			if (sWildDetected != "") sWildDetected += ";";
			sWildDetected += IntToString(ObjectToInt(oDetected));
			bWildMagicDetected = TRUE;
		}

		oDetected = GetNextObjectInShape(SHAPE_CONE, 5.0, lTarget, FALSE,
		 OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, vCaster);
	}

	// Print a message only visible to the caster and his party : Wild Magic Zone detected
	if (bWildMagicDetected)
		FloatingTextStringOnCreature(MSG_WILDMAGIC_DETECTED, oCaster, TRUE);

	return bWildMagicDetected;
}


//-------------------------------------------------------------
// Detect Wild Magic : Detect the location of a Wild Magic zone
//-------------------------------------------------------------
void DetectWildMagicLocation(object oCaster)
{
	int bWildMagicLocated = FALSE;
	int bSpellcraftCheck = FALSE;

	effect eWildMagic = EffectNWN2SpecialEffectFile("fx_ore");
	object oDetected;
	int bVFXPresent;

	// Make a spellcraft check DC 25 to determine the borders of the zone
	// (no Wild Magic localisation if the caster hasn't trained in Spellcraft)
	int iSpellcraftRank = GetSkillRank(SKILL_SPELLCRAFT, oCaster);
	if (iSpellcraftRank > 0)
		if (iSpellcraftRank + d20() >= 25)
			bSpellcraftCheck = TRUE;

	// Get the objects and auras previously saved
	int iCount = JXStringSplitCount(sWildDetected, ";");
	int iLoop;
	for (iLoop = 0; iLoop < iCount; iLoop++)
	{
		// Find a detected Wild Magic zone border
		oDetected = IntToObject(StringToInt(JXStringSplit(sWildDetected, ";", iLoop)));

		bVFXPresent = FALSE;
		if (GetIsEffectValid(GetFirstEffect(oDetected)))
			bVFXPresent = TRUE;

		// Show the Wild Magic border by applying a VFX on the detected placeables
		if (!bVFXPresent && bSpellcraftCheck)
		{
			ApplyEffectToObject(DURATION_TYPE_PERMANENT, eWildMagic, oDetected);
			bWildMagicLocated = TRUE;
		}
	}


	// Print a message only visible to the caster and his party : Wild Magic Zone located
	if (bWildMagicLocated)
		FloatingTextStringOnCreature(MSG_WILDMAGIC_LOCATED, oCaster, TRUE);
	else
		FloatingTextStringOnCreature(MSG_WILDMAGIC_NOTLOCATED, oCaster, TRUE);
}


//--------------------------------------------------------------------
// Detect Dead Magic : Determine the boundaries of the dead magic zone
//--------------------------------------------------------------------
void DetectDeadMagicZone(object oCaster)
{
	int bDeadMagicDetected = FALSE;

	effect eDeadMagic = EffectNWN2SpecialEffectFile("fx_ore");
	int bVFXPresent;

	// Loop placeables in the cone area
	location lTarget = GetAheadLocation(oCaster, 18.3);
	vector vCaster = GetPosition(oCaster);
	object oDetected = GetFirstObjectInShape(SHAPE_CONE, 5.0, lTarget, FALSE, OBJECT_TYPE_PLACEABLE, vCaster);
	while (GetIsObjectValid(oDetected))
	{
		// Dead Magic border detected
		if (GetTag(oDetected) == TAG_DEADMAGIC)
		{
			bVFXPresent = FALSE;
			if (GetIsEffectValid(GetFirstEffect(oDetected)))
				bVFXPresent = TRUE;

			// Show the Dead Magic border by applying a VFX on the detected placeables
			if (!bVFXPresent)
			{
				ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDeadMagic, oDetected);
				bDeadMagicDetected = TRUE;
			}
		}

		oDetected = GetNextObjectInShape(SHAPE_CONE, 5.0, lTarget, TRUE,
		 OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE, vCaster);
	}

	// Print a message only visible to the caster and his party : Dead Magic Zone located
	if (bDeadMagicDetected)
		FloatingTextStringOnCreature(MSG_DEADDMAGIC_LOCATED, oCaster, TRUE);
}




//---------------------------------------------------------------
// Detect Magic (round manager) : Determine the action to perform
// - iOperation : 0 to detect magical auras
//                1 to detect wild magic
//                2 to detect magical auras & wild magic
//---------------------------------------------------------------
void DetectMagicByRound(int iRoundCount, object oCaster, location lCaster, int iOperation = 0)
{
	// If the caster is not concentrating or if his position has changed, wait for the next round
	if ((GetCurrentAction(oCaster) != ACTION_INVALID) || (GetLocation(oCaster) != lCaster))
	{
		DelayCommand(6.0f, DetectMagicByRound(1, oCaster, GetLocation(oCaster)));
		return;
	}

	int bResultDetectAuraNumber = FALSE;
	int bResultDetectWildMagic = FALSE;
	switch (iRoundCount)
	{
		case 1:
			// Locate a Dead Magic zone
			DetectDeadMagicZone(oCaster);
			// Detect the presence of a magic
			switch (DetectAuraPresence(oCaster))
			{
				case 0 :	// No magic detected
					DelayCommand(6.0f, DetectMagicByRound(0, oCaster, lCaster));
					break;
				case 1 :	// Magical aura detected
					DelayCommand(6.0f, DetectMagicByRound(2, oCaster, lCaster));
					break;
				case 2 : 	// Wild Magic detected
					DelayCommand(6.0f, DetectMagicByRound(2, oCaster, lCaster, 1));
					break;
				case 3 :	// Magical aura & Wild Magic detected
					DelayCommand(6.0f, DetectMagicByRound(2, oCaster, lCaster, 2));
					break;
			}
			break;
		case 2:
			// Detect the number of magical auras
			if ((iOperation == 0) || (iOperation == 2))
				bResultDetectAuraNumber = DetectAuraNumber(oCaster);
			// Detect the presence of Wild Magic
			if ((iOperation == 1) || (iOperation == 2))
				bResultDetectWildMagic = DetectWildMagicPresence(oCaster);
			// Process round 3
			if (bResultDetectAuraNumber && !bResultDetectWildMagic)
				DelayCommand(6.0f, DetectMagicByRound(3, oCaster, lCaster));
			else if (!bResultDetectAuraNumber && bResultDetectWildMagic)
				DelayCommand(6.0f, DetectMagicByRound(3, oCaster, lCaster, 1));
			else if (bResultDetectAuraNumber && bResultDetectWildMagic)
				DelayCommand(6.0f, DetectMagicByRound(3, oCaster, lCaster, 2));
			else
				DelayCommand(6.0f, DetectMagicByRound(0, oCaster, lCaster));
			break;
		case 3:
			// Detect the power of the magical auras
			if ((iOperation == 0) || (iOperation == 2))
				DetectAuraPower(oCaster);
			if ((iOperation == 1) || (iOperation == 2))
				DetectWildMagicLocation(oCaster);
			DelayCommand(6.0f, DetectMagicByRound(0, oCaster, lCaster));
			break;
		default:
			DelayCommand(6.0f, DetectMagicByRound(0, oCaster, lCaster));
			break;
	}
}


//-----------------------------------------------
// Detect Magic (main function) : Start detection
//-----------------------------------------------
void main()
{
	object oCaster = GetEnteringObject();

	// Test if the entering object is the caster
	object oAOECreator = JXGetAOERealCreator();
	if (oAOECreator != oCaster) return;

	DetectMagicByRound(1, oCaster, GetLocation(oCaster));
}