1 //
2 // C++ Interface: bot
3 //
4 // Description:
5 //
6 // Main bot header
7 //
8 //
9 // Author:  Rick <rickhelmus@gmail.com>
10 //
11 //
12 //
13 
14 
15 /*
16 
17      TODO list
18 
19      -bots that "cover" each other in team matches ?
20      -If a bot gets ammo it should ignore that kind of ammo for the next 10 seconds. ?
21      -bots should ignore players that are too far away ?
22      -bots should dodge/jump when shot at
23      -If the bot's only weapon is the fist it should make looking for ammo its priority - Done ?
24      -bots should rocket jump to get quads and the 150 armor if normal jumping doesn't
25       work (only if health is x so they don't suicide).
26      -Make all the "UNDONE's" done :)
27      -Finish waypoint navigation
28      -Make bot personalities
29      -More advanced enemy scoring
30      -Bots should less bump into walls
31      -(Better) Coop support
32      -Check for reachable instead of visible in GetNearestWaypoint
33      -Waypoint experience file
34      -Bots should avoid team mates
35      -Handle failed goals better(ie remember them)
36      -Test multiplayer
37      -Fix bots getting stuck in each other
38      -Optimize hunting code
39      -Check/Fix msg code
40 */
41 
42 #ifndef BOT_H
43 #define BOT_H
44 
45 //#define RELEASE_BUILD // Set when you want to make a release build
46 
47 
48 // Set for which mod the code is
49 
50 //#define VANILLA_CUBE
51 #define AC_CUBE
52 //#define CUBE_X
53 
54 #include "bot_util.h"
55 #include "bot_waypoint.h"
56 
57 extern bool dedserv;
58 extern itemstat itemstats[];
59 
60 #ifdef RELEASE_BUILD
61 inline void condebug(const char *s, int a = 0, int b = 0, int c = 0) {}
62 inline void debugnav(const char *s, int a = 0, int b = 0, int c = 0) {}
debugbeam(vec & s,vec & e)63 inline void debugbeam(vec &s, vec &e) { }
64 #else
65 inline void condebug(const char *s, int a = 0, int b = 0, int c = 0) { /*conoutf(s, a, b, c);*/ }
66 inline void debugnav(const char *s, int a = 0, int b = 0, int c = 0) { /*conoutf(s, a, b, c);*/ }
debugbeam(vec & s,vec & e)67 inline void debugbeam(vec &s, vec &e) { /*if (!dedserv) particle_trail(1, 500, s, e);*/ }
68 #endif
69 
70 #define JUMP_HEIGHT      4.0f // NOT accurate
71 
72 #define FORWARD       (1<<1)
73 #define BACKWARD      (1<<2)
74 #define LEFT          (1<<3)
75 #define RIGHT         (1<<4)
76 #define UP            (1<<5)
77 #define DOWN          (1<<6)
78 #define DIR_NONE      0
79 
80 //fixmebot
81 #define m_sp 1000
82 #define m_classicsp 1000
83 
84 enum EBotCommands // For voting of bot commands
85 {
86      COMMAND_ADDBOT=0,
87      COMMAND_KICKBOT,
88      COMMAND_BOTSKILL
89 };
90 
91 struct bot_skill_s
92 {
93      float flMinReactionDelay; // Minimal reaction time
94      float flMaxReactionDelay; // Maximal reaction time
95      float flMinAimXSpeed; // Minimal X aim speed in degrees(base value)
96      float flMaxAimXSpeed; // Maximal X aim speed in degrees(base value)
97      float flMinAimYSpeed; // Minimal Y aim speed in degrees(base value)
98      float flMaxAimYSpeed; // Maximal Y aim speed in degrees(base value)
99      float flMinAimXOffset; // Minimal X aim offset in degrees(base value)
100      float flMaxAimXOffset; // Maximal X aim offset in degrees(base value)
101      float flMinAimYOffset; // Minimal Y aim offset in degrees(base value)
102      float flMaxAimYOffset; // Maximal Y aim offset in degrees(base value)
103      float flMinAttackDelay; // Minimal delay for when a bot can attack again
104      float flMaxAttackDelay; // Maximal delay for when a bot can attack again
105      float flMinEnemySearchDelay; // Minimal delay for when a bot can search for an
106                                   // enemy again
107      float flMaxEnemySearchDelay; // Maximal delay for when a bot can search for an
108                                   // enemy again
109      float flAlwaysDetectDistance;
110      short sShootAtFeetWithRLPercent; // Percent that a bot shoot with a rocket
111                                       // launcher at the enemy feet.
112      int iMaxHearVolume; // Max volume that bot can hear
113      int iFov; // bots field of view
114      bool bCanPredict; // Can this bot predict his enemy position?
115      bool bCircleStrafe; // Can this bot circle strafe?
116      bool bCanSearchItemsInCombat;
117 };
118 
119 enum EBotWeaponTypes
120 {
121      TYPE_MELEE, // Fist, knife etc
122      TYPE_NORMAL, // Normal weapon, distance doesn't really matter(ie pistol)
123      TYPE_SHOTGUN,
124      TYPE_ROCKET,
125      TYPE_SNIPER, // Rifle, sniper etc
126      TYPE_GRENADE,
127      TYPE_AUTO // Chain gun, machine gun etc
128 };
129 
130 struct weaponinfo_s
131 {
132      EBotWeaponTypes eWeaponType;
133      float flMinDesiredDistance;
134      float flMaxDesiredDistance;
135      float flMinFireDistance;
136      float flMaxFireDistance;
137      short sMinDesiredAmmo;
138 };
139 
140 enum ECurrentBotState
141 {
142      STATE_ENEMY, // Bot has an enemy
143      STATE_HUNT, // Bot is hunting an enemy
144      STATE_ENT, // Bot is heading to an entity
145      STATE_SP, // Bot is doing sp specific stuff
146      STATE_NORMAL // Bot is doing normal navigation
147 };
148 
149 struct unreachable_ent_s
150 {
151      entity *ent;
152      int time;
153 
unreachable_ent_sunreachable_ent_s154      unreachable_ent_s(entity *e, int t) : ent(e), time(t) { };
155 };
156 
157 class CBot
158 {
159 public:
160      botent *m_pMyEnt;
161      int m_iLastBotUpdate;
162 
163      // Combat variabels
164      playerent *m_pPrevEnemy;
165      int m_iShootDelay;
166      int m_iChangeWeaponDelay;
167      int m_iCombatNavTime;
168      int m_iEnemySearchDelay;
169      int m_iSawEnemyTime;
170      bool m_bCombatJump;
171      float m_iCombatJumpDelay;
172      bool m_bShootAtFeet;
173 
174      // Hunting variabeles
175      int m_iHuntDelay;
176      vec m_vHuntLocation, m_vPrevHuntLocation;
177      playerent *m_pHuntTarget;
178      float m_fPrevHuntDist;
179      int m_iHuntPauseTime, m_iHuntPlayerUpdateTime, m_iHuntLastTurnLessTime;
180      int m_iLookAroundDelay, m_iLookAroundTime, m_iLookAroundUpdateTime;
181      float m_fLookAroundYaw;
182      bool m_bLookLeft;
183 
184      // Navigation variabeles
185      int m_iCheckEnvDelay;
186      int m_iLastJumpPad;
187      vec m_vPrevOrigin;
188      float m_iStuckCheckDelay;
189      bool m_bStuck;
190      int m_iStuckTime;
191      int m_iStrafeTime;
192      int m_iStrafeCheckDelay;
193      int m_iMoveDir;
194      int m_iSPMoveTime;
195      bool m_bCalculatingAStarPath;
196      TLinkedList<waypoint_s *> m_AStarNodeList;
197      TPriorList<waypoint_s *, float> m_AStarOpenList[2];
198      TLinkedList<waypoint_s *> m_AStarClosedList[2];
199      vec m_vWaterGoal; // Place to go to when underwater
200 
201      // Waypoint variabeles
202      TLinkedList<waypoint_s *> m_WaypointList[MAX_MAP_GRIDS][MAX_MAP_GRIDS];
203      float m_iWaypointTime;
204      waypoint_s *m_pCurrentWaypoint;
205      waypoint_s *m_pCurrentGoalWaypoint;
206      vec m_vGoal;
207      waypoint_s *m_pPrevWaypoints[5];
208      int m_iRandomWaypointTime;
209      float m_fPrevWaypointDistance;
210      int m_iLookForWaypointTime;
211      int m_iWaypointHeadLastTurnLessTime; // Last time the didn't had to turn much wile
212                                           // heading to a WP
213      int m_iWaypointHeadPauseTime; // Pause time to give the bot time to aim.
214      bool m_bGoToDebugGoal;
215 
216      // Misc stuff
217      ECurrentBotState m_eCurrentBotState;
218      entity *m_pTargetEnt;
219      TLinkedList<unreachable_ent_s *> m_UnreachableEnts;
220      int m_iCheckTeleporterDelay;
221      int m_iCheckJumppadsDelay;
222      int m_iCheckEntsDelay;
223      int m_iCheckTriggersDelay;
224      int m_iAimDelay;
225      float m_fYawToTurn, m_fPitchToTurn;
226      bot_skill_s *m_pBotSkill; // Pointer to current bot skill
227      short m_sSkillNr; // Skill number, 0 == best 4 == worst
228 
229      void AimToVec(const vec &o);
230      void AimToIdeal(void);
231      float ChangeAngle(float speed, float ideal, float current);
232      bool SelectGun(int Gun);
233      virtual void CheckItemPickup(void) = 0;
234      void SendBotInfo(void);
235      float GetDistance(const vec &o);
236      float GetDistance(const vec &v1, const vec &v2);
237      float GetDistance(entity *e);
Get2DDistance(const vec & v)238      float Get2DDistance(const vec &v) { return ::Get2DDistance(m_pMyEnt->o, v); };
GetViewAngles(void)239      vec GetViewAngles(void) { return vec(m_pMyEnt->pitch, m_pMyEnt->yaw, m_pMyEnt->roll); };
ResetMoveSpeed(void)240      void ResetMoveSpeed(void) { m_pMyEnt->move = m_pMyEnt->strafe = 0; };
241      void SetMoveDir(int iMoveDir, bool add);
242      void ResetCurrentTask();
243 
244      // AI Functions
245      bool BotsAgainstHumans();
246      bool DetectEnemy(playerent *p);
247      bool FindEnemy(void);
248      void CheckReload(void);
249      void CheckWeaponSwitch(void); // 2011jan17:ft: fix non-shooting bots
250      void CheckScope(void);
251      void ShootEnemy(void);
252      bool CheckHunt(void);
253      bool HuntEnemy(void);
254      void DoCombatNav(void);
255      void MainAI(void);
256      bool CheckStuck(void);
257      bool CheckJump(void);
258      bool CheckCrouch(void);
259      bool CheckStrafe(void);
260      void CheckFOV(void);
261      bool IsVisible(const vec &o, bool CheckPlayers = false) { return ::IsVisible(m_pMyEnt->o, o,
262                                                                       (CheckPlayers) ? m_pMyEnt :
263                                                                        NULL); };
264      bool IsVisible(playerent *d, bool CheckPlayers = false) { return ::IsVisible(m_pMyEnt->o, d->o,
265                                                                                (CheckPlayers) ?
266                                                                                 m_pMyEnt : NULL); };
267      bool IsVisible(entity *e, bool CheckPlayers = false);
268      bool IsVisible(vec o, int Dir, float flDist, bool CheckPlayers, float *pEndDist = NULL);
IsVisible(int Dir,float flDist,bool CheckPlayers)269      bool IsVisible(int Dir, float flDist, bool CheckPlayers)
270                           { return IsVisible(m_pMyEnt->o, Dir, flDist, CheckPlayers); };
271      bool IsInFOV(const vec &o);
IsInFOV(playerent * d)272      bool IsInFOV(playerent *d) { return IsInFOV(d->o); };
273      int GetShootDelay(void);
274      virtual bool ChoosePreferredWeapon(void);
275      virtual entity *SearchForEnts(bool bUseWPs, float flRange=9999.0f,
276                                    float flMaxHeight=JUMP_HEIGHT) = 0;
277      virtual bool HeadToTargetEnt(void) = 0;
278      bool CheckItems(void);
279      bool InUnreachableList(entity *e);
280      virtual bool DoSPStuff(void) = 0;
281      vec GetEnemyPos(playerent *d);
282      bool AStar(void);
283      float AStarCost(waypoint_s *pWP1, waypoint_s *pWP2);
284      void CleanAStarLists(bool bPathFailed);
285      bool IsReachable(vec to, float flMaxHeight=JUMP_HEIGHT);
286      bool WaterNav(void);
287      void HearSound(int n, vec *o);
288 
289      // Waypoint functions
290      bool HeadToWaypoint(void);
291      bool FindWaypoint(void);
292      void ResetWaypointVars(void);
293      void SetCurrentWaypoint(node_s *pWP);
294      void SetCurrentWaypoint(waypoint_s *pWP);
295      void SetCurrentGoalWaypoint(node_s *pNode);
296      void SetCurrentGoalWaypoint(waypoint_s *pWP);
297      bool CurrentWPIsValid(void);
298      bool ReachedGoalWP(void);
299      bool HeadToGoal(void);
300      waypoint_s *GetWPFromNode(node_s *pNode);
301      waypoint_s *GetNearestWaypoint(vec v_src, float flRange);
GetNearestWaypoint(float flRange)302      waypoint_s *GetNearestWaypoint(float flRange) { return GetNearestWaypoint(m_pMyEnt->o, flRange); };
303      waypoint_s *GetNearestTriggerWaypoint(vec v_src, float flRange);
304 #ifdef WP_FLOOD
305      waypoint_s *GetNearestFloodWP(vec v_origin, float flRange);
GetNearestFloodWP(float flRange)306      waypoint_s *GetNearestFloodWP(float flRange) { return GetNearestFloodWP(m_pMyEnt->o, flRange); };
307      waypoint_s *GetNearestTriggerFloodWP(vec v_origin, float flRange);
308 #endif
309      void SyncWaypoints(void);
310 
311      friend class CBotManager;
312      friend class CWaypointClass;
313 
314      bool m_bSendC2SInit;
315 
316      virtual ~CBot(void);
317 
318      virtual void Spawn(void);
319      virtual void Think(void);
320      void GoToDebugGoal(vec o);
321 };
322 
323 class CStoredBot // Used to store bots after mapchange, so that they can be readded
324 {
325 public:
326      char m_szName[32];
327      char m_szTeam[32];
328      short m_sSkillNr;
329 
CStoredBot(char * name,char * team,short skill)330      CStoredBot(char *name, char *team, short skill) : m_sSkillNr(skill)
331           { strcpy(m_szName, name); strcpy(m_szTeam, team); };
332 };
333 
334 extern vector<botent *> bots;
335 
336 class CBotManager
337 {
338      char m_szBotNames[150][16]; // Max 150 bot names with a length of 16 characters
339      short m_sBotNameCount;
340      char m_szBotTeams[20][5]; // Max 100 bot teams co a length of 5 characters
341      short m_sBotTeamCount;
342      bool m_bInit;
343      bool m_bBotsShoot;
344      bool m_bIdleBots;
345      bot_skill_s m_BotSkills[5]; // 5 different bot skills, 0 = best 4 = worst
346      int m_iFrameTime;
347      int m_iPrevTime;
348      short m_sBotSkill; // Bad - Worse - Medium - Good - Best
349      short m_sMaxAStarBots; // Max bots that can use a* at the same time
350      short m_sUsingAStarBotsCount; // Number of bots that are using a*
351      short m_sCurrentTriggerNr; // Current waypoint trigger bots should use
352      TLinkedList<CStoredBot *> m_StoredBots; // List of bots that should be re-added after map change
353      float m_fReAddBotDelay;
354 
355      void LoadBotNamesFile(void);
356      const char *GetBotName(void);
357      void LoadBotTeamsFile(void);
358      const char *GetBotTeam(void);
359      void CreateSkillData(void);
360      void InitSkillData(void);
361      void InitBotItems(void);
362 
363      friend class CBot;
364      friend class CCubeBot;
365      friend class CACBot;
366      friend class CWaypointClass;
367 
368 public:
369      botent *m_pBotToView;
370 
371      // Construction
CBotManager(void)372      CBotManager(void) { m_bInit = true; m_fReAddBotDelay = -1.0f; };
373 
374      // Destruction
375      ~CBotManager(void);
376 
377      void Init(void);
378      void Think(void);
379      void RenderBots(void);
RespawnBots(void)380      void RespawnBots(void) { loopv(bots) if (bots[i] && bots[i]->pBot) bots[i]->pBot->Spawn(); };
ClearStoredBots(void)381      void ClearStoredBots(void) { while(!m_StoredBots.Empty()) delete m_StoredBots.Pop(); }
ReAddBot(CStoredBot * bot)382      void ReAddBot(CStoredBot *bot) { CreateBot(bot->m_szTeam, SkillNrToSkillName(bot->m_sSkillNr), bot->m_szName); };
383      void EndMap(void);
384      void BeginMap(const char *szMapName);
385      int GetBotIndex(botent *m);
386      void LetBotsUpdateStats(void);
387      void LetBotsHear(int n, vec *loc);
388      void AddWaypoint(node_s *pNode);
389      void DelWaypoint(node_s *pNode);
BotsShoot(void)390      bool BotsShoot(void) { return m_bBotsShoot; };
IdleBots(void)391      bool IdleBots(void) { return m_bIdleBots; };
SetBotsShoot(bool bShoot)392      void SetBotsShoot(bool bShoot) { m_bBotsShoot = bShoot; };
SetIdleBots(bool bIdle)393      void SetIdleBots(bool bIdle) { m_bIdleBots = bIdle; };
EnableBotView(botent * bot)394      void EnableBotView(botent *bot) { m_pBotToView = bot; };
395      void DisableBotView(void);
396      void ChangeBotSkill(short Skill, botent *bot = NULL);
397      botent *CreateBot(const char *team, const char *skill, const char *name);
398      void ViewBot(void);
399      void CalculateMaxAStarCount(void);
400      void PickNextTrigger(void);
401 
402      void MakeBotFileName(const char *szFileName, const char *szDir1, const char *szDir2,
403                           char *szOutput);
404 };
405 
406 #if defined VANILLA_CUBE
407 #include "cube_bot.h"
408 #elif defined AC_CUBE
409 #include "ac_bot.h"
410 #endif
411 
412 extern CBotManager BotManager;
413 extern const vec g_vecZero;
414 
415 #if defined AC_CUBE
416 extern CACWaypointClass WaypointClass;
417 #elif defined VANILLA_CUBE
418 extern CCubeWaypointClass WaypointClass;
419 #endif
420 
421 extern void kickallbots();
422 
423 #endif
424