// AI_base.cpp // Native state-machine replacement for ai_base.script. #include "precompiled.h" #pragma hdrstop #include "../Game_local.h" rvmAIObject::rvmAIObject() { owner = NULL; scratchEndTime = 0.0f; scratchMinTime = 0.0f; scratchNextTime = 0.0f; scratchCount = 0.0f; scratchFlags = 0.0f; scratchBool = false; scratchEntity = NULL; ClearParms( stateParms ); ClearParms( actionParms ); for ( int i = 0; i < AI_NATIVE_MAX_CHANNELS; ++i ) { ClearParms( animParms[i] ); } } rvmAIObject::~rvmAIObject() { Destroy(); } void rvmAIObject::Init( idAI* aiOwner ) { owner = aiOwner; currentState.Clear(); currentAction.Clear(); waitActionName.Clear(); for ( int i = 0; i < AI_NATIVE_MAX_CHANNELS; ++i ) { currentAnimState[i].Clear(); ClearParms( animParms[i] ); } ClearParms( stateParms ); ClearParms( actionParms ); } void rvmAIObject::Destroy() { owner = NULL; currentState.Clear(); currentAction.Clear(); waitActionName.Clear(); } void rvmAIObject::Update() { for ( int i = 0; i < AI_NATIVE_MAX_CHANNELS; ++i ) { if ( currentAnimState[i].Length() ) { RunStateByName( currentAnimState[i].c_str(), &animParms[i] ); } } if ( currentAction.Length() ) { stateResult_t result = RunStateByName( currentAction.c_str(), &actionParms ); if ( result != SRESULT_WAIT ) { currentAction.Clear(); ClearParms( actionParms ); } return; } if ( currentState.Length() ) { RunStateByName( currentState.c_str(), &stateParms ); } } void rvmAIObject::SetState( const char* stateName ) { currentState = stateName ? stateName : ""; ClearParms( stateParms ); } void rvmAIObject::SetAnimState( int channel, const char* stateName, int blendFrames ) { if ( channel == ANIMCHANNEL_ALL ) { SetAnimState( ANIMCHANNEL_HEAD, stateName, blendFrames ); SetAnimState( ANIMCHANNEL_TORSO, stateName, blendFrames ); SetAnimState( ANIMCHANNEL_LEGS, stateName, blendFrames ); return; } const int index = ChannelIndex( channel ); if ( index < 0 ) { return; } currentAnimState[index] = stateName ? stateName : ""; ClearParms( animParms[index] ); SetBlendFrames( channel, blendFrames ); if ( owner ) { owner->Event_EnableAnim( channel, blendFrames ); if ( channel == ANIMCHANNEL_TORSO ) { owner->Event_EnableAnim( ANIMCHANNEL_LEGS, blendFrames ); } else if ( channel == ANIMCHANNEL_LEGS ) { owner->Event_EnableAnim( ANIMCHANNEL_TORSO, blendFrames ); } } } bool rvmAIObject::InAnimState( int channel, const char* stateName ) const { const int index = ChannelIndex( channel ); if ( index < 0 || !stateName ) { return false; } return !idStr::Icmp( currentAnimState[index].c_str(), stateName ); } void rvmAIObject::StartAction( const char* actionName ) { currentAction = actionName ? actionName : ""; ClearParms( actionParms ); } bool rvmAIObject::InAction() const { return currentAction.Length() != 0; } void rvmAIObject::FinishAction( const char* actionName ) { if ( !actionName || !waitActionName.Length() || !idStr::Icmp( waitActionName.c_str(), actionName ) ) { waitActionName.Clear(); } } bool rvmAIObject::ActionDone( const char* actionName ) const { if ( !waitActionName.Length() ) { return true; } return actionName && idStr::Icmp( waitActionName.c_str(), actionName ) != 0; } stateResult_t rvmAIObject::RunStateByName( const char* stateName, stateParms_t* parms ) { return SRESULT_DONE; } int rvmAIObject::ChannelIndex( int channel ) const { if ( channel == ANIMCHANNEL_HEAD ) { return 0; } if ( channel == ANIMCHANNEL_TORSO ) { return 1; } if ( channel == ANIMCHANNEL_LEGS ) { return 2; } if ( channel == ANIMCHANNEL_ALL ) { return 3; } return -1; } void rvmAIObject::ClearParms( stateParms_t& parms ) { memset( &parms, 0, sizeof( parms ) ); } float rvmAIObject::Time() const { return MS2SEC( gameLocal.time ); } float rvmAIObject::FrameTime() const { return MS2SEC( gameLocal.msec ); } float rvmAIObject::RandomFloat( float max ) const { return gameLocal.random.RandomFloat() * max; } float rvmAIObject::RandomDelay( float minSeconds, float maxSeconds ) const { return Time() + minSeconds + RandomFloat( maxSeconds - minSeconds ); } float rvmAIObject::DelayTime( float seconds ) const { return Time() + seconds; } float rvmAIObject::RandomTime( float seconds ) const { return Time() + RandomFloat( seconds ); } bool rvmAIObject::InfluenceActive() const { // Some branches keep the old DoomScript influence query only in script/event glue, // and idPlayer has no public InfluenceActive() accessor. Keep this wrapper compile-safe; // wire it to your branch's real influence flag here if one exists. return false; } idPlayer* rvmAIObject::Player() const { return gameLocal.GetLocalPlayer(); } void rvmAIObject::IdleAnim( int channel, const char* animName ) { if ( owner ) { owner->Event_IdleAnim( channel, animName ); } } void rvmAIObject::PlayCycle( int channel, const char* animName ) { if ( owner ) { owner->Event_PlayCycle( channel, animName, 1.0f); } } void rvmAIObject::PlayAnim( int channel, const char* animName, bool blend ) { if ( owner ) { // idActor::Event_PlayAnim takes channel + anim name; the weapon-native bool // parameter does not exist on actors. owner->Event_PlayAnim( channel, animName, blend ); } } void rvmAIObject::StopAnim( int channel, int frames ) { if ( owner ) { owner->Event_StopAnim( channel, frames ); } } bool rvmAIObject::AnimDone( int channel, int blendFrames ) const { return owner ? owner->AnimDone( channel, blendFrames ) : true; } bool rvmAIObject::HasAnim( int channel, const char* animName ) const { return owner ? owner->GetAnim( channel, animName ) != 0 : false; } const char* rvmAIObject::GetPainAnim() const { if ( !owner ) { return "pain"; } const char* animName = owner->spawnArgs.GetString( "anim_pain", "" ); if ( animName && animName[0] ) { return animName; } animName = owner->spawnArgs.GetString( "pain_anim", "" ); if ( animName && animName[0] ) { return animName; } return "pain"; } void rvmAIObject::SetBlendFrames( int channel, int blendFrames ) { if ( owner ) { owner->Event_SetBlendFrames( channel, blendFrames ); } } void rvmAIObject::OverrideAnim( int channel ) { if ( owner ) { owner->Event_OverrideAnim( channel ); } } void rvmAIObject::SetAnimPrefix( const char* prefix ) { if ( owner ) { owner->Event_SetAnimPrefix( prefix ); } } void rvmAIObject::PreventPain( float seconds ) { if ( owner ) { owner->Event_PreventPain( seconds ); } } void rvmAIObject::LookAtEnemy( float seconds ) { if ( owner ) { owner->LookAtEnemy( seconds ); } } void rvmAIObject::LookAtEntity( idEntity* ent, float seconds ) { if ( owner ) { owner->LookAtEntity( ent, seconds ); } } void rvmAIObject::FaceEnemy() { if ( owner ) { owner->FaceEnemy(); } } void rvmAIObject::FaceEntity( idEntity* ent ) { if ( owner ) { owner->FaceEntity( ent ); } } bool rvmAIObject::FacingIdeal() const { return owner ? owner->FacingIdeal() : true; } void rvmAIObject::StopMove() { if ( owner ) { owner->StopMove(); } } void rvmAIObject::MoveToEnemy() { if ( owner ) { owner->MoveToEnemy(); } } void rvmAIObject::MoveToEnemyHeight() { if ( owner ) { owner->MoveToEnemyHeight(); } } void rvmAIObject::MoveToEntity( idEntity* ent ) { if ( owner ) { owner->MoveToEntity( ent ); } } void rvmAIObject::MoveToPosition( const idVec3& pos ) { if ( owner ) { owner->MoveToPosition( pos ); } } void rvmAIObject::MoveToAttackPosition( idEntity* ent, const char* animName ) { if ( owner && ent && animName && animName[0] ) { const int anim = owner->GetAnim( ANIMCHANNEL_LEGS, animName ); if ( anim ) { owner->MoveToAttackPosition( ent, anim ); } } } void rvmAIObject::MoveOutOfRange( idEntity* ent, float range ) { if ( owner ) { owner->MoveOutOfRange( ent, range ); } } void rvmAIObject::MoveToCover() { if ( owner ) { owner->MoveToCover(); } } void rvmAIObject::Wander() { if ( owner ) { owner->Wander(); } } bool rvmAIObject::MoveDone() const { return owner ? owner->MoveDone() : true; } int rvmAIObject::MoveStatus() const { return owner ? owner->MoveStatus() : MOVE_STATUS_DONE; } bool rvmAIObject::DestinationUnreachable() const { return owner ? owner->AI_DEST_UNREACHABLE != 0 : true; } idActor* rvmAIObject::GetEnemy() const { return owner ? owner->GetEnemy() : NULL; } void rvmAIObject::SetEnemy( idEntity* ent ) { if ( owner ) { owner->SetEnemy( ent ); } } void rvmAIObject::ClearEnemy() { if ( owner ) { owner->ClearEnemy(); } } bool rvmAIObject::EnemyVisible() const { return owner ? owner->AI_ENEMY_VISIBLE != 0 : false; } bool rvmAIObject::EnemyInFOV() const { return owner ? owner->AI_ENEMY_IN_FOV != 0 : false; } bool rvmAIObject::EnemyDead() const { return owner ? owner->AI_ENEMY_DEAD != 0 : true; } float rvmAIObject::EnemyRange() const { return owner ? owner->EnemyRange() : idMath::INFINITY; } bool rvmAIObject::CheckForMelee() const { return owner ? owner->TestMeleeAttack() != 0 : false; } bool rvmAIObject::CanHitEnemy() const { return owner ? owner->CanHitEnemy() != 0 : false; } bool rvmAIObject::CanHitEnemyFromAnim( const char* animName ) const { return owner ? owner->CanHitEnemyFromAnim( animName ) != 0 : false; } bool rvmAIObject::EntityInAttackCone( idEntity* ent ) const { return owner ? owner->EntityInAttackCone( ent ) != 0 : false; } bool rvmAIObject::CanReachEnemy() const { return owner ? owner->CanReachEnemy() != 0 : false; } bool rvmAIObject::CanReachEntity( idEntity* ent ) const { return owner ? owner->CanReachEntity( ent ) != 0 : false; } bool rvmAIObject::CanSeeEntity( idEntity* ent ) const { return owner ? owner->CanSeeEntity( ent ) != 0 : false; } void rvmAIObject::LocateEnemy() { if ( owner ) { owner->LocateEnemy(); } } bool rvmAIObject::AttackMelee( const char* meleeDefName ) { return owner ? owner->AttackMelee( meleeDefName ) != 0 : false; } idEntity* rvmAIObject::AttackMissile( const char* jointName ) { return owner ? owner->AttackMissile( jointName ) : NULL; } void rvmAIObject::MuzzleFlash( const char* jointName ) { if ( owner ) { owner->MuzzleFlash( jointName ); } } idEntity* rvmAIObject::GetCombatNode() { return owner ? owner->GetCombatNode() : NULL; } bool rvmAIObject::Pain() const { return owner ? owner->AI_PAIN != 0 : false; } bool rvmAIObject::Activated() const { return owner ? owner->AI_ACTIVATED != 0 : false; } void rvmAIObject::ClearActivated() { if ( owner ) { owner->AI_ACTIVATED = false; } } bool rvmAIObject::MovingForward() const { return owner ? owner->AI_FORWARD != 0 : false; } bool rvmAIObject::Blocked() const { return owner ? owner->AI_BLOCKED != 0 : false; } bool rvmAIObject::ObstacleInPath() const { return owner ? owner->AI_OBSTACLE_IN_PATH != 0 : false; } void rvmAIObject::AllowMovement( bool allow ) { if ( owner ) { owner->AllowMovement( allow ? 1.0f : 0.0f ); } } void rvmAIObject::SetMoveType( int moveType ) { if ( owner ) { owner->SetMoveType( moveType ); } } float rvmAIObject::GetTurnDelta() const { return owner ? owner->GetTurnDelta() : 0.0f; } void rvmAIObject::TurnTo( float yaw ) { if ( owner ) { owner->TurnTo( yaw ); } } float rvmAIObject::CurrentYaw() const { return owner ? owner->GetCurrentYaw() : 0.0f; } void rvmAIObject::TurnToPos( const idVec3& pos ) { if ( owner ) { owner->TurnToPos( pos ); } } idVec3 rvmAIObject::GetOrigin() const { return owner ? owner->GetPhysics()->GetOrigin() : vec3_zero; } idVec3 rvmAIObject::GetEnemyPos() const { return owner ? owner->GetEnemyPos() : GetOrigin(); } idVec3 rvmAIObject::PredictEnemyPos( float seconds ) const { return owner ? owner->PredictEnemyPos( seconds ) : GetOrigin(); } idVec3 rvmAIObject::GetLinearVelocity() const { return owner ? owner->GetPhysics()->GetLinearVelocity() : vec3_zero; } void rvmAIObject::SetLinearVelocity( const idVec3& velocity ) { if ( owner ) { owner->GetPhysics()->SetLinearVelocity( velocity ); } } float rvmAIObject::AnimLength( int channel, const char* animName ) const { if ( !owner || !animName || !animName[0] ) { return 0.0f; } const int anim = owner->GetAnim( channel, animName ); if ( !anim || !owner->GetAnimator() ) { return 0.0f; } return MS2SEC( owner->GetAnimator()->AnimLength( anim ) ); } const char* rvmAIObject::ChooseAnim( int channel, const char* animName ) const { if ( !owner || !animName || !animName[0] ) { return ""; } const int anim = owner->GetAnim( channel, animName ); if ( !anim ) { return ""; } if ( channel == ANIMCHANNEL_HEAD ) { return animName; } return owner->GetAnimator() ? owner->GetAnimator()->AnimFullName( anim ) : ""; } bool rvmAIObject::TestAnimMove( const char* animName ) const { return owner ? owner->TestAnimMove( animName ) != 0 : false; } bool rvmAIObject::TestAnimMoveTowardEnemy( const char* animName ) const { return owner ? owner->TestAnimMoveTowardEnemy( animName ) != 0 : false; } bool rvmAIObject::TestAnimAttack( const char* animName ) const { return owner ? owner->TestAnimAttack( animName ) != 0 : false; } bool rvmAIObject::TestMoveToPosition( const idVec3& pos ) const { return owner ? owner->TestMoveToPosition( pos ) != 0 : false; } float rvmAIObject::TravelDistanceToPoint( const idVec3& pos ) const { return owner ? owner->TravelDistanceToPoint( pos ) : idMath::INFINITY; } float rvmAIObject::TravelDistanceToEntity( idEntity* ent ) const { return ( owner && ent ) ? owner->TravelDistanceToEntity( ent ) : idMath::INFINITY; } float rvmAIObject::TravelDistanceBetweenPoints( const idVec3& source, const idVec3& dest ) const { return owner ? owner->TravelDistanceBetweenPoints( source, dest ) : idMath::INFINITY; } idVec3 rvmAIObject::GetReachableEntityPosition( idEntity* ent ) const { return ( owner && ent ) ? owner->GetReachableEntityPosition( ent ) : vec3_zero; } idVec3 rvmAIObject::GetJumpVelocity( const idVec3& pos, float speed, float maxHeight ) const { return owner ? owner->GetJumpVelocity( pos, speed, maxHeight ) : vec3_zero; } void rvmAIObject::AttackBegin( const char* damageDefName ) { if ( owner ) { owner->BeginAttack( damageDefName ); } } void rvmAIObject::AttackEnd() { if ( owner ) { owner->EndAttack(); } } void rvmAIObject::ChargeAttack( const char* damageDefName ) { if ( owner ) { owner->ChargeAttack( damageDefName ); } } float rvmAIObject::TestChargeAttack() const { return owner ? owner->TestChargeAttack() : 0.0f; } idEntity* rvmAIObject::CreateMissile( const char* jointName ) { return owner ? owner->CreateMissile( jointName ) : NULL; } idEntity* rvmAIObject::FireMissileAtTarget( const char* jointName, const char* targetName ) { return owner ? owner->FireMissileAtTarget( jointName, targetName ) : NULL; } idEntity* rvmAIObject::LaunchMissile( const idVec3& origin, const idAngles& angles ) { return owner ? owner->LaunchMissile( origin, angles ) : NULL; } void rvmAIObject::DirectDamage( idEntity* target, const char* damageDefName ) { if ( owner && target ) { owner->DirectDamage( target, damageDefName ); } } void rvmAIObject::RadiusDamageFromJoint( const char* jointName, const char* damageDefName ) { if ( owner ) { owner->RadiusDamageFromJoint( jointName, damageDefName ); } } void rvmAIObject::SetFlySpeed( float speed ) { if ( owner ) { owner->SetFlySpeed( speed ); } } void rvmAIObject::SetFlyOffset( int offset ) { if ( owner ) { owner->SetFlyOffset( offset ); } } void rvmAIObject::ClearFlyOffset() { if ( owner ) { owner->ClearFlyOffset(); } } void rvmAIObject::SetHealth( float value ) { if ( owner ) { owner->SetHealth( value ); } } float rvmAIObject::GetHealth() const { return owner ? owner->GetHealth() : 0.0f; } void rvmAIObject::AllowDamage() { if ( owner ) { owner->AllowDamage(); } } void rvmAIObject::IgnoreDamage() { if ( owner ) { owner->IgnoreDamage(); } } void rvmAIObject::BecomeSolid() { if ( owner ) { owner->BecomeSolid(); } } void rvmAIObject::BecomeNonSolid() { if ( owner ) { owner->BecomeNonSolid(); } } void rvmAIObject::PreBurn() { if ( owner ) { owner->PreBurn(); } } void rvmAIObject::Burn() { if ( owner ) { owner->Burn(); } } void rvmAIObject::ClearBurn() { if ( owner ) { owner->ClearBurn(); } } void rvmAIObject::KillEntity( idEntity* ent ) { if ( !ent ) { return; } if ( ent->IsType( idAI::Type ) ) { static_cast( ent )->Kill(); } else { ent->PostEventMS( &EV_Remove, 0 ); } } idEntity* rvmAIObject::RandomPathFrom( idEntity* from ) const { return from ? idPathCorner::RandomPath( from, NULL ) : NULL; } idEntity* rvmAIObject::FindEnemy( bool useFOV ) { return owner ? owner->FindEnemy( useFOV ? 1 : 0 ) : NULL; } idEntity* rvmAIObject::FindEnemyAI( bool useFOV ) { return owner ? owner->FindEnemyAI( useFOV ? 1 : 0 ) : NULL; } idEntity* rvmAIObject::HeardSound( bool ignoreTeam ) { return owner ? owner->HeardSound( ignoreTeam ? 1 : 0 ) : NULL; } idEntity* rvmAIObject::FindActorsInBounds( const idVec3& mins, const idVec3& maxs ) { return owner ? owner->FindActorsInBounds( mins, maxs ) : NULL; } idEntity* rvmAIObject::ClosestReachableEnemyOfEntity( idEntity* teamMate ) { return ( owner && teamMate ) ? owner->ClosestReachableEnemyOfEntity( teamMate ) : NULL; } idEntity* rvmAIObject::GetRandomTarget( const char* type ) { return owner ? owner->GetRandomTarget( type ) : NULL; } idVec3 rvmAIObject::GetVectorKey( const char* key, const char* defaultValue ) const { return owner ? owner->spawnArgs.GetVector( key, defaultValue ) : vec3_zero; } void rvmAIObject::HideEntity( idEntity* ent ) { if ( ent ) { ent->Hide(); } } void rvmAIObject::ShowEntity( idEntity* ent ) { if ( ent ) { ent->Show(); } } void rvmAIObject::RemoveEntity( idEntity* ent ) { if ( ent ) { ent->PostEventMS( &EV_Remove, 0 ); } } int rvmAIObject::GetIntKey( const char* key, const char* defaultValue ) const { return owner ? owner->spawnArgs.GetInt( key, defaultValue ) : atoi( defaultValue ); } int rvmAIObject::GetIntKey( const char* key, int defaultValue ) const { if ( !owner ) { return defaultValue; } return owner->spawnArgs.GetInt( key, va( "%d", defaultValue ) ); } float rvmAIObject::GetFloatKey( const char* key, const char* defaultValue ) const { return owner ? owner->spawnArgs.GetFloat( key, defaultValue ) : atof( defaultValue ); } float rvmAIObject::GetFloatKey( const char* key, float defaultValue ) const { if ( !owner ) { return defaultValue; } return owner->spawnArgs.GetFloat( key, va( "%g", defaultValue ) ); } const char* rvmAIObject::GetKey( const char* key, const char* defaultValue ) const { return owner ? owner->spawnArgs.GetString( key, defaultValue ) : defaultValue; } idEntity* rvmAIObject::GetEntityKey( const char* key ) const { if ( !owner ) { return NULL; } const char* name = owner->spawnArgs.GetString( key, "" ); return name && name[0] ? gameLocal.FindEntity( name ) : NULL; } void rvmAIObject::HideOwner() { if ( owner ) { owner->Hide(); } } void rvmAIObject::ShowOwner() { if ( owner ) { owner->Show(); } } bool rvmAIObject::CanBecomeSolid() const { return owner ? owner->CanBecomeSolid() != 0.0f : false; } void rvmAIObject::SetNeverDormant( bool value ) { if ( owner ) { owner->fl.neverDormant = value; } } void rvmAIObject::WakeOnFlashlight( bool value ) { if ( owner ) { owner->WakeOnFlashlight( value ? 1 : 0 ); } } void rvmAIObject::StartSoundKey( const char* key, int channel, bool netSync ) { if ( owner ) { owner->StartSound( key, channel, netSync ? SSF_GLOBAL : 0, false, NULL ); } } void rvmAIObject::StartFx( const char* fx ) { if ( owner && fx && fx[0] ) { idEntityFx::StartFx( fx, NULL, NULL, owner, true ); } } void rvmAIObject::SetSmokeVisibility( int index, bool visible ) { if ( owner ) { owner->SetSmokeVisibility( index, visible ? 1 : 0 ); } } void rvmAIObject::TriggerParticles( const char* jointName ) { if ( owner ) { owner->TriggerParticles( jointName ); } } void rvmAIObject::BecomeRagdoll() { if ( owner ) { owner->BecomeRagdoll(); } } void rvmAIObject::StopThinking() { if ( owner ) { owner->StopThinking(); } } void rvmAIObject::RemoveOwner() { if ( owner ) { owner->PostEventMS( &EV_Remove, 0 ); } }