sof-sdk/Source/Game/gamecpp/ai.h
2000-06-15 00:00:00 +00:00

559 lines
No EOL
20 KiB
C++

#ifndef __AI_H
#define __AI_H
void vectoangles(vec3_t in, vec3_t out);//urk. the body of the stuff that uses this should be in .cpp, but for now, it's more convenient in here
#define SPAWNFLAG_ECON_OVERRIDE (1<<0)
#define SPAWNFLAG_BLIND (1<<1)
#define SPAWNFLAG_DEAF (1<<2)
#define SPAWNFLAG_NOSCALE (1<<3)
#define SPAWNFLAG_TRIGGER_SPAWN (1<<4)
#define SPAWNFLAG_SENSE_MUTE (1<<5)
#define SPAWNFLAG_START_ACTIVE (1<<6)
#define SPAWNFLAG_HOLD_POSITION (1<<7)
//
// bits 8 through 12 (0-indexed) are used in g_local.h for difficulty settings, deathmatch, and coop
//
#define SPAWNFLAG_NEVER_STARTLED (1<<13)
#define SPAWNFLAG_HOSTAGE (1<<14)
#define SPAWNFLAG_NO_ARMOR (1<<15)
#define SPAWNFLAG_ARMOR_PICKUP (1<<16)
#define SPAWNFLAG_NO_WEAPONS (1<<17)
#define SPAWNFLAG_NO_WOUND (1<<18)
#define SPAWNFLAG_HAS_PROJECTILE (1<<19)
#define SPAWNFLAG_FACE_PLAYER (1<<20)
#define MISC_FLAG_FIRINGBLIND 0x00000001
//
// Rick sez we've got up to bit 20
//
#define AIS_NODROPWEAPON 0x00000001
#define AIS_WONTADVANCE 0x00000002
#define AIS_NOKNOCKOVER 0x00000004
#define AIS_NOATTACKONRETREAT 0X00000008
#define AIS_NODUCK 0x00000010
#define AIS_NOSUPPRESS 0x00000020
#define AIS_CHEATERSEARCH 0x00000040
#define AIS_ATTACKONLYINRANGE 0x00000080
typedef enum
{
LEVCODE_UNKNOWN,
LEVCODE_TUTORIAL,
LEVCODE_NYC_SUBWAY,
LEVCODE_NYC_SUBWAY2,
LEVCODE_AFR_TRAIN,
LEVCODE_KOS_SEWER,
LEVCODE_KOS_BIGGUN,
LEVCODE_KOS_HANGAR,
LEVCODE_SIB_CANYON,
LEVCODE_SIB_BASE,
LEVCODE_SIB_PLANT,
LEVCODE_IRQ_TOWNA,
LEVCODE_IRQ_BUNKER,
LEVCODE_IRQ_CARGO,
LEVCODE_NYC_WARE,
LEVCODE_NYC_STEAM,
LEVCODE_NYC_STREETS,
LEVCODE_AFR_YARD,
LEVCODE_AFR_HOUSE,
LEVCODE_AFR_FACT,
LEVCODE_TOK_STREET,
LEVCODE_TOK_OFFICE,
LEVCODE_TOK_PENT,
LEVCODE_IRQ_STREETS,
LEVCODE_IRQ_FORT,
LEVCODE_IRQ_OIL,
LEVCODE_CAS_1,
LEVCODE_CAS_2,
LEVCODE_CAS_3,
LEVCODE_CAS_4,
LEVCODE_ARM_1,
LEVCODE_ARM_2,
LEVCODE_ARM_3,
} lev_interp_code;
//enemy styles
enum
{
EST_AGGRESSIVE,
EST_EVASIVE,
EST_SNEAKY,
EST_TACTICAL,
EST_COWARDLY,
EST_CAUTIOUS,
EST_NUM_STYLES
};
//enemy style shot at
enum
{
ESSA_RETREAT_TO_COVER,
ESSA_FLEE_TO_COVER,
ESSA_ATTACK_DIRECTION
};
//enemy style friends killed
enum
{
ESFK_IGNORE,
ESFK_RETREAT_TO_COVER,
ESFK_RETREAT_TO_ALLIES,
ESFK_RETREAT_TO_AMBUSH
};
//enemy style attacked
enum
{
ESAT_DUCK,
ESAT_APPROACH,
ESAT_CIRCLE,
ESAT_COVER_AND_ATTACK,
ESAT_COVER_AND_AMBUSH
};
//enemy style out of range
enum
{
ESOR_APPROACH,
ESOR_HOLD_POSITION,
ESOR_ATTACK_IF_POSSIBLE
};
//enemy style too close
enum
{
ESTC_ROLL_TO_SIDE,
ESTC_RETREAT,
ESTC_HOLD_POSITION,
ESTC_CIRCLE
};
//enemy style explosive
enum
{ //huh huh, huh huh
ESEX_RETREAT,
ESEX_DUCK,
ESEX_DODGE,
ESEX_IGNORE
};
typedef struct tempStyle_s
{
int shotAt;
int friendsKilled;
int attacked;
int outOfRange;
int tooClose;
int explosive;
}tempStyle_t;
class CAISkills
{
protected:
float idealRangeMin;
float idealRangeMax;
float dodgeAbility;
float shootingAccuracy;
float hesitation; // way to make guys less certain about attacking
float aimTime;
float cashValue;
int flags;
float turnSpeed;
int shotAt;
int friendsKilled;
int attacked;
int outOfRange;
int tooClose;
int explosive;
public:
CAISkills(void);
CAISkills(float rangeMin, float rangeMax, float dodge, float accuracy,
float newHesitation, float newAimTime, float newCashValue, float newTurnSpeed,float newFlags,
int newShotAt = 0, int newFriendsKilled = 0, int newAttacked = 0, int newOutOfRange = 0,
int newTooClose = 0, int newExplosive = 0);
void CAISkills::operator=(CAISkills &that);
float getRangeMin(void){return idealRangeMin;}
float getRangeMax(void){return idealRangeMax;}
float getDodge(void){return dodgeAbility;}
float getAccuracy(void){return shootingAccuracy;}
float getHesitation(void){return hesitation;}
float getAimTime(void){return aimTime;}
float getCashValue(void){return cashValue;}
float getDropWeap(void){return (flags & AIS_NODROPWEAPON) == 0;}
float getTurnSpeed(void){return turnSpeed;}
int testFlag(int flag){return (flags & flag);}
// rangeMin and Max are in terms of world units, dodge, accuracy, mobility, tactics, and cowardice are from 0 to 1,
// and aimMax is in world units. absoluteMin is in world units.
void setSkills(float rangeMin, float rangeMax, float dodge, float accuracy,
float newHesitation, float newAimTime, float newCashValue, float newTurnSpeed, float newFlags);
int getShotAt(void){return shotAt;}
int getFriendsKilled(void){return friendsKilled;}
int getAttacked(void){return attacked;}
int getOutOfRange(void){return outOfRange;}
int getTooClose(void){return tooClose;}
int getExplosive(void){return explosive;}
void setStyles(int newShotAt, int newFriendsKilled, int newAttacked, int newOutOfRange,
int newTooClose, int newExplosive);
void setStyles(int styleNum);
void InitStyles(edict_t *monster);
void adjustAccuracy(float val){shootingAccuracy *= val;}
};
// external table of skills so that guys know what they are
extern CAISkills enemySkills[];
typedef enum
{
LINK_NORMAL,
LINK_STAIR_UP,
LINK_STAIR_DOWN,
LINK_LADDER_UP,
LINK_LADDER_DOWN,
LINK_JUMP,
}connectType;
typedef struct nodeData_s
{
vec3_t curSpot;//used internally
vec3_t goPoint;
int curNode; // node we're at
int curRegion;
int nextNode; // node we're going to next
int finalNode; // node that is ultimately our destination
int blocked; // flag indicating we have been seriously impeded
int lastNode; // I was here before
int lastNode2; // and before
int lastNode3; // and before
int backingUp; // keep movements less jerky, please
int approaching; //
int corner1; // floors my corners are on
int corner2;
int corner3;
int corner4;
vec3_t lastDir;
float lastDirSetTime;
}nodeData_t;
lev_interp_code GetInterpCode(void);
void GetLevelSoundSuffix(char *putSuffixHere);
class ai_c: public ai_public_c
{
private:
float lFootPos, rFootPos;
qboolean done_firstframe;
float allowActionChangeTime;
vec3_t preset_mins[BBOX_PRESET_NUMBER];
vec3_t preset_maxs[BBOX_PRESET_NUMBER];
bbox_preset current_bbox;
float ground;
qboolean hasHadTarget;
float lastTargetTime;
float firstTargetTime;//when guys wake up, they need a bit of time to get the sleep out of their eyes, as it were...
qboolean abusedByTeam;
float lastNonTargetTime;//when guys search, set this. Need it for aiming and such too
float nextWakeReactTime;
// shared between all decisions
nodeData_t nodeData;
// enemyWorldInfo_e enemyInfo;
// float enemyInfoTime;
protected:
edict_t *ent;
edict_t *curTarget;
action_c_ptr current_action;
action_c_ptr recycle_action;
//moved from mosterinfo: keeps track of whether my standing support has gone gone away
int linkcount;
qboolean isActive;
//when i first get a target, should i consider going through the startled sequence?
qboolean isStartleable;
qboolean m_bHostage;
qboolean m_bSpecialBuddy;
qboolean m_bConcentratingOnPlayer;
vec3_t requestedMoveDir;//for guys bumpn into each other.
float scale;
int sense_mask;
float jumpdistance;
float jumpheight;
float fallheight;
float stepheight;
int move_mask;
int miscFlags;
priority_index worldpriority;
int lastCheckTime;
attention_index attentionLevel;
int watchState;
int lastCorpseCheck;
//the higher the rank, the more likely others will make room for me?
int rank;
CAISkills mySkills;
body_c_ptr body;
gg_obj_c_ptr MyGhoulObj;
vec3_t aim_angles;
vec3_t look_angles;
#define AI_SAVE_SIZE (offsetof(ai_c, look_angles) + sizeof(look_angles))
list<sense_c_ptr> senses;
list<action_c_ptr> actions;
list<decision_c_ptr> decisions;
virtual void Pain(edict_t &monster, edict_t *other, vec3_t point, float kick, int damage);
virtual void Die(edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int dflags = 0);
virtual void Escape(edict_t &monster);
void InitBBoxPreset(bbox_preset preset_index, vec_t xMinVal, vec_t yMinVal, vec_t zMinVal,
vec_t xMaxVal, vec_t yMaxVal, vec_t zMaxVal);
virtual void AddBody(edict_t *monster);
virtual void PickDeathAnim(edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int dflags = 0);
public:
ai_c(edict_t *monster=NULL);
virtual ~ai_c(void);
virtual qboolean IsFirstFrameTime(void);
virtual void SetEnt(edict_t *monster){ent=monster;}
virtual void FirstFrame(edict_t *monster);
virtual void Init(edict_t *monster, char *ghoulname="enemy/meso", char *subname="");
//the extent to which aim can deviate from edict's angles (in degrees)
virtual float GetAimConeDegrees(edict_t &monster, bbox_preset bbox);
//the extent of inaccuracy in aiming--that is, the difference between where i want to aim and where i do aim (in degrees)
virtual float GetAimDeviationDegrees(edict_t &monster);
//fixme: this is a shoddy way of handling save/load
virtual int GetClassCode(void){return AI_BASE;}//this should be different for everybody in this class family
//adjust this to return something moderately compatible with player team types
virtual int GetTeam(edict_t &monster){return 1;}
// someone can be on the other team and still be innocent (iraqi civilians)
virtual int IsInnocent() { return 0; }
virtual bool AmIAsGoodAsDead();
virtual qboolean SafeToRemove(edict_t &monster);
virtual void Emote(edict_t &monster, emotion_index new_emotion, float emotion_duration, qboolean scripted_emoting=false);
virtual emotion_index GetMood(edict_t &monster);
virtual void SetPriority(priority_index newp){worldpriority = newp;}
virtual priority_index GetPriority(void){return worldpriority;}
virtual void UseMonster(edict_t *user);
virtual void TouchMonster(edict_t *user);
virtual void SetAbusedByTeam(qboolean newa){abusedByTeam = newa;}
virtual qboolean GetAbusedByTeam(void){return abusedByTeam;}
virtual void NewSense(sense_c *new_sense, edict_t *monster);
// enemyWorldInfo_e LastEnemyInfo(void){return enemyInfo;}
// enemyWorldInfo_e CurrentEnemyInfo(void){if (enemyInfoTime > level.time-0.2)return enemyInfo; else return EWI_NUM;}
//add action to my action list; override Activate to let ai know I want to be considered activated (scripts, etc)
virtual void NewAction(action_c *new_action, edict_t *monster, qboolean activatenow=false);
virtual void NewNextAction(action_c *new_action, edict_t *monster, qboolean activatenow=false);
virtual void NewDecision(decision_c *new_decision, edict_t *monster);
virtual void NewCurrentAction(action_c *new_action, edict_t &monster);
virtual void NewDeathArmorAction(edict_t &monster);
virtual void NextAction(edict_t &monster);
virtual void EvaluateDecisions(edict_t &monster);
virtual void EvaluateSenses(edict_t &monster);
virtual void Think(edict_t &monster);
virtual qboolean Damage (edict_t &monster, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t origin, int damage, int knockback, int dflags, int mod, float penetrate, float absorb);
virtual float GetJumpDistance(void){return jumpdistance;}
virtual float GetJumpHeight(void){return jumpheight;}
virtual float GetFallHeight(void){return fallheight;}
virtual float GetStepHeight(void){return stepheight;}
virtual int GetMoveMask(void){return move_mask;}
virtual int GetRank(void){return rank;}
virtual void SetRank(int newrank){rank=newrank;}
virtual void GetSensedClientInfo(unsigned mask, sensedEntInfo_t &sensedEnt);
virtual void GetSensedMonsterInfo(unsigned mask, sensedEntInfo_t &sensedEnt);
virtual qboolean IsActive(void){return isActive;}
virtual void Activate(edict_t &monster);
virtual void SetStartleability(qboolean newVal){isStartleable=newVal;}
virtual qboolean GetStartleability(void){return isStartleable;}
virtual void SetHostage(qboolean bHostage) { m_bHostage = bHostage; }
virtual qboolean IsHostage() { return m_bHostage; }
virtual void SetSpecialBuddy(qboolean bBuddy) { m_bSpecialBuddy = bBuddy; }
virtual qboolean IsSpecialBuddy() { return m_bSpecialBuddy; }
virtual void SetConcentratingOnPlayer(qboolean bConcentrating) { m_bConcentratingOnPlayer = bConcentrating; }
virtual qboolean IsConcentratingOnPlayer() { return m_bConcentratingOnPlayer; }
//do i have a weapon?
virtual qboolean IsArmed(edict_t &monster);
virtual qboolean HasTarget(void){return (hasHadTarget && level.time-lastTargetTime<1.0);}
virtual qboolean HasHadTarget(void){return hasHadTarget;}
virtual void SetTargetTime(float now, edict_t *target, vec3_t position);
virtual edict_t *getTarget(void){return curTarget;}
virtual void setTarget(edict_t *target){assert((!target)||(target->inuse < 10));curTarget = target;}
virtual void setFirstTargetTime(float newTime){firstTargetTime = newTime;}
virtual float getFirstTargetTime(void){return firstTargetTime;}
virtual void setLastNonTargetTime(float newTime){lastNonTargetTime = newTime;}
virtual float getLastNonTargetTime(void){return lastNonTargetTime;}
virtual float getLastTargetTime(void){return lastTargetTime;}
virtual qboolean getTargetPos(vec3_t putPosHere);
virtual void MuteSenses(unsigned mask, float degree, smute_recovery recovery_code, float recovery_time);
virtual void RegisterSenseEvent(unsigned mask, vec3_t event_origin, float event_time, edict_t *event_edict, ai_sensetype_e event_code);
//go through senses asking them their muted level with this mask, and return highest response
virtual float GetSenseMutedLevel(unsigned mask);
virtual mmove_t *GetMove(void);
virtual void SetMove(mmove_t *newmove);
virtual body_c *GetBody(void){return body;}
virtual ggObjC *GetGhoulObj(void){return MyGhoulObj;}
virtual void SetAimAngles(vec3_t newaim){VectorCopy(newaim, aim_angles);}
virtual void SetAimVector(vec3_t newaim){vectoangles(newaim, aim_angles);}
virtual void GetAimAngles(vec3_t myaim){VectorCopy(aim_angles,myaim);}
virtual void GetAimVector(vec3_t forward){AngleVectors(aim_angles, forward, NULL, NULL);}
virtual void SetLookAngles(vec3_t newaim){VectorCopy(newaim, look_angles);}
virtual void SetLookVector(vec3_t newaim){vectoangles(newaim, look_angles);}
virtual void GetLookAngles(vec3_t myaim){VectorCopy(look_angles,myaim);}
virtual void GetLookVector(vec3_t forward){AngleVectors(look_angles, forward, NULL, NULL);}
virtual attention_index GetAttention(edict_t &monster){return attentionLevel;}
virtual void HandleCallBack(IGhoulInst *me,void *user,float now,const void *data);
virtual float GetLeftFootPos(void){return lFootPos;}
virtual float GetRightFootPos(void){return rFootPos;}
virtual void SetLeftFootPos(float newpos){lFootPos=newpos;}
virtual void SetRightFootPos(float newpos){rFootPos=newpos;}
virtual float GetGround(void){return ground;}
virtual void SetGround(float groundval);
virtual void FinishMove(edict_t &monster);
//send frames to body for storage
virtual void InAirFrame(edict_t &monster, float frameTime);
virtual void JumpFrame(edict_t &monster);
virtual void LandFrame(edict_t &monster);
virtual void AttackFrame(edict_t &monster);
virtual void MeleeFrame(edict_t &monster);
virtual void ThrowFrame(edict_t &monster);
virtual qboolean AttemptSetBBox (edict_t &monster, bbox_preset preset_index, qboolean forceZ = false);
virtual void ConfirmBBox (edict_t &monster, mmove_t *curMove);
virtual void GetBBoxPreset (bbox_preset preset_index, vec3_t pmins, vec3_t pmaxs){VectorCopy(preset_mins[preset_index],pmins);VectorCopy(preset_maxs[preset_index],pmaxs);}
virtual bbox_preset GetBBoxPresetIndex(edict_t &monster){return current_bbox;}
// Find a scripted decision
//if you pass in NULL, will return any old scripted decision
virtual scripted_decision *FindScriptedDecision(edict_t* ScriptEntity);
virtual void CancelScripting(edict_t* ScriptEntity);
// Find an order decision
decision_c *FindOrderDecision();
void RemoveOldDecisions(int code);
virtual action_c *GetLastAction();
int &GetMiscFlags(void){return miscFlags;}
bool GetLastActionDestination(vec3_t destination);
virtual void SetAttentionLevel(attention_index newIndex){assert(newIndex >= ATTENTION_DISTRACTED);assert(newIndex <= ATTENTION_ESCAPED); attentionLevel = newIndex;}
// Accessor function to Die
virtual void AnimDie(edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point){Die(monster, inflictor, attacker, damage, point);};
// Get a default action
virtual action_c *DefaultAction(decision_c *od, action_c *oa, mmove_t *newanim, vec3_t destination = vec3_origin, vec3_t facing = vec3_origin, edict_t *target = NULL, float timeout=0/*999999999999*/, qboolean fullAnimation = false);//for standing
virtual action_c *WalkAction(decision_c *od, action_c *oa, mmove_t *newanim, vec3_t destination, vec3_t facing = vec3_origin, float timeout=999999999999, qboolean fullAnimation = false);
virtual action_c *PainAction(decision_c *od, action_c *oa, mmove_t *newanim, edict_t &monster, edict_t *other, float kick, int damage, float timeout=999999999999, qboolean fullAnimation = true);
virtual action_c *DeathAction(decision_c *od, action_c *oa, mmove_t *newanim, edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
virtual action_c *DeathAction(decision_c *od, action_c *oa, mmove_t *newanim1, mmove_t *newanim2, edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
virtual action_c *DeathArmorAction(decision_c *od, action_c *oa, mmove_t *newanim, edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
virtual action_c *DeathArmorAction(decision_c *od, action_c *oa, mmove_t *newanim1, mmove_t *newanim2, edict_t &monster, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
virtual action_c *AttackAction(decision_c *od, action_c *oa, mmove_t *newanim, edict_t *attackTarget, vec3_t attackPos, vec3_t facing = vec3_origin, float timeout=999999999999, qboolean fullAnimation = false, bool shouldKill = false, int NullTarget = 0);
virtual action_c *JumpAction(decision_c *od, action_c *oa, mmove_t *newanim, vec3_t destination, vec3_t facing = vec3_origin, float timeout=999999999999, qboolean fullAnimation = false);
virtual action_c *FallAction(decision_c *od, action_c *oa, mmove_t *newanim, mmove_t *newanim2, vec3_t destination, vec3_t facing = vec3_origin, float timeout=999999999999, qboolean fullAnimation = false);
virtual action_c *SurrenderAction(decision_c *od, action_c *oa, mmove_t *newanim, edict_t *surrenderTo, vec3_t attackerPos, vec3_t facing = vec3_origin, float timeout=999999999999, qboolean fullAnimation = false);
virtual action_c *CaptureAction(decision_c *od, action_c *oa, mmove_t *newanim, edict_t *attackTarget, vec3_t attackPos, vec3_t facing = vec3_origin, float timeout=999999999999, qboolean fullAnimation = false);
virtual action_c *EndScriptAction(decision_c *od);
nodeData_t &getPathData(void){return nodeData;}
virtual qboolean BeingWatched(void){return watchState;}
virtual void WatchMe(void){watchState = true;}
virtual void UpdatePathPosition(edict_t *myEnt);
virtual int getMyNode(void){return nodeData.curNode;}
virtual void RegisterShotForDodge(vec3_t start, vec3_t end, edict_t *shooter);
virtual void RegisterShotForReply(vec3_t start, vec3_t end, edict_t *shooter);
virtual void Spook(float amount, vec3_t center);
virtual int CheckForCorpseActivate(edict_t &monster);
virtual void RequestMoveOutOfWay(vec3_t moveDir);
virtual float *GetMoveOutOfWay(void){return requestedMoveDir;}
virtual CAISkills *GetMySkills(void){return &mySkills;}
static ai_c *Create(int classcode, edict_t *monster=NULL, char *ghoulname="enemy/meso", char *subname="");
ai_c(ai_c *orig);
virtual void Evaluate(ai_c *orig);
virtual void Write();
virtual void Read();
};
/**********************************************************************************
**********************************************************************************/
#endif