Xonotic
api.qh File Reference
+ Include dependency graph for api.qh:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

bool bot_aim (entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
 
void bot_aim_reset (entity this)
 
void bot_clientconnect (entity this)
 
void bot_clientdisconnect (entity this)
 
void bot_cmdhelp (string scmd)
 
void bot_endgame ()
 
bool bot_fixcount (bool multiple_per_frame)
 
void bot_list_commands ()
 
void bot_queuecommand (entity bot, string cmdstring)
 
void bot_relinkplayerlist ()
 
void bot_resetqueues ()
 
void bot_serverframe ()
 
bool bot_shouldattack (entity this, entity e)
 
void bot_think (entity this)
 
entity find_bot_by_name (string name)
 
entity find_bot_by_number (float number)
 
 float (entity player, entity item) bot_pickupevalfunc
 
vector get_closer_dest (entity ent, vector org)
 
void havocbot_goalrating_enemyplayers (entity this, float ratingscale, vector org, float sradius)
 
bool havocbot_goalrating_item_pickable_check_players (entity this, vector org, entity item, vector item_org)
 
void havocbot_goalrating_items (entity this, float ratingscale, vector org, float sradius)
 
void havocbot_goalrating_waypoints (entity this, float ratingscale, vector org, float sradius)
 
void navigation_dynamicgoal_init (entity this, bool initially_static)
 
void navigation_dynamicgoal_set (entity this, entity dropper)
 
void navigation_dynamicgoal_unset (entity this)
 
entity navigation_findnearestwaypoint (entity ent, float walkfromwp)
 
void navigation_goalrating_end (entity this)
 
void navigation_goalrating_start (entity this)
 
bool navigation_goalrating_timeout (entity this)
 
bool navigation_goalrating_timeout_can_be_anticipated (entity this)
 
void navigation_goalrating_timeout_expire (entity this, float seconds)
 
void navigation_goalrating_timeout_extend_if_needed (entity this, float seconds)
 
void navigation_goalrating_timeout_force (entity this)
 
void navigation_goalrating_timeout_set (entity this)
 
void navigation_markroutes (entity this, entity fixed_source_waypoint)
 
void navigation_markroutes_inverted (entity fixed_source_waypoint)
 
void navigation_routerating (entity this, entity e, float f, float rangebias)
 
void set_tracewalk_dest (entity ent, vector org, bool fix_player_dest)
 
vector set_tracewalk_dest_2 (entity ent, vector org)
 
 STATIC_INIT (botapi)
 
bool tracewalk (entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
 
 void (entity this) havocbot_role
 
void waypoint_getSymmetricalAxis_cmd (entity caller, bool save, int arg_idx)
 
void waypoint_getSymmetricalOrigin_cmd (entity caller, bool save, int arg_idx)
 
void waypoint_lock (entity pl)
 
void waypoint_remove (entity wp)
 
void waypoint_remove_fromeditor (entity pl)
 
void waypoint_saveall ()
 
void waypoint_schedulerelink (entity wp)
 
void waypoint_schedulerelinkall ()
 
entity waypoint_spawn (vector m1, vector m2, float f)
 
void waypoint_spawn_fromeditor (entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp)
 
void waypoint_spawnforitem (entity e)
 
void waypoint_spawnforitem_force (entity e, vector org)
 
void waypoint_spawnforteleporter (entity e, vector destination, float timetaken, entity tracetest_ent)
 
void waypoint_spawnforteleporter_wz (entity e, entity tracetest_ent)
 
void waypoint_start_hardwiredlink (entity pl, bool at_crosshair)
 
void waypoint_unreachable (entity pl)
 

Variables

bool autocvar_g_waypoints_for_items
 
float bot_attack
 
entity bot_basewaypoint
 
float bot_custom_weapon
 
float bot_dodge
 
float bot_dodgerating
 
float bot_forced_team
 
float bot_moveskill
 
float bot_pickup
 
float bot_tracewalk_time
 
bool bot_waypoints_for_items
 
float bot_weapons_close [REGISTRY_MAX(Weapons)]
 
float bot_weapons_far [REGISTRY_MAX(Weapons)]
 
float bot_weapons_mid [REGISTRY_MAX(Weapons)]
 
bool bots_would_leave
 
string cleanname
 
int currentbots
 
IntrusiveList g_bot_dodge
 
IntrusiveList g_bot_targets
 
IntrusiveList g_waypoints
 
float goalentity_lock_timeout
 
vector havocbot_middlepoint
 
float havocbot_middlepoint_radius
 
float havocbot_role_timeout
 
float havocbot_symmetry_axis_m
 
float havocbot_symmetry_axis_q
 
float havocbot_symmetry_origin_order
 
entity ignoregoal
 
float ignoregoaltime
 
float isbot
 
vector lastteleport_origin
 
float lastteleporttime
 
bool navigation_dynamicgoal
 
float navigation_hasgoals
 
entity nearestwaypoint
 
float nearestwaypointtimeout
 
int player_count
 
float skill
 
float speed
 
const int WAYPOINTFLAG_CROUCH = BIT(12)
 
const int WAYPOINTFLAG_CUSTOM_JP = BIT(13)
 
const int WAYPOINTFLAG_DEAD_END = BIT(16)
 
const int WAYPOINTFLAG_GENERATED = BIT(23)
 
const int WAYPOINTFLAG_ITEM = BIT(22)
 
const int WAYPOINTFLAG_JUMP = BIT(14)
 
const int WAYPOINTFLAG_LADDER = BIT(15)
 
const int WAYPOINTFLAG_NORELINK__DEPRECATED = BIT(20)
 
const int WAYPOINTFLAG_PERSONAL = BIT(19)
 
const int WAYPOINTFLAG_PROTECTED = BIT(18)
 
const int WAYPOINTFLAG_SUPPORT = BIT(11)
 
const int WAYPOINTFLAG_TELEPORT = BIT(21)
 
const int WAYPOINTFLAG_USEFUL = BIT(17)
 
entity wp00
 
float wp00mincost
 
entity wp01
 
float wp01mincost
 
entity wp02
 
float wp02mincost
 
entity wp03
 
float wp03mincost
 
entity wp04
 
float wp04mincost
 
entity wp05
 
float wp05mincost
 
entity wp06
 
float wp06mincost
 
entity wp07
 
float wp07mincost
 
entity wp08
 
float wp08mincost
 
entity wp09
 
float wp09mincost
 
entity wp10
 
float wp10mincost
 
entity wp11
 
float wp11mincost
 
entity wp12
 
float wp12mincost
 
entity wp13
 
float wp13mincost
 
entity wp14
 
float wp14mincost
 
entity wp15
 
float wp15mincost
 
entity wp16
 
float wp16mincost
 
entity wp17
 
float wp17mincost
 
entity wp18
 
float wp18mincost
 
entity wp19
 
float wp19mincost
 
entity wp20
 
float wp20mincost
 
entity wp21
 
float wp21mincost
 
entity wp22
 
float wp22mincost
 
entity wp23
 
float wp23mincost
 
entity wp24
 
float wp24mincost
 
entity wp25
 
float wp25mincost
 
entity wp26
 
float wp26mincost
 
entity wp27
 
float wp27mincost
 
entity wp28
 
float wp28mincost
 
entity wp29
 
float wp29mincost
 
entity wp30
 
float wp30mincost
 
entity wp31
 
float wp31mincost
 
float wpconsidered
 
float wpcost
 
const int WPFLAGMASK_NORELINK = (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER | WAYPOINTFLAG_JUMP | WAYPOINTFLAG_CUSTOM_JP | WAYPOINTFLAG_SUPPORT)
 
int wpflags
 
entity wphw00
 
entity wphw01
 
entity wphw02
 
entity wphw03
 
entity wphw04
 
entity wphw05
 
entity wphw06
 
entity wphw07
 

Function Documentation

◆ bot_aim()

bool bot_aim ( entity  this,
.entity  weaponentity,
float  shotspeed,
float  shotspeedupward,
float  maxshottime,
float  applygravity 
)

◆ bot_aim_reset()

void bot_aim_reset ( entity  this)

Definition at line 170 of file aim.qc.

Referenced by MUTATOR_HOOKFUNCTION(), ons_Teleport(), PutPlayerInServer(), TeleportPlayer(), and WarpZone_TeleportPlayer().

171 {
172  this.bot_mouseaim = this.v_angle;
173  this.bot_olddesiredang = this.v_angle;
174  this.bot_aimdir_executed = true;
175  this.bot_badaimtime = 0;
176  this.bot_aimthinktime = time;
177  this.bot_prevaimtime = time;
178  this.bot_1st_order_aimfilter = '0 0 0';
179  this.bot_2nd_order_aimfilter = '0 0 0';
180  this.bot_3th_order_aimfilter = '0 0 0';
181  this.bot_4th_order_aimfilter = '0 0 0';
182  this.bot_5th_order_aimfilter = '0 0 0';
183  this.bot_firetimer = 0;
184 }
float bot_prevaimtime
Definition: aim.qh:65
vector bot_1st_order_aimfilter
Definition: aim.qh:71
float bot_aimthinktime
Definition: aim.qh:64
vector bot_5th_order_aimfilter
Definition: aim.qh:75
vector bot_4th_order_aimfilter
Definition: aim.qh:74
vector v_angle
Definition: progsdefs.qc:161
vector bot_3th_order_aimfilter
Definition: aim.qh:73
float bot_firetimer
Definition: aim.qh:66
float bot_badaimtime
Definition: aim.qh:63
bool bot_aimdir_executed
Definition: aim.qh:62
vector bot_2nd_order_aimfilter
Definition: aim.qh:72
vector bot_mouseaim
Definition: aim.qh:69
float time
Definition: csprogsdefs.qc:16
vector bot_olddesiredang
Definition: aim.qh:76
+ Here is the caller graph for this function:

◆ bot_clientconnect()

void bot_clientconnect ( entity  this)

Definition at line 426 of file bot.qc.

427 {
428  if (!IS_BOT_CLIENT(this)) return;
429  this.bot_preferredcolors = this.clientcolors;
430  this.bot_nextthink = time - random();
431  this.lag_func = bot_lagfunc;
432  this.isbot = true;
433  this.createdtime = this.bot_nextthink;
434 
435  if(!this.bot_config_loaded) // This is needed so team overrider doesn't break between matches
436  {
437  bot_setnameandstuff(this);
438  bot_setclientfields(this);
439  }
440 
442  {
444  }
445  else
446  {
447  this.bot_forced_team = 0;
449  }
450 
451  havocbot_setupbot(this);
452 }
bool SetPlayerTeam(entity player, int team_index, int type)
Sets the team of the player.
Definition: teamplay.qc:237
float bot_preferredcolors
Definition: bot.qh:60
bool Team_IsValidIndex(int index)
Returns whether the team index is valid.
Definition: teams.qh:151
void bot_setclientfields(entity this)
Definition: bot.qc:36
void TeamBalance_JoinBestTeam(entity player)
Assigns the given player to a team that will make the game most balanced.
Definition: teamplay.qc:451
Player has manually selected their team.
Definition: teamplay.qh:112
void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
Definition: aim.qc:151
float bot_nextthink
Definition: bot.qh:57
float teamplay
Definition: progsdefs.qc:31
void bot_setnameandstuff(entity this)
Definition: bot.qc:143
float bot_config_loaded
Definition: bot.qh:73
float bot_forced_team
Definition: api.qh:41
void havocbot_setupbot(entity this)
Definition: havocbot.qc:1683
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
float createdtime
Definition: bot.qh:59
float clientcolors
float time
Definition: csprogsdefs.qc:16
float isbot
Definition: api.qh:49

◆ bot_clientdisconnect()

void bot_clientdisconnect ( entity  this)

Definition at line 411 of file bot.qc.

412 {
413  if (!IS_BOT_CLIENT(this))
414  return;
415  bot_clearqueue(this);
416  strfree(this.cleanname);
417  strfree(this.netname_freeme);
420  if(this.bot_cmd_current)
421  delete(this.bot_cmd_current);
422  if(bot_waypoint_queue_owner == this)
424 }
entity bot_cmd_current
Definition: scripting.qh:60
string netname_freeme
Definition: bot.qh:53
string playermodel_freeme
Definition: bot.qh:54
string cleanname
Definition: api.qh:45
#define NULL
Definition: post.qh:17
string playerskin_freeme
Definition: bot.qh:55
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
#define strfree(this)
Definition: string.qh:56
void bot_clearqueue(entity bot)
Definition: scripting.qc:21

◆ bot_cmdhelp()

void bot_cmdhelp ( string  scmd)

Definition at line 331 of file scripting.qc.

Referenced by GameCommand_bot_cmd().

332 {
333  int i, ntype;
334  string stype;
335 
338 
339  for(i=1;i<BOT_CMD_COUNTER;++i)
340  {
341  if(bot_cmd_string[i]!=scmd)
342  continue;
343 
344  ntype = bot_cmd_parm_type[i];
345 
346  switch(ntype)
347  {
349  stype = "float";
350  break;
352  stype = "string";
353  break;
355  stype = "vector";
356  break;
357  default:
358  stype = "none";
359  break;
360  }
361 
362  string desc = "";
363  switch(i)
364  {
365  case BOT_CMD_PAUSE:
366  desc = "Stops the bot completely. Any command other than 'continue' will be ignored.";
367  break;
368  case BOT_CMD_CONTINUE:
369  desc = "Disable paused status";
370  break;
371  case BOT_CMD_WAIT:
372  desc = "Pause command parsing and bot ai for N seconds. Pressed key will remain pressed";
373  break;
374  case BOT_CMD_WAIT_UNTIL:
375  desc = "Pause command parsing and bot ai until time is N from the last barrier. Pressed key will remain pressed";
376  break;
377  case BOT_CMD_BARRIER:
378  desc = "Waits till all bots that have a command queue reach this command. Pressed key will remain pressed";
379  break;
380  case BOT_CMD_TURN:
381  desc = "Look to the right or left N degrees. For turning to the left use positive numbers.";
382  break;
383  case BOT_CMD_MOVETO:
384  desc = "Walk to an specific coordinate on the map. Usage: moveto \'x y z\'";
385  break;
387  desc = "Walk to the specific target on the map";
388  break;
389  case BOT_CMD_RESETGOAL:
390  desc = "Resets the goal stack";
391  break;
392  case BOT_CMD_CC:
393  desc = "Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;";
394  break;
395  case BOT_CMD_IF:
396  desc = "Perform simple conditional execution.\n"
397  "Syntax: \n"
398  " sv_cmd .. if \"condition\"\n"
399  " sv_cmd .. <instruction if true>\n"
400  " sv_cmd .. <instruction if true>\n"
401  " sv_cmd .. else\n"
402  " sv_cmd .. <instruction if false>\n"
403  " sv_cmd .. <instruction if false>\n"
404  " sv_cmd .. fi\n"
405  "Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n"
406  " Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n"
407  "Fields: health, speed, flagcarrier\n"
408  "Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;";
409  break;
410  case BOT_CMD_RESETAIM:
411  desc = "Points the aim to the coordinates x,y 0,0";
412  break;
413  case BOT_CMD_AIM:
414  desc = "Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n"
415  "There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n"
416  "Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n"
417  " aim \"0 90 2\" // Will gradually look to the sky in the next two seconds";
418  break;
419  case BOT_CMD_AIMTARGET:
420  desc = "Points the aim to given target";
421  break;
422  case BOT_CMD_PRESSKEY:
423  desc = "Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use"
424  "Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called"
425  "Note: The script will not return the control to the bot ai until all keys are released";
426  break;
427  case BOT_CMD_RELEASEKEY:
428  desc = "Release previoulsy used keys. Use the parameter \"all\" to release all keys";
429  break;
430  case BOT_CMD_SOUND:
431  desc = "play sound file at bot location";
432  break;
434  desc = "verify the state of the weapon entity";
435  break;
436  default:
437  desc = "This command has no description yet.";
438  break;
439  }
440  LOG_HELP("Command: ", bot_cmd_string[i], "\nParameter: <", stype, ">", "\nDescription: ", desc);
441  }
442 }
string bot_cmd_string[BOT_CMD_COUNTER]
Definition: scripting.qh:56
const int BOT_CMD_MOVETOTARGET
Definition: scripting.qh:31
const int BOT_CMD_SOUND
Definition: scripting.qh:35
const int BOT_CMD_AIMTARGET
Definition: scripting.qh:32
const int BOT_CMD_AIM
Definition: scripting.qh:25
int bot_cmd_parm_type[BOT_CMD_COUNTER]
Definition: scripting.qh:55
void bot_commands_init()
Definition: scripting.qc:157
const int BOT_CMD_RESETAIM
Definition: scripting.qh:24
const int BOT_CMD_MOVETO
Definition: scripting.qh:18
const int BOT_CMD_CC
Definition: scripting.qh:20
const int BOT_CMD_CONTINUE
Definition: scripting.qh:15
#define LOG_HELP(...)
Definition: log.qh:95
const int BOT_CMD_PAUSE
Definition: scripting.qh:14
const int BOT_CMD_PRESSKEY
Definition: scripting.qh:26
const int BOT_CMD_DEBUG_ASSERT_CANFIRE
Definition: scripting.qh:36
const int BOT_CMD_PARAMETER_VECTOR
Definition: scripting.qh:52
const int BOT_CMD_RESETGOAL
Definition: scripting.qh:19
const int BOT_CMD_WAIT_UNTIL
Definition: scripting.qh:30
const int BOT_CMD_COUNTER
Definition: scripting.qh:41
const int BOT_CMD_RELEASEKEY
Definition: scripting.qh:27
const int BOT_CMD_IF
Definition: scripting.qh:21
const int BOT_CMD_BARRIER
Definition: scripting.qh:33
const int BOT_CMD_PARAMETER_FLOAT
Definition: scripting.qh:50
float bot_cmds_initialized
Definition: scripting.qh:54
const int BOT_CMD_WAIT
Definition: scripting.qh:16
const int BOT_CMD_TURN
Definition: scripting.qh:17
const int BOT_CMD_PARAMETER_STRING
Definition: scripting.qh:51
+ Here is the caller graph for this function:

◆ bot_endgame()

void bot_endgame ( )

Definition at line 369 of file bot.qc.

Referenced by Shutdown().

370 {
372  entity e = bot_list;
373  while (e)
374  {
375  setcolor(e, e.bot_preferredcolors);
376  e = e.nextbot;
377  }
378  // if dynamic waypoints are ever implemented, save them here
379 }
entity() spawn
#define setcolor
Definition: pre.qh:11
void bot_relinkplayerlist()
Definition: bot.qc:381
entity bot_list
Definition: bot.qh:48
+ Here is the caller graph for this function:

◆ bot_fixcount()

bool bot_fixcount ( bool  multiple_per_frame)

Definition at line 591 of file bot.qc.

Referenced by GameCommand_bot_cmd(), and GameCommand_setbots().

592 {
593  int activerealplayers = 0;
594  int realplayers = 0;
595  if (MUTATOR_CALLHOOK(Bot_FixCount, activerealplayers, realplayers)) {
596  activerealplayers = M_ARGV(0, int);
597  realplayers = M_ARGV(1, int);
598  } else {
600  if(IS_PLAYER(it))
601  ++activerealplayers;
602  ++realplayers;
603  });
604  }
605 
606  int bots;
607  // But don't remove bots immediately on level change, as the real players
608  // usually haven't rejoined yet
609  bots_would_leave = false;
611  bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers);
612  else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5)))
613  {
614  int minplayers = max(0, floor(autocvar_minplayers));
615  if (teamplay)
617  int minbots = max(0, floor(autocvar_bot_number));
618 
619  // add bots to reach minplayers if needed
620  bots = max(minbots, minplayers - activerealplayers);
621  // cap bots to the max players allowed by the server
622  int player_limit = GetPlayerLimit();
623  if(player_limit)
624  bots = min(bots, max(player_limit - activerealplayers, 0));
625  bots = min(bots, maxclients - realplayers);
626 
627  if(bots > minbots)
628  bots_would_leave = true;
629  }
630  else
631  {
632  // if there are no players, remove bots
633  bots = 0;
634  }
635 
636  // only add one bot per frame to avoid utter chaos
638  {
639  while (currentbots < bots)
640  {
641  if (bot_spawn() == NULL)
642  {
643  bprint("Can not add bot, server full.\n");
644  return false;
645  }
646  if (!multiple_per_frame)
647  {
648  break;
649  }
650  }
651  while (currentbots > bots && bots >= 0)
653  }
654 
655  return true;
656 }
float botframe_nextthink
Definition: bot.qh:79
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
int GetPlayerLimit()
Definition: client.qc:1990
float maxclients
Definition: csprogsdefs.qc:21
int autocvar_bot_vs_human
Definition: cvars.qh:70
int autocvar_minplayers
Definition: cvars.qh:71
entity bot_spawn()
Definition: bot.qc:42
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
int currentbots
Definition: api.qh:104
bool bots_would_leave
Definition: api.qh:101
#define NULL
Definition: post.qh:17
int autocvar_bot_number
Definition: cvars.qh:67
int AvailableTeams()
Definition: scores_rules.qc:22
float teamplay
Definition: progsdefs.qc:31
#define M_ARGV(x, type)
Definition: events.qh:17
bool autocvar_bot_join_empty
Definition: cvars.qh:52
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
int autocvar_minplayers_per_team
Definition: cvars.qh:72
void bot_removenewest()
Definition: bot.qc:501
float time
Definition: csprogsdefs.qc:16
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the caller graph for this function:

◆ bot_list_commands()

void bot_list_commands ( )

Definition at line 444 of file scripting.qc.

Referenced by GameCommand_bot_cmd().

445 {
446  int i;
447  string ptype;
448 
451 
452  LOG_HELP("Bot commands:");
453 
454  for(i=1;i<BOT_CMD_COUNTER;++i)
455  {
456  switch(bot_cmd_parm_type[i])
457  {
459  ptype = "float";
460  break;
462  ptype = "string";
463  break;
465  ptype = "vector";
466  break;
467  default:
468  ptype = "none";
469  break;
470  }
471  if (ptype != "none")
472  LOG_HELP(" ^2", bot_cmd_string[i]," ^7<", ptype, ">");
473  else
474  LOG_HELP(" ^2", bot_cmd_string[i]);
475  }
476  LOG_HELP("For help about a specific command, type bot_cmd help <command>");
477 }
string bot_cmd_string[BOT_CMD_COUNTER]
Definition: scripting.qh:56
int bot_cmd_parm_type[BOT_CMD_COUNTER]
Definition: scripting.qh:55
void bot_commands_init()
Definition: scripting.qc:157
#define LOG_HELP(...)
Definition: log.qh:95
const int BOT_CMD_PARAMETER_VECTOR
Definition: scripting.qh:52
const int BOT_CMD_COUNTER
Definition: scripting.qh:41
const int BOT_CMD_PARAMETER_FLOAT
Definition: scripting.qh:50
float bot_cmds_initialized
Definition: scripting.qh:54
const int BOT_CMD_PARAMETER_STRING
Definition: scripting.qh:51
+ Here is the caller graph for this function:

◆ bot_queuecommand()

void bot_queuecommand ( entity  bot,
string  cmdstring 
)

Definition at line 30 of file scripting.qc.

Referenced by GameCommand_bot_cmd().

31 {
32  if(!bot.bot_cmdqueuebuf_allocated)
33  {
34  bot.bot_cmdqueuebuf = buf_create();
35  bot.bot_cmdqueuebuf_allocated = true;
36  bot.bot_cmdqueuebuf_start = 0;
37  bot.bot_cmdqueuebuf_end = 0;
38  }
39 
40  bufstr_set(bot.bot_cmdqueuebuf, bot.bot_cmdqueuebuf_end, cmdstring);
41 
42  // if the command was a "sound" command, precache the sound NOW
43  // this prevents lagging!
44  {
45  float sp;
46  string parm;
47  string cmdstr;
48 
49  sp = strstrofs(cmdstring, " ", 0);
50  if(sp >= 0)
51  {
52  parm = substring(cmdstring, sp + 1, -1);
53  cmdstr = substring(cmdstring, 0, sp);
54  if(cmdstr == "sound")
55  {
56  // find the LAST word
57  for (;;)
58  {
59  sp = strstrofs(parm, " ", 0);
60  if(sp < 0)
61  break;
62  parm = substring(parm, sp + 1, -1);
63  }
64  precache_sound(parm);
65  }
66  }
67  }
68 
69  bot.bot_cmdqueuebuf_end += 1;
70 }
#define buf_create
Definition: dpextensions.qh:63
#define strstrofs
Definition: dpextensions.qh:42
+ Here is the caller graph for this function:

◆ bot_relinkplayerlist()

void bot_relinkplayerlist ( )

Definition at line 381 of file bot.qc.

Referenced by bot_cmd_continue(), bot_cmd_pause(), ClientConnect(), ClientDisconnect(), PutClientInServer(), and PutObserverInServer().

382 {
383  player_count = 0;
384  currentbots = 0;
385  bot_list = NULL;
386 
387  entity prevbot = NULL;
388  FOREACH_CLIENT(true,
389  {
390  ++player_count;
391 
392  if(IS_BOT_CLIENT(it))
393  {
394  if (!IS_OBSERVER(it) && !bot_ispaused(it))
395  {
396  if(prevbot)
397  prevbot.nextbot = it;
398  else
399  bot_list = it;
400  prevbot = it;
401  }
402  ++currentbots;
403  }
404  });
405  if(prevbot)
406  prevbot.nextbot = NULL;
409 }
entity() spawn
int player_count
Definition: api.qh:103
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
#define IS_OBSERVER(v)
Definition: utils.qh:11
int currentbots
Definition: api.qh:104
#define NULL
Definition: post.qh:17
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
entity bot_list
Definition: bot.qh:48
bool bot_ispaused(entity this)
Definition: scripting.qc:1003
entity bot_strategytoken
Definition: bot.qh:76
float bot_strategytoken_taken
Definition: bot.qh:75
+ Here is the caller graph for this function:

◆ bot_resetqueues()

void bot_resetqueues ( )

Definition at line 1165 of file scripting.qc.

Referenced by GameCommand_bot_cmd().

1166 {
1167  FOREACH_CLIENT(it.isbot, {
1168  it.bot_cmd_execution_index = 0;
1169  bot_clearqueue(it);
1170  // also, cancel all barriers
1171  it.bot_barrier = 0;
1172  for(int i = 0; i < it.bot_places_count; ++i)
1173  {
1174  strfree(it.(bot_placenames[i]));
1175  }
1176  it.bot_places_count = 0;
1177  });
1178 
1180 }
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
float bot_barriertime
Definition: scripting.qh:68
float time
Definition: csprogsdefs.qc:16
+ Here is the caller graph for this function:

◆ bot_serverframe()

void bot_serverframe ( )

Definition at line 658 of file bot.qc.

Referenced by StartFrame().

659 {
661  {
662  // after the end of the match all bots stay unless all human players disconnect
663  int realplayers = 0;
664  FOREACH_CLIENT(IS_REAL_CLIENT(it), { ++realplayers; });
665  if (!realplayers)
666  {
667  FOREACH_CLIENT(IS_BOT_CLIENT(it), { dropclient(it); });
668  currentbots = 0;
669  }
670  return;
671  }
672 
673  if (game_stopped)
674  return;
675 
676  // Added 0.5 to avoid possible addition + immediate removal of bots that would make them appear as
677  // spectators in the scoreboard and never go away. This issue happens at time 2 if map is changed
678  // with the gotomap command, minplayers is > 1 and human clients join as players very soon
679  // either intentionally or automatically (sv_spectate 0)
680  if (time < 2.5)
681  {
682  currentbots = -1;
683  return;
684  }
685 
686  if (currentbots == -1)
687  {
688  // count bots already in the server from the previous match
689  currentbots = 0;
691  }
692 
693  if(autocvar_skill != skill)
694  {
695  float wpcost_update = false;
697  wpcost_update = true;
698  if(skill < autocvar_bot_ai_bunnyhop_skilloffset && autocvar_skill >= autocvar_bot_ai_bunnyhop_skilloffset)
699  wpcost_update = true;
700 
702  if (wpcost_update)
704  }
705 
708 
710  {
711  float a;
713  if(a)
714  autoskill(a);
716  }
717 
719  {
720  if(!bot_fixcount(false))
721  botframe_nextthink = time + 10;
722  }
723 
725  {
727  localcmd("quit\n");
728  }
729 
732  {
734  {
737  }
738  else
739  {
740  // TODO: Make this check cleaner
741  IL_EACH(g_waypoints, time - it.nextthink > 10,
742  {
743  waypoint_save_links();
744  break;
745  });
746  }
747  }
748  else
749  {
753  }
754 
755  if (bot_list)
756  {
757  // cycle the goal token from one bot to the next each frame
758  // (this prevents them from all doing spawnfunc_waypoint searches on the same
759  // frame, which causes choppy framerates)
761  {
762  // give goal token to the first bot without goals; if all bots don't have
763  // any goal (or are dead/frozen) simply give it to the next one
764  bot_strategytoken_taken = false;
765  entity bot_strategytoken_save = bot_strategytoken;
766  while (true)
767  {
768  if (bot_strategytoken)
770  if (!bot_strategytoken)
772 
773  if (!(IS_DEAD(bot_strategytoken) || STAT(FROZEN, bot_strategytoken))
774  && !bot_strategytoken.goalcurrent)
775  break;
776 
777  if (!bot_strategytoken_save) // break loop if all the bots are dead or frozen
778  break;
779  if (bot_strategytoken == bot_strategytoken_save)
780  bot_strategytoken_save = NULL; // looped through all the bots
781  }
782  }
783 
785  {
786  float interval;
788  if (botframe_nextdangertime < time - interval * 1.5)
792  }
793  }
794 
797 
800 
801  if (currentbots > 0)
803 }
#define IL_EACH(this, cond, body)
void waypoint_updatecost_foralllinks()
Definition: waypoints.qc:973
float botframe_loadedforcedlinks
Definition: waypoints.qh:23
float autoskill_nextthink
Definition: bot.qh:23
float botframe_nextthink
Definition: bot.qh:79
entity() spawn
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
float skill
Definition: api.qh:35
bool bot_fixcount(bool multiple_per_frame)
Definition: bot.qc:591
float botframe_cachedwaypointlinks
Definition: waypoints.qh:24
void bot_calculate_stepheightvec()
Definition: bot.qc:583
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
float autocvar_bot_ai_dangerdetectioninterval
Definition: cvars.qh:33
float autocvar_bot_ai_bunnyhop_skilloffset
Definition: cvars.qh:22
int autocvar_g_waypointeditor_auto
Definition: cvars.qh:63
int currentbots
Definition: api.qh:104
float botframe_spawnedwaypoints
Definition: bot.qh:78
bool waypointeditor_enabled
Definition: waypoints.qh:3
float autocvar_bot_ai_dangerdetectionupdates
Definition: cvars.qh:34
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
void waypoint_load_hardwiredlinks()
Definition: waypoints.qc:1470
bool waypoint_load_links()
Definition: waypoints.qc:1322
float waypoint_loadall()
Definition: waypoints.qc:1842
void autoskill(float factor)
Definition: bot.qc:537
void bot_custom_weapon_priority_setup()
Definition: bot.qc:308
float botframe_nextdangertime
Definition: bot.qh:80
#define NULL
Definition: post.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
IntrusiveList g_waypoints
Definition: api.qh:148
float autocvar_skill_auto
Definition: cvars.qh:65
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
void botframe_showwaypointlinks()
Definition: waypoints.qc:2156
entity bot_list
Definition: bot.qh:48
bool intermission_running
Definition: intermission.qh:9
entity bot_strategytoken
Definition: bot.qh:76
float time
Definition: csprogsdefs.qc:16
bool autocvar_waypoint_benchmark
Definition: cvars.qh:66
float bot_strategytoken_taken
Definition: bot.qh:75
#define autocvar_skill
Definition: cvars.qh:64
bool autocvar_bot_navigation_ignoreplayers
Definition: cvars.qh:53
void botframe_autowaypoints()
Definition: waypoints.qc:2472
+ Here is the caller graph for this function:

◆ bot_shouldattack()

bool bot_shouldattack ( entity  this,
entity  e 
)

Definition at line 112 of file aim.qc.

Referenced by havocbot_chooseenemy(), and havocbot_goalrating_enemyplayers().

113 {
114  if (targ.team == this.team)
115  {
116  if (targ == this)
117  return false;
118  if (teamplay)
119  if (targ.team != 0)
120  return false;
121  }
122 
123  if(STAT(FROZEN, targ))
124  return false;
125 
126  if(teamplay)
127  {
128  if(targ.team==0)
129  return false;
130  }
131  else if (autocvar_bot_ignore_bots && IS_BOT_CLIENT(targ))
132  return false;
133 
134  if (!targ.takedamage)
135  return false;
136  if (IS_DEAD(targ))
137  return false;
139  return false;
140  if(targ.flags & FL_NOTARGET)
141  return false;
142  if(targ.alpha <= 0.1 && targ.alpha != 0)
143  return false; // invisible via alpha
144 
145  if(MUTATOR_CALLHOOK(BotShouldAttack, this, targ))
146  return false;
147 
148  return true;
149 }
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition: player.qh:155
float teamplay
Definition: progsdefs.qc:31
#define IS_DEAD(s)
Definition: utils.qh:26
bool autocvar_bot_ignore_bots
Definition: cvars.qh:51
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
bool autocvar_bot_typefrag
Definition: cvars.qh:61
float FL_NOTARGET
Definition: progsdefs.qc:238
+ Here is the caller graph for this function:

◆ bot_think()

void bot_think ( entity  this)

Definition at line 57 of file bot.qc.

Referenced by sys_phys_ai().

58 {
59  if (this.bot_nextthink > time)
60  return;
61 
62  this.flags &= ~FL_GODMODE;
64  this.flags |= FL_GODMODE;
65 
66  this.bot_nextthink = max(time, this.bot_nextthink) + max(0.01, autocvar_bot_ai_thinkinterval * (0.5 ** this.bot_aiskill) * min(14 / (skill + 14), 1));
67 
69  {
70  CS(this).movement = '0 0 0';
71  this.bot_nextthink = time + 0.5;
72  return;
73  }
74 
75  if (this.fixangle)
76  {
77  this.v_angle = this.angles;
78  this.v_angle_z = 0;
79  this.fixangle = false;
80  }
81 
82  this.dmg_take = 0;
83  this.dmg_save = 0;
84  this.dmg_inflictor = NULL;
85 
86  // calculate an aiming latency based on the skill setting
87  // (simulated network latency + naturally delayed reflexes)
88  //this.ping = 0.7 - bound(0, 0.05 * skill, 0.5); // moved the reflexes to bot_aimdir (under the name 'think')
89  // minimum ping 20+10 random
90  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 higer skill players take a less laggy server
91  // skill 10 = ping 0.2 (adrenaline)
92  // skill 0 = ping 0.7 (slightly drunk)
93 
94  // clear buttons
95  PHYS_INPUT_BUTTON_ATCK(this) = false;
96  // keep jump button pressed for a short while, useful with ramp jumps
97  PHYS_INPUT_BUTTON_JUMP(this) = (!IS_DEAD(this) && time < this.bot_jump_time + 0.2);
98  PHYS_INPUT_BUTTON_ATCK2(this) = false;
99  PHYS_INPUT_BUTTON_ZOOM(this) = false;
100  PHYS_INPUT_BUTTON_CROUCH(this) = false;
101  PHYS_INPUT_BUTTON_HOOK(this) = false;
102  PHYS_INPUT_BUTTON_INFO(this) = false;
103  PHYS_INPUT_BUTTON_DRAG(this) = false;
104  PHYS_INPUT_BUTTON_CHAT(this) = false;
105  PHYS_INPUT_BUTTON_USE(this) = false;
106 
107  if (time < game_starttime)
108  {
109  // block the bot during the countdown to game start
110  CS(this).movement = '0 0 0';
111  this.bot_nextthink = game_starttime;
112  return;
113  }
114 
115  // if dead, just wait until we can respawn
116  if (IS_DEAD(this) || IS_OBSERVER(this))
117  {
118  if (bot_waypoint_queue_owner == this)
120  this.aistatus = 0;
121  CS(this).movement = '0 0 0';
122  if (IS_OBSERVER(this))
123  return;
124  if (IS_DEAD(this))
125  {
128  // jump must not be pressed for at least one frame in order for
129  // PlayerThink to detect the key down event
130  if (this.deadflag == DEAD_DYING)
131  PHYS_INPUT_BUTTON_JUMP(this) = false;
132  else if (this.deadflag == DEAD_DEAD)
133  PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn
134  }
135  }
136  else if(this.aistatus & AI_STATUS_STUCK)
137  navigation_unstuck(this);
138 
139  // now call the current bot AI (havocbot for example)
140  this.bot_ai(this);
141 }
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition: player.qh:148
float DEAD_DYING
Definition: progsdefs.qc:275
float bot_pingskill
Definition: bot.qh:29
#define PHYS_INPUT_BUTTON_JUMP(s)
Definition: player.qh:147
float dmg_take
Definition: view.qh:119
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition: player.qh:155
#define PHYS_INPUT_BUTTON_CROUCH(s)
Definition: player.qh:150
#define PHYS_INPUT_BUTTON_DRAG(s)
Definition: player.qh:153
#define PHYS_INPUT_BUTTON_HOOK(s)
Definition: player.qh:151
int aistatus
Definition: bot.qh:20
ClientState CS(Client this)
Definition: state.qh:47
vector v_angle
Definition: progsdefs.qc:161
float skill
Definition: api.qh:35
#define IS_OBSERVER(v)
Definition: utils.qh:11
#define PHYS_INPUT_BUTTON_ZOOM(s)
Definition: player.qh:149
float FL_GODMODE
Definition: progsdefs.qc:237
void navigation_goalrating_timeout_force(entity this)
Definition: navigation.qc:28
float DEAD_DEAD
Definition: progsdefs.qc:276
float dmg_save
Definition: progsdefs.qc:199
entity dmg_inflictor
Definition: progsdefs.qc:200
bool navigation_goalrating_timeout(entity this)
Definition: navigation.qc:43
#define PHYS_INPUT_BUTTON_USE(s)
Definition: player.qh:154
float fixangle
Definition: progsdefs.qc:160
#define NULL
Definition: post.qh:17
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition: player.qh:146
bool autocvar_bot_god
Definition: cvars.qh:50
float bot_nextthink
Definition: bot.qh:57
#define IS_DEAD(s)
Definition: utils.qh:26
float bot_jump_time
Definition: bot.qh:70
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:27
float deadflag
Definition: progsdefs.qc:149
float flags
Definition: csprogsdefs.qc:129
float bot_aiskill
Definition: bot.qh:40
vector angles
Definition: csprogsdefs.qc:104
bool autocvar_g_campaign
Definition: campaign.qh:6
const int AI_STATUS_STUCK
Definition: bot.qh:17
float time
Definition: csprogsdefs.qc:16
#define PHYS_INPUT_BUTTON_INFO(s)
Definition: player.qh:152
#define IS_PLAYER(v)
Definition: utils.qh:9
float autocvar_bot_ai_thinkinterval
Definition: cvars.qh:44
+ Here is the caller graph for this function:

◆ find_bot_by_name()

entity find_bot_by_name ( string  name)

Definition at line 235 of file scripting.qc.

Referenced by GameCommand_bot_cmd().

236 {
237  FOREACH_CLIENT(IS_BOT_CLIENT(it) && it.netname == name,
238  {
239  return it;
240  });
241 
242  return NULL;
243 }
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
#define NULL
Definition: post.qh:17
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
+ Here is the caller graph for this function:

◆ find_bot_by_number()

entity find_bot_by_number ( float  number)

Definition at line 246 of file scripting.qc.

Referenced by GameCommand_bot_cmd().

247 {
248  entity bot;
249  float c = 0;
250 
251  if(!number)
252  return NULL;
253 
254  bot = findchainflags(flags, FL_CLIENT); // TODO: doesn't findchainflags loop backwards through entities?
255  while (bot)
256  {
257  if(IS_BOT_CLIENT(bot))
258  {
259  if(++c==number)
260  return bot;
261  }
262  bot = bot.chain;
263  }
264 
265  return NULL;
266 }
int int number
Definition: impulse.qc:89
entity() spawn
#define NULL
Definition: post.qh:17
float flags
Definition: csprogsdefs.qc:129
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
float FL_CLIENT
Definition: progsdefs.qc:234
+ Here is the caller graph for this function:

◆ float()

float ( entity  player,
entity  item 
)

◆ get_closer_dest()

vector get_closer_dest ( entity  ent,
vector  org 
)

Definition at line 103 of file navigation.qc.

References bound(), dest, and vector().

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

104 {
105  vector dest = '0 0 0';
106  if ((ent.classname != "waypoint") || ent.wpisbox)
107  {
108  vector wm1 = ent.origin + ent.mins;
109  vector wm2 = ent.origin + ent.maxs;
110  dest.x = bound(wm1.x, org.x, wm2.x);
111  dest.y = bound(wm1.y, org.y, wm2.y);
112  dest.z = bound(wm1.z, org.z, wm2.z);
113  }
114  else
115  dest = ent.origin;
116  return dest;
117 }
vector dest
Definition: jumppads.qh:41
vector(float skel, float bonenum) _skel_get_boneabs_hidden
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ havocbot_goalrating_enemyplayers()

void havocbot_goalrating_enemyplayers ( entity  this,
float  ratingscale,
vector  org,
float  sradius 
)

Definition at line 176 of file roles.qc.

References autocvar_bot_nofire, BOT_RATING_ENEMY, bot_shouldattack(), bound(), FOREACH_CLIENT, GetResource(), IS_PLAYER, max(), navigation_routerating(), RES_HEALTH, skill, time, vdist, vec2, waterlevel, and WATERLEVEL_WETFEET.

Referenced by havocbot_role_generic().

177 {
179  return;
180 
181  // don't chase players if we're under water
182  if(this.waterlevel > WATERLEVEL_WETFEET)
183  return;
184 
185  ratingscale = ratingscale * 0.0001;
186 
187  FOREACH_CLIENT(IS_PLAYER(it) && bot_shouldattack(this, it), {
188  // TODO: Merge this logic with the bot_shouldattack function
189  if(vdist(it.origin - org, <, 100) || vdist(it.origin - org, >, sradius))
190  continue;
191  if(vdist(vec2(it.velocity), >, autocvar_sv_maxspeed * 2))
192  continue;
193 
194  // rate only visible enemies
195  /*
196  traceline(this.origin + this.view_ofs, it.origin, MOVE_NOMONSTERS, this);
197  if (trace_fraction < 1 || trace_ent != it)
198  continue;
199  */
200 
201  float t = ((GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR)) - (GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR))) / 150;
202  t = bound(0, 1 + t, 3);
203  if (skill > 3)
204  {
205  if (time < StatusEffects_gettime(STATUSEFFECT_Strength, this) - 1) t += 0.5;
206  if (time < StatusEffects_gettime(STATUSEFFECT_Strength, it) - 1) t -= 0.5;
207  if (time < StatusEffects_gettime(STATUSEFFECT_Shield, this) - 1) t += 0.2;
208  if (time < StatusEffects_gettime(STATUSEFFECT_Shield, it) - 1) t -= 0.4;
209  }
210  t += max(0, 8 - skill) * 0.05; // less skilled bots attack more mindlessly
211  ratingscale *= t;
212  if (ratingscale > 0)
213  navigation_routerating(this, it, ratingscale * BOT_RATING_ENEMY, 2000);
214  });
215 }
float waterlevel
Definition: progsdefs.qc:181
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
float skill
Definition: api.qh:35
void navigation_routerating(entity this, entity e, float f, float rangebias)
Definition: navigation.qc:1220
RES_HEALTH
Definition: ent_cs.qc:126
const float BOT_RATING_ENEMY
Definition: roles.qh:3
const int WATERLEVEL_WETFEET
Definition: movetypes.qh:12
bool autocvar_bot_nofire
Definition: cvars.qh:54
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
#define vec2(...)
Definition: vector.qh:90
bool bot_shouldattack(entity this, entity e)
Definition: aim.qc:112
float time
Definition: csprogsdefs.qc:16
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ havocbot_goalrating_item_pickable_check_players()

bool havocbot_goalrating_item_pickable_check_players ( entity  this,
vector  org,
entity  item,
vector  item_org 
)

Definition at line 60 of file roles.qc.

References autocvar_bot_ai_friends_aware_pickup_radius, FLOAT_MAX, FOREACH_CLIENT, IS_DEAD, IS_PLAYER, teamplay, and vlen2.

Referenced by havocbot_goalrating_items(), and navigation_goalrating_timeout_can_be_anticipated().

61 {
62  if(!teamplay)
63  return true;
64 
65  // these variables hold squared distances in order to optimize code
66  float friend_dist2 = FLOAT_MAX;
67  float enemy_dist2 = FLOAT_MAX;
68  float dist2;
69 
70  FOREACH_CLIENT(IS_PLAYER(it) && it != this && !(IS_DEAD(it) || STAT(FROZEN, it)),
71  {
72  if (it.team == this.team)
73  {
74  if (!IS_REAL_CLIENT(it))
75  continue;
76 
77  dist2 = vlen2(it.origin - item_org);
78  if (dist2 > friend_dist2)
79  continue;
80 
81  if(havocbot_goalrating_item_can_be_left_to_teammate(this, it, item))
82  {
83  friend_dist2 = dist2;
84  continue;
85  }
86  }
87  else
88  {
89  // If enemy only track distances
90  // TODO: track only if visible ?
91  dist2 = vlen2(it.origin - item_org);
92  if (dist2 < enemy_dist2)
93  enemy_dist2 = dist2;
94  }
95  });
96 
97  // Rate the item only if no one needs it, or if an enemy is closer to it
98  dist2 = vlen2(item_org - org);
99  if ((enemy_dist2 < friend_dist2 && dist2 < enemy_dist2)
100  || (friend_dist2 > autocvar_bot_ai_friends_aware_pickup_radius ** 2)
101  || (dist2 < friend_dist2 && dist2 < 200 ** 2))
102  return true;
103  return false;
104 };
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
#define vlen2(v)
Definition: vector.qh:4
float teamplay
Definition: progsdefs.qc:31
#define IS_DEAD(s)
Definition: utils.qh:26
float autocvar_bot_ai_friends_aware_pickup_radius
Definition: cvars.qh:38
#define IS_PLAYER(v)
Definition: utils.qh:9
const float FLOAT_MAX
Definition: float.qh:3
+ Here is the caller graph for this function:

◆ havocbot_goalrating_items()

void havocbot_goalrating_items ( entity  this,
float  ratingscale,
vector  org,
float  sradius 
)

Definition at line 106 of file roles.qc.

References g_items, havocbot_goalrating_item_pickable_check_players(), ignoregoal, ignoregoaltime, IL_EACH, IN_LAVA, IS_ONGROUND, Item_IsLoot(), navigation_routerating(), NULL, time, trace_endpos, vdist, and vector().

Referenced by havocbot_role_generic().

107 {
108  ratingscale = ratingscale * 0.0001;
109 
110  IL_EACH(g_items, it.bot_pickup,
111  {
112  // ignore if bot already rated this item with a higher ratingscale
113  // NOTE: this code assumes each bot rates items in a different frame
114  if(it.bot_ratingscale_time == time && ratingscale < it.bot_ratingscale)
115  continue;
116 
117  if(!it.solid)
118  {
119  if(!autocvar_bot_ai_timeitems)
120  continue;
121  if(!it.scheduledrespawntime)
122  continue;
123  if(it.respawntime < max(11, autocvar_bot_ai_timeitems_minrespawndelay))
124  continue;
125  if(it.respawntimejitter && !it.itemdef.instanceOfPowerup)
126  continue;
127 
128  float t = 0;
129  if(it.itemdef.instanceOfPowerup)
130  t = bound(0, skill / 10, 1) * 6;
131  else if(skill >= 9)
132  t = 4;
133 
134  if(time < it.scheduledrespawntime - t)
135  continue;
136 
137  it.bot_pickup_respawning = true;
138  }
139  vector o = (it.absmin + it.absmax) * 0.5;
140  if(vdist(o - org, >, sradius) || (it == this.ignoregoal && time < this.ignoregoaltime) )
141  continue;
142 
143  // Check if the item can be picked up safely
144  if(Item_IsLoot(it))
145  {
146  if(!IS_ONGROUND(it))
147  continue;
148  traceline(o, o + '0 0 -1500', true, NULL);
149 
150  if(IN_LAVA(trace_endpos + '0 0 1'))
151  continue;
152 
153  // this tracebox_hits_trigger_hurt call isn't needed:
154  // dropped weapons are removed as soon as they fall on a trigger_hurt
155  // and can't be rated while they are in the air
156  //if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
157  // continue;
158  }
159  else
160  {
161  if(IN_LAVA(it.origin + (it.mins + it.maxs) * 0.5))
162  continue;
163  }
164 
166  continue;
167 
168  it.bot_ratingscale_time = time;
169  it.bot_ratingscale = ratingscale;
170  float rating = it.bot_pickupevalfunc(this, it);
171  if(rating > 0)
172  navigation_routerating(this, it, rating * ratingscale, 2000);
173  });
174 }
#define IL_EACH(this, cond, body)
float ignoregoaltime
Definition: api.qh:98
entity ignoregoal
Definition: api.qh:99
#define IN_LAVA(pos)
Definition: bot.qh:83
#define IS_ONGROUND(s)
Definition: movetypes.qh:16
void navigation_routerating(entity this, entity e, float f, float rangebias)
Definition: navigation.qc:1220
IntrusiveList g_items
Definition: items.qh:126
#define NULL
Definition: post.qh:17
vector trace_endpos
Definition: csprogsdefs.qc:37
vector(float skel, float bonenum) _skel_get_boneabs_hidden
bool havocbot_goalrating_item_pickable_check_players(entity this, vector org, entity item, vector item_org)
Definition: roles.qc:60
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
bool Item_IsLoot(entity item)
Returns whether the item is loot.
Definition: spawning.qc:121
float time
Definition: csprogsdefs.qc:16
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ havocbot_goalrating_waypoints()

void havocbot_goalrating_waypoints ( entity  this,
float  ratingscale,
vector  org,
float  sradius 
)

Definition at line 16 of file roles.qc.

References g_waypoints, IL_EACH, max(), navigation_bestgoal, random(), vdist, and WAYPOINTFLAG_TELEPORT.

Referenced by havocbot_role_dom(), havocbot_role_ft_freeing(), havocbot_role_ft_offense(), havocbot_role_generic(), and havocbot_role_ka_carrier().

17 {
18  // rate waypoints only if there's no alternative goal
20  return;
21 
22  float f;
23  float range = 500;
24  sradius = max(range, (0.5 + random() * 0.5) * sradius);
25  while(sradius > 100)
26  {
27  IL_EACH(g_waypoints, vdist(it.origin - org, <, sradius)
28  && vdist(it.origin - org, >, max(100, sradius - range))
29  && !(it.wpflags & WAYPOINTFLAG_TELEPORT),
30  {
31  if(vdist(it.origin - this.wp_goal_prev0.origin, <, range * 1.5))
32  f = 0.1;
33  else if(vdist(it.origin - this.wp_goal_prev1.origin, <, range * 1.5))
34  f = 0.1;
35  else
36  f = 0.5 + random() * 0.5;
37  navigation_routerating(this, it, ratingscale * f, 2000);
38  });
40  break;
41  sradius -= range;
42  }
43 };
#define IL_EACH(this, cond, body)
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
IntrusiveList g_waypoints
Definition: api.qh:148
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_dynamicgoal_init()

void navigation_dynamicgoal_init ( entity  this,
bool  initially_static 
)

Definition at line 76 of file navigation.qc.

Referenced by ctf_DelayedFlagSetup(), ka_SpawnBall(), kh_Key_Spawn(), PutPlayerInServer(), and W_ThrowNewWeapon().

77 {
78  this.navigation_dynamicgoal = true;
80  if(initially_static)
81  this.nearestwaypointtimeout = -1;
82  else
84 }
float nearestwaypointtimeout
Definition: api.qh:53
bool navigation_dynamicgoal
Definition: api.qh:107
entity bot_basewaypoint
Definition: api.qh:106
entity nearestwaypoint
Definition: api.qh:54
float time
Definition: csprogsdefs.qc:16
+ Here is the caller graph for this function:

◆ navigation_dynamicgoal_set()

void navigation_dynamicgoal_set ( entity  this,
entity  dropper 
)

Definition at line 86 of file navigation.qc.

Referenced by ctf_Handle_Throw(), ka_DropEvent(), ka_RespawnBall(), and kh_Key_Detach().

87 {
89  if (dropper && dropper.nearestwaypointtimeout && dropper.nearestwaypointtimeout < time + 2)
90  this.nearestwaypoint = dropper.nearestwaypoint;
91  if (this.nearestwaypoint)
92  this.nearestwaypointtimeout += 2;
93 }
float nearestwaypointtimeout
Definition: api.qh:53
entity nearestwaypoint
Definition: api.qh:54
float time
Definition: csprogsdefs.qc:16
+ Here is the caller graph for this function:

◆ navigation_dynamicgoal_unset()

void navigation_dynamicgoal_unset ( entity  this)

Definition at line 95 of file navigation.qc.

Referenced by ctf_RespawnFlag(), ka_TouchEvent(), and kh_Key_Attach().

96 {
97  if(this.bot_basewaypoint)
99  this.nearestwaypointtimeout = -1;
100 }
float nearestwaypointtimeout
Definition: api.qh:53
entity bot_basewaypoint
Definition: api.qh:106
entity nearestwaypoint
Definition: api.qh:54
+ Here is the caller graph for this function:

◆ navigation_findnearestwaypoint()

entity navigation_findnearestwaypoint ( entity  ent,
float  walkfromwp 
)

Definition at line 1011 of file navigation.qc.

Referenced by botframe_autowaypoints_fix_from(), waypoint_remove_fromeditor(), and waypoint_unreachable().

1012 {
1013  entity wp = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, NULL);
1015  {
1016  entity wp2 = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, wp);
1017  if (wp && !wp2)
1018  wp.wpflags |= WAYPOINTFLAG_PROTECTED;
1019  }
1020  return wp;
1021 }
const int WAYPOINTFLAG_PROTECTED
Definition: api.qh:16
entity() spawn
int autocvar_g_waypointeditor_auto
Definition: cvars.qh:63
#define NULL
Definition: post.qh:17
+ Here is the caller graph for this function:

◆ navigation_goalrating_end()

void navigation_goalrating_end ( entity  this)

Definition at line 1845 of file navigation.qc.

Referenced by havocbot_moveto_refresh_route(), havocbot_role_ast_defense(), havocbot_role_ast_offense(), havocbot_role_ctf_carrier(), havocbot_role_ctf_defense(), havocbot_role_ctf_escort(), havocbot_role_ctf_middle(), havocbot_role_ctf_offense(), havocbot_role_ctf_retriever(), havocbot_role_cts(), havocbot_role_dom(), havocbot_role_ft_freeing(), havocbot_role_ft_offense(), havocbot_role_generic(), havocbot_role_ka_carrier(), havocbot_role_ka_collector(), havocbot_role_kh_carrier(), havocbot_role_kh_defense(), havocbot_role_kh_freelancer(), havocbot_role_kh_offense(), havocbot_role_ons_offense(), and havocbot_role_race().

1846 {
1847  if(this.aistatus & AI_STATUS_STUCK)
1848  return;
1849 
1850  entity wp = this.goalstack31; // save to wp as this.goalstack31 is set by navigation_routetogoal
1851  this.goalstack31 = NULL;
1852 
1854  LOG_DEBUG("best goal ", navigation_bestgoal.classname);
1855 
1856  if (wp && this.goalcurrent == wp)
1857  navigation_poproute(this);
1858 
1859  // If the bot got stuck then try to reach the farthest waypoint
1860  if (!this.goalentity)
1861  {
1862  if (autocvar_bot_wander_enable && !(this.aistatus & AI_STATUS_STUCK))
1863  {
1864  LOG_DEBUG(this.netname, " cannot walk to any goal");
1865  this.aistatus |= AI_STATUS_STUCK;
1866  }
1867  this.goalentity_shouldbefrozen = false;
1868  }
1869  else
1870  this.goalentity_shouldbefrozen = boolean(STAT(FROZEN, this.goalentity));
1871 }
int aistatus
Definition: bot.qh:20
entity() spawn
string netname
Definition: powerups.qc:20
origin
Definition: ent_cs.qc:114
entity goalentity
Definition: progsdefs.qc:189
#define NULL
Definition: post.qh:17
bool autocvar_bot_wander_enable
Definition: cvars.qh:60
const int AI_STATUS_STUCK
Definition: bot.qh:17
#define boolean(value)
Definition: bool.qh:9
#define LOG_DEBUG(...)
Definition: log.qh:85
+ Here is the caller graph for this function:

◆ navigation_goalrating_start()

void navigation_goalrating_start ( entity  this)

Definition at line 1830 of file navigation.qc.

Referenced by havocbot_moveto_refresh_route(), havocbot_role_ast_defense(), havocbot_role_ast_offense(), havocbot_role_ctf_carrier(), havocbot_role_ctf_defense(), havocbot_role_ctf_escort(), havocbot_role_ctf_middle(), havocbot_role_ctf_offense(), havocbot_role_ctf_retriever(), havocbot_role_cts(), havocbot_role_dom(), havocbot_role_ft_freeing(), havocbot_role_ft_offense(), havocbot_role_generic(), havocbot_role_ka_carrier(), havocbot_role_ka_collector(), havocbot_role_kh_carrier(), havocbot_role_kh_defense(), havocbot_role_kh_freelancer(), havocbot_role_kh_offense(), havocbot_role_ons_offense(), and havocbot_role_race().

1831 {
1832  if(this.aistatus & AI_STATUS_STUCK)
1833  return;
1834 
1836  navigation_bestrating = -1;
1838  navigation_clearroute(this);
1840  navigation_markroutes(this, wp);
1841  this.goalstack31 = wp; // temporarly save the really close waypoint
1842 }
int aistatus
Definition: bot.qh:20
entity() spawn
#define NULL
Definition: post.qh:17
const int AI_STATUS_STUCK
Definition: bot.qh:17
+ Here is the caller graph for this function:

◆ navigation_goalrating_timeout()

◆ navigation_goalrating_timeout_can_be_anticipated()

bool navigation_goalrating_timeout_can_be_anticipated ( entity  this)

Definition at line 55 of file navigation.qc.

References autocvar_bot_ai_ignoregoal_timeout, bot_strategytime, goalentity, havocbot_goalrating_item_pickable_check_players(), ignoregoal, ignoregoaltime, IS_MOVABLE, origin, time, vdist, and vector().

Referenced by havocbot_movetogoal().

56 {
57  vector gco = (this.goalentity.absmin + this.goalentity.absmax) * 0.5;
58  if (vdist(gco - this.origin, >, autocvar_sv_maxspeed * 1.5)
59  && time > this.bot_strategytime - (IS_MOVABLE(this.goalentity) ? 3 : 2))
60  {
61  return true;
62  }
63 
64  if (this.goalentity.bot_pickup && time > this.bot_strategytime - 5)
65  {
67  {
68  this.ignoregoal = this.goalentity;
70  return true;
71  }
72  }
73  return false;
74 }
float ignoregoaltime
Definition: api.qh:98
entity ignoregoal
Definition: api.qh:99
float autocvar_bot_ai_ignoregoal_timeout
Definition: cvars.qh:39
#define IS_MOVABLE(v)
Definition: utils.qh:25
origin
Definition: ent_cs.qc:114
entity goalentity
Definition: progsdefs.qc:189
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float bot_strategytime
Definition: bot.qh:69
float time
Definition: csprogsdefs.qc:16
bool havocbot_goalrating_item_pickable_check_players(entity this, vector org, entity item, vector item_org)
Definition: roles.qc:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_goalrating_timeout_expire()

void navigation_goalrating_timeout_expire ( entity  this,
float  seconds 
)

Definition at line 35 of file navigation.qc.

References bot_strategytime, and time.

Referenced by havocbot_movetogoal(), havocbot_role_ctf_escort(), havocbot_role_ctf_setrole(), havocbot_role_ka_carrier(), havocbot_role_ka_collector(), navigation_goalrating_timeout_force(), and navigation_unstuck().

36 {
37  if (seconds <= 0)
38  this.bot_strategytime = 0;
39  else if (this.bot_strategytime > time + seconds)
40  this.bot_strategytime = time + seconds;
41 }
float bot_strategytime
Definition: bot.qh:69
float time
Definition: csprogsdefs.qc:16
+ Here is the caller graph for this function:

◆ navigation_goalrating_timeout_extend_if_needed()

void navigation_goalrating_timeout_extend_if_needed ( entity  this,
float  seconds 
)

Definition at line 49 of file navigation.qc.

References bot_strategytime, max(), and time.

50 {
51  this.bot_strategytime = max(this.bot_strategytime, time + seconds);
52 }
float bot_strategytime
Definition: bot.qh:69
float time
Definition: csprogsdefs.qc:16
+ Here is the call graph for this function:

◆ navigation_goalrating_timeout_force()

void navigation_goalrating_timeout_force ( entity  this)

Definition at line 28 of file navigation.qc.

Referenced by bot_think(), havocbot_ai(), havocbot_chooserole(), havocbot_movetogoal(), havocbot_role_ctf_retriever(), and havocbot_role_ctf_setrole().

29 {
31 }
+ Here is the caller graph for this function:

◆ navigation_goalrating_timeout_set()

◆ navigation_markroutes()

void navigation_markroutes ( entity  this,
entity  fixed_source_waypoint 
)

Definition at line 1081 of file navigation.qc.

Referenced by waypoint_unreachable().

1082 {
1083  float cost, cost2;
1084  vector p;
1085 
1086  IL_EACH(g_waypoints, true,
1087  {
1088  it.wpconsidered = false;
1089  it.wpnearestpoint = '0 0 0';
1090  it.wpcost = 10000000;
1091  it.wpfire = 0;
1092  it.enemy = NULL;
1093  });
1094 
1095  if(fixed_source_waypoint)
1096  {
1097  fixed_source_waypoint.wpconsidered = true;
1098  fixed_source_waypoint.wpnearestpoint = fixed_source_waypoint.origin + 0.5 * (fixed_source_waypoint.mins + fixed_source_waypoint.maxs);
1099  fixed_source_waypoint.wpcost = fixed_source_waypoint.dmg;
1100  fixed_source_waypoint.wpfire = 1;
1101  fixed_source_waypoint.enemy = NULL;
1102  }
1103  else
1104  {
1105  // try a short range search for the nearest waypoints, and expand the search repeatedly if none are found
1106  // as this search is expensive we will use lower values if the bot is on the air
1107  float increment, maxdistance;
1108  if(IS_ONGROUND(this))
1109  {
1110  increment = 750;
1111  maxdistance = 50000;
1112  }
1113  else
1114  {
1115  increment = 500;
1116  maxdistance = 1500;
1117  }
1118 
1119  for(int j = increment; !navigation_markroutes_nearestwaypoints(this, j) && j < maxdistance; j += increment);
1120  }
1121 
1122  bool searching = true;
1123  while (searching)
1124  {
1125  searching = false;
1126  IL_EACH(g_waypoints, it.wpfire,
1127  {
1128  searching = true;
1129  it.wpfire = 0;
1130  cost = it.wpcost;
1131  p = it.wpnearestpoint;
1132  entity wp;
1133  wp = it.wp00;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp00mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1134  wp = it.wp01;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp01mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1135  wp = it.wp02;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp02mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1136  wp = it.wp03;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp03mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1137  wp = it.wp04;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp04mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1138  wp = it.wp05;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp05mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1139  wp = it.wp06;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp06mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1140  wp = it.wp07;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp07mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1141  wp = it.wp08;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp08mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1142  wp = it.wp09;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp09mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1143  wp = it.wp10;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp10mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1144  wp = it.wp11;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp11mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1145  wp = it.wp12;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp12mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1146  wp = it.wp13;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp13mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1147  wp = it.wp14;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp14mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1148  wp = it.wp15;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp15mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1149  wp = it.wp16;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp16mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1150  wp = it.wp17;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp17mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1151  wp = it.wp18;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp18mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1152  wp = it.wp19;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp19mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1153  wp = it.wp20;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp20mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1154  wp = it.wp21;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp21mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1155  wp = it.wp22;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp22mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1156  wp = it.wp23;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp23mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1157  wp = it.wp24;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp24mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1158  wp = it.wp25;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp25mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1159  wp = it.wp26;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp26mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1160  wp = it.wp27;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp27mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1161  wp = it.wp28;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp28mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1162  wp = it.wp29;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp29mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1163  wp = it.wp30;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp30mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1164  wp = it.wp31;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + it.wp31mincost) navigation_markroutes_checkwaypoint(it, wp, cost2, p);
1165  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
1166  });
1167  }
1168 }
#define IL_EACH(this, cond, body)
#define IS_ONGROUND(s)
Definition: movetypes.qh:16
#define NULL
Definition: post.qh:17
IntrusiveList g_waypoints
Definition: api.qh:148
vector(float skel, float bonenum) _skel_get_boneabs_hidden
+ Here is the caller graph for this function:

◆ navigation_markroutes_inverted()

void navigation_markroutes_inverted ( entity  fixed_source_waypoint)

Definition at line 1171 of file navigation.qc.

Referenced by waypoint_unreachable().

1172 {
1173  float cost, cost2;
1174  vector p;
1175  IL_EACH(g_waypoints, true,
1176  {
1177  it.wpconsidered = false;
1178  it.wpnearestpoint = '0 0 0';
1179  it.wpcost = 10000000;
1180  it.wpfire = 0;
1181  it.enemy = NULL;
1182  });
1183 
1184  if(fixed_source_waypoint)
1185  {
1186  fixed_source_waypoint.wpconsidered = true;
1187  fixed_source_waypoint.wpnearestpoint = fixed_source_waypoint.origin + 0.5 * (fixed_source_waypoint.mins + fixed_source_waypoint.maxs);
1188  fixed_source_waypoint.wpcost = fixed_source_waypoint.dmg; // the cost to get from X to fixed_source_waypoint
1189  fixed_source_waypoint.wpfire = 1;
1190  fixed_source_waypoint.enemy = NULL;
1191  }
1192  else
1193  {
1194  error("need to start with a waypoint\n");
1195  }
1196 
1197  bool searching = true;
1198  while (searching)
1199  {
1200  searching = false;
1201  IL_EACH(g_waypoints, it.wpfire,
1202  {
1203  searching = true;
1204  it.wpfire = 0;
1205  cost = it.wpcost; // cost to walk from it to home
1206  p = it.wpnearestpoint;
1207  entity wp = it;
1208  IL_EACH(g_waypoints, it != wp,
1209  {
1210  if(!waypoint_islinked(it, wp))
1211  continue;
1212  cost2 = cost + it.dmg;
1213  navigation_markroutes_checkwaypoint(wp, it, cost2, p);
1214  });
1215  });
1216  }
1217 }
#define IL_EACH(this, cond, body)
#define NULL
Definition: post.qh:17
IntrusiveList g_waypoints
Definition: api.qh:148
vector(float skel, float bonenum) _skel_get_boneabs_hidden
+ Here is the caller graph for this function:

◆ navigation_routerating()

void navigation_routerating ( entity  this,
entity  e,
float  f,
float  rangebias 
)

Definition at line 1220 of file navigation.qc.

Referenced by havocbot_ctf_teamcount(), havocbot_goalrating_ast_targets(), havocbot_goalrating_ball(), havocbot_goalrating_ctf_droppedflags(), havocbot_goalrating_ctf_enemybase(), havocbot_goalrating_ctf_enemyflag(), havocbot_goalrating_ctf_ourbase(), havocbot_goalrating_ctf_ourstolenflag(), havocbot_goalrating_enemyplayers(), havocbot_goalrating_ft_freeplayers(), havocbot_goalrating_items(), havocbot_goalrating_kh(), havocbot_goalrating_ons_controlpoints_attack(), havocbot_goalrating_ons_generator_attack(), havocbot_moveto_refresh_route(), havocbot_role_cts(), and havocbot_role_race().

1221 {
1222  if (!e || e.blacklisted) { return; }
1223 
1224  rangebias = waypoint_getlinearcost(rangebias);
1225  f = waypoint_getlinearcost(f);
1226 
1227  if (IS_PLAYER(e))
1228  {
1229  bool rate_wps = false;
1230  if (e.watertype < CONTENT_WATER || (e.waterlevel > WATERLEVEL_WETFEET && !STAT(FROZEN, e))
1231  || (e.flags & FL_PARTIALGROUND))
1232  {
1233  rate_wps = true;
1234  }
1235 
1236  if(!IS_ONGROUND(e))
1237  {
1238  traceline(e.origin, e.origin + '0 0 -1500', true, NULL);
1239  int t = pointcontents(trace_endpos + '0 0 1');
1240  if(t != CONTENT_SOLID )
1241  {
1242  if(t == CONTENT_WATER || t == CONTENT_SLIME || t == CONTENT_LAVA)
1243  rate_wps = true;
1244  else if(tracebox_hits_trigger_hurt(e.origin, e.mins, e.maxs, trace_endpos))
1245  return;
1246  }
1247  }
1248 
1249  if(rate_wps)
1250  {
1251  entity theEnemy = e;
1252  entity best_wp = NULL;
1253  float best_dist = FLOAT_MAX;
1254  IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_TELEPORT)
1255  && vdist(it.origin - theEnemy.origin, <, 500)
1256  && vdist(it.origin - this.origin, >, 100)
1257  && vdist(it.origin - this.origin, <, 10000),
1258  {
1259  float dist = vlen2(it.origin - theEnemy.origin);
1260  if (dist < best_dist)
1261  {
1262  best_wp = it;
1263  best_dist = dist;
1264  }
1265  });
1266  if (!best_wp)
1267  return;
1268  e = best_wp;
1269  }
1270  }
1271 
1272  vector goal_org = (e.absmin + e.absmax) * 0.5;
1273 
1274  //print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n");
1275 
1276  // Evaluate path using jetpack
1277  if(this.items & IT_JETPACK)
1280  {
1281  vector pointa, pointb;
1282 
1283  LOG_DEBUG("jetpack ai: evaluating path for ", e.classname);
1284 
1285  // Point A
1286  traceline(this.origin, this.origin + '0 0 65535', MOVE_NORMAL, this);
1287  pointa = trace_endpos - '0 0 1';
1288 
1289  // Point B
1290  traceline(goal_org, goal_org + '0 0 65535', MOVE_NORMAL, e);
1291  pointb = trace_endpos - '0 0 1';
1292 
1293  // Can I see these two points from the sky?
1294  traceline(pointa, pointb, MOVE_NORMAL, this);
1295 
1296  if(trace_fraction==1)
1297  {
1298  LOG_DEBUG("jetpack ai: can bridge these two points");
1299 
1300  // Lower the altitude of these points as much as possible
1301  float zdistance, xydistance, cost, t, fuel;
1302  vector down, npa, npb;
1303 
1304  down = '0 0 -1' * (STAT(PL_MAX, this).z - STAT(PL_MIN, this).z) * 10;
1305 
1306  do{
1307  npa = pointa + down;
1308  npb = pointb + down;
1309 
1310  if(npa.z<=this.absmax.z)
1311  break;
1312 
1313  if(npb.z<=e.absmax.z)
1314  break;
1315 
1316  traceline(npa, npb, MOVE_NORMAL, this);
1317  if(trace_fraction==1)
1318  {
1319  pointa = npa;
1320  pointb = npb;
1321  }
1322  }
1323  while(trace_fraction == 1);
1324 
1325 
1326  // Rough estimation of fuel consumption
1327  // (ignores acceleration and current xyz velocity)
1328  xydistance = vlen(pointa - pointb);
1329  zdistance = fabs(pointa.z - this.origin.z);
1330 
1331  t = zdistance / autocvar_g_jetpack_maxspeed_up;
1332  t += xydistance / autocvar_g_jetpack_maxspeed_side;
1333  fuel = t * autocvar_g_jetpack_fuel * 0.8;
1334 
1335  LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), ", have ", ftos(GetResource(this, RES_FUEL)));
1336 
1337  // enough fuel ?
1338  if(GetResource(this, RES_FUEL) > fuel || (this.items & IT_UNLIMITED_AMMO))
1339  {
1340  // Estimate cost
1341  // (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
1342  // - between air and ground speeds)
1343 
1344  cost = xydistance / (autocvar_g_jetpack_maxspeed_side/autocvar_sv_maxspeed);
1345  cost += zdistance / (autocvar_g_jetpack_maxspeed_up/autocvar_sv_maxspeed);
1346  cost *= 1.5;
1347 
1348  // Compare against other goals
1349  f = f * rangebias / (rangebias + cost);
1350 
1351  if (navigation_bestrating < f)
1352  {
1353  LOG_DEBUG("jetpack path: added goal ", e.classname, " (with rating ", ftos(f), ")");
1355  navigation_bestgoal = e;
1356  this.navigation_jetpack_goal = e;
1357  this.navigation_jetpack_point = pointb;
1358  }
1359  return;
1360  }
1361  }
1362  }
1363 
1364  entity nwp;
1365  //te_wizspike(e.origin);
1366  //bprint(etos(e));
1367  //bprint("\n");
1368  // update the cached spawnfunc_waypoint link on a dynamic item entity
1369  if(e.classname == "waypoint" && !(e.wpflags & WAYPOINTFLAG_PERSONAL))
1370  {
1371  nwp = e;
1372  }
1373  else
1374  {
1375  if(waypointeditor_enabled && e.nearestwaypointtimeout >= 0 && time > e.nearestwaypointtimeout)
1376  e.nearestwaypoint = NULL;
1377 
1378  if ((!e.nearestwaypoint || e.navigation_dynamicgoal)
1379  && e.nearestwaypointtimeout >= 0 && time > e.nearestwaypointtimeout)
1380  {
1381  if(IS_BOT_CLIENT(e) && e.goalcurrent && e.goalcurrent.classname == "waypoint")
1382  e.nearestwaypoint = nwp = e.goalcurrent;
1383  else
1384  e.nearestwaypoint = nwp = navigation_findnearestwaypoint(e, true);
1385  if(!nwp)
1386  {
1387  LOG_DEBUG("FAILED to find a nearest waypoint to '", e.classname, "' #", etos(e));
1388 
1389  if(!e.navigation_dynamicgoal)
1390  e.blacklisted = true;
1391 
1392  if(e.blacklisted)
1393  {
1394  LOG_DEBUG("The entity '", e.classname, "' is going to be excluded from path finding during this match");
1395  return;
1396  }
1397  }
1398 
1399  if(e.navigation_dynamicgoal)
1400  e.nearestwaypointtimeout = time + 2;
1401  else if(waypointeditor_enabled)
1402  e.nearestwaypointtimeout = time + 3 + random() * 2;
1403  }
1404  nwp = e.nearestwaypoint;
1405  }
1406 
1407  if (nwp && nwp.wpcost < 10000000)
1408  {
1409  //te_wizspike(nwp.wpnearestpoint);
1410  float nwptoitem_cost = 0;
1411  if(nwp.wpflags & WAYPOINTFLAG_TELEPORT)
1412  nwptoitem_cost = nwp.wp00mincost;
1413  else
1414  nwptoitem_cost = waypoint_gettravelcost(nwp.wpnearestpoint, goal_org, nwp, e);
1415  float cost = nwp.wpcost + nwptoitem_cost;
1416  LOG_DEBUG("checking ^5", e.classname, "^7 with base rating ^xf04", ftos(f), "^7 and rangebias ^xf40", ftos(rangebias));
1417  f = f * rangebias / (rangebias + cost);
1418  LOG_DEBUG(" ^5", e.classname, "^7 with cost ^6", ftos(cost), "^7 and final rating ^2", ftos(f));
1419  if (navigation_bestrating < f)
1420  {
1421  LOG_DEBUG(" ground path: ^3added goal ^5", e.classname);
1423  navigation_bestgoal = e;
1424  }
1425  }
1426 }
#define IL_EACH(this, cond, body)
const float CONTENT_LAVA
Definition: csprogsdefs.qc:240
float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_ent)
Definition: waypoints.qc:1030
float autocvar_bot_ai_navigation_jetpack
Definition: cvars.qh:42
entity() spawn
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
#define IS_ONGROUND(s)
Definition: movetypes.qh:16
const float CONTENT_SOLID
Definition: csprogsdefs.qc:237
origin
Definition: ent_cs.qc:114
float FL_PARTIALGROUND
Definition: progsdefs.qc:241
bool waypointeditor_enabled
Definition: waypoints.qh:3
const float CONTENT_SLIME
Definition: csprogsdefs.qc:239
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
const float CONTENT_WATER
Definition: csprogsdefs.qc:238
#define NULL
Definition: post.qh:17
vector trace_endpos
Definition: csprogsdefs.qc:37
const int WATERLEVEL_WETFEET
Definition: movetypes.qh:12
float waypoint_getlinearcost(float dist)
Definition: waypoints.qc:1012
IntrusiveList g_waypoints
Definition: api.qh:148
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float items
Definition: progsdefs.qc:145
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
const int WAYPOINTFLAG_PERSONAL
Definition: api.qh:15
float autocvar_bot_ai_navigation_jetpack_mindistance
Definition: cvars.qh:43
float time
Definition: csprogsdefs.qc:16
float trace_fraction
Definition: csprogsdefs.qc:36
#define IS_PLAYER(v)
Definition: utils.qh:9
const float FLOAT_MAX
Definition: float.qh:3
#define LOG_DEBUG(...)
Definition: log.qh:85
+ Here is the caller graph for this function:

◆ set_tracewalk_dest()

void set_tracewalk_dest ( entity  ent,
vector  org,
bool  fix_player_dest 
)

Definition at line 119 of file navigation.qc.

References bound(), IS_MONSTER, IS_ONGROUND, IS_PLAYER, MOVE_NORMAL, trace_endpos, trace_startsolid, tracewalk_dest, tracewalk_dest_height, vec2, and vector().

Referenced by havocbot_movetogoal(), navigation_findnearestwaypoint_withdist_except(), navigation_get_really_close_waypoint(), navigation_routetogoal(), navigation_shortenpath(), and navigation_unstuck().

120 {
121  if ((ent.classname != "waypoint") || ent.wpisbox)
122  {
123  vector wm1 = ent.origin + ent.mins;
124  vector wm2 = ent.origin + ent.maxs;
125  if (IS_PLAYER(ent) || IS_MONSTER(ent))
126  {
127  // move destination point out of player bbox otherwise tracebox always fails
128  // (if bot_navigation_ignoreplayers is false)
129  wm1 += vec2(PL_MIN_CONST) + '-1 -1 0';
130  wm2 += vec2(PL_MAX_CONST) + '1 1 0';
131  }
132  // set destination point to x and y coords of ent that are closer to org
133  // z coord is set to ent's min height
134  tracewalk_dest.x = bound(wm1.x, org.x, wm2.x);
135  tracewalk_dest.y = bound(wm1.y, org.y, wm2.y);
136  if ((IS_PLAYER(ent) || IS_MONSTER(ent))
137  && org.x == tracewalk_dest.x && org.y == tracewalk_dest.y && org.z > tracewalk_dest.z)
138  {
139  tracewalk_dest.z = wm2.z - PL_MIN_CONST.z;
141  fix_player_dest = false;
142  }
143  else
144  {
145  tracewalk_dest.z = wm1.z;
146  tracewalk_dest_height = wm2.z - wm1.z;
147  }
148  }
149  else
150  {
151  tracewalk_dest = ent.origin;
153  }
154  if (fix_player_dest && IS_PLAYER(ent) && !IS_ONGROUND(ent))
155  {
156  // snap player to the ground
157  if (org.x == tracewalk_dest.x && org.y == tracewalk_dest.y)
158  {
159  // bot is right under the player
160  tracebox(ent.origin, ent.mins, ent.maxs, ent.origin - '0 0 700', MOVE_NORMAL, ent);
163  }
164  else
165  {
166  tracebox(tracewalk_dest, ent.mins, ent.maxs, tracewalk_dest - '0 0 700', MOVE_NORMAL, ent);
167  if (!trace_startsolid && tracewalk_dest.z - trace_endpos.z > 0)
168  {
171  }
172  }
173  }
174 }
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
#define IS_ONGROUND(s)
Definition: movetypes.qh:16
#define IS_MONSTER(v)
Definition: utils.qh:21
vector trace_endpos
Definition: csprogsdefs.qc:37
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define vec2(...)
Definition: vector.qh:90
float trace_startsolid
Definition: csprogsdefs.qc:35
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_tracewalk_dest_2()

vector set_tracewalk_dest_2 ( entity  ent,
vector  org 
)

Definition at line 177 of file navigation.qc.

References bound(), tracewalk_dest, tracewalk_dest_height, and vector().

Referenced by waypoint_think().

178 {
179  vector closer_dest = '0 0 0';
180  if ((ent.classname != "waypoint") || ent.wpisbox)
181  {
182  vector wm1 = ent.origin + ent.mins;
183  vector wm2 = ent.origin + ent.maxs;
184  closer_dest.x = bound(wm1.x, org.x, wm2.x);
185  closer_dest.y = bound(wm1.y, org.y, wm2.y);
186  closer_dest.z = bound(wm1.z, org.z, wm2.z);
187  // set destination point to x and y coords of ent that are closer to org
188  // z coord is set to ent's min height
189  tracewalk_dest.x = closer_dest.x;
190  tracewalk_dest.y = closer_dest.y;
191  tracewalk_dest.z = wm1.z;
192  tracewalk_dest_height = wm2.z - wm1.z; // destination height
193  }
194  else
195  {
196  closer_dest = ent.origin;
197  tracewalk_dest = closer_dest;
199  }
200  return closer_dest;
201 }
vector(float skel, float bonenum) _skel_get_boneabs_hidden
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ STATIC_INIT()

STATIC_INIT ( botapi  )

Definition at line 151 of file api.qh.

References IL_NEW.

152 {
153  g_waypoints = IL_NEW();
154  g_bot_targets = IL_NEW();
155  g_bot_dodge = IL_NEW();
156 }
#define IL_NEW()
IntrusiveList g_bot_dodge
Definition: api.qh:150
IntrusiveList g_bot_targets
Definition: api.qh:149
IntrusiveList g_waypoints
Definition: api.qh:148

◆ tracewalk()

bool tracewalk ( entity  e,
vector  start,
vector  m1,
vector  m2,
vector  end,
float  end_height,
float  movemode 
)

Definition at line 273 of file navigation.qc.

Referenced by GameCommand_trace(), and havocbot_movetogoal().

274 {
276  {
277  debugresetnodes();
278  debugnode(e, start);
279  }
280 
281  vector org = start;
282  vector flatdir = end - start;
283  flatdir.z = 0;
284  float flatdist = vlen(flatdir);
285  flatdir = normalize(flatdir);
286  float stepdist = 32;
287  bool ignorehazards = false;
288  int nav_action;
289 
290  // Analyze starting point
291  if (IN_LAVA(start))
292  ignorehazards = true;
293 
294  tracebox(start, m1, m2, start, MOVE_NOMONSTERS, e);
295  if (trace_startsolid)
296  {
297  // Bad start
300 
301  //print("tracewalk: ", vtos(start), " is a bad start\n");
302  return false;
303  }
304 
305  vector end2 = end;
306  if(end_height)
307  end2.z += end_height;
308 
309  vector fixed_end = end;
310  vector move;
311 
312  if (flatdist > 0 && WETFEET(org))
313  {
314  if (SUBMERGED(org))
315  nav_action = NAV_SWIM_UNDERWATER;
316  else
317  {
318  // tracebox down by player's height
319  // useful to know if water level is so low that bot can still walk
320  tracebox(org, m1, m2, org - eZ * (m2.z - m1.z), movemode, e);
321  if (SUBMERGED(trace_endpos))
322  {
323  org = trace_endpos;
324  nav_action = NAV_SWIM_UNDERWATER;
325  }
326  else
327  nav_action = NAV_WALK;
328  }
329  }
330  else
331  nav_action = NAV_WALK;
332 
333  // Movement loop
334  while (true)
335  {
336  if (flatdist <= 0)
337  {
338  bool success = true;
339  if (org.z > end2.z + 1)
340  {
341  tracebox(org, m1, m2, end2, movemode, e);
342  org = trace_endpos;
343  if (org.z > end2.z + 1)
344  success = false;
345  }
346  else if (org.z < end.z - 1)
347  {
348  tracebox(org, m1, m2, org - jumpheight_vec, movemode, e);
349  if (SUBMERGED(trace_endpos))
350  {
352  tracebox(v, m1, m2, end, movemode, e);
353  if(trace_endpos.z >= end.z - 1)
354  {
356  trace_endpos = v;
357  }
358  }
359  else if (trace_endpos.z > org.z - jumpheight_vec.z)
360  tracebox(trace_endpos, m1, m2, trace_endpos + jumpheight_vec, movemode, e);
361  org = trace_endpos;
362  if (org.z < end.z - 1)
363  success = false;
364  }
365 
366  if (success)
367  {
368  // Succeeded
370  {
371  debugnode(e, org);
373  }
374 
375  //print("tracewalk: ", vtos(start), " can reach ", vtos(end), "\n");
376  return true;
377  }
378  }
379 
381  debugnode(e, org);
382 
383  if (flatdist <= 0)
384  break;
385 
386  if (stepdist > flatdist)
387  stepdist = flatdist;
388  if(nav_action == NAV_SWIM_UNDERWATER || (nav_action == NAV_SWIM_ONWATER && org.z > end2.z))
389  {
390  // can't use movement direction here to calculate move because of
391  // precision errors especially when direction has a high enough z value
392  //water_dir = normalize(water_end - org);
393  //move = org + water_dir * stepdist;
394  fixed_end.z = bound(end.z, org.z, end2.z);
395  if (stepdist == flatdist) {
396  move = fixed_end;
397  flatdist = 0;
398  } else {
399  move = org + (fixed_end - org) * (stepdist / flatdist);
400  flatdist = vlen(vec2(fixed_end - move));
401  }
402  }
403  else // horiz. direction
404  {
405  flatdist -= stepdist;
406  move = org + flatdir * stepdist;
407  }
408 
409  if(nav_action == NAV_SWIM_ONWATER)
410  {
411  tracebox(org, m1, m2, move, movemode, e); // swim
412 
413  // hit something
414  if (trace_fraction < 1)
415  {
416  // stepswim
417  tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
418 
419  if (trace_fraction < 1 || trace_startsolid) // can't jump obstacle out of water
420  {
421  org = trace_endpos;
422  if(navigation_checkladders(e, org, m1, m2, end, end2, movemode))
423  {
425  {
426  debugnode(e, org);
428  }
429 
430  //print("tracewalk: ", vtos(start), " can reach ", vtos(end), "\n");
431  return true;
432  }
433 
436 
437  return false;
438  //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
439  }
440 
441  //succesful stepswim
442 
443  if (flatdist <= 0)
444  {
445  org = trace_endpos;
446  continue;
447  }
448 
449  if (org.z <= move.z) // going horiz.
450  {
451  tracebox(trace_endpos, m1, m2, move, movemode, e);
452  org = trace_endpos;
453  nav_action = NAV_WALK;
454  continue;
455  }
456  }
457 
458  if (org.z <= move.z) // going horiz.
459  {
460  org = trace_endpos;
461  nav_action = NAV_SWIM_ONWATER;
462  }
463  else // going down
464  {
465  org = trace_endpos;
466  if (SUBMERGED(org))
467  nav_action = NAV_SWIM_UNDERWATER;
468  else
469  nav_action = NAV_SWIM_ONWATER;
470  }
471  }
472  else if(nav_action == NAV_SWIM_UNDERWATER)
473  {
474  if (move.z >= org.z) // swimming upwards or horiz.
475  {
476  tracebox(org, m1, m2, move, movemode, e); // swim
477 
478  bool stepswum = false;
479 
480  // hit something
481  if (trace_fraction < 1)
482  {
483  // stepswim
484  vector stepswim_move = move + stepheightvec;
485  if (flatdist > 0 && stepswim_move.z > end2.z + stepheightvec.z) // don't allow stepswim to go higher than destination
486  stepswim_move.z = end2.z;
487 
488  tracebox(org + stepheightvec, m1, m2, stepswim_move, movemode, e);
489 
490  // hit something
491  if (trace_startsolid)
492  {
495 
496  //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
497  return false;
498  }
499 
500  if (trace_fraction < 1)
501  {
502  float org_z_prev = org.z;
503  RESURFACE_LIMITED(org, end2.z);
504  if(org.z == org_z_prev)
505  {
508 
509  //print("tracewalk: ", vtos(start), " can't reach ", vtos(end), "\n");
510  return false;
511  }
512  if(SUBMERGED(org))
513  nav_action = NAV_SWIM_UNDERWATER;
514  else
515  nav_action = NAV_SWIM_ONWATER;
516 
517  // we didn't advance horiz. in this step, flatdist decrease should be reverted
518  // but we can't do it properly right now... apply this workaround instead
519  if (flatdist <= 0)
520  flatdist = 1;
521 
522  continue;
523  }
524 
525  //succesful stepswim
526 
527  if (flatdist <= 0)
528  {
529  org = trace_endpos;
530  continue;
531  }
532 
533  stepswum = true;
534  }
535 
536  if (!WETFEET(trace_endpos))
537  {
538  tracebox(trace_endpos, m1, m2, trace_endpos - eZ * (stepdist + (m2.z - m1.z)), movemode, e);
539  // if stepswum we'll land on the obstacle, avoid the SUBMERGED check
540  if (!stepswum && SUBMERGED(trace_endpos))
541  {
543  org = trace_endpos;
544  nav_action = NAV_SWIM_ONWATER;
545  continue;
546  }
547 
548  // not submerged
549  org = trace_endpos;
550  nav_action = NAV_WALK;
551  continue;
552  }
553 
554  // wetfeet
555  org = trace_endpos;
556  nav_action = NAV_SWIM_UNDERWATER;
557  continue;
558  }
559  else //if (move.z < org.z) // swimming downwards
560  {
561  tracebox(org, m1, m2, move, movemode, e); // swim
562 
563  // hit something
564  if (trace_fraction < 1)
565  {
566  // stepswim
567  tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
568 
569  // hit something
570  if (trace_fraction < 1 || trace_startsolid) // can't jump obstacle out of water
571  {
574 
575  //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
576  return false;
577  }
578 
579  //succesful stepswim
580 
581  if (flatdist <= 0)
582  {
583  org = trace_endpos;
584  continue;
585  }
586 
587  if (trace_endpos.z > org.z && !SUBMERGED(trace_endpos))
588  {
589  // stepswim caused upwards direction
590  tracebox(trace_endpos, m1, m2, trace_endpos - stepheightvec, movemode, e);
591  if (!SUBMERGED(trace_endpos))
592  {
593  org = trace_endpos;
594  nav_action = NAV_WALK;
595  continue;
596  }
597  }
598  }
599 
600  org = trace_endpos;
601  nav_action = NAV_SWIM_UNDERWATER;
602  continue;
603  }
604  }
605  else if(nav_action == NAV_WALK)
606  {
607  // walk
608  tracebox(org, m1, m2, move, movemode, e);
609 
612 
613  // hit something
614  if (trace_fraction < 1)
615  {
616  // check if we can walk over this obstacle, possibly by jumpstepping
617  tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
618  if (trace_fraction < 1 || trace_startsolid)
619  {
620  if (trace_startsolid) // hit ceiling above org
621  {
622  // reduce stepwalk height
623  tracebox(org, m1, m2, org + stepheightvec, movemode, e);
624  tracebox(trace_endpos, m1, m2, move + eZ * (trace_endpos.z - move.z), movemode, e);
625  }
626  else //if (trace_fraction < 1)
627  {
628  tracebox(org + jumpstepheightvec, m1, m2, move + jumpstepheightvec, movemode, e);
629  if (trace_startsolid) // hit ceiling above org
630  {
631  // reduce jumpstepwalk height
632  tracebox(org, m1, m2, org + jumpstepheightvec, movemode, e);
633  tracebox(trace_endpos, m1, m2, move + eZ * (trace_endpos.z - move.z), movemode, e);
634  }
635  }
636 
637  if (trace_fraction < 1)
638  {
639  vector v = trace_endpos;
640  v.z = org.z + jumpheight_vec.z;
641  if(navigation_checkladders(e, v, m1, m2, end, end2, movemode))
642  {
644  {
645  debugnode(e, v);
647  }
648 
649  //print("tracewalk: ", vtos(start), " can reach ", vtos(end), "\n");
650  return true;
651  }
652 
655 
656  traceline( org, move, movemode, e);
657 
658  if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
659  {
660  vector nextmove;
661  move = trace_endpos;
662  while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
663  {
664  nextmove = move + (flatdir * stepdist);
665  traceline( move, nextmove, movemode, e);
666  move = nextmove;
667  }
668  flatdist = vlen(vec2(end - move));
669  }
670  else
671  {
674 
675  //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
676  //te_explosion(trace_endpos);
677  //print(ftos(e.dphitcontentsmask), "\n");
678  return false; // failed
679  }
680  }
681  else
682  move = trace_endpos;
683  }
684  else
685  move = trace_endpos;
686  }
687  else
688  move = trace_endpos;
689 
690  // trace down from stepheight as far as possible and move there,
691  // if this starts in solid we try again without the stepup, and
692  // if that also fails we assume it is a wall
693  // (this is the same logic as the Quake walkmove function used)
694  tracebox(move, m1, m2, move + '0 0 -65536', movemode, e);
695 
696  org = trace_endpos;
697 
698  if (!ignorehazards)
699  {
700  if (IN_LAVA(org))
701  {
703  {
706  }
707 
708  //print("tracewalk: ", vtos(start), " hits a hazard when trying to reach ", vtos(end), "\n");
709  return false;
710  }
711  }
712 
713  if (flatdist <= 0)
714  {
715  if(move.z >= end2.z && org.z < end2.z)
716  org.z = end2.z;
717  continue;
718  }
719 
720  if(org.z > move.z - 1 || !SUBMERGED(org))
721  {
722  nav_action = NAV_WALK;
723  continue;
724  }
725 
726  // ended up submerged while walking
728  debugnode(e, org);
729 
730  RESURFACE_LIMITED(org, move.z);
731  nav_action = NAV_SWIM_ONWATER;
732  continue;
733  }
734  }
735 
736  //print("tracewalk: ", vtos(start), " did not arrive at ", vtos(end), " but at ", vtos(org), "\n");
737 
738  // moved but didn't arrive at the intended destination
741 
742  return false;
743 }
bool autocvar_bot_debug_tracewalk
Definition: cvars.qh:58
#define IN_LAVA(pos)
Definition: bot.qh:83
entity trace_ent
Definition: csprogsdefs.qc:40
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
vector trace_endpos
Definition: csprogsdefs.qc:37
#define WETFEET(pos)
Definition: bot.qh:86
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define SUBMERGED(pos)
Definition: bot.qh:85
vector v
Definition: ent_cs.qc:116
const vector eZ
Definition: vector.qh:46
#define vec2(...)
Definition: vector.qh:90
float trace_startsolid
Definition: csprogsdefs.qc:35
float trace_fraction
Definition: csprogsdefs.qc:36
+ Here is the caller graph for this function:

◆ void()

void ( entity  this)

◆ waypoint_getSymmetricalAxis_cmd()

void waypoint_getSymmetricalAxis_cmd ( entity  caller,
bool  save,
int  arg_idx 
)

Definition at line 137 of file waypoints.qc.

References argv(), cvar_set(), cvar_string(), fabs(), ftos(), sprint(), stov(), strcat(), and vector().

Referenced by ClientCommand_wpeditor().

138 {
139  vector v1 = stov(argv(arg_idx++));
140  vector v2 = stov(argv(arg_idx++));
141  vector mid = (v1 + v2) / 2;
142 
143  float diffy = (v2.y - v1.y);
144  float diffx = (v2.x - v1.x);
145  if (v1.y == v2.y)
146  diffy = 0.000001;
147  if (v1.x == v2.x)
148  diffx = 0.000001;
149  float m = - diffx / diffy;
150  float q = - m * mid.x + mid.y;
151  if (fabs(m) <= 0.000001) m = 0;
152  if (fabs(q) <= 0.000001) q = 0;
153 
154  string axis_str = strcat(ftos(m), " ", ftos(q));
155  if (save)
156  cvar_set("g_waypointeditor_symmetrical_axis", axis_str);
157  axis_str = strcat("\"", axis_str, "\"");
158  sprint(caller, strcat("Axis of symmetry based on input points: ", axis_str, "\n"));
159  if (save)
160  sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_axis"));
161  if (save)
162  {
163  cvar_set("g_waypointeditor_symmetrical", "-2");
164  sprint(caller, strcat("g_waypointeditor_symmetrical", " has been set to ",
165  cvar_string("g_waypointeditor_symmetrical"), "\n"));
166  }
167 }
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
vector(float skel, float bonenum) _skel_get_boneabs_hidden
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ waypoint_getSymmetricalOrigin_cmd()

void waypoint_getSymmetricalOrigin_cmd ( entity  caller,
bool  save,
int  arg_idx 
)

Definition at line 169 of file waypoints.qc.

References argv(), cvar_set(), cvar_string(), fabs(), ftos(), havocbot_middlepoint, havocbot_middlepoint_radius, sprint(), stov(), strcat(), vec2, and vector().

Referenced by ClientCommand_wpeditor().

170 {
171  vector org = '0 0 0';
172  int ctf_flags = 0;
173  for (int i = 0; i < 6; i++)
174  {
175  if (argv(arg_idx + i) != "")
176  ctf_flags++;
177  }
178  if (ctf_flags < 2)
179  {
180  ctf_flags = 0;
181  org = vec2(havocbot_middlepoint);
182  if (argv(arg_idx) != "")
183  sprint(caller, "WARNING: Ignoring single input point\n");
185  {
186  sprint(caller, "Origin of symmetry can't be automatically determined\n");
187  return;
188  }
189  }
190  else
191  {
192  vector v1, v2, v3, v4, v5, v6;
193  for (int i = 1; i <= ctf_flags; i++)
194  {
195  if (i == 1) { v1 = stov(argv(arg_idx++)); org = v1 / ctf_flags; }
196  else if (i == 2) { v2 = stov(argv(arg_idx++)); org += v2 / ctf_flags; }
197  else if (i == 3) { v3 = stov(argv(arg_idx++)); org += v3 / ctf_flags; }
198  else if (i == 4) { v4 = stov(argv(arg_idx++)); org += v4 / ctf_flags; }
199  else if (i == 5) { v5 = stov(argv(arg_idx++)); org += v5 / ctf_flags; }
200  else if (i == 6) { v6 = stov(argv(arg_idx++)); org += v6 / ctf_flags; }
201  }
202  }
203 
204  if (fabs(org.x) <= 0.000001) org.x = 0;
205  if (fabs(org.y) <= 0.000001) org.y = 0;
206  string org_str = strcat(ftos(org.x), " ", ftos(org.y));
207  if (save)
208  {
209  cvar_set("g_waypointeditor_symmetrical_origin", org_str);
210  cvar_set("g_waypointeditor_symmetrical_order", ftos(ctf_flags));
211  }
212  org_str = strcat("\"", org_str, "\"");
213 
214  if (ctf_flags < 2)
215  sprint(caller, strcat("Origin of symmetry based on flag positions: ", org_str, "\n"));
216  else
217  sprint(caller, strcat("Origin of symmetry based on input points: ", org_str, "\n"));
218  if (save)
219  sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_origin"));
220 
221  if (ctf_flags < 2)
222  sprint(caller, "Order of symmetry: 0 (autodetected)\n");
223  else
224  sprint(caller, strcat("Order of symmetry: ", ftos(ctf_flags), "\n"));
225  if (save)
226  sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_order"));
227 
228  if (save)
229  {
230  if (ctf_flags < 2)
231  cvar_set("g_waypointeditor_symmetrical", "0");
232  else
233  cvar_set("g_waypointeditor_symmetrical", "-1");
234  sprint(caller, strcat("g_waypointeditor_symmetrical", " has been set to ",
235  cvar_string("g_waypointeditor_symmetrical"), "\n"));
236  }
237 }
float havocbot_middlepoint_radius
Definition: api.qh:92
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
vector havocbot_middlepoint
Definition: api.qh:91
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define vec2(...)
Definition: vector.qh:90
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ waypoint_lock()

void waypoint_lock ( entity  pl)

Definition at line 268 of file waypoints.qc.

References crosshair_trace_waypoints(), and trace_ent.

Referenced by ClientCommand_wpeditor().

269 {
271  pl.wp_locked = trace_ent;
272 }
entity trace_ent
Definition: csprogsdefs.qc:40
void crosshair_trace_waypoints(entity pl)
Definition: waypoints.qc:2134
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ waypoint_remove()

void waypoint_remove ( entity  wp)

Definition at line 821 of file waypoints.qc.

Referenced by havocbot_moveto().

822 {
823  IL_EACH(g_waypoints, it != wp,
824  {
825  if (it.SUPPORT_WP == wp)
826  {
827  it.SUPPORT_WP = NULL;
828  waypoint_schedulerelink(it); // restore incoming links
829  }
830  if (waypoint_islinked(it, wp))
831  {
832  if (waypoint_is_hardwiredlink(it, wp))
834  waypoint_removelink(it, wp);
835  }
836  });
837  delete(wp);
838 }
#define IL_EACH(this, cond, body)
bool waypoint_islinked(entity from, entity to)
Definition: waypoints.qc:968
void waypoint_unmark_hardwiredlink(entity wp_from, entity wp_to)
Definition: waypoints.qc:316
void waypoint_removelink(entity from, entity to)
Definition: waypoints.qc:907
IntrusiveList g_waypoints
Definition: api.qh:148
bool waypoint_is_hardwiredlink(entity wp_from, entity wp_to)
Definition: waypoints.qc:281
if(IS_DEAD(this))
Definition: impulse.qc:92
+ Here is the caller graph for this function:

◆ waypoint_remove_fromeditor()

void waypoint_remove_fromeditor ( entity  pl)

Definition at line 840 of file waypoints.qc.

Referenced by ClientCommand_wpeditor().

841 {
843  {
844  LOG_INFOF("^1Editing waypoints with a higher version number (%f) is not allowed.\n"
845  "Update Xonotic to make them editable.", waypoint_version_loaded);
846  return;
847  }
848 
849  entity e = navigation_findnearestwaypoint(pl, false);
850 
851  int ctf_flags = havocbot_symmetry_origin_order;
852  bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
856  if (sym && ctf_flags < 2)
857  ctf_flags = 2;
858  int wp_num = ctf_flags;
859 
860  LABEL(remove_wp);
861  if (!e) return;
862 
863  if (e.wpflags & WAYPOINTFLAG_GENERATED)
864  {
867  return;
868  }
869 
871  {
872  LOG_INFO("Can't remove a waypoint with hardwired links, remove links with \"wpeditor hardwire\" first\n");
873  return;
874  }
875 
876  entity wp_sym = NULL;
877  if (sym)
878  {
879  vector org = waypoint_getSymmetricalPoint(e.origin, ctf_flags);
880  FOREACH_ENTITY_CLASS("waypoint", !(it.wpflags & WAYPOINTFLAG_GENERATED), {
881  if(vdist(org - it.origin, <, 3))
882  {
883  wp_sym = it;
884  break;
885  }
886  });
887  }
888 
889  bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
890  te_explosion(e.origin);
891  waypoint_remove(e);
892 
893  if (sym && wp_sym)
894  {
895  e = wp_sym;
896  if(wp_num > 2)
897  wp_num--;
898  else
899  sym = false;
900  goto remove_wp;
901  }
902 
905 }
bool start_wp_is_spawned
Definition: waypoints.qc:518
void waypoint_clear_start_wp_globals(entity pl, bool warn)
Definition: waypoints.qc:523
entity() spawn
vector waypoint_getSymmetricalPoint(vector org, int ctf_flags)
Definition: waypoints.qc:239
#define FOREACH_ENTITY_CLASS(class, cond, body)
Definition: iter.qh:189
float waypoint_version_loaded
Definition: waypoints.qh:16
#define LOG_INFOF(...)
Definition: log.qh:71
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
#define NULL
Definition: post.qh:17
#define LOG_INFO(...)
Definition: log.qh:70
bool waypoint_has_hardwiredlinks(entity wp)
Definition: waypoints.qc:274
vector(float skel, float bonenum) _skel_get_boneabs_hidden
bool autocvar_g_waypointeditor_symmetrical
Definition: waypoints.qh:6
#define LABEL(id)
Definition: compiler.qh:36
const int WAYPOINTFLAG_GENERATED
Definition: api.qh:11
float havocbot_symmetry_origin_order
Definition: api.qh:95
void waypoint_remove(entity wp)
Definition: waypoints.qc:821
int autocvar_g_waypointeditor_symmetrical_order
Definition: waypoints.qh:9
const float WAYPOINT_VERSION
Definition: waypoints.qh:15
entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
Definition: navigation.qc:1011
+ Here is the caller graph for this function:

◆ waypoint_saveall()

void waypoint_saveall ( )

Definition at line 1760 of file waypoints.qc.

Referenced by ClientCommand_wpeditor().

1761 {
1763  {
1764  LOG_INFOF("^1Overwriting waypoints with a higher version number (%f) is not allowed.\n"
1765  "Update Xonotic to make them editable.", waypoint_version_loaded);
1766  return;
1767  }
1768  string gt_ext = GET_GAMETYPE_EXTENSION();
1769 
1770  string filename = sprintf("maps/%s.waypoints", strcat(mapname, gt_ext));
1771  int file = fopen(filename, FILE_WRITE);
1772  if (file < 0)
1773  {
1774  waypoint_save_links(); // save anyway?
1776 
1777  LOG_INFOF("waypoint links: save to %s failed", filename);
1778  return;
1779  }
1780 
1782  string sym_str = ftos(sym);
1783  if (sym == -1 || (sym == 1 && autocvar_g_waypointeditor_symmetrical_order >= 2))
1784  {
1785  if (sym == 1)
1786  {
1787  sym_str = cons(sym_str, "-");
1788  sym_str = cons(sym_str, "-");
1789  }
1790  else
1791  {
1794  }
1797  }
1799  {
1800  sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_axis.x));
1801  sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_axis.y));
1802  }
1803 
1804  // a group of 3 comments doesn't break compatibility with older Xonotic versions
1805  // (they are read as a waypoint with origin '0 0 0' and flag 0 though)
1806  fputs(file, strcat("//", "WAYPOINT_VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n"));
1807  fputs(file, strcat("//", "WAYPOINT_SYMMETRY ", sym_str, "\n"));
1808 
1809  strcpy(waypoint_time, strftime(true, "%Y-%m-%d %H:%M:%S"));
1810  fputs(file, strcat("//", "WAYPOINT_TIME ", waypoint_time, "\n"));
1811  //fputs(file, strcat("//", "\n"));
1812  //fputs(file, strcat("//", "\n"));
1813  //fputs(file, strcat("//", "\n"));
1814 
1815  int c = 0;
1816  IL_EACH(g_waypoints, true,
1817  {
1818  if(it.wpflags & WAYPOINTFLAG_GENERATED)
1819  continue;
1820 
1821  string s;
1822  // NOTE: vtos rounds vector components to 1 decimal place
1823  s = strcat(vtos(it.origin + it.mins), "\n");
1824  s = strcat(s, vtos(it.origin + it.maxs));
1825  s = strcat(s, "\n");
1826  s = strcat(s, ftos(it.wpflags));
1827  s = strcat(s, "\n");
1828  fputs(file, s);
1829  c++;
1830  });
1831  fclose(file);
1834 
1836 
1838  LOG_INFOF("saved %d waypoints to %s", c, filename);
1839 }
#define IL_EACH(this, cond, body)
ERASEABLE string ftos_decimals(float number, int decimals)
converts a number to a string with the indicated number of decimals
Definition: string.qh:450
float botframe_loadedforcedlinks
Definition: waypoints.qh:23
#define strcpy(this, s)
Definition: string.qh:49
string mapname
Definition: csprogsdefs.qc:26
vector autocvar_g_waypointeditor_symmetrical_axis
Definition: waypoints.qh:10
#define GET_GAMETYPE_EXTENSION()
Definition: waypoints.qc:1319
float waypoint_version_loaded
Definition: waypoints.qh:16
#define LOG_INFOF(...)
Definition: log.qh:71
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
void waypoint_save_hardwiredlinks()
Definition: waypoints.qc:1667
string waypoint_time
Definition: waypoints.qh:17
IntrusiveList g_waypoints
Definition: api.qh:148
const float FILE_WRITE
Definition: csprogsdefs.qc:233
bool autocvar_g_waypointeditor_symmetrical
Definition: waypoints.qh:6
void waypoint_save_links()
Definition: waypoints.qc:1721
vector autocvar_g_waypointeditor_symmetrical_origin
Definition: waypoints.qh:8
const int WAYPOINTFLAG_GENERATED
Definition: api.qh:11
ERASEABLE string cons(string a, string b)
Definition: string.qh:257
int autocvar_g_waypointeditor_symmetrical_order
Definition: waypoints.qh:9
const float WAYPOINT_VERSION
Definition: waypoints.qh:15
+ Here is the caller graph for this function:

◆ waypoint_schedulerelink()

void waypoint_schedulerelink ( entity  wp)

Definition at line 1275 of file waypoints.qc.

1276 {
1277  if (wp == NULL)
1278  return;
1279 
1280  waypoint_setupmodel(wp);
1281  wp.wpisbox = vdist(wp.size, >, 0);
1282  wp.enemy = NULL;
1283  if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
1284  wp.owner = NULL;
1285  if (!(wp.wpflags & WPFLAGMASK_NORELINK))
1286  waypoint_clearlinks(wp);
1287  // schedule an actual relink on next frame
1288  setthink(wp, waypoint_think);
1289  wp.nextthink = time;
1290  wp.effects = EF_LOWPRECISION;
1291 }
const int WPFLAGMASK_NORELINK
Definition: api.qh:29
void waypoint_think(entity this)
Definition: waypoints.qc:1149
#define NULL
Definition: post.qh:17
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
void waypoint_clearlinks(entity wp)
Definition: waypoints.qc:1255
#define setthink(e, f)
const int WAYPOINTFLAG_PERSONAL
Definition: api.qh:15
float time
Definition: csprogsdefs.qc:16
float EF_LOWPRECISION
void waypoint_setupmodel(entity wp)
Definition: waypoints.qc:360

◆ waypoint_schedulerelinkall()

void waypoint_schedulerelinkall ( )

Definition at line 1309 of file waypoints.qc.

Referenced by ClientCommand_wpeditor().

1310 {
1312  IL_EACH(g_waypoints, true,
1313  {
1315  });
1317 }
#define IL_EACH(this, cond, body)
float relink_pvsculled
Definition: waypoints.qh:20
float relink_lengthculled
Definition: waypoints.qh:20
void waypoint_load_hardwiredlinks()
Definition: waypoints.qc:1470
void waypoint_schedulerelink(entity wp)
Definition: waypoints.qc:1275
IntrusiveList g_waypoints
Definition: api.qh:148
float relink_total
Definition: waypoints.qh:20
float relink_walkculled
Definition: waypoints.qh:20
+ Here is the caller graph for this function:

◆ waypoint_spawn()

entity waypoint_spawn ( vector  m1,
vector  m2,
float  f 
)

Definition at line 431 of file waypoints.qc.

432 {
433  if(!(f & (WAYPOINTFLAG_PERSONAL | WAYPOINTFLAG_GENERATED)) && m1 == m2)
434  {
435  entity wp_found = waypoint_get(m1, m2);
436  if (wp_found)
437  return wp_found;
438  }
439  // spawn only one destination waypoint for teleports teleporting player to the exact same spot
440  // otherwise links loaded from file would be applied only to the first destination
441  // waypoint since link format doesn't specify waypoint entities but just positions
442  if((f & WAYPOINTFLAG_GENERATED) && !(f & (WPFLAGMASK_NORELINK | WAYPOINTFLAG_PERSONAL)) && m1 == m2)
443  {
444  IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
445  {
446  return it;
447  });
448  }
449 
450  entity w = new(waypoint);
451  IL_PUSH(g_waypoints, w);
453  w.wpflags = f;
454  w.solid = SOLID_TRIGGER;
455  w.createdtime = time;
456  w.origin = (m1 + m2) * 0.5;
458  setorigin(w, w.origin);
459  else // don't link into the world, only bots are aware of waypoints
460  make_pure(w);
461  setsize(w, m1 - w.origin, m2 - w.origin);
462  if (w.size)
463  w.wpisbox = true;
464 
465  if(!w.wpisbox)
466  {
467  if (f & WAYPOINTFLAG_CROUCH)
468  setsize(w, PL_CROUCH_MIN_CONST - '1 1 0', PL_CROUCH_MAX_CONST + '1 1 0');
469  else
470  setsize(w, PL_MIN_CONST - '1 1 0', PL_MAX_CONST + '1 1 0');
471  if(!move_out_of_solid(w))
472  {
473  if(!(f & WAYPOINTFLAG_GENERATED))
474  {
475  LOG_TRACE("Killed a waypoint that was stuck in solid at ", vtos(w.origin));
476  delete(w);
477  return NULL;
478  }
479  else
480  {
481  if(autocvar_developer > 0)
482  {
483  LOG_INFO("A generated waypoint is stuck in solid at ", vtos(w.origin));
484  backtrace("Waypoint stuck");
485  }
486  }
487  }
488  setsize(w, '0 0 0', '0 0 0');
489  }
490 
492  //waypoint_schedulerelink(w);
493 
495 
496  return w;
497 }
const int WAYPOINTFLAG_CROUCH
Definition: api.qh:22
#define IL_EACH(this, cond, body)
entity() spawn
float DPCONTENTS_BOTCLIP
const int WPFLAGMASK_NORELINK
Definition: api.qh:29
float DPCONTENTS_PLAYERCLIP
#define move_out_of_solid(e)
Definition: common.qh:110
bool waypointeditor_enabled
Definition: waypoints.qh:3
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
Definition: vector.qh:73
entity waypoint_get(vector m1, vector m2)
Definition: waypoints.qc:418
#define NULL
Definition: post.qh:17
#define LOG_INFO(...)
Definition: log.qh:70
float DPCONTENTS_SOLID
#define backtrace(msg)
Definition: log.qh:105
#define make_pure(e)
Definition: oo.qh:12
IntrusiveList g_waypoints
Definition: api.qh:148
float DPCONTENTS_BODY
void waypoint_clearlinks(entity wp)
Definition: waypoints.qc:1255
#define LOG_TRACE(...)
Definition: log.qh:81
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
const int WAYPOINTFLAG_GENERATED
Definition: api.qh:11
setorigin(ent, v)
noref int autocvar_developer
Definition: log.qh:102
const int WAYPOINTFLAG_PERSONAL
Definition: api.qh:15
float time
Definition: csprogsdefs.qc:16
void waypoint_setupmodel(entity wp)
Definition: waypoints.qc:360

◆ waypoint_spawn_fromeditor()

void waypoint_spawn_fromeditor ( entity  pl,
bool  at_crosshair,
bool  is_jump_wp,
bool  is_crouch_wp,
bool  is_support_wp 
)

Definition at line 570 of file waypoints.qc.

Referenced by ClientCommand_wpeditor().

571 {
573  {
574  LOG_INFOF("^1Editing waypoints with a higher version number (%f) is not allowed.\n"
575  "Update Xonotic to make them editable.", waypoint_version_loaded);
576  return;
577  }
578 
579  entity e = NULL, jp = NULL;
580  vector org = pl.origin;
581  if (at_crosshair)
582  {
584  org = trace_endpos;
585  if (!trace_ent)
586  org.z -= PL_MIN_CONST.z;
588  IL_EACH(g_jumppads, boxesoverlap(org + PL_MIN_CONST, org + PL_MAX_CONST, it.absmin, it.absmax),
589  {
590  jp = it;
591  break;
592  });
593  if (!jp && !start_wp_is_spawned && trace_ent)
594  {
595  if (trace_ent.wpflags & (WAYPOINTFLAG_JUMP))
596  is_jump_wp = true;
597  else if (trace_ent.wpflags & (WAYPOINTFLAG_SUPPORT))
598  is_support_wp = true;
599  }
600  }
601  if (jp || is_jump_wp || is_support_wp)
602  {
604  start_wp_is_spawned = false;
605  LOG_INFO("^xf80Spawning start waypoint...\n");
606  }
607  int ctf_flags = havocbot_symmetry_origin_order;
608  bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
612  if (sym && ctf_flags < 2)
613  ctf_flags = 2;
614  int wp_num = ctf_flags;
615 
616  if(!PHYS_INPUT_BUTTON_CROUCH(pl) && !at_crosshair && !is_jump_wp && !is_support_wp)
617  {
618  // snap waypoint to item's origin if close enough
619  IL_EACH(g_items, true,
620  {
621  vector item_org = (it.absmin + it.absmax) * 0.5;
622  item_org.z = it.absmin.z - PL_MIN_CONST.z;
623  if (vlen(item_org - org) < 20)
624  {
625  org = item_org;
626  break;
627  }
628  });
629  }
630 
631  vector start_org = '0 0 0';
633  {
635  LOG_INFO("^xf80Spawning destination waypoint...\n");
636  start_org = start_wp_origin;
637  }
638 
639  // save org as it can be modified spawning symmetrycal waypoints
640  vector initial_origin = '0 0 0';
641  bool initial_origin_is_set = false;
642 
643  LABEL(add_wp);
644 
645  if (jp)
646  {
647  e = NULL;
648  IL_EACH(g_waypoints, (it.wpflags & WPFLAGMASK_NORELINK)
649  && boxesoverlap(org + PL_MIN_CONST, org + PL_MAX_CONST, it.absmin, it.absmax),
650  {
651  e = it; break;
652  });
653  if (!e)
654  e = waypoint_spawn(jp.absmin - PL_MAX_CONST + '1 1 1', jp.absmax - PL_MIN_CONST + '-1 -1 -1', WAYPOINTFLAG_TELEPORT);
655  if (!pl.wp_locked)
656  pl.wp_locked = e;
657  }
658  else if (is_jump_wp || is_support_wp)
659  {
660  int type_flag = (is_jump_wp) ? WAYPOINTFLAG_JUMP : WAYPOINTFLAG_SUPPORT;
661 
662  entity wp_found = waypoint_get(org, org);
663  if (wp_found && !(wp_found.wpflags & type_flag))
664  {
665  LOG_INFOF("Error: can't spawn a %s waypoint over an existent waypoint of a different type\n", (is_jump_wp) ? "Jump" : "Support");
666  return;
667  }
668  e = waypoint_spawn(org, org, type_flag);
669  if (!pl.wp_locked)
670  pl.wp_locked = e;
671  }
672  else
673  e = waypoint_spawn(org, org, (is_crouch_wp) ? WAYPOINTFLAG_CROUCH : 0);
674  if(!e)
675  {
676  LOG_INFOF("Couldn't spawn waypoint at %v\n", org);
679  return;
680  }
681 
682  if (!initial_origin_is_set)
683  {
684  initial_origin = e.origin;
685  initial_origin_is_set = true;
686  }
687 
688  entity start_wp = NULL;
690  {
692  && boxesoverlap(start_org, start_org, it.absmin, it.absmax),
693  {
694  start_wp = it; break;
695  });
696  if(!start_wp)
697  {
698  // should not happen
699  LOG_INFOF("Couldn't find start waypoint at %v\n", start_org);
701  return;
702  }
704  {
705  if (waypoint_is_hardwiredlink(start_wp, e))
706  {
707  waypoint_unmark_hardwiredlink(start_wp, e);
708  waypoint_removelink(start_wp, e);
709  string s = strcat(vtos(start_wp.origin), "*", vtos(e.origin));
710  LOG_INFOF("^x80fRemoved hardwired link %s.\n", s);
711  }
712  else
713  {
714  if (e.createdtime == time)
715  {
716  LOG_INFO("Error: hardwired links can be created only between 2 existing (and unconnected) waypoints.\n");
717  waypoint_remove(e);
719  waypoint_spawn_fromeditor(pl, at_crosshair, is_jump_wp, is_crouch_wp, is_support_wp);
720  return;
721  }
722  if (start_wp == e)
723  {
724  LOG_INFO("Error: start and destination waypoints coincide.\n");
726  return;
727  }
728  if (waypoint_islinked(start_wp, e))
729  {
730  LOG_INFO("Error: waypoints are already linked.\n");
732  return;
733  }
734  waypoint_addlink(start_wp, e);
735  waypoint_mark_hardwiredlink(start_wp, e);
736  string s = strcat(vtos(start_wp.origin), "*", vtos(e.origin));
737  LOG_INFOF("^x80fAdded hardwired link %s.\n", s);
738  }
739  }
740  else
741  {
743  {
744  if (e.SUPPORT_WP)
745  {
746  LOG_INFOF("Waypoint %v has already a support waypoint, delete it first.\n", e.origin);
748  return;
749  }
750  // clear all links to e
751  IL_EACH(g_waypoints, it != e,
752  {
753  if (waypoint_islinked(it, e) && !waypoint_is_hardwiredlink(it, e))
754  waypoint_removelink(it, e);
755  });
756  }
757  waypoint_addlink(start_wp, e);
758  }
759  }
760 
761  if (!(jp || is_jump_wp || is_support_wp || start_wp_is_hardwired))
763 
764  string wp_type_str = waypoint_get_type_name(e);
765 
766  bprint(strcat(wp_type_str, "^7 spawned at ", vtos(e.origin), "\n"));
767 
769  {
770  pl.wp_locked = NULL;
772  waypoint_schedulerelink(start_wp);
773  if (start_wp.wpflags & WAYPOINTFLAG_TELEPORT)
774  {
775  if (start_wp.wp00_original == start_wp.wp00)
776  start_wp.wpflags &= ~WAYPOINTFLAG_CUSTOM_JP;
777  else
778  start_wp.wpflags |= WAYPOINTFLAG_CUSTOM_JP;
779  }
780  }
781 
782  if (sym)
783  {
784  org = waypoint_getSymmetricalPoint(org, ctf_flags);
785  if (jp)
786  {
787  IL_EACH(g_jumppads, boxesoverlap(org + PL_MIN_CONST, org + PL_MAX_CONST, it.absmin, it.absmax),
788  {
789  jp = it; break;
790  });
791  }
793  start_org = waypoint_getSymmetricalPoint(start_org, ctf_flags);
794  if (vdist(org - pl.origin, >, 32))
795  {
796  if(wp_num > 2)
797  wp_num--;
798  else
799  sym = false;
800  goto add_wp;
801  }
802  }
803  if (jp || is_jump_wp || is_support_wp)
804  {
805  if (!start_wp_is_spawned)
806  {
807  // we've just created a custom jumppad waypoint
808  // the next one created by the user will be the destination waypoint
809  start_wp_is_spawned = true;
810  start_wp_origin = initial_origin;
811  if (is_support_wp)
812  start_wp_is_support = true;
813  }
814  }
815  else if (start_wp_is_spawned)
816  {
818  }
819 }
const int WAYPOINTFLAG_CROUCH
Definition: api.qh:22
#define IL_EACH(this, cond, body)
#define PHYS_INPUT_BUTTON_CROUCH(s)
Definition: player.qh:150
bool start_wp_is_spawned
Definition: waypoints.qc:518
void waypoint_clear_start_wp_globals(entity pl, bool warn)
Definition: waypoints.qc:523
void waypoint_mark_hardwiredlink(entity wp_from, entity wp_to)
Definition: waypoints.qc:299
bool start_wp_is_support
Definition: waypoints.qc:521
entity() spawn
const int WAYPOINTFLAG_JUMP
Definition: api.qh:20
bool waypoint_islinked(entity from, entity to)
Definition: waypoints.qc:968
vector waypoint_getSymmetricalPoint(vector org, int ctf_flags)
Definition: waypoints.qc:239
const int WPFLAGMASK_NORELINK
Definition: api.qh:29
entity waypoint_spawn(vector m1, vector m2, float f)
Definition: waypoints.qc:431
void waypoint_unmark_hardwiredlink(entity wp_from, entity wp_to)
Definition: waypoints.qc:316
entity trace_ent
Definition: csprogsdefs.qc:40
IntrusiveList g_jumppads
Definition: jumppads.qh:7
bool start_wp_is_hardwired
Definition: waypoints.qc:520
void waypoint_removelink(entity from, entity to)
Definition: waypoints.qc:907
float waypoint_version_loaded
Definition: waypoints.qh:16
#define LOG_INFOF(...)
Definition: log.qh:71
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
Definition: vector.qh:73
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
IntrusiveList g_items
Definition: items.qh:126
entity waypoint_get(vector m1, vector m2)
Definition: waypoints.qc:418
void waypoint_schedulerelink(entity wp)
Definition: waypoints.qc:1275
#define NULL
Definition: post.qh:17
#define LOG_INFO(...)
Definition: log.qh:70
vector start_wp_origin
Definition: waypoints.qc:519
vector trace_endpos
Definition: csprogsdefs.qc:37
IntrusiveList g_waypoints
Definition: api.qh:148
vector(float skel, float bonenum) _skel_get_boneabs_hidden
void waypoint_addlink(entity from, entity to)
Definition: waypoints.qc:1135
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
bool autocvar_g_waypointeditor_symmetrical
Definition: waypoints.qh:6
bool waypoint_is_hardwiredlink(entity wp_from, entity wp_to)
Definition: waypoints.qc:281
#define LABEL(id)
Definition: compiler.qh:36
void crosshair_trace_waypoints(entity pl)
Definition: waypoints.qc:2134
float havocbot_symmetry_origin_order
Definition: api.qh:95
void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp)
Definition: waypoints.qc:570
void waypoint_remove(entity wp)
Definition: waypoints.qc:821
float time
Definition: csprogsdefs.qc:16
const int WAYPOINTFLAG_CUSTOM_JP
Definition: api.qh:21
int autocvar_g_waypointeditor_symmetrical_order
Definition: waypoints.qh:9
const float WAYPOINT_VERSION
Definition: waypoints.qh:15
string waypoint_get_type_name(entity wp)
Definition: waypoints.qc:395
const int WAYPOINTFLAG_SUPPORT
Definition: api.qh:23
+ Here is the caller graph for this function:

◆ waypoint_spawnforitem()

void waypoint_spawnforitem ( entity  e)

Definition at line 2007 of file waypoints.qc.

Referenced by _StartItem(), and dom_controlpoint_setup().

2008 {
2010  return;
2011 
2012  waypoint_spawnforitem_force(e, e.origin);
2013 }
bool bot_waypoints_for_items
Definition: api.qh:9
void waypoint_spawnforitem_force(entity e, vector org)
Definition: waypoints.qc:1978
+ Here is the caller graph for this function:

◆ waypoint_spawnforitem_force()

void waypoint_spawnforitem_force ( entity  e,
vector  org 
)

Definition at line 1978 of file waypoints.qc.

Referenced by ctf_DelayedFlagSetup(), ons_DelayedGeneratorSetup(), spawnfunc(), and target_checkpoint_setup().

1979 {
1980  // Fix the waypoint altitude if necessary
1981  org = waypoint_fixorigin(org, NULL);
1982 
1983  // don't spawn an item spawnfunc_waypoint if it already exists
1984  IL_EACH(g_waypoints, true,
1985  {
1986  if(it.wpisbox)
1987  {
1988  if(boxesoverlap(org, org, it.absmin, it.absmax))
1989  {
1990  e.nearestwaypoint = it;
1991  return;
1992  }
1993  }
1994  else
1995  {
1996  if(vdist(it.origin - org, <, 16))
1997  {
1998  e.nearestwaypoint = it;
1999  return;
2000  }
2001  }
2002  });
2003 
2004  e.nearestwaypoint = waypoint_spawn(org, org, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_ITEM);
2005 }
#define IL_EACH(this, cond, body)
#define waypoint_fixorigin(position, tracetest_ent)
Definition: waypoints.qc:1962
entity waypoint_spawn(vector m1, vector m2, float f)
Definition: waypoints.qc:431
#define NULL
Definition: post.qh:17
IntrusiveList g_waypoints
Definition: api.qh:148
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
const int WAYPOINTFLAG_GENERATED
Definition: api.qh:11
const int WAYPOINTFLAG_ITEM
Definition: api.qh:12
+ Here is the caller graph for this function:

◆ waypoint_spawnforteleporter()

void waypoint_spawnforteleporter ( entity  e,
vector  destination,
float  timetaken,
entity  tracetest_ent 
)

Definition at line 2069 of file waypoints.qc.

Referenced by teleport_findtarget(), and trigger_push_test().

2070 {
2071  destination = waypoint_fixorigin(destination, tracetest_ent);
2072  waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, e.absmin - PL_MAX_CONST + '1 1 1', e.absmax - PL_MIN_CONST + '-1 -1 -1', destination, destination, timetaken);
2073 }
#define waypoint_fixorigin(position, tracetest_ent)
Definition: waypoints.qc:1962
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1, vector org2, vector destination1, vector destination2, float timetaken)
Definition: waypoints.qc:2015
+ Here is the caller graph for this function:

◆ waypoint_spawnforteleporter_wz()

void waypoint_spawnforteleporter_wz ( entity  e,
entity  tracetest_ent 
)

Definition at line 2031 of file waypoints.qc.

Referenced by WarpZone_PostInitialize_Callback().

2032 {
2033  float src_angle = e.warpzone_angles.x;
2034  while (src_angle < -180) src_angle += 360;
2035  while (src_angle > 180) src_angle -= 360;
2036 
2037  float dest_angle = e.enemy.warpzone_angles.x;
2038  while (dest_angle < -180) dest_angle += 360;
2039  while (dest_angle > 180) dest_angle -= 360;
2040 
2041  // no waypoints for warpzones pointing upwards, they can't be used by the bots
2042  if (src_angle == -90 || dest_angle == -90)
2043  return;
2044 
2045  makevectors(e.warpzone_angles);
2046  vector src = (e.absmin + e.absmax) * 0.5;
2047  src += ((e.warpzone_origin - src) * v_forward) * v_forward + 16 * v_right;
2048  vector down_dir_src = -v_up;
2049 
2050  makevectors(e.enemy.warpzone_angles);
2051  vector dest = (e.enemy.absmin + e.enemy.absmax) * 0.5;
2052  dest += ((e.enemy.warpzone_origin - dest) * v_forward) * v_forward - 16 * v_right;
2053  vector down_dir_dest = -v_up;
2054 
2055  int extra_flag = 0;
2056  // don't snap to the ground waypoints for source warpzones pointing downwards
2057  if (src_angle != 90)
2058  {
2059  src = waypoint_fixorigin_down_dir(src, tracetest_ent, down_dir_src);
2060  dest = waypoint_fixorigin_down_dir(dest, tracetest_ent, down_dir_dest);
2061  // oblique warpzones need a jump otherwise bots gets stuck
2062  if (src_angle != 0)
2063  extra_flag = WAYPOINTFLAG_JUMP;
2064  }
2065 
2066  waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT | extra_flag, src, src, dest, dest, 0);
2067 }
vector waypoint_fixorigin_down_dir(vector position, entity tracetest_ent, vector down_dir)
Definition: waypoints.qc:1965
vector dest
Definition: jumppads.qh:41
const int WAYPOINTFLAG_JUMP
Definition: api.qh:20
vector v_up
Definition: csprogsdefs.qc:31
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
vector(float skel, float bonenum) _skel_get_boneabs_hidden
vector v_right
Definition: csprogsdefs.qc:31
void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1, vector org2, vector destination1, vector destination2, float timetaken)
Definition: waypoints.qc:2015
#define makevectors
Definition: post.qh:21
vector v_forward
Definition: csprogsdefs.qc:31
+ Here is the caller graph for this function:

◆ waypoint_start_hardwiredlink()

void waypoint_start_hardwiredlink ( entity  pl,
bool  at_crosshair 
)

Definition at line 534 of file waypoints.qc.

References crosshair_trace_waypoints(), entity(), err, LOG_INFO, LOG_INFOF, start_wp_is_hardwired, start_wp_is_spawned, start_wp_origin, trace_ent, vtos(), and WPFLAGMASK_NORELINK.

Referenced by ClientCommand_wpeditor().

535 {
536  entity wp = pl.nearestwaypoint;
537  if (at_crosshair)
538  {
540  wp = trace_ent;
541  }
542  string err = "";
544  err = "can't hardwire while in the process of creating a special link";
545  else if (!wp)
546  {
547  if (at_crosshair)
548  err = "couldn't find any waypoint at crosshair";
549  else
550  err = "couldn't find any waypoint nearby";
551  }
552  else if (wp.wpflags & WPFLAGMASK_NORELINK)
553  err = "can't hardwire a waypoint with special links";
554 
555  if (err == "")
556  {
557  start_wp_is_hardwired = true;
558  start_wp_is_spawned = true;
559  start_wp_origin = wp.origin;
560  pl.wp_locked = wp;
561  LOG_INFOF("^x80fWaypoint %s marked as hardwired link origin.\n", vtos(wp.origin));
562  }
563  else
564  {
565  start_wp_is_hardwired = false;
566  LOG_INFO("Error: ", err, "\n");
567  }
568 }
bool start_wp_is_spawned
Definition: waypoints.qc:518
entity() spawn
entity err
Definition: promise.qc:44
const int WPFLAGMASK_NORELINK
Definition: api.qh:29
entity trace_ent
Definition: csprogsdefs.qc:40
bool start_wp_is_hardwired
Definition: waypoints.qc:520
#define LOG_INFOF(...)
Definition: log.qh:71
#define LOG_INFO(...)
Definition: log.qh:70
vector start_wp_origin
Definition: waypoints.qc:519
void crosshair_trace_waypoints(entity pl)
Definition: waypoints.qc:2134
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ waypoint_unreachable()

void waypoint_unreachable ( entity  pl)

Definition at line 28 of file waypoints.qc.

Referenced by ClientCommand_wpeditor().

29 {
30  IL_EACH(g_waypoints, true,
31  {
32  it.colormod = '0.5 0.5 0.5';
33  it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
34  });
35 
36  entity e2 = navigation_findnearestwaypoint(pl, false);
37  if(!e2)
38  {
39  LOG_INFO("Can't find any waypoint nearby\n");
40  return;
41  }
42 
43  navigation_markroutes(pl, e2);
44 
45  int j = 0;
46  int m = 0;
47  IL_EACH(g_waypoints, it.wpcost >= 10000000,
48  {
49  LOG_INFO("unreachable: ", etos(it), " ", vtos(it.origin), "\n");
50  it.colormod_z = 8;
51  it.effects |= EF_NODEPTHTEST | EF_BLUE;
52  j++;
53  m++;
54  });
55  if (j) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", j);
57 
58  j = 0;
59  IL_EACH(g_waypoints, it.wpcost >= 10000000,
60  {
61  LOG_INFO("cannot reach me: ", etos(it), " ", vtos(it.origin), "\n");
62  it.colormod_x = 8;
63  if (!(it.effects & EF_NODEPTHTEST)) // not already reported before
64  m++;
65  it.effects |= EF_NODEPTHTEST | EF_RED;
66  j++;
67  });
68  if (j) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", j);
69  if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
70 
71  j = 0;
72  IL_EACH(g_spawnpoints, true,
73  {
74  if (navigation_findnearestwaypoint(it, false))
75  {
76  if(it.spawnpointmodel)
77  {
78  delete(it.spawnpointmodel);
79  it.spawnpointmodel = NULL;
80  }
81  }
82  else
83  {
84  if(!it.spawnpointmodel)
85  {
86  tracebox(it.origin, PL_MIN_CONST, PL_MAX_CONST, it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
87  entity e = new(spawnpointmodel);
88  vector org = trace_endpos + eZ;
89  setorigin(e, org);
90  e.solid = SOLID_TRIGGER;
91  it.spawnpointmodel = e;
92  }
93  LOG_INFO("spawn without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
94  it.spawnpointmodel.effects |= EF_NODEPTHTEST;
95  _setmodel(it.spawnpointmodel, pl.model);
96  it.spawnpointmodel.frame = ANIM_idle.m_id;
97  it.spawnpointmodel.skin = pl.skin;
98  it.spawnpointmodel.colormap = 1024 + 68;
99  it.spawnpointmodel.glowmod = '1 0 0';
100  it.spawnpointmodel.angles = it.angles;
101  setsize(it.spawnpointmodel, PL_MIN_CONST, PL_MAX_CONST);
102  j++;
103  }
104  });
105  if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", j);
106 
107  j = 0;
108  IL_EACH(g_items, true,
109  {
110  it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
111  it.colormod = '0.5 0.5 0.5';
112  });
113  IL_EACH(g_items, true,
114  {
115  if (navigation_findnearestwaypoint(it, false))
116  continue;
117  LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
118  it.effects |= EF_NODEPTHTEST | EF_RED;
119  it.colormod_x = 8;
120  j++;
121  });
122  if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", j);
123 
124  j = 0;
125  IL_EACH(g_items, true,
126  {
127  if (navigation_findnearestwaypoint(it, true))
128  continue;
129  LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
130  it.effects |= EF_NODEPTHTEST | EF_BLUE;
131  it.colormod_z = 8;
132  j++;
133  });
134  if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
135 }
#define IL_EACH(this, cond, body)
void navigation_markroutes_inverted(entity fixed_source_waypoint)
Definition: navigation.qc:1171
entity() spawn
void navigation_markroutes(entity this, entity fixed_source_waypoint)
Definition: navigation.qc:1081
const float EF_NODEPTHTEST
Definition: csprogsdefs.qc:304
#define LOG_INFOF(...)
Definition: log.qh:71
const float EF_BLUE
Definition: csprogsdefs.qc:301
IntrusiveList g_items
Definition: items.qh:126
#define LOG_INFO(...)
Definition: log.qh:70
IntrusiveList g_waypoints
Definition: api.qh:148
const float EF_RED
Definition: csprogsdefs.qc:307
IntrusiveList g_spawnpoints
Definition: spawnpoints.qh:32
entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
Definition: navigation.qc:1011
+ Here is the caller graph for this function:

Variable Documentation

◆ autocvar_g_waypoints_for_items

bool autocvar_g_waypoints_for_items

Definition at line 8 of file api.qh.

Referenced by spawnfunc().

◆ bot_attack

◆ bot_basewaypoint

entity bot_basewaypoint

◆ bot_custom_weapon

float bot_custom_weapon

Definition at line 31 of file api.qh.

Referenced by bot_custom_weapon_priority_setup(), and havocbot_chooseweapon().

◆ bot_dodge

float bot_dodge

Definition at line 40 of file api.qh.

Referenced by havocbot_dodge().

◆ bot_dodgerating

float bot_dodgerating

Definition at line 39 of file api.qh.

◆ bot_forced_team

float bot_forced_team

Definition at line 41 of file api.qh.

Referenced by bot_clientconnect(), and bot_setnameandstuff().

◆ bot_moveskill

float bot_moveskill

Definition at line 42 of file api.qh.

Referenced by bot_setnameandstuff(), havocbot_keyboard_movement(), and havocbot_movetogoal().

◆ bot_pickup

float bot_pickup

Definition at line 43 of file api.qh.

Referenced by _StartItem(), buff_Init(), and func_ladder_think().

◆ bot_tracewalk_time

float bot_tracewalk_time

Definition at line 37 of file api.qh.

Referenced by havocbot_movetogoal(), and navigation_shortenpath().

◆ bot_waypoints_for_items

bool bot_waypoints_for_items

Definition at line 9 of file api.qh.

Referenced by spawnfunc(), and waypoint_spawnforitem().

◆ bot_weapons_close

float bot_weapons_close[REGISTRY_MAX(Weapons)]

Definition at line 32 of file api.qh.

Referenced by havocbot_chooseweapon().

◆ bot_weapons_far

float bot_weapons_far[REGISTRY_MAX(Weapons)]

Definition at line 33 of file api.qh.

Referenced by havocbot_chooseweapon().

◆ bot_weapons_mid

float bot_weapons_mid[REGISTRY_MAX(Weapons)]

Definition at line 34 of file api.qh.

Referenced by havocbot_chooseweapon().

◆ bots_would_leave

bool bots_would_leave

Definition at line 101 of file api.qh.

Referenced by bot_fixcount(), and TeamBalance_CompareTeamsInternal().

◆ cleanname

string cleanname

Definition at line 45 of file api.qh.

Referenced by bot_clientdisconnect(), and bot_setnameandstuff().

◆ currentbots

◆ g_bot_dodge

◆ g_bot_targets

◆ g_waypoints

◆ goalentity_lock_timeout

◆ havocbot_middlepoint

◆ havocbot_middlepoint_radius

◆ havocbot_role_timeout

◆ havocbot_symmetry_axis_m

float havocbot_symmetry_axis_m

Definition at line 93 of file api.qh.

Referenced by havocbot_ctf_calculate_middlepoint(), and waypoint_getSymmetricalPoint().

◆ havocbot_symmetry_axis_q

float havocbot_symmetry_axis_q

Definition at line 94 of file api.qh.

Referenced by havocbot_ctf_calculate_middlepoint(), and waypoint_getSymmetricalPoint().

◆ havocbot_symmetry_origin_order

float havocbot_symmetry_origin_order

◆ ignoregoal

◆ ignoregoaltime

◆ isbot

float isbot

Definition at line 49 of file api.qh.

Referenced by bot_clientconnect().

◆ lastteleport_origin

vector lastteleport_origin

Definition at line 51 of file api.qh.

◆ lastteleporttime

float lastteleporttime

◆ navigation_dynamicgoal

bool navigation_dynamicgoal

Definition at line 107 of file api.qh.

Referenced by navigation_dynamicgoal_init().

◆ navigation_hasgoals

float navigation_hasgoals

Definition at line 52 of file api.qh.

◆ nearestwaypoint

◆ nearestwaypointtimeout

◆ player_count

◆ skill

◆ speed

float speed

Definition at line 55 of file api.qh.

◆ WAYPOINTFLAG_CROUCH

◆ WAYPOINTFLAG_CUSTOM_JP

◆ WAYPOINTFLAG_DEAD_END

const int WAYPOINTFLAG_DEAD_END = BIT(16)

Definition at line 18 of file api.qh.

Referenced by botframe_deleteuselesswaypoints().

◆ WAYPOINTFLAG_GENERATED

◆ WAYPOINTFLAG_ITEM

◆ WAYPOINTFLAG_JUMP

◆ WAYPOINTFLAG_LADDER

const int WAYPOINTFLAG_LADDER = BIT(15)

◆ WAYPOINTFLAG_NORELINK__DEPRECATED

const int WAYPOINTFLAG_NORELINK__DEPRECATED = BIT(20)

Definition at line 28 of file api.qh.

Referenced by waypoint_loadall().

◆ WAYPOINTFLAG_PERSONAL

◆ WAYPOINTFLAG_PROTECTED

const int WAYPOINTFLAG_PROTECTED = BIT(18)

◆ WAYPOINTFLAG_SUPPORT

◆ WAYPOINTFLAG_TELEPORT

◆ WAYPOINTFLAG_USEFUL

const int WAYPOINTFLAG_USEFUL = BIT(17)

Definition at line 17 of file api.qh.

Referenced by botframe_deleteuselesswaypoints().

◆ wp00

entity wp00

Definition at line 56 of file api.qh.

Referenced by vehicles_gib_explode(), vehicles_return(), and vehicles_showwp().

◆ wp00mincost

float wp00mincost

Definition at line 58 of file api.qh.

◆ wp01

entity wp01

Definition at line 56 of file api.qh.

◆ wp01mincost

float wp01mincost

Definition at line 58 of file api.qh.

◆ wp02

entity wp02

Definition at line 56 of file api.qh.

◆ wp02mincost

float wp02mincost

Definition at line 58 of file api.qh.

◆ wp03

entity wp03

Definition at line 56 of file api.qh.

◆ wp03mincost

float wp03mincost

Definition at line 58 of file api.qh.

◆ wp04

entity wp04

Definition at line 56 of file api.qh.

◆ wp04mincost

float wp04mincost

Definition at line 58 of file api.qh.

◆ wp05

entity wp05

Definition at line 56 of file api.qh.

◆ wp05mincost

float wp05mincost

Definition at line 58 of file api.qh.

◆ wp06

entity wp06

Definition at line 56 of file api.qh.

◆ wp06mincost

float wp06mincost

Definition at line 58 of file api.qh.

◆ wp07

entity wp07

Definition at line 56 of file api.qh.

◆ wp07mincost

float wp07mincost

Definition at line 58 of file api.qh.

◆ wp08

entity wp08

Definition at line 56 of file api.qh.

◆ wp08mincost

float wp08mincost

Definition at line 59 of file api.qh.

◆ wp09

entity wp09

Definition at line 56 of file api.qh.

◆ wp09mincost

float wp09mincost

Definition at line 59 of file api.qh.

◆ wp10

entity wp10

Definition at line 56 of file api.qh.

◆ wp10mincost

float wp10mincost

Definition at line 59 of file api.qh.

◆ wp11

entity wp11

Definition at line 56 of file api.qh.

◆ wp11mincost

float wp11mincost

Definition at line 59 of file api.qh.

◆ wp12

entity wp12

Definition at line 56 of file api.qh.

◆ wp12mincost

float wp12mincost

Definition at line 59 of file api.qh.

◆ wp13

entity wp13

Definition at line 56 of file api.qh.

◆ wp13mincost

float wp13mincost

Definition at line 59 of file api.qh.

◆ wp14

entity wp14

Definition at line 56 of file api.qh.

◆ wp14mincost

float wp14mincost

Definition at line 59 of file api.qh.

◆ wp15

entity wp15

Definition at line 56 of file api.qh.

◆ wp15mincost

float wp15mincost

Definition at line 59 of file api.qh.

◆ wp16

entity wp16

Definition at line 57 of file api.qh.

◆ wp16mincost

float wp16mincost

Definition at line 60 of file api.qh.

◆ wp17

entity wp17

Definition at line 57 of file api.qh.

◆ wp17mincost

float wp17mincost

Definition at line 60 of file api.qh.

◆ wp18

entity wp18

Definition at line 57 of file api.qh.

◆ wp18mincost

float wp18mincost

Definition at line 60 of file api.qh.

◆ wp19

entity wp19

Definition at line 57 of file api.qh.

◆ wp19mincost

float wp19mincost

Definition at line 60 of file api.qh.

◆ wp20

entity wp20

Definition at line 57 of file api.qh.

◆ wp20mincost

float wp20mincost

Definition at line 60 of file api.qh.

◆ wp21

entity wp21

Definition at line 57 of file api.qh.

◆ wp21mincost

float wp21mincost

Definition at line 60 of file api.qh.

◆ wp22

entity wp22

Definition at line 57 of file api.qh.

◆ wp22mincost

float wp22mincost

Definition at line 60 of file api.qh.

◆ wp23

entity wp23

Definition at line 57 of file api.qh.

◆ wp23mincost

float wp23mincost

Definition at line 60 of file api.qh.

◆ wp24

entity wp24

Definition at line 57 of file api.qh.

◆ wp24mincost

float wp24mincost

Definition at line 61 of file api.qh.

◆ wp25

entity wp25

Definition at line 57 of file api.qh.

◆ wp25mincost

float wp25mincost

Definition at line 61 of file api.qh.

◆ wp26

entity wp26

Definition at line 57 of file api.qh.

◆ wp26mincost

float wp26mincost

Definition at line 61 of file api.qh.

◆ wp27

entity wp27

Definition at line 57 of file api.qh.

◆ wp27mincost

float wp27mincost

Definition at line 61 of file api.qh.

◆ wp28

entity wp28

Definition at line 57 of file api.qh.

◆ wp28mincost

float wp28mincost

Definition at line 61 of file api.qh.

◆ wp29

entity wp29

Definition at line 57 of file api.qh.

◆ wp29mincost

float wp29mincost

Definition at line 61 of file api.qh.

◆ wp30

entity wp30

Definition at line 57 of file api.qh.

◆ wp30mincost

float wp30mincost

Definition at line 61 of file api.qh.

◆ wp31

entity wp31

Definition at line 57 of file api.qh.

◆ wp31mincost

float wp31mincost

Definition at line 61 of file api.qh.

◆ wpconsidered

float wpconsidered

Definition at line 62 of file api.qh.

◆ wpcost

float wpcost

Definition at line 63 of file api.qh.

◆ WPFLAGMASK_NORELINK

◆ wpflags

int wpflags

Definition at line 64 of file api.qh.

Referenced by waypoint_think().

◆ wphw00

entity wphw00

Definition at line 65 of file api.qh.

◆ wphw01

entity wphw01

Definition at line 65 of file api.qh.

◆ wphw02

entity wphw02

Definition at line 65 of file api.qh.

◆ wphw03

entity wphw03

Definition at line 65 of file api.qh.

◆ wphw04

entity wphw04

Definition at line 65 of file api.qh.

◆ wphw05

entity wphw05

Definition at line 65 of file api.qh.

◆ wphw06

entity wphw06

Definition at line 65 of file api.qh.

◆ wphw07

entity wphw07

Definition at line 65 of file api.qh.