Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
bot.qh File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define IN_LAVA(pos)
#define IN_LIQUID(pos)
#define SUBMERGED(pos)
#define SUPERBOT   (skill > 100)
#define WETFEET(pos)

Functions

void autoskill (float factor)
void bot_calculate_stepheightvec ()
void bot_clientconnect (entity this)
void bot_clientdisconnect (entity this)
void bot_custom_weapon_priority_setup ()
void bot_endgame ()
bool bot_fixcount (bool multiple_per_frame)
void bot_relinkplayerlist ()
void bot_removefromlargestteam ()
void bot_removenewest ()
void bot_serverframe ()
void bot_setnameandstuff (entity this)
entity bot_spawn ()
void bot_think (entity this)
 float (entity player, entity item) bot_pickupevalfunc
 void (entity this) bot_ai

Variables

int _content_type
const int AI_STATUS_ATTACKING = BIT(1)
const int AI_STATUS_DANGER_AHEAD = BIT(3)
const int AI_STATUS_JETPACK_FLYING = BIT(9)
const int AI_STATUS_JETPACK_LANDING = BIT(10)
const int AI_STATUS_OUT_JUMPPAD = BIT(4)
const int AI_STATUS_OUT_WATER = BIT(5)
const int AI_STATUS_ROAMING = BIT(0)
const int AI_STATUS_RUNNING = BIT(2)
const int AI_STATUS_STUCK = BIT(11)
const int AI_STATUS_WAYPOINT_PERSONAL_GOING = BIT(7)
const int AI_STATUS_WAYPOINT_PERSONAL_LINKING = BIT(6)
const int AI_STATUS_WAYPOINT_PERSONAL_REACHED = BIT(8)
int aistatus
float autoskill_nextthink
float bot_aggresskill
float bot_aimskill
float bot_aiskill
float bot_attack
float bot_config_loaded
float bot_distance_close
float bot_distance_far
float bot_dodge
float bot_dodgerating
float bot_dodgeskill
float bot_forced_team
float bot_jump_time
entity bot_list
float bot_mouseskill
float bot_moveskill
float bot_nextthink
float bot_offsetskill
float bot_pickup
bool bot_pickup_respawning
float bot_pickupbasevalue
float bot_pingskill
float bot_preferredcolors
float bot_rangepreference
float bot_strategytime
entity bot_strategytoken
float bot_strategytoken_taken
float bot_thinkskill
float bot_weaponskill
float botframe_nextdangertime
float botframe_nextthink
float botframe_spawnedwaypoints
string cleanname
float createdtime
bool isbot
string netname_freeme
entity nextbot
string playermodel_freeme
string playerskin_freeme
float totalfrags_lastcheck

Macro Definition Documentation

◆ IN_LAVA

#define IN_LAVA ( pos)
Value:
int _content_type
Definition bot.qh:83
const float CONTENT_LAVA
const float CONTENT_SLIME

Definition at line 84 of file bot.qh.

Referenced by havocbot_goalrating_items(), and tracewalk().

◆ IN_LIQUID

#define IN_LIQUID ( pos)
Value:
const float CONTENT_WATER

Definition at line 85 of file bot.qh.

◆ SUBMERGED

#define SUBMERGED ( pos)
Value:
#define IN_LIQUID(pos)
Definition bot.qh:85
vector autocvar_sv_player_viewoffset
Definition player.qh:348

Definition at line 86 of file bot.qh.

Referenced by navigation_check_submerged_state(), and tracewalk().

◆ SUPERBOT

#define SUPERBOT   (skill > 100)

◆ WETFEET

#define WETFEET ( pos)
Value:
IN_LIQUID(pos + eZ * (m1.z + 1))
const vector eZ
Definition vector.qh:46

Definition at line 87 of file bot.qh.

Referenced by resurface_limited(), and tracewalk().

Function Documentation

◆ autoskill()

void autoskill ( float factor)

Definition at line 569 of file bot.qc.

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}
#define IS_PLAYER(s)
Definition player.qh:243
#define autocvar_skill
Definition cvars.qh:61
#define LOG_DEBUG(...)
Definition log.qh:80
void cvar_set(string name, string value)
void bprint(string text,...)
string ftos(float f)
float max(float f,...)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:50

References autocvar_skill, bprint(), cvar_set(), FOREACH_CLIENT, ftos(), IS_PLAYER, IS_REAL_CLIENT, LOG_DEBUG, max(), and strcat().

Referenced by bot_serverframe().

◆ bot_calculate_stepheightvec()

void bot_calculate_stepheightvec ( )

Definition at line 615 of file bot.qc.

616{
619 jumpstepheightvec = stepheightvec + jumpheight_vec * 0.85; // reduce it a bit to make the jumps easy
621}
float autocvar_sv_jumpvelocity
Definition player.qh:50
#define autocvar_sv_gravity
Definition stats.qh:421
float autocvar_sv_stepheight
Definition stats.qh:422
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

References autocvar_sv_gravity, autocvar_sv_jumpvelocity, autocvar_sv_stepheight, jumpheight_time, jumpheight_vec, jumpstepheightvec, and stepheightvec.

Referenced by bot_serverframe(), STATIC_INIT(), and waypoint_think().

◆ bot_clientconnect()

void bot_clientconnect ( entity this)

Definition at line 469 of file bot.qc.

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}
float isbot
Definition api.qh:49
void bot_setclientfields(entity this)
Definition bot.qc:39
void bot_setnameandstuff(entity this)
Definition bot.qc:163
float createdtime
Definition bot.qh:61
float bot_config_loaded
Definition bot.qh:74
float bot_nextthink
Definition bot.qh:59
float bot_preferredcolors
Definition bot.qh:62
float time
clientcolors
Definition ent_cs.qc:147
void havocbot_setupbot(entity this)
Definition havocbot.qc:1764
float random(void)
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15

◆ bot_clientdisconnect()

void bot_clientdisconnect ( entity this)

Definition at line 454 of file bot.qc.

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}
string cleanname
Definition api.qh:45
string netname_freeme
Definition bot.qh:55
string playermodel_freeme
Definition bot.qh:56
string playerskin_freeme
Definition bot.qh:57
void bot_clearqueue(entity bot)
Definition scripting.qc:21
entity bot_waypoint_queue_owner
Definition navigation.qh:85
#define NULL
Definition post.qh:14
entity bot_cmd_current
Definition scripting.qh:60
#define strfree(this)
Definition string.qh:59

◆ bot_custom_weapon_priority_setup()

void bot_custom_weapon_priority_setup ( )

Definition at line 351 of file bot.qc.

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}
float bot_custom_weapon
Definition api.qh:31
#define PARSE_WEAPON_PRIORITIES(dist)
float bot_distance_far
Definition bot.qh:47
float bot_distance_close
Definition bot.qh:48
string autocvar_bot_ai_custom_weapon_priority_far
Definition cvars.qh:28
string autocvar_bot_ai_custom_weapon_priority_distances
Definition cvars.qh:27
string autocvar_bot_ai_custom_weapon_priority_mid
Definition cvars.qh:29
string autocvar_bot_ai_custom_weapon_priority_close
Definition cvars.qh:26
#define tokenizebyseparator
float stof(string val,...)
string argv(float n)
#define strcpy(this, s)
Definition string.qh:52

References argv(), autocvar_bot_ai_custom_weapon_priority_close, autocvar_bot_ai_custom_weapon_priority_distances, autocvar_bot_ai_custom_weapon_priority_far, autocvar_bot_ai_custom_weapon_priority_mid, bot_custom_weapon, bot_distance_close, bot_distance_far, PARSE_WEAPON_PRIORITIES, stof(), strcpy, and tokenizebyseparator.

Referenced by bot_serverframe().

◆ bot_endgame()

void bot_endgame ( )

Definition at line 412 of file bot.qc.

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}
void bot_relinkplayerlist()
Definition bot.qc:424
entity bot_list
Definition bot.qh:50
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define setcolor
Definition pre.qh:11

◆ bot_fixcount()

bool bot_fixcount ( bool multiple_per_frame)

Definition at line 623 of file bot.qc.

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}
int bots_would_leave
how many bots would leave so humans can replace them
Definition api.qh:101
int currentbots
Definition api.qh:104
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
entity bot_spawn()
Definition bot.qc:45
void bot_removenewest()
Definition bot.qc:533
float botframe_nextthink
Definition bot.qh:80
#define M_ARGV(x, type)
Definition events.qh:17
float maxclients
bool autocvar_bot_join_empty
Definition cvars.qh:49
int autocvar_bot_number
Definition cvars.qh:64
int autocvar_minplayers
Definition cvars.qh:68
int autocvar_minplayers_per_team
Definition cvars.qh:69
int autocvar_bot_vs_human
Definition cvars.qh:67
float ceil(float f)
float min(float f,...)
float fabs(float f)
float floor(float f)
#define AVAILABLE_TEAMS
int GetPlayerLimit()
Definition client.qc:2127
bool teamplay
Definition teams.qh:59

Referenced by bot_serverframe().

◆ bot_relinkplayerlist()

void bot_relinkplayerlist ( )

Definition at line 424 of file bot.qc.

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}
int player_count
Definition api.qh:103
entity bot_strategytoken
Definition bot.qh:77
float bot_strategytoken_taken
Definition bot.qh:76
bool bot_ispaused(entity this)
#define IS_OBSERVER(v)
Definition utils.qh:11

Referenced by bot_endgame().

◆ bot_removefromlargestteam()

void bot_removefromlargestteam ( )

Definition at line 486 of file bot.qc.

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}
best
Definition all.qh:82
if(frag_attacker.flagcarried)
Definition sv_ctf.qc:2325
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:599
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

References best, entity(), FOREACH_CLIENT, if(), NULL, Team_IsValidTeam(), TeamBalance_CheckAllowedTeams(), and TeamBalance_GetTeamCounts().

Referenced by bot_removenewest().

◆ bot_removenewest()

void bot_removenewest ( )

Definition at line 533 of file bot.qc.

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}
void bot_removefromlargestteam()
Definition bot.qc:486

References best, bot_removefromlargestteam(), entity(), FOREACH_CLIENT, NULL, and teamplay.

Referenced by bot_fixcount().

◆ bot_serverframe()

void bot_serverframe ( )

Definition at line 689 of file bot.qc.

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 skill
Definition api.qh:35
IntrusiveList g_waypoints
Definition api.qh:148
bool bot_fixcount(bool multiple_per_frame)
Definition bot.qc:623
void bot_custom_weapon_priority_setup()
Definition bot.qc:351
void autoskill(float factor)
Definition bot.qc:569
void bot_calculate_stepheightvec()
Definition bot.qc:615
float autoskill_nextthink
Definition bot.qh:25
float botframe_spawnedwaypoints
Definition bot.qh:79
float botframe_nextdangertime
Definition bot.qh:81
#define IS_DEAD(s)
Definition player.qh:245
float game_stopped
Definition stats.qh:81
const float MOVE_NOMONSTERS
const float MOVE_NORMAL
bool autocvar_bot_navigation_ignoreplayers
Definition cvars.qh:50
float autocvar_skill_auto
Definition cvars.qh:62
int autocvar_g_waypointeditor_auto
Definition cvars.qh:60
bool autocvar_waypoint_benchmark
Definition cvars.qh:63
float autocvar_bot_ai_dangerdetectioninterval
Definition cvars.qh:30
float autocvar_bot_ai_bunnyhop_skilloffset
Definition cvars.qh:19
float autocvar_bot_ai_dangerdetectionupdates
Definition cvars.qh:31
bool intermission_running
#define IL_EACH(this, cond, body)
#define STAT(...)
Definition stats.qh:82
void localcmd(string command,...)
void botframe_updatedangerousobjects(float maxupdate)
float bot_navigation_movemode
Definition navigation.qh:7
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

◆ bot_setnameandstuff()

void bot_setnameandstuff ( entity this)

Definition at line 163 of file bot.qc.

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}
float bot_forced_team
Definition api.qh:41
float bot_moveskill
Definition api.qh:42
#define READSKILL(f, w, r)
float bot_aiskill
Definition bot.qh:42
float bot_aggresskill
Definition bot.qh:34
float bot_pingskill
Definition bot.qh:31
float bot_weaponskill
Definition bot.qh:33
float bot_rangepreference
Definition bot.qh:35
float bot_mouseskill
Definition bot.qh:39
#define SUPERBOT
Definition bot.qh:23
float bot_thinkskill
Definition bot.qh:41
float bot_aimskill
Definition bot.qh:37
float bot_offsetskill
Definition bot.qh:38
float bot_dodgeskill
Definition bot.qh:29
string netname
Definition powerups.qc:20
float count
Definition powerups.qc:22
int team
Definition main.qh:188
const float FILE_READ
#define autocvar_bot_suffix
Definition cvars.qh:53
string autocvar_bot_config_file
Definition cvars.qh:46
bool autocvar_bot_usemodelnames
Definition cvars.qh:54
#define autocvar_bot_prefix
Definition cvars.qh:52
string playerskin
string playermodel
float havocbot_keyboardskill
Definition havocbot.qh:7
#define LOG_INFOF(...)
Definition log.qh:66
bool autocvar_g_campaign
Definition menu.qc:747
string name
Definition menu.qh:30
string fgets(float fhandle)
void fclose(float fhandle)
string substring(string s, float start, float length)
float fopen(string filename, float mode)
string strzone(string s)
#define etof(e)
Definition misc.qh:25
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
int TeamBalance_GetNumberOfPlayers(entity balance, int index)
Returns the number of players (both humans and bots) in a team.
Definition teamplay.qc:927
bool Team_IsValidIndex(int index)
Returns whether the team index is valid.
Definition teams.qh:151

References argv(), autocvar_bot_config_file, autocvar_bot_prefix, autocvar_bot_suffix, autocvar_bot_usemodelnames, autocvar_bot_vs_human, autocvar_g_campaign, AVAILABLE_TEAMS, bot_aggresskill, bot_aimskill, bot_aiskill, bot_config_loaded, bot_dodgeskill, bot_forced_team, bot_mouseskill, bot_moveskill, bot_offsetskill, bot_pingskill, bot_preferredcolors, bot_rangepreference, bot_thinkskill, bot_weaponskill, cleanname, clientcolors, count, entity(), etof, fclose(), fgets(), FILE_READ, floor(), fopen(), FOREACH_CLIENT, ftos(), havocbot_keyboardskill, IS_BOT_CLIENT, LOG_INFOF, name, netname, netname_freeme, NULL, playermodel, playermodel_freeme, playerskin, playerskin_freeme, random(), RandomSelection_AddString, RandomSelection_chosen_string, RandomSelection_Init(), READSKILL, setcolor, stof(), strcat(), strzone(), substring(), SUPERBOT, team, Team_IsValidIndex(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetNumberOfPlayers(), TeamBalance_GetTeamCounts(), teamplay, and tokenizebyseparator.

Referenced by bot_clientconnect(), and bot_spawn().

◆ bot_spawn()

entity bot_spawn ( )

Definition at line 45 of file bot.qc.

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}
#define ClientConnect
Definition _all.inc:238
#define PutClientInServer
Definition _all.inc:246
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
void setItemGroupCount()
Definition items.qc:1294

References bot_setclientfields(), bot_setnameandstuff(), ClientConnect, currentbots, entity(), NULL, PutClientInServer, Send_Notification(), setItemGroupCount(), and teamplay.

Referenced by bot_fixcount().

◆ bot_think()

void bot_think ( entity this)

Definition at line 62 of file bot.qc.

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}
void navigation_goalrating_timeout_force(entity this)
Definition navigation.qc:29
bool navigation_goalrating_timeout(entity this)
Definition navigation.qc:44
int aistatus
Definition bot.qh:20
float bot_jump_time
Definition bot.qh:71
const int AI_STATUS_STUCK
Definition bot.qh:17
bool ready
Definition main.qh:88
bool warmup_stage
Definition main.qh:120
#define PHYS_INPUT_BUTTON_CROUCH(s)
Definition player.qh:154
#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 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
float game_starttime
Definition stats.qh:82
const int FL_GODMODE
Definition constants.qh:75
float flags
float autocvar_bot_ai_thinkinterval
Definition cvars.qh:41
bool autocvar_bot_god
Definition cvars.qh:47
ent angles
Definition ent_cs.qc:121
float bound(float min, float value, float max)
void navigation_unstuck(entity this)
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
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
void ReadyCount()
Definition vote.qc:553
ClientState CS(Client this)
Definition state.qh:47
float dmg_take
Definition view.qh:123

◆ float()

float ( entity player,
entity item )

References entity(), and havocbot_setupbot().

◆ void()

void ( entity this)

References entity().

Variable Documentation

◆ _content_type

int _content_type

Definition at line 83 of file bot.qh.

◆ AI_STATUS_ATTACKING

const int AI_STATUS_ATTACKING = BIT(1)

Definition at line 7 of file bot.qh.

Referenced by havocbot_ai(), havocbot_bunnyhop(), and havocbot_movetogoal().

◆ AI_STATUS_DANGER_AHEAD

const int AI_STATUS_DANGER_AHEAD = BIT(3)

Definition at line 9 of file bot.qh.

Referenced by havocbot_bunnyhop(), and havocbot_movetogoal().

◆ AI_STATUS_JETPACK_FLYING

const int AI_STATUS_JETPACK_FLYING = BIT(9)

Definition at line 15 of file bot.qh.

Referenced by havocbot_movetogoal().

◆ AI_STATUS_JETPACK_LANDING

const int AI_STATUS_JETPACK_LANDING = BIT(10)

Definition at line 16 of file bot.qh.

Referenced by havocbot_movetogoal().

◆ AI_STATUS_OUT_JUMPPAD

const int AI_STATUS_OUT_JUMPPAD = BIT(4)

Definition at line 10 of file bot.qh.

Referenced by havocbot_movetogoal().

◆ AI_STATUS_OUT_WATER

const int AI_STATUS_OUT_WATER = BIT(5)

Definition at line 11 of file bot.qh.

Referenced by havocbot_ai(), and havocbot_movetogoal().

◆ AI_STATUS_ROAMING

const int AI_STATUS_ROAMING = BIT(0)

Definition at line 6 of file bot.qh.

Referenced by havocbot_ai(), and havocbot_checkdanger().

◆ AI_STATUS_RUNNING

const int AI_STATUS_RUNNING = BIT(2)

◆ AI_STATUS_STUCK

const int AI_STATUS_STUCK = BIT(11)

◆ AI_STATUS_WAYPOINT_PERSONAL_GOING

const int AI_STATUS_WAYPOINT_PERSONAL_GOING = BIT(7)

Definition at line 13 of file bot.qh.

Referenced by havocbot_moveto(), and navigation_poptouchedgoals().

◆ AI_STATUS_WAYPOINT_PERSONAL_LINKING

const int AI_STATUS_WAYPOINT_PERSONAL_LINKING = BIT(6)

Definition at line 12 of file bot.qh.

Referenced by havocbot_moveto().

◆ AI_STATUS_WAYPOINT_PERSONAL_REACHED

const int AI_STATUS_WAYPOINT_PERSONAL_REACHED = BIT(8)

Definition at line 14 of file bot.qh.

Referenced by havocbot_moveto(), and navigation_poptouchedgoals().

◆ aistatus

◆ autoskill_nextthink

float autoskill_nextthink

Definition at line 25 of file bot.qh.

Referenced by bot_serverframe().

◆ bot_aggresskill

float bot_aggresskill

Definition at line 34 of file bot.qh.

Referenced by bot_aimdir(), and bot_setnameandstuff().

◆ bot_aimskill

float bot_aimskill

Definition at line 37 of file bot.qh.

Referenced by bot_aim(), bot_aimdir(), and bot_setnameandstuff().

◆ bot_aiskill

float bot_aiskill

Definition at line 42 of file bot.qh.

Referenced by bot_setnameandstuff(), and bot_think().

◆ bot_attack

float bot_attack

Definition at line 63 of file bot.qh.

◆ bot_config_loaded

float bot_config_loaded

Definition at line 74 of file bot.qh.

Referenced by bot_clientconnect(), and bot_setnameandstuff().

◆ bot_distance_close

float bot_distance_close

Definition at line 48 of file bot.qh.

Referenced by bot_custom_weapon_priority_setup(), and havocbot_chooseweapon().

◆ bot_distance_far

float bot_distance_far

Definition at line 47 of file bot.qh.

Referenced by bot_custom_weapon_priority_setup(), and havocbot_chooseweapon().

◆ bot_dodge

float bot_dodge

Definition at line 64 of file bot.qh.

◆ bot_dodgerating

float bot_dodgerating

Definition at line 65 of file bot.qh.

◆ bot_dodgeskill

float bot_dodgeskill

Definition at line 29 of file bot.qh.

Referenced by bot_setnameandstuff(), and havocbot_movetogoal().

◆ bot_forced_team

float bot_forced_team

Definition at line 73 of file bot.qh.

◆ bot_jump_time

float bot_jump_time

Definition at line 71 of file bot.qh.

Referenced by bot_think(), havocbot_bunnyhop(), and havocbot_movetogoal().

◆ bot_list

entity bot_list

Definition at line 50 of file bot.qh.

Referenced by bot_endgame(), bot_relinkplayerlist(), and bot_serverframe().

◆ bot_mouseskill

float bot_mouseskill

Definition at line 39 of file bot.qh.

Referenced by bot_aimdir(), and bot_setnameandstuff().

◆ bot_moveskill

float bot_moveskill

Definition at line 28 of file bot.qh.

◆ bot_nextthink

float bot_nextthink

Definition at line 59 of file bot.qh.

Referenced by bot_clientconnect(), and bot_think().

◆ bot_offsetskill

float bot_offsetskill

Definition at line 38 of file bot.qh.

Referenced by bot_aimdir(), and bot_setnameandstuff().

◆ bot_pickup

float bot_pickup

Definition at line 67 of file bot.qh.

◆ bot_pickup_respawning

bool bot_pickup_respawning

Definition at line 69 of file bot.qh.

◆ bot_pickupbasevalue

float bot_pickupbasevalue

Definition at line 68 of file bot.qh.

Referenced by buff_Init(), and StartItem().

◆ bot_pingskill

float bot_pingskill

Definition at line 31 of file bot.qh.

Referenced by bot_setnameandstuff(), and bot_think().

◆ bot_preferredcolors

float bot_preferredcolors

Definition at line 62 of file bot.qh.

Referenced by bot_clientconnect(), and bot_setnameandstuff().

◆ bot_rangepreference

float bot_rangepreference

Definition at line 35 of file bot.qh.

Referenced by bot_setnameandstuff(), and havocbot_chooseweapon().

◆ bot_strategytime

◆ bot_strategytoken

entity bot_strategytoken

Definition at line 77 of file bot.qh.

Referenced by bot_relinkplayerlist(), bot_serverframe(), havocbot_ai(), and navigation_unstuck().

◆ bot_strategytoken_taken

float bot_strategytoken_taken

Definition at line 76 of file bot.qh.

Referenced by bot_relinkplayerlist(), bot_serverframe(), havocbot_ai(), and havocbot_moveto().

◆ bot_thinkskill

float bot_thinkskill

Definition at line 41 of file bot.qh.

Referenced by bot_aimdir(), and bot_setnameandstuff().

◆ bot_weaponskill

float bot_weaponskill

Definition at line 33 of file bot.qh.

Referenced by bot_setnameandstuff(), and havocbot_chooseweapon().

◆ botframe_nextdangertime

float botframe_nextdangertime

Definition at line 81 of file bot.qh.

Referenced by bot_serverframe().

◆ botframe_nextthink

float botframe_nextthink

Definition at line 80 of file bot.qh.

Referenced by bot_fixcount(), and bot_serverframe().

◆ botframe_spawnedwaypoints

float botframe_spawnedwaypoints

Definition at line 79 of file bot.qh.

Referenced by bot_serverframe().

◆ cleanname

string cleanname

Definition at line 52 of file bot.qh.

◆ createdtime

float createdtime

Definition at line 61 of file bot.qh.

Referenced by bot_clientconnect().

◆ isbot

bool isbot

Definition at line 19 of file bot.qh.

◆ netname_freeme

string netname_freeme

Definition at line 55 of file bot.qh.

Referenced by bot_clientdisconnect(), and bot_setnameandstuff().

◆ nextbot

entity nextbot

Definition at line 51 of file bot.qh.

◆ playermodel_freeme

string playermodel_freeme

Definition at line 56 of file bot.qh.

Referenced by bot_clientdisconnect(), and bot_setnameandstuff().

◆ playerskin_freeme

string playerskin_freeme

Definition at line 57 of file bot.qh.

Referenced by bot_clientdisconnect(), and bot_setnameandstuff().

◆ totalfrags_lastcheck

float totalfrags_lastcheck

Definition at line 44 of file bot.qh.