


#include "../Game_local.h"
#include "../spawner.h"
#include "AI_Manager.h"
#include "AI_Util.h"
#include "AAS_Find.h"

/*
===============================================================================

rvAIHelper

===============================================================================
*/

CLASS_DECLARATION( idEntity, rvAIHelper  )
	EVENT( EV_Activate,	rvAIHelper::Event_Activate )
END_CLASS

/*
================
rvAIHelper::rvAIHelper
================
*/
rvAIHelper::rvAIHelper ( void ) {
	helperNode.SetOwner( this );	
}

/*
================
rvAIHelper::Spawn
================
*/
void rvAIHelper::Spawn ( void ) {
	// Auto activate?
	if ( spawnArgs.GetBool ( "start_on" ) ) {
		PostEventMS ( &EV_Activate, 0, this );
	}
}

/*
================
rvAIHelper::IsCombat
================
*/
bool rvAIHelper::IsCombat ( void ) const {
	return false;
}


/*
================
rvAIHelper::OnActivate
================
*/
void rvAIHelper::OnActivate ( bool active ) {
	if ( active ) {
		ActivateTargets ( this );
	}
}

/*
================
rvAIHelper::Event_Activate
================
*/
void rvAIHelper::Event_Activate( idEntity *activator ) {
	if ( !helperNode.InList ( ) ) {	
		aiManager.RegisterHelper ( this );
		OnActivate ( true );
	} else { 
		aiManager.UnregisterHelper ( this );
		OnActivate ( false );
	}
}

/*
================
rvAIHelper::GetDirection
================
*/
idVec3 rvAIHelper::GetDirection	( const idAI* ai ) const {
	if ( ai->team == 0 ) {
		return GetPhysics()->GetAxis()[0];
	} 
	return -GetPhysics()->GetAxis()[0];
}

/*
================
rvAIHelper::ValidateDestination
================
*/
bool rvAIHelper::ValidateDestination ( const idAI* ent, const idVec3& dest ) const {
	return true;
}

/*
===============================================================================

rvAICombatHelper

===============================================================================
*/

class rvAICombatHelper : public rvAIHelper {
public:
	CLASS_PROTOTYPE( rvAICombatHelper );

	rvAICombatHelper ( void );

	void			Spawn				( void );

	virtual bool	IsCombat			( void ) const;
	virtual bool	ValidateDestination ( const idAI* ent, const idVec3& dest ) const;
	
protected:

	virtual void	OnActivate			( bool active );

	idEntityPtr<idLocationEntity>	location;
};

CLASS_DECLARATION( rvAIHelper, rvAICombatHelper )
END_CLASS

/*
================
rvAICombatHelper::rvAICombatHelper
================
*/
rvAICombatHelper::rvAICombatHelper ( void ) {
}

/*
================
rvAICombatHelper::Spawn
================
*/
void rvAICombatHelper::Spawn ( void ) {
}

/*
================
rvAICombatHelper::OnActivate
================
*/
void rvAICombatHelper::OnActivate ( bool active ) {
	rvAIHelper::OnActivate ( active );
	
	if ( active ) {
		if ( spawnArgs.GetBool ( "tetherLocation", "1" ) ) {
			location = gameLocal.LocationForPoint ( GetPhysics()->GetOrigin() );
		} else {
			location = NULL;
		}
	}
}

/*
================
rvAICombatHelper::IsCombat
================
*/
bool rvAICombatHelper::IsCombat ( void ) const {
	return true;
}

/*
================
rvAICombatHelper::ValidateDestination
================
*/
bool rvAICombatHelper::ValidateDestination ( const idAI* ai, const idVec3& dest ) const {
	// If tethering to a location then see if the location of the given points matches our tethered location
	if ( location ) {
		if ( gameLocal.LocationForPoint ( dest - ai->GetPhysics()->GetGravityNormal() * 32.0f ) != location ) {
			return false;
		}
	}

	// Is the destination on the wrong side of the helper?
	idVec3 origin;
	idVec3 dir;
	
	dir = GetDirection(ai);
	if ( ai->enemy.ent ) {
		origin  = ai->enemy.lastKnownPosition;
		origin -= (dir * ai->combat.attackRange[0]);
	} else {
		origin  = GetPhysics()->GetOrigin();
		origin -= (dir * 32.0f);
	}
	
	if ( dir * (origin-dest) < 0.0f ) {
		return false;
	}
	
	// Would this destination link us to the wrong helper?
	if ( static_cast< const rvAIHelper * >( aiManager.FindClosestHelper( dest ) ) != this ) {
		return false;
	}
	
	return true;
}

/*
===============================================================================

									rvAIAvoid

===============================================================================
*/

class rvAIAvoid : public idEntity {
public:
	CLASS_PROTOTYPE( rvAIAvoid );

	rvAIAvoid ( void );

	void	Spawn	( void );
};

CLASS_DECLARATION( idEntity, rvAIAvoid )
END_CLASS

/*
================
rvAIAvoid::rvAIAvoid
================
*/
rvAIAvoid::rvAIAvoid ( void ) {
} 

/*
================
rvAIAvoid::Spawn
================
*/
void rvAIAvoid::Spawn ( void ) {
	int team = -1;
	if ( !spawnArgs.GetInt ( "teamFilter", "-1", team ) ) {
		//hmm, no "teamFilter" set, check "team" since many were set up like this
		team = spawnArgs.GetInt ( "team", "-1" );
	}
	aiManager.AddAvoid ( GetPhysics()->GetOrigin(), spawnArgs.GetFloat ( "radius", "64" ), team );	
	PostEventMS ( &EV_Remove, 0 );
}

/*
===============================================================================

								rvAITrigger

===============================================================================
*/

const idEventDef AI_AppendFromSpawner ( "<appendFromSpawner>", "ee" );

CLASS_DECLARATION( idEntity, rvAITrigger )
	EVENT( EV_Activate,				rvAITrigger::Event_Activate )
	EVENT( AI_AppendFromSpawner,	rvAITrigger::Event_AppendFromSpawner )
END_CLASS

/*
================
rvAITrigger::rvAITrigger
================
*/
rvAITrigger::rvAITrigger( void ) {
}

/*
================
rvAITrigger::Spawn
================
*/
void rvAITrigger::Spawn ( void ) {
	nextTriggerTime = 0;
	wait = SEC2MS ( spawnArgs.GetFloat ( "wait", "-1" ) );
	
	conditionDead	= spawnArgs.GetBool ( "condition_dead", "0" );
	conditionTether = spawnArgs.GetBool ( "condition_tether", "0" );
	conditionStop	= spawnArgs.GetBool ( "condition_stop", "0" );
	
	percent			= spawnArgs.GetFloat ( "percent", "1" );
	
	// Start on by default?
	nextTriggerTime = spawnArgs.GetBool ( "start_on", "0" ) ? 0 : -1;
	if ( nextTriggerTime == 0 ) {
		BecomeActive ( TH_THINK );
	} else {
		BecomeInactive ( TH_THINK );
	}

	// If there are no conditions we are done
	if ( !conditionDead && !conditionTether && !conditionStop ) {
		gameLocal.Warning ( "No conditions specified on ai trigger entity '%s'", GetName ( ) );
		PostEventMS ( &EV_Remove, 0 );
	}
}

/*
================
rvAITrigger::Save
================
*/
void rvAITrigger::Save ( idSaveGame *savefile ) const {
	int i;
	savefile->WriteInt ( testAI.Num ( ) );
	for ( i = 0; i < testAI.Num(); i ++ ) {
		testAI[i].Save ( savefile );
	}

	savefile->WriteInt ( testSpawner.Num ( ) );
	for ( i = 0; i < testSpawner.Num(); i ++ ) {
		testSpawner[i].Save ( savefile );
	}
	
	savefile->WriteBool ( conditionDead );
	savefile->WriteBool ( conditionTether );
	savefile->WriteBool ( conditionStop );

	savefile->WriteInt ( wait );
	savefile->WriteInt ( nextTriggerTime );

	savefile->WriteFloat ( percent );
}

/*
================
rvAITrigger::Restore
================
*/
void rvAITrigger::Restore ( idRestoreGame *savefile ) {
	int i;
	int num;

	savefile->ReadInt ( num );
	if ( num < 0 || num > MAX_SAVEGAME_AI_TRIGGER_TESTS ) {
		savefile->Error( "rvAITrigger::Restore: invalid AI test count %d", num );
	}
	testAI.Clear ( );
	testAI.SetNum ( num );
	for ( i = 0; i < num; i ++ ) {
		testAI[i].Restore ( savefile );
	}

	savefile->ReadInt ( num );
	if ( num < 0 || num > MAX_SAVEGAME_AI_TRIGGER_TESTS ) {
		savefile->Error( "rvAITrigger::Restore: invalid spawner test count %d", num );
	}
	testSpawner.Clear ( );
	testSpawner.SetNum ( num );
	for ( i = 0; i < num; i ++ ) {
		testSpawner[i].Restore ( savefile );
	}

	savefile->ReadBool ( conditionDead );
	savefile->ReadBool ( conditionTether );
	savefile->ReadBool ( conditionStop );

	savefile->ReadInt ( wait );
	savefile->ReadInt ( nextTriggerTime );

	savefile->ReadFloat ( percent );
}

/*
================
rvAITrigger::Think
================
*/
void rvAITrigger::Think ( void ) {
	int		v;

	// Only trigger so often		
	if ( nextTriggerTime == -1 || gameLocal.time < nextTriggerTime ) {
		return;
	}

	// If we have any attached spawners then our condition cannot be met
	if ( testSpawner.Num() ) {
		for ( v = 0; v < testSpawner.Num(); v ++ ) {
			rvSpawner* spawner = testSpawner[v];
			if ( !spawner ) {
				testSpawner.RemoveIndex ( v );
				v--;
				continue;
			}
			return;
		}
	}

	// If we have no AI we are tracking then wait until we do
	if ( !testAI.Num ( ) ) {
		return;
	}
	
	int count = 0;
	for ( v = 0; v < testAI.Num(); v ++ ) {
		idAI* ai = testAI[v];
		if ( !ai ) {
			testAI.RemoveIndex ( v );
			v--;
			continue;
		}
		if ( !ai->aifl.dead ) {
			if ( conditionDead ) {
				continue;
			}
			if ( conditionTether && !ai->IsWithinTether ( ) ) {
				continue;
			}
			if ( conditionStop && ai->move.fl.moving ) {
				continue;
			}
		}
		count++;
	}
	
	// If result is true then we should fire our trigger now
	if ( count >= (int) ((float)testAI.Num()*percent) ) {
		ActivateTargets ( this );
		
		// If only triggering once just remove ourselves now
		if ( wait < 0 ) {
			nextTriggerTime = -1;
		} else {
			nextTriggerTime = gameLocal.time + wait;
		}
	}
}

/*
================
rvAITrigger::FindTargets
================
*/
void rvAITrigger::FindTargets ( void ) {
	int t;
	
	idEntity::FindTargets ( );
	
	for ( t = 0; t < targets.Num(); t ++ ) {
		idEntity* ent = targets[t];
		if ( !ent ) {
			continue;
		}
		if ( ent->IsType ( idAI::GetClassType ( ) ) ) {
			testAI.Append ( idEntityPtr<idAI>(static_cast<idAI*>(ent)) );
			targets.RemoveIndex ( t );
			t--;
			continue;
		}
		if ( ent->IsType ( rvSpawner::GetClassType ( ) ) ) {
			static_cast<rvSpawner*>(ent)->AddCallback ( this, &AI_AppendFromSpawner );
			testSpawner.Append ( idEntityPtr<rvSpawner>(static_cast<rvSpawner*>(ent)) );
			targets.RemoveIndex ( t );
			t--;
			continue;
		}
	}		
}

/*
================
rvAITrigger::Event_Activate
================
*/
void rvAITrigger::Event_Activate( idEntity *activator ) {
	
	// Add spawners and ai to the list when they come in
	if ( activator && activator->IsType ( idAI::GetClassType ( ) ) ) {
		testAI.Append ( idEntityPtr<idAI>(static_cast<idAI*>(activator)) );	
		return;
	}

	if ( nextTriggerTime == -1 ) {
		nextTriggerTime = 0;
		BecomeActive ( TH_THINK );
	} else {
		nextTriggerTime = -1;
		BecomeInactive ( TH_THINK );
	}
}

/*
================
rvAITrigger::Event_AppendFromSpawner
================
*/
void rvAITrigger::Event_AppendFromSpawner ( rvSpawner* spawner, idEntity* spawned ) {
	// If its an ai entity being spawned then add it to our test list
	if ( spawned && spawned->IsType ( idAI::GetClassType ( ) ) ) {	
		testAI.Append ( idEntityPtr<idAI>(static_cast<idAI*>(spawned)) );	
	}
}

/*
===============================================================================

								rvAITether

===============================================================================
*/
const idEventDef EV_TetherSetupLocation ( "tetherSetupLocation" );
const idEventDef EV_TetherGetLocation ( "tetherGetLocation" );
CLASS_DECLARATION( idEntity, rvAITether )
	EVENT( EV_Activate,					rvAITether::Event_Activate )
	EVENT( EV_TetherGetLocation,		rvAITether::Event_TetherGetLocation )
	EVENT( EV_TetherSetupLocation,		rvAITether::Event_TetherSetupLocation )
END_CLASS

/*
================
rvAITether::rvAITether
================
*/
rvAITether::rvAITether ( void ) {
}

/*
================
rvAITether::InitNonPersistentSpawnArgs
================
*/
void rvAITether::InitNonPersistentSpawnArgs ( void ) {
	tfl.canBreak   		 = spawnArgs.GetBool ( "allowBreak", "1" );
	tfl.autoBreak		 = spawnArgs.GetBool ( "autoBreak", "0" );
	tfl.forceRun   		 = spawnArgs.GetBool ( "forceRun", "0" );
	tfl.forceWalk  		 = spawnArgs.GetBool ( "forceWalk", "0" );
	tfl.becomeAggressive = spawnArgs.GetBool ( "becomeAggressive", "0" );
	tfl.becomePassive    = spawnArgs.GetBool ( "becomePassive",    "0" );

	// Check for both being set
	if ( tfl.forceRun && tfl.forceWalk ) {
		gameLocal.Warning ( "both forceRun and forceWalk were specified for tether '%s', forceRun will take precedence" );
		tfl.forceWalk = false;
	}
	if ( tfl.becomeAggressive && tfl.becomePassive ) {
		gameLocal.Warning ( "both becomePassive and becomeAggressive were specified for tether '%s', becomeAggressive will take precedence" );
		tfl.becomePassive = false;
	}
}

/*
================
rvAITether::Spawn
================
*/
void rvAITether::Spawn ( void ) {
	InitNonPersistentSpawnArgs ( );

	PostEventMS( &EV_TetherSetupLocation, 100 );
}

/*
================
rvAITether::Event_TetherSetupLocation
================
*/
void rvAITether::Event_TetherSetupLocation( void ) {
	//NOTE: we now do this right after spawn so we don't stomp other tether's locations
	//		if we activate after them and are in the same room as them.
	//		Dynamically-spawned locations are very, very bad!
	
	// All pre-existing locations should be placed and spread by now
	// Get the location entity we are attached to
	if ( spawnArgs.GetBool ( "location", "1" ) ) {
		location = gameLocal.LocationForPoint ( GetPhysics()->GetOrigin() - GetPhysics()->GetGravityNormal() * 32.0f );
		if ( !location ) {
			location = gameLocal.AddLocation ( GetPhysics()->GetOrigin() - GetPhysics()->GetGravityNormal() * 32.0f, "tether_location" );
		}
	} else {
		location = NULL;
	}
	PostEventMS( &EV_TetherGetLocation, 100 );
}

/*
================
rvAITether::Event_TetherGetLocation
================
*/
void rvAITether::Event_TetherGetLocation( void ) {
	//NOW: all locations should be made & spread, get our location (may not be the one
	//		we added, it could be be the same as another tether if it's in the same room as us)
	if ( spawnArgs.GetBool ( "location", "1" ) ) {
		location = gameLocal.LocationForPoint ( GetPhysics()->GetOrigin() - GetPhysics()->GetGravityNormal() * 32.0f );
	} else {
		location = NULL;
	}
}

/*
================
rvAITether::Save
================
*/
void rvAITether::Save ( idSaveGame *savefile ) const {
	location.Save( savefile );
}

/*
================
rvAITether::Restore
================
*/
void rvAITether::Restore ( idRestoreGame *savefile ) {
	location.Restore( savefile );
	
	InitNonPersistentSpawnArgs ( );
}

/*
================
rvAITether::ValidateAAS
================
*/
bool rvAITether::ValidateAAS ( idAI* ai ) {
	if ( !ai->aas ) {
		return false;
	}
	return true;
}

/*
================
rvAITether::ValidateDestination
================
*/
bool rvAITether::ValidateDestination ( idAI* ai, const idVec3& dest ) {
	if ( location ) {
		if ( gameLocal.LocationForPoint ( dest - ai->GetPhysics()->GetGravityNormal() * 32.0f ) != location ) {
			return false;
		}
	}
	return true;
}

/*
================
rvAITether::ValidateBounds
================
*/
bool rvAITether::ValidateBounds	( const idBounds& bounds ) {
	return true;
}

/*
================
rvAITether::FindGoal
================
*/
bool rvAITether::FindGoal ( idAI* ai, aasGoal_t& goal ) {
	rvAASFindGoalForTether findGoal ( ai, this );
	if ( !ai->aas->FindNearestGoal( goal, 
								ai->PointReachableAreaNum( ai->GetPhysics()->GetOrigin() ), 
								ai->GetPhysics()->GetOrigin(), 
								GetPhysics()->GetOrigin(), 
								ai->move.travelFlags, 
								0.0f, 0.0f,
								NULL, 0, findGoal ) ) {
		return false;
	}
	return true;
}


/*
================
rvAITether::Event_Activate
================
*/
void rvAITether::Event_Activate( idEntity *activator ) {
	int i;

	//WELL!  Turns out designers are binding tethers to movers, so we have to get our location *again* on activation...
	if ( spawnArgs.GetBool ( "location", "1" ) ) {
		location = gameLocal.LocationForPoint ( GetPhysics()->GetOrigin() - GetPhysics()->GetGravityNormal() * 32.0f );
	}

	if ( activator && activator->IsType ( idAI::GetClassType() ) ) {
		activator->ProcessEvent ( &EV_Activate, this );
	}
	
	// All targetted AI will be activated with the tether AI entity
	for ( i = 0; i < targets.Num(); i ++ ) {
		if ( !targets[i] ) {
			continue;
		}
		if ( targets[i]->IsType ( idAI::GetClassType() ) ) {
			targets[i]->ProcessEvent ( &EV_Activate, this );			
			
			// Aggressive/Passive stance change?
			if ( tfl.becomeAggressive ) {
				targets[i]->ProcessEvent ( &AI_BecomeAggressive );
		 	} else if ( tfl.becomePassive ) {
				targets[i]->ProcessEvent ( &AI_BecomePassive, false );
			}
		}
	}			
}

/*
================
rvAITether::DebugDraw
================
*/
void rvAITether::DebugDraw ( void ) {
	const idBounds& bounds = GetPhysics()->GetAbsBounds();
	gameRenderWorld->DebugBounds ( colorYellow, bounds.Expand ( 8.0f ) );
	gameRenderWorld->DebugArrow ( colorWhite, bounds.GetCenter(), bounds.GetCenter() + GetPhysics()->GetAxis()[0] * 16.0f, 8.0f );
	gameRenderWorld->DrawText( name.c_str(), bounds.GetCenter(), 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 );
	gameRenderWorld->DrawText( va( "#%d", entityNumber ), bounds.GetCenter() - GetPhysics()->GetGravityNormal() * 5.0f, 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 );	
}

/*
===============================================================================

								rvAITetherBehind

===============================================================================
*/

CLASS_DECLARATION( rvAITether, rvAITetherBehind )
END_CLASS

/*
================
rvAITetherBehind::InitNonPersistentSpawnArgs
================
*/
void rvAITetherBehind::InitNonPersistentSpawnArgs ( void ) {
	range = spawnArgs.GetFloat ( "range" );
}

/*
================
rvAITetherBehind::Spawn
================
*/
void rvAITetherBehind::Spawn ( void ) {
	InitNonPersistentSpawnArgs ( );
}

/*
================
rvAITetherBehind::Restore
================
*/
void rvAITetherBehind::Restore ( idRestoreGame* savefile ) {
	InitNonPersistentSpawnArgs ( );
}

/*
================
rvAITetherBehind::ValidateDestination
================
*/
bool rvAITetherBehind::ValidateDestination ( idAI* ai, const idVec3& dest ) {
	// Check base tether first
	if ( !rvAITether::ValidateDestination ( ai, dest ) ) {
		return false;
	}
	
	// Make sure we include the move range in the tether
	idVec3 origin;
	if ( range ) {
		origin = GetPhysics()->GetOrigin ( ) + GetPhysics()->GetAxis()[0] * GetOriginReachedRange() - GetPhysics()->GetAxis()[0] * range;
		if ( GetPhysics()->GetAxis()[0] * (origin-dest) > 0.0f ) {
			return false;
		}
	}			

	origin = GetPhysics()->GetOrigin ( ) - GetPhysics()->GetAxis()[0] * GetOriginReachedRange(); 			
	
	// Are we on wrong side of tether?
	return ( GetPhysics()->GetAxis()[0] * (origin-dest) ) >= 0.0f;
}

/*
================
rvAITetherBehind::ValidateBounds
================
*/
bool rvAITetherBehind::ValidateBounds ( const idBounds& bounds ) {
	if ( !rvAITether::ValidateBounds ( bounds ) ) {
		return false;
	}

	idPlane plane;
	int     side;
	plane.SetNormal ( GetPhysics()->GetAxis ( )[0] );
	plane.FitThroughPoint ( GetPhysics()->GetOrigin ( ) );
	side = bounds.PlaneSide ( plane );	
	return ( side == PLANESIDE_CROSS || side == PLANESIDE_BACK );
}

/*
================
rvAITetherBehind::DebugDraw
================
*/
void rvAITetherBehind::DebugDraw ( void ) {
	idVec3 dir;
	
	rvAITether::DebugDraw ( );	
	
	dir = GetPhysics()->GetGravityNormal ( ).Cross ( GetPhysics()->GetAxis()[0] );
	gameRenderWorld->DebugLine ( colorPink, 
								 GetPhysics()->GetOrigin() - dir * 1024.0f,
								 GetPhysics()->GetOrigin() + dir * 1024.0f );

	if ( range ) {
		idVec3 origin;
		origin = GetPhysics()->GetOrigin ( ) - GetPhysics()->GetAxis ( )[0] * range;
		gameRenderWorld->DebugArrow ( colorPink, GetPhysics()->GetOrigin(), origin, 5.0f );
		gameRenderWorld->DebugLine ( colorPink, 
									 origin - dir * 1024.0f,
									 origin + dir * 1024.0f );
	}	
}

/*
===============================================================================

								rvAITetherRadius

===============================================================================
*/

CLASS_DECLARATION( rvAITether, rvAITetherRadius )
END_CLASS

/*
================
rvAITetherRadius::InitNonPersistentSpawnArgs
================
*/
void rvAITetherRadius::InitNonPersistentSpawnArgs ( void ) {
	float radius;
	if ( !spawnArgs.GetFloat ( "tetherRadius", "0", radius ) ) {	
		radius = spawnArgs.GetFloat ( "radius", "128" );
	}
	radiusSqr = Square ( radius );
}

/*
================
rvAITetherRadius::Spawn
================
*/
void rvAITetherRadius::Spawn ( void ) {
	InitNonPersistentSpawnArgs ( );
}

/*
================
rvAITetherRadius::Restore
================
*/
void rvAITetherRadius::Restore ( idRestoreGame* savefile ) {
	InitNonPersistentSpawnArgs ( );
}

/*
================
rvAITetherRadius::ValidateDestination
================
*/
bool rvAITetherRadius::ValidateDestination ( idAI* ai, const idVec3& dest ) {
	// Check base tether first
	if ( !rvAITether::ValidateDestination ( ai, dest ) ) {
		return false;
	}
	// Are we within tether radius?
	return ((dest - GetPhysics()->GetOrigin()).LengthSqr ( ) < radiusSqr - Square ( ai->move.range ) );
}


/*
================
rvAITetherRadius::ValidateBounds
================
*/
bool rvAITetherRadius::ValidateBounds ( const idBounds& bounds ) {
	if ( !rvAITether::ValidateBounds ( bounds ) ) {
		return false;
	}
	return ( Square ( bounds.ShortestDistance ( GetPhysics()->GetOrigin ( ) ) ) < radiusSqr );
}

/*
================
rvAITetherRadius::DebugDraw
================
*/
void rvAITetherRadius::DebugDraw ( void ) {
	rvAITether::DebugDraw ( );
	gameRenderWorld->DebugCircle( colorPink, GetPhysics()->GetOrigin(), GetPhysics()->GetGravityNormal(), idMath::Sqrt(radiusSqr), 25 );
}


/*
===============================================================================

								rvAITetherClear

===============================================================================
*/

CLASS_DECLARATION( rvAITether, rvAITetherClear )
END_CLASS


/*
===============================================================================

								rvAIBecomePassive

===============================================================================
*/

CLASS_DECLARATION( idEntity, rvAIBecomePassive )
	EVENT( EV_Activate,	rvAIBecomePassive::Event_Activate )
END_CLASS

/*
================
rvAIBecomePassive::Event_Activate
================
*/
void rvAIBecomePassive::Event_Activate( idEntity *activator ) {
	int		i;
	bool	ignoreEnemies;
	
	ignoreEnemies = spawnArgs.GetBool ( "ignoreEnemies", "1" );
	
	// All targeted AI will become passive
	for ( i = 0; i < targets.Num(); i ++ ) {
		if ( !targets[i] ) {
			continue;
		}
		if ( targets[i]->IsType ( idAI::GetClassType() ) ) {
			targets[i]->ProcessEvent ( &AI_BecomePassive, ignoreEnemies );
		}
	}			
}

/*
===============================================================================

								rvAIBecomeAggressive

===============================================================================
*/

CLASS_DECLARATION( idEntity, rvAIBecomeAggressive )
	EVENT( EV_Activate,	rvAIBecomeAggressive::Event_Activate )
END_CLASS

/*
================
rvAIBecomeAggressive::Event_Activate
================
*/
void rvAIBecomeAggressive::Event_Activate( idEntity *activator ) {
	int i;
	
	// All targetted AI will become aggressive
	for ( i = 0; i < targets.Num(); i ++ ) {
		if ( !targets[i] ) {
			continue;
		}
		if ( targets[i]->IsType ( idAI::GetClassType() ) ) {
			targets[i]->ProcessEvent ( &AI_BecomeAggressive );
		}
	}			
}
