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