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<idEntity> 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 );