Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
bot.qc
Go to the documentation of this file.
1#include "bot.qh"
2
3#include <common/constants.qh>
4#include <common/mapinfo.qh>
8#include <common/stats.qh>
9#include <common/teams.qh>
10#include <common/util.qh>
15#include <server/antilag.qh>
23#include <server/campaign.qh>
24#include <server/client.qh>
25#include <server/damage.qh>
26#include <server/items/items.qh>
28#include <server/race.qh>
30#include <server/teamplay.qh>
33#include <server/world.qh>
35
37
38// TODO: remove this function! its only purpose is to update these fields since bot_setnameandstuff is called before ClientState
40{
41 CS_CVAR(this).cvar_cl_accuracy_data_share = 1; // share the bots weapon accuracy data with the world
42 CS_CVAR(this).cvar_cl_accuracy_data_receive = 0; // don't receive any weapon accuracy data
43}
44
46{
47 entity bot = spawnclient();
48 if (bot)
49 {
53 ClientConnect(bot);
56 if (!teamplay)
57 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, bot.netname);
58 }
59 return bot;
60}
61
62void bot_think(entity this)
63{
64 if (this.bot_nextthink > time)
65 return;
66
67 this.flags &= ~FL_GODMODE;
69 this.flags |= FL_GODMODE;
70
71 // if bot skill is high enough don't limit their think frequency
72 if (SUPERBOT)
73 this.bot_nextthink = max(time, this.bot_nextthink) + 0.005;
74 else
75 this.bot_nextthink = max(time, this.bot_nextthink) + max(0.01, autocvar_bot_ai_thinkinterval * min(14 / (skill + this.bot_aiskill + 14), 1));
76
78 {
79 CS(this).movement = '0 0 0';
80 this.bot_nextthink = time + 0.5;
81 return;
82 }
83
84 if (this.fixangle)
85 {
86 this.v_angle = this.angles;
87 this.v_angle_z = 0;
88 this.fixangle = false;
89 }
90
91 this.dmg_take = 0;
92 this.dmg_save = 0;
93 this.dmg_inflictor = NULL;
94
95 // if bot skill is high enough don't assign latency to them
96 if (SUPERBOT)
97 CS(this).ping = 0;
98 else
99 {
100 // calculate an aiming latency based on the skill setting
101 // (simulated network latency + naturally delayed reflexes)
102 //this.ping = 0.7 - bound(0, 0.05 * skill, 0.5); // moved the reflexes to bot_aimdir (under the name 'think')
103 // minimum ping 20+10 random
104 CS(this).ping = bound(0,0.07 - bound(0, (skill + this.bot_pingskill) * 0.005,0.05)+random()*0.01,0.65); // Now holds real lag to server, and higher skill players take a less laggy server
105 // skill 10 = ping 0.2 (adrenaline)
106 // skill 0 = ping 0.7 (slightly drunk)
107 }
108
109 // clear buttons
110 PHYS_INPUT_BUTTON_ATCK(this) = false;
111 // keep jump button pressed for a short while, useful with ramp jumps
112 PHYS_INPUT_BUTTON_JUMP(this) = (!IS_DEAD(this) && time < this.bot_jump_time + 0.2);
113 PHYS_INPUT_BUTTON_ATCK2(this) = false;
114 PHYS_INPUT_BUTTON_ZOOM(this) = false;
115 PHYS_INPUT_BUTTON_CROUCH(this) = false;
116 PHYS_INPUT_BUTTON_HOOK(this) = false;
117 PHYS_INPUT_BUTTON_INFO(this) = false;
118 PHYS_INPUT_BUTTON_DRAG(this) = false;
119 PHYS_INPUT_BUTTON_CHAT(this) = false;
120 PHYS_INPUT_BUTTON_USE(this) = false;
121
122 if (time < game_starttime)
123 {
124 // block the bot during the countdown to game start
125 CS(this).movement = '0 0 0';
126 return;
127 }
128
129 // if dead, just wait until we can respawn
130 if (IS_DEAD(this) || IS_OBSERVER(this))
131 {
132 if (bot_waypoint_queue_owner == this)
134 this.aistatus = 0;
135 CS(this).movement = '0 0 0';
136 if (IS_OBSERVER(this))
137 return;
138 if (IS_DEAD(this))
139 {
142 // jump must not be pressed for at least one frame in order for
143 // PlayerThink to detect the key down event
144 if (this.deadflag == DEAD_DYING)
145 PHYS_INPUT_BUTTON_JUMP(this) = false;
146 else if (this.deadflag == DEAD_DEAD)
147 PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn
148 }
149 }
150 else if(this.aistatus & AI_STATUS_STUCK)
151 navigation_unstuck(this);
152
153 if (warmup_stage && !this.ready)
154 {
155 this.ready = true;
156 ReadyCount(); // this must be delayed until the bot has spawned
157 }
158
159 // now call the current bot AI (havocbot for example)
160 this.bot_ai(this);
161}
162
164{
165 string readfile, s;
166 int file, tokens, prio;
167
169
170 if(file < 0)
171 {
172 LOG_INFOF("Error: Can not open the bot configuration file '%s'", autocvar_bot_config_file);
173 readfile = "";
174 }
175 else
176 {
179 int smallest_team = -1;
180 int smallest_count = -1;
181 if (teamplay)
182 {
183 for (int i = 1; i <= AVAILABLE_TEAMS; ++i)
184 {
185 // NOTE if (autocvar_g_campaign && autocvar_g_campaign_forceteam == i)
186 // TeamBalance_GetNumberOfPlayers(balance, i); returns the number of players + 1
187 // since it keeps a spot for the real player in the desired team
188 int count = TeamBalance_GetNumberOfPlayers(balance, i);
189 if (smallest_count < 0 || count < smallest_count)
190 {
191 smallest_team = i;
192 smallest_count = count;
193 }
194 }
195 }
196 TeamBalance_Destroy(balance);
198 while((readfile = fgets(file)))
199 {
200 if(substring(readfile, 0, 2) == "//")
201 continue;
202 if(substring(readfile, 0, 1) == "#")
203 continue;
204 // NOTE if the line is empty tokenizebyseparator(readfile, "\t")
205 // will create 1 empty token because there's no separator (bug?)
206 if (readfile == "")
207 continue;
208 tokens = tokenizebyseparator(readfile, "\t");
209 if(tokens == 0)
210 continue;
211 s = argv(0);
212 prio = 0;
213 bool conflict = false;
215 if (s == it.cleanname)
216 {
217 conflict = true;
218 break;
219 }
220 });
221 if (!conflict)
222 prio += 1;
224 {
225 int forced_team = stof(argv(5));
226 if (!Team_IsValidIndex(forced_team))
227 forced_team = 0;
228 if (!forced_team || forced_team == smallest_team)
229 prio += 2;
230 }
231 RandomSelection_AddString(readfile, 1, prio);
232 }
234 fclose(file);
235 }
236
237 string bot_name, bot_model, bot_skin, bot_shirt, bot_pants;
238
239 tokens = tokenizebyseparator(readfile, "\t");
240 if(argv(0) != "") bot_name = argv(0);
241 else bot_name = "Bot";
242
243 if(argv(1) != "") bot_model = argv(1);
244 else bot_model = "";
245
246 if(argv(2) != "") bot_skin = argv(2);
247 else bot_skin = "0";
248
249 if(argv(3) != "" && stof(argv(3)) >= 0) bot_shirt = argv(3);
250 else bot_shirt = ftos(floor(random() * 15));
251
252 if(argv(4) != "" && stof(argv(4)) >= 0) bot_pants = argv(4);
253 else bot_pants = ftos(floor(random() * 15));
254
256 {
257 this.bot_forced_team = stof(argv(5));
259 this.bot_forced_team = 0;
260 }
261 else
262 this.bot_forced_team = 0;
263
264 prio = 6;
265
266 #define READSKILL(f, w, r) MACRO_BEGIN \
267 if(argv(prio) != "") \
268 this.f = stof(argv(prio)) * w; \
269 else \
270 this.f = (!autocvar_g_campaign) * (2 * random() - 1) * r * w; \
271 prio++; \
272 MACRO_END
273 //print(bot_name, ": ping=", argv(9), "\n");
274
275 READSKILL(havocbot_keyboardskill, 0.5, 0.5); // keyboard skill
276 READSKILL(bot_moveskill, 2, 0); // move skill
277 READSKILL(bot_dodgeskill, 2, 0); // dodge skill
278
279 READSKILL(bot_pingskill, 0.5, 0); // ping skill
280
281 READSKILL(bot_weaponskill, 2, 0); // weapon skill
282 READSKILL(bot_aggresskill, 1, 0); // aggre skill
283 READSKILL(bot_rangepreference, 1, 0); // read skill
284
285 READSKILL(bot_aimskill, 2, 0); // aim skill
286 READSKILL(bot_offsetskill, 2, 0.5); // offset skill
287 READSKILL(bot_mouseskill, 1, 0.5); // mouse skill
288
289 READSKILL(bot_thinkskill, 1, 0.5); // think skill
290 READSKILL(bot_aiskill, 2, 0); // "ai" skill
291
292 // if bot skill is high enough don't limit their skill
293 if (SUPERBOT)
294 {
295 // commented out means they're meaningless with this high skill
296 // no reason to set them, uncomment if this changes
297 //this.havocbot_keyboardskill = 10;
298 //this.bot_moveskill = 10; //midair modifier sets this to 0 to disable bhop
299 //this.bot_dodgeskill = 10;
300 //this.bot_pingskill = 10;
301 //this.bot_weaponskill = 10;
302 //this.bot_aggresskill = 10;
303 this.bot_rangepreference = 1; // no range preference modification
304 //this.bot_aimskill = 10;
305 //this.bot_offsetskill = 10;
306 //this.bot_mouseskill = 10;
307 //this.bot_thinkskill = 10;
308 //this.bot_aiskill = 10;
309 }
310 if (file >= 0 && argv(prio) != "")
311 LOG_INFOF("^1Warning^7: too many parameters for bot %s, please check format of %s", bot_name, autocvar_bot_config_file);
312
313 this.bot_config_loaded = true;
314
315 setcolor(this, stof(bot_shirt) * 16 + stof(bot_pants));
316 this.team = -1; // undo team change by setcolor
317 // save clientcolors now because they may be overriden when joining a team
319
320 string prefix = (autocvar_g_campaign ? "" : autocvar_bot_prefix);
321 string suffix = (autocvar_g_campaign ? "" : autocvar_bot_suffix);
322 string name = (autocvar_bot_usemodelnames ? bot_model : bot_name);
323
324 if (name == "")
325 {
326 name = ftos(etof(this));
327 this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
328 }
329 else
330 {
331 // number bots with identical names
332 int j = 0;
334 if(it.cleanname == name)
335 ++j;
336 });
337 if (j)
338 this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
339 else
340 this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
341 }
342 this.cleanname = strzone(name);
343
344 // pick the model and skin
345 if(substring(bot_model, -4, 1) != ".")
346 bot_model = strcat(bot_model, ".iqm");
347 this.playermodel = this.playermodel_freeme = strzone(strcat("models/player/", bot_model));
348 this.playerskin = this.playerskin_freeme = strzone(bot_skin);
349}
350
352{
353 static string bot_priority_far_prev;
354 static string bot_priority_mid_prev;
355 static string bot_priority_close_prev;
356 static string bot_priority_distances_prev;
357 float tokens, i, w;
358
359 bot_custom_weapon = false;
360
365 )
366 return;
367
368 if (bot_priority_distances_prev != autocvar_bot_ai_custom_weapon_priority_distances)
369 {
370 strcpy(bot_priority_distances_prev, autocvar_bot_ai_custom_weapon_priority_distances);
372
373 if (tokens!=2)
374 return;
375
378
382 }
383 }
384
385 int c;
386
387 #define PARSE_WEAPON_PRIORITIES(dist) MACRO_BEGIN \
388 if (bot_priority_##dist##_prev != autocvar_bot_ai_custom_weapon_priority_##dist) { \
389 strcpy(bot_priority_##dist##_prev, autocvar_bot_ai_custom_weapon_priority_##dist); \
390 tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_##dist)," "); \
391 bot_weapons_##dist[0] = -1; \
392 c = 0; \
393 for(i = 0; i < tokens && c < REGISTRY_COUNT(Weapons); ++i) { \
394 w = stof(argv(i)); \
395 if (w >= WEP_FIRST && w <= WEP_LAST) { \
396 bot_weapons_##dist[c] = w; \
397 ++c; \
398 } \
399 } \
400 if (c < REGISTRY_COUNT(Weapons)) \
401 bot_weapons_##dist[c] = -1; \
402 } \
403 MACRO_END
404
408
409 bot_custom_weapon = true;
410}
411
413{
415 entity e = bot_list;
416 while (e)
417 {
418 setcolor(e, e.bot_preferredcolors);
419 e = e.nextbot;
420 }
421 // if dynamic waypoints are ever implemented, save them here
422}
423
425{
426 player_count = 0;
427 currentbots = 0;
428 bot_list = NULL;
429
430 entity prevbot = NULL;
431 FOREACH_CLIENT(true,
432 {
433 ++player_count;
434
435 if(IS_BOT_CLIENT(it))
436 {
437 if (!IS_OBSERVER(it) && !bot_ispaused(it))
438 {
439 if(prevbot)
440 prevbot.nextbot = it;
441 else
442 bot_list = it;
443 prevbot = it;
444 }
445 ++currentbots;
446 }
447 });
448 if(prevbot)
449 prevbot.nextbot = NULL;
452}
453
455{
456 if (!IS_BOT_CLIENT(this))
457 return;
458 bot_clearqueue(this);
459 strfree(this.cleanname);
463 if(this.bot_cmd_current)
464 delete(this.bot_cmd_current);
465 if(bot_waypoint_queue_owner == this)
467}
468
470{
471 if (!IS_BOT_CLIENT(this)) return;
473 this.bot_nextthink = time - random();
474 this.isbot = true;
475 this.createdtime = this.bot_nextthink;
476
477 if(!this.bot_config_loaded) // This is needed so team overrider doesn't break between matches
478 {
481 }
482
483 havocbot_setupbot(this);
484}
485
487{
490
491 entity best = NULL;
492 float besttime = 0;
493 int bestcount = 0;
494
495 int bcount = 0;
496 FOREACH_CLIENT(it.isbot,
497 {
498 ++bcount;
499
500 if(!best)
501 {
502 best = it;
503 besttime = it.createdtime;
504 }
505
506 int thiscount = 0;
507
508 if (Team_IsValidTeam(it.team))
509 {
510 thiscount = TeamBalance_GetNumberOfPlayers(balance,
511 Team_TeamToIndex(it.team));
512 }
513
514 if(thiscount > bestcount)
515 {
516 bestcount = thiscount;
517 besttime = it.createdtime;
518 best = it;
519 }
520 else if(thiscount == bestcount && besttime < it.createdtime)
521 {
522 besttime = it.createdtime;
523 best = it;
524 }
525 });
526 TeamBalance_Destroy(balance);
527 if(!bcount)
528 return; // no bots to remove
530 dropclient(best);
531}
532
534{
535 if(teamplay)
536 {
538 return;
539 }
540
541 float besttime = 0;
542 entity best = NULL;
543 int bcount = 0;
544
545 FOREACH_CLIENT(it.isbot,
546 {
547 ++bcount;
548
549 if(!best)
550 {
551 best = it;
552 besttime = it.createdtime;
553 }
554
555 if(besttime < it.createdtime)
556 {
557 besttime = it.createdtime;
558 best = it;
559 }
560 });
561
562 if(!bcount)
563 return; // no bots to remove
564
566 dropclient(best);
567}
568
569void autoskill(float factor)
570{
571 int bestbot = -1;
572 int bestplayer = -1;
574 if(IS_REAL_CLIENT(it))
575 bestplayer = max(bestplayer, it.totalfrags - it.totalfrags_lastcheck);
576 else
577 bestbot = max(bestbot, it.totalfrags - it.totalfrags_lastcheck);
578 });
579
580 string msg = strcat("autoskill: best player got ", ftos(bestplayer), ", ""best bot got ", ftos(bestbot), "; ");
581 if(bestbot < 0 || bestplayer < 0)
582 {
583 msg = strcat(msg, "not doing anything");
584 // don't return, let it reset all counters below
585 }
586 else if(bestbot <= bestplayer * factor - 2)
587 {
588 if(autocvar_skill < 17)
589 {
590 msg = strcat(msg, "2 frags difference, increasing skill");
591 cvar_set("skill", ftos(autocvar_skill + 1));
592 bprint("^2BOT SKILL UP!^7 Now at level ", ftos(autocvar_skill), "\n");
593 }
594 }
595 else if(bestbot >= bestplayer * factor + 2)
596 {
597 if(autocvar_skill > 0)
598 {
599 msg = strcat(msg, "2 frags difference, decreasing skill");
600 cvar_set("skill", ftos(autocvar_skill - 1));
601 bprint("^1BOT SKILL DOWN!^7 Now at level ", ftos(autocvar_skill), "\n");
602 }
603 }
604 else
605 {
606 msg = strcat(msg, "not doing anything");
607 return;
608 // don't reset counters, wait for them to accumulate
609 }
610 LOG_DEBUG(msg);
611
612 FOREACH_CLIENT(IS_PLAYER(it), { it.totalfrags_lastcheck = it.totalfrags; });
613}
614
622
623bool bot_fixcount(bool multiple_per_frame)
624{
625 int activerealplayers = 0;
626 int realplayers = 0;
627 if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers)) {
628 activerealplayers = M_ARGV(0, int);
629 realplayers = M_ARGV(1, int);
630 } else {
632 if(IS_PLAYER(it))
633 ++activerealplayers;
634 ++realplayers;
635 });
636 }
637
638 int bots;
639 // But don't remove bots immediately on level change, as the real players
640 // usually haven't rejoined yet
643 bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
644 else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
645 {
646 int minplayers = max(0, floor(autocvar_minplayers));
647 if (teamplay)
649 int minbots = max(0, floor(autocvar_bot_number));
650
651 // add bots to reach minplayers if needed
652 bots = max(minbots, minplayers - activerealplayers);
653 // cap bots to the max players allowed by the server
654 int player_limit = GetPlayerLimit();
655 if(player_limit)
656 bots = min(bots, max(player_limit - activerealplayers, 0));
657 bots = min(bots, maxclients - realplayers);
658
659 bots_would_leave = max(0, bots - minbots);
660 }
661 else
662 {
663 // if there are no players, remove bots
664 bots = 0;
665 }
666
667 // only add one bot per frame to avoid utter chaos
669 {
670 while (currentbots < bots)
671 {
672 if (bot_spawn() == NULL)
673 {
674 bprint("Can not add bot, server full.\n");
675 return false;
676 }
677 if (!multiple_per_frame)
678 {
679 break;
680 }
681 }
682 while (currentbots > bots && bots >= 0)
684 }
685
686 return true;
687}
688
690{
692 {
693 // after the end of the match all bots stay unless all human players disconnect
694 int realplayers = 0;
695 FOREACH_CLIENT(IS_REAL_CLIENT(it), { ++realplayers; });
696 if (!realplayers)
697 {
698 FOREACH_CLIENT(IS_BOT_CLIENT(it), { dropclient(it); });
699 currentbots = 0;
700 }
701 return;
702 }
703
704 if (game_stopped)
705 return;
706
707 // Added 0.5 to avoid possible addition + immediate removal of bots that would make them appear as
708 // spectators in the scoreboard and never go away. This issue happens at time 2 if map is changed
709 // with the gotomap command, minplayers is > 1 and human clients join as players very soon
710 // either intentionally or automatically (sv_spectate 0)
711 // A working workaround for this bug was implemented in commit fbd145044, see entcs_attach
712 if (time < 2.5)
713 {
714 currentbots = -1;
715 return;
716 }
717
718 if (currentbots == -1)
719 {
720 // count bots already in the server from the previous match
721 currentbots = 0;
723 }
724
725 if(autocvar_skill != skill)
726 {
727 float wpcost_update = false;
729 wpcost_update = true;
731 wpcost_update = true;
732
734 if (wpcost_update)
736 }
737
740
742 {
743 float a;
745 if(a)
746 autoskill(a);
748 }
749
751 {
752 if(!bot_fixcount(false))
754 }
755
757 {
759 localcmd("quit\n");
760 }
761
764 {
766 {
769 }
770 else
771 {
772 // TODO: Make this check cleaner
773 IL_EACH(g_waypoints, time - it.nextthink > 10,
774 {
775 waypoint_save_links();
776 break;
777 });
778 }
779 }
780 else
781 {
785 }
786
787 if (bot_list)
788 {
789 // cycle the goal token from one bot to the next each frame
790 // (this prevents them from all doing spawnfunc_waypoint searches on the same
791 // frame, which causes choppy framerates)
793 {
794 // give goal token to the first bot without goals; if all bots don't have
795 // any goal (or are dead/frozen) simply give it to the next one
797 entity bot_strategytoken_save = bot_strategytoken;
798 while (true)
799 {
804
806 && !bot_strategytoken.goalcurrent)
807 break;
808
809 if (!bot_strategytoken_save) // break loop if all the bots are dead or frozen
810 break;
811 if (bot_strategytoken == bot_strategytoken_save)
812 bot_strategytoken_save = NULL; // looped through all the bots
813 }
814 }
815
817 {
818 float interval;
820 if (botframe_nextdangertime < time - interval * 1.5)
824 }
825 }
826
829
832
833 if (currentbots > 0)
835}
float bot_forced_team
Definition api.qh:41
void navigation_goalrating_timeout_force(entity this)
Definition navigation.qc:29
bool navigation_goalrating_timeout(entity this)
Definition navigation.qc:44
float bot_moveskill
Definition api.qh:42
float skill
Definition api.qh:35
float bot_custom_weapon
Definition api.qh:31
int bots_would_leave
how many bots would leave so humans can replace them
Definition api.qh:101
int currentbots
Definition api.qh:104
float isbot
Definition api.qh:49
int player_count
Definition api.qh:103
string cleanname
Definition api.qh:45
IntrusiveList g_waypoints
Definition api.qh:148
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
bool bot_fixcount(bool multiple_per_frame)
Definition bot.qc:623
void bot_custom_weapon_priority_setup()
Definition bot.qc:351
void bot_setclientfields(entity this)
Definition bot.qc:39
void bot_think(entity this)
Definition bot.qc:62
#define PARSE_WEAPON_PRIORITIES(dist)
entity bot_spawn()
Definition bot.qc:45
void autoskill(float factor)
Definition bot.qc:569
#define READSKILL(f, w, r)
void bot_calculate_stepheightvec()
Definition bot.qc:615
void bot_setnameandstuff(entity this)
Definition bot.qc:163
void bot_removefromlargestteam()
Definition bot.qc:486
void bot_clientdisconnect(entity this)
Definition bot.qc:454
void bot_endgame()
Definition bot.qc:412
void bot_clientconnect(entity this)
Definition bot.qc:469
void bot_serverframe()
Definition bot.qc:689
void bot_removenewest()
Definition bot.qc:533
void bot_relinkplayerlist()
Definition bot.qc:424
float bot_aiskill
Definition bot.qh:42
string netname_freeme
Definition bot.qh:55
float createdtime
Definition bot.qh:61
float bot_aggresskill
Definition bot.qh:34
entity bot_list
Definition bot.qh:50
int aistatus
Definition bot.qh:20
float bot_pingskill
Definition bot.qh:31
float autoskill_nextthink
Definition bot.qh:25
float bot_weaponskill
Definition bot.qh:33
float bot_rangepreference
Definition bot.qh:35
string playermodel_freeme
Definition bot.qh:56
float bot_config_loaded
Definition bot.qh:74
entity bot_strategytoken
Definition bot.qh:77
float bot_mouseskill
Definition bot.qh:39
float botframe_spawnedwaypoints
Definition bot.qh:79
float bot_distance_far
Definition bot.qh:47
float bot_nextthink
Definition bot.qh:59
#define SUPERBOT
Definition bot.qh:23
float botframe_nextthink
Definition bot.qh:80
float bot_thinkskill
Definition bot.qh:41
float bot_aimskill
Definition bot.qh:37
float bot_jump_time
Definition bot.qh:71
float botframe_nextdangertime
Definition bot.qh:81
float bot_offsetskill
Definition bot.qh:38
string playerskin_freeme
Definition bot.qh:57
float bot_strategytoken_taken
Definition bot.qh:76
float bot_preferredcolors
Definition bot.qh:62
float bot_dodgeskill
Definition bot.qh:29
float bot_distance_close
Definition bot.qh:48
const int AI_STATUS_STUCK
Definition bot.qh:17
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
string netname
Definition powerups.qc:20
float count
Definition powerups.qc:22
bool ready
Definition main.qh:88
bool warmup_stage
Definition main.qh:120
int team
Definition main.qh:188
#define M_ARGV(x, type)
Definition events.qh:17
#define PHYS_INPUT_BUTTON_CROUCH(s)
Definition player.qh:154
float autocvar_sv_jumpvelocity
Definition player.qh:50
#define IS_DEAD(s)
Definition player.qh:245
#define PHYS_INPUT_BUTTON_JUMP(s)
Definition player.qh:151
#define PHYS_INPUT_BUTTON_HOOK(s)
Definition player.qh:155
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition player.qh:159
vector v_angle
Definition player.qh:237
#define PHYS_INPUT_BUTTON_INFO(s)
Definition player.qh:156
#define IS_PLAYER(s)
Definition player.qh:243
#define PHYS_INPUT_BUTTON_USE(s)
Definition player.qh:158
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:150
#define PHYS_INPUT_BUTTON_ZOOM(s)
Definition player.qh:153
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition player.qh:152
#define PHYS_INPUT_BUTTON_DRAG(s)
Definition player.qh:157
#define autocvar_sv_gravity
Definition stats.qh:421
float game_starttime
Definition stats.qh:82
float game_stopped
Definition stats.qh:81
float autocvar_sv_stepheight
Definition stats.qh:422
const int FL_GODMODE
Definition constants.qh:75
float flags
const float MOVE_NOMONSTERS
float maxclients
const float MOVE_NORMAL
const float FILE_READ
float time
float autocvar_bot_ai_thinkinterval
Definition cvars.qh:41
bool autocvar_bot_join_empty
Definition cvars.qh:49
bool autocvar_bot_navigation_ignoreplayers
Definition cvars.qh:50
int autocvar_bot_number
Definition cvars.qh:64
#define autocvar_bot_suffix
Definition cvars.qh:53
string autocvar_bot_ai_custom_weapon_priority_far
Definition cvars.qh:28
int autocvar_minplayers
Definition cvars.qh:68
float autocvar_skill_auto
Definition cvars.qh:62
string autocvar_bot_config_file
Definition cvars.qh:46
int autocvar_g_waypointeditor_auto
Definition cvars.qh:60
string autocvar_bot_ai_custom_weapon_priority_distances
Definition cvars.qh:27
bool autocvar_bot_usemodelnames
Definition cvars.qh:54
bool autocvar_waypoint_benchmark
Definition cvars.qh:63
int autocvar_minplayers_per_team
Definition cvars.qh:69
float autocvar_bot_ai_dangerdetectioninterval
Definition cvars.qh:30
string autocvar_bot_ai_custom_weapon_priority_mid
Definition cvars.qh:29
float autocvar_bot_ai_bunnyhop_skilloffset
Definition cvars.qh:19
string autocvar_bot_ai_custom_weapon_priority_close
Definition cvars.qh:26
int autocvar_bot_vs_human
Definition cvars.qh:67
#define autocvar_bot_prefix
Definition cvars.qh:52
bool autocvar_bot_god
Definition cvars.qh:47
float autocvar_bot_ai_dangerdetectionupdates
Definition cvars.qh:31
#define autocvar_skill
Definition cvars.qh:61
string playerskin
string playermodel
#define tokenizebyseparator
ent angles
Definition ent_cs.qc:121
clientcolors
Definition ent_cs.qc:147
void bot_clearqueue(entity bot)
Definition scripting.qc:21
void havocbot_setupbot(entity this)
Definition havocbot.qc:1764
float havocbot_keyboardskill
Definition havocbot.qh:7
best
Definition all.qh:82
bool intermission_running
#define IL_EACH(this, cond, body)
#define ClientConnect
Definition _all.inc:238
#define PutClientInServer
Definition _all.inc:246
#define STAT(...)
Definition stats.qh:82
#define LOG_DEBUG(...)
Definition log.qh:80
#define LOG_INFOF(...)
Definition log.qh:66
bool autocvar_g_campaign
Definition menu.qc:747
string name
Definition menu.qh:30
void localcmd(string command,...)
void cvar_set(string name, string value)
string fgets(float fhandle)
void fclose(float fhandle)
float ceil(float f)
float stof(string val,...)
float bound(float min, float value, float max)
string substring(string s, float start, float length)
float fopen(string filename, float mode)
float random(void)
void bprint(string text,...)
float min(float f,...)
string ftos(float f)
float fabs(float f)
float floor(float f)
string strzone(string s)
string argv(float n)
float max(float f,...)
#define etof(e)
Definition misc.qh:25
void navigation_unstuck(entity this)
void botframe_updatedangerousobjects(float maxupdate)
float bot_navigation_movemode
Definition navigation.qh:7
entity bot_waypoint_queue_owner
Definition navigation.qh:85
vector jumpstepheightvec
Definition navigation.qh:10
vector stepheightvec
Definition navigation.qh:11
vector jumpheight_vec
Definition navigation.qh:12
float jumpheight_time
Definition navigation.qh:13
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
#define NULL
Definition post.qh:14
#define setcolor
Definition pre.qh:11
float DEAD_DYING
Definition progsdefs.qc:275
float fixangle
Definition progsdefs.qc:160
float deadflag
Definition progsdefs.qc:149
float dmg_save
Definition progsdefs.qc:199
float DEAD_DEAD
Definition progsdefs.qc:276
entity dmg_inflictor
Definition progsdefs.qc:200
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
string RandomSelection_chosen_string
Definition random.qh:7
#define RandomSelection_AddString(s, weight, priority)
Definition random.qh:16
#define AVAILABLE_TEAMS
bool bot_ispaused(entity this)
entity bot_cmd_current
Definition scripting.qh:60
bool campaign_bots_may_start
campaign mode: bots shall spawn but wait for the player to spawn before they do anything in other gam...
Definition campaign.qh:26
int GetPlayerLimit()
Definition client.qc:2127
void ReadyCount()
Definition vote.qc:553
void setItemGroupCount()
Definition items.qc:1294
#define CS_CVAR(this)
Definition state.qh:51
ClientState CS(Client this)
Definition state.qh:47
#define STATIC_INIT(func)
during worldspawn
Definition static.qh:32
#define strfree(this)
Definition string.qh:59
#define strcpy(this, s)
Definition string.qh:52
if(frag_attacker.flagcarried)
Definition sv_ctf.qc:2325
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:599
int TeamBalance_GetNumberOfPlayers(entity balance, int index)
Returns the number of players (both humans and bots) in a team.
Definition teamplay.qc:927
void TeamBalance_GetTeamCounts(entity balance, entity ignore)
Counts the number of players and various other information about each team.
Definition teamplay.qc:846
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:459
bool Team_IsValidTeam(int team_num)
Returns whether team value is valid.
Definition teams.qh:133
bool Team_IsValidIndex(int index)
Returns whether the team index is valid.
Definition teams.qh:151
bool teamplay
Definition teams.qh:59
#define IS_OBSERVER(v)
Definition utils.qh:11
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:50
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15
float dmg_take
Definition view.qh:123
bool waypoint_load_links()
void waypoint_updatecost_foralllinks()
Definition waypoints.qc:971
float waypoint_loadall()
void waypoint_load_hardwiredlinks()
void botframe_showwaypointlinks()
void botframe_autowaypoints()
bool waypointeditor_enabled
Definition waypoints.qh:3
float botframe_cachedwaypointlinks
Definition waypoints.qh:24
float botframe_loadedforcedlinks
Definition waypoints.qh:23