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

Go to the source code of this file.

Macros

#define MAX_CHASE_DISTANCE   700
 
#define NAV_SWIM_ONWATER   1
 
#define NAV_SWIM_UNDERWATER   2
 
#define NAV_WALK   0
 
#define RESURFACE_LIMITED(org, lim)   org = resurface_limited(org, lim, m1)
 

Functions

void botframe_updatedangerousobjects (float maxupdate)
 
void debuggoalstack (entity this)
 
void debugnode (entity this, vector node)
 
void debugnodestatus (vector position, float status)
 
void debugresetnodes ()
 
vector get_closer_dest (entity ent, vector org)
 
bool navigation_check_submerged_state (entity ent, vector pos)
 
bool navigation_checkladders (entity e, vector org, vector m1, vector m2, vector end, vector end2, int movemode)
 
void navigation_clearroute (entity this)
 
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)
 
entity navigation_findnearestwaypoint_withdist_except (entity ent, float walkfromwp, float bestdist, entity except)
 
entity navigation_get_really_close_waypoint (entity this)
 
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)
 
ERASEABLE 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_checkwaypoint (entity w, entity wp, float cost, vector p)
 
void navigation_markroutes_inverted (entity fixed_source_waypoint)
 
float navigation_markroutes_nearestwaypoints (entity this, float maxdist)
 
void navigation_poproute (entity this)
 
int navigation_poptouchedgoals (entity this)
 
void navigation_pushroute (entity this, entity e)
 
void navigation_routerating (entity this, entity e, float f, float rangebias)
 
bool navigation_routetogoal (entity this, entity e, vector startposition)
 
bool navigation_shortenpath (entity this)
 
void navigation_unstuck (entity this)
 
float navigation_waypoint_will_link (vector v, vector org, entity ent, vector v2, float v2_height, vector o2, float o2_height, float walkfromwp, float bestdist)
 
vector resurface_limited (vector org, float lim, vector m1)
 
void set_tracewalk_dest (entity ent, vector org, bool fix_player_dest)
 
vector set_tracewalk_dest_2 (entity ent, vector org)
 
bool tracewalk (entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
 

Variables

float goalcounter
 
vector lastposition
 
float speed
 

Macro Definition Documentation

◆ MAX_CHASE_DISTANCE

#define MAX_CHASE_DISTANCE   700

Definition at line 54 of file navigation.qc.

Referenced by navigation_routetogoal(), and navigation_shortenpath().

◆ NAV_SWIM_ONWATER

#define NAV_SWIM_ONWATER   1

Definition at line 266 of file navigation.qc.

Referenced by tracewalk().

◆ NAV_SWIM_UNDERWATER

#define NAV_SWIM_UNDERWATER   2

Definition at line 267 of file navigation.qc.

Referenced by tracewalk().

◆ NAV_WALK

#define NAV_WALK   0

Definition at line 265 of file navigation.qc.

Referenced by tracewalk().

◆ RESURFACE_LIMITED

#define RESURFACE_LIMITED (   org,
  lim 
)    org = resurface_limited(org, lim, m1)

Definition at line 263 of file navigation.qc.

Referenced by tracewalk().

Function Documentation

◆ botframe_updatedangerousobjects()

void botframe_updatedangerousobjects ( float  maxupdate)

Definition at line 1873 of file navigation.qc.

References entity(), g_bot_dodge, g_waypoints, IL_EACH, v, and vector().

Referenced by bot_serverframe().

1874 {
1875  vector m1, m2, v, o;
1876  float c, d, danger;
1877  c = 0;
1878  entity wp_cur;
1879  IL_EACH(g_waypoints, true,
1880  {
1881  danger = 0;
1882  m1 = it.absmin;
1883  m2 = it.absmax;
1884  wp_cur = it;
1885  IL_EACH(g_bot_dodge, it.bot_dodge,
1886  {
1887  v = it.origin;
1888  v.x = bound(m1_x, v.x, m2_x);
1889  v.y = bound(m1_y, v.y, m2_y);
1890  v.z = bound(m1_z, v.z, m2_z);
1891  o = (it.absmin + it.absmax) * 0.5;
1892  d = waypoint_getlinearcost(it.bot_dodgerating) - waypoint_gettravelcost(o, v, it, wp_cur);
1893  if (d > 0)
1894  {
1895  traceline(o, v, true, NULL);
1896  if (trace_fraction == 1)
1897  danger = danger + d;
1898  }
1899  });
1900  it.dmg = danger;
1901  c = c + 1;
1902  if (c >= maxupdate)
1903  break;
1904  });
1905 }
#define IL_EACH(this, cond, body)
entity() spawn
IntrusiveList g_bot_dodge
Definition: api.qh:150
IntrusiveList g_waypoints
Definition: api.qh:148
vector(float skel, float bonenum) _skel_get_boneabs_hidden
vector v
Definition: ent_cs.qc:116
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ debuggoalstack()

void debuggoalstack ( entity  this)

Definition at line 2061 of file navigation.qc.

References entity(), goalcounter, goalcurrent, goalstack01, goalstack02, goalstack03, goalstack04, goalstack05, goalstack06, goalstack07, goalstack08, goalstack09, goalstack10, goalstack11, goalstack12, goalstack13, goalstack14, goalstack15, goalstack16, goalstack17, goalstack18, goalstack19, goalstack20, goalstack21, goalstack22, goalstack23, goalstack24, goalstack25, goalstack26, goalstack27, goalstack28, goalstack29, goalstack30, goalstack31, lastposition, NULL, origin, and vector().

Referenced by havocbot_moveto(), and havocbot_movetogoal().

2062 {
2063  entity goal;
2064  vector org, go;
2065 
2066  if(this.goalcounter==0)goal=this.goalcurrent;
2067  else if(this.goalcounter==1)goal=this.goalstack01;
2068  else if(this.goalcounter==2)goal=this.goalstack02;
2069  else if(this.goalcounter==3)goal=this.goalstack03;
2070  else if(this.goalcounter==4)goal=this.goalstack04;
2071  else if(this.goalcounter==5)goal=this.goalstack05;
2072  else if(this.goalcounter==6)goal=this.goalstack06;
2073  else if(this.goalcounter==7)goal=this.goalstack07;
2074  else if(this.goalcounter==8)goal=this.goalstack08;
2075  else if(this.goalcounter==9)goal=this.goalstack09;
2076  else if(this.goalcounter==10)goal=this.goalstack10;
2077  else if(this.goalcounter==11)goal=this.goalstack11;
2078  else if(this.goalcounter==12)goal=this.goalstack12;
2079  else if(this.goalcounter==13)goal=this.goalstack13;
2080  else if(this.goalcounter==14)goal=this.goalstack14;
2081  else if(this.goalcounter==15)goal=this.goalstack15;
2082  else if(this.goalcounter==16)goal=this.goalstack16;
2083  else if(this.goalcounter==17)goal=this.goalstack17;
2084  else if(this.goalcounter==18)goal=this.goalstack18;
2085  else if(this.goalcounter==19)goal=this.goalstack19;
2086  else if(this.goalcounter==20)goal=this.goalstack20;
2087  else if(this.goalcounter==21)goal=this.goalstack21;
2088  else if(this.goalcounter==22)goal=this.goalstack22;
2089  else if(this.goalcounter==23)goal=this.goalstack23;
2090  else if(this.goalcounter==24)goal=this.goalstack24;
2091  else if(this.goalcounter==25)goal=this.goalstack25;
2092  else if(this.goalcounter==26)goal=this.goalstack26;
2093  else if(this.goalcounter==27)goal=this.goalstack27;
2094  else if(this.goalcounter==28)goal=this.goalstack28;
2095  else if(this.goalcounter==29)goal=this.goalstack29;
2096  else if(this.goalcounter==30)goal=this.goalstack30;
2097  else if(this.goalcounter==31)goal=this.goalstack31;
2098  else goal=NULL;
2099 
2100  if(goal==NULL)
2101  {
2102  this.goalcounter = 0;
2103  this.lastposition='0 0 0';
2104  return;
2105  }
2106 
2107  if(this.lastposition=='0 0 0')
2108  org = this.origin;
2109  else
2110  org = this.lastposition;
2111 
2112 
2113  go = ( goal.absmin + goal.absmax ) * 0.5;
2114  te_lightning2(NULL, org, go);
2115  this.lastposition = go;
2116 
2117  this.goalcounter++;
2118 }
entity() spawn
origin
Definition: ent_cs.qc:114
#define NULL
Definition: post.qh:17
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:

◆ debugnode()

void debugnode ( entity  this,
vector  node 
)

Definition at line 2018 of file navigation.qc.

References debuglastnode, IS_PLAYER, and NULL.

Referenced by tracewalk().

2019 {
2020  if (!IS_PLAYER(this))
2021  return;
2022 
2023  if(debuglastnode=='0 0 0')
2024  {
2025  debuglastnode = node;
2026  return;
2027  }
2028 
2029  te_lightning2(NULL, node, debuglastnode);
2030  debuglastnode = node;
2031 }
#define NULL
Definition: post.qh:17
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the caller graph for this function:

◆ debugnodestatus()

void debugnodestatus ( vector  position,
float  status 
)

Definition at line 2033 of file navigation.qc.

References DEBUG_NODE_FAIL, DEBUG_NODE_SUCCESS, DEBUG_NODE_WARNING, and vector().

Referenced by tracewalk().

2034 {
2035  vector c;
2036 
2037  switch (status)
2038  {
2039  case DEBUG_NODE_SUCCESS:
2040  c = '0 15 0';
2041  break;
2042  case DEBUG_NODE_WARNING:
2043  c = '15 15 0';
2044  break;
2045  case DEBUG_NODE_FAIL:
2046  c = '15 0 0';
2047  break;
2048  default:
2049  c = '15 15 15';
2050  }
2051 
2052  te_customflash(position, 40, 2, c);
2053 }
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:

◆ debugresetnodes()

void debugresetnodes ( )

Definition at line 2013 of file navigation.qc.

References debuglastnode.

Referenced by tracewalk().

2014 {
2015  debuglastnode = '0 0 0';
2016 }
+ Here is the caller graph for this function:

◆ 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:

◆ navigation_check_submerged_state()

bool navigation_check_submerged_state ( entity  ent,
vector  pos 
)

Definition at line 203 of file navigation.qc.

References IS_PLAYER, SUBMERGED, SUBMERGED_NO, SUBMERGED_UNDEFINED, SUBMERGED_YES, and WATERLEVEL_SUBMERGED.

Referenced by waypoint_gettravelcost().

204 {
205  bool submerged;
206  if(IS_PLAYER(ent))
207  submerged = (ent.waterlevel == WATERLEVEL_SUBMERGED);
208  else if(ent.nav_submerged_state != SUBMERGED_UNDEFINED)
209  submerged = (ent.nav_submerged_state == SUBMERGED_YES);
210  else
211  {
212  submerged = SUBMERGED(pos);
213  // NOTE: SUBMERGED check of box waypoint origin may fail even if origin
214  // is actually submerged because often they are inside some solid.
215  // That's why submerged state is saved now that we know current pos is
216  // not stuck in solid (previous tracewalk call to this pos was successfully)
217  if(!ent.navigation_dynamicgoal)
218  ent.nav_submerged_state = (submerged) ? SUBMERGED_YES : SUBMERGED_NO;
219  }
220  return submerged;
221 }
const int WATERLEVEL_SUBMERGED
Definition: movetypes.qh:14
#define SUBMERGED(pos)
Definition: bot.qh:85
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the caller graph for this function:

◆ navigation_checkladders()

bool navigation_checkladders ( entity  e,
vector  org,
vector  m1,
vector  m2,
vector  end,
vector  end2,
int  movemode 
)

Definition at line 223 of file navigation.qc.

References boxesoverlap(), IL_EACH, trace_fraction, vec2, and vector().

Referenced by tracewalk().

224 {
225  IL_EACH(g_ladders, true,
226  {
227  if(it.bot_pickup)
228  if(boxesoverlap(org + m1 + '-1 -1 -1', org + m2 + '1 1 1', it.absmin, it.absmax))
229  if(boxesoverlap(end, end2, it.absmin + vec2(m1) + '-1 -1 0', it.absmax + vec2(m2) + '1 1 0'))
230  {
231  vector top = org;
232  top.z = it.absmax.z + (PL_MAX_CONST.z - PL_MIN_CONST.z);
233  tracebox(org, m1, m2, top, movemode, e);
234  if(trace_fraction == 1)
235  return true;
236  }
237  });
238  return false;
239 }
#define IL_EACH(this, cond, body)
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
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define vec2(...)
Definition: vector.qh:90
float trace_fraction
Definition: csprogsdefs.qc:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_clearroute()

void navigation_clearroute ( entity  this)

Definition at line 750 of file navigation.qc.

References FLOAT_MAX, goalcurrent, goalcurrent_distance_2d, goalcurrent_distance_time, goalcurrent_distance_z, goalcurrent_prev, goalentity, goalentity_lock_timeout, goalentity_shouldbefrozen, goalstack01, goalstack02, goalstack03, goalstack04, goalstack05, goalstack06, goalstack07, goalstack08, goalstack09, goalstack10, goalstack11, goalstack12, goalstack13, goalstack14, goalstack15, goalstack16, goalstack17, goalstack18, goalstack19, goalstack20, goalstack21, goalstack22, goalstack23, goalstack24, goalstack25, goalstack26, goalstack27, goalstack28, goalstack29, goalstack30, goalstack31, lastteleporttime, and NULL.

Referenced by havocbot_ai(), havocbot_movetogoal(), havocbot_resetgoal(), navigation_goalrating_start(), and navigation_unstuck().

751 {
752  this.lastteleporttime = 0;
753  this.goalcurrent_prev = this.goalcurrent;
756  this.goalcurrent_distance_time = 0;
757  this.goalentity_lock_timeout = 0;
758  this.goalentity_shouldbefrozen = false;
759  this.goalentity = NULL;
760  this.goalcurrent = NULL;
761  this.goalstack01 = NULL;
762  this.goalstack02 = NULL;
763  this.goalstack03 = NULL;
764  this.goalstack04 = NULL;
765  this.goalstack05 = NULL;
766  this.goalstack06 = NULL;
767  this.goalstack07 = NULL;
768  this.goalstack08 = NULL;
769  this.goalstack09 = NULL;
770  this.goalstack10 = NULL;
771  this.goalstack11 = NULL;
772  this.goalstack12 = NULL;
773  this.goalstack13 = NULL;
774  this.goalstack14 = NULL;
775  this.goalstack15 = NULL;
776  this.goalstack16 = NULL;
777  this.goalstack17 = NULL;
778  this.goalstack18 = NULL;
779  this.goalstack19 = NULL;
780  this.goalstack20 = NULL;
781  this.goalstack21 = NULL;
782  this.goalstack22 = NULL;
783  this.goalstack23 = NULL;
784  this.goalstack24 = NULL;
785  this.goalstack25 = NULL;
786  this.goalstack26 = NULL;
787  this.goalstack27 = NULL;
788  this.goalstack28 = NULL;
789  this.goalstack29 = NULL;
790  this.goalstack30 = NULL;
791  this.goalstack31 = NULL;
792 }
float goalentity_lock_timeout
Definition: api.qh:97
entity goalentity
Definition: progsdefs.qc:189
#define NULL
Definition: post.qh:17
float lastteleporttime
Definition: api.qh:50
const float FLOAT_MAX
Definition: float.qh:3
+ 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.

References bot_basewaypoint, navigation_dynamicgoal, nearestwaypoint, nearestwaypointtimeout, and time.

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.

References nearestwaypoint, nearestwaypointtimeout, and time.

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.

References bot_basewaypoint, nearestwaypoint, and nearestwaypointtimeout.

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.

References autocvar_g_waypointeditor_auto, entity(), navigation_findnearestwaypoint_withdist_except(), NULL, and WAYPOINTFLAG_PROTECTED.

Referenced by botframe_autowaypoints_fix_from(), navigation_routerating(), 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 call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_findnearestwaypoint_withdist_except()

entity navigation_findnearestwaypoint_withdist_except ( entity  ent,
float  walkfromwp,
float  bestdist,
entity  except 
)

Definition at line 918 of file navigation.qc.

References best, boxesoverlap(), entity(), g_jumppads, g_waypoints, if(), IL_EACH, IS_BOT_CLIENT, IS_PLAYER, navigation_testtracewalk, navigation_waypoint_will_link(), NULL, set_tracewalk_dest(), SOLID_BSP, trace_ent, tracewalk_dest, tracewalk_dest_height, trigger_push_test(), v, vector(), vlen(), waypointeditor_enabled, WAYPOINTFLAG_JUMP, WAYPOINTFLAG_TELEPORT, and WPFLAGMASK_NORELINK.

Referenced by navigation_findnearestwaypoint().

919 {
920  if(ent.tag_entity)
921  ent = ent.tag_entity;
922 
923  vector pm1 = ent.origin + ent.mins;
924  vector pm2 = ent.origin + ent.maxs;
925 
927  {
928  // this code allows removing waypoints in the air and seeing jumppad/telepport waypoint links
929  // FIXME it causes a bug where a waypoint spawned really close to another one (max 16 qu)
930  // isn't detected as the nearest waypoint
931  IL_EACH(g_waypoints, it != ent && it != except,
932  {
933  if (boxesoverlap(pm1, pm2, it.absmin, it.absmax))
934  return it;
935  });
936  }
937  else
938  {
939  // do two scans, because box test is cheaper
940  IL_EACH(g_waypoints, it != ent && it != except && !(it.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)),
941  {
942  if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
943  {
944  if(walkfromwp && !ent.navigation_dynamicgoal)
945  waypoint_clearlinks(ent); // initialize wpXXmincost fields
946  return it;
947  }
948  });
949  }
950 
951  vector org = ent.origin;
953  te_plasmaburn(org);
954 
955  entity best = NULL;
956  vector v = '0 0 0';
957 
958  if(ent.size && !IS_PLAYER(ent))
959  {
960  org += 0.5 * (ent.mins + ent.maxs);
961  org.z = ent.origin.z + ent.mins.z - PL_MIN_CONST.z; // player height
962  }
963 
964  // box check failed, try walk
965  IL_EACH(g_waypoints, it != ent,
966  {
967  if (walkfromwp && (it.wpflags & WPFLAGMASK_NORELINK))
968  continue;
969  v = it.origin;
970 
971  if (walkfromwp)
972  {
973  set_tracewalk_dest(ent, v, true);
974  if (trace_ent == ent)
975  {
976  bestdist = 0;
977  best = it;
978  break;
979  }
980  }
981  else
982  set_tracewalk_dest(it, org, false);
983 
984  if (navigation_waypoint_will_link(v, org, ent,
986  tracewalk_dest, tracewalk_dest_height, walkfromwp, bestdist))
987  {
988  if (walkfromwp)
989  bestdist = vlen(tracewalk_dest - v);
990  else
991  bestdist = vlen(v - org);
992  best = it;
993  }
994  });
995  if(!best && !ent.navigation_dynamicgoal)
996  {
997  int solid_save = ent.solid;
998  ent.solid = SOLID_BSP;
999  IL_EACH(g_jumppads, true,
1000  {
1001  if(trigger_push_test(it, ent))
1002  {
1003  best = it.nearestwaypoint;
1004  break;
1005  }
1006  });
1007  ent.solid = solid_save;
1008  }
1009  return best;
1010 }
#define IL_EACH(this, cond, body)
entity() spawn
const int WAYPOINTFLAG_JUMP
Definition: api.qh:20
const int WPFLAGMASK_NORELINK
Definition: api.qh:29
entity trace_ent
Definition: csprogsdefs.qc:40
IntrusiveList g_jumppads
Definition: jumppads.qh:7
bool waypointeditor_enabled
Definition: waypoints.qh:3
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
#define NULL
Definition: post.qh:17
IntrusiveList g_waypoints
Definition: api.qh:148
vector(float skel, float bonenum) _skel_get_boneabs_hidden
vector v
Definition: ent_cs.qc:116
const float SOLID_BSP
Definition: csprogsdefs.qc:248
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
bool trigger_push_test(entity this, entity item)
if (item != NULL) returns true if the item can be reached by using this jumppad, false otherwise if (...
Definition: jumppads.qc:387
best
Definition: all.qh:77
if(IS_DEAD(this))
Definition: impulse.qc:92
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_get_really_close_waypoint()

entity navigation_get_really_close_waypoint ( entity  this)

Definition at line 1783 of file navigation.qc.

References AI_STATUS_RUNNING, aistatus, BOT_BUNNYHOP_WP_DETECTION_RANGE, bot_navigation_movemode, entity(), g_waypoints, goalcurrent, goalcurrent_prev, IL_EACH, NULL, origin, set_tracewalk_dest(), tracewalk(), tracewalk_dest, tracewalk_dest_height, vdist, WAYPOINTFLAG_JUMP, and WAYPOINTFLAG_TELEPORT.

Referenced by navigation_goalrating_start().

1784 {
1785  entity wp = this.goalcurrent;
1786  if(!wp)
1787  wp = this.goalcurrent_prev;
1788  if(!wp)
1789  return NULL;
1790  float min_dist = ((this.aistatus & AI_STATUS_RUNNING) ? BOT_BUNNYHOP_WP_DETECTION_RANGE : 50);
1791  if(wp != this.goalcurrent_prev && vdist(wp.origin - this.origin, >, min_dist))
1792  {
1793  wp = this.goalcurrent_prev;
1794  if(!wp)
1795  return NULL;
1796  }
1797  if(wp.classname != "waypoint")
1798  {
1799  wp = wp.nearestwaypoint;
1800  if(!wp)
1801  return NULL;
1802  }
1803  if(vdist(wp.origin - this.origin, >, min_dist))
1804  {
1805  wp = NULL;
1807  {
1808  if(vdist(it.origin - this.origin, <, min_dist))
1809  {
1810  wp = it;
1811  break;
1812  }
1813  });
1814  if(!wp)
1815  return NULL;
1816  }
1817  if(wp.wpflags & WAYPOINTFLAG_TELEPORT)
1818  return NULL;
1819 
1820  set_tracewalk_dest(wp, this.origin, false);
1821  if (!tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
1823  {
1824  return NULL;
1825  }
1826  return wp;
1827 }
#define IL_EACH(this, cond, body)
int aistatus
Definition: bot.qh:20
entity() spawn
const int WAYPOINTFLAG_JUMP
Definition: api.qh:20
origin
Definition: ent_cs.qc:114
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
#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 AI_STATUS_RUNNING
Definition: bot.qh:8
+ Here is the call graph for this function:
+ 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.

References AI_STATUS_STUCK, aistatus, autocvar_bot_wander_enable, boolean, entity(), goalcurrent, goalentity, goalentity_shouldbefrozen, goalstack31, LOG_DEBUG, navigation_bestgoal, navigation_poproute(), navigation_routetogoal(), netname, NULL, and origin.

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 call graph for this function:
+ 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.

References AI_STATUS_STUCK, aistatus, entity(), goalstack31, navigation_bestgoal, navigation_bestrating, navigation_clearroute(), navigation_get_really_close_waypoint(), navigation_jetpack_goal, navigation_markroutes(), and NULL.

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 call graph for this function:
+ 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()

ERASEABLE 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.

References navigation_goalrating_timeout_expire().

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

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

◆ navigation_goalrating_timeout_set()

void navigation_goalrating_timeout_set ( entity  this)

Definition at line 19 of file navigation.qc.

References autocvar_bot_ai_strategyinterval, autocvar_bot_ai_strategyinterval_movingtarget, bot_strategytime, goalentity, IS_MOVABLE, and time.

Referenced by 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(), havocbot_role_race(), and navigation_unstuck().

20 {
21  if(IS_MOVABLE(this.goalentity))
23  else
25 }
float autocvar_bot_ai_strategyinterval
Definition: cvars.qh:68
#define IS_MOVABLE(v)
Definition: utils.qh:25
float autocvar_bot_ai_strategyinterval_movingtarget
Definition: cvars.qh:69
entity goalentity
Definition: progsdefs.qc:189
float bot_strategytime
Definition: bot.qh:69
float time
Definition: csprogsdefs.qc:16
+ Here is the caller graph for this function:

◆ navigation_markroutes()

void navigation_markroutes ( entity  this,
entity  fixed_source_waypoint 
)

Definition at line 1081 of file navigation.qc.

References g_waypoints, IL_EACH, IS_ONGROUND, navigation_markroutes_nearestwaypoints(), NULL, and vector().

Referenced by navigation_goalrating_start(), and 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 call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_markroutes_checkwaypoint()

void navigation_markroutes_checkwaypoint ( entity  w,
entity  wp,
float  cost,
vector  p 
)

Definition at line 1053 of file navigation.qc.

References bound(), v, vector(), waypoint_gettravelcost(), and WAYPOINTFLAG_TELEPORT.

1054 {
1055  vector m1, m2;
1056  vector v;
1057  if (wp.wpisbox)
1058  {
1059  m1 = wp.origin + wp.mins;
1060  m2 = wp.origin + wp.maxs;
1061  v.x = bound(m1_x, p.x, m2_x);
1062  v.y = bound(m1_y, p.y, m2_y);
1063  v.z = bound(m1_z, p.z, m2_z);
1064  }
1065  else
1066  v = wp.origin;
1067  if (w.wpflags & WAYPOINTFLAG_TELEPORT)
1068  cost += w.wp00mincost; // assuming teleport has exactly one destination
1069  else
1070  cost += waypoint_gettravelcost(p, v, w, wp);
1071  if (wp.wpcost > cost)
1072  {
1073  wp.wpcost = cost;
1074  wp.enemy = w;
1075  wp.wpfire = 1;
1076  wp.wpnearestpoint = v;
1077  }
1078 }
float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_ent)
Definition: waypoints.qc:1030
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
vector(float skel, float bonenum) _skel_get_boneabs_hidden
vector v
Definition: ent_cs.qc:116
+ Here is the call graph for this function:

◆ navigation_markroutes_inverted()

void navigation_markroutes_inverted ( entity  fixed_source_waypoint)

Definition at line 1171 of file navigation.qc.

References error(), g_waypoints, IL_EACH, NULL, and vector().

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 call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_markroutes_nearestwaypoints()

float navigation_markroutes_nearestwaypoints ( entity  this,
float  maxdist 
)

Definition at line 1024 of file navigation.qc.

References g_waypoints, and IL_EACH.

Referenced by navigation_markroutes().

1025 {
1026  //navigation_testtracewalk = true;
1027  int c = 0;
1028  IL_EACH(g_waypoints, !it.wpconsidered,
1029  {
1030  set_tracewalk_dest(it, this.origin, false);
1031 
1032  vector diff = tracewalk_dest - this.origin;
1033  diff.z = max(0, diff.z);
1034  if(vdist(diff, <, maxdist))
1035  {
1036  it.wpconsidered = true;
1037  if (tracewalk(this, this.origin, this.mins, this.maxs,
1038  tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
1039  {
1040  it.wpnearestpoint = tracewalk_dest;
1041  it.wpcost = waypoint_gettravelcost(this.origin, tracewalk_dest, this, it) + it.dmg;
1042  it.wpfire = 1;
1043  it.enemy = NULL;
1044  c = c + 1;
1045  }
1046  }
1047  });
1048  //navigation_testtracewalk = false;
1049  return c;
1050 }
#define IL_EACH(this, cond, body)
IntrusiveList g_waypoints
Definition: api.qh:148
+ Here is the caller graph for this function:

◆ navigation_poproute()

void navigation_poproute ( entity  this)

Definition at line 846 of file navigation.qc.

References FLOAT_MAX, goalcurrent, goalcurrent_distance_2d, goalcurrent_distance_time, goalcurrent_distance_z, goalcurrent_prev, goalentity, goalentity_lock_timeout, goalstack01, goalstack02, goalstack03, goalstack04, goalstack05, goalstack06, goalstack07, goalstack08, goalstack09, goalstack10, goalstack11, goalstack12, goalstack13, goalstack14, goalstack15, goalstack16, goalstack17, goalstack18, goalstack19, goalstack20, goalstack21, goalstack22, goalstack23, goalstack24, goalstack25, goalstack26, goalstack27, goalstack28, goalstack29, goalstack30, goalstack31, and NULL.

Referenced by navigation_goalrating_end(), navigation_poptouchedgoals(), and navigation_shortenpath().

847 {
848  this.goalcurrent_prev = this.goalcurrent;
851  this.goalcurrent_distance_time = 0;
852  //print("bot ", etos(this), " pop\n");
853  if(this.goalcurrent == this.goalentity)
854  {
855  this.goalentity = NULL;
856  this.goalentity_lock_timeout = 0;
857  }
858  this.goalcurrent = this.goalstack01;
859  this.goalstack01 = this.goalstack02;
860  this.goalstack02 = this.goalstack03;
861  this.goalstack03 = this.goalstack04;
862  this.goalstack04 = this.goalstack05;
863  this.goalstack05 = this.goalstack06;
864  this.goalstack06 = this.goalstack07;
865  this.goalstack07 = this.goalstack08;
866  this.goalstack08 = this.goalstack09;
867  this.goalstack09 = this.goalstack10;
868  this.goalstack10 = this.goalstack11;
869  this.goalstack11 = this.goalstack12;
870  this.goalstack12 = this.goalstack13;
871  this.goalstack13 = this.goalstack14;
872  this.goalstack14 = this.goalstack15;
873  this.goalstack15 = this.goalstack16;
874  this.goalstack16 = this.goalstack17;
875  this.goalstack17 = this.goalstack18;
876  this.goalstack18 = this.goalstack19;
877  this.goalstack19 = this.goalstack20;
878  this.goalstack20 = this.goalstack21;
879  this.goalstack21 = this.goalstack22;
880  this.goalstack22 = this.goalstack23;
881  this.goalstack23 = this.goalstack24;
882  this.goalstack24 = this.goalstack25;
883  this.goalstack25 = this.goalstack26;
884  this.goalstack26 = this.goalstack27;
885  this.goalstack27 = this.goalstack28;
886  this.goalstack28 = this.goalstack29;
887  this.goalstack29 = this.goalstack30;
888  this.goalstack30 = this.goalstack31;
889  this.goalstack31 = NULL;
890 }
float goalentity_lock_timeout
Definition: api.qh:97
entity goalentity
Definition: progsdefs.qc:189
#define NULL
Definition: post.qh:17
const float FLOAT_MAX
Definition: float.qh:3
+ Here is the caller graph for this function:

◆ navigation_poptouchedgoals()

int navigation_poptouchedgoals ( entity  this)

Definition at line 1629 of file navigation.qc.

References absmax, absmin, AI_STATUS_RUNNING, AI_STATUS_WAYPOINT_PERSONAL_GOING, AI_STATUS_WAYPOINT_PERSONAL_REACHED, aistatus, BOT_BUNNYHOP_WP_DETECTION_RANGE, boxesoverlap(), entity(), eZ, goalcurrent, goalstack01, goalstack02, goalstack03, IS_PLAYER, jumpheight_vec, jumppadcount, ladder_entity, lastteleporttime, navigation_poproute(), NULL, origin, random(), TELEPORT_USED, time, trace_fraction, vdist, vec2, vector(), velocity, view_ofs, vlen2, WAYPOINTFLAG_JUMP, WAYPOINTFLAG_PERSONAL, and WAYPOINTFLAG_TELEPORT.

Referenced by havocbot_movetogoal().

1630 {
1631  int removed_goals = 0;
1632 
1633  if(!this.goalcurrent)
1634  return removed_goals;
1635 
1636  if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
1637  {
1638  if (!this.goalcurrent.wpisbox // warpzone
1639  && vlen2(this.origin - this.goalstack01.origin) < vlen2(this.origin - this.goalcurrent.origin))
1640  {
1641  // immediately remove origin and destination waypoints
1642  navigation_poproute(this);
1643  ++removed_goals;
1644  navigation_poproute(this);
1645  ++removed_goals;
1646  this.lastteleporttime = 0;
1647  }
1648 
1649  // make sure jumppad is really hit, don't rely on distance based checks
1650  // as they may report a touch even if it didn't really happen
1651  if(this.lastteleporttime > 0 && TELEPORT_USED(this, this.goalcurrent))
1652  {
1654  if((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) && this.goalcurrent.owner==this)
1655  {
1656  this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
1658  }
1659  if(this.jumppadcount)
1660  {
1661  // remove jumppad waypoint after a random delay to prevent bots getting
1662  // stuck on certain jumppads that require an extra initial horizontal speed
1663  float max_delay = 0.1;
1664  if (vdist(vec2(this.velocity), >, 2 * autocvar_sv_maxspeed))
1665  max_delay = 0.05;
1666  if (time - this.lastteleporttime < random() * max_delay)
1667  return removed_goals;
1668  }
1669  else if (this.goalcurrent.wpisbox) // teleport
1670  {
1671  // immediately remove origin and destination waypoints
1672  navigation_poproute(this);
1673  ++removed_goals;
1674  }
1675  navigation_poproute(this);
1676  this.lastteleporttime = 0;
1677  ++removed_goals;
1678  }
1679  return removed_goals;
1680  }
1681  else if (this.lastteleporttime > 0)
1682  {
1683  // sometimes bot is pushed so hard (by a jumppad or a shot) that ends up touching the next
1684  // teleport / jumppad / warpzone present in its path skipping check of one or more goals
1685  // if so immediately fix bot path by removing skipped goals
1686  entity tele_ent = NULL;
1687  if (this.goalstack01 && (this.goalstack01.wpflags & WAYPOINTFLAG_TELEPORT))
1688  tele_ent = this.goalstack01;
1689  else if (this.goalstack02 && (this.goalstack02.wpflags & WAYPOINTFLAG_TELEPORT))
1690  tele_ent = this.goalstack02;
1691  else if (this.goalstack03 && (this.goalstack03.wpflags & WAYPOINTFLAG_TELEPORT))
1692  tele_ent = this.goalstack03;
1693  if (tele_ent && TELEPORT_USED(this, tele_ent))
1694  {
1695  if (this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
1696  if ((tele_ent.wpflags & WAYPOINTFLAG_PERSONAL) && tele_ent.owner == this)
1697  {
1698  this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
1700  }
1701  while (this.goalcurrent != tele_ent)
1702  {
1703  navigation_poproute(this);
1704  ++removed_goals;
1705  }
1706  navigation_poproute(this);
1707  this.lastteleporttime = 0;
1708  ++removed_goals;
1709  return removed_goals;
1710  }
1711  // reset of lastteleporttime can be overriden by a jumppad when it's set
1712  // in more than one frame: make sure it's reset
1713  this.lastteleporttime = 0;
1714  }
1715 
1716  // Loose goal touching check when running
1717  // check goalstack01 to make sure waypoint isn't the final goal
1718  if((this.aistatus & AI_STATUS_RUNNING) && this.goalcurrent.classname == "waypoint" && !(this.goalcurrent.wpflags & WAYPOINTFLAG_JUMP)
1719  && this.goalstack01 && !wasfreed(this.goalstack01) && vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed))
1720  {
1721  vector gco = this.goalcurrent.origin;
1722  float min_dist = BOT_BUNNYHOP_WP_DETECTION_RANGE;
1723  // also detect waypoints when bot is way above them but with a narrower horizontal range
1724  // so to increase chances bot ends up in the standard range (optimizes nearest waypoint finding)
1725  if(vdist(this.origin - gco, <, min_dist)
1726  || (vdist(vec2(this.origin - gco), <, min_dist * 0.5) && vdist(this.origin - eZ * 1.5 * min_dist - gco, <, min_dist)))
1727  {
1728  traceline(this.origin + this.view_ofs , this.goalcurrent.origin, true, NULL);
1729  if(trace_fraction==1)
1730  {
1731  // Detect personal waypoints
1732  if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
1733  if((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) && this.goalcurrent.owner==this)
1734  {
1735  this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
1737  }
1738 
1739  navigation_poproute(this);
1740  ++removed_goals;
1741  if(this.goalcurrent && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
1742  return removed_goals;
1743  }
1744  }
1745  }
1746 
1747  while (this.goalcurrent && !IS_PLAYER(this.goalcurrent))
1748  {
1749  vector gc_min = this.goalcurrent.absmin;
1750  vector gc_max = this.goalcurrent.absmax;
1751  if(this.goalcurrent.classname == "waypoint" && !this.goalcurrent.wpisbox)
1752  {
1753  gc_min = this.goalcurrent.origin - '1 1 1' * 12;
1754  gc_max = this.goalcurrent.origin + '1 1 1' * 12 + eZ * (jumpheight_vec.z + STAT(PL_MIN, this).z);
1755  }
1756  if (this.ladder_entity)
1757  {
1758  if (!boxesoverlap(this.absmin, this.absmax - eZ * STAT(PL_MAX, this).z, gc_min, gc_max))
1759  break;
1760  }
1761  else
1762  {
1763  if (!boxesoverlap(this.absmin, this.absmax, gc_min, gc_max))
1764  break;
1765  }
1766 
1767  // Detect personal waypoints
1768  if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
1769  if((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) && this.goalcurrent.owner==this)
1770  {
1771  this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
1773  }
1774 
1775  navigation_poproute(this);
1776  ++removed_goals;
1777  if(this.goalcurrent && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
1778  return removed_goals;
1779  }
1780  return removed_goals;
1781 }
vector view_ofs
Definition: progsdefs.qc:151
int aistatus
Definition: bot.qh:20
entity() spawn
const int WAYPOINTFLAG_JUMP
Definition: api.qh:20
const int AI_STATUS_WAYPOINT_PERSONAL_GOING
Definition: bot.qh:13
float jumppadcount
Definition: jumppads.qh:15
origin
Definition: ent_cs.qc:114
vector absmax
Definition: csprogsdefs.qc:92
#define vlen2(v)
Definition: vector.qh:4
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
#define NULL
Definition: post.qh:17
float lastteleporttime
Definition: api.qh:50
const int AI_STATUS_WAYPOINT_PERSONAL_REACHED
Definition: bot.qh:14
entity ladder_entity
Definition: ladder.qh:11
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
const vector eZ
Definition: vector.qh:46
#define vec2(...)
Definition: vector.qh:90
const int WAYPOINTFLAG_PERSONAL
Definition: api.qh:15
vector absmin
Definition: csprogsdefs.qc:92
float time
Definition: csprogsdefs.qc:16
vector velocity
Definition: csprogsdefs.qc:103
float trace_fraction
Definition: csprogsdefs.qc:36
const int AI_STATUS_RUNNING
Definition: bot.qh:8
#define IS_PLAYER(v)
Definition: utils.qh:9
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_pushroute()

void navigation_pushroute ( entity  this,
entity  e 
)

Definition at line 800 of file navigation.qc.

References FLOAT_MAX, goalcurrent, goalcurrent_distance_2d, goalcurrent_distance_time, goalcurrent_distance_z, goalcurrent_prev, goalentity, goalstack01, goalstack02, goalstack03, goalstack04, goalstack05, goalstack06, goalstack07, goalstack08, goalstack09, goalstack10, goalstack11, goalstack12, goalstack13, goalstack14, goalstack15, goalstack16, goalstack17, goalstack18, goalstack19, goalstack20, goalstack21, goalstack22, goalstack23, goalstack24, goalstack25, goalstack26, goalstack27, goalstack28, goalstack29, goalstack30, goalstack31, and NULL.

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

801 {
802  this.goalcurrent_prev = this.goalcurrent;
805  this.goalcurrent_distance_time = 0;
806  //print("bot ", etos(this), " push ", etos(e), "\n");
807  if(this.goalstack31 == this.goalentity)
808  this.goalentity = NULL;
809  this.goalstack31 = this.goalstack30;
810  this.goalstack30 = this.goalstack29;
811  this.goalstack29 = this.goalstack28;
812  this.goalstack28 = this.goalstack27;
813  this.goalstack27 = this.goalstack26;
814  this.goalstack26 = this.goalstack25;
815  this.goalstack25 = this.goalstack24;
816  this.goalstack24 = this.goalstack23;
817  this.goalstack23 = this.goalstack22;
818  this.goalstack22 = this.goalstack21;
819  this.goalstack21 = this.goalstack20;
820  this.goalstack20 = this.goalstack19;
821  this.goalstack19 = this.goalstack18;
822  this.goalstack18 = this.goalstack17;
823  this.goalstack17 = this.goalstack16;
824  this.goalstack16 = this.goalstack15;
825  this.goalstack15 = this.goalstack14;
826  this.goalstack14 = this.goalstack13;
827  this.goalstack13 = this.goalstack12;
828  this.goalstack12 = this.goalstack11;
829  this.goalstack11 = this.goalstack10;
830  this.goalstack10 = this.goalstack09;
831  this.goalstack09 = this.goalstack08;
832  this.goalstack08 = this.goalstack07;
833  this.goalstack07 = this.goalstack06;
834  this.goalstack06 = this.goalstack05;
835  this.goalstack05 = this.goalstack04;
836  this.goalstack04 = this.goalstack03;
837  this.goalstack03 = this.goalstack02;
838  this.goalstack02 = this.goalstack01;
839  this.goalstack01 = this.goalcurrent;
840  this.goalcurrent = e;
841 }
entity goalentity
Definition: progsdefs.qc:189
#define NULL
Definition: post.qh:17
const float FLOAT_MAX
Definition: float.qh:3
+ 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.

References autocvar_bot_ai_navigation_jetpack, autocvar_bot_ai_navigation_jetpack_mindistance, CONTENT_LAVA, CONTENT_SLIME, CONTENT_SOLID, CONTENT_WATER, entity(), etos(), fabs(), FL_PARTIALGROUND, FLOAT_MAX, ftos(), g_waypoints, GetResource(), IL_EACH, IS_BOT_CLIENT, IS_ONGROUND, IS_PLAYER, items, LOG_DEBUG, MOVE_NORMAL, navigation_bestgoal, navigation_bestrating, navigation_findnearestwaypoint(), navigation_jetpack_goal, navigation_jetpack_point, NULL, origin, random(), time, trace_endpos, trace_fraction, vdist, vector(), vlen(), WATERLEVEL_WETFEET, waypoint_getlinearcost(), waypoint_gettravelcost(), waypointeditor_enabled, WAYPOINTFLAG_PERSONAL, and WAYPOINTFLAG_TELEPORT.

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 call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_routetogoal()

bool navigation_routetogoal ( entity  this,
entity  e,
vector  startposition 
)

Definition at line 1429 of file navigation.qc.

References autocvar_bot_ai_strategyinterval_movingtarget, bot_navigation_movemode, checkpvs(), entity(), goalcurrent, goalentity, IS_MOVABLE, items, MAX_CHASE_DISTANCE, navigation_item_add_link, navigation_item_getlinknum, navigation_item_initlinks_ifneeded, navigation_item_iswalkablelink, navigation_jetpack_goal, navigation_pushroute(), NULL, origin, set_tracewalk_dest(), trace_ent, tracewalk(), tracewalk_dest, tracewalk_dest_height, vdist, vec2, vlen2, waypointeditor_enabled, WAYPOINTFLAG_PERSONAL, WAYPOINTFLAG_TELEPORT, wp_goal_prev0, wp_goal_prev1, and WPFLAGMASK_NORELINK.

Referenced by havocbot_movetogoal(), navigation_goalrating_end(), and navigation_unstuck().

1430 {
1431  // if there is no goal, just exit
1432  if (!e)
1433  return false;
1434 
1435  entity teleport_goal = NULL;
1436 
1437  this.goalentity = e;
1438 
1439  if(e.wpflags & WAYPOINTFLAG_TELEPORT)
1440  {
1441  // force teleport destination as route destination
1442  teleport_goal = e;
1443  navigation_pushroute(this, e.wp00);
1444  this.goalentity = e.wp00;
1445  }
1446 
1447  // put the entity on the goal stack
1448  //print("routetogoal ", etos(e), "\n");
1449  navigation_pushroute(this, e);
1450 
1451  if(teleport_goal)
1452  e = this.goalentity;
1453 
1454  if(e.classname == "waypoint" && !(e.wpflags & WAYPOINTFLAG_PERSONAL))
1455  {
1456  this.wp_goal_prev1 = this.wp_goal_prev0;
1457  this.wp_goal_prev0 = e;
1458  }
1459 
1460  if((this.items & IT_JETPACK) && e == this.navigation_jetpack_goal)
1461  return true;
1462 
1463  // if it can reach the goal there is nothing more to do
1464  set_tracewalk_dest(e, startposition, true);
1466  && (trace_ent == this || tracewalk(this, startposition, STAT(PL_MIN, this), STAT(PL_MAX, this),
1468  {
1469  return true;
1470  }
1471 
1472  entity nearest_wp = NULL;
1473  // see if there are waypoints describing a path to the item
1474  if(e.classname != "waypoint" || (e.wpflags & WAYPOINTFLAG_PERSONAL))
1475  {
1476  e = e.nearestwaypoint;
1477  nearest_wp = e;
1478  }
1479  else if(teleport_goal)
1480  e = teleport_goal;
1481  else
1482  e = e.enemy; // we already have added it, so...
1483 
1484  if(e == NULL)
1485  return false;
1486 
1487  if(nearest_wp && nearest_wp.enemy && !(nearest_wp.enemy.wpflags & WPFLAGMASK_NORELINK))
1488  {
1489  // often path can be optimized by not adding the nearest waypoint
1490  if (this.goalentity.navigation_dynamicgoal || waypointeditor_enabled)
1491  {
1492  if (nearest_wp.enemy.wpcost < autocvar_bot_ai_strategyinterval_movingtarget)
1493  {
1494  if (vdist(vec2(this.goalentity.origin - nearest_wp.origin), <, 32))
1495  e = nearest_wp.enemy;
1496  else
1497  {
1498  set_tracewalk_dest(this.goalentity, nearest_wp.enemy.origin, true);
1499  if (trace_ent == this || (vdist(tracewalk_dest - nearest_wp.enemy.origin, <, 1050)
1500  && vlen2(tracewalk_dest - nearest_wp.enemy.origin) < vlen2(nearest_wp.origin - nearest_wp.enemy.origin)
1501  && tracewalk(this, nearest_wp.enemy.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
1503  {
1504  e = nearest_wp.enemy;
1505  }
1506  }
1507  }
1508  }
1509  else
1510  {
1511  // NOTE unlike waypoints, items hold incoming links
1513  int link_num = navigation_item_getlinknum(this.goalentity, nearest_wp.enemy);
1514  if (link_num >= 0)
1515  {
1516  if (navigation_item_iswalkablelink(this.goalentity, link_num))
1517  e = nearest_wp.enemy;
1518  }
1519  else // untested link
1520  {
1521  entity wp = nearest_wp.enemy;
1522  entity goal = this.goalentity;
1523  bool walkable = false;
1524  if (checkpvs(wp.origin, goal))
1525  {
1526  set_tracewalk_dest(goal, wp.origin, false);
1527  if (vdist(tracewalk_dest - wp.origin, <, 1050)
1528  && tracewalk(goal, wp.origin, PL_MIN_CONST, PL_MAX_CONST,
1530  {
1531  walkable = true;
1532  e = nearest_wp.enemy;
1533  }
1534  }
1535  navigation_item_add_link(wp, goal, walkable);
1536  }
1537  }
1538  }
1539 
1540  for (;;)
1541  {
1542  // add the spawnfunc_waypoint to the path
1543  navigation_pushroute(this, e);
1544  e = e.enemy;
1545 
1546  if(e==NULL)
1547  break;
1548  }
1549 
1550  return false;
1551 }
entity() spawn
float checkpvs(vector viewpos, entity viewee)
const int WPFLAGMASK_NORELINK
Definition: api.qh:29
#define IS_MOVABLE(v)
Definition: utils.qh:25
origin
Definition: ent_cs.qc:114
entity trace_ent
Definition: csprogsdefs.qc:40
bool waypointeditor_enabled
Definition: waypoints.qh:3
#define vlen2(v)
Definition: vector.qh:4
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
float autocvar_bot_ai_strategyinterval_movingtarget
Definition: cvars.qh:69
entity goalentity
Definition: progsdefs.qc:189
#define NULL
Definition: post.qh:17
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float items
Definition: progsdefs.qc:145
#define vec2(...)
Definition: vector.qh:90
const int WAYPOINTFLAG_PERSONAL
Definition: api.qh:15
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_shortenpath()

bool navigation_shortenpath ( entity  this)

Definition at line 1554 of file navigation.qc.

References bot_navigation_movemode, bot_tracewalk_time, checkpvs(), entity(), fabs(), goalcurrent, goalentity, goalstack01, IS_MOVABLE, LOG_DEBUG, max(), MAX_CHASE_DISTANCE, maxs, mins, navigation_poproute(), netname, next, origin, set_tracewalk_dest(), time, trace_ent, tracewalk(), tracewalk_dest, tracewalk_dest_height, vdist, vectoangles(), vector(), view_ofs, vlen2, WAYPOINTFLAG_JUMP, and WAYPOINTFLAG_TELEPORT.

Referenced by havocbot_movetogoal().

1555 {
1556  if (!this.goalstack01 || wasfreed(this.goalstack01))
1557  return false;
1558  if (this.bot_tracewalk_time > time)
1559  return false;
1560  this.bot_tracewalk_time = max(time, this.bot_tracewalk_time) + 0.25;
1561 
1562  bool cut_allowed = false;
1563  entity next = this.goalentity;
1564  // evaluate whether bot can discard current route and chase directly a player, trying to
1565  // keep waypoint route as long as possible, as it is safer and faster (bot can bunnyhop)
1566  if (IS_MOVABLE(next))
1567  {
1568  set_tracewalk_dest(next, this.origin, true);
1569  if (vdist(this.origin - tracewalk_dest, <, 200))
1570  cut_allowed = true;
1571  else if (vdist(tracewalk_dest - this.origin, <, MAX_CHASE_DISTANCE)
1572  && vdist(tracewalk_dest - this.goalcurrent.origin, >, 200)
1573  && vdist(this.origin - this.goalcurrent.origin, >, 100)
1574  && checkpvs(this.origin + this.view_ofs, next))
1575  {
1576  if (vlen2(next.origin - this.origin) < vlen2(this.goalcurrent.origin - this.origin))
1577  cut_allowed = true;
1578  else
1579  {
1580  vector deviation = vectoangles(this.goalcurrent.origin - this.origin) - vectoangles(next.origin - this.origin);
1581  while (deviation.y < -180) deviation.y += 360;
1582  while (deviation.y > 180) deviation.y -= 360;
1583  if (fabs(deviation.y) > 25)
1584  cut_allowed = true;
1585  }
1586  }
1587  if (cut_allowed)
1588  {
1589  if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
1591  {
1592  LOG_DEBUG("path optimized for ", this.netname, ", route cleared");
1593  do
1594  {
1595  navigation_poproute(this);
1596  }
1597  while (this.goalcurrent != next);
1598  return true;
1599  }
1600  return false;
1601  }
1602  }
1603 
1604  next = this.goalstack01;
1605  // if for some reason the bot is closer to the next goal, pop the current one
1606  if (!IS_MOVABLE(next) && !(this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP))
1607  && vlen2(this.goalcurrent.origin - next.origin) > vlen2(next.origin - this.origin)
1608  && checkpvs(this.origin + this.view_ofs, next))
1609  {
1610  set_tracewalk_dest(next, this.origin, true);
1611  cut_allowed = true;
1612  }
1613 
1614  if (cut_allowed)
1615  {
1616  if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
1618  {
1619  LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
1620  navigation_poproute(this);
1621  return true;
1622  }
1623  }
1624  return false;
1625 }
vector view_ofs
Definition: progsdefs.qc:151
entity() spawn
const int WAYPOINTFLAG_JUMP
Definition: api.qh:20
vector maxs
Definition: csprogsdefs.qc:113
float checkpvs(vector viewpos, entity viewee)
string netname
Definition: powerups.qc:20
#define IS_MOVABLE(v)
Definition: utils.qh:25
origin
Definition: ent_cs.qc:114
entity trace_ent
Definition: csprogsdefs.qc:40
float bot_tracewalk_time
Definition: api.qh:37
vector mins
Definition: csprogsdefs.qc:113
#define vlen2(v)
Definition: vector.qh:4
const int WAYPOINTFLAG_TELEPORT
Definition: api.qh:13
entity goalentity
Definition: progsdefs.qc:189
vector(float skel, float bonenum) _skel_get_boneabs_hidden
next
Definition: all.qh:88
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float time
Definition: csprogsdefs.qc:16
#define LOG_DEBUG(...)
Definition: log.qh:85
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_unstuck()

void navigation_unstuck ( entity  this)

Definition at line 1907 of file navigation.qc.

References AI_STATUS_STUCK, aistatus, autocvar_bot_wander_enable, bot_navigation_movemode, bot_strategytoken, bot_waypoint_queue_bestgoal, bot_waypoint_queue_bestgoalrating, bot_waypoint_queue_goal, bot_waypoint_queue_owner, entity(), ftos(), g_waypoints, goalentity, IL_EACH, LOG_DEBUG, navigation_clearroute(), navigation_goalrating_timeout_expire(), navigation_goalrating_timeout_set(), navigation_routetogoal(), netname, NULL, origin, random(), set_tracewalk_dest(), tracewalk(), tracewalk_dest, tracewalk_dest_height, vlen2, and WAYPOINTFLAG_GENERATED.

Referenced by bot_think().

1908 {
1910  return;
1911 
1912  bool has_user_waypoints = false;
1913  IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_GENERATED),
1914  {
1915  has_user_waypoints = true;
1916  break;
1917  });
1918  if (!has_user_waypoints)
1919  return;
1920 
1921  float search_radius = 1000;
1922 
1924  {
1925  LOG_DEBUG(this.netname, " stuck, taking over the waypoints queue");
1926  bot_waypoint_queue_owner = this;
1929  }
1930 
1931  if(bot_waypoint_queue_owner!=this)
1932  return;
1933 
1935  {
1936  // evaluate the next goal on the queue
1937  float d = vlen2(this.origin - bot_waypoint_queue_goal.origin);
1938  LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with squared distance ", ftos(d));
1940  if (tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
1942  {
1944  {
1947  }
1948  }
1949 
1950  // move to a random waypoint while bot is searching for a walkable path;
1951  // this is usually sufficient to unstuck bots from bad spots or when other
1952  // bots of the same team block all their ways
1953  if (!bot_waypoint_queue_bestgoal && (!this.goalentity || random() < 0.1))
1954  {
1955  navigation_clearroute(this);
1958  }
1959 
1960  bot_waypoint_queue_goal = bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal;
1961 
1963  {
1965  {
1966  LOG_DEBUG(this.netname, " stuck, reachable waypoint found, heading to it");
1967  navigation_clearroute(this);
1970  this.aistatus &= ~AI_STATUS_STUCK;
1971  }
1972  else
1973  {
1974  LOG_DEBUG(this.netname, " stuck, cannot walk to any waypoint at all");
1975  }
1976 
1978  }
1979  }
1980  else
1981  {
1982  if(bot_strategytoken!=this)
1983  return;
1984 
1985  // build a new queue
1986  LOG_DEBUG(this.netname, " stuck, scanning reachable waypoints within ", ftos(search_radius)," qu");
1987 
1988  entity first = NULL;
1989 
1990  FOREACH_ENTITY_RADIUS(this.origin, search_radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
1991  {
1992  if(bot_waypoint_queue_goal)
1993  bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = it;
1994  else
1995  first = it;
1996 
1997  bot_waypoint_queue_goal = it;
1998  bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = NULL;
1999  });
2000 
2001  if (first)
2002  bot_waypoint_queue_goal = first;
2003  else
2004  {
2005  LOG_DEBUG(this.netname, " stuck, cannot walk to any waypoint at all");
2007  }
2008  }
2009 }
#define IL_EACH(this, cond, body)
int aistatus
Definition: bot.qh:20
entity() spawn
string netname
Definition: powerups.qc:20
origin
Definition: ent_cs.qc:114
#define vlen2(v)
Definition: vector.qh:4
entity goalentity
Definition: progsdefs.qc:189
#define NULL
Definition: post.qh:17
bool autocvar_bot_wander_enable
Definition: cvars.qh:60
IntrusiveList g_waypoints
Definition: api.qh:148
const int WAYPOINTFLAG_GENERATED
Definition: api.qh:11
const int AI_STATUS_STUCK
Definition: bot.qh:17
entity bot_strategytoken
Definition: bot.qh:76
#define LOG_DEBUG(...)
Definition: log.qh:85
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ navigation_waypoint_will_link()

float navigation_waypoint_will_link ( vector  v,
vector  org,
entity  ent,
vector  v2,
float  v2_height,
vector  o2,
float  o2_height,
float  walkfromwp,
float  bestdist 
)

Definition at line 895 of file navigation.qc.

References bot_navigation_movemode, trace_fraction, tracewalk(), and vdist.

Referenced by botframe_autowaypoints_fix_from(), and navigation_findnearestwaypoint_withdist_except().

896 {
897  if (vdist(v - org, <, bestdist))
898  {
899  traceline(v, org, true, ent);
900  if (trace_fraction == 1)
901  {
902  if (walkfromwp)
903  {
904  if (tracewalk(ent, v, PL_MIN_CONST, PL_MAX_CONST, v2, v2_height, bot_navigation_movemode))
905  return true;
906  }
907  else
908  {
909  if (tracewalk(ent, org, PL_MIN_CONST, PL_MAX_CONST, o2, o2_height, bot_navigation_movemode))
910  return true;
911  }
912  }
913  }
914  return false;
915 }
vector v
Definition: ent_cs.qc:116
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float trace_fraction
Definition: csprogsdefs.qc:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ resurface_limited()

vector resurface_limited ( vector  org,
float  lim,
vector  m1 
)

Definition at line 244 of file navigation.qc.

References eZ, and WETFEET.

245 {
246  if (WETFEET(org + eZ * (lim - org.z)))
247  org.z = lim;
248  else
249  {
250  float RES_min_h = org.z;
251  float RES_max_h = lim;
252  do {
253  org.z = 0.5 * (RES_min_h + RES_max_h);
254  if(WETFEET(org))
255  RES_min_h = org.z;
256  else
257  RES_max_h = org.z;
258  } while (RES_max_h - RES_min_h >= 1);
259  org.z = RES_min_h;
260  }
261  return org;
262 }
#define WETFEET(pos)
Definition: bot.qh:86
const vector eZ
Definition: vector.qh:46

◆ 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:

◆ 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.

References autocvar_bot_debug_tracewalk, bound(), DEBUG_NODE_FAIL, DEBUG_NODE_SUCCESS, DEBUG_NODE_WARNING, debugnode(), debugnodestatus(), debugresetnodes(), eZ, IN_LAVA, jumpheight_vec, jumpstepheightvec, MOVE_NOMONSTERS, NAV_SWIM_ONWATER, NAV_SWIM_UNDERWATER, NAV_WALK, navigation_checkladders(), normalize(), RESURFACE_LIMITED, stepheightvec, SUBMERGED, trace_endpos, trace_ent, trace_fraction, trace_startsolid, v, vec2, vector(), vlen(), and WETFEET.

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

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 call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ goalcounter

float goalcounter

Definition at line 2057 of file navigation.qc.

Referenced by debuggoalstack().

◆ lastposition

vector lastposition

Definition at line 2058 of file navigation.qc.

Referenced by debuggoalstack().

◆ speed

float speed

Definition at line 17 of file navigation.qc.