quake4-sdk/source/mpgame/ai/Monster_NetworkGuardian.cpp
2007-06-15 00:00:00 +00:00

822 lines
22 KiB
C++

#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
class rvMonsterNetworkGuardian : public idAI {
public:
CLASS_PROTOTYPE( rvMonsterNetworkGuardian );
rvMonsterNetworkGuardian ( void );
void Spawn ( void );
void Save ( idSaveGame *savefile ) const;
void Restore ( idRestoreGame *savefile );
protected:
virtual bool CheckActions ( void );
int shots;
int landTime;
int flagFlying;
float strafeSpeed;
//this flag allows the AI to control when it takes off and lands.
bool flagAutopilot;
int battleStage;
enum {
FLY_NONE = 0,
FLY_TRANSITION,
FLY_FLYING,
};
private:
rvAIAction actionShotgunRocketAttack;
rvAIAction actionFlyingRangedAttack;
rvAIAction actionFlyingSweepAttack;
rvAIAction actionMeleeAttack;
rvAIAction actionBlasterSweepGround;
rvAIAction actionBlasterAttack;
rvAIAction actionMIRVAttack;
stateResult_t State_Wait_Flying ( const stateParms_t& parms );
// stateResult_t State_Dead ( const stateParms_t& parms );
// walking melee attacks
// walking ranged attacks
stateResult_t State_Torso_ShotgunRocket ( const stateParms_t& parms );
stateResult_t State_Torso_BlasterSweepGround ( const stateParms_t& parms );
stateResult_t State_Torso_BlasterAttack ( const stateParms_t& parms );
stateResult_t State_Torso_MIRVAttack ( const stateParms_t& parms );
//flying evades
stateResult_t State_Torso_EvadeLeft ( const stateParms_t& parms );
stateResult_t State_Torso_EvadeRight ( const stateParms_t& parms );
//flying ranged attacks
stateResult_t State_Torso_FlyingRanged ( const stateParms_t& parms );
stateResult_t State_Torso_FlyingSweep ( const stateParms_t& parms );
// flying anims
stateResult_t State_Torso_LiftOff ( const stateParms_t& parms );
stateResult_t State_Torso_Fall ( const stateParms_t& parms );
// walking turn anims
stateResult_t State_Torso_TurnRight90 ( const stateParms_t& parms );
stateResult_t State_Torso_TurnLeft90 ( const stateParms_t& parms );
//force the NG into walking mode. This does not play the landing anim, and will make him fall from the sky.
void Event_ForceWalkMode( void );
//These commands change the NG's state, but do so through states and animations.
void Event_ForceLanding( void );
void Event_ForceTakeoff( void );
//toggles the NG between AI controlled flight and script controlled flight
void Event_AllowAutopilot( float f);
//for staged combat, sets the int value of the battle stage
void Event_SetBattleStage( float f);
CLASS_STATES_PROTOTYPE ( rvMonsterNetworkGuardian );
};
const idEventDef EV_ForceWalkMode( "forceWalkMode" );
const idEventDef EV_ForceLanding( "forceLanding" );
const idEventDef EV_ForceTakeoff( "forceTakeoff" );
const idEventDef EV_AllowAutopilot( "allowAutopilot", "f" );
const idEventDef EV_SetBattleStage( "setBattleStage", "f" );
CLASS_DECLARATION( idAI, rvMonsterNetworkGuardian )
EVENT( EV_ForceWalkMode, rvMonsterNetworkGuardian::Event_ForceWalkMode )
EVENT( EV_ForceLanding, rvMonsterNetworkGuardian::Event_ForceLanding )
EVENT( EV_ForceTakeoff, rvMonsterNetworkGuardian::Event_ForceTakeoff )
EVENT( EV_AllowAutopilot, rvMonsterNetworkGuardian::Event_AllowAutopilot )
EVENT( EV_SetBattleStage, rvMonsterNetworkGuardian::Event_SetBattleStage )
END_CLASS
/*
================
rvMonsterNetworkGuardian::rvMonsterNetworkGuardian
================
*/
rvMonsterNetworkGuardian::rvMonsterNetworkGuardian ( ) {
shots = 0;
landTime = 0;
flagFlying = FLY_NONE;
battleStage = 1;
strafeSpeed = 0;
}
/*
================
rvMonsterNetworkGuardian::Spawn
================
*/
void rvMonsterNetworkGuardian::Spawn ( void ) {
disablePain = true;
flagAutopilot = false;
strafeSpeed = spawnArgs.GetFloat( "strafeSpeed", "500" );
actionShotgunRocketAttack.Init ( spawnArgs, "action_ShotgunRocket", "Torso_ShotgunRocket_Attack", AIACTIONF_ATTACK );
actionFlyingRangedAttack.Init( spawnArgs, "action_FlyingRangedAttack", "Torso_FlyingRanged_Attack", AIACTIONF_ATTACK );
actionFlyingSweepAttack.Init( spawnArgs, "action_blasterSweepAirAttack", "Torso_FlyingSweep_Attack", AIACTIONF_ATTACK );
actionMeleeAttack.Init( spawnArgs, "action_meleeAttack", NULL, AIACTIONF_ATTACK );
actionBlasterSweepGround.Init( spawnArgs, "action_blasterSweepGroundAttack", "Torso_BlasterSweepGround_Attack", AIACTIONF_ATTACK );
actionBlasterAttack.Init( spawnArgs, "action_blasterAttack", "Torso_Blaster_Attack", AIACTIONF_ATTACK );
actionMIRVAttack.Init( spawnArgs, "action_MIRVAttack", "Torso_MIRV_Attack", AIACTIONF_ATTACK );
}
/*
================
rvMonsterNetworkGuardian::Save
================
*/
void rvMonsterNetworkGuardian::Save ( idSaveGame *savefile ) const {
savefile->WriteInt( shots );
savefile->WriteInt( landTime );
savefile->WriteInt( flagFlying );
savefile->WriteInt( battleStage );
savefile->WriteBool( flagAutopilot );
savefile->WriteFloat( strafeSpeed );
actionShotgunRocketAttack.Save( savefile );
actionFlyingRangedAttack.Save( savefile );
actionFlyingSweepAttack.Save( savefile );
actionMeleeAttack.Save( savefile );
actionBlasterSweepGround.Save( savefile );
actionBlasterAttack.Save( savefile );
actionMIRVAttack.Save( savefile );
}
/*
================
rvMonsterNetworkGuardian::Restore
================
*/
void rvMonsterNetworkGuardian::Restore ( idRestoreGame *savefile )
{
savefile->ReadInt( shots );
savefile->ReadInt( landTime );
savefile->ReadInt( flagFlying );
savefile->ReadInt( battleStage );
savefile->ReadBool( flagAutopilot );
savefile->ReadFloat( strafeSpeed );
actionShotgunRocketAttack.Restore( savefile );
actionFlyingRangedAttack.Restore( savefile );
actionFlyingSweepAttack.Restore( savefile );
actionMeleeAttack.Restore( savefile );
actionBlasterSweepGround.Restore( savefile );
actionBlasterAttack.Restore( savefile );
actionMIRVAttack.Restore( savefile );
}
/*
================
rvMonsterNetworkGuardian::CheckActions
================
*/
bool rvMonsterNetworkGuardian::CheckActions ( void ) {
// If not moving, try turning in place
if ( !move.fl.moving && gameLocal.time > combat.investigateTime )
{
float turnYaw = idMath::AngleNormalize180 ( move.ideal_yaw - move.current_yaw ) ;
if ( turnYaw > lookMax[YAW] * 0.75f )
{
PerformAction ( "Torso_TurnRight90", 4, true );
return true;
}
else if ( turnYaw < -lookMax[YAW] * 0.75f )
{
PerformAction ( "Torso_TurnLeft90", 4, true );
return true;
}
}
//if the flight is transitioning, do nothing
if( flagFlying == FLY_TRANSITION ) {
return false;
}
//this is the autopilot section.
if( flagAutopilot ) {
// If he's been on the ground long enough, fly...
if ( move.moveType == MOVETYPE_ANIM && move.fl.onGround && !flagFlying && gameLocal.time > landTime )
{
PostState ( "Wait_Flying" );
SetAnimState ( ANIMCHANNEL_TORSO, "Torso_LiftOff", 4 );
disablePain = true;
actionMeleeAttack.fl.disabled = true;
flagFlying = FLY_TRANSITION;
return true;
}
else if ( move.moveType == MOVETYPE_FLY && gameLocal.time > landTime )
{
SetMoveType ( MOVETYPE_ANIM );
animPrefix = "";
move.fl.noGravity = false;
physicsObj.UseFlyMove ( false );
actionMeleeAttack.fl.disabled = false;
flagFlying = FLY_TRANSITION;
SetAnimState ( ANIMCHANNEL_TORSO, "Torso_Fall", 4 );
PostAnimState ( ANIMCHANNEL_TORSO, "Torso_FinishAction", 0, SFLAG_ONCLEAR );
PostAnimState ( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
return true;
}
}
//Normal actions here -----------
//if he's close enough for melee, use melee
if( flagFlying == FLY_NONE) {
if( PerformAction ( &actionMeleeAttack, (checkAction_t)&idAI::CheckAction_MeleeAttack, NULL ) ) {
return true;
}
}
//check for ranged attacks on the ground
if( flagFlying == FLY_NONE ) {
switch (battleStage) {
case 1:
if( PerformAction ( &actionShotgunRocketAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ||
PerformAction ( &actionBlasterAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ||
PerformAction ( &actionBlasterSweepGround, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ) {
return true;
}
break;
case 2:
if( PerformAction ( &actionMIRVAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ||
PerformAction ( &actionBlasterAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ||
PerformAction ( &actionBlasterSweepGround, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ||
PerformAction ( &actionShotgunRocketAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ) {
return true;
}
break;
default:
gameLocal.Error("Bad battleStage '%d' set for Network Guardian.", battleStage);
break;
}
}
//airborne attack actions
if( (flagFlying == FLY_FLYING) ) {
if( PerformAction ( &actionEvadeLeft, (checkAction_t)&idAI::CheckAction_EvadeLeft, &actionTimerEvade ) ||
PerformAction ( &actionEvadeRight, (checkAction_t)&idAI::CheckAction_EvadeRight, &actionTimerEvade ) ||
PerformAction ( &actionFlyingRangedAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ||
PerformAction ( &actionFlyingSweepAttack, (checkAction_t)&idAI::CheckAction_RangedAttack, &actionTimerRangedAttack ) ){
return true;
}
}
//No.
//return idAI::CheckActions ( );
return false;
}
/*
===============================================================================
Events
===============================================================================
*/
/*
================
rvMonsterNetworkGuardian::Event_ForceWalkMode
================
*/
// forces NG to obey gravity and immediately switch to walking mode.
void rvMonsterNetworkGuardian::Event_ForceWalkMode( void ) {
SetMoveType ( MOVETYPE_ANIM );
animPrefix = "";
move.fl.noGravity = false;
physicsObj.UseFlyMove ( false );
actionMeleeAttack.fl.disabled = false;
move.fl.allowDirectional = false;
flagFlying = FLY_NONE;
}
/*
================
rvMonsterNetworkGuardian::Event_ForceLanding
================
*/
// forces NG play his landing animation. He will not just fall from the sky.
void rvMonsterNetworkGuardian::Event_ForceLanding( void ) {
SetMoveType ( MOVETYPE_ANIM );
animPrefix = "";
move.fl.noGravity = false;
physicsObj.UseFlyMove ( false );
actionMeleeAttack.fl.disabled = false;
move.fl.allowDirectional = false;
flagFlying = FLY_TRANSITION;
SetAnimState ( ANIMCHANNEL_TORSO, "Torso_Fall", 4 );
PostAnimState ( ANIMCHANNEL_TORSO, "Torso_FinishAction", 0, SFLAG_ONCLEAR );
//PostAnimState ( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
}
/*
================
rvMonsterNetworkGuardian::Event_ForceTakeoff
================
*/
// forces NG to take off and fly.
void rvMonsterNetworkGuardian::Event_ForceTakeoff( void ) {
disablePain = true;
actionMeleeAttack.fl.disabled = true;
flagFlying = FLY_TRANSITION;
SetAnimState ( ANIMCHANNEL_TORSO, "Torso_LiftOff", 4 );
move.fl.allowDirectional = true;
SetState ( "Wait_Flying" );
}
/*
================
rvMonsterNetworkGuardian::Event_AllowAutoPilot
================
*/
// toggles the AI autoPilot for deciding when to fly and land.
void rvMonsterNetworkGuardian::Event_AllowAutopilot( float f ) {
flagAutopilot = f ? true : false;
}
/*
================
rvMonsterNetworkGuardian::Event_SetBattleStage
================
*/
// sets the current battle stage. Each stage has different behaviors.
void rvMonsterNetworkGuardian::Event_SetBattleStage( float f ) {
battleStage = f;
}
/*
===============================================================================
States
===============================================================================
*/
CLASS_STATES_DECLARATION ( rvMonsterNetworkGuardian )
STATE ( "Wait_Flying", rvMonsterNetworkGuardian::State_Wait_Flying )
STATE ( "State_Dead", rvMonsterNetworkGuardian::State_Dead )
STATE ( "Torso_ShotgunRocket_Attack", rvMonsterNetworkGuardian::State_Torso_ShotgunRocket )
STATE ( "Torso_BlasterSweepGround_Attack", rvMonsterNetworkGuardian::State_Torso_BlasterSweepGround )
STATE ( "Torso_Blaster_Attack", rvMonsterNetworkGuardian::State_Torso_BlasterAttack )
STATE ( "Torso_MIRV_Attack", rvMonsterNetworkGuardian::State_Torso_MIRVAttack)
STATE ( "Torso_EvadeLeft", rvMonsterNetworkGuardian::State_Torso_EvadeLeft )
STATE ( "Torso_EvadeRight", rvMonsterNetworkGuardian::State_Torso_EvadeRight )
STATE ( "Torso_FlyingRanged_Attack", rvMonsterNetworkGuardian::State_Torso_FlyingRanged )
STATE ( "Torso_FlyingSweep_Attack", rvMonsterNetworkGuardian::State_Torso_FlyingSweep )
STATE ( "Torso_LiftOff", rvMonsterNetworkGuardian::State_Torso_LiftOff )
STATE ( "Torso_Fall", rvMonsterNetworkGuardian::State_Torso_Fall )
STATE ( "Torso_TurnRight90", rvMonsterNetworkGuardian::State_Torso_TurnRight90 )
STATE ( "Torso_TurnLeft90", rvMonsterNetworkGuardian::State_Torso_TurnLeft90 )
END_CLASS_STATES
stateResult_t rvMonsterNetworkGuardian::State_Torso_EvadeLeft ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch ( parms.stage ) {
case STAGE_INIT:
{
idVec3 vel = GetPhysics()->GetLinearVelocity();
vel += viewAxis[1] * strafeSpeed;
physicsObj.UseVelocityMove( true );
GetPhysics()->SetLinearVelocity( vel );
PlayAnim ( ANIMCHANNEL_TORSO, "evade_left", parms.blendFrames );
}
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, parms.blendFrames ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
stateResult_t rvMonsterNetworkGuardian::State_Torso_EvadeRight ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch ( parms.stage ) {
case STAGE_INIT:
{
idVec3 vel = GetPhysics()->GetLinearVelocity();
vel += viewAxis[1] * -strafeSpeed;
physicsObj.UseVelocityMove( true );
GetPhysics()->SetLinearVelocity( vel );
PlayAnim ( ANIMCHANNEL_TORSO, "evade_right", parms.blendFrames );
}
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, parms.blendFrames ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Torso_ShotgunRocket
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_ShotgunRocket ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "shotgunRocket_attack", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Torso_BlasterSweepGround
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_BlasterSweepGround ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "attack_spray_grd", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Torso_FlyingSweep
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_FlyingSweep ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "attack_spray_air", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Torso_FlyingRanged
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_FlyingRanged ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "flyingRanged_attack", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Torso_MIRVAttack
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_MIRVAttack ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "attack_vert", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT);
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Wait_Flying
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Wait_Flying ( const stateParms_t& parms ) {
if ( move.moveType == MOVETYPE_ANIM ) {
return SRESULT_WAIT;
}
return SRESULT_DONE;
}
/*
================
rvMonsterNetworkGuardian::State_Dead
================
*/
/*
stateResult_t rvMonsterNetworkGuardian::State_Dead ( const stateParms_t& parms ) {
return SRESULT_DONE;
}*/
/*
================
rvMonsterNetworkGuardian::State_Torso_LiftOff
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_LiftOff ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
};
switch ( parms.stage ) {
case STAGE_INIT:
move.fl.noGravity = true;
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "liftoff", parms.blendFrames );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
SetMoveType ( MOVETYPE_FLY );
landTime = gameLocal.time + DelayTime ( 5000, 10000 );
animPrefix = "fly";
SetAnimState ( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
SetAnimState ( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
flagFlying = FLY_FLYING;
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvMonsterNetworkGuardian::State_Torso_Fall
================
*/
stateResult_t rvMonsterNetworkGuardian::State_Torso_Fall ( const stateParms_t& parms ) {
enum {
STAGE_FALLSTART,
STAGE_FALLSTARTWAIT,
STAGE_FALLLOOPWAIT,
STAGE_FALLENDWAIT
};
switch ( parms.stage ) {
case STAGE_FALLSTART:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "fly_descend_start", parms.blendFrames );
return SRESULT_STAGE ( STAGE_FALLSTARTWAIT );
case STAGE_FALLSTARTWAIT:
if ( move.fl.onGround ) {
PlayAnim ( ANIMCHANNEL_TORSO, "fly_descend_end", 4 );
return SRESULT_STAGE ( STAGE_FALLENDWAIT );
}
if ( AnimDone ( ANIMCHANNEL_TORSO, 0 ) ) {
PlayAnim ( ANIMCHANNEL_TORSO, "fly_descend_loop", 0 );
return SRESULT_STAGE ( STAGE_FALLLOOPWAIT );
}
return SRESULT_WAIT;
case STAGE_FALLLOOPWAIT:
if ( move.fl.onGround ) {
PlayAnim ( ANIMCHANNEL_TORSO, "fly_descend_end", 0 );
return SRESULT_STAGE ( STAGE_FALLENDWAIT );
}
return SRESULT_WAIT;
case STAGE_FALLENDWAIT:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
// we've landed! determine the next fly time
landTime = gameLocal.time + DelayTime ( 10000, 15000 );
flagFlying = FLY_NONE;
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
//================
//rvMonsterNetworkGuardian::State_Torso_TurnRight90
//================
stateResult_t rvMonsterNetworkGuardian::State_Torso_TurnRight90 ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch ( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "turn_left", parms.blendFrames );
AnimTurn ( 90.0f, true );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( move.fl.moving || AnimDone ( ANIMCHANNEL_TORSO, 0 )) {
AnimTurn ( 0, true );
combat.investigateTime = gameLocal.time + 250;
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
//================
//rvMonsterNetworkGuardian::State_Torso_TurnLeft90
//================
stateResult_t rvMonsterNetworkGuardian::State_Torso_TurnLeft90 ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT
};
switch ( parms.stage ) {
case STAGE_INIT:
DisableAnimState ( ANIMCHANNEL_LEGS );
PlayAnim ( ANIMCHANNEL_TORSO, "turn_right", parms.blendFrames );
AnimTurn ( 90.0f, true );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( move.fl.moving || AnimDone ( ANIMCHANNEL_TORSO, 0 )) {
AnimTurn ( 0, true );
combat.investigateTime = gameLocal.time + 250;
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
//================
//rvMonsterNetworkGuardian::State_Torso_BlasterAttack
//================
stateResult_t rvMonsterNetworkGuardian::State_Torso_BlasterAttack ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAITSTART,
STAGE_LOOP,
STAGE_WAITLOOP,
STAGE_WAITEND
};
switch ( parms.stage ) {
case STAGE_INIT:
//if flying, do not override legs
if( (flagFlying != FLY_NONE ) && move.fl.moving ) {
DisableAnimState ( ANIMCHANNEL_LEGS );
}
PlayAnim ( ANIMCHANNEL_TORSO, "attack_blaster_start", parms.blendFrames );
shots = (gameLocal.random.RandomInt ( 12 ) + 8) * combat.aggressiveScale;
return SRESULT_STAGE ( STAGE_WAITSTART );
case STAGE_WAITSTART:
if ( AnimDone ( ANIMCHANNEL_TORSO, 0 ) ) {
return SRESULT_STAGE ( STAGE_LOOP );
}
return SRESULT_WAIT;
case STAGE_LOOP:
PlayAnim ( ANIMCHANNEL_TORSO, "attack_blaster_loop", 0 );
return SRESULT_STAGE ( STAGE_WAITLOOP );
case STAGE_WAITLOOP:
if ( AnimDone ( ANIMCHANNEL_TORSO, 0 ) ) {
if ( --shots <= 0 || (IsEnemyVisible() && !enemy.fl.inFov) ) {
PlayAnim ( ANIMCHANNEL_TORSO, "attack_blaster_end", 0 );
return SRESULT_STAGE ( STAGE_WAITEND );
}
return SRESULT_STAGE ( STAGE_LOOP );
}
return SRESULT_WAIT;
case STAGE_WAITEND:
if ( AnimDone ( ANIMCHANNEL_TORSO, 4 ) ) {
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}