//-----------------------------------------------------------------------------
//
//  $Logfile:: /EF2/Code/DLLs/game/stationaryFireCombatEX.cpp                 $
// $Revision:: 7                                                              $
//   $Author:: Singlis                                                        $
//     $Date:: 9/26/03 2:36p                                                  $
//
// Copyright (C) 2002 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:
//	StationaryFireCombatEX Implementation
// 
// PARAMETERS:
//
// ANIMATIONS:
//--------------------------------------------------------------------------------

#include "actor.h"
#include "stationaryFireCombatEX.hpp"
#include <qcommon/gameplaymanager.h>

//--------------------------------------------------------------
//
// Class Declaration and Event Registration
//
//--------------------------------------------------------------
CLASS_DECLARATION( Behavior, StationaryFireCombatEX, NULL )
	{
		{ &EV_Behavior_Args,		&StationaryFireCombatEX::SetArgs	},
		{ &EV_Behavior_AnimDone,	&StationaryFireCombatEX::AnimDone	}, 
		{ NULL, NULL }
	};


//--------------------------------------------------------------
// Name:		StationaryFireCombatEX()
// Class:		StationaryFireCombatEX
//
// Description:	Constructor
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
StationaryFireCombatEX::StationaryFireCombatEX()
{	
	_endFireTime		= 0.0f;
	_endAimTime			= 0.0f;
}	

//--------------------------------------------------------------
// Name:		~StationaryFireCombatEX()
// Class:		StationaryFireCombatEX
//
// Description:	Destructor
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
StationaryFireCombatEX::~StationaryFireCombatEX()
{
}

//--------------------------------------------------------------
// Name:        SetArgs()
// Class:       StationaryFireCombatEX
//
// Description: Sets Arguments for this behavior
//
// Parameters:  Event *ev -- Event holding the arguments
//
// Returns:     None
//--------------------------------------------------------------
void StationaryFireCombatEX::SetArgs( Event *ev )
{		
	_stance			= ev->GetString( 1 );
	_aimTimeMin		= ev->GetFloat( 2 );
	_aimTimeMax		= ev->GetFloat( 3 );
	_fireTimeMin	= ev->GetFloat( 4 );
	_fireTimeMax	= ev->GetFloat( 5 );
	_forceAttack	= ev->GetBoolean( 6 );	

}



//--------------------------------------------------------------
// Name:        AnimDone()
// Class:       StationaryFireCombatEX
//
// Description: Handles an animation completion
//
// Parameters:  Event *ev -- Event holding the completion notification
//
// Returns:     None
//--------------------------------------------------------------
void StationaryFireCombatEX::AnimDone( Event *ev )
{
	_animDone = true;
}



//--------------------------------------------------------------
// Name:        Begin()
// Class:       StationaryFireCombatEX
//
// Description: Initializes the behavior
//
// Parameters:  Actor &self -- The actor executing this behavior
//
// Returns:     None
//--------------------------------------------------------------
void StationaryFireCombatEX::Begin( Actor &self )
{       
	init( self );
	transitionToState ( STATIONARY_FIRE_AIM );
}


//--------------------------------------------------------------
// Name:        Evaluate()
// Class:       StationaryFireCombatEX
//
// Description: Evaluates the behavior
//
// Parameters:  Actor &self -- The actor executing this behavior
//
// Returns:     BehaviorReturnCode_t 
//--------------------------------------------------------------
BehaviorReturnCode_t StationaryFireCombatEX::Evaluate( Actor &self )
{
	BehaviorReturnCode_t stateResult;

	think();
	
	switch ( _state )
		{
		//---------------------------------------------------------------------
		case STATIONARY_FIRE_AIM:
		//---------------------------------------------------------------------		
			stateResult = evaluateStateAim();

			if ( stateResult == BEHAVIOR_SUCCESS )
				{
				updateEnemy();
				if ( _preFireAnim.length() )
					transitionToState( STATIONARY_FIRE_PRE_FIRE );
				else
					transitionToState( STATIONARY_FIRE_ATTACK );
				}
				
		break;

		//---------------------------------------------------------------------
		case STATIONARY_FIRE_PRE_FIRE:
		//---------------------------------------------------------------------
			stateResult = evaluateStatePreFire();

			if ( stateResult == BEHAVIOR_SUCCESS )
				{
					transitionToState( STATIONARY_FIRE_ATTACK );	
				}

			if ( stateResult == BEHAVIOR_FAILED )
				{
				transitionToState( STATIONARY_FIRE_FAILED );
				}
			
		break;

		//---------------------------------------------------------------------
		case STATIONARY_FIRE_ATTACK:
		//---------------------------------------------------------------------		
			stateResult = evaluateStateAttack();

			if ( stateResult == BEHAVIOR_SUCCESS )
				{
				_fireWeapon.End( *_self );

				if ( _postFireAnim.length() )
					transitionToState( STATIONARY_FIRE_POST_FIRE );
				else
					transitionToState( STATIONARY_FIRE_SUCCESS );
				}

			if ( stateResult == BEHAVIOR_FAILED )
				{
				_fireWeapon.End( *_self );

				if ( _postFireAnim.length() )
					transitionToState( STATIONARY_FIRE_POST_FIRE );
				else
					transitionToState( STATIONARY_FIRE_SUCCESS );
				}

		break;


		//---------------------------------------------------------------------
		case STATIONARY_FIRE_POST_FIRE:
		//---------------------------------------------------------------------
			stateResult = evaluateStatePostFire();

			if ( stateResult == BEHAVIOR_SUCCESS )
				{
					transitionToState( STATIONARY_FIRE_SUCCESS );	
				}
		break;

		//---------------------------------------------------------------------
		case STATIONARY_FIRE_SUCCESS:
		//---------------------------------------------------------------------
			return BEHAVIOR_SUCCESS;

		break;


		//---------------------------------------------------------------------
		case STATIONARY_FIRE_FAILED:
		//---------------------------------------------------------------------
			return BEHAVIOR_FAILED;

		break;


		}
	

	return BEHAVIOR_EVALUATING;   

}



//--------------------------------------------------------------
// Name:        End()
// Class:       StationaryFireCombatEX
//
// Description: Cleans Up the behavior
//
// Parameters:  Actor &self -- The actor executing this behavior
//
// Returns:     None
//--------------------------------------------------------------
void StationaryFireCombatEX::End(Actor &self)
{ 
	if ( !_self )
		return;

	_fireWeapon.End(*_self);
	_self->SetAnim( _aimAnim , NULL , torso );
}



//--------------------------------------------------------------
// Name:		transitionToState()
// Class:		StationaryFireCombatEX
//
// Description:	Transitions the behaviors state
//
// Parameters:	coverCombatStates_t state -- The state to transition to
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::transitionToState( StationaryFireStates_t state )
{	
	switch ( state )
		{	
		case STATIONARY_FIRE_AIM:
			setupStateAim();
			setInternalState( state , "STATIONARY_FIRE_AIM" );
		break;

		case STATIONARY_FIRE_PRE_FIRE:
			setupStatePreFire();
			setInternalState( state , "STATIONARY_FIRE_PRE_FIRE" );
		break;

		case STATIONARY_FIRE_ATTACK:
			setupStateAttack();
			setInternalState( state , "STATIONARY_FIRE_ATTACK" );
		break;

		case STATIONARY_FIRE_POST_FIRE:
			setupStatePostFire();
			setInternalState( state , "STATIONARY_FIRE_POST_FIRE" );
		break;

		case STATIONARY_FIRE_SUCCESS:
			setInternalState( state , "STATIONARY_FIRE_SUCCESS" );
		break;

		case STATIONARY_FIRE_FAILED:
			setInternalState( state , "SUPPRESSION_FIRE_FAILED" );
		break;
		}
	
}


//--------------------------------------------------------------
// Name:		setInternalState()
// Class:		StationaryFireCombatEX
//
// Description:	Sets the internal state of the behavior
//
// Parameters:	unsigned int state
//				const str &stateName
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::setInternalState( StationaryFireStates_t state , const str &stateName )
{
	_state = state;
	SetInternalStateName( stateName );
}

//--------------------------------------------------------------
// Name:		init()
// Class:		StationaryFireCombatEX
//
// Description:	Initializes the behavior
//
// Parameters:	Actor &self
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::init( Actor &self )
{
	_self = &self;	
	_animDone = false;
	_canAttack = true;

	_aimAnim		= "idle";
	_preFireAnim	= "idle";
	_fireAnim		= "idle";
	_postFireAnim	= "idle";

	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	if ( !gpm->hasObject(self.getArchetype()) )
		return;
		
	str objname = self.combatSubsystem->GetActiveWeaponArchetype();	
	objname = "Hold" + objname;

	if ( gpm->hasProperty(objname, "Idle") )
		_aimAnim = gpm->getStringValue( objname , "Idle" );
	
	if ( gpm->hasProperty( objname , "PreFire" ) )
		_preFireAnim = gpm->getStringValue( objname , "PreFire" );

	if ( gpm->hasProperty( objname , "Fire" ) )
		_fireAnim = gpm->getStringValue( objname , "Fire" );

	if ( gpm->hasProperty( objname , "PostFire" ) )
		_postFireAnim = gpm->getStringValue( objname , "PostFire" );

	_stance = self.GetStateVar( _stance );

	if ( !_stance.length() )
		_stance = "idle";

	updateEnemy();
}

//--------------------------------------------------------------
// Name:		think()
// Class:		StationaryFireCombatEX
//
// Description:	Does any processing required before evaluating states
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::think()
{
}

//--------------------------------------------------------------
// Name:		StationaryFireCombat()
// Class:		StationaryFireCombatEX
//
// Description:	Sets up our Attack State
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::setupStateAttack()
{
	faceEnemy();
	_endFireTime = level.time + G_Random(_fireTimeMax - _fireTimeMin) + _fireTimeMin;

	if ( _self->combatSubsystem->CanAttackEnemy() || _forceAttack )
		{	
		_fireWeapon.SetAnim( _fireAnim ); 
		_fireWeapon.Begin( *_self );
		}

}

//--------------------------------------------------------------
// Name:		evaluateStateAttack()
// Class:		StationaryFireCombatEX
//
// Description:	Evaluates our Attack State
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
BehaviorReturnCode_t StationaryFireCombatEX::evaluateStateAttack()
{
	BehaviorReturnCode_t result;
	_rotateToEntity.Evaluate( *_self );
	
	if ( _self->combatSubsystem->CanAttackEnemy() || _forceAttack )
		result = _fireWeapon.Evaluate( *_self );
	else
		{
		_fireWeapon.End( *_self );
		result = BEHAVIOR_FAILED;
		}

	if ( result == BEHAVIOR_FAILED )
		failureStateAttack( "StationaryFireCombat::evaluateStateAttack -- FAILED" );

	if ( level.time > _endFireTime )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
}

//--------------------------------------------------------------
// Name:		failureStateAttack()
// Class:		StationaryFireCombatEX
//
// Description:	Failure Handler for Attack State
//
// Parameters:	const str &failureReason
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::failureStateAttack( const str &failureReason )
{
	SetFailureReason( failureReason );
	_fireWeapon.End( *_self );
}

//--------------------------------------------------------------
// Name:		setupStatePause()
// Class:		StationaryFireCombatEX
//
// Description:	Sets up our Pause State
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::setupStateAim()
{
	faceEnemy();
	_endAimTime = level.time + G_Random(_aimTimeMax - _aimTimeMin ) + _aimTimeMin;
	_self->SetAnim( _aimAnim , NULL , torso );
	_self->SetAnim( _stance , NULL , legs );

}

//--------------------------------------------------------------
// Name:		evaluateStatePause()
// Class:		StationaryFireCombatEX
//
// Description:	Evaluates our Pause State
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
BehaviorReturnCode_t StationaryFireCombatEX::evaluateStateAim()
{
	_rotateToEntity.Evaluate( *_self );
	if ( level.time > _endAimTime )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_EVALUATING;
}


//--------------------------------------------------------------
// Name:		failureStatePause()
// Class:		StationaryFireCombatEX
//
// Description:	Failure Handler for our Pause State
//
// Parameters:	const str &failureReason
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::failureStateAim( const str &failureReason )
{
	SetFailureReason( failureReason );
}


void StationaryFireCombatEX::setupStatePreFire()
{
	if ( _self->combatSubsystem->CanAttackEnemy() || _forceAttack )
		{
		_animDone = false;
		_self->SetAnim( _preFireAnim , EV_Actor_NotifyBehavior , torso );
		}
	else
		_canAttack = false;
}

BehaviorReturnCode_t StationaryFireCombatEX::evaluateStatePreFire()
{
	if ( _animDone )
		return BEHAVIOR_SUCCESS;

	if ( !_canAttack )
		return BEHAVIOR_FAILED;

	return BEHAVIOR_EVALUATING;
}

void StationaryFireCombatEX::failureStatePreFire( const str &failureReason )
{
}

void StationaryFireCombatEX::setupStatePostFire()
{
	_animDone = false;
	_self->SetAnim( _postFireAnim , EV_Actor_NotifyBehavior , torso );

}

BehaviorReturnCode_t StationaryFireCombatEX::evaluateStatePostFire()
{
	if ( _animDone )
		return BEHAVIOR_SUCCESS;

	return BEHAVIOR_FAILED;

}

void StationaryFireCombatEX::failureStatePostFire( const str &failureReason )
{
}

//--------------------------------------------------------------
// Name:		updateEnemy()
// Class:		StationaryFireCombatEX
//
// Description:	Sets our _currentEnemy
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::updateEnemy()
{
	//
	// First, we try and get our current enemy.  If we don't have one
	// then we ask the enemyManager to evaluate and try again.
	// If that fails, then we look at our _forceAttack status.
	// If we are forcing and attack, then that means we want to
	// fire pretty much no matter what... So if we don't have a 
	// currentEnemy, then I'm going to see if the Player is a valid
	// target, and set that to be the current enemy
	Entity *currentEnemy = _self->enemyManager->GetCurrentEnemy();
	if ( !currentEnemy )
		{
		_self->enemyManager->FindHighestHateEnemy();
		currentEnemy = _self->enemyManager->GetCurrentEnemy();
		if ( !currentEnemy )
			{
			Player* player;
			player = GetPlayer( 0 );

			if ( player && GetSelf()->enemyManager->Hates(player) && _forceAttack )
				{
				currentEnemy = player;
				GetSelf()->enemyManager->SetCurrentEnemy( currentEnemy );
				}
			else
				{
				SetFailureReason( "STATIONARY_FIRE_FAILED::updateEnemy -- No Enemy" );
				transitionToState( STATIONARY_FIRE_FAILED );
				return;
				}
			}
			
		}

	_currentEnemy = currentEnemy;
	_self->turnTowardsEntity( _currentEnemy, 0.0f );	
}

//--------------------------------------------------------------
// Name:		faceEnemy()
// Class:		StationaryFireCombat
//
// Description:	Sets up the Rotate Component
//
// Parameters:	None
//
// Returns:		None
//--------------------------------------------------------------
void StationaryFireCombatEX::faceEnemy()
{
	_rotateToEntity.SetEntity( _currentEnemy );
	_rotateToEntity.SetTurnSpeed( 30.0f );
	_rotateToEntity.Begin( *_self );	

}






















