



#include "../Game_local.h"

class rvMonsterTurretFlying : public idAI {
public:

	CLASS_PROTOTYPE( rvMonsterTurretFlying );

	rvMonsterTurretFlying ( void );

	void				InitSpawnArgsVariables( void );
	void				Spawn				( void );
	void				Save				( idSaveGame *savefile ) const;
	void				Restore				( idRestoreGame *savefile );

	virtual bool		Pain				( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );

	virtual bool		CheckActions					( void );

protected:

	stateResult_t		State_Combat				( const stateParms_t& parms );
	stateResult_t		State_Fall					( const stateParms_t& parms );
	stateResult_t		State_Killed				( const stateParms_t& parms );

	stateResult_t		State_Torso_Idle			( const stateParms_t& parms );
	stateResult_t		State_Legs_Idle				( const stateParms_t& parms );

	stateResult_t		State_Torso_BlasterAttack	( const stateParms_t& parms );

	int					shieldHealth;
	int					maxShots;	
	int					minShots;
	int					shots;

private:

	rvAIAction			actionBlasterAttack;

	CLASS_STATES_PROTOTYPE ( rvMonsterTurretFlying );
};

CLASS_DECLARATION( idAI, rvMonsterTurretFlying )
END_CLASS

/*
================
rvMonsterTurretFlying::rvMonsterTurretFlying
================
*/
rvMonsterTurretFlying::rvMonsterTurretFlying ( ) {
	shieldHealth = spawnArgs.GetInt ( "shieldHealth" );
}

void rvMonsterTurretFlying::InitSpawnArgsVariables( void )
{
	maxShots	= spawnArgs.GetInt ( "maxShots", "1" );
	minShots	= spawnArgs.GetInt ( "minShots", "1" );
}
/*
================
rvMonsterTurretFlying::Spawn
================
*/
void rvMonsterTurretFlying::Spawn ( void ) {
	shieldHealth = spawnArgs.GetInt ( "shieldHealth" );

	InitSpawnArgsVariables();
	shots		= 0;
	
	actionBlasterAttack.Init ( spawnArgs,	"action_blasterAttack",	"Torso_BlasterAttack",	AIACTIONF_ATTACK );

	//don't take damage until we open up
	fl.takedamage = false;
}

/*
================
rvMonsterTurretFlying::CheckActions
================
*/
bool rvMonsterTurretFlying::CheckActions ( void ) {
	// Attacks
	if ( PerformAction ( &actionBlasterAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ) {
		return true;
	}
	return idAI::CheckActions ( );
}


/*
================
rvMonsterTurretFlying::Pain
================
*/
bool rvMonsterTurretFlying::Pain ( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
	// Handle the shield effects
	if ( shieldHealth > 0 ) {
		shieldHealth -= damage;
		if ( shieldHealth <= 0 ) {
			PlayEffect ( "fx_shieldBreak", GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3() );
		} else {
			PlayEffect ( "fx_shieldHit", GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3() );
		}
	}

	return idAI::Pain ( inflictor, attacker, damage, dir, location );
}

/*
================
rvMonsterTurretFlying::Save
================
*/
void rvMonsterTurretFlying::Save( idSaveGame *savefile ) const {
	savefile->WriteInt ( shieldHealth );
	savefile->WriteInt ( shots );
	actionBlasterAttack.Save ( savefile ) ;	
}

/*
================
rvMonsterTurretFlying::Restore
================
*/
void rvMonsterTurretFlying::Restore( idRestoreGame *savefile ) {
	savefile->ReadInt ( shieldHealth );
	savefile->ReadInt ( shots );
	actionBlasterAttack.Restore ( savefile ) ;	

	InitSpawnArgsVariables();
}

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

	States 

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

CLASS_STATES_DECLARATION ( rvMonsterTurretFlying )
	STATE ( "State_Combat",			rvMonsterTurretFlying::State_Combat )
	STATE ( "State_Fall",			rvMonsterTurretFlying::State_Fall )
	STATE ( "State_Killed",			rvMonsterTurretFlying::State_Killed )

	STATE ( "Torso_Idle",			rvMonsterTurretFlying::State_Torso_Idle )
	STATE ( "Legs_Idle",			rvMonsterTurretFlying::State_Legs_Idle )
	
	STATE ( "Torso_BlasterAttack",	rvMonsterTurretFlying::State_Torso_BlasterAttack )
END_CLASS_STATES

/*
================
rvMonsterTurretFlying::State_Combat
================
*/
stateResult_t rvMonsterTurretFlying::State_Combat ( const stateParms_t& parms ) {
	// Special handling for not being on the ground
	if ( !move.fl.onGround ) {
		PostState ( "State_Fall", 0 );
		return SRESULT_DONE;
	}
	
	// Keep the enemy status up to date
	if ( !enemy.ent || enemy.fl.dead ) {
		enemy.fl.dead = false;
		CheckForEnemy ( true );
	}
			
	// try moving, if there was no movement run then just try and action instead
	UpdateAction ( );
		
	return SRESULT_WAIT;
}

/*
================
rvMonsterTurretFlying::State_Fall
================
*/
stateResult_t rvMonsterTurretFlying::State_Fall ( const stateParms_t& parms ) {
	enum {
		STAGE_INIT,			// Initialize fall stage
		STAGE_WAITIMPACT,	// Wait for the drop turret to hit the ground
		STAGE_IMPACT,		// Handle drop turret impact
		STAGE_WAITOPEN,		// Wait for drop turret to open up
		STAGE_OPENED,		// Drop turret opened and ready for combat
	};
	switch ( parms.stage ) {
		case STAGE_INIT:
			StopMove ( MOVE_STATUS_DONE );
			StartSound ( "snd_falling", SND_CHANNEL_VOICE, 0, false, NULL );
			PlayEffect ( "fx_droptrail", animator.GetJointHandle ( "origin" ), true );
			PlayCycle ( ANIMCHANNEL_TORSO, "idle_closed", 0 );
			return SRESULT_STAGE(STAGE_WAITIMPACT);
			
		case STAGE_WAITIMPACT:
			if ( move.fl.onGround ) {
				return SRESULT_STAGE(STAGE_IMPACT);
			}
			return SRESULT_WAIT;
			
		case STAGE_IMPACT:
			StopSound ( SND_CHANNEL_VOICE, false );
			StopEffect ( "fx_droptrail" );
			PlayEffect ( "fx_landing", GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3() );
			PlayAnim ( ANIMCHANNEL_TORSO, "open", 2 );
			return SRESULT_STAGE ( STAGE_WAITOPEN );
		
		case STAGE_WAITOPEN:
			if ( AnimDone ( ANIMCHANNEL_TORSO, 0 ) ) {
				return SRESULT_STAGE ( STAGE_OPENED );
			}
			return SRESULT_WAIT;
		
		case STAGE_OPENED:		 
			// Activate shield
			fl.takedamage = true;
			health += shieldHealth;
			PlayEffect ( "fx_shieldOpen", GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3() );
			SetAnimState ( ANIMCHANNEL_TORSO, "Torso_Idle", 2 );
			PostState ( "State_Combat" );
			return SRESULT_DONE;
	}
	return SRESULT_ERROR;
}

/*
================
rvMonsterTurretFlying::State_Killed
================
*/
stateResult_t rvMonsterTurretFlying::State_Killed ( const stateParms_t& parms ) {
	gameLocal.PlayEffect ( spawnArgs, "fx_death", GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3() );
	gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 128.0f, true, 96.0f, "textures/decals/genericdamage" );
	return idAI::State_Killed ( parms );
}
	
/*
================
rvMonsterTurretFlying::State_Torso_Idle
================
*/
stateResult_t rvMonsterTurretFlying::State_Torso_Idle ( const stateParms_t& parms ) {
	if ( move.fl.onGround ) {
		IdleAnim ( ANIMCHANNEL_TORSO, "idle_open", parms.blendFrames );
	} else {
		IdleAnim ( ANIMCHANNEL_TORSO, "idle_closed", parms.blendFrames );
	}
	return SRESULT_DONE;
}

/*
================
rvMonsterTurretFlying::State_Legs_Idle
================
*/
stateResult_t rvMonsterTurretFlying::State_Legs_Idle ( const stateParms_t& parms ) {
	return SRESULT_DONE;
}

/*
================
rvMonsterTurretFlying::State_Torso_BlasterAttack
================
*/
stateResult_t rvMonsterTurretFlying::State_Torso_BlasterAttack ( const stateParms_t& parms ) {
	enum { 
		STAGE_INIT,
		STAGE_FIRE,
		STAGE_WAIT,
	};
	switch ( parms.stage ) {
		case STAGE_INIT:
			DisableAnimState ( ANIMCHANNEL_LEGS );
			shots = (minShots + gameLocal.random.RandomInt(maxShots-minShots+1)) * combat.aggressiveScale;
			return SRESULT_STAGE ( STAGE_FIRE );
			
		case STAGE_FIRE:
			PlayAnim ( ANIMCHANNEL_TORSO, (shots&1)?"range_attack_top":"range_attack_bottom", 2 );
			return SRESULT_STAGE ( STAGE_WAIT );

		case STAGE_WAIT:
			if ( AnimDone ( ANIMCHANNEL_TORSO, 2 ) ) {
				if ( --shots <= 0 ) {
					return SRESULT_DONE;
				}
				return SRESULT_STAGE ( STAGE_FIRE );
			}
			return SRESULT_WAIT;
	}
	return SRESULT_ERROR; 
}
