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

ai_follower.script

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

#define FOLLOW_MAXDIST	120
#define FOLLOW_MINDIST	80
#define FOLLOW_RUNDIST	180

object follower : ai {
	string		customAnim;
	boolean		inCustomAnim;
	float		customBlendOut;
	boolean		run;
	
	//
	// States
	//
	void		state_Idle();
	void		state_Killed();
	void		state_Follow();
	void		getCloser();

	void		init();
	
	void		playCustomCycle( string animname, float blendTime );
	void		playCustomAnim( string animname, float blendIn, float blendOut );

	float		should_turn_left();
	float		should_turn_right();
		
	// torso anim states
	void		Torso_Death();
	void		Torso_Idle();
	void		Torso_Pain();
	void		Torso_CustomAnim();
	void		Torso_CustomCycle();
	
	// legs anim states
	void		Legs_Death();
	void		Legs_Idle();
	void		Legs_Walk();
	void		Legs_Run();
	void		Legs_TurnLeft();
	void		Legs_TurnRight();
};

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

	Torso animation control

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

void follower::Torso_CustomCycle() {
	overrideAnim( ANIMCHANNEL_LEGS );
	playCycle( ANIMCHANNEL_TORSO, customAnim );
	eachFrame {
		;
	}
}

void follower::Torso_CustomAnim() {
	inCustomAnim = true;
	playAnim( ANIMCHANNEL_TORSO, customAnim );
	
	while( !( animDone( ANIMCHANNEL_TORSO, customBlendOut ) ) ) {
		waitFrame();
	}
	
	finishAction( "customAnim" );
	inCustomAnim = false;
	animState( ANIMCHANNEL_TORSO, "Torso_Idle", customBlendOut );
}

void follower::Torso_Death() {
	finishAction( "dead" );
}

void follower::Torso_Idle() {
	idleAnim( ANIMCHANNEL_TORSO, "idle" );
	
	while( !AI_PAIN ) {
		waitFrame();
	}
	
	animState( ANIMCHANNEL_TORSO, "Torso_Pain", 0 );
}

void follower::Torso_Pain() {
	string animname;
	float nextpain;
	float currenttime;
	
	animname = getPainAnim();
	playAnim( ANIMCHANNEL_TORSO, animname );

	nextpain = sys.getTime() + 0.25;
	while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
		if ( AI_PAIN ) {
			currenttime = sys.getTime();
			if ( currenttime > nextpain ) {
				animState( ANIMCHANNEL_TORSO, "Torso_Pain", 0 );
			}
		}
		waitFrame();
	}
	
	finishAction( "pain" );
	animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
}

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

	Legs animation control

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

void follower::Legs_Death() {
}

float follower::should_turn_left() {
	float turnAmount;
	
	turnAmount = getTurnDelta();
	if ( turnAmount > 10 ) {
		if ( hasAnim( ANIMCHANNEL_LEGS, "turn_left" ) ) {
			return true;
		}
	}
	return false;
}

float follower::should_turn_right() {
	float turnAmount;
	
	turnAmount = getTurnDelta();
	if ( turnAmount < -10 ) {
		if ( hasAnim( ANIMCHANNEL_LEGS, "turn_right" ) ) {
			return true;
		}
	}
	return false;
}

void follower::Legs_Idle() {
	if ( !AI_FORWARD && !facingIdeal() ) {
		if ( should_turn_left() ) {
			animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", 4 );
		}
		if ( should_turn_right() ) {
			animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", 4 );
		}
	}
	
	idleAnim( ANIMCHANNEL_LEGS, "idle" );
	eachFrame {
		if ( AI_FORWARD ) {
			if ( run ) {
				animState( ANIMCHANNEL_LEGS, "Legs_Run", 12 );
			} else {
				animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
			}
		}
		
		if ( !facingIdeal() ) {
			if ( should_turn_left() ) {
				animState( ANIMCHANNEL_LEGS, "Legs_TurnLeft", 4 );
			}
			if ( should_turn_right() ) {
				animState( ANIMCHANNEL_LEGS, "Legs_TurnRight", 4 );
			}
		}
	}
}

void follower::Legs_Walk() {
	playCycle( ANIMCHANNEL_LEGS, "walk" );
	
	while( AI_FORWARD && !run )	{
		waitFrame();
	}
	
	if ( AI_FORWARD && run ) {
		animState( ANIMCHANNEL_LEGS, "Legs_Run", 12 );
	}
	animState( ANIMCHANNEL_LEGS, "Legs_Idle", 12 );
}

void follower::Legs_Run() {
	playCycle( ANIMCHANNEL_LEGS, "run" );
	
	while( AI_FORWARD && run )	{
		waitFrame();
	}
	
	if ( AI_FORWARD ) {
		animState( ANIMCHANNEL_LEGS, "Legs_Walk", 12 );
	}
	animState( ANIMCHANNEL_LEGS, "Legs_Idle", 12 );
}

void follower::Legs_TurnLeft() {
	float turnAmount;
	
	turnAmount = getTurnDelta();
	if ( turnAmount > 110 ) {
		// do it in two turns
		turnAmount *= 0.5;
	}

	playAnim( ANIMCHANNEL_LEGS, "turn_left" );
	while( !animDone( ANIMCHANNEL_LEGS, 0 ) ) {
		waitFrame();
	}
	
	playAnim( ANIMCHANNEL_LEGS, "turn_right" );
	while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
		waitFrame();
	}
	
	animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
}

void follower::Legs_TurnRight() {
	float turnAmount;
	
	turnAmount = getTurnDelta();
	if ( turnAmount < -110 ) {
		// do it in two turns
		turnAmount *= 0.5;
	}

	playAnim( ANIMCHANNEL_LEGS, "turn_right" );
	while( !animDone( ANIMCHANNEL_LEGS, 0 ) ) {
		waitFrame();
	}
	
	playAnim( ANIMCHANNEL_LEGS, "turn_left" );
	while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
		waitFrame();
	}

	animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
}

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

	AI

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

/*
=====================
follower::init
=====================
*/
void follower::init() {
	inCustomAnim = false;
	run = false;
	
	float mod;
	mod = getIntKey( "head_look" );
	setBoneMod( mod );
	
	setTalkState( TALK_OK );

	self.setKey( "conversationNext", "" );
	
	setKey( "wander", "1" );
	
	animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
	animState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
	setState( "state_Idle" );
}

/*
=====================
follower::playCustomCycle
=====================
*/
void follower::playCustomCycle( string animname, float blendTime ) {
	customAnim = animname;
	animState( ANIMCHANNEL_TORSO, "Torso_CustomCycle", blendTime );
}

/*
=====================
follower::playCustomAnim
=====================
*/
void follower::playCustomAnim( string animname, float blendIn, float blendOut ) {
	customBlendOut = blendOut;
	customAnim = animname;
	inCustomAnim = true;
	animState( ANIMCHANNEL_TORSO, "Torso_CustomAnim", blendIn );
}

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

	States

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

/*
=====================
follower::state_Idle
=====================
*/
void follower::state_Idle() {
	stopMove();
	setTalkTarget( $null_entity );
	while( 1 ) {
		if ( AI_TALK ) {
			setState( "state_Follow" );
		}
		waitFrame();
	}
}

/*
=====================
follower::state_Killed
=====================
*/
void follower::state_Killed() {
	stopMove();
	animState( ANIMCHANNEL_TORSO, "Torso_Death", 0 );
	animState( ANIMCHANNEL_LEGS, "Legs_Death", 0 );

	waitAction( "dead" );
	stopThinking();
}

/*
=====================
follower::state_Follow
=====================
*/
void follower::state_Follow() {
	entity leader;

	leader = getTalkTarget();
	if ( !leader ) {
		leader = $player1;
	}
	setTalkTarget( $null_entity );
	while( 1 ) {
		lookAt( leader, 0.1 );
		if ( AI_TALK ) {
			setState( "state_Idle" );
		}
		if ( distanceTo( leader ) > FOLLOW_MAXDIST ) {
			getCloser();
		} else {
			faceEntity( leader );
		}
		waitFrame();
	}
}

void follower::getCloser() {
	entity leader;

	leader = getTalkTarget();
	if ( !leader ) {
		leader = $player1;
	}
	setTalkTarget( $null_entity );
	run = false;
	moveToEntity( leader );
	while( !AI_DEST_UNREACHABLE && !AI_MOVE_DONE && ( distanceTo( leader ) > FOLLOW_MINDIST ) ) {
		lookAt( leader, 0.1 );
		if ( distanceTo( leader ) > FOLLOW_RUNDIST ) {
			run = true;
		}
		if ( distanceTo( leader ) < FOLLOW_MAXDIST ) {
			run = false;
		}
		if ( AI_TALK ) {
			setState( "state_Idle" );
		}
			
		waitFrame();
	}
	stopMove();
}
