quake4-sdk/source/game/ai/AI_events.cpp
2007-06-15 00:00:00 +00:00

1146 lines
31 KiB
C++

#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "AI.h"
#ifndef __GAME_PROJECTILE_H__
#include "../Projectile.h"
#endif
#include "AI_Manager.h"
#include "../vehicle/Vehicle.h"
#include "../spawner.h"
#define idAI_EVENT( eventname, inparms, outparm) \
const idEventDef AI_##eventname( #eventname, inparms, outparm); \
void idAI::Event_##eventname
/***********************************************************************
AI Events
***********************************************************************/
// Get / Set
const idEventDef AI_GetLeader ( "getLeader", NULL, 'e' );
const idEventDef AI_SetLeader ( "setLeader", "E" );
const idEventDef AI_GetEnemy ( "getEnemy", NULL, 'e' );
const idEventDef AI_SetEnemy ( "setEnemy", "E" );
const idEventDef AI_SetHealth ( "setHealth", "f" );
const idEventDef AI_SetTalkState ( "setTalkState", "d" );
const idEventDef AI_SetScript ( "setScript", "ss" );
const idEventDef AI_SetMoveSpeed ( "setMoveSpeed", "d" );
const idEventDef AI_SetPassivePrefix ( "setPassivePrefix", "s" );
// Enable / Disable
const idEventDef AI_EnableClip ( "enableClip" );
const idEventDef AI_DisableClip ( "disableClip" );
const idEventDef AI_EnableGravity ( "enableGravity" );
const idEventDef AI_DisableGravity ( "disableGravity" );
const idEventDef AI_EnableAFPush ( "enableAFPush" );
const idEventDef AI_DisableAFPush ( "disableAFPush" );
const idEventDef AI_EnableDamage ( "enableDamage" );
const idEventDef AI_DisableDamage ( "disableDamage" );
const idEventDef AI_EnableTarget ( "enableTarget" );
const idEventDef AI_DisableTarget ( "disableTarget" );
const idEventDef AI_EnableMovement ( "enableMovement" );
const idEventDef AI_DisableMovement ( "disableMovement" );
const idEventDef AI_TakeDamage ( "takeDamage", "f" );
const idEventDef AI_SetUndying ( "setUndying", "f" );
const idEventDef AI_EnableAutoBlink ( "enableAutoBlink" );
const idEventDef AI_DisableAutoBlink ( "disableAutoBlink" );
// Scripted Sequences
const idEventDef AI_ScriptedMove ( "scriptedMove", "efd" );
const idEventDef AI_ScriptedFace ( "scriptedFace", "ed" );
const idEventDef AI_ScriptedAnim ( "scriptedAnim", "sddd" );
const idEventDef AI_ScriptedPlaybackMove ( "scriptedPlaybackMove", "sdd" );
const idEventDef AI_ScriptedPlaybackAim ( "scriptedPlaybackAim", "sdd" );
const idEventDef AI_ScriptedAction ( "scriptedAction", "ed" );
const idEventDef AI_ScriptedDone ( "scriptedDone", NULL, 'd' );
const idEventDef AI_ScriptedStop ( "scriptedStop" );
const idEventDef AI_ScriptedJumpDown ( "scriptedJumpDown", "f" );
// Misc
const idEventDef AI_LookAt ( "lookAt", "E" );
const idEventDef AI_Attack ( "attack", "ss" );
const idEventDef AI_LockEnemyOrigin ( "lockEnemyOrigin" );
const idEventDef AI_StopThinking ( "stopThinking" );
const idEventDef AI_JumpFrame ( "<jumpframe>" );
const idEventDef AI_RealKill ( "<kill>" );
const idEventDef AI_Kill ( "kill" );
const idEventDef AI_RemoveUpdateSpawner ( "removeUpdateSpawner" );
const idEventDef AI_AllowHiddenMovement ( "allowHiddenMovement", "d" );
const idEventDef AI_Speak ( "speak", "s" );
const idEventDef AI_SpeakRandom ( "speakRandom", "s" );
const idEventDef AI_IsSpeaking ( "isSpeaking", NULL, 'f' );
const idEventDef AI_IsTethered ( "isTethered", NULL, 'f' );
const idEventDef AI_IsWithinTether ( "isWithinTether", NULL, 'f' );
const idEventDef AI_LaunchMissile ( "launchMissile", "vv", 'e' );
const idEventDef AI_AttackMelee ( "attackMelee", "s", 'd' );
const idEventDef AI_DirectDamage ( "directDamage", "es" );
const idEventDef AI_RadiusDamageFromJoint ( "radiusDamageFromJoint", "ss" );
const idEventDef AI_MeleeAttackToJoint ( "meleeAttackToJoint", "ss", 'd' );
const idEventDef AI_CanBecomeSolid ( "canBecomeSolid", NULL, 'f' );
const idEventDef AI_BecomeSolid ( "becomeSolid" );
const idEventDef AI_BecomeRagdoll ( "becomeRagdoll", NULL, 'd' );
const idEventDef AI_BecomePassive ( "becomePassive", "d" );
const idEventDef AI_BecomeAggressive ( "becomeAggressive" );
const idEventDef AI_StopRagdoll ( "stopRagdoll" );
const idEventDef AI_FaceEnemy ( "faceEnemy" );
const idEventDef AI_FaceEntity ( "faceEntity", "E" );
//jshepard
const idEventDef AI_FindEnemy ( "findEnemy", "f", 'e');
void idAI::Event_Activate( idEntity *activator ) { Activate( activator );}
void idAI::Event_Touch( idEntity *other, trace_t *trace ) { OnTouch( other, trace ); }
void idAI::Event_SetEnemy( idEntity *ent ) { if ( !ent ) ClearEnemy(); else SetEnemy( ent );}
void idAI::Event_DirectDamage( idEntity *damageTarget, const char *damageDefName ) { DirectDamage( damageDefName, damageTarget ); }
void idAI::Event_RadiusDamageFromJoint( const char *jointname, const char *damageDefName ) { RadiusDamageFromJoint( jointname, damageDefName ); }
void idAI::Event_CanBecomeSolid( void ) { idThread::ReturnFloat( CanBecomeSolid() ); }
void idAI::Event_BecomeSolid( void ) { BecomeSolid(); }
void idAI::Event_BecomeNonSolid( void ) { BecomeNonSolid(); }
void idAI::Event_BecomeRagdoll( void ) { idThread::ReturnInt( StartRagdoll() ); }
void idAI::Event_StopRagdoll( void ) { StopRagdoll(); SetPhysics( &physicsObj ); }
void idAI::Event_SetHealth( float newHealth ) { health = newHealth; fl.takedamage = true; if( health > 0 ) aifl.dead = false; else aifl.dead = true; }
void idAI::Event_FaceEnemy( void ) { FaceEnemy(); }
void idAI::Event_FaceEntity( idEntity *ent ) { FaceEntity( ent ); }
void idAI::Event_SetTalkState( int state ) { SetTalkState ( (talkState_t)state ); }
void idAI::Event_Speak( const char *speechDecl ) { Speak( speechDecl ); }
void idAI::Event_SpeakRandom( const char *speechDecl ) { Speak( speechDecl, true ); }
void idAI::Event_GetLeader( void ) { idThread::ReturnEntity( leader ); }
void idAI::Event_SetLeader( idEntity* ent ) { SetLeader ( ent ); }
void idAI::Event_GetEnemy( void ) { idThread::ReturnEntity( enemy.ent ); }
void idAI::Event_TakeDamage( float takeDamage ) { fl.takedamage = ( takeDamage ) ? true : false; }
void idAI::Event_SetUndying( float setUndying ) { aifl.undying = ( setUndying ) ? true : false; }
void idAI::Event_IsSpeaking ( void ) { idThread::ReturnFloat ( IsSpeaking ( ) ); }
void idAI::Event_IsTethered ( void ) { idThread::ReturnFloat ( IsTethered ( ) ); }
void idAI::Event_IsWithinTether ( void ) { idThread::ReturnFloat ( IsWithinTether ( ) ); }
void idAI::Event_IsMoving ( void ) { idThread::ReturnFloat ( move.fl.moving ); }
CLASS_DECLARATION( idActor, idAI )
EVENT( EV_Activate, idAI::Event_Activate )
EVENT( EV_Touch, idAI::Event_Touch )
// Enable / Disable
EVENT( AI_EnableClip, idAI::Event_EnableClip )
EVENT( AI_DisableClip, idAI::Event_DisableClip )
EVENT( AI_EnableGravity, idAI::Event_EnableGravity )
EVENT( AI_DisableGravity, idAI::Event_DisableGravity )
EVENT( AI_EnableAFPush, idAI::Event_EnableAFPush )
EVENT( AI_DisableAFPush, idAI::Event_DisableAFPush )
EVENT( AI_EnableDamage, idAI::Event_EnableDamage )
EVENT( AI_DisableDamage, idAI::Event_DisableDamage )
EVENT( AI_EnablePain, idAI::Event_EnablePain )
EVENT( AI_DisablePain, idAI::Event_DisablePain )
EVENT( AI_EnableTarget, idAI::Event_EnableTarget )
EVENT( AI_DisableTarget, idAI::Event_DisableTarget )
EVENT( AI_TakeDamage, idAI::Event_TakeDamage )
EVENT( AI_SetUndying, idAI::Event_SetUndying )
EVENT( AI_EnableAutoBlink, idAI::Event_EnableAutoBlink )
EVENT( AI_DisableAutoBlink, idAI::Event_DisableAutoBlink )
// Scripted sequences
EVENT( AI_ScriptedMove, idAI::Event_ScriptedMove )
EVENT( AI_ScriptedFace, idAI::Event_ScriptedFace )
EVENT( AI_ScriptedAnim, idAI::Event_ScriptedAnim )
EVENT( AI_ScriptedAction, idAI::Event_ScriptedAction )
EVENT( AI_ScriptedPlaybackMove, idAI::Event_ScriptedPlaybackMove )
EVENT( AI_ScriptedPlaybackAim, idAI::Event_ScriptedPlaybackAim )
EVENT( AI_ScriptedDone, idAI::Event_ScriptedDone )
EVENT( AI_ScriptedStop, idAI::Event_ScriptedStop )
EVENT( AI_ScriptedJumpDown, idAI::Event_ScriptedJumpDown )
// Get / Set
EVENT( AI_SetTalkState, idAI::Event_SetTalkState )
EVENT( AI_SetLeader, idAI::Event_SetLeader )
EVENT( AI_GetLeader, idAI::Event_GetLeader )
EVENT( AI_SetEnemy, idAI::Event_SetEnemy )
EVENT( AI_GetEnemy, idAI::Event_GetEnemy )
EVENT( EV_GetAngles, idAI::Event_GetAngles )
EVENT( EV_SetAngles, idAI::Event_SetAngles )
EVENT( AI_SetScript, idAI::Event_SetScript )
EVENT( AI_SetMoveSpeed, idAI::Event_SetMoveSpeed )
EVENT( AI_SetPassivePrefix, idAI::Event_SetPassivePrefix )
// Misc
EVENT( AI_Attack, idAI::Event_Attack )
EVENT( AI_AttackMelee, idAI::Event_AttackMelee )
EVENT( AI_LookAt, idAI::Event_LookAt )
EVENT( AI_DirectDamage, idAI::Event_DirectDamage )
EVENT( AI_RadiusDamageFromJoint, idAI::Event_RadiusDamageFromJoint )
EVENT( AI_CanBecomeSolid, idAI::Event_CanBecomeSolid )
EVENT( AI_BecomeSolid, idAI::Event_BecomeSolid )
EVENT( EV_BecomeNonSolid, idAI::Event_BecomeNonSolid )
EVENT( AI_BecomeRagdoll, idAI::Event_BecomeRagdoll )
EVENT( AI_BecomePassive, idAI::Event_BecomePassive )
EVENT( AI_BecomeAggressive, idAI::Event_BecomeAggressive )
EVENT( AI_StopRagdoll, idAI::Event_StopRagdoll )
EVENT( AI_SetHealth, idAI::Event_SetHealth )
EVENT( AI_FaceEnemy, idAI::Event_FaceEnemy )
EVENT( AI_FaceEntity, idAI::Event_FaceEntity )
EVENT( AI_StopThinking, idAI::Event_StopThinking )
EVENT( AI_LockEnemyOrigin, idAI::Event_LockEnemyOrigin )
EVENT( AI_JumpFrame, idAI::Event_JumpFrame )
EVENT( AI_RealKill, idAI::Event_RealKill )
EVENT( AI_Kill, idAI::Event_Kill )
EVENT( AI_RemoveUpdateSpawner, idAI::Event_RemoveUpdateSpawner )
EVENT( AI_AllowHiddenMovement, idAI::Event_AllowHiddenMovement )
EVENT( AI_Speak, idAI::Event_Speak )
EVENT( AI_SpeakRandom, idAI::Event_SpeakRandom )
EVENT( AI_IsSpeaking, idAI::Event_IsSpeaking )
EVENT( AI_IsTethered, idAI::Event_IsTethered )
EVENT( AI_IsWithinTether, idAI::Event_IsWithinTether )
EVENT( EV_IsMoving, idAI::Event_IsMoving )
EVENT( AI_TakeDamage, idAI::Event_TakeDamage )
EVENT( AI_FindEnemy, idAI::Event_FindEnemy )
EVENT( EV_SetKey, idAI::Event_SetKey )
// RAVEN BEGIN
// twhitaker: needed this for difficulty settings
EVENT( EV_PostSpawn, idAI::Event_PostSpawn )
// RAVEN END
END_CLASS
/*
=====================
idAI::Event_PredictEnemyPos
=====================
*/
void idAI::Event_PredictEnemyPos( float time ) {
predictedPath_t path;
idEntity* enemyEnt = enemy.ent;
// if no enemy set
if ( !enemyEnt ) {
idThread::ReturnVector( physicsObj.GetOrigin() );
return;
}
// predict the enemy movement
idAI::PredictPath( enemyEnt, aas, enemy.lastKnownPosition, enemyEnt->GetPhysics()->GetLinearVelocity(), SEC2MS( time ), SEC2MS( time ), ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
idThread::ReturnVector( path.endPos );
}
/*
=====================
idAI::Event_TestAnimMoveTowardEnemy
=====================
*/
void idAI::Event_TestAnimMoveTowardEnemy( const char *animname ) {
int anim;
predictedPath_t path;
idVec3 moveVec;
float yaw;
idVec3 delta;
idEntity *enemyEnt;
enemyEnt = enemy.ent;
if ( !enemyEnt ) {
idThread::ReturnInt( false );
return;
}
anim = GetAnim( ANIMCHANNEL_LEGS, animname );
if ( !anim ) {
gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
idThread::ReturnInt( false );
return;
}
delta = enemyEnt->GetPhysics()->GetOrigin() - physicsObj.GetOrigin();
yaw = delta.ToYaw();
moveVec = animator.TotalMovementDelta( anim ) * idAngles( 0.0f, yaw, 0.0f ).ToMat3() * physicsObj.GetGravityAxis();
idAI::PredictPath( this, aas, physicsObj.GetOrigin(), moveVec, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
if ( DebugFilter(ai_debugMove) ) {
gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), physicsObj.GetOrigin() + moveVec, gameLocal.msec );
gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), physicsObj.GetOrigin() + moveVec, gameLocal.msec );
}
idThread::ReturnInt( path.endEvent == 0 );
}
/*
=====================
idAI::Event_TestAnimMove
=====================
*/
void idAI::Event_TestAnimMove( const char *animname ) {
int anim;
predictedPath_t path;
idVec3 moveVec;
int animLen;
anim = GetAnim( ANIMCHANNEL_LEGS, animname );
if ( !anim ) {
gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
idThread::ReturnInt( false );
return;
}
moveVec = animator.TotalMovementDelta( anim ) * idAngles( 0.0f, move.ideal_yaw, 0.0f ).ToMat3() * physicsObj.GetGravityAxis();
animLen = animator.AnimLength( anim );
idAI::PredictPath( this, aas, physicsObj.GetOrigin(), moveVec, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
if ( DebugFilter(ai_debugMove) ) {
gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), physicsObj.GetOrigin() + moveVec, gameLocal.msec );
gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), physicsObj.GetOrigin() + moveVec, gameLocal.msec );
}
idThread::ReturnInt( path.endEvent == 0 );
}
/*
=====================
idAI::Event_TestMoveToPosition
=====================
*/
void idAI::Event_TestMoveToPosition( const idVec3 &position ) {
predictedPath_t path;
idAI::PredictPath( this, aas, physicsObj.GetOrigin(), position - physicsObj.GetOrigin(), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
if ( DebugFilter(ai_debugMove) ) {
gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), position, gameLocal.msec );
gameRenderWorld->DebugBounds( colorYellow, physicsObj.GetBounds(), position, gameLocal.msec );
if ( path.endEvent ) {
gameRenderWorld->DebugBounds( colorRed, physicsObj.GetBounds(), path.endPos, gameLocal.msec );
}
}
idThread::ReturnInt( path.endEvent == 0 );
}
/*
=====================
idAI::Event_TestMeleeAttack
=====================
*/
void idAI::Event_TestMeleeAttack( void ) {
bool result = TestMelee();
idThread::ReturnInt( result );
}
/*
=====================
idAI::Event_TestAnimAttack
=====================
*/
void idAI::Event_TestAnimAttack( const char *animname ) {
int anim;
predictedPath_t path;
anim = GetAnim( ANIMCHANNEL_LEGS, animname );
if ( !anim ) {
gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
idThread::ReturnInt( false );
return;
}
idAI::PredictPath( this, aas, physicsObj.GetOrigin(), animator.TotalMovementDelta( anim ), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
idThread::ReturnInt( path.blockingEntity && ( path.blockingEntity == enemy.ent ) );
}
/*
=====================
idAI::Event_LockEnemyOrigin
=====================
*/
void idAI::Event_LockEnemyOrigin ( void ) {
enemy.fl.lockOrigin = true;
}
/*
=====================
idAI::Event_StopThinking
=====================
*/
void idAI::Event_StopThinking( void ) {
BecomeInactive( TH_THINK );
idThread *thread = idThread::CurrentThread();
if ( thread ) {
thread->DoneProcessing();
}
}
/*
=====================
idAI::Event_JumpFrame
=====================
*/
void idAI::Event_JumpFrame( void ) {
aifl.jump = true;
}
/*
=====================
idAI::Event_EnableClip
=====================
*/
void idAI::Event_EnableClip( void ) {
physicsObj.SetClipMask( MASK_MONSTERSOLID );
Event_EnableGravity ( );
}
/*
=====================
idAI::Event_DisableClip
=====================
*/
void idAI::Event_DisableClip( void ) {
physicsObj.SetClipMask( 0 );
Event_DisableGravity ( );
}
/*
=====================
idAI::Event_EnableGravity
=====================
*/
void idAI::Event_EnableGravity( void ) {
OverrideFlag ( AIFLAGOVERRIDE_NOGRAVITY, false );
}
/*
=====================
idAI::Event_DisableGravity
=====================
*/
void idAI::Event_DisableGravity( void ) {
OverrideFlag ( AIFLAGOVERRIDE_NOGRAVITY, true );
}
/*
=====================
idAI::Event_EnableAFPush
=====================
*/
void idAI::Event_EnableAFPush( void ) {
move.fl.allowPushMovables = true;
}
/*
=====================
idAI::Event_DisableAFPush
=====================
*/
void idAI::Event_DisableAFPush( void ) {
move.fl.allowPushMovables = false;
}
/*
=====================
idAI::Event_EnableDamage
=====================
*/
void idAI::Event_EnableDamage ( void ) {
OverrideFlag ( AIFLAGOVERRIDE_DAMAGE, true );
}
/*
=====================
idAI::Event_DisableDamage
=====================
*/
void idAI::Event_DisableDamage ( void ) {
OverrideFlag ( AIFLAGOVERRIDE_DAMAGE, false );
}
/*
===============
idAI::Event_DisablePain
===============
*/
void idAI::Event_DisablePain( void ) {
OverrideFlag ( AIFLAGOVERRIDE_DISABLEPAIN, true );
}
/*
===============
idAI::Event_EnablePain
===============
*/
void idAI::Event_EnablePain( void ) {
OverrideFlag ( AIFLAGOVERRIDE_DISABLEPAIN, false );
}
/*
===============
idAI::Event_EnableTarget
===============
*/
void idAI::Event_EnableTarget ( void ) {
fl.notarget = false;
}
/*
===============
idAI::Event_DisableTarget
===============
*/
void idAI::Event_DisableTarget ( void ) {
fl.notarget = true;
}
/*
=====================
idAI::Event_EnableAutoBlink
=====================
*/
void idAI::Event_EnableAutoBlink( void ) {
fl.allowAutoBlink = true;
}
/*
=====================
idAI::Event_DisableAutoBlink
=====================
*/
void idAI::Event_DisableAutoBlink( void ) {
fl.allowAutoBlink = false;
}
/*
=====================
idAI::Event_BecomeAggressive
=====================
*/
void idAI::Event_BecomeAggressive ( void ) {
combat.fl.ignoreEnemies = false;
combat.fl.aware = true;
ForceTacticalUpdate ( );
}
/*
=====================
idAI::Event_BecomePassive
=====================
*/
void idAI::Event_BecomePassive ( int ignoreEnemies ) {
combat.fl.ignoreEnemies = (ignoreEnemies != 0);
combat.fl.aware = false;
SetEnemy ( NULL );
ForceTacticalUpdate ( );
}
/*
=====================
idAI::Event_LookAt
=====================
*/
void idAI::Event_LookAt ( idEntity* lookAt ) {
lookTarget = lookAt;
}
/*
=====================
idAI::LookAtEntity
=====================
*/
void idAI::LookAtEntity( idEntity *ent, float duration ) {
if ( ent == this ) {
ent = NULL;
}
if ( ( ent != focusEntity.GetEntity() ) || ( focusTime < gameLocal.time ) ) {
focusEntity = ent;
alignHeadTime = gameLocal.time;
forceAlignHeadTime = gameLocal.time + SEC2MS( 1 );
blink_time = 0;
}
focusTime = gameLocal.time + SEC2MS( duration );
}
/*
================
idAI::Event_ThrowMoveable
================
*/
void idAI::Event_ThrowMoveable( void ) {
idEntity *ent;
idEntity *moveable = NULL;
for ( ent = GetNextTeamEntity(); ent != NULL; ent = ent->GetNextTeamEntity() ) {
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( ent->GetBindMaster() == this && ent->IsType( idMoveable::GetClassType() ) ) {
// RAVEN END
moveable = ent;
break;
}
}
if ( moveable ) {
moveable->Unbind();
moveable->PostEventMS( &EV_SetOwner, 200, NULL );
}
}
/*
================
idAI::Event_ThrowAF
================
*/
void idAI::Event_ThrowAF( void ) {
idEntity *ent;
idEntity *af = NULL;
for ( ent = GetNextTeamEntity(); ent != NULL; ent = ent->GetNextTeamEntity() ) {
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( ent->GetBindMaster() == this && ent->IsType( idAFEntity_Base::GetClassType() ) ) {
// RAVEN END
af = ent;
break;
}
}
if ( af ) {
af->Unbind();
af->PostEventMS( &EV_SetOwner, 200, NULL );
}
}
/*
================
idAI::Event_SetAngles
================
*/
void idAI::Event_SetAngles( idAngles const &ang ) {
move.current_yaw = ang.yaw;
viewAxis = idAngles( 0, move.current_yaw, 0 ).ToMat3();
}
/*
================
idAI::Event_GetAngles
================
*/
void idAI::Event_GetAngles( void ) {
idThread::ReturnVector( idVec3( 0.0f, move.current_yaw, 0.0f ) );
}
/*
================
idAI::Event_RealKill
================
*/
void idAI::Event_RealKill( void ) {
health = 0;
if ( af.IsLoaded() ) {
// clear impacts
af.Rest();
// physics is turned off by calling af.Rest()
BecomeActive( TH_PHYSICS );
}
Killed( this, this, 0, vec3_zero, INVALID_JOINT );
}
/*
================
idAI::Event_Kill
================
*/
void idAI::Event_Kill( void ) {
PostEventMS( &AI_RealKill, 0 );
}
/*
================
idAI::Event_RemoveUpdateSpawner
================
*/
void idAI::Event_RemoveUpdateSpawner( void ) {
// Detach from any spawners
if( GetSpawner() ) {
GetSpawner()->Detach( this );
SetSpawner( NULL );
}
PostEventMS( &EV_Remove, 0 );
}
/*
=====================
idAI::Event_FindActorsInBounds
=====================
*/
void idAI::Event_FindActorsInBounds( const idVec3 &mins, const idVec3 &maxs ) {
idEntity * ent;
idEntity * entityList[ MAX_GENTITIES ];
int numListedEntities;
int i;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
numListedEntities = gameLocal.EntitiesTouchingBounds( this, idBounds( mins, maxs ), CONTENTS_BODY, entityList, MAX_GENTITIES );
// RAVEN END
for( i = 0; i < numListedEntities; i++ ) {
ent = entityList[ i ];
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( ent != this && !ent->IsHidden() && ( ent->health > 0 ) && ent->IsType( idActor::GetClassType() ) ) {
// RAVEN END
idThread::ReturnEntity( ent );
return;
}
}
idThread::ReturnEntity( NULL );
}
/*
=====================
idAI::Event_ClosestReachableEnemyOfEntity
=====================
*/
void idAI::Event_ClosestReachableEnemyOfEntity( idEntity *team_mate ) {
idActor *actor;
idActor *ent;
idActor *bestEnt;
float bestDistSquared;
float distSquared;
idVec3 delta;
int areaNum;
int enemyAreaNum;
aasPath_t path;
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( !team_mate->IsType( idActor::GetClassType() ) ) {
// RAVEN END
gameLocal.Error( "Entity '%s' is not an AI character or player", team_mate->GetName() );
}
actor = static_cast<idActor *>( team_mate );
const idVec3 &origin = physicsObj.GetOrigin();
areaNum = PointReachableAreaNum( origin );
bestDistSquared = idMath::INFINITY;
bestEnt = NULL;
for( ent = actor->enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
if ( ent->fl.hidden ) {
continue;
}
delta = ent->GetPhysics()->GetOrigin() - origin;
distSquared = delta.LengthSqr();
if ( distSquared < bestDistSquared ) {
const idVec3 &enemyPos = ent->GetPhysics()->GetOrigin();
enemyAreaNum = PointReachableAreaNum( enemyPos );
if ( ( areaNum != 0 ) && PathToGoal( path, areaNum, origin, enemyAreaNum, enemyPos ) ) {
bestEnt = ent;
bestDistSquared = distSquared;
}
}
}
idThread::ReturnEntity( bestEnt );
}
/*
=====================
idAI::Event_EntityInAttackCone
=====================
*/
void idAI::Event_EntityInAttackCone( idEntity *ent ) {
float attack_cone;
idVec3 delta;
float yaw;
float relYaw;
if ( !ent ) {
idThread::ReturnInt( false );
return;
}
delta = ent->GetPhysics()->GetOrigin() - GetEyePosition();
// get our gravity normal
const idVec3 &gravityDir = GetPhysics()->GetGravityNormal();
// infinite vertical vision, so project it onto our orientation plane
delta -= gravityDir * ( gravityDir * delta );
delta.Normalize();
yaw = delta.ToYaw();
attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
relYaw = idMath::AngleNormalize180( move.ideal_yaw - yaw );
if ( idMath::Fabs( relYaw ) < ( attack_cone * 0.5f ) ) {
idThread::ReturnInt( true );
} else {
idThread::ReturnInt( false );
}
}
/*
================
idAI::Event_CanReachPosition
================
*/
void idAI::Event_CanReachPosition( const idVec3 &pos ) {
aasPath_t path;
int toAreaNum;
int areaNum;
toAreaNum = PointReachableAreaNum( pos );
areaNum = PointReachableAreaNum( physicsObj.GetOrigin() );
if ( !toAreaNum || !PathToGoal( path, areaNum, physicsObj.GetOrigin(), toAreaNum, pos ) ) {
idThread::ReturnInt( false );
} else {
idThread::ReturnInt( true );
}
}
/*
================
idAI::Event_CanReachEntity
================
*/
void idAI::Event_CanReachEntity( idEntity *ent ) {
aasPath_t path;
int toAreaNum;
int areaNum;
idVec3 pos;
if ( !ent ) {
idThread::ReturnInt( false );
return;
}
if ( move.moveType != MOVETYPE_FLY ) {
if ( !ent->GetFloorPos( 64.0f, pos ) ) {
idThread::ReturnInt( false );
return;
}
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( ent->IsType( idActor::GetClassType() ) && static_cast<idActor *>( ent )->OnLadder() ) {
// RAVEN END
idThread::ReturnInt( false );
return;
}
} else {
pos = ent->GetPhysics()->GetOrigin();
}
toAreaNum = PointReachableAreaNum( pos );
if ( !toAreaNum ) {
idThread::ReturnInt( false );
return;
}
const idVec3 &org = physicsObj.GetOrigin();
areaNum = PointReachableAreaNum( org );
if ( !toAreaNum || !PathToGoal( path, areaNum, org, toAreaNum, pos ) ) {
idThread::ReturnInt( false );
} else {
idThread::ReturnInt( true );
}
}
/*
================
idAI::Event_CanReachEnemy
================
*/
void idAI::Event_CanReachEnemy( void ) {
aasPath_t path;
int toAreaNum = 0;
int areaNum;
idVec3 pos;
idEntity *enemyEnt;
enemyEnt = enemy.ent;
if ( !enemyEnt ) {
idThread::ReturnInt( false );
return;
}
if ( move.moveType != MOVETYPE_FLY ) {
if( enemyEnt->IsType( idActor::GetClassType() ) ){
idActor *enemyAct = static_cast<idActor *>( enemyEnt );
if ( enemyAct->OnLadder() ) {
idThread::ReturnInt( false );
return;
}
enemyAct->GetAASLocation( aas, pos, toAreaNum );
}
} else {
pos = enemyEnt->GetPhysics()->GetOrigin();
toAreaNum = PointReachableAreaNum( pos );
}
if ( !toAreaNum ) {
idThread::ReturnInt( false );
return;
}
const idVec3 &org = physicsObj.GetOrigin();
areaNum = PointReachableAreaNum( org );
if ( !PathToGoal( path, areaNum, org, toAreaNum, pos ) ) {
idThread::ReturnInt( false );
} else {
idThread::ReturnInt( true );
}
}
/*
================
idAI::Event_GetReachableEntityPosition
================
*/
void idAI::Event_GetReachableEntityPosition( idEntity *ent ) {
int toAreaNum;
idVec3 pos;
if ( move.moveType != MOVETYPE_FLY ) {
if ( !ent->GetFloorPos( 64.0f, pos ) ) {
idThread::ReturnInt( false );
return;
}
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( ent->IsType( idActor::GetClassType() ) && static_cast<idActor *>( ent )->OnLadder() ) {
// RAVEN END
idThread::ReturnInt( false );
return;
}
} else {
pos = ent->GetPhysics()->GetOrigin();
}
if ( aas ) {
toAreaNum = PointReachableAreaNum( pos );
aas->PushPointIntoAreaNum( toAreaNum, pos );
}
idThread::ReturnVector( pos );
}
/*
================
idAI::Event_ScriptedMove
================
*/
void idAI::Event_ScriptedMove ( idEntity* destEnt, float minDist, bool endWithIdle ) {
ScriptedMove ( destEnt, minDist, endWithIdle );
}
/*
================
idAI::Event_ScriptedFace
================
*/
void idAI::Event_ScriptedFace ( idEntity* faceEnt, bool endWithIdle ) {
ScriptedFace ( faceEnt, endWithIdle );
}
/*
================
idAI::Event_ScriptedAnim
================
*/
void idAI::Event_ScriptedAnim ( const char* animname, int blendFrames, bool loop, bool endWithIdle ) {
ScriptedAnim ( animname, blendFrames, loop, endWithIdle );
}
/*
================
idAI::Event_ScriptedAction
================
*/
void idAI::Event_ScriptedAction ( idEntity* actionEnt, bool endWithIdle ) {
ScriptedAction ( actionEnt, endWithIdle );
}
/*
================
idAI::Event_ScriptedPlaybackMove
================
*/
void idAI::Event_ScriptedPlaybackMove ( const char* playback, int flags, int numFrames ) {
ScriptedPlaybackMove ( playback, flags, numFrames );
}
/*
================
idAI::Event_ScriptedPlaybackAim
================
*/
void idAI::Event_ScriptedPlaybackAim( const char* playback, int flags, int numFrames ) {
ScriptedPlaybackAim ( playback, flags, numFrames );
}
/*
================
idAI::Event_ScriptedDone
================
*/
void idAI::Event_ScriptedDone ( void ) {
idThread::ReturnFloat ( !aifl.scripted );
}
/*
================
idAI::Event_ScriptedStop
================
*/
void idAI::Event_ScriptedStop ( void ) {
ScriptedStop ( );
}
/*
================
idAI::Event_AllowHiddenMovement
================
*/
void idAI::Event_AllowHiddenMovement( int enable ) {
move.fl.allowHiddenMove = ( enable != 0 );
}
/*
================
idAI::Event_SetScript
================
*/
void idAI::Event_SetScript ( const char* scriptName, const char* funcName ) {
SetScript ( scriptName, funcName );
}
/*
================
idAI::Event_SetMoveSpeed
================
*/
void idAI::Event_SetMoveSpeed ( int speed ) {
switch ( speed ) {
case AIMOVESPEED_DEFAULT:
move.fl.noRun = false;
move.fl.noWalk = false;
break;
case AIMOVESPEED_RUN:
move.fl.noRun = false;
move.fl.noWalk = true;
break;
case AIMOVESPEED_WALK:
move.fl.noRun = true;
move.fl.noWalk = false;
break;
}
}
/*
================
idAI::Event_SetPassivePrefix
================
*/
void idAI::Event_SetPassivePrefix ( const char* prefix ) {
SetPassivePrefix ( prefix );
}
/*
================
idAI::Event_Attack
================
*/
void idAI::Event_Attack ( const char* attackName, const char* jointName ) {
Attack ( attackName, animator.GetJointHandle ( jointName ), enemy.ent ); // , physicsObj.GetPushedLinearVelocity ( ) );
}
/*
================
idAI::Event_AttackMelee
================
*/
void idAI::Event_AttackMelee( const char* meleeName ) {
const idDict* meleeDict;
meleeDict = gameLocal.FindEntityDefDict ( spawnArgs.GetString ( va("def_attack_%s", meleeName ) ), false );
if ( !meleeDict ) {
gameLocal.Error ( "missing meleeDef '%s' for ai entity '%s'", meleeName, GetName() );
}
AttackMelee ( meleeName, meleeDict );
}
/*
================
idAI::Event_ScriptedJumpDown
================
*/
void idAI::Event_ScriptedJumpDown( float yaw ) {
if ( animator.HasAnim( "jumpdown_start" ) )
{
aifl.scripted = true;
move.ideal_yaw = yaw;
SetState( "State_ScriptedJumpDown" );
}
}
/*
================
idAI::Event_FindEnemy
================
*/
void idAI::Event_FindEnemy( float distSqr ) {
idThread::ReturnEntity ( FindEnemy( false, 1, distSqr ));
}
/*
================
idAI::Event_SetKey
================
*/
void idAI::Event_SetKey( const char *key, const char *value ) {
spawnArgs.Set( key, value );
OnSetKey ( key, value );
}
/*
================
idAI::Event_PostSpawn
================
*/
void idAI::Event_PostSpawn( void ) {
// RAVEN BEGIN
// twhitaker: difficulty levels
if ( team == TEAM_MARINE ) {
//health /= 1.0f + gameLocal.GetDifficultyModifier( );
//buddies are a little more healthy on hard & nightmare since the baddies deal so much more damage
switch ( g_skill.GetInteger() ) {
case 3:
health *= 1.4f;
break;
case 2:
health *= 1.2f;
break;
case 0:
health *= 1.2f;
break;
case 1:
default:
break;
}
} else {
health *= 1.0f + gameLocal.GetDifficultyModifier( );
}
// RAVEN END
}