/* ================ AI.h ================ */ #ifndef __AI_H__ #define __AI_H__ // moved all motion related code to AI_Move.h #ifndef __AI_MOVE_H__ #include "AI_Move.h" #endif #ifndef __AAS_TACTICAL_H__ #include "AAS_tactical.h" #endif typedef enum { AITACTICAL_NONE, AITACTICAL_MELEE, // Rush towards the enemy and perform melee attacks when within range AITACTICAL_MOVE_FOLLOW, // Move towards leader, stop when within range AITACTICAL_MOVE_TETHER, // Move within tether, stop when within tether AITACTICAL_MOVE_PLAYERPUSH, // Move away when the player pushes us (or another ai entity pushes us that was pushe by player) AITACTICAL_COVER, // Move to cover and perform attacks from that cover position AITACTICAL_COVER_FLANK, AITACTICAL_COVER_ADVANCE, AITACTICAL_COVER_RETREAT, AITACTICAL_COVER_AMBUSH, AITACTICAL_RANGED, // Move to position in which the enemy can be attacked from range, stop when there and attack enemy AITACTICAL_TURRET, // Stay in current position and attack enemy AITACTICAL_HIDE, // Move to a position where we cannot be seen by our enemy AITACTICAL_PASSIVE, // Stay in current position with multiple idles, twitch animations, and conversations AITACTICAL_MAX } aiTactical_t; typedef enum { AICTRESULT_OK, AICTRESULT_SKIP, AICTRESULT_NOMOVE, } aiCTResult_t; const int AITACTICAL_NONE_BIT = BIT(AITACTICAL_NONE); const int AITACTICAL_MELEE_BIT = BIT(AITACTICAL_MELEE); const int AITACTICAL_MOVE_FOLLOW_BIT = BIT(AITACTICAL_MOVE_FOLLOW); const int AITACTICAL_MOVE_TETHER_BIT = BIT(AITACTICAL_MOVE_TETHER); const int AITACTICAL_MOVE_PLAYERPUSH_BIT = BIT(AITACTICAL_MOVE_PLAYERPUSH); const int AITACTICAL_COVER_BIT = BIT(AITACTICAL_COVER); const int AITACTICAL_COVER_FLANK_BIT = BIT(AITACTICAL_COVER_FLANK); const int AITACTICAL_COVER_ADVANCE_BIT = BIT(AITACTICAL_COVER_ADVANCE); const int AITACTICAL_COVER_RETREAT_BIT = BIT(AITACTICAL_COVER_RETREAT); const int AITACTICAL_COVER_AMBUSH_BIT = BIT(AITACTICAL_COVER_AMBUSH); const int AITACTICAL_RANGED_BIT = BIT(AITACTICAL_RANGED); const int AITACTICAL_TURRET_BIT = BIT(AITACTICAL_TURRET); const int AITACTICAL_HIDE_BIT = BIT(AITACTICAL_HIDE); const int AITACTICAL_PASSIVE_BIT = BIT(AITACTICAL_PASSIVE); const int AITACTICAL_COVER_BITS = (AITACTICAL_COVER_BIT|AITACTICAL_COVER_FLANK_BIT|AITACTICAL_COVER_ADVANCE_BIT|AITACTICAL_COVER_RETREAT_BIT|AITACTICAL_COVER_AMBUSH_BIT); const int AITACTICAL_RANGED_BITS = (AITACTICAL_RANGED_BIT); const int AITACTICAL_NONMOVING_BITS = (AITACTICAL_NONE_BIT|AITACTICAL_TURRET_BIT|AITACTICAL_PASSIVE_BIT); typedef enum { TALKMSG_NONE, TALKMSG_PRIMARY, TALKMSG_SECONDARY, TALKMSG_LOOP, } talkMessage_t; typedef enum { AIFLAGOVERRIDE_DAMAGE, AIFLAGOVERRIDE_DISABLEPAIN, AIFLAGOVERRIDE_NOTURN, AIFLAGOVERRIDE_NOGRAVITY } aiFlagOverride_t; typedef enum { TALK_NEVER, // Never talk to the player TALK_DEAD, // Cant talk due to being dead TALK_OK, // Can talk TALK_FOLLOW, // Talking to will cause a follow TALK_BUSY, // Cant talk right now, is busy TALK_WAIT, // Wait a bit - he's probably in the middle of a conversation (this is so you can still see their names but they won't talk to you when clicked on) NUM_TALK_STATES } talkState_t; //chance that AI will make an announcement when they have the option (0 - 1.0f) #define AISPEAK_CHANCE 0.2f typedef enum { AIFOCUS_NONE, AIFOCUS_LEADER, AIFOCUS_TARGET, AIFOCUS_TALK, AIFOCUS_PLAYER, AIFOCUS_USE_DIRECTIONAL_MOVE, AIFOCUS_ENEMY = AIFOCUS_USE_DIRECTIONAL_MOVE, AIFOCUS_COVER, AIFOCUS_COVERLOOK, AIFOCUS_HELPER, AIFOCUS_TETHER, AIFOCUS_MAX } aiFocus_t; typedef enum { AIMOVESPEED_DEFAULT, // Choose run/walk depending on situation AIMOVESPEED_RUN, // Always run AIMOVESPEED_WALK, // alwasy walk } aiMoveSpeed_t; typedef struct rvAIFuncs_s { rvScriptFuncUtility first_sight; // script to run when an enemy is first sighted rvScriptFuncUtility sight; // script to run every time an enemy is sighted rvScriptFuncUtility pain; // script to run when the AI takes pain rvScriptFuncUtility damage; // script to run when the AI takes damage rvScriptFuncUtility death; // script to run when the AI dies rvScriptFuncUtility attack; // script to run when attacking an enemy rvScriptFuncUtility init; // script to run on initialization rvScriptFuncUtility onclick; // script to run when a friendly AI is clicked on rvScriptFuncUtility launch_projectile; // script to run when a projectile is launched rvScriptFuncUtility footstep; // script to run on a footstep } rvAIFuncs_t; typedef struct rvAICombat_s{ struct combatFlags_s { bool ignoreEnemies :1; bool alert :1; bool aware :1; bool tetherNoBreak :1; // Set to true to prevent enemies from breaking tethers bool tetherAutoBreak :1; // Set to true to automatically break tethers when within range bool tetherOutOfRange :1; // Set to true when we are out of range of our curren tether bool seenEnemyDirectly :1; // Has directly seen an enemy (as opposed to having heard or been told about him) bool noChatter :1; // No combat announcements bool crouchViewClear :1; // Can I crouch at the position that I stopped at? } fl; float max_chasing_turn; float shotAtTime; float shotAtAngle; idVec2 hideRange; idVec2 attackRange; int attackSightDelay; float meleeRange; float aggressiveRange; // Range to become more aggressive float aggressiveScale; // Scale to use when altering numbers due to aggression int investigateTime; float visStandHeight; // Height to check enemy visibiliy while standing float visCrouchHeight; // Height to check enemy visiblity while crouching float visRange; // Maximum distance to check enemy visibility float earRange; // Maximum distance to check hearing an enemy from float awareRange; // Distance to become automatically aware of an enemy int tacticalMaskAvailable; // Currently available tactical states int tacticalMaskUpdate; // states currently being evaluated aiTactical_t tacticalCurrent; // Current tactical state int tacticalUpdateTime; // Last time the tacitcal state was updated (for delaying updating) int tacticalPainTaken; // Amount of damage taken in the current tactical state int tacticalPainThreshold; // Threshold of pain before invalidating the current tactical state int tacticalFlinches; // Number of flinches that have occured at the current tactical state float threatBase; // Base amount of threat generated by AI float threatCurrent; // Current amount of threat generatd by AI based on current state int maxLostVisTime; int coverValidTime; int maxInvalidCoverTime; } rvAICombat_t; typedef struct rvAIPain_s { float threshold; float takenThisFrame; int lastTakenTime; int loopEndTime; idStr loopType; } rvAIPain_t; typedef struct rvAIEnemy_s { struct flags_s { bool lockOrigin :1; // Stop tracking enemy origin until state changes bool dead :1; // Enemy is dead bool inFov :1; // Enemy is currently in fov bool sighted :1; // Enemy was sighted at least once bool visible :1; // Enemy is visible? } fl; idEntityPtr ent; int lastVisibleChangeTime; // last time the visible state of the enemy changed idVec3 lastVisibleFromEyePosition; // Origin used in last successfull visibility check idVec3 lastVisibleEyePosition; // Origin of last known visible eye position idVec3 lastVisibleChestPosition; // Origin of last known visible chest position int lastVisibleTime; // Time we last saw and enemy idVec3 smoothedLinearVelocity; idVec3 smoothedPushedVelocity; float smoothVelocityRate; idVec3 lastKnownPosition; // last place the enemy was known to be (does not mean visiblity) float range; // range to enemy float range2d; // 2d range to enemy int changeTime; // Time enemy was last changed int checkTime; // Time we last checked for a new enemy } rvAIEnemy_t; typedef struct rvAIPassive_s { struct flags_s { bool disabled :1; // No advanced passive state bool multipleIdles :1; // Has multiple idle animations to play bool fidget :1; // Has fidget animations } fl; idStr animIdlePrefix; idStr animFidgetPrefix; idStr animTalkPrefix; //idStr talkPrefix; idStr prefix; idStr idleAnim; int idleAnimChangeTime; int fidgetTime; int talkTime; } rvAIPassive_t; typedef struct rvAIAttackAnimInfo_s { idVec3 attackOffset; idVec3 eyeOffset; } rvAIAttackAnimInfo_t; #define AIACTIONF_ATTACK BIT(0) #define AIACTIONF_MELEE BIT(1) class rvAIActionTimer { public: rvAIActionTimer ( void ); bool Init ( const idDict& args, const char* name ); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); void Clear ( int currentTime ); void Reset ( int currentTime, float diversity = 0.0f, float scale = 1.0f ); void Add ( int _time, float diversity = 0.0f ); bool IsDone ( int currentTime ) const; int GetTime ( void ) const; int GetRate ( void ) const; protected: int time; int rate; }; ID_INLINE bool rvAIActionTimer::IsDone ( int currentTime ) const { return currentTime >= time; } ID_INLINE int rvAIActionTimer::GetTime ( void ) const { return time; } ID_INLINE int rvAIActionTimer::GetRate ( void ) const { return rate; } class rvAIAction { public: rvAIAction ( void ); bool Init ( const idDict& args, const char* name, const char* defaultState, int flags ); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); enum EStatus { STATUS_UNUSED, STATUS_OK, // action was performed STATUS_FAIL_DISABLED, // action is current disabled STATUS_FAIL_TIMER, // actions timer has not finished STATUS_FAIL_EXTERNALTIMER, // external timer passed in to PerformAction has not finished STATUS_FAIL_MINRANGE, // enemy is not within minimum range STATUS_FAIL_MAXRANGE, // enemy is out of maximum range STATUS_FAIL_CHANCE, // action chance check failed STATUS_FAIL_ANIM, // bad animation STATUS_FAIL_CONDITION, // condition given to PerformAction failed STATUS_FAIL_NOENEMY, // enemy cant be attacked STATUS_MAX }; struct flags_s { bool disabled :1; // action disabled? bool noPain :1; // no pain during action bool noTurn :1; // no turning during action bool isAttack :1; // attack? bool isMelee :1; // melee? bool overrideLegs :1; // override legs on this action? bool noSimpleThink :1; // dont use simple think logic for this action } fl; idStrList anims; idStr state; rvAIActionTimer timer; int blendFrames; int failRate; float minRange; float maxRange; float minRange2d; float maxRange2d; float chance; float diversity; EStatus status; }; typedef bool (idAI::*checkAction_t)(rvAIAction*,int); class rvPlaybackDriver { public: rvPlaybackDriver( void ) { mPlaybackDecl = NULL; mOldPlaybackDecl = NULL; } bool Start( const char *playback, idEntity *owner, int flags, int numFrames ); bool UpdateFrame( idEntity *ent, rvDeclPlaybackData &out ); void EndFrame( void ); bool IsActive( void ) { return( !!mPlaybackDecl || !!mOldPlaybackDecl ); } const char *GetDestination( void ); // cnicholson: Begin Added save/restore functionality void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); // cnicholson: End Added save/restore functionality private: int mLastTime; int mTransitionTime; int mStartTime; int mFlags; const rvDeclPlayback *mPlaybackDecl; idVec3 mOffset; int mOldStartTime; int mOldFlags; const rvDeclPlayback *mOldPlaybackDecl; idVec3 mOldOffset; }; /* =============================================================================== idAI =============================================================================== */ const float AI_TURN_SCALE = 60.0f; const float AI_SEEK_PREDICTION = 0.3f; const float AI_FLY_DAMPENING = 0.15f; const float AI_HEARING_RANGE = 2048.0f; const float AI_COVER_MINRANGE = 4.0f; const float AI_PAIN_LOOP_DELAY = 200; const int DEFAULT_FLY_OFFSET = 68.0f; #define ATTACK_IGNORE 0 #define ATTACK_ON_DAMAGE BIT(0) #define ATTACK_ON_ACTIVATE BIT(1) #define ATTACK_ON_SIGHT BIT(2) // defined in script/ai_base.script. please keep them up to date. #define DI_NODIR -1 // // events // extern const idEventDef AI_DirectDamage; extern const idEventDef AI_JumpFrame; extern const idEventDef AI_EnableClip; extern const idEventDef AI_DisableClip; extern const idEventDef AI_EnableGravity; extern const idEventDef AI_DisableGravity; extern const idEventDef AI_EnablePain; extern const idEventDef AI_DisablePain; extern const idEventDef AI_EnableTarget; extern const idEventDef AI_DisableTarget; extern const idEventDef AI_EnableMovement; extern const idEventDef AI_DisableMovement; extern const idEventDef AI_Vagary_ChooseObjectToThrow; extern const idEventDef AI_Speak; extern const idEventDef AI_SpeakRandom; extern const idEventDef AI_Attack; extern const idEventDef AI_AttackMelee; extern const idEventDef AI_WaitMove; extern const idEventDef AI_EnableDamage; extern const idEventDef AI_DisableDamage; extern const idEventDef AI_LockEnemyOrigin; extern const idEventDef AI_SetEnemy; extern const idEventDef AI_ScriptedAnim; extern const idEventDef AI_ScriptedDone; extern const idEventDef AI_ScriptedStop; extern const idEventDef AI_SetScript; extern const idEventDef AI_BecomeSolid; extern const idEventDef AI_BecomePassive; extern const idEventDef AI_BecomeAggressive; extern const idEventDef AI_SetHealth; extern const idEventDef AI_TakeDamage; extern const idEventDef AI_EnableBlink; extern const idEventDef AI_DisableBlink; extern const idEventDef AI_EnableAutoBlink; extern const idEventDef AI_DisableAutoBlink; class idPathCorner; class idProjectile; class rvSpawner; class rvAIHelper; class rvAITether; class idAI : public idActor { friend class rvAIManager; friend class idAASFindAttackPosition; public: CLASS_PROTOTYPE( idAI ); idAI(); ~idAI(); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); void Spawn ( void ); virtual void TalkTo ( idActor *actor ); idEntity* GetEnemy ( void ) const; idEntity* GetGoalEntity ( void ) const; talkState_t GetTalkState ( void ) const; const idVec2& GetAttackRange ( void ) const; const idVec2& GetFollowRange ( void ) const; int GetTravelFlags ( void ) const; void TouchedByFlashlight ( idActor *flashlight_owner ); idEntity * FindEnemy ( bool inFov, bool forceNearest, float maxDistSqr = 0.0f ); void SetSpawner ( rvSpawner* _spawner ); rvSpawner* GetSpawner ( void ); idActor* GetLeader ( void ) const; // Outputs a list of all monsters to the console. static void List_f( const idCmdArgs &args ); // Add some dynamic externals for debugging virtual void GetDebugInfo ( debugInfoProc_t proc, void* userData ); bool IsEnemyVisible ( void ) const; bool InCoverMode ( void ) const; bool InCrouchCoverMode ( void ) const; bool LookAtCoverTall ( void ) const; bool InLookAtCoverMode ( void ) const; bool IsBehindCover ( void ) const; bool IsLipSyncing ( void ) const; bool IsSpeaking ( void ) const; bool IsFacingEnt ( idEntity* targetEnt ); bool IsCoverValid ( void ) const; virtual bool IsCrouching ( void ) const; public: idLinkList simpleThinkNode; // navigation idAAS* aas; idAASCallback* aasFind; // movement idMoveState move; idMoveState savedMove; // physics idPhysics_Monster physicsObj; // weapon/attack vars bool lastHitCheckResult; int lastHitCheckTime; int lastAttackTime; float projectile_height_to_distance_ratio; // calculates the maximum height a projectile can be thrown idList attackAnimInfo; mutable idClipModel* projectileClipModel; idEntityPtr projectile; // chatter/talking int chatterTime; int chatterRateCombat; int chatterRateIdle; talkState_t talkState; idEntityPtr talkTarget; talkMessage_t talkMessage; int talkBusyCount; int speakTime; // Focus idEntityPtr lookTarget; aiFocus_t focusType; idEntityPtr focusEntity; float focusRange; int focusAlignTime; int focusTime; idVec3 currentFocusPos; // Looking bool allowJointMod; int alignHeadTime; int forceAlignHeadTime; idAngles eyeAng; idAngles lookAng; idAngles destLookAng; idAngles lookMin; idAngles lookMax; idList lookJoints; idList lookJointAngles; float eyeVerticalOffset; float eyeHorizontalOffset; float headFocusRate; float eyeFocusRate; // joint controllers idAngles eyeMin; idAngles eyeMax; jointHandle_t orientationJoint; idEntityPtr pusher; idEntityPtr scriptedActionEnt; // script variables struct aiFlags_s { bool awake :1; // set to false until state_wakeup is called. bool damage :1; bool pain :1; bool dead :1; bool activated :1; bool jump :1; bool hitEnemy :1; bool pushed :1; bool disableAttacks :1; bool scriptedEndWithIdle :1; bool scriptedNeverDormant :1; // Prevent going dormant while in scripted sequence bool scripted :1; bool simpleThink :1; bool ignoreFlashlight :1; bool action :1; bool lookAtPlayer :1; bool disableLook :1; bool undying :1; bool tetherMover :1; // Currently using a dynamic tether to a mover bool meleeSuperhero :1; bool killerGuard :1; // Do 100 points of damage with each hit } aifl; // // ai/ai.cpp // void SetAAS ( void ); virtual void DormantBegin ( void ); // called when entity becomes dormant virtual void DormantEnd ( void ); // called when entity wakes from being dormant virtual void Think ( void ); void Activate ( idEntity *activator ); virtual void Hide ( void ); virtual void Show ( void ); virtual void AdjustHealthByDamage ( int inDamage ); void CalculateAttackOffsets ( void ); void InitNonPersistentSpawnArgs ( void ); /* =============================================================================== Speaking & Chatter =============================================================================== */ public: bool Speak ( const char *speechDecl, bool random = false ); void StopSpeaking ( bool stopAnims ); virtual void CheckBlink ( void ); protected: virtual bool CanPlayChatterSounds ( void ) const; void UpdateChatter ( void ); /* =============================================================================== Movement =============================================================================== */ // static helper functions public: // Finds a path around dynamic obstacles. static bool FindPathAroundObstacles ( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path ); // Frees any nodes used for the dynamic obstacle avoidance. static void FreeObstacleAvoidanceNodes ( void ); // Predicts movement, returns true if a stop event was triggered. static bool PredictPath ( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path, const idEntity *ignore = NULL ); // Return true if the trajectory of the clip model is collision free. static bool TestTrajectory ( const idVec3 &start, const idVec3 &end, float zVel, float gravity, float time, float max_height, const idClipModel *clip, int clipmask, const idEntity *ignore, const idEntity *targetEntity, int drawtime ); // Finds the best collision free trajectory for a clip model. static bool PredictTrajectory ( const idVec3 &firePos, const idVec3 &target, float projectileSpeed, const idVec3 &projGravity, const idClipModel *clip, int clipmask, float max_height, const idEntity *ignore, const idEntity *targetEntity, int drawtime, idVec3 &aimDir ); // special flying code void AdjustFlyingAngles ( void ); void AddFlyBob ( idVec3 &vel ); void AdjustFlyHeight ( idVec3 &vel, const idVec3 &goalPos ); void FlySeekGoal ( idVec3 &vel, idVec3 &goalPos ); void AdjustFlySpeed ( idVec3 &vel ); void FlyTurn ( void ); // movement types void Move ( void ); virtual void DeadMove ( void ); void AnimMove ( void ); void SlideMove ( void ); void PlaybackMove ( void ); void FlyMove ( void ); void StaticMove ( void ); void RVMasterMove ( void ); void SetMoveType ( moveType_t moveType ); //twhitaker: added custom move type virtual void CustomMove ( void ); // movement actions void KickObstacles ( const idVec3 &dir, float force, idEntity *alwaysKick ); // steering virtual void ApplyImpulse ( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash = false ); void GetAnimMoveDelta ( const idMat3 &oldaxis, const idMat3 &axis, idVec3 &delta ); void CheckObstacleAvoidance ( const idVec3 &goalPos, idVec3 &newPos, idReachability* goalReach=0 ); bool GetMovePos ( idVec3 &seekPos, idReachability** seekReach=0 ); // navigation float TravelDistance ( const idVec3 &end ) const; float TravelDistance ( const idVec3 &start, const idVec3 &end ) const; float TravelDistance ( idEntity* ent ) const; float TravelDistance ( idEntity* start, idEntity* end ) const; int PointReachableAreaNum ( const idVec3 &pos, const float boundsScale = 2.0f ) const; bool PathToGoal ( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const; void BlockedFailSafe ( void ); // turning void Turn ( void ); bool TurnToward ( float yaw ); bool TurnToward ( const idVec3 &pos ); bool TurnTowardLeader ( bool faceLeaderByDefault=false ); bool FacingIdeal ( void ); bool DirectionalTurnToward ( const idVec3 &pos ); // movement control bool FaceEnemy ( void ); bool FaceEntity ( idEntity *ent ); bool SlideToPosition ( const idVec3 &pos, float time ); bool WanderAround ( void ); bool StepDirection ( float dir ); bool NewWanderDir ( const idVec3 &dest ); /* =============================================================================== Reactions =============================================================================== */ void ReactToShotAt ( idEntity* attacker, const idVec3 &origOrigin, const idVec3 &origDir ); void ReactToPain ( idEntity* attacker, int damage ); /* =============================================================================== AI helpers =============================================================================== */ public: void UpdateHelper ( void ); rvAIHelper* GetActiveHelper ( void ); /* =============================================================================== Sensory Perception =============================================================================== */ public: const idVec3& LastKnownPosition ( const idEntity *ent ); const idVec3& LastKnownFacing ( const idEntity *ent ); idEntity * HeardSound ( int ignore_team ); int ReactionTo ( const idEntity *ent ); void SetLastVisibleEnemyTime ( int time=-1/* DEFAULT IS CURRENT TIME*/ ); bool IsEnemyRecentlyVisible ( float maxLostVisTimeScale = 1.0f ) const; /* =============================================================================== Passive =============================================================================== */ public: void SetTalkState ( talkState_t state ); void SetPassivePrefix ( const char* prefix ); protected: bool GetPassiveAnimPrefix ( const char* animName, idStr& animPrefix ); /* =============================================================================== Combat =============================================================================== */ public: // enemy managment bool SetEnemy ( idEntity *newEnemy ); void ClearEnemy ( bool dead = false ); void UpdateEnemy ( void ); void UpdateEnemyPosition ( bool force = true ); void UpdateEnemyVisibility ( void ); // Attack direction bool GetAimDir ( const idVec3& source, const idEntity* aimAtEnt, const idDict* projectileDict, idEntity *ignore, idVec3 &aimDir, float aimOffset, float predict ) const; void GetPredictedAimDirOffset ( const idVec3& source, const idVec3& target, float projectileSpeed, const idVec3& targetVelocity, idVec3& offset ) const; // damage virtual bool Pain ( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); virtual void Killed ( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); bool CheckDeathCausesMissionFailure ( void ); // attacks virtual bool Attack ( const char* attackName, jointHandle_t joint, idEntity* target, const idVec3& pushVelocity = vec3_origin ); virtual idProjectile* AttackRanged ( const char* attackName, const idDict* attackDict, jointHandle_t joint, idEntity* target, const idVec3& pushVelocity = vec3_origin ); virtual idProjectile* AttackProjectile ( const idDict* projectileDict, const idVec3 &org, const idAngles &ang ); virtual bool AttackMelee ( const char* attackName, const idDict* meleeDict ); void CreateProjectileClipModel ( void ) const; idProjectile* CreateProjectile ( const idDict* projectileDict, const idVec3 &pos, const idVec3 &dir ); void RemoveProjectile ( void ); virtual void DamageFeedback ( idEntity *victim, idEntity *inflictor, int &damage ); void DirectDamage ( const char *meleeDefName, idEntity *ent ); bool TestMelee ( void ) const; void PushWithAF ( void ); bool IsMeleeNeeded ( void ); // special effects void GetMuzzle ( jointHandle_t joint, idVec3 &muzzle, idMat3 &axis ); void LerpLookAngles ( idAngles &curAngles, idAngles newAngles, float orientationJointYaw, float focusRate ); virtual bool UpdateAnimationControllers ( void ); // AI script state management void UpdateStates ( void ); void UpdateFocus ( const idMat3& orientationAxis ); void SetFocus ( aiFocus_t focus, int time ); // event? virtual void FootStep ( void ); void CreateMissile ( jointHandle_t joint ); void RadiusDamageFromJoint ( const char *jointname, const char *damageDefName ); void BecomeSolid ( void ); void BecomeNonSolid ( void ); const char * ChooseAnim ( int channel, const char *animname ); // // ai/ai_events.cpp // public: virtual bool CanTakeDamage ( void ) const; virtual bool CanTakePain ( void ) const; virtual bool CanTurn ( void ) const; virtual bool CanMove ( void ) const; virtual bool CanAnnounce ( float chance ) const; virtual bool SkipCurrentDestination ( void ) const; // ----------------------------- Functions ------------------------------------ virtual bool DoDormantTests ( void ); void OverrideFlag ( aiFlagOverride_t flag, bool value ); void RestoreFlag ( aiFlagOverride_t flag ); virtual bool SkipImpulse ( idEntity *ent, int id ); virtual const char* GetIdleAnimName ( void ); bool RespondToFlashlight ( void ) { return !aifl.ignoreFlashlight;} bool ForceFaceEnemy ( void ) { return ( move.moveCommand == MOVE_TO_ENEMY ); } bool CanBecomeSolid ( void ); bool CanHitEnemyFromAnim ( int animNum, idVec3 offset = vec3_origin ); bool CanHitEnemy ( void ); bool CanHitEnemyFromJoint ( const char *jointname ); float GetTurnDelta ( void ); int TestTrajectory ( const idVec3 &firePos, const idVec3 &target, const char *projectileName ); bool TestAnimMove ( int animNum, idEntity *ignore = NULL, idVec3 *pMoveVec = NULL ); void ExecScriptFunction ( rvScriptFuncUtility& func, idEntity* parm = NULL ); void SetLeader ( idEntity *newLeader ); int CheckMelee ( bool disableAttack ); bool CheckForEnemy ( bool useFov, bool force = false ); bool CheckForCloserEnemy ( void ); bool CheckForReplaceEnemy ( idEntity* replacement ); bool CheckForTeammateEnemy ( void ); void DrawSuspicion ( void ); float RateSuspiciousness ( idActor* shady, bool rateSound = false ); void RateSuspicionLevel ( void ); void UpdatePlayback ( idVec3 &goalPos, idVec3 &delta, idVec3 &oldorigin, idMat3 &oldaxis ); void LookAtEntity ( idEntity *ent, float duration ); // ----------------------------- Variables ------------------------------------ int actionAnimNum; // Index of animation to use for the upcoming action int actionTime; // Time line for actions (time is stopped when an action is running) int actionSkipTime; // Time to use if an action is skipped by another int flagOverrides; float announceRate; // How often (0 - 1.0f) the AI will make certain announcements. rvAICombat_t combat; // Members related to combat state rvAIPassive_t passive; // Members related to passive state rvAIEnemy_t enemy; // Members related to tracking enemies rvAIPain_t pain; rvAIFuncs_t funcs; rvPlaybackDriver mPlayback; rvPlaybackDriver mLookPlayback; rvAASTacticalSensor* aasSensor; idEntityPtr tether; idEntityPtr helperCurrent; idEntityPtr helperIdeal; idEntityPtr leader; idEntityPtr spawner; bool ValidateCover ( void ); virtual bool UpdateRunStatus ( void ); bool UpdateTactical ( int delay = 0 ); void ForceTacticalUpdate ( void ); bool UpdateTactical_r ( void ); virtual int FilterTactical ( int availableTactical ); void WakeUpTargets ( void ); virtual aiCTResult_t CheckTactical ( aiTactical_t tactical ); void Begin ( void ); void WakeUp ( void ); virtual void Prethink ( void ); virtual void Postthink ( void ); /* =============================================================================== Threat Management =============================================================================== */ protected: virtual void UpdateThreat ( void ); virtual float CalculateEnemyThreat ( idEntity* enemy ); /* =============================================================================== Tethers =============================================================================== */ public: virtual bool IsTethered ( void ) const; bool IsWithinTether ( void ) const; rvAITether* GetTether ( void ); virtual void SetTether ( rvAITether* newTether ); /* =============================================================================== Scripting =============================================================================== */ public: void ScriptedMove ( idEntity* destEnt, float minDist, bool endWithIdle ); void ScriptedFace ( idEntity* faceEnt, bool endWithIdle ); void ScriptedAnim ( const char* animname, int blendFrames, bool loop, bool endWithIdle ); void ScriptedPlaybackMove ( const char* playback, int flags, int numFrames ); void ScriptedPlaybackAim ( const char* playback, int flags, int numFrames ); void ScriptedAction ( idEntity* actionEnt, bool endWithIdle ); void ScriptedStop ( void ); void SetScript ( const char* scriptName, const char* funcName ); private: bool ScriptedBegin ( bool endWithIdle, bool allowDormant = false ); void ScriptedEnd ( void ); /* =============================================================================== Handlers =============================================================================== */ protected: virtual void OnDeath ( void ); virtual void OnStateChange ( int channel ); virtual void OnUpdatePlayback ( const rvDeclPlaybackData& pbd ); virtual void OnEnemyChange ( idEntity* oldEnemy ); virtual void OnLeaderChange ( idEntity* oldLeader ); virtual void OnStartMoving ( void ); virtual void OnStopMoving ( aiMoveCommand_t oldMoveCommand ); virtual void OnTacticalChange ( aiTactical_t oldTactical ); virtual void OnFriendlyFire ( idActor* attacker ); virtual void OnWakeUp ( void ); virtual void OnTouch ( idEntity *other, trace_t *trace ); virtual void OnCoverInvalidated ( void ); virtual void OnCoverNotFacingEnemy ( void ); virtual void OnEnemyVisiblityChange ( bool oldVisible ); virtual void OnStartAction ( void ); virtual void OnStopAction ( void ); virtual void OnSetKey ( const char* key, const char* value ); /* =============================================================================== Movement / Turning =============================================================================== */ protected: bool StartMove ( aiMoveCommand_t command, const idVec3& goalOrigin, int goalArea, idEntity* goalEntity, aasFeature_t* feature, float range ); void StopMove ( moveStatus_t status ); bool MoveTo ( const idVec3 &pos, float range = 0.0f ); bool MoveToAttack ( idEntity *ent, int attack_anim ); bool MoveToTether ( rvAITether* tether ); virtual bool MoveToEnemy ( void ); bool MoveToEntity ( idEntity *ent, float range = 0.0f ); bool MoveToCover ( float minRange, float maxRange, aiTactical_t coverType ); bool MoveToHide ( void ); bool MoveOutOfRange ( idEntity *entity, float range, float minRange=0.0f ); void AnimTurn ( float angles, bool force ); bool ReachedPos ( const idVec3 &pos, const aiMoveCommand_t moveCommand, float range = 0.0f ) const; /* =============================================================================== Debug =============================================================================== */ public: void DrawRoute ( void ) const; void DrawTactical ( void ); /* =============================================================================== Announcements =============================================================================== */ public: bool ActorIsBehindActor ( idActor* ambusher, idActor* victim ); void AnnounceNewEnemy ( void ); void AnnounceKill ( idActor *victim ); void AnnounceTactical ( aiTactical_t newTactical ); void AnnounceSuppressed ( idActor *suppressor ); void AnnounceSuppressing ( void ); void AnnounceFlinch ( idEntity *attacker ); void AnnounceInjured ( void ); void AnnounceFriendlyFire ( idActor* attacker ); void AnnounceGrenade ( void ); void AnnounceGrenadeThrow ( void ); /* =============================================================================== Actions =============================================================================== */ protected: rvAIActionTimer actionTimerRangedAttack; rvAIActionTimer actionTimerEvade; rvAIActionTimer actionTimerSpecialAttack; rvAIActionTimer actionTimerPain; rvAIAction actionEvadeLeft; rvAIAction actionEvadeRight; rvAIAction actionRangedAttack; rvAIAction actionMeleeAttack; rvAIAction actionLeapAttack; rvAIAction actionJumpBack; bool UpdateAction ( void ); virtual bool CheckActions ( void ); virtual bool CheckPainActions ( void ); bool PerformAction ( rvAIAction* action, bool (idAI::*)(rvAIAction*,int), rvAIActionTimer* timer = NULL ); void PerformAction ( const char* stateName, int blendFrames = 0, bool noPain = false ); // RAVEN BEGIN // twhitaker: needed this for difficulty settings virtual void Event_PostSpawn ( void ); // RAVEN END public: virtual bool CheckAction_EvadeLeft ( rvAIAction* action, int animNum ); virtual bool CheckAction_EvadeRight ( rvAIAction* action, int animNum ); virtual bool CheckAction_RangedAttack ( rvAIAction* action, int animNum ); virtual bool CheckAction_MeleeAttack ( rvAIAction* action, int animNum ); bool CheckAction_LeapAttack ( rvAIAction* action, int animNum ); virtual bool CheckAction_JumpBack ( rvAIAction* action, int animNum ); /* =============================================================================== Events =============================================================================== */ private: // Orphaned events void Event_ClosestReachableEnemyOfEntity ( idEntity *team_mate ); void Event_GetReachableEntityPosition ( idEntity *ent ); void Event_EntityInAttackCone ( idEntity *ent ); void Event_TestAnimMoveTowardEnemy ( const char *animname ); void Event_TestAnimMove ( const char *animname ); void Event_TestMoveToPosition ( const idVec3 &position ); void Event_TestMeleeAttack ( void ); void Event_TestAnimAttack ( const char *animname ); void Event_SaveMove ( void ); void Event_RestoreMove ( void ); void Event_ThrowMoveable ( void ); void Event_ThrowAF ( void ); void Event_PredictEnemyPos ( float time ); void Event_FindActorsInBounds ( const idVec3 &mins, const idVec3 &maxs ); void Event_Activate ( idEntity *activator ); void Event_Touch ( idEntity *other, trace_t *trace ); void Event_LookAt ( idEntity* lookAt ); void Event_SetAngles ( idAngles const &ang ); void Event_SetEnemy ( idEntity *ent ); void Event_SetHealth ( float newHealth ); void Event_SetTalkTarget ( idEntity *target ); void Event_SetTalkState ( int state ); void Event_SetLeader ( idEntity *newLeader ); void Event_SetScript ( const char* scriptName, const char* funcName ); void Event_SetMoveSpeed ( int speed ); void Event_SetPassivePrefix ( const char* prefix ); void Event_GetAngles ( void ); void Event_GetEnemy ( void ); void Event_GetLeader ( void ); void Event_Attack ( const char* attackName, const char* jointName ); void Event_AttackMelee ( const char *meleeDefName ); void Event_DirectDamage ( idEntity *damageTarget, const char *damageDefName ); void Event_RadiusDamageFromJoint ( const char *jointname, const char *damageDefName ); void Event_CanBecomeSolid ( void ); void Event_BecomeSolid ( void ); void Event_BecomeNonSolid ( void ); void Event_BecomeRagdoll ( void ); void Event_StopRagdoll ( void ); void Event_FaceEnemy ( void ); void Event_FaceEntity ( idEntity *ent ); void Event_WaitMove ( void ); void Event_BecomePassive ( int ignoreEnemies ); void Event_BecomeAggressive ( void ); void Event_EnableDamage ( void ); void Event_EnableClip ( void ); void Event_EnableGravity ( void ); void Event_EnableAFPush ( void ); void Event_EnablePain ( void ); void Event_DisableDamage ( void ); void Event_DisableClip ( void ); void Event_DisableGravity ( void ); void Event_DisableAFPush ( void ); void Event_DisablePain ( void ); void Event_EnableTarget ( void ); void Event_DisableTarget ( void ); void Event_TakeDamage ( float takeDamage ); void Event_SetUndying ( float setUndying ); void Event_EnableAutoBlink ( void ); void Event_DisableAutoBlink ( void ); void Event_LockEnemyOrigin ( void ); void Event_StopThinking ( void ); void Event_JumpFrame ( void ); void Event_RealKill ( void ); void Event_Kill ( void ); void Event_RemoveUpdateSpawner ( void ); void Event_AllowHiddenMovement ( int enable ); void Event_CanReachPosition ( const idVec3 &pos ); void Event_CanReachEntity ( idEntity *ent ); void Event_CanReachEnemy ( void ); void Event_IsSpeaking ( void ); void Event_IsTethered ( void ); void Event_IsWithinTether ( void ); void Event_IsMoving ( void ); void Event_Speak ( const char *speechDecl ); void Event_SpeakRandom ( const char *speechDecl ); void Event_ScriptedMove ( idEntity* destEnt, float minDist, bool endWithIdle ); void Event_ScriptedFace ( idEntity* faceEnt, bool endWithIdle ); void Event_ScriptedAnim ( const char* animname, int blendFrames, bool loop, bool endWithIdle ); void Event_ScriptedPlaybackMove ( const char* playback, int flags, int numFrames ); void Event_ScriptedPlaybackAim ( const char* playback, int flags, int numFrames ); void Event_ScriptedAction ( idEntity* actionEnt, bool endWithIdle ); void Event_ScriptedDone ( void ); void Event_ScriptedStop ( void ); void Event_ScriptedJumpDown ( float yaw ); void Event_FindEnemy ( float distSquare ); void Event_SetKey ( const char *key, const char *value ); /* =============================================================================== States =============================================================================== */ protected: // Wait states stateResult_t State_Wait_Activated ( const stateParms_t& parms ); stateResult_t State_Wait_ScriptedDone ( const stateParms_t& parms ); stateResult_t State_Wait_Action ( const stateParms_t& parms ); stateResult_t State_Wait_ActionNoPain ( const stateParms_t& parms ); // Global states stateResult_t State_WakeUp ( const stateParms_t& parms ); stateResult_t State_TriggerAnim ( const stateParms_t& parms ); stateResult_t State_Wander ( const stateParms_t& parms ); stateResult_t State_Killed ( const stateParms_t& parms ); stateResult_t State_Dead ( const stateParms_t& parms ); stateResult_t State_LightningDeath ( const stateParms_t& parms ); stateResult_t State_Burn ( const stateParms_t& parms ); stateResult_t State_Remove ( const stateParms_t& parms ); stateResult_t State_Passive ( const stateParms_t& parms ); stateResult_t State_Combat ( const stateParms_t& parms ); stateResult_t State_CombatCover ( const stateParms_t& parms ); stateResult_t State_CombatMelee ( const stateParms_t& parms ); stateResult_t State_CombatRanged ( const stateParms_t& parms ); stateResult_t State_CombatTurret ( const stateParms_t& parms ); virtual stateResult_t State_CombatHide ( const stateParms_t& parms ); stateResult_t State_MovePlayerPush ( const stateParms_t& parms ); stateResult_t State_MoveTether ( const stateParms_t& parms ); stateResult_t State_MoveFollow ( const stateParms_t& parms ); stateResult_t State_ScriptedMove ( const stateParms_t& parms ); stateResult_t State_ScriptedFace ( const stateParms_t& parms ); stateResult_t State_ScriptedStop ( const stateParms_t& parms ); stateResult_t State_ScriptedPlaybackMove ( const stateParms_t& parms ); stateResult_t State_ScriptedPlaybackAim ( const stateParms_t& parms ); stateResult_t State_ScriptedJumpDown ( const stateParms_t& parms ); // Torso States stateResult_t State_Torso_Idle ( const stateParms_t& parms ); stateResult_t State_Torso_Sight ( const stateParms_t& parms ); stateResult_t State_Torso_CustomCycle ( const stateParms_t& parms ); stateResult_t State_Torso_Action ( const stateParms_t& parms ); stateResult_t State_Torso_FinishAction ( const stateParms_t& parms ); stateResult_t State_Torso_Pain ( const stateParms_t& parms ); stateResult_t State_Torso_ScriptedAnim ( const stateParms_t& parms ); stateResult_t State_Torso_PassiveIdle ( const stateParms_t& parms ); stateResult_t State_Torso_PassiveFidget ( const stateParms_t& parms ); // Leg States stateResult_t State_Legs_Idle ( const stateParms_t& parms ); stateResult_t State_Legs_TurnLeft ( const stateParms_t& parms ); stateResult_t State_Legs_TurnRight ( const stateParms_t& parms ); stateResult_t State_Legs_Move ( const stateParms_t& parms ); stateResult_t State_Legs_MoveThink ( const stateParms_t& parms ); stateResult_t State_Legs_ChangeDirection ( const stateParms_t& parms ); // Head states stateResult_t State_Head_Idle ( const stateParms_t& parms ); CLASS_STATES_PROTOTYPE ( idAI ); }; /* =============================================================================== idAI Inlines =============================================================================== */ ID_INLINE int DelayTime( int min, int range ) { return min + gameLocal.random.RandomInt ( range + 1 ); } ID_INLINE const idVec2& idAI::GetAttackRange ( void ) const { return combat.attackRange; } ID_INLINE const idVec2& idAI::GetFollowRange ( void ) const { return move.followRange; } ID_INLINE int idAI::GetTravelFlags ( void ) const { return move.travelFlags; } ID_INLINE bool idAI::IsEnemyVisible ( void ) const { return enemy.ent && enemy.fl.visible; } ID_INLINE bool idAI::IsEnemyRecentlyVisible( float maxLostVisTimeScale ) const { return (enemy.ent && combat.fl.seenEnemyDirectly && (enemy.lastVisibleTime && gameLocal.time-enemy.lastVisibleTime < (combat.maxLostVisTime * maxLostVisTimeScale))); } ID_INLINE bool idAI::LookAtCoverTall( void ) const { return ( aasSensor->Look() && (aasSensor->Look()->flags&FEATURE_LOOK_OVER) && aasSensor->Look()->height > 40.0f ); } ID_INLINE bool idAI::InLookAtCoverMode ( void ) const { return (!IsBehindCover() && !aifl.action && move.fl.moving && (combat.fl.alert || combat.fl.aware) && aasSensor->Look() && combat.tacticalCurrent != AITACTICAL_MELEE && combat.tacticalCurrent != AITACTICAL_HIDE && !IsEnemyRecentlyVisible(0.2f)); } ID_INLINE bool idAI::InCoverMode ( void ) const { return ( (1<Reserved ( ); } ID_INLINE bool idAI::InCrouchCoverMode ( void ) const { return ( InCoverMode() && (aasSensor->Reserved()->flags&FEATURE_LOOK_OVER) ); } ID_INLINE bool idAI::IsBehindCover ( void ) const { return ( InCoverMode() && move.fl.done && (aifl.action || DistanceTo2d ( aasSensor->ReservedOrigin() ) < AI_COVER_MINRANGE) ); } ID_INLINE bool idAI::IsSpeaking ( void ) const { return speakTime && gameLocal.time < speakTime; } ID_INLINE bool idAI::IsFacingEnt ( idEntity* targetEnt ) { return( move.moveCommand == MOVE_FACE_ENTITY && move.goalEntity == targetEnt && FacingIdeal() ); } ID_INLINE bool idAI::IsCoverValid ( ) const { return combat.coverValidTime && (gameLocal.time - combat.coverValidTime < combat.maxInvalidCoverTime); } ID_INLINE idActor* idAI::GetLeader ( void ) const { return leader; } ID_INLINE idEntity* idAI::GetGoalEntity ( void ) const { return move.goalEntity; } ID_INLINE bool idAI::CanTakeDamage( void ) const { return idActor::CanTakeDamage( ); } ID_INLINE bool idAI::CanTakePain ( void ) const { return !disablePain; } ID_INLINE bool idAI::CanTurn ( void ) const { return move.turnRate && !move.fl.noTurn && !move.fl.disabled; } ID_INLINE bool idAI::CanMove ( void ) const { return !move.fl.disabled && !move.fl.blocked && gameLocal.GetTime()>move.blockTime; } ID_INLINE bool idAI::CanAnnounce ( float chance ) const { return !aifl.dead && !IsSpeaking ( ) && !af.IsActive ( ) && !combat.fl.noChatter && ( gameLocal.random.RandomFloat() < chance ); } ID_INLINE void idAI::SetFocus ( aiFocus_t focus, int time ) { focusType = focus; focusTime = gameLocal.time + time; } ID_INLINE idEntity *idAI::GetEnemy( void ) const { return enemy.ent; } ID_INLINE void idAI::ForceTacticalUpdate ( void ) { combat.tacticalUpdateTime = 0; combat.tacticalMaskUpdate = 0; delete aasFind; aasFind = NULL; } /* =============================================================================== externs =============================================================================== */ extern const char* aiActionStatusString [ rvAIAction::STATUS_MAX ]; extern const char* aiTalkMessageString [ ]; extern const char* aiTacticalString [ AITACTICAL_MAX ]; extern const char* aiMoveCommandString [ NUM_MOVE_COMMANDS ]; extern const char* aiFocusString [ AIFOCUS_MAX ]; #endif /* !__AI_H__ */