#include "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 ( "" ); const idEventDef AI_RealKill ( "" ); 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( 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( 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( 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( 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 }