//-----------------------------------------------------------------------------
//
//  $Logfile:: /Code/DLLs/game/behavior.cpp                                  $
// $Revision:: 135                                                            $
//   $Author:: Steven                                                         $
//     $Date:: 10/13/03 9:11a                                                 $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// Behaviors used by the AI.
//

#include "_pch_cpp.h"
//#include "g_local.h"
#include "behavior.h"
#include "actor.h"
#include "doors.h"
#include "object.h"
#include "explosion.h"
#include "weaputils.h"
#include "player.h"

Event EV_Behavior_Args
	(
	"args",
	EV_CODEONLY,
	"SSSSSS",
	"token1 token2 token3 token4 token5 token6",
	"Gives the current behavior arguments."
	);
Event EV_Behavior_AnimDone
	(
	"animdone",
	EV_CODEONLY,
	NULL,
	NULL,
	"Tells the behavior that the current animation is done, "
	"it is not meant to be called from script."
	);
Event EV_PostureChanged_Completed
	(
	"posturechangecompleted",
	EV_CODEONLY,
	NULL,
	NULL,
	"Tells the behavior that the requested posture is active"
	);

Vector ChooseRandomDirection( Actor &self, const Vector &previousdir, float *time, int disallowcontentsmask, qboolean usepitch );

/****************************************************************************

  Behavior Class Definition

****************************************************************************/

CLASS_DECLARATION( Listener, Behavior, NULL )
	{
		{ NULL, NULL }
	};

Behavior::Behavior()
:	_controller( 0 ) // NULL
	{
	_self = NULL;
	}

void Behavior::ShowInfo
	(
	Actor &self
	)

	{
   if ( movegoal )
      {
      gi.Printf( "movegoal: ( %f, %f, %f ) - '%s'\n",
         movegoal->origin.x, movegoal->origin.y, movegoal->origin.z, movegoal->targetname.c_str() );
      }
   else
      {
      gi.Printf( "movegoal: NULL\n" );
      }
	}

void Behavior::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	Behavior::Evaluate
	(
	Actor &self
	)

	{
	return BEHAVIOR_SUCCESS;
	}

void Behavior::End
	(
	Actor &self
	)

	{
	}



/****************************************************************************
*****************************************************************************

  General behaviors

*****************************************************************************
****************************************************************************/



/****************************************************************************

  Idle Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Idle, NULL )
	{
		{ NULL, NULL }
	};

void Idle::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nnexttwitch : %f\n", nexttwitch );
	}

void Idle::Begin
	(
	Actor &self
	)

	{
	nexttwitch = level.time + 10.0f + G_Random( 30.0f );
	self.SetAnim( "idle", EV_Actor_NotifyBehavior );
	}

BehaviorReturnCode_t	Idle::Evaluate
	(
	Actor &self
	)

	{
	if ( self.enemyManager->GetCurrentEnemy() )
		{
		return BEHAVIOR_EVALUATING;
		}

	if ( nexttwitch < level.time )
		{
		self.chattime += 10.0f;
		self.AddStateFlag( STATE_FLAG_TWITCH );
		return BEHAVIOR_EVALUATING;
		}
	else
		{
		//self.Chatter( "snd_idle", 1 );		
		}

	return BEHAVIOR_EVALUATING;
	}

void Idle::End
	(
	Actor &self
	)

	{
	
	}

/****************************************************************************

  Pain Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Pain, NULL )
	{
		{ &EV_Behavior_AnimDone,	&Pain::AnimDone },
		{ NULL, NULL }
	};

void Pain::SetPainAnim
	(
	Actor &self,
	int new_pain_type,
	int new_anim_number
	)

	{
	str anim_name;

	// Determine which pain type to play

	if ( new_pain_type == PAIN_SMALL )
		anim_name = "pain_small";
	else
		anim_name = "pain";

	// Try to find the correct anim to play

	anim_name += new_anim_number;

	if ( !self.animate->HasAnim( anim_name.c_str() ) )
		{
		if ( new_pain_type == PAIN_SMALL )
			anim_name = "pain_small1";
		else
			anim_name = "pain1";

		pain_anim_number = 1;
		}

	anim_done = false;

	// Play the animation if we can

	if ( !self.animate->HasAnim( anim_name.c_str() ) )
		anim_done = true;
	else
		self.SetAnim( anim_name.c_str(), EV_Actor_NotifyBehavior );
	}

int Pain::GetNumberOfPainAnims
	(
	Actor &self,
	int new_pain_type
	)

	{
	str anim_name;
	str real_anim_name;
	int i;


	// Determine base animation name

	if ( new_pain_type == PAIN_SMALL )
		anim_name = "pain_small";
	else
		anim_name = "pain";

	// Find how many pain animations we have

	for( i = 1 ; i < 10 ; i++ )
		{
		real_anim_name = anim_name + i;

		if ( !self.animate->HasAnim( real_anim_name.c_str() ) )
			return( i - 1 );
		}

	return 9;
	}

void Pain::Begin
	(
	Actor &self
	)

	{
	str anim_name;
	int num_pain_anims;

	num_pain_anims = GetNumberOfPainAnims( self, self.pain_type );

	pain_anim_number = (int)G_Random( num_pain_anims ) + 1;

	// Figure out which type of pain to do

	if ( self.pain_type == PAIN_SMALL )
		SetPainAnim( self, PAIN_SMALL, pain_anim_number );
	else
		SetPainAnim( self, PAIN_BIG, pain_anim_number );

	current_pain_type = self.pain_type;
	number_of_pains   = 1;

	// Make sure we don't have pain any more

	self.state_flags &= ~STATE_FLAG_SMALL_PAIN;
	self.state_flags &= ~STATE_FLAG_IN_PAIN;

	max_pains = (int)G_Random( 4 ) + 4;
	}

void Pain::AnimDone
	(
	Event *ev
	)
	{
	anim_done = true;
	}

BehaviorReturnCode_t	Pain::Evaluate
	(
	Actor &self
	)

	{
	str anim_name;

	if ( self.state_flags & STATE_FLAG_SMALL_PAIN )
		{
		// See if we should play another pain animation

		if ( ( self.means_of_death != MOD_FIRE ) && ( self.means_of_death != MOD_ON_FIRE ) && ( self.means_of_death != MOD_FIRE_BLOCKABLE ) )
			{
			if ( ( self.pain_type == PAIN_SMALL ) && ( current_pain_type == PAIN_SMALL ) && ( number_of_pains < max_pains ) )
				{
				pain_anim_number++;

				number_of_pains++;

				SetPainAnim( self, PAIN_SMALL, pain_anim_number );
				}
			else if ( self.pain_type == PAIN_BIG )
				{
				pain_anim_number++;

				current_pain_type = PAIN_BIG;

				SetPainAnim( self, PAIN_BIG, pain_anim_number );
				}
			}

		// Reset pain stuff

		self.state_flags &= ~STATE_FLAG_SMALL_PAIN;
		self.state_flags &= ~STATE_FLAG_IN_PAIN;
		}

	// If the pain animation has finished, then we are done

	if ( anim_done )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void Pain::End
	(
	Actor &self
	)

	{
	self.bullet_hits = 0;
	}

/****************************************************************************

  Watch Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Watch, NULL )
	{
		{ &EV_Behavior_Args,			&Watch::SetArgs },
		{ NULL, NULL }
	};

Watch::Watch()
	{
	turn_speed = 360.0f;
	old_turn_speed = 0.0f;
	}

void Watch::SetArgs
	(
	Event *ev
	)

	{
	turn_speed = ev->GetFloat( 1 );
	}

void Watch::Begin
	(
	Actor &self
	)

	{
	ent_to_watch = self.enemyManager->GetCurrentEnemy();

	old_turn_speed = self.movementSubsystem->getTurnSpeed();
	self.movementSubsystem->setTurnSpeed( turn_speed );

	Vector test;
	Vector testAng;

	test = self.movementSubsystem->getMoveDir();
	testAng = test.toAngles();
	}

BehaviorReturnCode_t	Watch::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;

	Vector testAng;
	dir = self.movementSubsystem->getMoveDir();
	testAng = dir.toAngles();

	if ( !ent_to_watch )
		return BEHAVIOR_SUCCESS;

	if ( self.IsEntityAlive( ent_to_watch ) )
		{		
		dir = self.movementSubsystem->getMoveDir();

		testAng = dir.toAngles();

		self.movementSubsystem->Accelerate( 
			self.movementSubsystem->SteerTowardsPoint(ent_to_watch->centroid, vec_zero, dir, 1.0f)
			);
		}

	return BEHAVIOR_EVALUATING;
	}

void Watch::End
	(
	Actor &self
	)

	{
	self.movementSubsystem->setTurnSpeed( old_turn_speed );	
	}

/****************************************************************************

  Turn Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Turn, NULL )
	{
		{ &EV_Behavior_Args,			&Turn::SetArgs },
		{ NULL, NULL }
	};

Turn::Turn()
	{
	turn_speed = 5;
	}

void Turn::SetArgs
	(
	Event *ev
	)

	{
	turn_speed = ev->GetFloat( 1 );
	}

void Turn::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	Turn::Evaluate
	(
	Actor &self
	)

	{
	self.angles[YAW] += turn_speed;

	self.setAngles( self.angles );

	return BEHAVIOR_EVALUATING;
	}

void Turn::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  Aim Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Aim, NULL )
	{
		{ NULL, NULL }
	};

void Aim::SetTarget
	(
	Entity *ent
	)

	{
	target = ent;
	}

void Aim::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nseek:\n" );
   if ( target )
      {
      gi.Printf( "\ntarget : #%d '%s'\n", target->entnum, target->targetname.c_str() );
      }
   else
      {
      gi.Printf( "\ntarget : NULL\n" );
      }
	}

void Aim::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	Aim::Evaluate
	(
	Actor &self
	)

	{
   Vector dir;
   Vector ang;
   Vector pos;

	if ( !target )
		{
		return BEHAVIOR_SUCCESS;
		}

   //
   // get my gun pos
   //

	// Fixme ?
   //pos = self.GunPosition();
   //ang = self.MyGunAngles( pos, false );
	pos = self.centroid;
	ang = self.angles;
   ang.AngleVectors( &dir, NULL, NULL );
	Vector newSteeringDirection=self.movementSubsystem->SteerTowardsPoint(target->centroid, target->velocity, dir, 1400 + ( skill->value * 600 ));
	self.movementSubsystem->Accelerate( newSteeringDirection	);
	//self.Accelerate( seek.steeringforce );
	if ( newSteeringDirection.y < 0.25f )
		{
		// dead on
		return BEHAVIOR_SUCCESS;
		}

	return BEHAVIOR_EVALUATING;
	}

void Aim::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  TurnTo Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, TurnTo, NULL )
	{
		{ &EV_Behavior_AnimDone,	&TurnTo::AnimDone },
		{ NULL, NULL }
	};

TurnTo::TurnTo()
	{
	dir = Vector( 1.0f, 0.0f, 0.0f );
	mode = 0;
	ent = NULL;
   yaw = 0;
	anim_done = true;
	useTurnAnim = true;
	_useAnims = true;
	}

void TurnTo::SetDirection
	(
	float new_yaw
	)

	{
	Vector ang;

	ang = Vector( 0.0f, new_yaw, 0.0f );
	yaw = anglemod( new_yaw );
	ang.AngleVectors( &dir, NULL, NULL );
	dir *= 100.0f;
	mode = 1;
	}

void TurnTo::useAnims( bool useAnims )
{
	_useAnims = useAnims;
}

void TurnTo::SetTarget
	(
	Entity *target_ent
	)

	{
	ent = target_ent;
	mode = 2;
	}

void TurnTo::AnimDone
	(
	Event *ev
	)

	{
	anim_done = true;
	}

void TurnTo::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nseek:\n" );

   if ( ent )
      {
      gi.Printf( "\nent: #%d '%s'\n", ent->entnum, ent->targetname.c_str() );
      }
   else
      {
      gi.Printf( "\nent: NULL\n" );
      }

   gi.Printf( "dir: ( %f, %f, %f )\n", dir.x, dir.y, dir.z );
   gi.Printf( "yaw: %f\n", yaw );
   gi.Printf( "mode: %d\n", mode );
	}

void TurnTo::Begin( Actor &self )
{
	extraFrames = 0;
	
	if ( _useAnims )
	{
		self.SetAnim( "idle" );
	}
}

BehaviorReturnCode_t	TurnTo::Evaluate( Actor &self )
{
	Vector delta;
	float ang;
	str anim_name;
	
	Vector targetPosition;
	Vector targetVelocity;
	
	if ( anim_done )
	{
		if ( _useAnims )
		{
			self.SetAnim( "idle" );
		}
		anim_done = false;
	}
	
	switch( mode )
	{
	case 1 :
		ang = angledist( yaw - self.angles.yaw() );
		if ( fabs( ang ) < 1 )
		{
			self.movementSubsystem->Accelerate( Vector( 0.0f, ang, 0.0f ) );
			
			// If turned all the way wait for animation to finish
			
			if ( anim_done || ( self.animname == "idle" ) || !_useAnims )
				return BEHAVIOR_SUCCESS;
			else
				return BEHAVIOR_EVALUATING;
		}
		
		targetPosition = self.origin + dir ;
		targetVelocity = vec_zero ;
		break;
		
	case 2 :
		if ( !ent )
		{
			return BEHAVIOR_SUCCESS;
		}
		
		delta = ent->origin - self.origin;
		yaw = delta.toYaw();
		
		targetPosition =  ent->origin;
		targetVelocity = vec_zero;
		break;
		
	default :
		return BEHAVIOR_SUCCESS;
	}
	
	Vector newSteeringForce = 
		self.movementSubsystem->SteerTowardsPoint(
		targetPosition, 
		targetVelocity, 
		self.movementSubsystem->getMoveDir(), 
		self.movementSubsystem->getMoveSpeed()
		);
	
	if ( _useAnims )
	{
		if ( extraFrames < 1 )
		{				
			if ( useTurnAnim )
			{
				if ( newSteeringForce[YAW] > 1.0f )
				{
					anim_name = "turn_left";
					anim_done = false;
				}
				else if ( newSteeringForce[YAW] < -1.0f )
				{
					anim_name = "turn_right";
					anim_done = false;
				}
				else if ( anim_done )
				{
					anim_name = "idle";
				}
				else
				{
					anim_name = self.animname;
				}
			}
			else
			{
				anim_name = "idle";
			}
			
			if ( gi.Anim_NumForName( self.edict->s.modelindex, anim_name.c_str() ) != -1 )
			{
				if ( anim_name != self.animname )
					self.SetAnim( anim_name.c_str(), EV_Actor_NotifyBehavior );
			}
			else
			{
				anim_done = true;
			}
		}
	}
	
	extraFrames++;
	if ( extraFrames > 4 || anim_name == "idle" )
	{
		extraFrames = 5;
		self.movementSubsystem->Accelerate( newSteeringForce );	
	}
	
	return BEHAVIOR_EVALUATING;
}

void TurnTo::End( Actor &self )
{
	if ( _useAnims )
	{
		self.SetAnim( "idle" );
	}

	self.movementSubsystem->setMoveSpeed( 1.0 );
}

void TurnTo::SetUseTurnAnim( bool useAnim )
	{
	useTurnAnim = useAnim;
	}

/****************************************************************************

  RotateToEnemy Class Definition -- Primarily a convience wrapper for TurnTo

****************************************************************************/
CLASS_DECLARATION( Behavior, RotateToEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&RotateToEnemy::SetArgs },
		{ NULL, NULL }
	};

void RotateToEnemy::SetArgs
   (
	Event *ev
	)

	{
	if (ev->NumArgs() > 0 )
		anim = ev->GetString(1);
	else
		anim = "idle";

	if (ev->NumArgs() > 1 )
		turnSpeed = ev->GetFloat(2);
	else
		turnSpeed = 10;
	}

void RotateToEnemy::Begin
   (
	Actor &self
	)

	{

	}

BehaviorReturnCode_t RotateToEnemy::Evaluate
   (
	Actor &self
	)

	{
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	Vector dir = currentEnemy->origin - self.origin;
	float yaw_diff = AngleNormalize360( self.origin.toYaw() - dir.toYaw() );
	
	if (yaw_diff < 180.0f )
		self.angles[YAW]+=turnSpeed;

	if (yaw_diff > 180.0f )
		self.angles[YAW]-=turnSpeed;

	self.setAngles(self.angles);

	if (self.sensoryPerception->InFOV(currentEnemy) )
		return BEHAVIOR_SUCCESS;
	else
		return BEHAVIOR_EVALUATING;
	}

void RotateToEnemy::End
   (
	Actor &self
	)

	{

	}

/****************************************************************************

  HeadWatch Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, HeadWatch, NULL )
	{
		{ &EV_Behavior_Args,	&HeadWatch::SetArgs },
		{ NULL, NULL }
	};

HeadWatch::HeadWatch()
	{
	max_speed = 15;
	forever = true;
	usingEyes = false;
	}

void HeadWatch::SetArgs
	(
	Event *ev
	)

	{
	ent_to_watch = ev->GetEntity( 1 );

	if ( ev->NumArgs() > 1 )
		max_speed = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		forever = ev->GetBoolean( 3 );
	}


void HeadWatch::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void HeadWatch::Begin
	(
	Actor &self
	)

	{
	self.SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" ) );

	current_head_angles = self.GetControllerAngles( ACTOR_HEAD_TAG );

	self.SetActorFlag( ACTOR_FLAG_TURNING_HEAD, true );
	}

BehaviorReturnCode_t	HeadWatch::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	int tag_num;	
	Vector tag_pos;
	Vector watch_tag_pos;
	Vector angles_diff;
	Vector watch_position;
	Actor *act = NULL;
	Vector change;
	

	if ( ent_to_watch )
		{
		tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" );

		if ( tag_num < 0 )
			return BEHAVIOR_SUCCESS;

		self.GetTag( "Bip01 Head", &tag_pos );

		if ( ent_to_watch->isSubclassOf( Actor ) )
			act = (Actor *)(Entity *)ent_to_watch;

		if ( act && ( act->watch_offset != vec_zero ) )
			{
			MatrixTransformVector( act->watch_offset, ent_to_watch->orientation, watch_position );
			watch_position += ent_to_watch->origin;
			}
		else
			{			
			tag_num = gi.Tag_NumForName( ent_to_watch->edict->s.modelindex, "Bip01 Head" );
			
			if ( tag_num < 0 )
				watch_position = ent_to_watch->centroid;
			else
				{
				ent_to_watch->GetTag( "Bip01 Head", &watch_tag_pos );
				watch_position = watch_tag_pos;
				}
			}

		dir = watch_position - tag_pos;
		angles = dir.toAngles();

		angles_diff = angles - self.angles;
		}
	else
		{
		angles_diff = vec_zero;
		}

	angles_diff[YAW]   = AngleNormalize180( angles_diff[YAW] );
	angles_diff[PITCH] = AngleNormalize180( angles_diff[PITCH] );

	if (usingEyes)
		{
		if (angles_diff[YAW] > (self.minEyeYawAngle + (self.minEyeYawAngle * .5f )) && angles_diff[YAW] < (self.maxEyeYawAngle + (self.maxEyeYawAngle * .5f )))
			angles_diff[YAW] = 0.0f;
		if (angles_diff[PITCH] > self.minEyePitchAngle && angles_diff[PITCH] < self.maxEyePitchAngle )
		   angles_diff[PITCH] = 0.0f;
		}

	// Make sure we don't turn neck too far
	
	if ( angles_diff[YAW] < -80.0f )
		angles_diff[YAW] = -80.0f;
	else if ( angles_diff[YAW] > 80.0f )
		angles_diff[YAW] = 80.0f;

	if ( angles_diff[PITCH] < -45.0f )
		angles_diff[PITCH] = -45.0f;
	else if ( angles_diff[PITCH] > 45.0f )
		angles_diff[PITCH] = 45.0f;

	angles_diff[ROLL] = 0.0f;

	// Make sure we don't change our head angles too much at once

	change = angles_diff - current_head_angles;
	float absYaw = fabs( change[ YAW ] );
	float absPitch = fabs( change[ PITCH ] );

	if( ( absYaw < fEpsilon() ) && ( absPitch < fEpsilon() ) )
	{
		if( forever )
		{
			self.SetControllerAngles( ACTOR_HEAD_TAG, current_head_angles );
			return BEHAVIOR_EVALUATING;
		}
		else
			return BEHAVIOR_SUCCESS;
	}

	//change = vec_zero;

	bool isFinished = true;
	if( absYaw >= absPitch )
	{
		float ratioPitchToYaw = change[ PITCH ] / change[ YAW ];

		if( change[ YAW ] > max_speed )
		{
			change[ YAW ] = max_speed;
			isFinished = false;
		}
		else if( change[ YAW ] < -max_speed )
		{
			change[ YAW ] = -max_speed;
			isFinished = false;
		}
		change[ PITCH ] = change[ YAW ] * ratioPitchToYaw;
	}
	else if( absPitch > absYaw )
	{
		float ratioYawToPitch = change[ YAW ] / change[ PITCH ];

		if( change[ PITCH ] > max_speed )
		{
			change[ PITCH ] = max_speed;
			isFinished = false;
		}
		else if( change[ PITCH ] < -max_speed )
		{
			change[ PITCH ] = -max_speed;
			isFinished = false;
		}
		change[ YAW ] = change[ PITCH ] * ratioYawToPitch;
	}

	angles_diff = current_head_angles + change;
	angles_diff[ ROLL ] = 0.0f;

/*
	if ( change[YAW] > max_speed )
		angles_diff[YAW] = current_head_angles[YAW] + max_speed;
	else if ( change[YAW] < -max_speed )
		angles_diff[YAW] = current_head_angles[YAW] - max_speed;

	if ( change[PITCH] > max_speed )
		angles_diff[PITCH] = current_head_angles[PITCH] + max_speed;
	else if ( change[PITCH] < -max_speed )
		angles_diff[PITCH] = current_head_angles[PITCH] - max_speed;
*/
	self.SetControllerAngles( ACTOR_HEAD_TAG, angles_diff );
	self.real_head_pitch = angles_diff[PITCH];

	current_head_angles = angles_diff;	
	
	if ( !ent_to_watch && ( current_head_angles == vec_zero ) )
		return BEHAVIOR_SUCCESS;

//	if ( !forever && ( change[YAW] < max_speed ) && ( change[YAW] > -max_speed ) && ( change[PITCH] < max_speed ) && ( change[PITCH] > -max_speed ) )
	if( !forever && isFinished )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void HeadWatch::useEyes 
   (
	qboolean moveEyes
	)

	{
	usingEyes = moveEyes;
	}

void HeadWatch::End
	(
	Actor &self
	)

	{
	// Snap head back into position if we have lost our target or we are doing a resethead

	self.SetControllerAngles( ACTOR_HEAD_TAG, vec_zero );
	self.real_head_pitch = 0;

	self.SetActorFlag( ACTOR_FLAG_TURNING_HEAD, false );
	}



/****************************************************************************

  HeadWatchEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, HeadWatchEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&HeadWatchEnemy::SetArgs },
		{ NULL, NULL }
	};

HeadWatchEnemy::HeadWatchEnemy()
	{
	max_speed = 20;
	forever = true;
	usingEyes = false;
	threshold = 0;
	}

void HeadWatchEnemy::SetArgs
	(
	Event *ev
	)

	{
	max_speed = ev->GetFloat( 1 );

	if ( ev->NumArgs() > 1 )
		forever = ev->GetBoolean( 2 );

	if ( ev->NumArgs() > 2 )
		threshold = ev->GetFloat( 3 );
	}


void HeadWatchEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void HeadWatchEnemy::Begin
	(
	Actor &self
	)

	{
	self.SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" ) );

	current_head_angles = self.GetControllerAngles( ACTOR_HEAD_TAG );

	self.SetActorFlag( ACTOR_FLAG_TURNING_HEAD, true );

	ent_to_watch = self.enemyManager->GetCurrentEnemy();
	}

BehaviorReturnCode_t	HeadWatchEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	int tag_num;	
	Vector tag_pos;
	Vector watch_tag_pos;
	Vector angles_diff;
	Vector watch_position;
	Actor *act = NULL;
	Vector change;


   // Get our Torso Angles
   self.SetControllerTag( ACTOR_TORSO_TAG , gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" ) );
   current_torso_angles = self.GetControllerAngles( ACTOR_TORSO_TAG );

   //Reset our Controller Tag
   self.SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" ) );


   if ( !ent_to_watch )
      {
      ent_to_watch = self.enemyManager->GetCurrentEnemy();
      }

	if ( ent_to_watch )
		{
		tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" );

		if ( tag_num < 0 )
			return BEHAVIOR_SUCCESS;

		self.GetTag( "Bip01 Head", &tag_pos );

		if ( ent_to_watch->isSubclassOf( Actor ) )
			act = (Actor *)(Entity *)ent_to_watch;

		if ( act && ( act->watch_offset != vec_zero ) )
			{
			MatrixTransformVector( act->watch_offset, ent_to_watch->orientation, watch_position );
			watch_position += ent_to_watch->origin;
			}
		else
			{			
			tag_num = gi.Tag_NumForName( ent_to_watch->edict->s.modelindex, "Bip01 Head" );
			
			if ( tag_num < 0 )
				watch_position = ent_to_watch->centroid;
			else
				{
				ent_to_watch->GetTag( "Bip01 Head", &watch_tag_pos );
				watch_position = watch_tag_pos;
				}
			}

		dir = watch_position - tag_pos;
		angles = dir.toAngles();

		angles_diff = angles - self.angles;
		}
	else
		{
		angles_diff = vec_zero;
		}

	angles_diff[YAW]   = AngleNormalize180( angles_diff[YAW] );
	angles_diff[PITCH] = AngleNormalize180( angles_diff[PITCH] );

	float yaw_change = angles_diff[YAW];
	float pitch_change = angles_diff[PITCH];

	if ( threshold && ( yaw_change < threshold ) && ( yaw_change > -threshold ) && ( pitch_change < threshold ) && ( pitch_change > -threshold ) )
		{
		if ( forever )
			return BEHAVIOR_EVALUATING;
		else
			return BEHAVIOR_SUCCESS;
		}

	if (usingEyes)
		{
		if (angles_diff[YAW] > (self.minEyeYawAngle + (self.minEyeYawAngle * .5f )) && angles_diff[YAW] < (self.maxEyeYawAngle + (self.maxEyeYawAngle * .5f )))
			angles_diff[YAW] = 0.0f;
		if (angles_diff[PITCH] > self.minEyePitchAngle && angles_diff[PITCH] < self.maxEyePitchAngle )
		   angles_diff[PITCH] = 0.0f;
		}

	// Make sure we don't turn neck too far
	
	if ( angles_diff[YAW] < -80.0f )
		angles_diff[YAW] = -80.0f;
	else if ( angles_diff[YAW] > 80.0f )
		angles_diff[YAW] = 80.0f;

	if ( angles_diff[PITCH] < -45.0f )
		angles_diff[PITCH] = -45.0f;
	else if ( angles_diff[PITCH] > 45.0f )
		angles_diff[PITCH] = 45.0f;

	angles_diff[ROLL] = 0.0f;

	// Make sure we don't change our head angles too much at once

   //current_head_angles[YAW] = current_head_angles[YAW] - current_torso_angles[YAW];
	change = angles_diff - current_head_angles;

	if ( change[YAW] > max_speed )
		angles_diff[YAW] = current_head_angles[YAW] + max_speed;
	else if ( change[YAW] < -max_speed )
		angles_diff[YAW] = current_head_angles[YAW] - max_speed;

	if ( change[PITCH] > max_speed )
		angles_diff[PITCH] = current_head_angles[PITCH] + max_speed;
	else if ( change[PITCH] < -max_speed )
		angles_diff[PITCH] = current_head_angles[PITCH] - max_speed;

   Vector FinalAngles;
   FinalAngles = angles_diff;
   FinalAngles[YAW] = angles_diff[YAW] - current_torso_angles[YAW];
   
	//self.SetControllerAngles( ACTOR_HEAD_TAG, angles_diff );
   self.SetControllerAngles( ACTOR_HEAD_TAG, FinalAngles );
	self.real_head_pitch = angles_diff[PITCH];

	current_head_angles = angles_diff;
	
   /*
	if ( !ent_to_watch && ( current_head_angles == vec_zero ) )
		return false;
   */

  	if ( !ent_to_watch )
		return BEHAVIOR_EVALUATING;

	if ( !forever && ( change[YAW] < max_speed ) && ( change[YAW] > -max_speed ) && ( change[PITCH] < max_speed ) && ( change[PITCH] > -max_speed ) )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void HeadWatchEnemy::useEyes 
   (
	qboolean moveEyes
	)

	{
	usingEyes = moveEyes;
	}

void HeadWatchEnemy::End
	(
	Actor &self
	)

	{
	// Snap head back into position if we have lost our target or we are doing a resethead

	self.SetControllerAngles( ACTOR_HEAD_TAG, vec_zero );
	self.real_head_pitch = 0;

	self.SetActorFlag( ACTOR_FLAG_TURNING_HEAD, false );
	}
	
	
/****************************************************************************

  EyeWatch Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, EyeWatch, NULL )
	{
		{ &EV_Behavior_Args,			&EyeWatch::SetArgs },
		{ NULL, NULL }
	};

EyeWatch::EyeWatch()
	{
	ent_to_watch = NULL;
	max_speed = 10;
	forever = true;
	threshold = 0;
	}

void EyeWatch::SetArgs
	(
	Event *ev
	)

	{
	
	ent_to_watch = ev->GetEntity( 1 );

	if ( ev->NumArgs() > 1 )
		max_speed = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		forever = ev->GetBoolean( 3 );

	if ( ev->NumArgs() > 3 )
		threshold = ev->GetFloat( 4 );
	}


void EyeWatch::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void EyeWatch::Begin
	(
	Actor &self
	)

	{
	self.SetControllerTag( ACTOR_LEYE_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Face eyeballL" ) );
	self.SetControllerTag( ACTOR_REYE_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Face eyeballR" ) );
	

	current_left_eye_angles = self.GetControllerAngles( ACTOR_LEYE_TAG );
	current_right_eye_angles = self.GetControllerAngles( ACTOR_REYE_TAG );

	self.SetActorFlag( ACTOR_FLAG_MOVING_EYES, true );
	}

BehaviorReturnCode_t	EyeWatch::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	int tag_num;		
	Vector tag_pos;
	Vector watch_tag_pos;
	Vector angles_diff;
	Vector watch_position;
	Actor *act = NULL;
	Vector change;

	if ( ent_to_watch )
		{
		tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" );
		
		if ( tag_num < 0 )
			return BEHAVIOR_SUCCESS;

		self.GetTag( "Bip01 Head", &tag_pos );

		if ( ent_to_watch->isSubclassOf( Actor ) )
			act = (Actor *)(Entity *)ent_to_watch;

		if ( act && ( act->watch_offset != vec_zero ) )
			{
			MatrixTransformVector( act->watch_offset, ent_to_watch->orientation, watch_position );
			watch_position += ent_to_watch->origin;
			}
		else
			{			
			tag_num = gi.Tag_NumForName( ent_to_watch->edict->s.modelindex, "Bip01 Head" );
			
			if ( tag_num < 0 )
				watch_position = ent_to_watch->centroid;
			else
				{
				ent_to_watch->GetTag( "Bip01 Head", &watch_tag_pos );
				watch_position = watch_tag_pos;
				}
			}

		dir = watch_position - tag_pos;
		if ( dir.length() < 32.0f )
			{
			if ( !forever )
				return BEHAVIOR_SUCCESS;
			else 
			   return BEHAVIOR_EVALUATING;
			}

		angles = dir.toAngles();

		angles_diff = angles - self.angles;		
		}
	else
		{
		angles_diff = vec_zero;		
		}

	angles_diff[YAW]   = AngleNormalize180( angles_diff[YAW] );	
	
	// Make sure we don't turn eyes too far
	if ( angles_diff[YAW] < self.minEyeYawAngle )
		angles_diff[YAW] = self.minEyeYawAngle ;
	else if ( angles_diff[YAW] > self.maxEyeYawAngle  )
		angles_diff[YAW] = self.maxEyeYawAngle;

	if ( angles_diff[PITCH] < self.minEyePitchAngle  )
		angles_diff[PITCH] = self.minEyePitchAngle ;
	else if ( angles_diff[PITCH] > self.maxEyePitchAngle  )
		angles_diff[PITCH] = self.maxEyePitchAngle;

	angles_diff[ROLL] = 0;


	// Make sure we don't change our eye angles too much at once

	change = angles_diff - current_left_eye_angles;	

	
	// check left eye -- both eyes will be the same
	if ( change[YAW] > max_speed )
		angles_diff[YAW] = current_left_eye_angles[YAW] + max_speed;
	else if ( change[YAW] < -max_speed )
		angles_diff[YAW] = current_left_eye_angles[YAW] - max_speed;

	if ( change[PITCH] > max_speed )
		angles_diff[PITCH] = current_left_eye_angles[PITCH] + max_speed;
	else if ( change[PITCH] < -max_speed )
		angles_diff[PITCH] = current_left_eye_angles[PITCH] - max_speed;

	self.SetControllerAngles( ACTOR_LEYE_TAG, angles_diff );
	self.SetControllerAngles( ACTOR_REYE_TAG, angles_diff );

	current_left_eye_angles = angles_diff;
	current_right_eye_angles = angles_diff;

	
	if ( !ent_to_watch && ( current_left_eye_angles == vec_zero ) )
		return BEHAVIOR_SUCCESS;


	if ( !forever && ( change[YAW] < max_speed ) && ( change[YAW] > -max_speed ) &&
			( change[PITCH] < max_speed ) && ( change[PITCH] > -max_speed ) )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void EyeWatch::End
	(
	Actor &self
	)

	{
	// Snap head back into position if we have lost our target or we are doing a resethead

	self.SetControllerAngles( ACTOR_LEYE_TAG, vec_zero );
	self.SetControllerAngles( ACTOR_REYE_TAG, vec_zero );

	self.SetActorFlag( ACTOR_FLAG_MOVING_EYES, false );
	}




/****************************************************************************

  EyeWatchEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, EyeWatchEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&EyeWatchEnemy::SetArgs },
		{ NULL, NULL }
	};

EyeWatchEnemy::EyeWatchEnemy()
	{
	ent_to_watch = NULL;
	max_speed = 10;
	forever = true;
	threshold = 0;
	}

void EyeWatchEnemy::SetArgs
	(
	Event *ev
	)

	{
	
	max_speed = ev->GetFloat( 1 );

	if ( ev->NumArgs() > 1 )
		forever = ev->GetBoolean( 2 );

	if ( ev->NumArgs() > 2 )
		threshold = ev->GetFloat( 3 );
	}


void EyeWatchEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void EyeWatchEnemy::Begin
	(
	Actor &self
	)

	{
	self.SetControllerTag( ACTOR_LEYE_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Face eyeballL" ) );
	self.SetControllerTag( ACTOR_REYE_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Face eyeballR" ) );
	

	current_left_eye_angles = self.GetControllerAngles( ACTOR_LEYE_TAG );
	current_right_eye_angles = self.GetControllerAngles( ACTOR_REYE_TAG );

	self.SetActorFlag( ACTOR_FLAG_MOVING_EYES, true );
	}

BehaviorReturnCode_t	EyeWatchEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	int tag_num;		
	Vector tag_pos;
	Vector watch_tag_pos;
	Vector angles_diff;
	Vector watch_position;
	Actor *act = NULL;
	Vector change;

	ent_to_watch = self.enemyManager->GetCurrentEnemy();

	if ( ent_to_watch )
		{
		tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" );
		
		if ( tag_num < 0 )
			return BEHAVIOR_SUCCESS;

		self.GetTag( "Bip01 Head", &tag_pos );

		if ( ent_to_watch->isSubclassOf( Actor ) )
			act = (Actor *)(Entity *)ent_to_watch;

		if ( act && ( act->watch_offset != vec_zero ) )
			{
			MatrixTransformVector( act->watch_offset, ent_to_watch->orientation, watch_position );
			watch_position += ent_to_watch->origin;
			}
		else
			{			
			tag_num = gi.Tag_NumForName( ent_to_watch->edict->s.modelindex, "Bip01 Head" );
			
			if ( tag_num < 0 )
				watch_position = ent_to_watch->centroid;
			else
				{
				ent_to_watch->GetTag( "Bip01 Head", &watch_tag_pos );
				watch_position = watch_tag_pos;
				}
			}

		dir = watch_position - tag_pos;
		angles = dir.toAngles();

		angles_diff = angles - self.angles;		
		}
	else
		{
		angles_diff = vec_zero;		
		}

	angles_diff[YAW]   = AngleNormalize180( angles_diff[YAW] );	
	
	
	float yaw_change = angles_diff[YAW];
	float pitch_change = angles_diff[PITCH];
	if ( threshold && ( yaw_change < threshold ) && ( yaw_change > -threshold ) && 
			( pitch_change < threshold ) && ( pitch_change > -threshold ) )
		{
		if ( forever )
			return BEHAVIOR_EVALUATING;
		else
			return BEHAVIOR_SUCCESS;
		}

	
	// Make sure we don't turn eyes too far
	if ( angles_diff[YAW] < self.minEyeYawAngle )
		angles_diff[YAW] = self.minEyeYawAngle ;
	else if ( angles_diff[YAW] > self.maxEyeYawAngle  )
		angles_diff[YAW] = self.maxEyeYawAngle;

	if ( angles_diff[PITCH] < self.minEyePitchAngle  )
		angles_diff[PITCH] = self.minEyePitchAngle ;
	else if ( angles_diff[PITCH] > self.maxEyePitchAngle  )
		angles_diff[PITCH] = self.maxEyePitchAngle;

	angles_diff[ROLL] = 0;


	// Make sure we don't change our eye angles too much at once

	change = angles_diff - current_left_eye_angles;	

	
	// check left eye -- both eyes will be the same
	if ( change[YAW] > max_speed )
		angles_diff[YAW] = current_left_eye_angles[YAW] + max_speed;
	else if ( change[YAW] < -max_speed )
		angles_diff[YAW] = current_left_eye_angles[YAW] - max_speed;

	if ( change[PITCH] > max_speed )
		angles_diff[PITCH] = current_left_eye_angles[PITCH] + max_speed;
	else if ( change[PITCH] < -max_speed )
		angles_diff[PITCH] = current_left_eye_angles[PITCH] - max_speed;

	self.SetControllerAngles( ACTOR_LEYE_TAG, angles_diff );
	self.SetControllerAngles( ACTOR_REYE_TAG, angles_diff );
	//self.real_head_pitch = angles_diff[PITCH];

	current_left_eye_angles = angles_diff;
	current_right_eye_angles = angles_diff;
	//self.eyeposition = current_head_angles;
	
	if ( !ent_to_watch && ( current_left_eye_angles == vec_zero ) )
		return BEHAVIOR_SUCCESS;

	if ( !forever && ( change[YAW] < max_speed ) && ( change[YAW] > -max_speed ) &&
			( change[PITCH] < max_speed ) && ( change[PITCH] > -max_speed ) )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void EyeWatchEnemy::End
	(
	Actor &self
	)

	{
	// Snap head back into position if we have lost our target or we are doing a resethead

	//if ( !ent_to_watch )
	//	{
		self.SetControllerAngles( ACTOR_LEYE_TAG, vec_zero );
		self.SetControllerAngles( ACTOR_REYE_TAG, vec_zero );

		//self.real_head_pitch = 0;
	//	}

	self.SetActorFlag( ACTOR_FLAG_MOVING_EYES, false );
	}

/****************************************************************************

  HeadAndEyeWatch Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, HeadAndEyeWatch, NULL )
	{
		{ &EV_Behavior_Args,			&HeadAndEyeWatch::SetArgs },
		{ NULL, NULL }
	};

HeadAndEyeWatch::HeadAndEyeWatch()
	{
	}

void HeadAndEyeWatch::SetArgs
	(
	Event *ev
	)

	{
	headWatch.SetArgs(ev);
	eyeWatch.SetArgs(ev);

	headWatch.useEyes(true);
	}


void HeadAndEyeWatch::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );	
	headWatch.ShowInfo(self);
	eyeWatch.ShowInfo(self);
	}

void HeadAndEyeWatch::Begin
	(
	Actor &self
	)

	{
	headWatch.Begin(self);
	eyeWatch.Begin(self);
	}

BehaviorReturnCode_t	HeadAndEyeWatch::Evaluate
	(
	Actor &self
	)

	{
   // if headWatch returns 0 and eyeWatch returns 0 -- returns 0
	// if headWatch returns 1 and eyeWatch returns 0 -- returns 0
	// if headWatch returns 0 and eyeWatch returns 1 -- returns 0
	// if headWatch returns 1 and eyeWatch returns 1 -- returns 1  
	return BEHAVIOR_SUCCESS;
	}

void HeadAndEyeWatch::End
	(
	Actor &self
	)

	{
	headWatch.End(self);
	eyeWatch.End(self);
	}


/****************************************************************************

  TorsoTurn Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, TorsoTurn, NULL )
	{
		{ &EV_Behavior_Args,			&TorsoTurn::SetArgs },
		{ NULL, NULL }
	};

void TorsoTurn::SetArgs
	(
	Event *ev
	)

	{
	turn_towards_enemy = ev->GetInteger( 1 );
	speed              = ev->GetFloat( 2 );
	forever            = ev->GetInteger( 3 );		

	if ( ev->NumArgs() > 3 )
		tag_name = ev->GetString( 4 );

	if ( ev->NumArgs() > 4 )
		tolerance = ev->GetFloat( 5 );
	else
		tolerance = 0;

	if ( ev->NumArgs() > 5 )
		offset = ev->GetFloat( 6 );
	else
		offset = 0;
	
	if ( ev->NumArgs() > 6 )
		use_pitch = ev->GetBoolean( 7 );
	else
		use_pitch = true;
	}

void TorsoTurn::SetRequiredParameters( int TurnTowardsEnemy , int Speed , int Forever )
	{
	turn_towards_enemy = TurnTowardsEnemy;
	speed = Speed;
	forever = Forever;
	}

void TorsoTurn::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void TorsoTurn::Begin
	(
	Actor &self
	)

	{
	Vector controller_angles;

	self.SetControllerTag( ACTOR_TORSO_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" ) );

	controller_angles = self.GetControllerAngles( ACTOR_TORSO_TAG );

	current_yaw   = controller_angles[YAW];
	current_pitch = controller_angles[PITCH];
	}

BehaviorReturnCode_t	TorsoTurn::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	int tag_num;
	float yaw_diff;
	float pitch_diff;
	Vector new_angles;
	float yaw_change;
	float pitch_change;
	Vector tag_pos;
	Vector tag_forward;
	Vector tag_angles;
   
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();

	tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" );

	if ( tag_num < 0 )
		return BEHAVIOR_SUCCESS;

	// Determine the angle we want to go to

	if ( turn_towards_enemy )
		{
		if ( !currentEnemy )
			return BEHAVIOR_SUCCESS;
		

		if ( tag_name.length() )
			{
			self.GetTag( tag_name.c_str(), &tag_pos, &tag_forward );
			tag_angles = tag_forward.toAngles();
			dir = currentEnemy->centroid - tag_pos;
			}
		else
			{
			dir = currentEnemy->centroid - self.centroid;
			}
		
	
	

		angles = dir.toAngles();
		
	
		
		angles[YAW] += offset;

		yaw_diff   = AngleNormalize180( angles[YAW] - self.angles[YAW] );
		pitch_diff = AngleNormalize180( angles[PITCH] - self.angles[PITCH] );
		}
	else
		{
		yaw_diff   = 0.0f;
		pitch_diff = 0.0f;
		}

	// Determine the angle change

	yaw_change   = AngleNormalize180( yaw_diff - current_yaw );
	pitch_change = AngleNormalize180( pitch_diff - current_pitch );

	if ( tolerance && ( yaw_change < tolerance ) && ( yaw_change > -tolerance ) && 
			( pitch_change < tolerance ) && ( pitch_change > -tolerance ) )
		{
		if ( forever )
			return BEHAVIOR_EVALUATING;
		else
			return BEHAVIOR_SUCCESS;
		}

	// Make sure we don't change our torso angles too much at once

	if ( yaw_change > speed )
		yaw_diff = current_yaw + speed;
	else if ( yaw_change < -speed )
		yaw_diff = current_yaw - speed;

	if ( pitch_change > speed )
		pitch_diff = current_pitch + speed;
	else if ( yaw_change < -speed )
		pitch_diff = current_pitch - speed;

	// Determine our new angles

	new_angles[YAW]   = yaw_diff;
	
	if ( use_pitch )
		new_angles[PITCH] = pitch_diff;
	else
		new_angles[PITCH] = 0.0f;
	
	new_angles[ROLL]  = 0.0f;

	// Make sure we don't turn too far

	if ( ( new_angles[YAW] > 100.0f ) || ( new_angles[YAW] < -100.0f ) )
		{
		if (!forever ) 
			return BEHAVIOR_SUCCESS;
		else
			{
 	 	   self.angles[YAW] = new_angles[YAW];
		   self.angles[ROLL] = 0;
		   self.setAngles( self.angles );
			return BEHAVIOR_EVALUATING;
			}
		   
		}
		

	if ( new_angles[PITCH] > 45 || new_angles[PITCH] < -45 )
		{
		if (!forever ) 
			return BEHAVIOR_SUCCESS;
		else
			return BEHAVIOR_EVALUATING;
		}


	// Set our new angles

	self.SetControllerAngles( ACTOR_TORSO_TAG, new_angles );

	current_yaw = yaw_diff;
	current_pitch = pitch_diff;

	// See if we are turned the correct direction now

	if ( !forever && (yaw_change < speed) && (yaw_change > -speed) && (pitch_change < speed) && (pitch_change > -speed) )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void TorsoTurn::End
	(
	Actor &self
	)

	{
	self.SetControllerAngles( ACTOR_TORSO_TAG, vec_zero );		
	}





/****************************************************************************

  TorsoWatchEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, TorsoWatchEnemy, NULL )
	{
		{ &EV_Behavior_Args,		&TorsoWatchEnemy::SetArgs },
		{ NULL, NULL }
	};

void TorsoWatchEnemy::SetArgs
	(
	Event *ev
	)

	{
	
	invert = false;   

	speed              = ev->GetFloat( 1 );
	forever            = ev->GetInteger( 2 );		
	threshold          = ev->GetFloat( 3 );

	if ( ev->NumArgs() > 3 )
		offset = ev->GetFloat( 4 );
	else
		offset = 0;
	
	if ( ev->NumArgs() > 4 )
		use_pitch = ev->GetBoolean( 5 );
	else
		use_pitch = true;
	
	if ( ev->NumArgs() > 5 )
		invert = ev->GetBoolean( 6 );

	if ( ev->NumArgs() > 6 )
		reset = ev->GetBoolean ( 7 );
	else
		reset = true;


	invertLegs = false;
	nextFlipTime = 0;

	}


void TorsoWatchEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void TorsoWatchEnemy::Begin
	(
	Actor &self
	)

	{
	Vector controller_angles;

	self.SetControllerTag( ACTOR_TORSO_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" ) );

	controller_angles = self.GetControllerAngles( ACTOR_TORSO_TAG );

	current_yaw   = controller_angles[YAW];
	current_pitch = controller_angles[PITCH];

   self.SetActorFlag( ACTOR_FLAG_OUT_OF_TORSO_RANGE , false );
	}

BehaviorReturnCode_t	TorsoWatchEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	int tag_num;
	float yaw_diff;
	float pitch_diff;
	Vector new_angles;
	float yaw_change;
	float pitch_change;
	Vector tag_pos;
	Vector tag_forward;
	Vector tag_angles;
   


	tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" );

	if ( tag_num < 0 )
		return BEHAVIOR_SUCCESS;

	// Determine the angle we want to go to

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		{
		reset = true;
		return BEHAVIOR_EVALUATING;
		}
	
   /*
	if ( invertLegs && self.GetActorFlag( ACTOR_FLAG_ANIM_DONE ) )
      {
      self.SetAnim( "idle" );
      invertLegs = false;
      }
	*/	

	dir = currentEnemy->centroid - self.centroid;	
	
	if (invert)
		dir *= -1.0f;

	angles = dir.toAngles();
			
	angles[YAW] += offset;

   /*
	Vector controller_angles;
	controller_angles = self.GetControllerAngles( ACTOR_TORSO_TAG );

	current_yaw   = controller_angles[YAW];
	current_pitch = controller_angles[PITCH];
   */


	yaw_diff   = AngleNormalize180( angles[YAW] - self.angles[YAW] );
	pitch_diff = AngleNormalize180( angles[PITCH] - self.angles[PITCH] );
	
	//yaw_diff   = AngleNormalize180( angles[YAW] - test[YAW] );
	//pitch_diff = AngleNormalize180( angles[PITCH] - test[PITCH] );

	// Determine the angle change

	yaw_change   = AngleNormalize180( yaw_diff - current_yaw );
	pitch_change = AngleNormalize180( pitch_diff - current_pitch );

	/*
	if ( threshold && yaw_change < threshold && yaw_change > -threshold && pitch_change < threshold && pitch_change > -threshold )
		{
		if ( forever )
			return true;
		else
			return false;
		
		}
   */
	// Make sure we don't change our torso angles too much at once

	if ( yaw_change > speed )
		yaw_diff = current_yaw + speed;
	else if ( yaw_change < -speed )
		yaw_diff = current_yaw - speed;

	if ( pitch_change > speed )
		pitch_diff = current_pitch + speed;
	else if ( pitch_change < -speed )
		pitch_diff = current_pitch - speed;

	// Determine our new angles

	new_angles[YAW] = yaw_diff;
	
	if ( use_pitch )
		{
		new_angles[PITCH] = pitch_diff;
		}
	else
		new_angles[PITCH] = 0.0f;
	
	new_angles[ROLL] = 0.0f;

	// Make sure we don't turn too far

	if ( ( new_angles[YAW] > 100.0f ) || ( new_angles[YAW] < -100.0f ) )
		{
		if ( !forever ) 
			return BEHAVIOR_SUCCESS;
      else
			{
			if ( new_angles[YAW] < -100.0f || new_angles[YAW] > 100.0f )
				{            
            if ( nextFlipTime <= level.time )
               {               
               self.movementSubsystem->flipLegs();	
 	         	invertLegs = true;       
               nextFlipTime = level.time + .75;
               }
            
			   return BEHAVIOR_EVALUATING;
				}

			}	

		}

	if ( ( new_angles[PITCH] > 60.0f ) || ( new_angles[PITCH] < -60 ) )
		{
		if ( !forever ) 
			return BEHAVIOR_SUCCESS;
		else
			return BEHAVIOR_EVALUATING;
		}

	// Set our new angles

	self.SetControllerAngles( ACTOR_TORSO_TAG, new_angles );

	current_yaw   = yaw_diff;
	current_pitch = pitch_diff;

	// See if we are turned the correct direction now

	if ( !forever && (yaw_change < speed) && (yaw_change > -speed) && (pitch_change < speed) && (pitch_change > -speed) )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void TorsoWatchEnemy::End
	(
	Actor &self
	)

	{
   /*
   if ( invertLegs )
      self.movementSubsystem->flipLegs();
   */

   self.movementSubsystem->setMovingBackwards( false );   
   if ( reset )
		self.SetControllerAngles( ACTOR_TORSO_TAG, vec_zero );		
	}
/****************************************************************************

  GotoPathNode Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, GotoPathNode, NULL )
	{
		{ &EV_Behavior_AnimDone,	&GotoPathNode::AnimDone },
		{ &EV_Behavior_Args,		&GotoPathNode::SetArgs },
		{ NULL, NULL }
	};

GotoPathNode::GotoPathNode()
	{
	chase = NULL;
	usevec = false;
	movegoal = NULL;
	goal = vec_zero;
	goalent = NULL;
	state = 0;
	_followingEntity = false;
	}

void GotoPathNode::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->IsVectorAt( 2 ) )
		{
		goal = ev->GetVector( 2 );
		usevec = true;
		}
	else
		{
      usevec = false;
		movegoal = thePathManager.FindNode( ev->GetString( 2 ) );
		if ( !movegoal )
			{
			goalent = ev->GetEntity( 2 );
			}
		}

	if ( ev->NumArgs() > 2 )
		entity_to_watch = ev->GetEntity( 3 );
	}

void GotoPathNode::AnimDone
	(
	Event *ev
	)

	{
	turnto.ProcessEvent( EV_Behavior_AnimDone );
	}

void GotoPathNode::SetGoal
	(
	PathNode *node
	)

	{
	usevec = false;
	movegoal = node;
	}

void GotoPathNode::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nturnto:\n" );
   turnto.ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase->ShowInfo( self );

   gi.Printf( "\nstate: %d\n", state );
   gi.Printf( "usevec: %d\n", usevec );
   //gi.Printf( "time: %f\n", time );
   gi.Printf( "anim: %s\n", anim.c_str() );

   if ( goalent )
      {
      gi.Printf( "\ngoalent: #%d '%s'\n", goalent->entnum, goalent->targetname.c_str() );
      }
   else
      {
      gi.Printf( "\ngoalent: NULL\n" );
      }

   gi.Printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z );
	}

void GotoPathNode::Begin
	(
	Actor &self
	)

	{
	Event *ev;

   Vector dir;
	dir = self.movementSubsystem->getAnimDir();
	dir = dir.toAngles();
	self.setAngles( dir );

	turnto.Begin( self );
	float radius=12.0f;
	if ( goalent )
		{
		FollowPathToEntity *newFollowPath = new FollowPathToEntity();
		newFollowPath->SetGoal( goalent, radius, self );
		chase = newFollowPath;
		_followingEntity = true;
		}
	else if ( movegoal )
      {
		FollowPathToPoint *newFollowPath = new FollowPathToPoint();
		newFollowPath->SetGoal( movegoal->origin, radius, self );
		chase = newFollowPath;
      }
   else
		{
		FollowPathToPoint *newFollowPath = new FollowPathToPoint();
		newFollowPath->SetGoal( goal, radius, self );
		chase = newFollowPath;
		}

   chase->Begin( self );

   chase->Begin( self );

	if ( anim.length() )
		{
		self.SetAnim( anim );
		}

	// Setup head watch stuff

	head_watch.Begin( self );

	ev = new Event( EV_Behavior_Args );
	ev->AddEntity( entity_to_watch );
	head_watch.ProcessEvent( ev );
	}

BehaviorReturnCode_t	GotoPathNode::Evaluate
	(
	Actor &self
	)

	{
	float yaw;

	if ( !usevec && !goalent && !movegoal )
		{
		gi.DPrintf( "GotoPathNode::No goal\n" );
		return BEHAVIOR_SUCCESS;
		}

	if ( entity_to_watch )
		head_watch.Evaluate( self );

	switch( state )
		{
		case 0 :
			if ( chase->Evaluate( self ) == Steering::EVALUATING )
				{
				break;
				}

			state = 1;
			self.SetAnim( "idle" );

			// cascade down to case 1
			// lint -fallthrough
		case 1 :
			if ( !movegoal )
				{
				return BEHAVIOR_SUCCESS;
				}

			if ( movegoal->setangles )
				{
            yaw = movegoal->angles.yaw();
				turnto.SetDirection( yaw );
				if ( turnto.Evaluate( self ) )
					{
					break;
					}
				}

			if ( movegoal->animname == "" )
				{
            self.SetAnim( "idle" );
				return BEHAVIOR_SUCCESS;
				}

			self.SetAnim( movegoal->animname, EV_Actor_EndBehavior );
			state = 2;
			break;

		case 2 :
			break;
		}

	return BEHAVIOR_EVALUATING;
	}

void GotoPathNode::End
	(
	Actor &self
	)

	{
	chase->End( self );
	head_watch.End( self );
	}

/****************************************************************************

  Flee Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Flee, NULL )
	{
		{ &EV_Behavior_Args,			&Flee::SetArgs },
		{ NULL, NULL }
	};

void Flee::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void Flee::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void Flee::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
		{
		self.SetAnim( anim );
		}

	chase.Begin( self );
	FindFleeNode( self );
	}

void Flee::FindFleeNode
	(
	Actor &self
	)
	{
	int i;
	PathNode *start_node;
	PathNodeConnection *path;
	PathNode *current_node;
	int max_nodes_to_look_at;
	int nodes_looked_at;
	qboolean found;


	// Get closest node

	start_node = thePathManager.NearestNode( self.origin, &self );

	// Find a random node that is connected to this node

	found = false;

	if ( start_node )
		{
		max_nodes_to_look_at = (int)G_Random( 5.0f ) + 10;
		nodes_looked_at = 0;
		current_node = start_node;

		while( !found )
			{
			nodes_looked_at++;

			if ( ( nodes_looked_at >= max_nodes_to_look_at ) && ( current_node != start_node ) )
				{
				found = true;
				flee_node = current_node;
				}

			if ( current_node->NumberOfConnections() == 0 )
				break;

			path = &current_node->GetConnection( (int)G_Random( (float)current_node->NumberOfConnections() ) );
			current_node = thePathManager.GetNode( path->targetNodeIndex );
			}
		}

	if ( !found )
		{
		// If still not found, use old method

		for( i = 0; i < 5; i++ )
			{
			flee_node = thePathManager.GetNode( ( int )G_Random( (float)thePathManager.NumNodes() + 1.0f ) );
			if ( flee_node )
				break;
			}
		}
	}


BehaviorReturnCode_t	Flee::Evaluate
	(
	Actor &self
	)

	{
	// Make sure we have somewhere to flee to

	if ( !flee_node )
		return BEHAVIOR_SUCCESS;

	float radius=96.0f;
	chase.SetGoal( flee_node->origin, radius,  self );

	// Make a racket

	self.Chatter( "snd_panic", 3.0f );

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	// Try to get to flee node

	if ( chase.Evaluate( self ) != Steering::EVALUATING )
		{
		// See if we are done fleeing
		
		if ( !self.sensoryPerception->CanSeeEntity(&self, currentEnemy , true, true ))	
			return BEHAVIOR_SUCCESS;

		// Find a new spot to flee to

		FindFleeNode( self );
		}

	return BEHAVIOR_EVALUATING;
	}

void Flee::End
	(
	Actor &self
	)

	{
	chase.End( self );
	}

/****************************************************************************

  PlayAnim Class Definition

****************************************************************************/
/*
CLASS_DECLARATION( Behavior, PlayAnim, NULL )
	{
		{ &EV_Behavior_Args,			SetArgs },
		{ NULL, NULL }
	};

void PlayAnim::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void PlayAnim::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nanim: %s\n", anim.c_str() );
	}

void PlayAnim::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
		{
		if ( !self.SetAnim( anim, EV_Actor_EndBehavior ) )
         {
         self.PostEvent( EV_Actor_EndBehavior, 0.0f );
         }
		}
	}

BehaviorReturnCode_t	PlayAnim::Evaluate
	(
	Actor &self
	)

	{
	return BEHAVIOR_EVALUATING;
	}

void PlayAnim::End
	(
	Actor &self
	)

	{
	self.RemoveAnimDoneEvent();
	}
*/


/****************************************************************************

  FindCover Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FindCover, NULL )
	{
		{ &EV_Behavior_Args,			&FindCover::SetArgs },
		{ NULL, NULL }
	};

void FindCover::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		crouch_anim = ev->GetString( 2 );
	}

PathNode *FindCover::FindCoverNode
(
	Actor &self
	)
	
{
	PathNode	*bestnode;
	float		bestdist;
	PathNode	*desperatebestnode;
	float		desperatebestdist;
	FindCoverPath find;
	Path		*path;
	Vector	delta;
	float		dist;
	Vector	pos;
	
	pos = self.origin;
	
	// greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance
	bestdist = 999999999.0f;
	bestnode = NULL;
	
	// greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance
	desperatebestdist = 999999999.0f;
	desperatebestnode = NULL;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return NULL;
	
	PathNode *node = NULL;
	for ( int i = 1 ; i <= thePathManager.NumberOfSpecialNodes(); i++ )   
	{   
		node = thePathManager.GetSpecialNode( i );		
		
		if ( node && ( node->nodeflags & ( AI_DUCK | AI_COVER ) ) &&
			( ( node->occupiedTime <= level.time ) || ( node->entnum == self.entnum ) ) )
		{
			// get the distance squared (faster than getting real distance)
			delta = node->origin - pos;
			dist = delta * delta;
			
			if ( ( dist < bestdist ) && ( !self.sensoryPerception->CanSeeEntity ( node->origin , currentEnemy , true, true ) ||//) )//||
				( ( node->nodeflags & AI_DUCK ) && !self.sensoryPerception->CanSeeEntity( node->origin - Vector( 0.0f, 0.0f, 32.0f ) , currentEnemy , true , true ) ) ) )
			{
				bestnode = node;
				bestdist = dist;
			}
			else if ( ( dist < desperatebestdist ) && ( desperatebestdist > ( 64.0f * 64.0f ) ) )
			{
				desperatebestnode = node;
				desperatebestdist = dist; 
			}		
		}
	}
	
	if ( !bestnode )
	{
		bestnode = desperatebestnode;
	}
	
	if ( bestnode )
	{
		find.heuristic.self = &self;
		find.heuristic.setSize( self.size );
		find.heuristic.entnum = self.entnum;
		
		path = find.FindPath( self.origin, bestnode->origin );
		if ( path )
		{
			node = path->End();
			
			// Mark node as occupied for a short time
			node->occupiedTime = level.time + 1.5f;
			node->entnum = self.entnum;
			
			float radius=96.0f;
			chase.SetGoal( node->origin, radius, self );
			
			delete path;
			path = NULL;
			
			return node;
		}
	}
	
	return NULL;
}

void FindCover::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );

   gi.Printf( "\nstate: %d\n", state );
   gi.Printf( "anim: %s\n", anim.c_str() );
   gi.Printf( "nextsearch: %f\n", nextsearch );
	}

void FindCover::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
		{
		anim = "run";
		}

	if ( !crouch_anim.length() )
		{
		crouch_anim = "crouch_down";
		}

	movegoal = NULL;
	state = 0;
	}

BehaviorReturnCode_t	FindCover::Evaluate
	(
	Actor &self
	)

	{
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;	

	if ( !movegoal )
		{
		state = 0;
		}

	switch( state )
		{
		case 0 :
			// Checking for cover
			chase.Begin( self );
			movegoal = FindCoverNode( self );
			if ( !movegoal )
				{
            // Couldn't find any!
				return BEHAVIOR_SUCCESS;
				}

			// Found cover, going to it
			if ( anim.length() && ( ( anim != self.animname ) || self.newanim.length() ) )
				{
				self.SetAnim( anim );
				}

			state = 1;
			nextsearch = level.time + 1.0f;

			// lint -fallthrough
		case 1 :
			if ( chase.Evaluate( self ) == Steering::EVALUATING )
				{
				if ( nextsearch < level.time )
					{
					state = 0;
					}
				return BEHAVIOR_EVALUATING;
				}
			
			// Reached cover
		   if ( self.sensoryPerception->CanSeeEntity ( &self , currentEnemy , true , true ) )
				{
				state = 0;
				}

			if ( movegoal->nodeflags & AI_DUCK )
				{
            // ducking
				self.SetAnim( crouch_anim.c_str() );
				}
			else
				{
            // standing
				self.SetAnim( "idle" );
				}

			chase.End( self );
			return BEHAVIOR_SUCCESS;
			break;
		}

	return BEHAVIOR_EVALUATING;
	}

void FindCover::End
	(
	Actor &self
	)

	{
	chase.End( self );
	}

/****************************************************************************

  FindFlee Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FindFlee, NULL )
	{
		{ &EV_Behavior_Args,			&FindFlee::SetArgs },
		{ NULL, NULL }
	};

void FindFlee::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

PathNode *FindFlee::FindFleeNode
	(
	Actor &self
	)

	{
	PathNode	*bestnode;
	float		bestdist;
	PathNode	*desperatebestnode;
	float		desperatebestdist;
	FindFleePath find;
	Path		*path;
	Vector	delta;
	float		dist;
	Vector	pos;

   pos = self.origin;

   // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance
	bestdist = 999999999.0f;
	bestnode = NULL;

   // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance
	desperatebestdist = 999999999.0f;
   desperatebestnode = NULL;


	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return NULL;

	PathNode *node = NULL;
	for ( int i = 1 ; i <= thePathManager.NumberOfSpecialNodes(); i++ )   
	{   
		node = thePathManager.GetSpecialNode( i );		

		if ( node && ( node->nodeflags & AI_FLEE ) &&
			( ( node->occupiedTime <= level.time ) || ( node->entnum == self.entnum ) ) )
			{
			// get the distance squared (faster than getting real distance)
         delta = node->origin - pos;
			dist = delta * delta;
         
				if ( ( dist < bestdist ) && !self.sensoryPerception->CanSeeEntity( node->origin , currentEnemy , true, true  ) )
					{
					bestnode = node;
					bestdist = dist;
					}
				else if ( ( dist < desperatebestdist ) && ( desperatebestdist > ( 64.0f * 64.0f ) ) )
					{
					desperatebestnode = node;
					desperatebestdist = dist;
					}

			
			}
		}

	if ( !bestnode )
		{
		bestnode = desperatebestnode;
		}

	if ( bestnode )
		{
		find.heuristic.self = &self;
		find.heuristic.setSize( self.size );
		find.heuristic.entnum = self.entnum;

      path = find.FindPath( self.origin, bestnode->origin );
		if ( path )
			{
			node = path->End();

			// Mark node as occupied for a short time
			node->occupiedTime = level.time + 1.5f;
			node->entnum = self.entnum;

			float radius=96.0f;
			chase.SetGoal( node->origin, radius, self );

			delete path;
			path = NULL;

			return node;
			}
		}

	return NULL;
	}

void FindFlee::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );

   gi.Printf( "\nstate: %d\n", state );
   gi.Printf( "anim: %s\n", anim.c_str() );
   gi.Printf( "nextsearch: %f\n", nextsearch );
	}

void FindFlee::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
		{
		anim = "run";
		}

	movegoal = NULL;
	state = 0;
	}

BehaviorReturnCode_t	FindFlee::Evaluate
	(
	Actor &self
	)

	{
	if ( !movegoal )
		{
		state = 0;
		}

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	switch( state )
		{
		case 0 :
         // Checking for flee node
			chase.Begin( self );
			movegoal = FindFleeNode( self );
			if ( !movegoal )
				{
            // Couldn't find any!
				return BEHAVIOR_SUCCESS;
				}

         // Found flee node, going to it
			if ( anim.length() && ( anim != self.animname || self.newanim.length() ) )
				{
				self.SetAnim( anim );
				}

			state = 1;
			nextsearch = level.time + 1.0f;

			// lint -fallthrough
		case 1 :
			if ( chase.Evaluate( self ) == Steering::EVALUATING )
				{
				if ( nextsearch < level.time )
					{
					state = 0;
					}
				return BEHAVIOR_EVALUATING;
				}

		if ( self.sensoryPerception )
			{
		   // Reached cover
			if ( self.sensoryPerception->CanSeeEntity( &self , currentEnemy , true , true ) )
				{
				state = 0;
				}
			else
				{
				// standing
   			self.SetAnim( "idle" );
	   		chase.End( self );
				return BEHAVIOR_SUCCESS;
				}
			}

		break;
		}

	return BEHAVIOR_EVALUATING;
	}

void FindFlee::End
	(
	Actor &self
	)

	{
	chase.End( self );
	}

/****************************************************************************

  FindEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FindEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&FindEnemy::SetArgs },
		{ NULL, NULL }
	};

void FindEnemy::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void FindEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );

   gi.Printf( "\nstate: %d\n", state );
   gi.Printf( "nextsearch: %f\n", nextsearch );
   gi.Printf( "anim: %s\n", anim.c_str() );
	}

void FindEnemy::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
		{
		anim = "run";
		}

	movegoal = NULL;
   lastSearchNode = NULL;
	state = 0;
	}

PathNode *FindEnemy::FindClosestSightNode
	(
	Actor &self
	)

	{
	PathNode	*bestnode;
	float		bestdist;
	Vector	delta;
	float		dist;
	Vector	pos;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();

   if ( currentEnemy )
      {
      pos = currentEnemy->origin;
      }
   else
      {
      pos = self.origin;
      }

   // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance
	bestdist = 999999999;
	bestnode = NULL;

	for ( int i = 1 ; i <= thePathManager.NumberOfSpecialNodes(); i++ )   
	{   
		PathNode *node = thePathManager.GetSpecialNode( i );		

		if ( node && ( ( node->occupiedTime <= level.time ) || ( node->entnum != self.entnum ) ) )
			{
			// get the distance squared (faster than getting real distance)
         delta = node->origin - pos;
			dist = delta * delta;
			   if ( ( dist < bestdist ) && self.sensoryPerception->CanSeeEntity( node->origin, currentEnemy , true , true ) )
					{
					bestnode = node;
					bestdist = dist;
					}
			
			}
		}

	return bestnode;
	}

BehaviorReturnCode_t	FindEnemy::Evaluate
	(
	Actor &self
	)

	{
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( nextsearch < level.time )
		{
      // check if we should search for the first time
      if ( !lastSearchNode )
         {
         state = 0;
         }
      else
         {
         // search less often if we're far away
			nextsearch = self.DistanceTo( currentEnemy ) * ( 1.0f / 512.0f );
         if ( nextsearch < 1.0f )
            {
            nextsearch = 1.0f;
            }
         nextsearch += level.time;

         // don't search again if our enemy hasn't moved very far
         if ( currentEnemy->WithinDistance( lastSearchPos, 256.0f ) )
            {
            state = 0;
            }
         }
		}

	switch( state )
		{
		case 0 :
			// Searching for enemy
			chase.Begin( self );
         lastSearchPos = currentEnemy->origin;
         movegoal = thePathManager.NearestNode( lastSearchPos, &self );
         if ( !movegoal )
            {
            movegoal = thePathManager.NearestNode( lastSearchPos, &self, false );
            }

         lastSearchNode = movegoal;
			if ( movegoal )
				{
				Path *path;
				FindEnemyPath find;
            PathNode *from;

				find.heuristic.self = &self;
				find.heuristic.setSize( self.size );
				find.heuristic.entnum = self.entnum;

            from = thePathManager.NearestNode( self.origin, &self );
            if ( ( from == movegoal ) && ( self.DistanceTo( from->origin ) < 8.0f ) )
               {
               movegoal = NULL;
               from = NULL;
               }

            if ( from )
               {
               path = find.FindPath( from, movegoal );
				   if ( path )
					   {
						float radius=96.0f;
					   chase.SetGoal( movegoal->origin, radius,  self );

					   delete path;
					   path = NULL;
					   }
               else
                  {
                  movegoal = NULL;
                  }
               }
				}

			if ( !movegoal )
				{
				if ( self.sensoryPerception->CanSeeEntity( &self , currentEnemy , true , true  ) || ( !currentEnemy->groundentity && !self.waterlevel ) )
					{
					float radius=96.0f;
					chase.SetGoal( currentEnemy->origin, radius, self );
					}
				else
					{
					// Couldn't find enemy
					// since we can't reach em
					// clear out enemy state
					self.enemyManager->ClearCurrentEnemy();
					return BEHAVIOR_SUCCESS;
					}
				}

         // Found enemy, going to it
			if ( anim.length() && ( anim != self.animname || self.newanim.length() ) )
				{
				self.SetAnim( anim );
				}

			state = 1;

			// lint -fallthrough
		case 1 :
			if ( self.CanAttack( currentEnemy, false ) )
				{
				// Reached enemy
				chase.End( self );
				return BEHAVIOR_SUCCESS;
				}

			if ( chase.Evaluate( self ) != Steering::EVALUATING )
				{
            state = 0;
				nextsearch = 0;
				}
			break;
		}

	return BEHAVIOR_EVALUATING;
	}

void FindEnemy::End
	(
	Actor &self
	)

	{
	chase.End( self );
	}

/****************************************************************************

  AimAndShoot Class Definition

****************************************************************************/
#define START_AIM 0
#define AIM       1
#define FIRE      2

CLASS_DECLARATION( Behavior, AimAndShoot, NULL )
	{
		{ &EV_Behavior_Args,		&AimAndShoot::SetArgs },
		{ &EV_Behavior_AnimDone,	&AimAndShoot::AnimDone },
		{ NULL, NULL }
	};

AimAndShoot::AimAndShoot()
	{
	maxshots = 1;
	numshots = 0;
	aim_time = 0.0f;
	enemy_health = 0;
	animdone = false;
	}

void AimAndShoot::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\naim:\n" );
   aim.ShowInfo( self );

   gi.Printf( "\nmode: %d\n", mode );
   gi.Printf( "maxshots: %d\n", maxshots );
   gi.Printf( "numshots: %d\n", numshots );
   gi.Printf( "animdone: %d\n", animdone );
	}

void AimAndShoot::Begin
	(
	Actor &self
	)

	{
	if ( aimanim.length() )
		{
		self.SetAnim( aimanim.c_str() );
		mode = START_AIM;
		}
	else
		{
		self.SetAnim( "idle" );
		mode = AIM;
		}
   }

void AimAndShoot::SetMaxShots
	(
	int num
	)

	{
	maxshots = ( num / 2 ) + (int)G_Random( (float)num );
	}

void AimAndShoot::SetArgs
	(
	Event *ev
	)

	{
   fireanim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		maxshots = ev->GetInteger ( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		aimanim = ev->GetString ( 3 );
      }
	
	int turnTowardsEnemy = ev->GetInteger( 3 );
	int speed = ev->GetInteger( 4 );
	
	torsoTurn.SetRequiredParameters( turnTowardsEnemy, speed, 0 );
	}

void AimAndShoot::AnimDone
	(
	Event *ev
	)

	{
	animdone = true;
	}

BehaviorReturnCode_t	AimAndShoot::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();

	switch( mode )
		{
		case START_AIM :     
         
			if ( !currentEnemy || !self.CanAttack( currentEnemy, false ))
            return BEHAVIOR_SUCCESS;
  			
			animdone = false;
         if ( aimanim.length() )
            self.SetAnim( aimanim.c_str() );
         
         // save off time, in case we aim for too long
         aim_time = level.time + 1.0f;
			mode = AIM;

			// lint -fallthrough
		case AIM :
			
			if ( aimanim.length() )
				{
				if ( !currentEnemy || ( aim_time < level.time ) )
					return BEHAVIOR_SUCCESS;

				aim.SetTarget( currentEnemy );

				if ( aim.Evaluate( self ) )
					{
					break;
					}
				}
			else
				{
				if ( self.IsEntityAlive( currentEnemy ) )
					{
					dir = currentEnemy->centroid - self.origin;
					angles = dir.toAngles();

					self.angles[YAW] = angles[YAW];
					self.setAngles( self.angles );
					}
				}

			// don't go into our firing animation until our weapon is ready, and we are on target
			if ( currentEnemy && self.CanAttack( currentEnemy, true ) )
				{
				animdone = false;
				self.Chatter( "snd_inmysights", 5.0f );
				self.SetAnim( fireanim.c_str(), EV_Actor_NotifyBehavior );
            enemy_health = currentEnemy->health;
				mode = 2;
				}
			else if ( !currentEnemy || currentEnemy->deadflag ||
				( currentEnemy->health <= 0.0f ) || !self.CanAttack( currentEnemy, false ) )
				{
				// either our enemy is dead, or we can't shoot the enemy from here
				return BEHAVIOR_SUCCESS;
				}
			break;

		case FIRE :
			// Fire
			if ( animdone )
				{
				aim.SetTarget( currentEnemy );
				aim.Evaluate( self );

				self.times_done++;

            if ( !currentEnemy || ( currentEnemy->health < enemy_health ) )
               {
					self.Chatter( "snd_attacktaunt", 4.0f );
               }
            else
               {
					self.Chatter( "snd_missed", 7.0f );
               }

				animdone = false;
				numshots++;

				if ( ( numshots >= maxshots ) || !currentEnemy || currentEnemy->deadflag ||
					( currentEnemy->health <= 0.0f ) || !self.CanAttack( currentEnemy, false ) )
					{
					// either we're out of shots, our enemy is dead, or we can't shoot the enemy from here

					return BEHAVIOR_SUCCESS;
					}
				else if ( !self.CanAttack( currentEnemy, false ) )
					{
					// weapon not ready or not aimed at enemy, so just keep trying to get enemy in our sights
               if ( aimanim.length() )
                  {
		   			self.SetAnim( aimanim.c_str() );
                  }
               //
               // save off time, in case we aim for too long
               //
               aim_time = level.time + 1.0f;
					mode = 1;
					}
				else
					{
					// keep firing
					self.SetAnim( fireanim.c_str(), EV_Actor_NotifyBehavior );
               enemy_health = currentEnemy->health;
					}
				}
			break;
		}

	return BEHAVIOR_EVALUATING;
	}

void AimAndShoot::End
	(
	Actor &self
	)

	{
	aim.End( self );
	//self.SetAnim( "idle" );
	}

/****************************************************************************

  AimAndMelee Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, AimAndMelee, NULL )
	{
		{ &EV_Behavior_Args,		&AimAndMelee::SetArgs },
		{ &EV_Behavior_AnimDone,	&AimAndMelee::AnimDone },
		{ NULL, NULL }
	};

AimAndMelee::AimAndMelee()
	{
	maxshots = 1;
	anim_name = "melee";
	mode = 0;
   numshots = 0;
	animdone = false;
	}

void AimAndMelee::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\naim:\n" );
   aim.ShowInfo( self );

   gi.Printf( "\nmode: %d\n", mode );
   gi.Printf( "maxshots: %d\n", maxshots );
   gi.Printf( "numshots: %d\n", numshots );
   gi.Printf( "animdone: %d\n", animdone );
	}

void AimAndMelee::Begin
	(
	Actor &self
	)

	{
	self.SetAnim( "idle" );
	}

void AimAndMelee::SetArgs
	(
	Event *ev
	)

	{
	anim_name = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		maxshots = ev->GetInteger( 2 );
      }
	}

void AimAndMelee::AnimDone
	(
	Event *ev
	)

	{
	animdone = true;
	}

BehaviorReturnCode_t	AimAndMelee::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();

	switch( mode )
		{
		case 0 :
			if ( !currentEnemy )
            {
            return BEHAVIOR_SUCCESS;
            }

			if ( self.IsEntityAlive( currentEnemy ) )
				{
				dir = currentEnemy->centroid - self.origin;
				self.angles[YAW] = dir.toYaw();
				self.setAngles( self.angles );
				}

         numshots++;
         animdone = false;

			// melee
			self.SetAnim( anim_name.c_str() , EV_Actor_NotifyBehavior );
			self.Chatter( "snd_attacktaunt", 4.0f );
         mode = 1;

			// lint -fallthrough
		case 1 :
			// finish up the attack
			if ( animdone )
				{
				self.times_done++;
            if ( numshots >= maxshots )
               {
				   return BEHAVIOR_SUCCESS;
               }

            mode = 0;
            }
			break;
		}

	return BEHAVIOR_EVALUATING;
	}

void AimAndMelee::End
	(
	Actor &self
	)

	{
	aim.End( self );
	}

/****************************************************************************

  FallToDeath Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FallToDeath, NULL )
	{
		{ &EV_Behavior_Args,	&FallToDeath::SetArgs },
		{ NULL, NULL }
	};

FallToDeath::FallToDeath()
   {

	}

void FallToDeath::SetArgs
	(
	Event *ev
	)
	{
   // Get the Parameters
	forwardmove = ev->GetFloat( 1 );
   sidemove    = ev->GetFloat( 2 );
   speed       = ev->GetFloat( 3 );
	startAnim   = ev->GetString( 4 );
	fallAnim    = ev->GetString( 5 );
	deathAnim   = ev->GetString( 6 );
	
	if ( ev->NumArgs() > 6 )
		impulse_time = ( ev->GetFloat( 7 ) ) + level.time;
	else
		impulse_time = 0;

	animdone = false;
	state    = 0;
	did_impulse = false;
	}

void FallToDeath::Begin
	(
	Actor &self
	)

	{
	//Initialize our stuff


	self.SetAnim( startAnim.c_str() , EV_Anim_Done );
	self.ChangeAnim();
	}

BehaviorReturnCode_t	FallToDeath::Evaluate
	(
	Actor &self
	)

	{
   if ( !did_impulse && ( level.time >= impulse_time ) )
		{
		Vector( 0.0f, self.angles.y, 0.0f ).AngleVectors( &yaw_forward, &yaw_left );
		self.velocity = ( yaw_forward * forwardmove ) - ( yaw_left * sidemove );
	   distance = self.velocity.length();
	   self.velocity *= speed / distance;
	   time = distance / speed;
	   self.velocity[ 2 ] = sv_currentGravity->integer * time * 0.5f;
		did_impulse = true;
		}
	

	animdone = self.GetActorFlag( ACTOR_FLAG_ANIM_DONE );
	self.SetActorFlag( ACTOR_FLAG_ANIM_DONE, false );

   switch( state )
      {
      case 0:
         if ( did_impulse )
				state = 1;
         // this is here so that we at least hit this function at least once
         // this gaves the character the chance to leave the ground, nulling out
         // self.groundentity
         break;
		case 1:
			if ( animdone )
            {
            animdone = false;
         	self.SetAnim( fallAnim.c_str(), EV_Anim_Done );
            state = 2;
            }
			if ( self.groundentity )
				state = 2;
			break;
      case 2:
         //
         // wait for the character to hit the ground
         //
	      if ( self.groundentity )
            {
            //
            // if we have an anim, we go to state 3
            //
            animdone = false;
         	self.SetAnim( deathAnim.c_str(), EV_Actor_Dead );
            state = 3;            
            }
         break;
      case 3:
         //
         // we are on the ground and waiting for our landing animation to finish
         //
         
			if ( animdone )
            {
				return BEHAVIOR_SUCCESS;
            }			
         break;
      }

	return BEHAVIOR_EVALUATING;
	}

void FallToDeath::End
	(
	Actor &self
	)

	{
	Event *ev;
	ev = new Event( EV_Killed );

	ev->AddEntity( NULL );
	ev->AddFloat( 250.0f );
	ev->AddEntity( NULL );
	ev->AddInteger( MOD_FALLING );
	ev->AddInteger( 1 );

	self.PostEvent( ev , 0.0f );
	}

/****************************************************************************

  JumpToPathNode Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, JumpToPathNode, NULL )
	{
		{ &EV_Behavior_Args,		&JumpToPathNode::SetArgs },
		{ NULL, NULL }
	};

void JumpToPathNode::SetArgs( Event *ev )
{
	movegoal = thePathManager.FindNode( ev->GetString( 1 ) );
	
	if ( movegoal )
		jump.SetGoal( movegoal->origin );
	else
	{
		Entity *entity = ev->GetEntity( 1 );
		
		if ( entity )
			jump.SetEntity( entity );
	}
	
	if ( ev->NumArgs() > 1 )
		jump.SetLaunchAngle( ev->GetFloat( 2 ) );	
	
	
}

void JumpToPathNode::Begin( Actor &self )
{
	jump.Begin( self );
}

BehaviorReturnCode_t JumpToPathNode::Evaluate( Actor &self )
{
	if ( jump.Evaluate( self ) !=  Steering::SUCCESS )
		return BEHAVIOR_EVALUATING;
	
	return BEHAVIOR_SUCCESS;
}

void JumpToPathNode::End( Actor &self )
{
	jump.End( self );
}

/****************************************************************************

  LeapToEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, LeapToEnemy, NULL )
	{
		{ &EV_Behavior_Args,		&LeapToEnemy::SetArgs },
		{ NULL, NULL }
	};

void LeapToEnemy::SetArgs
	(
	Event *ev
	)

	{
	jump.SetLaunchAngle( ev->GetFloat( 1 ) );	
	}

void LeapToEnemy::Begin
	(
	Actor &self
	)

	{
	Entity* ent = self.enemyManager->GetCurrentEnemy();	
	jump.SetEntity(ent);
	jump.Begin(self);
	}

BehaviorReturnCode_t	LeapToEnemy::Evaluate
	(
	Actor &self
	)

	{
	if ( jump.Evaluate( self ) == Steering::EVALUATING )
      return BEHAVIOR_EVALUATING;

   return BEHAVIOR_SUCCESS;
	}

void LeapToEnemy::End
	(
	Actor &self
	)

	{
	jump.End(self);
	}

/****************************************************************************

  FlyToPoint Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyToPoint, NULL )
	{
		{ NULL, NULL }
	};

FlyToPoint::FlyToPoint()
	{
	turn_speed = 10.0;
	old_turn_speed = turn_speed;
	speed = 480.0;
	random_allowed = true;
	force_goal = false;
	adjustYawAndRoll = true;
	offsetOrigin = false;

	avoidtime = 0;
	stuck = 0;
	use_temp_goal = false;

	old_forward_speed = 0;
	}

void FlyToPoint::SetTurnSpeed( float new_turn_speed )
	{
	turn_speed = new_turn_speed;
	}

void FlyToPoint::SetGoalPoint( const Vector &goal_point )
	{
	if ( goal_point != goal )
		avoidtime = 0;

	goal = goal_point;
	}

void FlyToPoint::SetRandomAllowed( qboolean allowed )
	{
	random_allowed = allowed;
	}

void FlyToPoint::SetSpeed( float speed_value )
	{
	speed = speed_value;
	}

void FlyToPoint::ForceGoal( void )
	{
	force_goal = true;
	}

void FlyToPoint::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyToPoint::Begin
	(
	Actor &self
	)

	{
   avoidtime = 0;
	old_forward_speed = self.movementSubsystem->getForwardSpeed();	
	stuck = 0;
	use_temp_goal = false;
	}

BehaviorReturnCode_t	FlyToPoint::Evaluate
	(
	Actor &self
	)

	{
   trace_t trace;
   Vector dir;
   Vector ang;
	float time;
	float length;
	float old_yaw;
	float old_pitch;
	
	float x_offset = 0;
	float y_offset = 0;
	//float z_offset = 0;


   if (offsetOrigin)
		{
   	x_offset = self.centroid.x - self.origin.x;
   	y_offset = self.centroid.y - self.origin.y;
	   //z_offset = self.centroid.z - self.origin.z;
		
		self.origin.x+=x_offset;
	   self.origin.y+=y_offset;
	   //self.origin.z+=z_offset;
		}

	if ( self.movementSubsystem->getLastMove() != STEPMOVE_OK )
		stuck++;
	else
		stuck = 0;


	if ( stuck > 1 || ( avoidtime <= level.time ) )
      {
		time = G_Random( .3f ) + .3f;

		use_temp_goal = false;

		if ( !force_goal )
			{
			trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyToPoint" );
						
			if ( ( trace.fraction < 0.5f ) || ( stuck > 2 ) )
				{
				old_turn_speed = self.movementSubsystem->getTurnSpeed();
				self.movementSubsystem->setTurnSpeed( 60 );
				temp_goal = ChooseRandomDirection( self, goal, &time, MASK_WATER, false );
				
				self.movementSubsystem->setTurnSpeed( old_turn_speed );
				use_temp_goal = true;
				avoidtime = level.time + time;

				stuck = 0;
				}
			else
				{
				goal = trace.endpos;
				avoidtime = level.time + time;
				}
			}
		else
			{
			avoidtime = level.time + time;
			}
		
		if ( use_temp_goal )
			dir = temp_goal - self.origin;						
		else
			dir = goal - self.origin;			

		length = dir.length();
      dir.normalize();
		
      ang = dir.toAngles();
		
		if ( ( length > 150.0f ) && random_allowed && !use_temp_goal )
			{
			//ang[YAW]   += G_Random( 20 ) - 5.0;
			//ang[PITCH] += G_Random( 20 ) - 5.0;
			}

		target_angle = ang;

		target_angle[YAW]   = AngleNormalize360( target_angle[YAW] );
		target_angle[PITCH] = AngleNormalize360( target_angle[PITCH] );
      }

	if ( (self.angles[YAW] != target_angle[YAW]) || (self.angles[PITCH] != target_angle[PITCH]) )
      {
		self.movementSubsystem->setForwardSpeed( speed * 0.8f );
      }
	else
      {
		self.movementSubsystem->setForwardSpeed( speed );
      }

	old_yaw   = self.angles[YAW];
	old_pitch = self.angles[PITCH];
	
	ang[YAW]   = LerpAngle( self.angles[YAW],   target_angle[YAW],   turn_speed );
	ang[PITCH] = LerpAngle( self.angles[PITCH], target_angle[PITCH], turn_speed );
	ang[ROLL]  = 0;
	
	if( adjustYawAndRoll )
		{
	   
		if ( ( AngleDelta( ang[YAW], old_yaw ) > 0.0f ) && ( ( ang[ROLL] > 315.0f ) || ( ang[ROLL] <= 45.0f ) ) )
			{
			ang[ROLL] += 5.0f;
			}
		else if ( ( AngleDelta( ang[YAW], old_yaw ) < 0.0f ) && ( ( ang[ROLL] < 45.0f ) || ( ang[ROLL] >= 315.0f ) ) )
			{
			ang[ROLL] -= 5.0f;
			}
		else
			{
			if ( ang[ROLL] != 0.0f )
				{
				
				if ( ang[ROLL] < 5.0f || ang[ROLL] > 355.0f )
					{
					ang[ROLL] = 0.0f;
					}
				else
					{
					if ( ang[ROLL] < 180.0f )
						ang[ROLL] += 5.0f;
					else
						ang[ROLL] -= 5.0f;
					}
				}
			}
		}

	ang[YAW]   = AngleNormalize360( ang[YAW] );
	ang[PITCH] = AngleNormalize360( ang[PITCH] );
	ang[ROLL]  = AngleNormalize360( ang[ROLL] );

	// Don't get stuck if still turning

	if ( ( AngleDelta( ang[YAW], old_yaw ) > .5 ) || ( AngleDelta( ang[YAW], old_yaw ) < -.5 ) ||
		  ( AngleDelta( ang[PITCH], old_pitch ) > .5 ) || ( AngleDelta( ang[PITCH], old_pitch ) < -.5 ) )
		{
		stuck = 0;
		}

	self.setAngles( ang );

	if (offsetOrigin)
		{
   	self.origin.x-=x_offset;
	   self.origin.y-=y_offset;
	   //self.origin.z-=z_offset;
		}

	return BEHAVIOR_EVALUATING;
	}

float FlyToPoint::LerpAngle( float old_angle, float new_angle, float lerp_amount )
	{
	float diff;
	float abs_diff;
	float lerp_angle;

	new_angle = AngleNormalize360( new_angle );
	old_angle = AngleNormalize360( old_angle );

	diff = new_angle - old_angle;

	if ( diff > 180.0f )
      {
		diff -= 360.0f;
      }

	if ( diff < -180.0f )
      {
		diff += 360.0f;
      }

	lerp_angle = old_angle;
	
	abs_diff = diff;

	if ( abs_diff < 0.0f )
      {
		abs_diff = -abs_diff;
      }

	if ( abs_diff < lerp_amount )
      {
		lerp_amount = abs_diff;
      }

	if ( diff < 0.0f )
      {
		lerp_angle -= lerp_amount;
      }
	else if ( diff > 0.0f )
      {
		lerp_angle += lerp_amount;
      }
	
	lerp_angle = AngleNormalize360( lerp_angle );

	return lerp_angle;
	}

void FlyToPoint::End
	(
	Actor &self
	)

	{
	self.movementSubsystem->setForwardSpeed( old_forward_speed );	
	}

/****************************************************************************

  FlyCloseToEnemy Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyCloseToEnemy, NULL )
	{
		{ &EV_Behavior_Args,		&FlyCloseToEnemy::SetArgs },
		{ NULL, NULL }
	};

FlyCloseToEnemy::FlyCloseToEnemy()
	{
	speed = 0;
	turn_speed = 10.0;
	anim = "fly";
	adjustPitch = true;
	next_goal_time = 0;
	}

void FlyCloseToEnemy::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		turn_speed = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );

	if (ev->NumArgs() > 3 )
		fly.setAdjustYawAndRoll( ev->GetBoolean( 4 ) );	

	if (ev->NumArgs() > 4 )
		adjustPitch = ev->GetBoolean( 5 );
	}


void FlyCloseToEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCloseToEnemy::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );

	if ( speed )
		fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyCloseToEnemy::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

   if ( !self.IsEntityAlive( currentEnemy ) )
      return BEHAVIOR_SUCCESS;

	if ( next_goal_time <= level.time )
		{
		goal = currentEnemy->centroid;

		if (!adjustPitch)
			{
			goal.z = self.origin.z;
			}

		//goal[0] += G_Random( 30 ) - 15.0;
		//goal[1] += G_Random( 30 ) - 15.0;
		//goal[2] += G_Random( 60 ) - 30.0;

		fly.SetGoalPoint( goal );

		next_goal_time = level.time + .5f;
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyCloseToEnemy::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyCloseToPlayer Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyCloseToPlayer, NULL )
	{
		{ &EV_Behavior_Args,		&FlyCloseToPlayer::SetArgs },
		{ NULL, NULL }
	};

FlyCloseToPlayer::FlyCloseToPlayer()
	{
	speed = 0;
	turn_speed = 10.0;
	anim = "fly";
	next_goal_time = 0;
	}

void FlyCloseToPlayer::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		turn_speed = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );
	}

void FlyCloseToPlayer::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCloseToPlayer::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
		
	if ( speed )
		fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyCloseToPlayer::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;
	Entity *player;


	player = g_entities[ 0 ].entity;


   if ( !self.IsEntityAlive( player ) )
      return BEHAVIOR_SUCCESS;

	if ( next_goal_time <= level.time )
		{
		goal = player->centroid;

		//goal[0] += G_Random( 30 ) - 15.0;
		//goal[1] += G_Random( 30 ) - 15.0;
		//goal[2] += G_Random( 60 ) - 30.0;

		fly.SetGoalPoint( goal );

		next_goal_time = level.time + .5f;
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyCloseToPlayer::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}


/****************************************************************************

  FlyCloseToParent Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyCloseToParent, NULL )
	{
		{ &EV_Behavior_Args,		&FlyCloseToParent::SetArgs },
		{ NULL, NULL }
	};

FlyCloseToParent::FlyCloseToParent()
	{
	speed = 0.0f;
	turn_speed = 10.0f;
	anim = "fly";
	next_goal_time = 0.0f;
	}

void FlyCloseToParent::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		turn_speed = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );
	}

void FlyCloseToParent::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCloseToParent::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
		
	if ( speed )
		fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyCloseToParent::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;


   if ( !self.spawnparent || !self.spawnparent->isSubclassOf( Actor ) )
		return BEHAVIOR_SUCCESS;
   
	if ( next_goal_time <= level.time )
		{
		Actor* act;

		act = (Actor*)self.spawnparent;
		goal = act->centroid;
		
		fly.SetGoalPoint( goal );

		next_goal_time = level.time + .5f;
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyCloseToParent::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}


/****************************************************************************

  FlyDescend Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FlyDescend, NULL )
	{
		{ &EV_Behavior_Args,	&FlyDescend::SetArgs },
		{ NULL, NULL }
	};

FlyDescend::FlyDescend()
	{
	anim = "fly";
	height = 500;
	speed = 0;
	next_height_check = level.time + 2.0f;
	last_check_height = 0.0f;
	}

void FlyDescend::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		height = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );
	}

void FlyDescend::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyDescend::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return;

	fly.Begin( self );

	height = currentEnemy->origin.z;

	goal = self.origin;
	goal.z = height;

	fly.SetTurnSpeed( 1.0f );

	fly.SetGoalPoint( goal );
	
	last_check_height = self.origin.z;

	if ( speed )
		fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyDescend::Evaluate
	(
	Actor &self
	)

	{
	if ( self.origin.z <= height || !self.enemyManager->GetCurrentEnemy())
      {
		return BEHAVIOR_SUCCESS;
      }

	if ( next_height_check < level.time )
		{
		if ( self.origin.z < ( last_check_height + 25.0f ) )
			return BEHAVIOR_SUCCESS;

		next_height_check = level.time + 2.0f;
		last_check_height = self.origin.z;
		}

	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		fly.SetGoalPoint( goal );

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyDescend::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}



/****************************************************************************

  FlyWander Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyWander, NULL )
	{
		{ &EV_Behavior_Args,	&FlyWander::SetArgs },
		{ NULL, NULL }
	};

FlyWander::FlyWander()
	{
	turn_speed = 10.0;
	anim = "fly";
	change_course_time = 5.0;
	speed = 200;
	try_to_go_up = false;
	next_change_course_time = 0;
	original_z = 0;
	}

void FlyWander::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		speed = ev->GetFloat( 2 );
      
	if ( ev->NumArgs() > 2 )
      turn_speed = ev->GetFloat( 3 );
      
	if ( ev->NumArgs() > 3 )
      change_course_time = ev->GetFloat( 4 );
      
	if ( ev->NumArgs() > 4 )
      try_to_go_up = ev->GetBoolean( 5 );
      
	if (ev->NumArgs() > 5 )
		fly.setAdjustYawAndRoll( ev->GetBoolean( 6 ) );	

	if (ev->NumArgs() > 6 )
		fly.setOffsetOrigin( ev->GetBoolean ( 7 ) );

	}

void FlyWander::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyWander::Begin
	(
	Actor &self
	)

	{
	original_z = self.origin.z;

	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
	fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyWander::Evaluate
	(
	Actor &self
	)

	{
	trace_t trace;
	Vector dir;
	float length;
	int goal_try;
	Vector temp_goal;
	float max_dist = 0.0f;


	dir = goal - self.origin;
	length = dir.length();

	if ( ( next_change_course_time <= level.time ) || ( length < 100.0f ) ) //self.lastmove != STEPMOVE_OK )
		{
		for( goal_try = 0 ; goal_try < 5 ; goal_try++ )
			{
			temp_goal = self.origin;

			temp_goal[0] += G_Random( 10000.0f ) - 5000.0f;
			temp_goal[1] += G_Random( 10000.0f ) - 5000.0f;

			if ( try_to_go_up )
				temp_goal[2] += G_Random( 1000.0f ) - 250.0f;
			else
				temp_goal[2] += G_Random( 100.0f ) - 50.0f;

			trace = G_Trace( self.origin, self.mins, self.maxs, temp_goal, &self, self.edict->clipmask, false, "FlyWander" );

			temp_goal = trace.endpos;

			dir = temp_goal - self.origin;
			length = dir.length();

			if ( length > max_dist )
				{
				max_dist = length;
				goal = temp_goal;

				if ( length > 1000.0f )
					break;
				}
			}

		fly.SetGoalPoint( goal );

		next_change_course_time = level.time + change_course_time;
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyWander::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyToNode Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyToNode, NULL )
	{
		{ &EV_Behavior_Args,	&FlyToNode::SetArgs },
		{ NULL, NULL }
	};

FlyToNode::FlyToNode()
	{
	turn_speed = 10.0;
	anim = "fly";
	speed = 200;
	NumberOfNodes = 0;
	}

void FlyToNode::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		speed = ev->GetFloat( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		turn_speed = ev->GetFloat( 3 );
      }

	if ( ev->NumArgs() > 3 )
      {
		NodeType = ev->GetString( 4 );
      }

	if ( ev->NumArgs() > 4 )
		{
		NumberOfNodes = ev->GetInteger( 5 );
		}
	}

void FlyToNode::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyToNode::Begin
	(
	Actor &self
	)

	{
	
	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
	fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyToNode::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	str pathnode_name;
	PathNode *goal;
	Vector teleport_position;
	Vector attack_position;

	int bestNode = 0;
	float bestDistance = -1;
	
	for(int i = 0; i <= NumberOfNodes; i++)
		{
		pathnode_name = NodeType + i;

		goal = thePathManager.FindNode( pathnode_name );

		if( goal )
			{
			float distanceTest = self.origin.length()  - goal->origin.length();

			if ( bestDistance < 0.0f )
				{
				bestDistance = distanceTest;
				bestNode = i;
				}
			else if (distanceTest < bestDistance )
				{
				bestDistance = distanceTest;
				bestNode = i;
				}
			}
		}
	
	pathnode_name = NodeType + bestNode;
	goal = thePathManager.FindNode( pathnode_name );
	
	if ( !goal )
		{
		gi.WDPrintf( "Can't find position %s\n", pathnode_name.c_str() );
		return BEHAVIOR_SUCCESS;
		}

	fly.SetGoalPoint( goal->origin );
	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyToNode::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyToRandomNode Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyToRandomNode, NULL )
	{
		{ &EV_Behavior_Args,	&FlyToRandomNode::SetArgs },
		{ NULL, NULL }
	};

FlyToRandomNode::FlyToRandomNode()
	{
	turn_speed = 10.0;
	anim = "fly";
	speed = 200;
	CurrentNode = -1;
	NeedNextNode = true;
	NumberOfNodes = 0;
	goal = NULL;
	}

void FlyToRandomNode::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		speed = ev->GetFloat( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		turn_speed = ev->GetFloat( 3 );
      }

	if ( ev->NumArgs() > 3 )
      {
		NodeType = ev->GetString( 4 );
      }

	if ( ev->NumArgs() > 4 )
		{
		NumberOfNodes = ev->GetInteger( 5 );		
		}	
	}

void FlyToRandomNode::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyToRandomNode::Begin
	(
	Actor &self
	)

	{
	
	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
	fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyToRandomNode::Evaluate
	(
	Actor &self
	)

	{
	str pathnode_name;
	Vector dir;
	
	if(NeedNextNode)
		{
		int x = (int)G_Random( (float)NumberOfNodes );
	   if (x == CurrentNode)
			x++;
	
	   CurrentNode = x;

		pathnode_name = NodeType + CurrentNode;
		
	   goal = thePathManager.FindNode( pathnode_name );

		NeedNextNode = false;
		}
   
	if ( !goal )
		{
		gi.WDPrintf( "Can't find position %s\n", pathnode_name.c_str() );
		return BEHAVIOR_SUCCESS;
		}

	fly.SetGoalPoint( goal->origin );
	fly.Evaluate( self );
   
	dir = self.origin - goal->origin;
	
	if ( dir.length() < 100.0f )
		{
		NeedNextNode = true;
		}

	return BEHAVIOR_EVALUATING;
	}

void FlyToRandomNode::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyToNodeNearestPlayer Class Definition

****************************************************************************/
CLASS_DECLARATION( Behavior, FlyToNodeNearestPlayer, NULL )
	{
		{ &EV_Behavior_Args,	&FlyToNodeNearestPlayer::SetArgs },
		{ NULL, NULL }
	};

FlyToNodeNearestPlayer::FlyToNodeNearestPlayer()
	{
	turn_speed = 10.0;
	anim = "fly";
	speed = 200;
	CurrentNode = -1;
	NeedNextNode = true;
	NumberOfNodes = 0;
	goal = NULL;
	}

void FlyToNodeNearestPlayer::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		speed = ev->GetFloat( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		turn_speed = ev->GetFloat( 3 );
      }

	if ( ev->NumArgs() > 3 )
      {
		NodeType = ev->GetString( 4 );
      }

	if ( ev->NumArgs() > 4 )
		{
		NumberOfNodes = ev->GetInteger( 5 );		
		}	
	}

void FlyToNodeNearestPlayer::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyToNodeNearestPlayer::Begin
	(
	Actor &self
	)

	{
	
	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
	fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyToNodeNearestPlayer::Evaluate
	(
	Actor &self
	)

	{
	str pathnode_name;
	Vector dir;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	
	if(NeedNextNode)
		{
		int ClosestNode = 0;
		float CheckLen = -1;
		PathNode* Pnode = 0;

		for ( int i = 1; i <= NumberOfNodes; i++ )
			{
			pathnode_name = NodeType + i;
			Pnode = thePathManager.FindNode(pathnode_name);
	
			if ( !Pnode )
				{
				gi.WDPrintf( "Can't find Pathnode %s\n", pathnode_name.c_str() );
				return BEHAVIOR_SUCCESS;
				}
			
			if( currentEnemy)
				{
				dir = Pnode->origin - currentEnemy->centroid;
				}
			else
				{
				Entity* player = g_entities[0].entity;
				dir = Pnode->origin - player->centroid;
				}

			if ( CheckLen < 0.0f )
				{
				CheckLen = dir.length();
				}
			else
				{
				if(dir.length() < CheckLen)
					{
					CheckLen = dir.length();
					ClosestNode = i;
					}
				}
			}
		
		pathnode_name = NodeType + ClosestNode;
		
	   goal = thePathManager.FindNode( pathnode_name );

		NeedNextNode = false;
		}

	fly.SetGoalPoint( goal->origin );
	fly.Evaluate( self );
   
	dir = self.origin - goal->origin;
	
	if ( dir.length() < 100.0f )
		{
		NeedNextNode = true;
		}

	return BEHAVIOR_EVALUATING;
	}

void FlyToNodeNearestPlayer::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyNodePath Class Definition

****************************************************************************/
CLASS_DECLARATION( Behavior, FlyNodePath, NULL )
	{
		{ &EV_Behavior_Args,		&FlyNodePath::SetArgs },
		{ NULL, NULL }
	};

FlyNodePath::FlyNodePath()
	{
	turn_speed = 10.0f;
	anim = "fly";
	speed = 200.0f;
	CurrentNode = -1;
	NeedNextNode = true;
	NumberOfNodes = 0;
	goal = NULL;
	}

void FlyNodePath::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		speed = ev->GetFloat( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		turn_speed = ev->GetFloat( 3 );
      }

	if ( ev->NumArgs() > 3 )
      {
		NodeType = ev->GetString( 4 );
      }

	if ( ev->NumArgs() > 4 )
		{
		NumberOfNodes = ev->GetInteger( 5 );		
		}	
	}

void FlyNodePath::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyNodePath::Begin
	(
	Actor &self
	)

	{
	
	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );
	fly.SetTurnSpeed( turn_speed );
	fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyNodePath::Evaluate
	(
	Actor &self
	)

	{
	str pathnode_name;
	Vector dir;
	
	if(NeedNextNode)
		{
	   CurrentNode++;

		if(CurrentNode > NumberOfNodes)
			CurrentNode = 0;

		pathnode_name = NodeType + CurrentNode;
		
	   goal = thePathManager.FindNode( pathnode_name );

		NeedNextNode = false;
		}
   
	if ( !goal )
		{
		gi.WDPrintf( "Can't find position %s\n", pathnode_name.c_str() );
		return BEHAVIOR_SUCCESS;
		}

	fly.SetGoalPoint( goal->origin );
	fly.Evaluate( self );
   
	dir = self.origin - goal->origin;
	
	if ( dir.length() < 100.0f )
		{
		NeedNextNode = true;
		}
	
	if ( (CurrentNode == NumberOfNodes) && NeedNextNode )
		return BEHAVIOR_SUCCESS;
	
	return BEHAVIOR_EVALUATING;
	}

void FlyNodePath::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyCircle Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyCircle, NULL )
	{
		{ &EV_Behavior_Args,	&FlyCircle::SetArgs },
		{ NULL, NULL }
	};

FlyCircle::FlyCircle()
	{
	anim = "fly";	
	fly_clockwise = true;
	circle_player = false;
	original_z = 0.0f;
	}

void FlyCircle::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	fly_clockwise = ev->GetBoolean( 2 );

	if (ev->NumArgs() > 2 )
		fly.setAdjustYawAndRoll( ev->GetBoolean( 3 ) );
	
	if (ev->NumArgs() > 3 )
		circle_player = ev->GetBoolean ( 4 );
	else
		circle_player = false;	
	
	if (ev->NumArgs() > 4 )
		fly.SetSpeed( ev->GetFloat( 5 ) );
	}

void FlyCircle::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCircle::Begin
	(
	Actor &self
	)

	{
	original_z = self.origin.z;

	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( 5.0f );
	}

BehaviorReturnCode_t	FlyCircle::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;
	trace_t trace;
	Vector dir;
	Vector angle;
	Vector left;
	qboolean too_far = false;
	Vector new_dir;
	Vector fly_dir;
	
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) && !circle_player )
      {
      return BEHAVIOR_SUCCESS;
      }


	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		{
		fly.SetTurnSpeed( 5.0f );

		if (circle_player)
			{
			Player *player = NULL;
			Player *temp_player = NULL;

			// Make sure the player is alive and well
			for(int i = 0; i < game.maxclients; i++)
				{
				temp_player = GetPlayer(i);		
			
				// don't target while player is not in the game or he's in notarget
				if ( temp_player && !( temp_player->flags & FL_NOTARGET ) )
					{
					player = temp_player;
					break;
					}
				}

			if ( !player )
				return BEHAVIOR_SUCCESS;
						
			dir = player->centroid - self.origin;
			dir.z = 0.0f;

			if ( dir.length() > ( ( self.origin.z - player->centroid.z ) / .5f ) )
				{
				too_far = true;
				}

			}
		else
			{
			dir = currentEnemy->centroid - self.origin;
			dir.z = 0.0f;

			if ( dir.length() > ( ( self.origin.z - currentEnemy->centroid.z ) / 2.0f ) )
				{
				too_far = true;
				}

			}

		angle = dir.toAngles();

		angle.AngleVectors( NULL, &left, NULL );

		if ( fly_clockwise )
			fly_dir = left;
		else
			fly_dir = left * -1.0f;

		dir.normalize();

		if ( too_far )
			{
			new_dir = ( fly_dir * 0.5f ) + ( dir * 0.5f );
			new_dir.normalize();
			}
		else
			{
			new_dir = fly_dir;
			}

		//goal = self.origin + new_dir * 200;
		goal = self.origin + ( new_dir * 700.0f );

		trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyCircle" );

		if ( trace.fraction < 1.0f )
			{
			if ( too_far )
				trace.fraction /= 2.0f;

			new_dir = ( fly_dir * trace.fraction ) + ( dir * ( 1.0f - trace.fraction ) );
			new_dir.normalize();

			//goal = self.origin + new_dir * 200;
			goal = self.origin + ( new_dir * 700.0f );
			}
		else
			{
			goal = trace.endpos;
			}

		fly.SetGoalPoint( goal );
		}
	else
		{
		fly.SetTurnSpeed( 20.0f );
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyCircle::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyStrafe Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyStrafe, NULL )
	{
		{ &EV_Behavior_Args,	&FlyStrafe::SetArgs },
		{ NULL, NULL }
	};

FlyStrafe::FlyStrafe()
	{
	anim = "fly";	
	}

void FlyStrafe::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	speed = ev->GetFloat( 2 );
	right = ev->GetBoolean( 3 );
	roll  = ev->GetFloat( 4 );	
	}

void FlyStrafe::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyStrafe::Begin
	(
	Actor &self
	)

	{
	self.SetAnim( anim );
	self.movementSubsystem->setForwardSpeed( speed );

   /*
	if ( right )
		self.FlightDirection = FLY_RIGHT;
	else
		self.FlightDirection = FLY_LEFT;
   */
	}

BehaviorReturnCode_t	FlyStrafe::Evaluate
	(
	Actor &self
	)

	{
 	Vector dir;
	Vector delta;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	dir = currentEnemy->centroid - self.origin;
	dir = dir.toAngles();

	if ( right )
		dir[ROLL] -= roll;
	else
		dir[ROLL] += roll;

	self.setAngles( dir );
	
   


	return BEHAVIOR_EVALUATING;
	}	
	

void FlyStrafe::End
	(
	Actor &self
	)

	{
	//self.FlightDirection = FLY_FORWARD;
	}

/****************************************************************************

  FlyCircleRandomPoint Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FlyCircleRandomPoint, NULL )
	{
		{ &EV_Behavior_Args,	&FlyCircleRandomPoint::SetArgs },
		{ NULL, NULL }
	};

FlyCircleRandomPoint::FlyCircleRandomPoint()
	{
	anim = "fly";
	//original_z = 0.0f;
	fly_clockwise = true;
	change_course_time = 5;
	try_to_go_up = false;
	next_change_course_time = 0;
	}

void FlyCircleRandomPoint::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	fly_clockwise = ev->GetBoolean( 2 );

	if ( ev->NumArgs() > 2 )
      change_course_time = ev->GetFloat( 3 );
      
	if ( ev->NumArgs() > 3 )
      try_to_go_up = ev->GetBoolean( 4 );
      
	if (ev->NumArgs() > 4 )
		fly.setAdjustYawAndRoll( ev->GetBoolean( 5 ) );	

	if (ev->NumArgs() > 5 )
		fly.SetSpeed( ev->GetFloat( 6 ) );

	}

void FlyCircleRandomPoint::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCircleRandomPoint::Begin
	(
	Actor &self
	)

	{
	//original_z = self.origin.z;

	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( 5.0f );
	fly.ForceGoal();
	}

BehaviorReturnCode_t	FlyCircleRandomPoint::Evaluate
	(
	Actor &self
	)

	{
   trace_t trace;
	Vector dir;
	Vector angle;
	Vector left;
	qboolean too_far = false;
	Vector new_dir;
	Vector fly_dir;
   float length;
	int goal_try;
	Vector temp_goal;
	float max_dist = 0;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) )
      {
      return BEHAVIOR_SUCCESS;
      }
	

	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		{
		fly.SetTurnSpeed( 5.0f );
		
		if ( next_change_course_time <= level.time ) //self.lastmove != STEPMOVE_OK )
			{
			
			dir = goal - self.origin;
			dir.z = 0;
			length = dir.length();
			
			fly_clockwise = !fly_clockwise;

			for( goal_try = 0 ; goal_try < 5 ; goal_try++ )
				{
							
				temp_goal = self.origin;
				
				//temp_goal[0] += G_Random( 10000 ) - 2500.0;
				//temp_goal[1] += G_Random( 10000 ) - 2500.0;
								
				temp_goal[0] += G_Random( 10000.0f ) + 10000.0f;
				temp_goal[1] += G_Random( 10000.0f ) + 10000.0f;
				if ( try_to_go_up )
					temp_goal[2] += G_Random( 1000.0f ) - 250.0f;
				else
					temp_goal[2] += G_Random( 100.0f ) - 50.0f;

				trace = G_Trace( self.origin, self.mins, self.maxs, temp_goal, &self, self.edict->clipmask, false, "FlyCircleRandomPoint" );

				temp_goal = trace.endpos;

				dir = temp_goal - self.origin;
				length = dir.length();

				if ( length > max_dist )
					{
					max_dist = length;
					goal = temp_goal;

					if ( length > 1000.0f )
					   break;
					}

				}

			next_change_course_time = (level.time + change_course_time);
			}
		
		if ( dir.length() > ( (self.origin.z - goal.z ) / 2.0f ) )
			{
			too_far = true;
			}

		angle = dir.toAngles();

		angle.AngleVectors( NULL, &left, NULL );

		if ( fly_clockwise )
			fly_dir = left;
		else
			fly_dir = left * -1.0f;

		dir.normalize();

		if ( too_far )
			{
		   new_dir = ( fly_dir * 0.5f ) + ( dir * 0.5f );
			new_dir.normalize();
			}
		else
			{
			new_dir = fly_dir;
			}

		goal = self.origin + ( new_dir * 30.0f );
		//goal = self.origin + new_dir * 100;

		
		trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyCircleRandomPoint" );

		if ( trace.fraction < 1.0f )
			{
			if ( too_far )
				trace.fraction /= 2.0f;

			new_dir = ( fly_dir * trace.fraction ) + ( dir * ( 1.0f - trace.fraction ) );
			new_dir.normalize();

			//goal = self.origin + new_dir * 200;
			goal = self.origin + ( new_dir * 100.0f );
			}
		else
			{
			goal = trace.endpos;
			}

		fly.SetGoalPoint( goal );
		}
	else
		{
		fly.SetTurnSpeed( 30.0f );
		}
	
	
	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;

	}

void FlyCircleRandomPoint::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlyDive Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyDive, NULL )
	{
		{ &EV_Behavior_Args, &FlyDive::SetArgs },
		{ NULL, NULL }
	};

FlyDive::FlyDive()
	{
	anim = "fly";
	speed = 2000;
	damage = 0;
	}

void FlyDive::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		speed = ev->GetFloat( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		damage = ev->GetFloat( 3 );
      }
	}

void FlyDive::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyDive::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return;

	if ( !self.IsEntityAlive( currentEnemy ) )
      {
		return;
      }

	goal = currentEnemy->centroid - self.origin;
	goal.normalize();
	goal *= 10000.0f;
	goal += self.origin;	
	
	self.movementSubsystem->setDiveDir( self.origin );

   fly.SetGoalPoint( goal );

	fly.SetTurnSpeed( 100.0f );
	fly.SetSpeed( speed );
	fly.SetRandomAllowed( false );
	fly.ForceGoal();
	}

BehaviorReturnCode_t	FlyDive::Evaluate
	(
	Actor &self
	)

	{
	trace_t trace;
	Vector dir;
	Entity *hit_entity;
	qboolean stuck;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) )
      return BEHAVIOR_SUCCESS;

	if ( self.origin.z < ( currentEnemy->origin.z + 50.0f ) )
		return BEHAVIOR_SUCCESS;

	if ( (self.movementSubsystem->getLastMove() == STEPMOVE_STUCK ) || ( self.movementSubsystem->getLastMove() == STEPMOVE_BLOCKED_BY_WATER ) )
		{
		stuck = true;

		dir = self.movementSubsystem->getMoveDir() * 100.0f;

		trace = G_Trace( self.origin, self.mins, self.maxs, self.origin + dir, &self, self.edict->clipmask, false, "FlyDive" );

		if ( trace.entityNum != ENTITYNUM_NONE )
			{
			hit_entity = G_GetEntity( trace.entityNum );

			// Damage entity hit
			//if ( hit_entity->isSubclassOf( Sentient ) )
			if ( hit_entity->takedamage )
				{
				//hit_entity->Damage( &self, &self, damage, Vector (0, 0, 0), Vector (0, 0, 0), Vector (0, 0, 0), 0, 0, MOD_CRUSH );
				dir.normalize();
				hit_entity->Damage( &self, &self, damage, self.centroid, dir, vec_zero, 0, 0, MOD_CRUSH );
				self.AddStateFlag( STATE_FLAG_MELEE_HIT );
				stuck = false;
				}
			}

		// Make sure we really are still stuck

		if ( trace.fraction > 0.05f )
			stuck = false;

		self.angles[PITCH] = 0.0f;
		self.setAngles( self.angles );

		if ( stuck )
			self.AddStateFlag( STATE_FLAG_STUCK );

		return BEHAVIOR_SUCCESS;
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyDive::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}


/****************************************************************************

  FlyCharge Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyCharge, NULL )
	{
		{ &EV_Behavior_Args,	&FlyCharge::SetArgs },
		{ NULL, NULL }
	};

FlyCharge::FlyCharge()
	{
	anim = "fly";
	speed = 2000;
	damage = 0;
	}

void FlyCharge::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
      {
		speed = ev->GetFloat( 2 );
      }

	if ( ev->NumArgs() > 2 )
      {
		damage = ev->GetFloat( 3 );
      }
	}

void FlyCharge::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCharge::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
		self.SetAnim( anim );

	fly.Begin( self );

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return;

	if ( !self.IsEntityAlive( currentEnemy ) )
      {
		return;
      }

	goal = currentEnemy->centroid - self.origin;
	goal.normalize();
	goal *= 10000.0f;
	goal += self.origin;
	goal.z = self.origin.z;
	
	self.movementSubsystem->setDiveDir( self.origin );

   fly.SetGoalPoint( goal );

	fly.SetTurnSpeed( 100.0f );
	fly.SetSpeed( speed );
	fly.SetRandomAllowed( false );
	fly.ForceGoal();
	}

BehaviorReturnCode_t	FlyCharge::Evaluate
	(
	Actor &self
	)

	{
	trace_t trace;
	Vector dir;
	Entity *hit_entity;
	qboolean stuck;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) )
      return BEHAVIOR_SUCCESS;

	if ( ( self.movementSubsystem->getLastMove() == STEPMOVE_STUCK ) || ( self.movementSubsystem->getLastMove() == STEPMOVE_BLOCKED_BY_WATER ) )
		{
		stuck = true;
				
		dir = self.movementSubsystem->getMoveDir() * 100.0f;

		trace = G_Trace( self.origin, self.mins, self.maxs, self.origin + dir, &self, self.edict->clipmask, false, "FlyDive" );

		if ( trace.entityNum != ENTITYNUM_NONE )
			{
			hit_entity = G_GetEntity( trace.entityNum );

			// Damage entity hit
			//if ( hit_entity->isSubclassOf( Sentient ) )
			if ( hit_entity->takedamage )
				{
				//hit_entity->Damage( &self, &self, damage, Vector (0, 0, 0), Vector (0, 0, 0), Vector (0, 0, 0), 0, 0, MOD_CRUSH );
				dir.normalize();
				hit_entity->Damage( &self, &self, damage, self.centroid, dir, vec_zero, 0, 0, MOD_CRUSH );
				self.AddStateFlag( STATE_FLAG_MELEE_HIT );
				stuck = false;
				}
			}

		// Make sure we really are still stuck

		if ( trace.fraction > 0.05f )
			stuck = false;

		self.angles[PITCH] = 0.0f;
		self.setAngles( self.angles );

		if ( stuck )
			self.AddStateFlag( STATE_FLAG_STUCK );

		return BEHAVIOR_SUCCESS;
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyCharge::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}


/****************************************************************************

  FlyClimb Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyClimb, NULL )
	{
		{ &EV_Behavior_Args,	&FlyClimb::SetArgs },
		{ NULL, NULL }
	};

FlyClimb::FlyClimb()
	{
	anim = "fly";
	height = 500;
	speed = 0;
	collision_buffer = 0;
	next_height_check = level.time + 2.0;
	last_check_height = 0.0f;
	}

void FlyClimb::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		height = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );

	if ( ev->NumArgs() > 3 )
		collision_buffer = ev->GetFloat( 1 );	
	}

void FlyClimb::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyClimb::Begin
	(
	Actor &self
	)

	{
	
	Vector forward;
	trace_t trace;

	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();


	if ( currentEnemy )
		height = currentEnemy->origin.z + height;	   
	else
		height = self.origin.z + height;

	self.angles.AngleVectors( &forward );
	
	//Okay, here's what we are attempting.  We are first going to get our initial point, 
	//this will be our forward vector * height, then add the the height to the the Z.
	//Next we will trace out, to see how far along that vector we got.  We will use our 
	//trace.endpos as a goal position

	//Now, we don't want to use this goal position as a final vector, because if we ran into
	//something, then we will smack it when we get there... this would be bad, so, we run a 
	//a vector from our origin to our goal position and get the length, we then shave some off of
	//this length and multiply it by another vector and add it to the origin, this will get us
	//our final position

	goal = forward * height;
	goal.z = height;
	goal += self.origin;

	trace = G_Trace( self.centroid, self.mins, self.maxs, goal, NULL, MASK_SOLID, false, "flyclimb" );
	goal = trace.endpos;

	Vector dir;
	dir = self.origin - goal;

	float length;	

	length = dir.length();
	
	if ( collision_buffer )
		length -= collision_buffer;
	else
		length -= (length / 10.0f);

	if ( length > 0.0f )
		{
      goal = forward * length;
		goal.z = length;
		goal += self.origin;
		}
		

	//if ( !self.divedir.x && !self.divedir.y && !self.divedir.z )
	//	{
   //   goal = forward * height;
	//   goal.z = height;
	//   goal += self.origin;
	//	trace = G_Trace( self.centroid, self.mins, self.maxs, goal, NULL, MASK_SOLID, false, "flyclimb" );
		
		


	//	}
   //else
	//	{
   //   goal = self.divedir;
	//	goal.z = height;
	//	}
		
	   


	fly.SetTurnSpeed( 10.0f );

	fly.SetGoalPoint( goal );
	
	last_check_height = self.origin.z;

	if ( speed )
		fly.SetSpeed( speed );
	}

BehaviorReturnCode_t	FlyClimb::Evaluate
	(
	Actor &self
	)

	{

	if ( self.origin.z >= height )
      {
		return BEHAVIOR_SUCCESS;
      }

	if ( next_height_check < level.time )
		{
		if ( self.origin.z < ( last_check_height + 25.0f ) )
			return BEHAVIOR_SUCCESS;

		next_height_check = level.time + 2.0f;
		last_check_height = self.origin.z;
		}

	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		fly.SetGoalPoint( goal );

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void FlyClimb::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  FlySplinePath Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, FlySplinePath, NULL )
	{
		{ &EV_Behavior_Args,	&FlySplinePath::SetArgs },
		{ NULL, NULL }
	};

FlySplinePath::FlySplinePath()
	{
	ent = NULL;
	clamp = true;
	ignoreAngles = false;
	splineAngles = true;	
	havePath = false;
	startTime = 0.0f;
	}

void FlySplinePath::SetArgs
	(
	Event *ev
	)

	{
   ent          = ev->GetEntity( 1 );
   ignoreAngles = ev->GetBoolean( 2 );
	splineAngles = ev->GetBoolean( 3 );
	clamp        = ev->GetBoolean( 4 );	
	}

void FlySplinePath::CreatePath
	(
	SplinePath *path,
	splinetype_t type
	)

	{
	
	SplinePath	*node;
   
	splinePath.Clear();
	splinePath.SetType( type );

	node = path;
	while( node != NULL )
		{
      splinePath.AppendControlPoint( node->origin, node->angles, node->speed );
		node = node->GetNext();

		if ( node == path )
			{
			break;
			}
		}
	
	}
void FlySplinePath::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlySplinePath::Begin
	(
	Actor &self
	)

	{
	
	if ( ent )
		havePath = true;
	else
		return;

	if ( ent->isSubclassOf( SplinePath ) )
		{

		SplinePath* path;
      
		path = (SplinePath*)(Entity*)ent;
		
		if ( clamp )			
			CreatePath( path, SPLINE_CLAMP );
		else
			CreatePath( path, SPLINE_LOOP );
		
		currentNode = path;
      
		if (currentNode->thread != "" )
			{
			if ( !ExecuteThread( currentNode->thread ) )
				{
				gi.Error( ERR_DROP, "FlySplinePath could not run thread '%s' from info_splinepath '%s'\n", 
					currentNode->thread.c_str(), currentNode->targetname.c_str() );
				}
			}
		
		if ( currentNode->triggertarget != "" )
			{
			Entity	*ent;
			Event		*event;

			ent = NULL;
			do
				{
				ent = G_FindTarget( ent, currentNode->triggertarget.c_str() );
				if ( !ent )
					{
					break;
					}
		   	event = new Event( EV_Activate );
				
				Actor* actorPtr = &self;
				Entity* entPtr = (Entity*)actorPtr;
				event->AddEntity( entPtr );
				ent->PostEvent( event, 0.0f );
				}
			while ( 1 );
			}
		
		}
   
	startTime = level.time + self.currentSplineTime;
	
	
	}

BehaviorReturnCode_t	FlySplinePath::Evaluate
	(
	Actor &self
	)

	{
   
	Vector goal;
	Vector dir;
	Vector angles;
	
	if(!havePath)
		return BEHAVIOR_SUCCESS;

	
	goal = splinePath.Eval( (level.time - startTime) );		

	if ( goal == oldGoal )
		{
		self.currentSplineTime = 0;
		return BEHAVIOR_SUCCESS;
		}
		

	oldGoal = goal;
	
	dir = goal - self.origin;
   angles = dir.toAngles();

	self.setOrigin(goal);
	self.setAngles(angles);

	
	return BEHAVIOR_EVALUATING;

	
	}

void FlySplinePath::End
	(
	Actor &self
	)

	{
   self.currentSplineTime = level.time - startTime;
   }

/****************************************************************************

  Land Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, Land, NULL )
	{
		{ &EV_Behavior_Args,	&Land::SetArgs },
		{ NULL, NULL }
	};

Land::Land()
	{
	anim = "fly";
	}

void Land::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void Land::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void Land::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	self.velocity = Vector(0, 0, -40);
	}

BehaviorReturnCode_t	Land::Evaluate
	(
	Actor &self
	)

	{
	self.angles[PITCH] = 0.0f;
	self.angles[ROLL]  = 0.0f;

	self.setAngles( self.angles );

	self.velocity.z -= 20.0f;

	if ( self.velocity.z < -200.0f )
      {
		self.velocity.z = -200.0f;
      }

   if ( !self.groundentity )
      return BEHAVIOR_EVALUATING;

	return BEHAVIOR_SUCCESS;
	}

void Land::End
	(
	Actor &self
	)

	{
	}


/****************************************************************************

  Vertical Takeoff Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, VerticalTakeOff, NULL )
	{
		{ &EV_Behavior_Args, &VerticalTakeOff::SetArgs },
		{ NULL, NULL }
	};

VerticalTakeOff::VerticalTakeOff()
	{
	anim = "fly";
	speed = 0;
	height = 0;
	}

void VerticalTakeOff::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	speed = ev->GetFloat( 2 );
	height = ev->GetFloat( 3 );
	}

void VerticalTakeOff::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void VerticalTakeOff::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }
	
	self.velocity.x = 0;
	self.velocity.y = 0;
	self.velocity.z = speed;
	
	}

BehaviorReturnCode_t	VerticalTakeOff::Evaluate
	(
	Actor &self
	)

	{
	self.angles[PITCH] = 0.0f;
	self.angles[ROLL]  = 0.0f;

	self.setAngles( self.angles );

	self.velocity.z += 20.0f;

	if ( self.velocity.z > 200.0f )
      {
		self.velocity.z = 200.0f;
      }

	if( self.origin.z >= height )
		return BEHAVIOR_SUCCESS;
	else
		return BEHAVIOR_EVALUATING;
	}

void VerticalTakeOff::End
	(
	Actor &self
	)

	{
	}


/****************************************************************************

  Hover Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Hover, NULL )
	{
		{ &EV_Behavior_Args, &Hover::SetArgs },
		{ NULL, NULL }
	};

Hover::Hover()
	{
	anim = "fly";
	}

void Hover::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void Hover::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void Hover::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }
   
	fly.Begin( self );	
	}

BehaviorReturnCode_t	Hover::Evaluate
	(
	Actor &self
	)

	{
	//self.angles[PITCH] = 0;
	self.angles[ROLL]  = 0;

	self.setAngles( self.angles );
	self.movementSubsystem->setForwardSpeed( 0 );

	return BEHAVIOR_EVALUATING;
	}

void Hover::End
	(
	Actor &self
	)

	{
	fly.End(self);
	}
/****************************************************************************

  Wander Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, Wander, NULL )
	{
		{ &EV_Behavior_Args,	&Wander::SetArgs },
		{ NULL, NULL }
	};

void Wander::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void Wander::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nseek:\n" );

	}

void Wander::Begin
	(
	Actor &self
	)

	{
   avoidtime = 0;
   avoidvec = vec_zero;

	if ( anim.length() )
		{
		self.SetAnim( anim );
		}
	}


BehaviorReturnCode_t	Wander::Evaluate
	(
	Actor &self
	)

	{
   if ( ( self.movementSubsystem->getLastMove() != STEPMOVE_OK ) || ( avoidtime <= level.time ) )
      {
      Vector dir;
      Vector ang;
      float time;

      time = 5.0f;
		//self.Chatter( "snd_idle", 4 );
      avoidvec = ChooseRandomDirection( self, avoidvec, &time, 0, false );
      self.movementSubsystem->setMovingBackwards( false );
      avoidtime = level.time + time;
      }

	float maxSpeed = 100.0f;
	if ( self.movementSubsystem->getMoveSpeed() != 1.0f )
		{	
		maxSpeed = self.movementSubsystem->getMoveSpeed();
		}

	self.movementSubsystem->Accelerate( 
			self.movementSubsystem->SteerTowardsPoint( avoidvec, vec_zero, self.movementSubsystem->getMoveDir(), maxSpeed)
		);

	return BEHAVIOR_EVALUATING;
	}

void Wander::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  GetCloseToEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, GetCloseToEnemy, NULL )
	{
		{ &EV_Behavior_Args,	&GetCloseToEnemy::SetArgs },
		{ NULL, NULL }
	};

void GetCloseToEnemy::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		forever = ev->GetBoolean( 2 );
	else
		forever = true;
	}

void GetCloseToEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void GetCloseToEnemy::Begin
	(
	Actor &self
	)

	{
   Vector dir;
	dir = self.movementSubsystem->getAnimDir();
	dir = dir.toAngles();
	self.setAngles( dir );

   if ( !anim.length() )
      {
		anim = "run";
      }

	if ( anim != self.animname || self.newanim.length() )
      {
		self.SetAnim( anim, EV_Actor_NotifyBehavior );
      }

	chase.Begin( self );
	wander.Begin( self );

	next_think_time = 0;
   
	}

BehaviorReturnCode_t	GetCloseToEnemy::Evaluate
	(
	Actor &self
	)

	{
	qboolean result;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( next_think_time <= level.time )
		{
		if ( self.groundentity && ( self.groundentity->s.number == currentEnemy->entnum ) )
			{
			wander.Evaluate( self );
			result = true;
			}
		else
			{
			float radius=96.0f;
			chase.SetGoal( currentEnemy, radius, self );			

			result = chase.Evaluate( self );
			}

		if ( self.GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) )
			next_think_time = level.time + ( 2.0f * FRAMETIME );
		else
			next_think_time = 0.0f;
		}
	else
		result = true;

	if ( !forever && !result )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void GetCloseToEnemy::End
	(
	Actor &self
	)

	{
	chase.End( self );
	wander.End( self );
	}

/****************************************************************************

  GetCloseToPlayer Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, GetCloseToPlayer, NULL )
	{
		{ &EV_Behavior_Args,	&GetCloseToPlayer::SetArgs },
		{ NULL, NULL }
	};

void GetCloseToPlayer::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		forever = ev->GetBoolean( 2 );
	else
		forever = true;

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );
	else
		speed = 100;
	}

void GetCloseToPlayer::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void GetCloseToPlayer::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
      {
		anim = "run";
      }

	if ( anim != self.animname || self.newanim.length() )
      {
		self.SetAnim( anim, EV_Actor_NotifyBehavior );
      }

	chase.Begin( self );
	wander.Begin( self );
	
	self.movementSubsystem->setForwardSpeed( speed );

	next_think_time = 0;
	}

BehaviorReturnCode_t	GetCloseToPlayer::Evaluate
	(
	Actor &self
	)

	{
	qboolean result;
	
	Player *player = NULL;
	Player *temp_player = NULL;
	// Make sure the player is alive and well
	for(int i = 0; i < game.maxclients; i++)
		{
		temp_player = GetPlayer(i);		
		
		// don't target while player is not in the game or he's in notarget
		if( temp_player && !( temp_player->flags & FL_NOTARGET ) )
			{
			player = temp_player;
			break;
			}
		}

	if ( !player )
		return BEHAVIOR_SUCCESS;

	if ( next_think_time <= level.time )
		{
		if ( self.groundentity && ( self.groundentity->s.number == player->entnum ) )
			{
			wander.Evaluate( self );
			result = true;
			}
		else
			{
			float radius=96.0f;
			chase.SetGoal( player, radius, self );			

			result = chase.Evaluate( self );
			}

		if ( self.GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) )
			next_think_time = level.time + ( 2.0f * FRAMETIME );
		else
			next_think_time = 0.0f;
		}
	else
		result = true;

	if ( !forever && !result )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void GetCloseToPlayer::End
	(
	Actor &self
	)

	{
	chase.End( self );
	wander.End( self );
	self.movementSubsystem->setForwardSpeed( 0 );
	}

/****************************************************************************

  RetreatFromEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, RetreatFromEnemy, NULL )
	{
		{ &EV_Behavior_Args, &RetreatFromEnemy::SetArgs },
		{ NULL, NULL }
	};

void RetreatFromEnemy::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		forever = ev->GetBoolean( 2 );
	else
		forever = true;
	}

void RetreatFromEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void RetreatFromEnemy::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
      {
		anim = "run";
      }

	if ( anim != self.animname || self.newanim.length() )
      {
		self.SetAnim( anim, EV_Actor_NotifyBehavior );
      }

	chase.Begin( self );
	wander.Begin( self );

	next_think_time = 0;
	}

BehaviorReturnCode_t	RetreatFromEnemy::Evaluate
	(
	Actor &self
	)

	{
	qboolean result;
	Entity *currentEnemy;

	currentEnemy = self.enemyManager->GetCurrentEnemy();

	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( next_think_time <= level.time )
		{
		if ( self.groundentity && ( self.groundentity->s.number == currentEnemy->entnum ) )
			{
			wander.Evaluate( self );
			result = true;
			}
		else
			{
			
			float currentZ = self.centroid.z; 
			Vector FleeVec = (self.centroid - currentEnemy->centroid) + self.centroid;
			FleeVec.z = currentZ;

			trace_t trace;
			trace = G_Trace( self.centroid, self.mins, self.maxs, FleeVec, NULL, MASK_SOLID, false, "RetreatFromEnemy" );
			
			float radius=96.0f;
			chase.SetGoal( trace.endpos, radius, self );

			result = chase.Evaluate( self );
			}

		if ( self.GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) )
			next_think_time = level.time + ( 2.0f * FRAMETIME );
		else
			next_think_time = 0.0f;
		}
	else
		result = true;

	if ( !forever && !result )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void RetreatFromEnemy::End
	(
	Actor &self
	)

	{
	chase.End( self );
	wander.End( self );
	}

/****************************************************************************

  GotoDeadEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, GotoDeadEnemy, NULL )
	{
		{ &EV_Behavior_Args,	&GotoDeadEnemy::SetArgs },
		{ NULL, NULL }
	};

void GotoDeadEnemy::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void GotoDeadEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void GotoDeadEnemy::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
      {
		anim = "run";
      }

	if ( anim != self.animname || self.newanim.length() )
      {
		self.SetAnim( anim, EV_Actor_NotifyBehavior );
      }

	chase.Begin( self );
	}

BehaviorReturnCode_t	GotoDeadEnemy::Evaluate
	(
	Actor &self
	)

	{
	qboolean result;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !currentEnemy->deadflag )
		return BEHAVIOR_SUCCESS;

	float radius=96.0f;
	chase.SetGoal( currentEnemy->origin, radius, self );

	result = chase.Evaluate( self );

	if ( !result )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void GotoDeadEnemy::End
	(
	Actor &self
	)

	{
	chase.End( self );
	}

/****************************************************************************

  Investigate Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Investigate, NULL )
	{
		{ &EV_Behavior_Args,	&Investigate::SetArgs },
		{ NULL, NULL }
	};

#define INVESTIGATE_MODE_INVESTIGATE	0
#define INVESTIGATE_MODE_LOOKAROUND		1
#define INVESTIGATE_MODE_RETURN			2
#define INVESTIGATE_MODE_TURN2			3

Investigate::Investigate()
	{
	investigate_time = 10.0f;
	moveanim = "run";
	lookaroundanim = "idle";
	curioustime = 0.0f;
	lookaroundtime = 2.0f;
	mode = INVESTIGATE_MODE_INVESTIGATE;
	return_to_original_location = true;
	start_yaw = 0.0f;
	}

void Investigate::SetArgs
	(
	Event *ev
	)

	{
	moveanim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		investigate_time = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		return_to_original_location = ev->GetBoolean( 3 );
	else
		return_to_original_location = true;

	if( ev->NumArgs() > 3 )
		lookaroundanim = ev->GetString( 4 );

	if( ev->NumArgs() > 4 )
		lookaroundtime = ev->GetFloat( 5 );
	}

void Investigate::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
   gi.Printf( "\nanim: %s\n", moveanim.c_str() );
   gi.Printf( "curioustime: %f\n", curioustime );
   gi.Printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z );
	}

void Investigate::Begin(
	Actor &self
	)
	
{
// Note: the state machine for this character needs to use "forgetenemies" or it will get
//  stuck in a loop.

	Vector trace_start_pos;
	Vector trace_end_pos;
	PathNode *goal_node;
	
	// Find the goal position
	if( self.sensoryPerception->GetLastSoundType() == SOUNDTYPE_NONE )
	{
		EntityPtr enemy = self.enemyManager->GetCurrentEnemy();
		if( enemy != NULL )
		{
			// Didn't hear a sound... must've seen someone
			goal = enemy->origin;
		}
		else
		{
			// Didn't hear or see anything?  wtf?!  Just hang out where you are, ai.
			goal = self.origin; 
		}
	}
	else
	{
		// Heard a sound
		goal = self.sensoryPerception->GetNoisePosition();
	}
	
	// Try to find a pathnode close to the goal position to ensure good pathfinding
	
	goal_node = self.NearestNodeInPVS( goal );
	if ( goal_node )
	{
		goal = goal_node->origin;
	}
	
	// Let anyone else who cares know that this guy is investigating
	
	self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, true );
	
	// Only search for a set amount of time before returning to non-investigative state
	
	curioustime = level.time + investigate_time;

	// Make some sounds?
	
	self.Chatter( "snd_investigate" );
	
	// Setup movement code to move toward the goal position
	
	chase.Begin( self );
	chase.SetGoal( goal, 96.0f, self );

	// Turn toward ???

	turnto.Begin( self );
	
	// Don't start movement anim if it's so close there will be no actual movement
	
	if ( moveanim.length() && ( Vector::DistanceXY( goal, self.origin ) >= 100.0f ) )
	{
		self.SetAnim( moveanim );
	}
	
	start_pos = self.origin;
	start_yaw = self.angles[YAW];
}

BehaviorReturnCode_t Investigate::Evaluate(
	Actor &self
	)
{
	Vector dir;
	Vector angles;
	Steering::ReturnValue steeringResult;
	
	switch ( mode )
	{
	// Go to spot where the noise was heard
	case INVESTIGATE_MODE_INVESTIGATE:
		
		// Go to next mode if time elapsed or pathing failed
		
		steeringResult = chase.Evaluate( self );
		if ( (steeringResult != Steering::EVALUATING) || curioustime < level.time )
		{
			mode = INVESTIGATE_MODE_LOOKAROUND;
			self.SetAnim( lookaroundanim );
			lookaroundtime_end = level.time + lookaroundtime;
		}
		else
		{
			// Go to next mode if close enough to goal position
			
			float dist = Vector::DistanceXY( goal, self.origin );
			if( dist < 100.0f )
			{
				mode = INVESTIGATE_MODE_LOOKAROUND;
				self.SetAnim( lookaroundanim );
				lookaroundtime_end = level.time + lookaroundtime;
			}
		}
		
		break;
		
	// look around for stuff for a second
	case INVESTIGATE_MODE_LOOKAROUND:
		
		if( level.time > lookaroundtime_end )
		{
			curioustime = level.time + (investigate_time * 2.0f );
			mode = INVESTIGATE_MODE_RETURN;
			self.SetAnim( moveanim );
		}
		
		break;
		
	// go back from whence you came, foul beast
	case INVESTIGATE_MODE_RETURN :
		
		if ( !return_to_original_location )
			return BEHAVIOR_SUCCESS;
		
		// Return back to our original position
		chase.SetGoal( start_pos, 96.0f, self );
		
		if ( chase.Evaluate( self ) != Steering::EVALUATING )
			mode = INVESTIGATE_MODE_TURN2;
		
		if ( curioustime < level.time )
			return BEHAVIOR_SUCCESS;
		
		break;

	// got stuck going back to start position, just face original direction?
	case INVESTIGATE_MODE_TURN2 :
		
		self.SetAnim( "idle" );
		
		// Turn back to our original direction
		
		turnto.SetDirection( start_yaw );
		if ( !turnto.Evaluate( self ) )
			return BEHAVIOR_SUCCESS;
		
		break;
	}
	
	return BEHAVIOR_EVALUATING;
}

void Investigate::End
(
	Actor &self
	)
	
{
	self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, false );
	self.SetActorFlag( ACTOR_FLAG_NOISE_HEARD, false );
	chase.End( self );
	turnto.End( self );
}

/****************************************************************************

  TurnInvestigate Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, TurnInvestigate, NULL )
	{
		{ &EV_Behavior_Args,	&TurnInvestigate::SetArgs },
		{ NULL, NULL }
	};

void TurnInvestigate::SetArgs
	(
	Event *ev
	)

	{
	left_anim  = ev->GetString( 1 );
	right_anim = ev->GetString( 2 );
	turn_speed = ev->GetFloat( 3 );
	}

void TurnInvestigate::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z );
	}

void TurnInvestigate::Begin
	(
	Actor &self
	)

	{
	goal = self.sensoryPerception->GetNoisePosition();
	self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, true );
	self.SetAnim( "idle" );
	}

BehaviorReturnCode_t	TurnInvestigate::Evaluate
	(
	Actor &self
	)

	{
	str turn_anim_name;

	Vector dir;
	self.angles.AngleVectors( &dir );

	Vector newSteeringForce = self.movementSubsystem->SteerTowardsPoint( goal, vec_zero, dir, 1.0f);

	// See if we have turned all of the way to the noise position

	if ( ( newSteeringForce[YAW] < .5f ) && ( newSteeringForce[YAW] > -.5f ) )
		return BEHAVIOR_SUCCESS;

	// Make sure we are not turning faster than out turn speed
	if ( newSteeringForce[YAW] > turn_speed )
		{
		newSteeringForce[YAW] = turn_speed;
		}

	if ( newSteeringForce[YAW] < -turn_speed )
		{
		newSteeringForce[YAW] = -turn_speed;
		}

	newSteeringForce[PITCH] = 0.0f;
	newSteeringForce[ROLL]  = 0.0f;

	// Set the correct animation (left or right)

	if ( newSteeringForce[YAW] > 0.0f )
		turn_anim_name = left_anim;
	else
		turn_anim_name = right_anim;

	if ( turn_anim_name != self.animname )
		self.SetAnim( turn_anim_name );

	// Actually turn here

	self.movementSubsystem->Accelerate( newSteeringForce );

	return BEHAVIOR_EVALUATING;
	}

void TurnInvestigate::End
	(
	Actor &self
	)

	{
	self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, false );
	self.SetActorFlag( ACTOR_FLAG_NOISE_HEARD, false );
	}

/****************************************************************************

  TurnToEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, TurnToEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&TurnToEnemy::SetArgs },
		{ &EV_Behavior_AnimDone,		&TurnToEnemy::AnimDone },
		{ NULL, NULL }
	};

void TurnToEnemy::SetArgs
	(
	Event *ev
	)

	{
	left_anim  = ev->GetString( 1 );
	right_anim = ev->GetString( 2 );
	turn_speed = ev->GetFloat( 3 );
	forever    = ev->GetBoolean( 4 );

	if ( ev->NumArgs() > 4 )
		use_last_known_position = ev->GetBoolean( 5 );
	else
		use_last_known_position = false;
	}

void TurnToEnemy::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void TurnToEnemy::Begin
	(
	Actor &self
	)

	{

	self.SetAnim( "idle" );
	}

void TurnToEnemy::AnimDone
	(
	Event *ev
	)

	{
	anim_done = true;
	}


BehaviorReturnCode_t	TurnToEnemy::Evaluate
	(
	Actor &self
	)

	{

	Entity *currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	Vector dir;
	self.angles.AngleVectors( &dir );

	Vector targetPosition=currentEnemy->origin;
	if ( use_last_known_position )
		{
		targetPosition = self.last_known_enemy_pos;
		}

	Vector newSteeringForce = self.movementSubsystem->SteerTowardsPoint( targetPosition, vec_zero, dir, 1.0f );

	// See if we have turned all of the way to the enemy position
	if ( ( newSteeringForce[YAW] < .5f ) && ( newSteeringForce[YAW] > -.5f ) )
		newSteeringForce[YAW] = 0.0f;

	// Make sure we are not turning faster than out turn speed

	if ( newSteeringForce[YAW] > turn_speed )
		{
		newSteeringForce[YAW] = turn_speed;
		}

	if ( newSteeringForce[YAW] < -turn_speed )
		{
		newSteeringForce[YAW] = -turn_speed;
		}

	newSteeringForce[PITCH] = 0.0f;
	newSteeringForce[ROLL]  = 0.0f;

	// Set the correct animation (left or right)
	str turn_anim_name;
	if ( newSteeringForce[YAW] > 0.0f )
		turn_anim_name = left_anim;
	else if ( newSteeringForce[YAW] < 0.0f )
		turn_anim_name = right_anim;
	else if ( anim_done )
		turn_anim_name = "idle";
	else
		turn_anim_name = self.animname.c_str();

	if ( turn_anim_name != self.animname )
		self.SetAnim( turn_anim_name, EV_Actor_NotifyBehavior );

	// Actually turn here

	self.movementSubsystem->Accelerate( newSteeringForce );

	// See if we have turned all of the way to the enemy position

	if ( ( newSteeringForce[YAW] < turn_speed ) && ( newSteeringForce[YAW] > -turn_speed ) && !forever )
		return BEHAVIOR_SUCCESS;

	anim_done = false;

	return BEHAVIOR_EVALUATING;
	}

void TurnToEnemy::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  PickupEntity Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, PickupEntity, NULL )
	{
		{ &EV_Behavior_Args,		&PickupEntity::SetArgs },
		{ &EV_Behavior_AnimDone,	&PickupEntity::AnimDone },
		{ NULL, NULL }
	};

void PickupEntity::SetArgs
	(
	Event *ev
	)

	{
	ent_to_pickup    = ev->GetEntity( 1 );
	pickup_anim_name = ev->GetString( 2 );
	}

void PickupEntity::Begin
	(
	Actor &self
	)

	{
	anim_done = false;
	self.pickup_ent = ent_to_pickup;

	self.SetAnim( pickup_anim_name.c_str(), EV_Actor_NotifyBehavior );
	}

void PickupEntity::AnimDone
	(
	Event *ev
	)

	{
	anim_done = true;
	}


BehaviorReturnCode_t	PickupEntity::Evaluate
	(
	Actor &self
	)

	{
	if ( !ent_to_pickup )
		return BEHAVIOR_SUCCESS;

	if ( anim_done )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void PickupEntity::End
	(
	Actor &self
	)

	{
	self.SetAnim( "idle" );
	self.pickup_ent = NULL;
	}

/****************************************************************************

  ThrowEntity Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, ThrowEntity, NULL )
	{
		{ &EV_Behavior_Args,		&ThrowEntity::SetArgs },
		{ &EV_Behavior_AnimDone,	&ThrowEntity::AnimDone },
		{ NULL, NULL }
	};

void ThrowEntity::SetArgs
	(
	Event *ev
	)

	{
	throw_anim_name = ev->GetString( 1 );
	}

void ThrowEntity::Begin
	(
	Actor &self
	)

	{
	anim_done = false;
	self.SetAnim( throw_anim_name, EV_Actor_NotifyBehavior );
	}

void ThrowEntity::AnimDone
	(
	Event *ev
	)

	{
	anim_done = true;
	}


BehaviorReturnCode_t	ThrowEntity::Evaluate
	(
	Actor &self
	)

	{
	if ( anim_done )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
	}

void ThrowEntity::End
	(
	Actor &self
	)

	{
	self.SetAnim( "idle" );
	}



/****************************************************************************
*****************************************************************************

  Behaviors for specific creatures

*****************************************************************************
****************************************************************************/



/****************************************************************************

  BurrowAttack Class Definition

****************************************************************************/

#define BURROW_MODE_MOVING  0
#define BURROW_MODE_ATTACK  1

CLASS_DECLARATION( Behavior, BurrowAttack, NULL )
	{
		{ NULL, NULL }
	};

void BurrowAttack::SetArgs
	(
	Event *ev
	)

	{
	use_last_known_position = ev->GetBoolean( 1 );
	}

void BurrowAttack::Begin
	(
	Actor &self
	)

	{
	Vector attack_dir;
	Vector start_pos;
	Vector end_pos;
	trace_t trace;

	if ( self.animname != "idle_down" )
		self.SetAnim( "idle_down" );

	// Setup our goal point
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();

	if ( currentEnemy )
		{
		if ( use_last_known_position )
			goal = self.last_known_enemy_pos;
		else
			goal = currentEnemy->origin;

		start_pos = goal + Vector( "0 0 10" );
		end_pos = start_pos + Vector( "0 0 -250" );

		trace = G_Trace( start_pos, vec_zero, vec_zero, end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack::Begin" );

		goal = trace.endpos;
		}

	// Setup our starting point, a little ways in front of our origin

	attack_dir = goal - self.origin;

	too_close = false;

	if ( attack_dir.length() < 300.0f )
		too_close = true;

	attack_dir.normalize();

	attack_origin = self.origin + ( attack_dir * 100.0f );

	burrow_mode = BURROW_MODE_MOVING;

	stage = self.stage;

	burrow_speed = 80.0f;

	if ( stage == 3 )
		{
		attacks_left = 2;
		}
	else if ( stage == 4 )
		{
		attacks_left = 3 + (int)G_Random( 3.0f );
		burrow_speed = 120.0f;
		}
	}

BehaviorReturnCode_t	BurrowAttack::Evaluate
	(
	Actor &self
	)

	{
	Vector attack_dir;
	Vector new_origin;
	float total_dist;
	Vector start_pos;
	Vector end_pos;
	Entity *dirt;
	trace_t trace;
	Vector temp_angles;
	int cont;
	Vector temp_endpos;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( too_close )
		return BEHAVIOR_SUCCESS;

	switch ( burrow_mode )
		{
		case BURROW_MODE_MOVING :

			attack_dir = goal - attack_origin;
			total_dist = attack_dir.length();
			attack_dir.normalize();

			if ( total_dist < burrow_speed )
				{
				new_origin = goal;
				}
			else
				{
				new_origin = attack_origin + ( attack_dir * burrow_speed );
				total_dist = burrow_speed;
				}

			// Spawn in dirt or water

			start_pos = attack_origin + attack_dir + Vector( "0 0 10" );
			end_pos = start_pos + Vector( "0 0 -250" );

			trace = G_Trace( start_pos, vec_zero, vec_zero, end_pos, NULL, MASK_DEADSOLID | MASK_WATER, false, "BurrowAttack" );

			temp_endpos = trace.endpos;
			temp_endpos -=  Vector( "0 0 5" );
			cont = gi.pointcontents( temp_endpos, 0 );

			dirt = new Entity( ENTITY_CREATE_FLAG_ANIMATE );

			dirt->setOrigin( trace.endpos );

			temp_angles = vec_zero;

			if (cont & MASK_WATER)
				dirt->setModel( "fx_splashsmall.tik" );
			else
				dirt->setModel( "fx_dirtcloud.tik" );

			dirt->setAngles( temp_angles );

			dirt->animate->RandomAnimate( "idle" );

			dirt->PostEvent( EV_Remove, 5.0f );

			attack_origin = new_origin;

			if ( attack_origin == goal )
				{
				// Got to our goal position, do attack

				if ( stage == 1 )
					{
					SpawnArm( self, leg1, attack_origin + Vector( " 25  25 0" ), "attack1", 0.0f );
					SpawnArm( self, leg2, attack_origin + Vector( " 25 -25 0" ), "attack1", 0.0f );
					SpawnArm( self, leg3, attack_origin + Vector( "-25  25 0" ), "attack1", 0.0f );
					SpawnArm( self, leg4, attack_origin + Vector( "-25 -25 0" ), "attack1", 0.0f );
					}
				else if ( stage == 2 )
					{
					SpawnArm( self, leg1, attack_origin + Vector( " 25   0 0" ), "attack2",   0.0f );
					SpawnArm( self, leg2, attack_origin + Vector( "-25  25 0" ), "attack2", 120.0f );
					SpawnArm( self, leg3, attack_origin + Vector( "-25 -25 0" ), "attack2", 240.0f );
					}
				else
					{
					SpawnArm( self, leg1, attack_origin, "attack1", 0.0f );
					}

				burrow_mode = BURROW_MODE_ATTACK;
				}

			break;
		case BURROW_MODE_ATTACK :

			// Wait until all of the legs are done

			if ( !leg1 && !leg2 && !leg3 && !leg4 )
				{
				if ( self.animname != "idle_down" )
					self.SetAnim( "idle_down" );

				if ( ( stage == 1 ) || ( stage == 2 ) )
					{
					return BEHAVIOR_SUCCESS;
					}
				else
					{
					attacks_left--;

					if ( attacks_left > 0 )
						{
						if ( use_last_known_position )
							if ( self.sensoryPerception->CanSeeEntity( &self , currentEnemy , true , true ) )
								goal = currentEnemy->origin;
							else
								return BEHAVIOR_SUCCESS;
						else
							goal = currentEnemy->origin;

						burrow_mode = BURROW_MODE_MOVING;
						}
					else
						{
						return BEHAVIOR_SUCCESS;
						}
					}
				}

			break;
		}

	return BEHAVIOR_EVALUATING;
	}

void BurrowAttack::SpawnArm
	(
	Actor &self,
	EntityPtr &leg,
	const Vector &original_arm_origin,
	const char *anim_name,
	float angle
	)

	{
	Vector angles;
	trace_t trace;
	Vector start_pos;
	Vector end_pos;
	str anim_to_play;
	Entity *leg_animate_ptr;
	Vector dir;
	Entity *dirt;
	Vector arm_origin;


	// Find correct spot to spawn

	arm_origin = original_arm_origin;

	arm_origin[2] = -575.0f;

	start_pos = arm_origin + Vector( "0 0 64" );
	end_pos = arm_origin - Vector( "0 0 100" );

	//trace = G_Trace( start_pos, Vector(-5, -5, 0), Vector(5, 5, 0), end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack" );
	trace = G_Trace( start_pos, Vector(-10.0f, -10.0f, 0.0f), Vector(10.0f, 10.0f, 0.0f), end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack" );

	arm_origin = trace.endpos;

	// Make sure can spawn here

	end_pos = arm_origin + Vector( "0 0 50" );

	trace = G_Trace( arm_origin, Vector(-10.0f, -10.0f, 0.0f), Vector(10.0f, 10.0f, 0.0f), end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack" );

	if ( ( trace.fraction < 1.0f ) || trace.startsolid || trace.allsolid )
		{
		if ( trace.entityNum == ENTITYNUM_WORLD || !( trace.ent && trace.ent->entity && trace.ent->entity->takedamage ) )
			return;
		}

	// Spawn some dirt

	dirt = new Entity( ENTITY_CREATE_FLAG_ANIMATE );

	dirt->setOrigin( arm_origin );
	dirt->setModel( "fx_dirtcloud.tik" );
	dirt->setAngles( vec_zero );
	dirt->animate->RandomAnimate( "idle" );
	dirt->PostEvent( EV_Remove, 5.0f );

	// Spawn leg

	leg = new Entity( ENTITY_CREATE_FLAG_ANIMATE );

	leg->setModel( "vmama_arm.tik" );
	leg->setOrigin( arm_origin );

	leg->ProcessPendingEvents();

	//leg->edict->clipmask	= MASK_MONSTERSOLID;
	leg->setContents( 0 );
	leg->setSolidType( SOLID_NOT );

	leg->PostEvent( EV_BecomeNonSolid, 0.0f );

	angles = vec_zero;
	angles[YAW] = angle;

	leg->setAngles( angles );

	anim_to_play = anim_name;

	// See if we should get stuck or not

	if ( strcmp( anim_name, "attack1" ) == 0 )
		{
		end_pos = arm_origin + Vector( "0 0 250" );

		leg_animate_ptr = leg;

		trace = G_Trace( arm_origin, Vector(-5.0f, -5.0f, 0.0f), Vector(5.0f, 5.0f, 0.0f), end_pos, leg_animate_ptr, MASK_DEADSOLID, false, "BurrowAttack" );

		if ( trace.fraction != 1.0f )
			{
			if ( self.animname != "struggle" )
				self.SetAnim( "struggle" );

			anim_to_play = "getstuck";
			}
		}

	// Damage entities in way

	if ( strcmp( anim_name, "attack1" ) == 0 )
		{
		start_pos = arm_origin;
		end_pos = arm_origin + Vector( "0 0 250" );

		dir = Vector ( G_CRandom( 5.0f ), G_CRandom( 5.0f ), 10.0f );
		}
	else
		{
		start_pos = arm_origin + Vector( "0 0 10" );

		angles.AngleVectors( &dir );

		end_pos = start_pos + ( dir * 250.0f );
		}

	leg_animate_ptr = leg;

	MeleeAttack( start_pos, end_pos, 50.0f, &self, MOD_IMPALE, 10.0f, 0.0f, 0.0f, 100.0f );

	leg->animate->RandomAnimate( anim_to_play.c_str(), EV_Remove );
	}

void BurrowAttack::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  CircleEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, CircleEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&CircleEnemy::SetArgs },
		{ NULL, NULL }
	};

void CircleEnemy::SetArgs
	(
	Event *ev
	)

	{
	center_part_name = ev->GetString( 1 );
	}

void CircleEnemy::Begin
	(
	Actor &self
	)

	{
	ent_to_circle = self.enemyManager->GetCurrentEnemy();
	last_angle_change = 0;
	}

float CircleEnemy::GetAngleDiff
	(
	const Actor &self,
	const Actor *center_actor,
	const Vector &origin
	)

	{
	Vector dir;
	Vector enemy_angles;
	Vector actor_angles;
	float angle_diff;

	if ( !ent_to_circle )
		return 0.0f;

	dir = ent_to_circle->origin - center_actor->origin;
	enemy_angles = dir.toAngles();

	dir = origin - center_actor->origin;
	actor_angles = dir.toAngles();

	angle_diff = AngleDelta( actor_angles[YAW], enemy_angles[YAW] );

	return angle_diff;
	}

#define MAX_CIRCLE_ACCELERATION  .125
#define MAX_CIRCLE_VELOCITY  10

BehaviorReturnCode_t	CircleEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Actor *center_actor;
	Vector actor_angles;
	float angle_diff;
	float other_angle_diff;
	float abs_angle_diff;
	float other_abs_angle_diff = 180.0f;
	float angle_change = MAX_CIRCLE_VELOCITY;
	float length;
	float real_angle_change;
	Actor *other;


	if ( !ent_to_circle )
		return BEHAVIOR_SUCCESS;

	center_actor = self.FindPartActor( center_part_name.c_str() );

	if ( !center_actor )
		return BEHAVIOR_SUCCESS;

	angle_diff = GetAngleDiff( self, center_actor, self.origin );

	if ( angle_diff < 0.0f )
		abs_angle_diff = -angle_diff;
	else
		abs_angle_diff = angle_diff;

	other = self.FindPartActor( self.part_name );

	if ( other )
		{
		other_angle_diff = GetAngleDiff( self, center_actor, other->origin );

		if ( other_angle_diff < 0.0f )
			other_abs_angle_diff = -other_angle_diff;
		else
			other_abs_angle_diff = other_angle_diff;
		}

	if ( abs_angle_diff < other_abs_angle_diff )
		{
		// Turn towards enemy

		if ( abs_angle_diff < angle_change )
			angle_change = abs_angle_diff;

		if ( angle_diff < 0.0f )
			real_angle_change = angle_change;
		else
			real_angle_change = -angle_change;
		}
	else
		{
		// Turn away from enemy

		if ( 180.0f - abs_angle_diff < angle_change )
			angle_change = 180.0f - abs_angle_diff;

		if ( angle_diff < 0.0f )
			real_angle_change = -angle_change;
		else
			real_angle_change = angle_change;
		}

	if ( ( real_angle_change < 1.0f ) && ( real_angle_change > -1.0f ) )
		real_angle_change = 0.0f;

	if ( real_angle_change > 0.0f )
		{
		if ( real_angle_change > ( last_angle_change + MAX_CIRCLE_ACCELERATION ) )
			real_angle_change = last_angle_change + MAX_CIRCLE_ACCELERATION;
		}
	else if ( real_angle_change < 0.0f )
		{
		if ( real_angle_change < ( last_angle_change - MAX_CIRCLE_ACCELERATION ) )
			real_angle_change = last_angle_change - MAX_CIRCLE_ACCELERATION;
		}

	last_angle_change = real_angle_change;

	dir = self.origin - center_actor->origin;
	length = dir.length();

	actor_angles = dir.toAngles();
	actor_angles[YAW] += real_angle_change;

	// Find new position

	actor_angles.AngleVectors( &dir, NULL, NULL );

	dir *= length;
	dir.z = 0.0f;

	self.setOrigin( center_actor->origin + dir );

	// Set the actors angle to look at the center

	dir[0] = -dir[0];
	dir[1] = -dir[1];
	dir[2] = -dir[2];

	self.angles[YAW] = dir.toYaw();
	self.setAngles( self.angles );

	return BEHAVIOR_EVALUATING;
	}

void CircleEnemy::End
	(
	Actor &self
	)

	{
	}
/****************************************************************************

  CircleCurrentEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, CircleCurrentEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&CircleCurrentEnemy::SetArgs },
		{ NULL, NULL }
	};

void CircleCurrentEnemy::SetArgs
	(
	Event *ev
	)

	{
	anim = "walk";
	
	radius = 0;
	maintainDistance = true;
	clockwise = true;
	
	if (ev->NumArgs() > 0 )
		anim = ev->GetString( 1 );

	if (ev->NumArgs() > 1 )
		radius = ev->GetFloat( 2 );

	if (ev->NumArgs() > 2 )
		maintainDistance = ev->GetBoolean( 3 );

	if (ev->NumArgs() > 3 )
		clockwise = ev->GetBoolean( 4 );
	
	}

void CircleCurrentEnemy::Begin
	(
	Actor &self
	)

	{
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return;
	
	self.SetAnim(anim);
	dirToEnemy = self.origin - currentEnemy->origin;

	if(!radius)
		radius = dirToEnemy.length();
	
	stuck = 0;
	stuckCheck = 0;

	if (clockwise)
		{
		turnAngle = 90;
		}
	else
		turnAngle = -90;

	oldAngle = 0;
	angleAdjusted = false;
	}


BehaviorReturnCode_t	CircleCurrentEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector dirAngles;
	Vector Angles;

	float dirYaw;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	dirToEnemy = currentEnemy->origin - self.origin;
	dirYaw = dirToEnemy.toYaw();
	
	if(!stuck)
		{
		float len = dirToEnemy.length();
		if(len > radius && maintainDistance && !angleAdjusted)
			{
			oldAngle = turnAngle;
			turnAngle*=.5f;
			angleAdjusted = true;
			}

		if(len <= radius && angleAdjusted)
			{
			turnAngle = oldAngle;
			angleAdjusted = false;
			}
		}

	dirYaw+=turnAngle;

	self.angles[YAW] = dirYaw;

	if ( self.movementSubsystem->getLastMove() != STEPMOVE_OK ) 
      {
		if(stuck >= 2)
			{
			if(stuck < 3 )
				{
				turnAngle = -turnAngle;
				}
			else
				{
				self.angles[YAW] = dirYaw + angleStep;
				angleStep += 45.0f;
				}
			}

		stuck++;
      }
	
	stuckCheck++;
	if(stuckCheck > stuck)
		{
		stuckCheck = 0;
		stuck = 0;
		angleStep = 45.0f;
		}

	self.setAngles(self.angles);
		
	return BEHAVIOR_EVALUATING;
	}

void CircleCurrentEnemy::End
	(
	Actor &self
	)

	{
	
	}

/****************************************************************************

  ChaoticDodge Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, ChaoticDodge, NULL )
	{
		{ &EV_Behavior_Args,			&ChaoticDodge::SetArgs },
		{ NULL, NULL }
	};

void ChaoticDodge::SetArgs
	(
	Event *ev
	)

	{
	anim = "walk";
	stuck = 0;
	time = .5;
	changeTime = 0;
	turnspeed = 45;
	adjusting = false;
	turnAngle = 0;
	
	if (ev->NumArgs() > 0 )
		anim = ev->GetString( 1 );

	if (ev->NumArgs() > 1 )
		time = ev->GetFloat( 2 );

	if (ev->NumArgs() > 2 )
		turnspeed = ev->GetFloat( 3 );
	
	}

void ChaoticDodge::Begin
	(
	Actor &self
	)

	{
	self.SetAnim(anim);

	}


BehaviorReturnCode_t	ChaoticDodge::Evaluate
	(
	Actor &self
	)

	{

	float dirYaw = GetNewYaw();

	float CurrentYaw = self.origin.toYaw();
		
	if ( self.movementSubsystem->getLastMove() != STEPMOVE_OK ) 
      {
		stuck++;
		turnAngle += 30.0f;
		if (stuck > 3 )
			{
			self.angles[YAW]+=turnAngle;
			self.setAngles(self.angles);
			time=1;
			changeTime = level.time + time;
			stuck = 0;
			turnAngle = 0.0f;
			}
		}

	if ( level.time <= changeTime )
		return BEHAVIOR_EVALUATING;
	
	dirYaw+=CurrentYaw;

	self.angles[YAW] = dirYaw;
	self.setAngles(self.angles);	
	time = G_Random ( .15f ) +.15f;
	changeTime = level.time + time;
		
	return BEHAVIOR_EVALUATING;
	}

float ChaoticDodge::GetNewYaw
   (
	void
	)

	{
	float dirYaw = G_Random( 20.0f ) + turnspeed;
	float randomSide = G_Random();
		if (randomSide < .5f )
			randomSide = 1.0f;
		else
			randomSide = -1.0f;
	
	dirYaw*=randomSide;
	
	return dirYaw;
	}

void ChaoticDodge::End
	(
	Actor &self
	)

	{
	
	}
/****************************************************************************

  ShockWater Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, ShockWater, NULL )
	{
		{ NULL, NULL }
	};

ShockWater::ShockWater()
	{
	left_beam   = NULL;
	right_beam  = NULL;
	center_beam = NULL;
	already_started = false;
	}

void ShockWater::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	ShockWater::Evaluate
	(
	Actor &self
	)

	{
	Vector left_tag_orig;
	Vector right_tag_orig;
	Vector end_pos;
	Vector center_point;
	Actor *center_actor;
	trace_t  trace;
	Entity *hit_entity;
	Vector diff_vect;
	float diff;
	Vector dir;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	center_actor = self.FindPartActor( "body" );

	if ( !center_actor )
		return BEHAVIOR_SUCCESS;

	if ( ( self.newanimnum == -1 ) && !already_started )
		{
		// Get tag positions
		self.GetTag( "tag_left",  &left_tag_orig );
		self.GetTag( "tag_right", &right_tag_orig );

		// Get end position
		end_pos = left_tag_orig + right_tag_orig;
		end_pos *= .5f;
		end_pos[2] -= 120.0f;

		dir = end_pos - self.origin;
		dir.z = 0.0f;
		dir *= 0.5f;

		end_pos += dir;

		// Add the left and right beams
      left_beam   = CreateBeam( NULL, "emap1", left_tag_orig, end_pos, 10, 1.5f, 0.2f );
		right_beam  = CreateBeam( NULL, "emap1", right_tag_orig, end_pos, 10, 1.5f, 0.2f );

		center_point = center_actor->origin;

		trace = G_Trace( center_point, vec_zero, vec_zero, end_pos, &self, MASK_SHOT, false, "ShockAttack" );

		if ( ( trace.fraction < 1.0f ) && ( trace.entityNum != center_actor->entnum ) )
			{
			hit_entity = G_GetEntity( trace.entityNum );
			if ( hit_entity )
            {
				center_point = hit_entity->origin;
            }
			}
		else
			{
			// Shock head
			center_actor->AddStateFlag( STATE_FLAG_IN_PAIN );

			center_actor->SpawnEffect( "fx_elecstrike.tik", center_actor->origin, vec_zero, 2.0f );
			center_actor->Sound( "sound/weapons/sword/electric/hitmix2.wav", 0, 1.0f, 500.0f );
			}

      // create the center beam
      center_beam = CreateBeam( NULL, "emap1", end_pos, center_point, 20, 3.0f, 0.2f );

		// Damage player if in water
	
		diff_vect = currentEnemy->origin - center_actor->origin;
		diff_vect[2] = 0.0f;

		diff = diff_vect.length();
		//if ( diff < 240 && self.currentEnemy->groundentity )
		if ( ( diff < 350.0f ) && currentEnemy->groundentity )
			{
			currentEnemy->Damage( &self, &self, 10, Vector (0.0f, 0.0f, 0.0f), Vector (0.0f, 0.0f, 0.0f), Vector (0.0f, 0.0f, 0.0f), 0, 0, MOD_ELECTRICWATER );
			}

		already_started = true;
		}

	return BEHAVIOR_EVALUATING;
	}

void ShockWater::End
	(
	Actor &self
	)

	{
   delete left_beam;
	delete right_beam;
	delete center_beam;
	}

/****************************************************************************

  Shock Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Shock, NULL )
	{
		{ &EV_Behavior_Args,			&Shock::SetArgs },
		{ NULL, NULL }
	};

Shock::Shock()
	{
	beam = NULL;
	damage = 10;
	already_started = false;
	random_angle = 0;
	beamShader = "emap1";
	z_offset = 100;
	}

void Shock::SetArgs
	(
	Event *ev
	)

	{
	tag_name = ev->GetString( 1 );
	beamShader = ev->GetString( 2 );

	if ( ev->NumArgs() > 3 )
      {
		damage = ev->GetInteger( 3 );
      }

	if ( ev->NumArgs() > 3 )
      {
		random_angle = ev->GetFloat( 4 );
      }
	
	if ( ev->NumArgs() > 4 )
		z_offset = ev->GetFloat( 5 );
	}

void Shock::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	Shock::Evaluate
	(
	Actor &self
	)

	{
	Vector tag_orig;
	Vector angles;
	Vector end_pos;
	trace_t  trace;
	Vector dir;
	float yaw_diff;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( ( self.newanimnum == -1 ) && !already_started )
		{
		// Get tag position
		if ( tag_name.length() == 0 )
         {
			return BEHAVIOR_SUCCESS;
         }

		self.GetTag( tag_name.c_str(), &tag_orig );

		// See if the enemy is in front of us

		dir = currentEnemy->centroid - self.centroid;
		angles = dir.toAngles();

		yaw_diff = AngleNormalize180( angles[YAW] - self.angles[YAW] );

		//if ( ( yaw_diff < 60.0f ) && ( yaw_diff > -60.0f ) )
		//	{
			// The enemy is in front of us

			angles[YAW] += G_CRandom( random_angle );

			angles.AngleVectors( &end_pos, NULL, NULL );
			end_pos *= 500.0f;
			end_pos += tag_orig;
			end_pos.z -= z_offset;
		//	}
      /*
		else
			{
			// Get end position
			angles = self.angles;

			angles[YAW] += G_Random( random_angle ) - ( random_angle / 2.0f );
			angles[PITCH] = 0.0f;
			angles[ROLL] = 0.0f;

			angles.AngleVectors( &end_pos, NULL, NULL );
			end_pos *= 500.0f;
			end_pos += tag_orig;
			end_pos.z -= z_offset;
			}
      */
		trace = G_Trace( tag_orig, Vector (-15.0f, -15.0f, -15.0f), Vector (15.0f, 15.0f, 15.0f), end_pos, &self, MASK_SHOT, false, "ShockAttack" );

		if ( ( trace.fraction < 1.0f ) && ( trace.entityNum == currentEnemy->entnum ) )
			{
			end_pos = currentEnemy->centroid;
			dir = end_pos - tag_orig;
			dir.normalize();
			currentEnemy->Damage( &self, &self, damage, vec_zero, dir, vec_zero, 0, 0, MOD_ELECTRIC );
			}

		// Add the beam
		beam = CreateBeam( NULL, beamShader.c_str(), tag_orig, end_pos, 2, 1.5f, 0.25f );

      already_started = true;
		}
	else if ( already_started )
		{
		self.GetTag( tag_name.c_str(), &tag_orig );
      if ( beam )
         beam->setOrigin( tag_orig );         
		}

	return BEHAVIOR_EVALUATING;
	}

void Shock::End
	(
	Actor &self
	)

	{
	if ( beam )
		{
		beam->ProcessEvent( EV_Remove );
		beam = NULL;
		}
	}

/****************************************************************************

  MultiShock Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, MultiShock, NULL )
	{
		{ &EV_Behavior_Args,			&MultiShock::SetArgs },
		{ NULL, NULL }
	};

MultiShock::MultiShock()
	{
	beam1 = NULL;
	beam2 = NULL;
	damage = 10;
	already_started = false;
	random_angle = 0;
	beamShader = "emap1";
	z_offset = 100;
	}

void MultiShock::SetArgs
	(
	Event *ev
	)

	{
	tag_name1 = ev->GetString( 1 );
	tag_name2 = ev->GetString( 2 );
	beamShader = ev->GetString( 3 );
	damage = ev->GetFloat( 4 );
	random_angle = ev->GetFloat( 5 );
	z_offset = ev->GetFloat( 6 );
	}
	

void MultiShock::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	MultiShock::Evaluate
	(
	Actor &self
	)

	{
	Vector tag1_orig;
	Vector tag2_orig;

	Vector angles;
	Vector end_pos1;
	Vector end_pos2;

	trace_t  trace;
	Vector dir;
	float yaw_diff;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;
	
	//if ( self.newanimnum == -1 && !already_started )
	if ( !already_started )
		{
		// Get tag position
		if ( tag_name1.length() == 0 )
			return BEHAVIOR_SUCCESS;
         
		if ( tag_name2.length() == 0 )
			return BEHAVIOR_SUCCESS;

		self.GetTag( tag_name1.c_str(), &tag1_orig );
		self.GetTag( tag_name2.c_str(), &tag2_orig );

		// See if the enemy is in front of us

		dir = currentEnemy->origin - self.origin;
		angles = dir.toAngles();

		yaw_diff = AngleNormalize180( angles[YAW] - self.angles[YAW] );

		if ( ( yaw_diff < 60.0f ) && ( yaw_diff > -60.0f ) )
			{
			// The enemy is in front of us

			angles[YAW] += G_CRandom( random_angle );

			angles.AngleVectors( &end_pos1, NULL, NULL );
			end_pos1 *= 500.0f;
			end_pos1 += tag1_orig;
			end_pos1.z -= z_offset;

			angles.AngleVectors( &end_pos2, NULL, NULL );
			end_pos2 *= 500.0f;
			end_pos2 += tag1_orig;
			end_pos2.z -= z_offset;
			}
		else
			{
			// Get end position
			angles = self.angles;

			angles[YAW] += G_Random( random_angle ) - ( random_angle / 2.0f );
			angles[PITCH] = 0.0f;
			angles[ROLL] = 0.0f;

			angles.AngleVectors( &end_pos1, NULL, NULL );
			end_pos1 *= 500.0f;
			end_pos1 += tag1_orig;
			end_pos1.z -= z_offset;
			
			angles.AngleVectors( &end_pos2, NULL, NULL );
			end_pos2 *= 500.0f;
			end_pos2 += tag1_orig;
			end_pos2.z -= z_offset;
			}

		trace = G_Trace( tag1_orig, Vector (-15.0f, -15.0f, -15.0f), Vector (15.0f, 15.0f, 15.0f), end_pos1, &self, MASK_SHOT, false, "ShockAttack" );

		if ( ( trace.fraction < 1.0f ) && ( trace.entityNum == currentEnemy->entnum ) )
			{
			end_pos1 = currentEnemy->centroid;
			dir = end_pos1 - tag1_orig;
			dir.normalize();
			currentEnemy->Damage( &self, &self, damage, vec_zero, dir, vec_zero, 0, 0, MOD_ELECTRIC );
			}

		// Add the beam
		beam1 = CreateBeam( NULL, beamShader.c_str(), tag1_orig, end_pos1, 20, 1.5f, 0.2f );

		trace = G_Trace( tag2_orig, Vector (-15.0f, -15.0f, -15.0f), Vector (15.0f, 15.0f, 15.0f), end_pos2, &self, MASK_SHOT, false, "ShockAttack" );

		if ( ( trace.fraction < 1.0f ) && ( trace.entityNum == currentEnemy->entnum ) )
			{
			end_pos2 = currentEnemy->centroid;
			dir = end_pos2 - tag2_orig;
			dir.normalize();
			currentEnemy->Damage( &self, &self, damage, vec_zero, dir, vec_zero, 0, 0, MOD_ELECTRIC );
			}

		// Add the beam
		beam2 = CreateBeam( NULL, beamShader.c_str(), tag2_orig, end_pos2, 20, 1.5f, 0.2f );

      already_started = true;
		}
	else
		{
		self.GetTag( tag_name1.c_str(), &tag1_orig );
		self.GetTag( tag_name2.c_str(), &tag2_orig );

		if ( beam1 )
			beam1->setOrigin( tag1_orig );

		if ( beam2 )
			beam2->setOrigin( tag2_orig );
		}

	return BEHAVIOR_EVALUATING;
	}

void MultiShock::End
	(
	Actor &self
	)

	{
	if ( beam1 )
		{
		beam1->ProcessEvent( EV_Remove );
		beam1 = NULL;
		}
	
	if ( beam2 )
		{
		beam2->ProcessEvent( EV_Remove );
		beam2 = NULL;
		}
	}

/****************************************************************************

  ShockDown Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, ShockDown, NULL )
	{
		{ &EV_Behavior_Args,			&ShockDown::SetArgs },
		{ NULL, NULL }
	};

ShockDown::ShockDown()
	{
	beam = NULL;
	damage = 10;
	already_started = false;	
	beamShader = "emap1";	
	}

void ShockDown::SetArgs
	(
	Event *ev
	)

	{
	tag_name = ev->GetString( 1 );
	beamShader = ev->GetString( 2 );

	if ( ev->NumArgs() > 3 )
      {
		damage = ev->GetInteger( 3 );
      }

	}

void ShockDown::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	ShockDown::Evaluate
	(
	Actor &self
	)

	{
	Vector tag_orig;
	Vector angles;
	Vector end_pos;
	trace_t  trace;
	Vector dir;
	

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( ( self.newanimnum == -1 ) && !already_started )
		{
		// Get tag position
		if ( tag_name.length() == 0 )
         {
			return BEHAVIOR_SUCCESS;
         }

		self.GetTag( tag_name.c_str(), &tag_orig );

		end_pos = self.origin;
		end_pos.z -= 10000.0f;
		
		trace = G_Trace( tag_orig, Vector (-15.0f, -15.0f, -15.0f), Vector (15.0f, 15.0f, 15.0f), end_pos, &self, MASK_SHOT, false, "ShockAttack" );
		end_pos = trace.endpos;

		dir = end_pos - tag_orig;
		angles = dir.toAngles();

		if ( ( trace.fraction < 1.0f ) && ( trace.entityNum == currentEnemy->entnum ) )
			{
			end_pos = currentEnemy->centroid;
			dir = end_pos - tag_orig;
			dir.normalize();
			currentEnemy->Damage( &self, &self, damage, vec_zero, dir, vec_zero, 0, 0, MOD_ELECTRIC );
			}

		// Add the beam
		beam = CreateBeam( NULL, beamShader.c_str(), tag_orig, end_pos, 20, 1.5f, 0.2f );

      already_started = true;
		}
	else if ( already_started )
		{
		self.GetTag( tag_name.c_str(), &tag_orig );

		if ( beam )
			beam->setOrigin( tag_orig );
		}

	return BEHAVIOR_EVALUATING;
	}

void ShockDown::End
	(
	Actor &self
	)

	{
	if ( beam )
		{
		beam->ProcessEvent( EV_Remove );
		beam = NULL;
		}
	}
/****************************************************************************

  CircleAttack Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, CircleAttack, NULL )
	{
		{ &EV_Behavior_Args,			&CircleAttack::SetArgs },
		{ NULL, NULL }
	};

CircleAttack::CircleAttack()
	{
	next_time = 0.0f;
	current_direction = 1;
	number_of_attacks = 1;
	}

void CircleAttack::SetArgs
	(
	Event *ev
	)

	{
	command   = ev->GetString( 1 );
	direction = ev->GetString( 2 );
	}

Actor *CircleAttack::FindClosestPart
	(
	const Actor &self,
	float angle
	)
	{
	float closest_diff = 360.0f;
	int i;
	part_t *part;
	Entity *partent;
	Actor *partact;
	Vector dir;
	Vector angles;
	float angle_diff;
	Actor *closest_part = NULL;

	for( i = 1 ; i <= self.parts.NumObjects(); i++ )
		{
		part = &self.parts.ObjectAt( i );

		partent = part->ent;
		partact = ( Actor * )partent;

		if ( partact && ( partact->part_name == "smallarm" ) )
			{
			dir = partact->origin - self.origin;
			angles = dir.toAngles();

			angle_diff = AngleDelta( angles[ YAW ], angle );

			if ( angle_diff < 0.0f )
            {
				angle_diff = -angle_diff;
            }

			if ( angle_diff < closest_diff )
				{
				closest_part = partact;
				closest_diff = angle_diff;
				}
			}
		}

	return closest_part;
	}

void CircleAttack::Begin
	(
	Actor &self
	)

	{
	float random_direction;
	Actor *closest_part;

	// Pick which arm to start with
	random_direction = G_Random( 360.0f );

	closest_part = FindClosestPart( self, random_direction );
	if ( closest_part != NULL )
		{
		first_part   = closest_part;
		current_part = closest_part;

		closest_part->command = command;
		next_time = level.time + 0.2f;
		}

	current_direction = 1;

	if ( direction == "counterclockwise" )
      {
		current_direction = 0;
      }
	}

BehaviorReturnCode_t	CircleAttack::Evaluate
	(
	Actor &self
	)

	{
	Entity *current_part_entity;
	Actor *current_part_actor;
	Vector dir;
	Vector angles;
	Actor *closest_part;

	if ( level.time >= next_time )
		{
		current_part_entity = current_part;
		current_part_actor = ( Actor * )current_part_entity;

		// Find the next part

		dir = current_part_actor->origin - self.origin;
		angles = dir.toAngles();

		if ( direction == "changing" )
			{
			if ( number_of_attacks >= 20 )
            {
				return BEHAVIOR_SUCCESS;
            }

			if ( G_Random( 1.0f ) < .3f )
            {
				current_direction = !current_direction;
            }
			}

		if ( current_direction == 1 )
         {
			angles[YAW] -= 360.0f / 8.0f;
         }
		else
         {
			angles[YAW] += 360.0f / 8.0f;
         }

		closest_part = FindClosestPart( self, angles[YAW] );

		if ( ( closest_part == first_part ) && ( direction != "changing" ) )
         {
			return BEHAVIOR_SUCCESS;
         }

		current_part = closest_part;

		closest_part->command = command;
		next_time = level.time + 0.2f;

		number_of_attacks++;
		}

	return BEHAVIOR_EVALUATING;
	}

void CircleAttack::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  DragEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, DragEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&DragEnemy::SetArgs },
		{ NULL, NULL }
	};

void DragEnemy::SetArgs
	(
	Event *ev
	)

	{
	tag_name = ev->GetString( 1 );
	damage   = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		drop = ev->GetBoolean( 3 );
	else
		drop = false;
	}

void DragEnemy::Begin
	(
	Actor &self
	)

	{
	Actor *body;
	Vector dir;
	Vector angles;

	ent_to_drag = self.enemyManager->GetCurrentEnemy();

	if ( !ent_to_drag )
		return;

	attached = false;

	if ( damage > 0.0f && !drop )
      {
		ent_to_drag->Damage( &self, &self, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_EAT );
      }

	body = self.FindPartActor( "body" );

	if ( body )
		{
		dir = body->origin - self.origin;
		angles = dir.toAngles();

		target_yaw = angles[ YAW ];
		last_turn_time = level.time;
		}
	else
		{
		target_yaw = self.angles[ YAW ];
		}
	}

BehaviorReturnCode_t	DragEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector orig;
	str anim_name;

	if ( !ent_to_drag )
		return BEHAVIOR_SUCCESS;

	if ( drop && ( damage > 0.0f ) )
		{
		if ( self.GetTag( tag_name.c_str(), &orig ) )
			{
			if ( ent_to_drag->isClient() )
            {
				orig[ 2 ] -= 85.0f;
            }
			else
				{
				offset[ 2 ] = ( ent_to_drag->absmin[ 2 ] - ent_to_drag->absmax[ 2 ] ) * 0.5f;

				if ( offset[ 2 ] < -40.0f )
               {
					offset[ 2 ] -= 25.0f;
               }
				orig += offset;
				}

			ent_to_drag->setOrigin( orig );
			}

		ent_to_drag->Damage( &self, &self, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_EAT );
		}

	if ( ent_to_drag->deadflag )
		return BEHAVIOR_SUCCESS;

	anim_name = self.animate->AnimName();

	if ( ( anim_name == "raise" ) && ( self.newanim == "" ) )
		{
		if ( !attached )
			{
			Event *ev;

			if ( damage > 0.0f )
				{
				if ( ent_to_drag->isClient() )
               {
					offset[ 2 ] -= 85.0f;
               }
				else
					{
					offset[ 2 ] = ( ent_to_drag->absmin[ 2 ] - ent_to_drag->absmax[ 2 ] ) * 0.5f;

					if ( offset[ 2 ] < -40.0f )
                  {
						offset[ 2 ] -= 25.0f;
                  }
					}

				ev = new Event( EV_Attach );
				ev->AddEntity( &self );
				ev->AddString( tag_name.c_str() );
				ev->AddInteger( false );
				ev->AddVector( offset );
				ent_to_drag->ProcessEvent( ev );

				ent_to_drag->flags |= FL_PARTIAL_IMMOBILE;
				}

			attached = true;
			}

		if ( target_yaw != self.angles[ YAW ] )
			{
			float yaw_diff = target_yaw - self.angles[ YAW ];

			if ( yaw_diff > 180.0f )
				{
				target_yaw -= 360.0f;
				yaw_diff -= 360.0f;
				}

			if ( yaw_diff < -180.0f )
				{
				target_yaw += 360.0f;
				yaw_diff += 360.0f;
				}

			if ( yaw_diff < 0.0f )
				{
				self.angles[ YAW ] -= 90.0f * (level.time - last_turn_time);

				if ( self.angles[ YAW ] < 0.0f )
               {
					self.angles[ YAW ] += 360.0f;
               }

				if ( self.angles[ YAW ] < target_yaw )
               {
					self.angles[ YAW ] = target_yaw;
               }

				self.setAngles( self.angles );
				}
			else if ( yaw_diff > 0.0f )
				{
				self.angles[ YAW ] += 90.0f * (level.time - last_turn_time);

				if ( self.angles[ YAW ] > 360.0f )
               {
					self.angles[ YAW ] -= 360.0f;
               }

				if ( self.angles[ YAW ] > target_yaw )
               {
					self.angles[ YAW ] = target_yaw;
               }

				self.setAngles( self.angles );
				}

			last_turn_time = level.time;
			}
		}

	return BEHAVIOR_EVALUATING;
	}

void DragEnemy::End
	(
	Actor &self
	)

	{
	Vector orig;
	Event *ev;
	trace_t trace;


	if ( !ent_to_drag )
		return;

	if ( drop || ( strcmp( self.currentState->getName(), "SUICIDE" ) == 0 ) )
		{
		ent_to_drag->flags &= ~FL_PARTIAL_IMMOBILE;

		ev = new Event( EV_Detach );
		ent_to_drag->ProcessEvent( ev );

		ent_to_drag->setSolidType( SOLID_BBOX );

		if ( self.GetTag( tag_name.c_str(), &orig ) )
			{
			trace = G_Trace( orig - Vector( "0 0 100" ), ent_to_drag->mins, ent_to_drag->maxs, orig, ent_to_drag, ent_to_drag->edict->clipmask, false, "DragEnemy" );

			if ( trace.allsolid )
				gi.WDPrintf( "Dropping entity into a solid!\n" );

			ent_to_drag->setOrigin( trace.endpos );

			/* if ( ent_to_drag->isClient() )
            {
				offset[2] = -85;
            }
			else
				{
				offset[2] = ( ent_to_drag->absmin[2] - ent_to_drag->absmax[2] ) * 0.5;

				if ( offset[2] < -40 )
               {
					offset[2] -= 25;
               }
				}

			ent_to_drag->setOrigin( orig + offset ); */
			}
		}

	ent_to_drag->velocity = Vector(0, 0, -20);
	}


/****************************************************************************

  PickupEnemy Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, PickupEnemy, NULL )
	{
		{ &EV_Behavior_Args,			&PickupEnemy::SetArgs },
		{ NULL, NULL }
	};

void PickupEnemy::SetArgs
	(
	Event *ev
	)

	{
	tag_name = ev->GetString( 1 );
	damage   = ev->GetFloat( 2 );

	if ( ev->NumArgs() > 2 )
		drop = ev->GetBoolean( 3 );
	else
		drop = false;
	}

void PickupEnemy::Begin
	(
	Actor &self
	)

	{
	Actor *body;
	Vector dir;
	Vector angles;

	ent_to_drag = self.enemyManager->GetCurrentEnemy();

	if ( !ent_to_drag )
		return;

	attached = false;

	if ( ( damage > 0.0f ) && !drop )
      {
		ent_to_drag->Damage( &self, &self, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_EAT );
      }

	body = self.FindPartActor( "body" );

	if ( body )
		{
		dir = body->origin - self.origin;
		angles = dir.toAngles();

		target_yaw = angles[ YAW ];
		last_turn_time = level.time;
		}
	else
		{
		target_yaw = self.angles[ YAW ];
		}
	}

BehaviorReturnCode_t	PickupEnemy::Evaluate
	(
	Actor &self
	)

	{
	Vector orig;
	str anim_name;

	if ( !ent_to_drag )
		return BEHAVIOR_SUCCESS;

	if ( drop && ( damage > 0.0f ) )
		{
		if ( self.GetTag( tag_name.c_str(), &orig ) )
			{
			if ( ent_to_drag->isClient() )
            {
				orig[ 2 ] -= 85.0f;
            }
			else
				{
				offset[ 2 ] = ( ent_to_drag->absmin[ 2 ] - ent_to_drag->absmax[ 2 ] ) * 0.5f;

				if ( offset[ 2 ] < -40.0f )
               {
					offset[ 2 ] -= 25.0f;
               }
				orig += offset;
				}

			ent_to_drag->setOrigin( orig );
			}

		ent_to_drag->Damage( &self, &self, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_EAT );
		}

	if ( ent_to_drag->deadflag )
		return BEHAVIOR_SUCCESS;

	anim_name = self.animate->AnimName();

	if ( !attached )
		{
		Event *ev;

		if ( damage > 0.0f )
			{
			if ( ent_to_drag->isClient() )
            {
				offset[ 2 ] -= 85.0f;
            }
			else
				{
				offset[ 2 ] = ( ent_to_drag->absmin[ 2 ] - ent_to_drag->absmax[ 2 ] ) * 0.5f;

				if ( offset[ 2 ] < -40.0f )
               {
			      offset[ 2 ] -= 25.0f;
               }
				}

			ev = new Event( EV_Attach );
			ev->AddEntity( &self );
			ev->AddString( tag_name.c_str() );
			ev->AddInteger( false );
			ev->AddVector( offset );
			ent_to_drag->ProcessEvent( ev );

			ent_to_drag->flags |= FL_PARTIAL_IMMOBILE;
			}

		attached = true;
		}

	if ( target_yaw != self.angles[ YAW ] )
		{
		float yaw_diff = target_yaw - self.angles[ YAW ];

		if ( yaw_diff > 180.0f )
			{
			target_yaw -= 360.0f;
			yaw_diff -= 360.0f;
			}

		if ( yaw_diff < -180.0f )
			{
			target_yaw += 360.0f;
			yaw_diff += 360.0f;
			}

		if ( yaw_diff < 0.0f )
			{
			self.angles[ YAW ] -= 90.0f * (level.time - last_turn_time);

			if ( self.angles[ YAW ] < 0.0f )
            {
				self.angles[ YAW ] += 360.0f;
            }

			if ( self.angles[ YAW ] < target_yaw )
            {
				self.angles[ YAW ] = target_yaw;
            }

			self.setAngles( self.angles );
			}
		else if ( yaw_diff > 0.0f )
			{
			self.angles[ YAW ] += 90.0f * (level.time - last_turn_time);

			if ( self.angles[ YAW ] > 360.0f )
            {
				self.angles[ YAW ] -= 360.0f;
            }

			if ( self.angles[ YAW ] > target_yaw )
            {
				self.angles[ YAW ] = target_yaw;
            }

			self.setAngles( self.angles );
			}

		last_turn_time = level.time;
		}

	return BEHAVIOR_EVALUATING;
	}

void PickupEnemy::End
	(
	Actor &self
	)

	{
	Vector orig;
	Event *ev;
	trace_t trace;


	if ( !ent_to_drag )
		return;

	if ( drop || ( strcmp( self.currentState->getName(), "SUICIDE" ) == 0 ) )
		{
		ent_to_drag->flags &= ~FL_PARTIAL_IMMOBILE;

		ev = new Event( EV_Detach );
		ent_to_drag->ProcessEvent( ev );

		ent_to_drag->setSolidType( SOLID_BBOX );

		if ( self.GetTag( tag_name.c_str(), &orig ) )
			{
			trace = G_Trace( orig - Vector( "0 0 100" ), ent_to_drag->mins, ent_to_drag->maxs, orig, ent_to_drag, ent_to_drag->edict->clipmask, false, "DragEnemy" );

			if ( trace.allsolid )
				gi.WDPrintf( "Dropping entity into a solid!\n" );

			ent_to_drag->setOrigin( trace.endpos );

			/* if ( ent_to_drag->isClient() )
            {
				offset[2] = -85;
            }
			else
				{
				offset[2] = ( ent_to_drag->absmin[2] - ent_to_drag->absmax[2] ) * 0.5;

				if ( offset[2] < -40 )
               {
					offset[2] -= 25;
               }
				}

			ent_to_drag->setOrigin( orig + offset ); */
			}
		}

	ent_to_drag->velocity = Vector(0, 0, -20);
	}

/****************************************************************************

  Teleport Class Definition

****************************************************************************/

#define TELEPORT_BEHIND   0
#define TELEPORT_TOLEFT   1
#define TELEPORT_TORIGHT  2
#define TELEPORT_INFRONT  3

#define TELEPORT_NUMBER_OF_POSITIONS  4

CLASS_DECLARATION( Behavior, Teleport, NULL )
	{
		{ NULL, NULL }
	};


void Teleport::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void Teleport::Begin
	(
	Actor &self
	)

	{

	}

qboolean	Teleport::TestPosition
	(
	Actor &self,
	int test_pos,
	Vector &good_position,
	qboolean	use_enemy_dir
	)
	{
	Vector test_position;
	Vector enemy_angles;
	Vector enemy_forward;
	Vector enemy_left;
	trace_t trace;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return false;

	// Get the position to test

	if ( use_enemy_dir )
		{
		// Get the enemy direction info

		enemy_angles = currentEnemy->angles;
		enemy_angles.AngleVectors( &enemy_forward, &enemy_left );

		test_position = currentEnemy->origin;

		if ( test_pos == TELEPORT_BEHIND )
			test_position -= enemy_forward * 135.0f;
		else if ( test_pos == TELEPORT_INFRONT )
			test_position += enemy_forward * 135.0f;
		else if ( test_pos == TELEPORT_TOLEFT )
			test_position += enemy_left * 135.0f;
		else
			test_position -= enemy_left * 135.0f;
		}
	else
		{
		test_position = currentEnemy->origin;

		if ( test_pos == TELEPORT_BEHIND )
			test_position += Vector(-110, 0, 0);
		else if ( test_pos == TELEPORT_INFRONT )
			test_position += Vector(110, 0, 0);
		else if ( test_pos == TELEPORT_TOLEFT )
			test_position += Vector(0, -110, 0);
		else
			test_position += Vector(0, 110, 0);
		}

	test_position += Vector(0, 0, 64);

	// Test to see if we can fit at the new position

	trace = G_Trace( test_position, self.mins, self.maxs, test_position - Vector( "0 0 1000" ), &self, self.edict->clipmask, false, "Teleport::TestPosition" );

	if ( trace.allsolid || trace.startsolid )
	//if ( trace.allsolid )
		return false;

	// Make sure we can see the enemy from this position

	if ( !self.IsEntityAlive( currentEnemy ) || !self.sensoryPerception->CanSeeEntity( Vector( trace.endpos ), currentEnemy , true , true ) )			
			return false;
	
	
	// This is a good position

	good_position = trace.endpos;
	return true;
	}

BehaviorReturnCode_t	Teleport::Evaluate
	(
	Actor &self
	)

	{
	int current_position;
	float random_number;
	Vector teleport_position;
	qboolean teleport_position_found;
	Vector new_position;
	int i;
	Vector dir;
	Vector angles;


	// Make sure we stll have an enemy to teleport near

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	// Default the teleport position to where we are now

	teleport_position = self.origin;
	teleport_position_found = false;

	// Determine which position to try first

	random_number = G_Random();

	if ( random_number < .5f )
		current_position = TELEPORT_BEHIND;
	else if ( random_number < .7f )
		current_position = TELEPORT_TOLEFT;
	else if ( random_number < .9f )
		current_position = TELEPORT_TORIGHT;
	else
		current_position = TELEPORT_INFRONT;

	// Try positions

	for( i = 0 ; i < TELEPORT_NUMBER_OF_POSITIONS ; i++ )
		{
		// Test this position

		if ( TestPosition( self, current_position, new_position, true ) )
			{
			teleport_position = new_position;
			teleport_position_found = true;
			break;
			}

		// Try the next position

		current_position++;

		if ( current_position >= TELEPORT_NUMBER_OF_POSITIONS )
			current_position = 0;
		}

	if ( !teleport_position_found )
		{
		// Try again with not using the enemies angles

		if ( current_position >= TELEPORT_NUMBER_OF_POSITIONS )
			current_position = 0;

		for( i = 0 ; i < TELEPORT_NUMBER_OF_POSITIONS ; i++ )
			{
			// Test this position

			if ( TestPosition( self, current_position, new_position, false ) )
				{
				teleport_position = new_position;
				teleport_position_found = true;
				break;
				}

			// Try the next position

			current_position++;

			if ( current_position >= TELEPORT_NUMBER_OF_POSITIONS )
				current_position = 0;
			}
		}

	// Do teleport stuff

	if ( teleport_position_found )
		{
		self.setOrigin( teleport_position );
		self.NoLerpThisFrame();

		dir = currentEnemy->origin - teleport_position;
		angles = dir.toAngles();

		angles[ROLL] = 0;
		angles[PITCH] = 0;

		self.setAngles( angles );
		}

	return BEHAVIOR_SUCCESS;
	}

void Teleport::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  TeleportToPlayer Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, TeleportToPlayer, NULL )
	{
		{ NULL, NULL }
	};


void TeleportToPlayer::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void TeleportToPlayer::Begin
	(
	Actor &self
	)

	{

	}

qboolean	TeleportToPlayer::TestPosition
	(
	Actor &self,
	int test_pos,
	Vector &good_position,
	Entity* player,
	qboolean	use_player_dir
	)
	{
	Vector test_position;
	Vector player_angles;
	Vector player_forward;
	Vector player_left;
	trace_t trace;


	// Get the position to test
	test_position = player->origin;
	
	if ( use_player_dir )
		{
		// Get the player direction info

		player_angles = player->angles;
		player_angles.AngleVectors( &player_forward, &player_left );
		
		// Check Behind the Player
		test_position -= player_forward * 75.0f;
		}
	else
		{
		
		// Check Behind the Player
		test_position += Vector(-60, 0, 0);
		}

	// Final Tweaking
	test_position += Vector(0, 0, 64);

	// Test to see if we can fit at the new position

	trace = G_Trace( test_position, self.mins, self.maxs, test_position - Vector( "0 0 250" ), &self, self.edict->clipmask, false, "Teleport::TestPosition" );

	if ( trace.allsolid || trace.startsolid )
		return false;

   if ( trace.fraction == 1.0 )
      return false;

	// Make sure we can see the Player from this position
   
	if ( !self.IsEntityAlive( player ) || !self.sensoryPerception->CanSeeEntity( Vector( trace.endpos ), player , true , true ) )
			return false;


	// This is a good position

	good_position = trace.endpos;
	return true;
	}

BehaviorReturnCode_t	TeleportToPlayer::Evaluate
	(
	Actor &self
	)

	{
	int current_position;
	Vector teleport_position;
	qboolean teleport_position_found;
	Vector new_position;
	int i;
	Vector dir;
	Vector angles;
	
	Player *player = NULL;
	Player *temp_player = NULL;
	// Make sure the player is alive and well
	for(i = 0; i < game.maxclients; i++)
		{
		player = GetPlayer(i);		
		
		// don't target while player is not in the game or he's in notarget
		if ( temp_player && !( temp_player->flags & FL_NOTARGET ) )
			{
			player = temp_player;
			break;
			}
		}

	if ( !player )
		return BEHAVIOR_SUCCESS;
	
	// Default the teleport position to where we are now

	teleport_position = self.origin;
	teleport_position_found = false;

	// Always teleport BEHIND the player - - we don't want him to see us pop in.
	current_position = TELEPORT_BEHIND;

	// Test this position
	if ( TestPosition( self, current_position, new_position, player, true ) )
		{
		teleport_position = new_position;
		teleport_position_found = true;
		}
	else
		{
			if ( TestPosition( self, current_position, new_position, player, false ) )
				{
				teleport_position = new_position;
				teleport_position_found = true;
				}
		}

	// Do teleport stuff
	if ( teleport_position_found )
		{
		self.setOrigin( teleport_position );
		self.NoLerpThisFrame();

		dir = player->origin - teleport_position;
		angles = dir.toAngles();

		angles[ROLL] = 0.0f;
		angles[PITCH] = 0.0f;

		self.setAngles( angles );
		}

	return BEHAVIOR_SUCCESS;
	}

void TeleportToPlayer::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  TeleportToPosition Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, TeleportToPosition, NULL )
	{
		{ &EV_Behavior_Args,			&TeleportToPosition::SetArgs },
		{ NULL, NULL }
	};

void TeleportToPosition::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void TeleportToPosition::SetArgs
	(
	Event *ev
	)

	{
	teleport_position_name = ev->GetString( 1 );
	number_of_teleport_positions = ev->GetInteger( 2 );
	}

void TeleportToPosition::Begin
	(
	Actor &self
	)

	{
	}

BehaviorReturnCode_t	TeleportToPosition::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	Vector angles;
	trace_t trace;
	str pathnode_name;
	PathNode *goal;
	Vector teleport_position;
	Vector attack_position;
	float half_height;
	//Entity *effect;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();


	// Get the pathnode name to teleport to

	pathnode_name = teleport_position_name;
	pathnode_name += (int)G_Random( (float)number_of_teleport_positions ) + 1 ;

	// Find the path node

	goal = thePathManager.FindNode( pathnode_name );

	if ( !goal )
		{
		gi.WDPrintf( "Can't find position %s\n", pathnode_name.c_str() );
		return BEHAVIOR_SUCCESS;
		}

	// Set the teleport position

	teleport_position = goal->origin;

	// Kill anything at this position

	half_height = self.maxs.z / 2.0f;
	attack_position = teleport_position;
	attack_position.z += half_height;

	MeleeAttack( attack_position, attack_position, 10000.0f, &self, MOD_TELEFRAG, self.maxs.x, -half_height, half_height, 0 );

	// Test to see if we can fit at the new position

	trace = G_Trace( teleport_position + Vector( "0 0 64" ), self.mins, self.maxs, teleport_position - Vector( "0 0 128" ), &self, MASK_PATHSOLID, false, "TeleportToPosition" );
	//trace = G_Trace( teleport_position, self.mins, self.maxs, teleport_position, &self, MASK_PATHSOLID, false, "TeleportToPosition" );

	if ( trace.allsolid )
		{
		gi.WDPrintf( "Failed to teleport to %s\n", goal->targetname.c_str() );
		return BEHAVIOR_SUCCESS;
		}

	teleport_position = trace.endpos;

	// Do teleport stuff

   /*
	// Spawn in teleport effect at old positiond

	effect = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
	effect->setModel( "fx_teleport3.tik" );
	effect->setOrigin( self.origin );
	effect->setScale( 2.0f );
	effect->setSolidType( SOLID_NOT );
	effect->animate->RandomAnimate( "idle", EV_Remove );
	//effect->Sound( "snd_teleport" );
   */

	// Set new position

	self.setOrigin( teleport_position );

	// Spawn in teleport effect at new position
   /*
	effect = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
	effect->setModel( "fx_teleport3.tik" );
	effect->setOrigin( self.origin );
	effect->setScale( 2.0f );
	effect->setSolidType( SOLID_NOT );
	effect->animate->RandomAnimate( "idle", EV_Remove );
	//effect->Sound( "snd_teleport" );
   */

	self.NoLerpThisFrame();

	if ( currentEnemy )
		{
		dir = currentEnemy->origin - teleport_position;
		angles = dir.toAngles();

		angles[ROLL] = 0.0f;
		angles[PITCH] = 0.0f;

		self.setAngles( angles );
		}

	return BEHAVIOR_SUCCESS;
	}

void TeleportToPosition::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************

  GhostAttack Class Definition

****************************************************************************/

#define GHOST_ATTACK_START  0
#define GHOST_ATTACK_END    1

#define GHOST_ATTACK_SPEED  350.0f

CLASS_DECLARATION( Behavior, GhostAttack, NULL )
	{
		{ &EV_Behavior_Args,			&GhostAttack::SetArgs },
		{ NULL, NULL }
	};

void GhostAttack::SetArgs
	(
	Event *ev
	)

	{
	real_attack = ev->GetBoolean( 1 );
	}


void GhostAttack::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void GhostAttack::Begin
	(
	Actor &self
	)

	{
	mode = GHOST_ATTACK_START;

	fly.Begin( self );
	fly.SetTurnSpeed( 25.0f );
	fly.SetRandomAllowed( false );
	fly.SetSpeed( GHOST_ATTACK_SPEED );

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();

	if ( currentEnemy )
		attack_position = currentEnemy->centroid;	
	else
		attack_position = self.origin;

	if ( !real_attack )
		{
		attack_position[0] += G_CRandom( 300.0f );
		attack_position[1] += G_CRandom( 300.0f );
		attack_position[2] += G_Random( 100.0f );
		}

	fly.SetGoalPoint( attack_position );

	attack_dir = attack_position - self.origin;

	if ( attack_dir == vec_zero )
		attack_dir = Vector(1, 1, 0);

	attack_dir.normalize();

	self.Sound( "snd_fadein", CHAN_VOICE );
	}

BehaviorReturnCode_t	GhostAttack::Evaluate
	(
	Actor &self
	)

	{
	Vector dir;
	float dist;
	float zdist;
	Vector new_pos;
	float new_alpha;
	float light_radius;
	float r, g, b;
	qboolean success;
	Vector start;
	Vector end;
	Event *event;


	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( mode == GHOST_ATTACK_START )
		{
		// Move closer to the enemy

		fly.Evaluate( self );

		// Get the new distance info

		dir = attack_position - self.origin;

		dist = dir.length();

		zdist = dir.z;

		if ( zdist < 0.0f )
			zdist = -zdist;

		dir.z = 0.0f;

		// If we are close enough change to shootable_only

		if ( real_attack && ( dist < 200.0f ) )
			{
			// Attackable now

			self.setSolidType( SOLID_BBOX );
			self.setContents( CONTENTS_SHOOTABLE_ONLY );

			event = new Event( EV_Actor_SetTargetable );
			event->AddInteger( 1 );
			self.ProcessEvent( event );
			}

		// If we are close enough damage enemy and goto end mode

		start = self.origin;
		end   = self.origin + ( attack_dir * 1.0f );

		if ( real_attack )
			{
			success = MeleeAttack( start, end, 7.5f, &self, MOD_LIFEDRAIN, 32.0f, 0.0f, 64.0f, 0.0f );
			self.AddStateFlag( STATE_FLAG_MELEE_HIT );
			}
		else
			success = false;

		if ( success || ( dist <= GHOST_ATTACK_SPEED / 40.0f ) )
			{
			// Attack mode is done go to retreat mode

			if ( self.attack_blocked && ( self.attack_blocked_time == level.time ) )
				{
				Vector retreat_angles;

				dir = attack_dir * -1.0f;

				retreat_angles = dir.toAngles();
				retreat_angles[YAW] += G_CRandom( 45.0f );
				retreat_angles[PITCH] += G_CRandom( 30.0f );
				retreat_angles.AngleVectors( &dir );

				dir *= 500.0f;

				self.setAngles( retreat_angles );
				}
			else
				{
				dir = attack_dir;

				dir.z = 0.0f;
				dir.normalize();
				dir *= 1000.0f;
				dir.z = 300.0f;
				}

			retreat_position = self.origin + dir;

			fly.SetGoalPoint( retreat_position );

			mode = GHOST_ATTACK_END;
			}

		// Fade in depending on how close we are to attack position

		if ( dist > 400.0f )
			new_alpha = 0.0f;
		else
			new_alpha = ( 400.0f - dist ) / 400.0f;

		if ( new_alpha > 0.4f )
			new_alpha = 0.4f;

		r = new_alpha / 0.4f;
		g = new_alpha / 0.4f;
		b = new_alpha / 0.4f;

		light_radius = 0.0f;

		G_SetConstantLight( &self.edict->s.constantLight, &r, &g, &b, &light_radius );

		self.setAlpha( new_alpha );
		}
	else
		{
		// Move away from enemy

		fly.Evaluate( self );

		// Get the new distance info

		dir = attack_position - self.origin;
		dist = dir.length();

		if ( real_attack && ( dist > 200.0f ) )
			{
			// Not attackable again

			self.setSolidType( SOLID_NOT );
			self.setContents( 0 );

			event = new Event( EV_Actor_SetTargetable );
			event->AddInteger( 0 );
			self.ProcessEvent( event );
			}

		// Fade out depending on how far we are from the attack position

		if ( dist > 400.0f )
			new_alpha = 0.0f;
		else
			new_alpha = ( 400.0f - dist ) / 400.0f;

		if ( new_alpha > 0.4f )
			new_alpha = 0.4f;

		r = new_alpha / 0.4f;
		g = new_alpha / 0.4f;
		b = new_alpha / 0.4f;

		light_radius = 0.0f;

		G_SetConstantLight( &self.edict->s.constantLight, &r, &g, &b, &light_radius );

		self.setAlpha( new_alpha );

		// See if we are far enough to be done

		if ( new_alpha == 0.0f )
			return BEHAVIOR_SUCCESS;
		}
	return BEHAVIOR_EVALUATING;
	}

void GhostAttack::End
	(
	Actor &self
	)

	{
	// Make sure we can't be shot any more

	self.setSolidType( SOLID_NOT );
	self.setContents( 0 );

	fly.End( self );
	}

/****************************************************************************

  Levitate Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, Levitate, NULL )
	{
		{ &EV_Behavior_Args,			&Levitate::SetArgs },
		{ NULL, NULL }
	};

void Levitate::SetArgs
	(
	Event *ev
	)

	{
	distance = ev->GetFloat( 1 );
	speed = ev->GetFloat( 2 );
	}


void Levitate::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void Levitate::Begin
	(
	Actor &self
	)

	{
	final_z = self.origin.z + distance;
	}

BehaviorReturnCode_t	Levitate::Evaluate
	(
	Actor &self
	)

	{
	trace_t trace;
	Vector start;
	Vector end;


	start = self.origin;
	end   = self.origin;

	if ( final_z < self.origin.z )
		{
		end.z -= speed;

		if ( end.z < final_z )
			end.z = final_z;
		}
	else
		{
		end.z += speed;

		if ( end.z > final_z )
			end.z = final_z;
		}

	trace = G_Trace( start, self.mins, self.maxs, end, &self, self.edict->clipmask, false, "Levitate" );

	if ( trace.fraction != 1.0 )
		return BEHAVIOR_SUCCESS;

	if ( end.z == final_z )
		return BEHAVIOR_SUCCESS;

	self.setOrigin( trace.endpos );

	return BEHAVIOR_EVALUATING;
	}

void Levitate::End
	(
	Actor &self
	)

	{
	}

/****************************************************************************
*****************************************************************************

  Utility functions

*****************************************************************************
****************************************************************************/



Vector ChooseRandomDirection
   (
   Actor &self,
   const Vector &previousdir,
   float *time,
   int disallowcontentsmask,
   qboolean usepitch
   )
   {
   //static float x[ 9 ] = { 0, 22, -22, 45, -45, 0, 22, -22, 45 };
	static float x[ 5 ] = { 0, 22, -22, 0, 22 };
   Vector dir;
   Vector ang;
   Vector bestdir;
   Vector newdir;
   Vector step;
	Vector endpos;
	Vector groundend;
   float bestfraction;
   trace_t trace;
	trace_t groundtrace;
   int i;
   int k;
   int t;
   int u;
   int contents;
   Vector centroid;
	float random_yaw;
	float movespeed;

	//if ( self.movespeed != 1 )
	if ( self.movementSubsystem->getMoveSpeed() != 1.0f )
		movespeed = self.movementSubsystem->getMoveSpeed();
	else
		movespeed = 100.0f;

   centroid = self.centroid - self.origin;

	step = Vector( 0.0f, 0.0f, STEPSIZE );
   bestfraction = -1.0f;
   bestdir = self.origin;

	random_yaw = G_Random( 360.0f );

   for( i = 0; i <= 8; i++ )
      {
      t = (int)random_yaw + ( i * 45 );

      ang.y = self.angles.y + (float)t;

      if ( usepitch )
         {
         u = ( int )G_Random( 5.0f );

         //for( k = 0; k < 5; k++ )
			for( k = 0; k < 3; k++ )
            {
            ang.x = x[ k + u ];
            ang.AngleVectors( &dir, NULL, NULL );

            dir *= movespeed * (*time);
            dir += self.origin;
            trace = G_Trace( self.origin, self.mins, self.maxs, dir, &self, self.edict->clipmask, false, "ChooseRandomDirection 1" );

            if ( !trace.startsolid && !trace.allsolid )
               {
               newdir = Vector( trace.endpos );

					if ( disallowcontentsmask )
						{
						contents = gi.pointcontents( ( newdir + centroid ), 0 );

						if ( contents & disallowcontentsmask )
							continue;
						}

               if (
                     ( trace.fraction > bestfraction ) &&
                     ( newdir != bestdir ) &&
                     ( newdir != previousdir )
                  )
                  {
                  bestdir = newdir;
                  bestfraction = trace.fraction;

						if ( bestfraction > .9f )
							{
							*time *= bestfraction;

							return bestdir;
							}
                  }
               }
            }
         }
      else
         {
         ang.x = 0.0f;
         ang.AngleVectors( &dir, NULL, NULL );

			endpos = self.origin + ( dir * movespeed * (*time) ) + step;

         trace = G_Trace( self.origin + step, self.mins, self.maxs, endpos, &self, self.edict->clipmask, false, "ChooseRandomDirection 2" );

         if ( !trace.startsolid && !trace.allsolid )
            {
            newdir = Vector( trace.endpos );

            if ( disallowcontentsmask )
               {
               contents = gi.pointcontents( ( newdir + centroid ), 0 );

					if ( contents & disallowcontentsmask )
						continue;
					}

            if (
                  ( trace.fraction > bestfraction ) &&
                  ( newdir != bestdir ) &&
                  ( newdir != previousdir )
               )
               {
					groundend = endpos - ( step * 2.0f );

					groundtrace = G_Trace( endpos, self.mins, self.maxs, groundend, &self, self.edict->clipmask, false, "Chase::ChooseRandomDirection 3" );

					if ( groundtrace.fraction == 1.0f )
						trace.fraction /= 2.0f;

					if ( trace.fraction > bestfraction )
						{
						bestdir = newdir;
						bestfraction = trace.fraction;

						if ( bestfraction > .9f )
							{
							*time *= bestfraction;

							return bestdir;
							}
						}
               }
            }
         }
      }

   if ( bestfraction > 0.0f )
      {
      *time *= bestfraction;
      }
   else
      {
      *time = 0.0f;
      }

   return bestdir;
   }


//
// WayPoint Stuff
//
/****************************************************************************

  GotoWayPoint Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, GotoWayPoint, NULL )
	{
		{ &EV_Behavior_Args,			       &GotoWayPoint::SetArgs          },
		{ NULL, NULL }
	};

void GotoWayPoint::SetArgs
	(
	Event *ev
	)

	{
	path_name = ev->GetString( 1 );
	anim = ev->GetString( 2 );
	current_waypoint_name = path_name;
	current_waypoint = NULL;
	}

void GotoWayPoint::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void GotoWayPoint::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
      {
		anim = "run";
      }

	if ( anim != self.animname || self.newanim.length() )
      {
		self.SetAnim( anim );
      }

	chase.Begin( self );	

	next_think_time = 0.0f;
	}

BehaviorReturnCode_t	GotoWayPoint::Evaluate
	(
	Actor &self
	)

	{
	//First Check if we are at a way point;
	Vector dest;
	Vector check;
	
	if (!current_waypoint)
		{
		current_waypoint = GetWayPoint( current_waypoint_name );
		if (!current_waypoint)
			return BEHAVIOR_SUCCESS;
		}
	
	dest = current_waypoint->origin;
	check = dest - self.origin;

	// Check if we're close enough
	if ( check.length() < 10.0f )
		{
		// Run Our Thread
		str waypointThread;
		waypointThread = current_waypoint->GetThread();

		if (waypointThread.length() )
			self.RunThread( waypointThread );

      // See if we have another point to go to
		if ( current_waypoint->target.length() == 0 )
			{
			return BEHAVIOR_SUCCESS;
			}

		// Check for new anim
		anim = "";
		anim = current_waypoint->GetActorAnim();
		
		if ( anim.length() )
			self.SetAnim( anim );			
		
		// Go To the Next Point
		current_waypoint_name = current_waypoint->target;
		current_waypoint = GetWayPoint( current_waypoint_name );		

		if (!current_waypoint)
			return BEHAVIOR_SUCCESS;

		dest = current_waypoint->origin;

		//Clear out anim strings
		anim = "";		
	
			
		}

	float radius=96.0f;
	chase.SetGoal( current_waypoint->origin, radius, self );
	chase.Evaluate(self);
   return BEHAVIOR_EVALUATING;
	}

void GotoWayPoint::End
	(
	Actor &self
	)

	{
	chase.End( self );		
	}

WayPointNode* GotoWayPoint::GetWayPoint
   (
	const str &waypoint_name
	)

	{
	Entity* ent_in_range;
	gentity_t *ed;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			if (!Q_stricmp(ent_in_range->targetname.c_str() , waypoint_name.c_str() ))
				{
				return (WayPointNode*)ent_in_range;
				}
			}
		}
	
	return NULL;
	}

/****************************************************************************

  FlyCircleAroundWaypoint Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, FlyCircleAroundWaypoint, NULL )
	{
		{ &EV_Behavior_Args,			&FlyCircleAroundWaypoint::SetArgs },
		{ NULL, NULL }
	};

FlyCircleAroundWaypoint::FlyCircleAroundWaypoint()
	{
	anim = "fly";	
	nearestPlayer = false;
	fly_clockwise = true;
	}

void FlyCircleAroundWaypoint::SetArgs
	(
	Event *ev
	)

	{
   anim = ev->GetString( 1 );
	fly_clockwise = ev->GetBoolean( 2 );
	waypointname = ev->GetString( 3 );
	
   if (ev->NumArgs() > 3 )
		fly.SetSpeed( ev->GetFloat( 4 ) );

   if (ev->NumArgs() > 4 )
		fly.setAdjustYawAndRoll( ev->GetBoolean( 5 ) );
	
	if ( !Q_stricmp(waypointname.c_str() , "player" ) )
		nearestPlayer = true;
	
	}

void FlyCircleAroundWaypoint::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void FlyCircleAroundWaypoint::Begin
	(
	Actor &self
	)

	{
	//original_z = self.origin.z;

	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( 5.0f );
	}

BehaviorReturnCode_t	FlyCircleAroundWaypoint::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;
	trace_t trace;
	Vector dir;
	Vector angle;
	Vector left;
	qboolean too_far = false;
	Vector new_dir;
	Vector fly_dir;
	WayPointNode *goalNode;
	
	
	goalNode = NULL;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) )
      {
      return BEHAVIOR_SUCCESS;
      }

	//if ( self.lastmove == STEPMOVE_OK )
	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		{
		fly.SetTurnSpeed( 5.0f );
		
		if ( nearestPlayer )
			goalNode = GetWayPointNearestPlayer( self );
		else
			goalNode = GetWayPoint( self );

		if ( !goalNode )
			return BEHAVIOR_SUCCESS;
		
		dir = goalNode->origin - self.origin;
		dir.z = 0;

   	if ( dir.length() > 200.0f ) //radius
			{
			too_far = true;
			}


		angle = dir.toAngles();
		angle.AngleVectors( NULL, &left, NULL );

		if ( fly_clockwise )
			fly_dir = left;
		else
			fly_dir = left * -1.0f;

		dir.normalize();

		if ( too_far )
			{
			new_dir = ( fly_dir * 0.5f ) + ( dir * 0.5f );
			new_dir.normalize();
			}
		else
			{
			new_dir = fly_dir;
			}

		goal = self.origin + ( new_dir * 200.0f );

		trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyCircle" );

		if ( trace.fraction < 1.0f )
			{
			if ( too_far )
				trace.fraction /= 2.0f;

			new_dir = ( fly_dir * trace.fraction ) + ( dir * ( 1.0f - trace.fraction ) );
			new_dir.normalize();
   		goal = self.origin + ( new_dir * 200.0f );
			}
		else
			{
			goal = trace.endpos;
			}

		fly.SetGoalPoint( goal );
		}
	else
		{
		fly.SetTurnSpeed( 20.0f );
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

WayPointNode *FlyCircleAroundWaypoint::GetWayPoint( Actor &self )
	{
	Entity* ent_in_range;
	gentity_t *ed;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			if (!Q_stricmp(ent_in_range->targetname.c_str() , waypointname.c_str() ))
				{
				return (WayPointNode*)ent_in_range;
				}
			}
		}
	
	return NULL;
	}

WayPointNode *FlyCircleAroundWaypoint::GetWayPointNearestPlayer( Actor &self)
	{
	Vector DistanceFromPlayer;
	float distance;
	Entity* ent_in_range;
	Entity* best_ent;

	gentity_t *ed;
	
	ent_in_range = NULL;
	best_ent = NULL;
	distance = 100000000;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return NULL;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			DistanceFromPlayer = ent_in_range->origin - currentEnemy->origin;
			if (DistanceFromPlayer.length() < distance )
				{
				best_ent = ent_in_range;
				distance = DistanceFromPlayer.length();
				}
			}
		}
	
	return (WayPointNode*)best_ent;
	}

void FlyCircleAroundWaypoint::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}

/****************************************************************************

  HelicopterFlyToPoint Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, HelicopterFlyToPoint, NULL )
	{
		{ NULL, NULL }
	};

HelicopterFlyToPoint::HelicopterFlyToPoint()
	{
	turn_speed = 10.0;
	old_turn_speed = turn_speed;
	speed = 480.0;
	random_allowed = true;
	force_goal = false;
	adjustYawAndRoll = true;
	offsetOrigin = false;
	avoidtime = 0;
	old_forward_speed = 0;
	stuck = 0;
	use_temp_goal = false;
	}

void HelicopterFlyToPoint::SetTurnSpeed( float new_turn_speed )
	{
	turn_speed = new_turn_speed;
	}

void HelicopterFlyToPoint::SetGoalPoint( const Vector &goal_point )
	{
	if ( goal_point != goal )
		avoidtime = 0;

	goal = goal_point;
	}

void HelicopterFlyToPoint::SetRandomAllowed( qboolean allowed )
	{
	random_allowed = allowed;
	}

void HelicopterFlyToPoint::SetSpeed( float speed_value )
	{
	speed = speed_value;
	}

void HelicopterFlyToPoint::ForceGoal( void )
	{
	force_goal = true;
	}

void HelicopterFlyToPoint::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void HelicopterFlyToPoint::Begin
	(
	Actor &self
	)

	{
   avoidtime = 0;
	//old_forward_speed = self.forwardspeed;
	old_forward_speed = self.movementSubsystem->getForwardSpeed();
	stuck = 0;
	use_temp_goal = false;
	}

BehaviorReturnCode_t	HelicopterFlyToPoint::Evaluate
	(
	Actor &self
	)

	{
   trace_t trace;
   Vector dir;
   Vector ang;
	float time;
	float length;
	float old_yaw;
	float old_pitch;
	
	float x_offset = 0.0f;
	float y_offset = 0.0f;
	//float z_offset = 0.0f;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();


   if (offsetOrigin)
		{
   	x_offset = self.centroid.x - self.origin.x;
   	y_offset = self.centroid.y - self.origin.y;
	   //z_offset = self.centroid.z - self.origin.z;
		
		self.origin.x+=x_offset;
	   self.origin.y+=y_offset;
	   //self.origin.z+=z_offset;
		}

	//if ( self.lastmove != STEPMOVE_OK )
	if ( self.movementSubsystem->getLastMove() != STEPMOVE_OK )
		stuck++;
	else
		stuck = 0;
	
	if ( ( stuck > 1 ) || ( avoidtime <= level.time ) )
      {
		time = G_Random( .3f ) + .3f;

		use_temp_goal = false;

		if ( !force_goal )
			{
			trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyToPoint" );
						
			if ( ( trace.fraction < 0.5f ) || ( stuck > 2 ) )
				{
				old_turn_speed = self.movementSubsystem->getTurnSpeed();
			   self.movementSubsystem->setTurnSpeed( 60.0f );
				//self.turnspeed = 60;
				temp_goal = ChooseRandomDirection( self, goal, &time, MASK_WATER, false );
				self.movementSubsystem->setTurnSpeed( old_turn_speed );
				//self.turnspeed = old_turn_speed;
				use_temp_goal = true;
				avoidtime = level.time + time;

				stuck = 0;
				}
			else
				{
				goal = trace.endpos;
				avoidtime = level.time + time;
				}
			}
		else
			{
			avoidtime = level.time + time;
			}
		
		if ( use_temp_goal )
			dir = temp_goal - self.origin;
		else
			dir = goal - self.origin;			

		length = dir.length();
      dir.normalize();
		
		//new stuff
		//self.FlightDir = dir;


      ang = dir.toAngles();
		
		if ( ( length > 150.0f ) && random_allowed && !use_temp_goal )
			{
			//ang[YAW]   += G_Random( 20 ) - 5.0;
			//ang[PITCH] += G_Random( 20 ) - 5.0;
			}

		target_angle = ang;

		target_angle[YAW]   = AngleNormalize180( target_angle[YAW] );
		target_angle[PITCH] = AngleNormalize180( target_angle[PITCH] );

		if ( currentEnemy )
			{
			Vector enemyDir;
			enemyDir = currentEnemy->origin - self.origin;
			enemyDir.normalize();
			target_angle[PITCH] = AngleNormalize180(-enemyDir.toPitch());
			if ( target_angle[PITCH] < -40.0f )
				target_angle[PITCH] = -40.0f;

			if ( target_angle[PITCH] > 40.0f )
				target_angle[PITCH] = 40.0f;

			target_angle[YAW] = enemyDir.toYaw();
			target_angle[ROLL] = 0.0f;
			}
      }

	target_angle[YAW]   = AngleNormalize360( target_angle[YAW] );
	target_angle[PITCH] = AngleNormalize360( target_angle[PITCH] );

	if ( (self.angles[YAW] != target_angle[YAW]) || (self.angles[PITCH] != target_angle[PITCH]) )
      {
		self.movementSubsystem->setForwardSpeed( speed * 0.8f );
		//self.forwardspeed = speed * 0.8f;
      }
	else
      {
		self.movementSubsystem->setForwardSpeed( speed );
		//self.forwardspeed = speed;
      }

	old_yaw   = self.angles[YAW];
	old_pitch = self.angles[PITCH];
	
	ang[YAW]   = LerpAngle( self.angles[YAW],   target_angle[YAW],   turn_speed );
	ang[PITCH] = LerpAngle( self.angles[PITCH], target_angle[PITCH], turn_speed );
	ang[ROLL]  = self.angles[ROLL];
	
	/*
	if( adjustYawAndRoll )
		{
	   
		if ( (AngleDelta( ang[YAW], old_yaw ) > 0) && (ang[ROLL] > 315 || ang[ROLL] <= 45) )
			{
			ang[ROLL] += 5;
			}
		else if ( (AngleDelta( ang[YAW], old_yaw ) < 0) && (ang[ROLL] < 45 || ang[ROLL] >= 315) )
			{
			ang[ROLL] -= 5;
			}
		else if ( (AngleDelta( ang[YAW], old_yaw ) == 0 ) )
			{
			if ( ang[ROLL] != 0 )
				{
				
				if ( ang[ROLL] < 5 || ang[ROLL] > 355 )
					{
					ang[ROLL] = 0;
					}
				else
					{
					if ( ang[ROLL] < 180 )
						ang[ROLL] += 5;
					else
						ang[ROLL] -= 5;
					}

				}
			}
		}
   */
	
	if ( adjustYawAndRoll )
		{
		//Vector travelAngleDelta = dir.toAngles();
		float yawDelta = dir[YAW] - self.angles[YAW];

		yawDelta = AngleNormalize360(yawDelta);

		if ( ( yawDelta > 0.0f ) && ( yawDelta <= 180.0f ) )
			{
			ang[ROLL] = self.angles[ROLL] + 2.0f;
			if ( AngleNormalize180(ang[ROLL]) > 30.0f )
				ang[ROLL] = 30.0f;
			}
	
		if ( ( yawDelta >= 180.0f ) && ( yawDelta <= 359.0f ) )
			{
			ang[ROLL] = self.angles[ROLL] - 2.0f;
			if ( AngleNormalize180(ang[ROLL]) < -30.0f )
				ang[ROLL] = -30.0f;
			}

		}
   
	ang[YAW]   = AngleNormalize360( ang[YAW] );
	ang[PITCH] = AngleNormalize360( ang[PITCH] );
	ang[ROLL]  = AngleNormalize360( ang[ROLL] );

	// Don't get stuck if still turning

	if ( ( AngleDelta( ang[YAW], old_yaw ) > .5f ) || ( AngleDelta( ang[YAW], old_yaw ) < -.5f ) ||
		  ( AngleDelta( ang[PITCH], old_pitch ) > .5f ) || ( AngleDelta( ang[PITCH], old_pitch ) < -.5f ) )
		{
		stuck = 0;
		}

	self.setAngles( ang );

	if (offsetOrigin)
		{
   	self.origin.x-=x_offset;
	   self.origin.y-=y_offset;
	   //self.origin.z-=z_offset;
		}

	return BEHAVIOR_EVALUATING;
	}

float HelicopterFlyToPoint::LerpAngle( float old_angle, float new_angle, float lerp_amount )
	{
	float diff;
	float abs_diff;
	float lerp_angle;

	new_angle = AngleNormalize360( new_angle );
	old_angle = AngleNormalize360( old_angle );

	diff = new_angle - old_angle;

	if ( diff > 180.0f )
      {
		diff -= 360.0f;
      }

	if ( diff < -180.0f )
      {
		diff += 360.0f;
      }

	lerp_angle = old_angle;
	
	abs_diff = diff;

	if ( abs_diff < 0.0f )
      {
		abs_diff = -abs_diff;
      }

	if ( abs_diff < lerp_amount )
      {
		lerp_amount = abs_diff;
      }

	if ( diff < 0.0f )
      {
		lerp_angle -= lerp_amount;
      }
	else if ( diff > 0.0f )
      {
		lerp_angle += lerp_amount;
      }
	
	lerp_angle = AngleNormalize360( lerp_angle );

	return lerp_angle;
	}

void HelicopterFlyToPoint::End
	(
	Actor &self
	)

	{
	self.movementSubsystem->setForwardSpeed( old_forward_speed );
	//self.FlightDir = vec_zero;
	}

/****************************************************************************

  FlyCircle Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, HelicopterFlyCircle, NULL )
	{
		{ &EV_Behavior_Args,			&HelicopterFlyCircle::SetArgs },
		{ NULL, NULL }
	};

HelicopterFlyCircle::HelicopterFlyCircle()
	{
	anim = "fly";	
	fly_clockwise = true;
	circle_player = false;
	}

void HelicopterFlyCircle::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	fly_clockwise = ev->GetBoolean( 2 );

	if (ev->NumArgs() > 2 )
		fly.setAdjustYawAndRoll( false );
		//fly.setAdjustYawAndRoll( ev->GetBoolean( 3 ) );
	
	if (ev->NumArgs() > 3 )
		circle_player = ev->GetBoolean ( 4 );
	else
		circle_player = false;	
	
	if (ev->NumArgs() > 4 )
		fly.SetSpeed( ev->GetFloat( 5 ) );
	}

void HelicopterFlyCircle::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void HelicopterFlyCircle::Begin
	(
	Actor &self
	)

	{
	//original_z = self.origin.z;

	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( 5.0f );
	}

BehaviorReturnCode_t	HelicopterFlyCircle::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;
	trace_t trace;
	Vector dir;
	Vector angle;
	Vector left;
	qboolean too_far = false;
	Vector new_dir;
	Vector fly_dir;
	
	//Vector or;

	//or = self.currentEnemy->centroid - self.origin;
	//or = or.toAngles();

	//self.angles = or;
	//self.setAngles( or );
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) && !circle_player )
      {
      return BEHAVIOR_SUCCESS;
      }

	//if ( self.lastmove == STEPMOVE_OK )
	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		{
		fly.SetTurnSpeed( 5.0f );

		if (circle_player)
			{
			Player *player = NULL;
			Player *temp_player = NULL;
			// Make sure the player is alive and well
			for(int i = 0; i < game.maxclients; i++)
				{
				temp_player = GetPlayer(i);		
			
				// don't target while player is not in the game or he's in notarget
				if ( temp_player && !( temp_player->flags & FL_NOTARGET ) )
					{
					player = temp_player;
					break;
					}
				}

			if ( !player )
				return BEHAVIOR_SUCCESS;
						
			dir = player->centroid - self.origin;
			dir.z = 0;

			//if ( dir.length() > (self.origin.z - player->centroid.z) / .5 )
			if ( dir.length() > 600.0f )
				{
				too_far = true;
				}

			}
		else
			{
			dir = currentEnemy->centroid - self.origin;
			dir.z = 0;

			if ( dir.length() > ( ( self.origin.z - currentEnemy->centroid.z) / 2.0f ) )
				{
				too_far = true;
				}

			}

		angle = dir.toAngles();

		angle.AngleVectors( NULL, &left, NULL );
		
		Vector newAngles = self.angles;
		if ( fly_clockwise )
			{
			fly_dir = left;

			newAngles[ROLL] -= 5.0f;
			if ( AngleNormalize180(newAngles[ROLL]) < -30.0f )
				newAngles[ROLL] = -30.0f;
			
			}			
		else
			{
			fly_dir = left * -1.0f;
			newAngles[ROLL] += 5.0f;
			if ( AngleNormalize180(newAngles[ROLL]) > 30.0f )
				newAngles[ROLL] = 30.0f;

			}
			
		self.setAngles(newAngles);

		dir.normalize();

		if ( too_far )
			{
			new_dir = ( fly_dir * 0.5f ) + ( dir * 0.5f );
			new_dir.normalize();
			}
		else
			{
			new_dir = fly_dir;
			}

		goal = self.origin + ( new_dir * 200.0f );

		trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyCircle" );

		if ( trace.fraction < 1.0f )
			{
			if ( too_far )
				trace.fraction /= 2.0f;

			new_dir = ( fly_dir * trace.fraction ) + ( dir * ( 1.0f - trace.fraction ) );
			new_dir.normalize();

			goal = self.origin + ( new_dir * 200.0f );
			}
		else
			{
			goal = trace.endpos;
			}

		fly.SetGoalPoint( goal );
		}
	else
		{
		fly.SetTurnSpeed( 20.0f );
		}

	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

void HelicopterFlyCircle::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}


/****************************************************************************

  HelicopterStrafeAttack Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, HelicopterStrafeAttack, NULL )
	{
		{ &EV_Behavior_Args,			&HelicopterStrafeAttack::SetArgs },
		{ NULL, NULL }
	};

HelicopterStrafeAttack::HelicopterStrafeAttack()
	{
	anim = "fly";
	turnTime = 5;
	setUpLerp = false;
	completedLerp = false;

	lerpStart = 0.0f;
	lerpEnd = 0.0f;

	startYaw = 0.0f;
	endYaw = 0.0f;
	}

void HelicopterStrafeAttack::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );
	}

void HelicopterStrafeAttack::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void HelicopterStrafeAttack::Begin
	(
	Actor &self
	)

	{
   self.SetAnim(anim);

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return;

	//First we find the waypoint closest to the player
	//These waypoints should be pointed along the axis
	//that we want the helicopter to strafe
	WayPointNode *wp = GetWayPointNearestPlayer(self);
	
	str tName = wp->Target();
	WayPointNode *target = GetWayPoint(self , tName );

	//Set up goal location
	//goal = target->origin;
	goal = wp->origin;
	goal.z = self.origin.z;
	
	//We need the cross product
	Vector wpForward;
	Vector wpUp;
	Vector cross;

   wpForward = target->origin - wp->origin;
	wpForward.normalize();
	

	wpUp.x = 0;
	wpUp.y = 0;
	wpUp.z = 1;
	
	CrossProduct(wpForward, wpUp, cross );

	
	
	//wpOrigin.AngleVectors(NULL,&left,NULL);

	//Get the vector from the player to the actor
	Vector playerToActor;
	playerToActor = self.origin - currentEnemy->origin;


	//Normalize the vectors
	playerToActor.normalize();
	cross.normalize();

	//Now we get the Dot product to see if towardPlayer
	float dot;
	dot = DotProduct(cross,playerToActor);
	

	//Now we get our actual direction Vector;	
	if ( dot > 0.0f )
		dir = cross * -1.0f;
	else
		dir = cross;

	
	//Now set our angles appropriately
	targetAngles = self.angles;
	targetAngles[YAW] = dir.toYaw();
	
	startYaw = AngleNormalize360(self.angles[YAW]);
	endYaw = AngleNormalize360(targetAngles[YAW]);
	
	if ( ( endYaw == 0.0f ) && ( startYaw > 180.0f ) )
		endYaw = 360.0f;

	}

BehaviorReturnCode_t	HelicopterStrafeAttack::Evaluate
	(
	Actor &self
	)

	{
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;
	
	if ( !setUpLerp )
		{
		lerpStart = level.time;
		lerpEnd = lerpStart + turnTime;
		setUpLerp = true;
		}
	
	if ( !completedLerp )
		LerpToNewAngle( self );


	//Get our travel destination
	Vector travelDir;
	travelDir = goal - self.origin;

	//Check if we are at our destination
	float length = travelDir.length();
	
	if ( length < 25.0f ) //We're close enough
		return BEHAVIOR_SUCCESS;
	
	travelDir.normalize();
	//self.FlightDir = travelDir;
	self.movementSubsystem->setForwardSpeed( 300.0f );
		

	return BEHAVIOR_EVALUATING;
	}

WayPointNode *HelicopterStrafeAttack::GetWayPointNearestPlayer( Actor &self)
	{
	Vector DistanceFromPlayer;
	float distance;
	Entity* ent_in_range;
	Entity* best_ent;

	gentity_t *ed;
	
	ent_in_range = NULL;
	best_ent = NULL;
	distance = 100000000;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return NULL;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			DistanceFromPlayer = ent_in_range->origin - currentEnemy->origin;
			if (DistanceFromPlayer.length() < distance )
				{
				best_ent = ent_in_range;
				distance = DistanceFromPlayer.length();
				}
			}
		}
	
	return (WayPointNode*)best_ent;
	}

WayPointNode *HelicopterStrafeAttack::GetWayPoint( Actor &self , const str &name )
	{
	Entity* ent_in_range;
	gentity_t *ed;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			if (!Q_stricmp(ent_in_range->targetname.c_str() , name.c_str() ))
				{
				return (WayPointNode*)ent_in_range;
				}
			}
		}
	
	return NULL;
	}

void HelicopterStrafeAttack::LerpToNewAngle( Actor &self )
	{
	Vector ang;
	float newYaw;

	ang = self.angles;
	
	newYaw = ( endYaw - startYaw ) / ( lerpEnd - lerpStart );
	newYaw = newYaw * (level.time - lerpStart );
	newYaw = newYaw + startYaw;
		
	ang[YAW] = newYaw;
	// Clamp it down in the end
	if ( level.time >= lerpEnd )
		{
		ang[YAW] = endYaw;
		completedLerp = true;
		}

	self.setAngles(ang);

	}

void HelicopterStrafeAttack::End
	(
	Actor &self
	)

	{
	//self.FlightDir = vec_zero;
	}


/****************************************************************************

  HelicopterFlyToWaypoint Class Definition

****************************************************************************/


CLASS_DECLARATION( Behavior, HelicopterFlyToWaypoint, NULL )
	{
		{ &EV_Behavior_Args,			&HelicopterFlyToWaypoint::SetArgs },
		{ NULL, NULL }
	};

HelicopterFlyToWaypoint::HelicopterFlyToWaypoint()
	{
	anim = "fly";	
	nearestPlayer = false;
	nearestPlayerTarget = false;

	}

void HelicopterFlyToWaypoint::SetArgs
	(
	Event *ev
	)

	{
   anim = ev->GetString( 1 );
	waypointname = ev->GetString( 2 );
	
   if (ev->NumArgs() > 2 )
		fly.SetSpeed( ev->GetFloat( 3 ) );

   if (ev->NumArgs() > 3 )
		fly.setAdjustYawAndRoll( ev->GetBoolean( 4 ) );
	
	if ( !Q_stricmp(waypointname.c_str() , "player" ) )
		nearestPlayer = true;

	if ( !Q_stricmp(waypointname.c_str() , "target" ) )
		nearestPlayerTarget = true;
	
	}

void HelicopterFlyToWaypoint::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );
	}

void HelicopterFlyToWaypoint::Begin
	(
	Actor &self
	)

	{
	if ( anim.length() )
      {
		self.SetAnim( anim );
      }

	fly.Begin( self );
	fly.SetTurnSpeed( 5.0f );
	}

BehaviorReturnCode_t	HelicopterFlyToWaypoint::Evaluate
	(
	Actor &self
	)

	{
   Vector goal;
	WayPointNode *goalNode;
	goalNode = NULL;

	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return BEHAVIOR_SUCCESS;

	if ( !self.IsEntityAlive( currentEnemy ) )
      {
      return BEHAVIOR_SUCCESS;
      }

	//if ( self.lastmove == STEPMOVE_OK )
	if ( self.movementSubsystem->getLastMove() == STEPMOVE_OK )
		{
		fly.SetTurnSpeed( 5.0f );
		
		if ( nearestPlayer )
			goalNode = GetWayPointNearestPlayer( self );
		else if ( nearestPlayerTarget )
			{
			goalNode = GetWayPointNearestPlayer( self );
			waypointname = goalNode->TargetName();			
			}
		
		if ( !nearestPlayer )
			goalNode = GetWayPoint( self );

		}
	

	if ( !goalNode )
		return BEHAVIOR_SUCCESS;

	goal = goalNode->origin;
	goal.z = self.origin.z;

	//Check if we have arrived
	Vector dir;
	dir = self.origin - goal;
	
	if ( dir.length() <= 25.0f )
		return BEHAVIOR_SUCCESS;
	
	fly.SetGoalPoint( goal );
	fly.Evaluate( self );

	return BEHAVIOR_EVALUATING;
	}

WayPointNode *HelicopterFlyToWaypoint::GetWayPoint( Actor &self )
	{
	Entity* ent_in_range;
	gentity_t *ed;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			if (!Q_stricmp(ent_in_range->targetname.c_str() , waypointname.c_str() ))
				{
				return (WayPointNode*)ent_in_range;
				}
			}
		}
	
	return NULL;
	}

WayPointNode *HelicopterFlyToWaypoint::GetWayPointNearestPlayer( Actor &self)
	{
	Vector DistanceFromPlayer;
	float distance;
	Entity* ent_in_range;
	Entity* best_ent;

	gentity_t *ed;
	
	ent_in_range = NULL;
	best_ent = NULL;
	distance = 100000000;
	
	Entity *currentEnemy;
	currentEnemy = self.enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		return NULL;

	for ( int i = 0; i < MAX_GENTITIES; i++ )
		{
		ed = &g_entities[i];

		if ( !ed->inuse || !ed->entity )
			{
			continue;
			}
				
			
		ent_in_range = g_entities[i].entity;

		if( ent_in_range->isSubclassOf( WayPointNode ) )
			{
			DistanceFromPlayer = ent_in_range->origin - currentEnemy->origin;
			if (DistanceFromPlayer.length() < distance )
				{
				best_ent = ent_in_range;
				distance = DistanceFromPlayer.length();
				}
			}
		}
	
	return (WayPointNode*)best_ent;
	}

void HelicopterFlyToWaypoint::End
	(
	Actor &self
	)

	{
	fly.End( self );
	}


/****************************************************************************

  GetWithinRangeOfPlayer Class Definition

****************************************************************************/

CLASS_DECLARATION( Behavior, GetWithinRangeOfPlayer, NULL )
	{
		{ &EV_Behavior_Args,			&GetWithinRangeOfPlayer::SetArgs },
		{ NULL, NULL }
	};

void GetWithinRangeOfPlayer::SetArgs
	(
	Event *ev
	)

	{
	anim = ev->GetString( 1 );

	if ( ev->NumArgs() > 1 )
		forever = ev->GetBoolean( 2 );
	else
		forever = true;

	if ( ev->NumArgs() > 2 )
		speed = ev->GetFloat( 3 );
	else
		speed = 100;

   if ( ev->NumArgs() > 3 )
      chase.SetRadius( ev->GetFloat( 4 ) );

	}

void GetWithinRangeOfPlayer::ShowInfo
	(
	Actor &self
	)

	{
   Behavior::ShowInfo( self );

   gi.Printf( "\nchase:\n" );
   chase.ShowInfo( self );
	}

void GetWithinRangeOfPlayer::Begin
	(
	Actor &self
	)

	{
	if ( !anim.length() )
      {
		anim = "run";
      }

	if ( anim != self.animname || self.newanim.length() )
      {
		self.SetAnim( anim, EV_Actor_NotifyBehavior );
      }

	chase.Begin( self );
	wander.Begin( self );
	
	self.movementSubsystem->setForwardSpeed( speed );

	next_think_time = 0;

   startRangeMin = self.preferredMax;
   startRangeMax = startRangeMin * 1.25;
	}

BehaviorReturnCode_t	GetWithinRangeOfPlayer::Evaluate
	(
	Actor &self
	)

	{
	Steering::ReturnValue result=Steering::EVALUATING;
	
	Player *player = NULL;
	Player *temp_player = NULL;
	// Make sure the player is alive and well
	for(int i = 0; i < game.maxclients; i++)
		{
		temp_player = GetPlayer(i);		
		
		// don't target while player is not in the game or he's in notarget
		if( temp_player && !( temp_player->flags & FL_NOTARGET ) )
			{
			player = temp_player;
			break;
			}
		}

	if ( !player )
		return BEHAVIOR_SUCCESS;

	if ( next_think_time <= level.time )
		{
		if ( self.groundentity && ( self.groundentity->s.number == player->entnum ) )
			{
			wander.Evaluate( self );
			result = Steering::SUCCESS;
			}
		else
			{
			float radius=96.0f;
			chase.SetGoal( player, radius, self );			

			result = chase.Evaluate( self );
			}

		if ( self.GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) )
			next_think_time = level.time + ( 2.0f * FRAMETIME );
		else
			next_think_time = 0.0f;
		}
	else
		result = Steering::SUCCESS;

	if ( !forever && ( result == Steering::SUCCESS) )
		return BEHAVIOR_SUCCESS;

	if ( !forever)
		{
		switch (result)
			{
			case Steering::EVALUATING:
				return BEHAVIOR_EVALUATING;
				break;
			
			case Steering::SUCCESS:
				return BEHAVIOR_SUCCESS;
				break;
			
			case Steering::FAILED_BLOCKED_BY_ENEMY:
			// lint -fallthrough
			case Steering::FAILED_BLOCKED_BY_CIVILIAN:
			// lint -fallthrough
			case Steering::FAILED_BLOCKED_BY_FRIEND:
			// lint -fallthrough
			case Steering::FAILED_BLOCKED_BY_TEAMMATE:
			// lint -fallthrough
			case Steering::FAILED_BLOCKED_BY_WORLD:
			// lint -fallthrough
			case Steering::FAILED_BLOCKED_BY_DOOR:
			// lint -fallthrough
			case Steering::FAILED_NO_PATH:
			// lint -fallthrough
			case Steering::FAILED:
			// lint -fallthrough
				return BEHAVIOR_FAILED;
				break;
			}
		}
	
	return BEHAVIOR_EVALUATING;
	}

void GetWithinRangeOfPlayer::End
	(
	Actor &self
	)

	{
	chase.End( self );
	wander.End( self );
	self.movementSubsystem->setForwardSpeed( 0 );
	}
