Files
DoomRTX/neo/doom3/game/ai/AI_monster_turret.cpp
T
2026-05-23 20:50:12 -07:00

171 lines
6.5 KiB
C++

// 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;
}