// AI_monster_turret.cpp // Native state-machine replacement for ai_monster_turret.script. #include "precompiled.h" #pragma hdrstop #include "../Game_local.h" rvmMonsterTurret::rvmMonsterTurret() { fire = false; attack_monsters = false; light_is_on = false; attackTime = 0.0f; nextFireTime = 0.0f; shutdownTime = 0.0f; light = NULL; } void rvmMonsterTurret::Init( idAI* aiOwner ) { rvmMonsterBase::Init( aiOwner ); IgnoreDamage(); ambush = true; attack_monsters = GetFloatKey( "team", "1" ) != 1.0f; if ( GetIntKey( "light" ) ) { StartAction( "spawn_light" ); } SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 ); SetState( "state_Begin" ); } stateResult_t rvmMonsterTurret::RunStateByName( const char* stateName, stateParms_t* parms ) { AI_DISPATCH_STATE( "Torso_Death", Torso_Death ); AI_DISPATCH_STATE( "Torso_Idle", Torso_Idle ); AI_DISPATCH_STATE( "Torso_Attack", Torso_Attack ); AI_DISPATCH_STATE( "state_Begin", state_Begin ); AI_DISPATCH_STATE( "state_Idle", state_Idle ); AI_DISPATCH_STATE( "state_Disabled", state_Disabled ); AI_DISPATCH_STATE( "state_Killed", state_Killed ); AI_DISPATCH_STATE( "state_Combat", state_Combat ); AI_DISPATCH_STATE( "combat_attack", combat_attack ); AI_DISPATCH_STATE( "spawn_light", spawn_light ); AI_DISPATCH_STATE( "light_off", light_off ); AI_DISPATCH_STATE( "light_on", light_on ); return rvmMonsterBase::RunStateByName( stateName, parms ); } stateResult_t rvmMonsterTurret::Torso_Death( stateParms_t* parms ) { FinishAction( "dead" ); return SRESULT_WAIT; } stateResult_t rvmMonsterTurret::Torso_Idle( stateParms_t* parms ) { if ( parms->stage == 0 ) { PlayCycle( ANIMCHANNEL_TORSO, "idle" ); parms->stage = 1; } if ( fire ) { SetAnimState( ANIMCHANNEL_TORSO, "Torso_Attack", 0 ); return SRESULT_DONE; } return SRESULT_WAIT; } stateResult_t rvmMonsterTurret::Torso_Attack( stateParms_t* parms ) { enum { STAGE_WINDUP, STAGE_FIRE, STAGE_WINDDOWN }; switch ( parms->stage ) { case STAGE_WINDUP: PlayCycle( ANIMCHANNEL_TORSO, "idle" ); StartSoundKey( "snd_windup", SND_CHANNEL_BODY, false ); attackTime = DelayTime( TURRET_MIN_ATTACK_TIME ); nextFireTime = Time(); parms->stage = STAGE_FIRE; return SRESULT_WAIT; case STAGE_FIRE: if ( ( !fire && Time() >= attackTime ) || InfluenceActive() ) { StartSoundKey( "snd_winddown", SND_CHANNEL_BODY2, false ); parms->stage = STAGE_WINDDOWN; scratchEndTime = DelayTime( 0.35f ); return SRESULT_WAIT; } if ( Time() >= nextFireTime ) { StartSoundKey( "snd_fire", SND_CHANNEL_WEAPON, false ); AttackMissile( "barrel" ); nextFireTime = DelayTime( TURRET_FIRE_RATE ); } return SRESULT_WAIT; case STAGE_WINDDOWN: if ( Time() < scratchEndTime ) { return SRESULT_WAIT; } FinishAction( "attack" ); SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 ); return SRESULT_DONE; } return SRESULT_ERROR; } stateResult_t rvmMonsterTurret::spawn_light( stateParms_t* parms ) { return SRESULT_DONE; } stateResult_t rvmMonsterTurret::light_off( stateParms_t* parms ) { light_is_on = false; return SRESULT_DONE; } stateResult_t rvmMonsterTurret::light_on( stateParms_t* parms ) { light_is_on = true; return SRESULT_DONE; } stateResult_t rvmMonsterTurret::state_Begin( stateParms_t* parms ) { SetMoveType( MOVETYPE_STATIC ); if ( GetIntKey( "trigger" ) ) { SetState( "state_Disabled" ); return SRESULT_DONE; } StartAction( "wait_for_enemy" ); parms->stage = 1; return SRESULT_WAIT; } stateResult_t rvmMonsterTurret::state_Idle( stateParms_t* parms ) { if ( parms->stage == 0 ) { StartSoundKey( "snd_shutdown", SND_CHANNEL_VOICE, false ); StartAction( "light_off" ); StartAction( "wait_for_enemy" ); parms->stage = 1; return SRESULT_WAIT; } if ( InAction() ) { return SRESULT_WAIT; } SetState( "state_Combat" ); return SRESULT_DONE; } stateResult_t rvmMonsterTurret::state_Disabled( stateParms_t* parms ) { enum { STAGE_START, STAGE_TRIGGER }; switch ( parms->stage ) { case STAGE_START: StartSoundKey( "snd_shutdown", SND_CHANNEL_VOICE, false ); LookAtEnemy( 0.0f ); attackTime = 0.0f; fire = false; ClearEnemy(); ClearActivated(); parms->stage = STAGE_TRIGGER; return SRESULT_WAIT; case STAGE_TRIGGER: if ( !Activated() ) { return SRESULT_WAIT; } ClearActivated(); SetState( "state_Combat" ); return SRESULT_DONE; } return SRESULT_ERROR; } stateResult_t rvmMonsterTurret::state_Killed( stateParms_t* parms ) { StopMove(); StartAction( "light_off" ); waitActionName = "dead"; SetAnimState( ANIMCHANNEL_TORSO, "Torso_Death", 0 ); StopThinking(); return SRESULT_WAIT; } bool rvmMonsterTurret::checkForEnemy( bool use_fov ) { idEntity* enemy = FindEnemy( use_fov ); if ( !enemy && attack_monsters ) { enemy = FindEnemyAI( use_fov ); } if ( !enemy ) { return false; } SetEnemy( enemy ); return true; } stateResult_t rvmMonsterTurret::state_Combat( stateParms_t* parms ) { if ( parms->stage == 0 ) { StartSoundKey( "snd_wakeup", SND_CHANNEL_VOICE, false ); StartAction( "light_on" ); shutdownTime = DelayTime( TURRET_SHUTDOWN_TIME ); parms->stage = 1; } LookAtEnemy( 1.0f ); if ( EnemyDead() ) { enemy_dead(); return SRESULT_DONE; } if ( Activated() ) { SetState( "state_Disabled" ); return SRESULT_DONE; } if ( EnemyVisible() ) { if ( owner && owner->CanHitEnemyFromJoint( "barrel" ) ) { StartAction( "combat_attack" ); } else { checkForEnemy( false ); } shutdownTime = DelayTime( TURRET_SHUTDOWN_TIME ); return SRESULT_WAIT; } if ( !checkForEnemy( false ) && Time() >= shutdownTime ) { LookAtEnemy( 0.0f ); ClearEnemy(); SetState( "state_Idle" ); return SRESULT_DONE; } return SRESULT_WAIT; } stateResult_t rvmMonsterTurret::combat_attack( stateParms_t* parms ) { FaceEnemy(); fire = true; if ( !EnemyVisible() || !( owner && owner->CanHitEnemyFromJoint( "barrel" ) ) || InfluenceActive() || Activated() ) { fire = false; if ( Activated() ) { SetState( "state_Disabled" ); } return SRESULT_DONE; } LookAtEnemy( 1.0f ); return SRESULT_WAIT; }