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

Go to the source code of this file.

Macros

#define navigation_item_add_link(from_wp, to_item, walkable)
#define navigation_item_getlinknum(to_item, from_wp)
#define navigation_item_initlinks_ifneeded(e)
#define navigation_item_iswalkablelink(to_item, from_wp)
#define SUBMERGED_NO   1
#define SUBMERGED_UNDEFINED   0
#define SUBMERGED_YES   2
#define TELEPORT_USED(pl, tele_wp)

Functions

void botframe_updatedangerousobjects (float maxupdate)
void debuggoalstack (entity this)
void debugnode (entity this, vector node)
void debugnodestatus (vector position, float status)
void debugresetnodes ()
bool navigation_check_submerged_state (entity ent, vector pos)
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)
void navigation_goalrating_end (entity this)
void navigation_goalrating_start (entity this)
bool navigation_goalrating_timeout (entity this)
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 cost2, 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)
float 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)
float tracewalk (entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)

Variables

float blacklisted
entity bot_basewaypoint
const float BOT_BUNNYHOP_WP_DETECTION_RANGE = 100
float bot_navigation_movemode
entity bot_waypoint_queue_bestgoal
float bot_waypoint_queue_bestgoalrating
entity bot_waypoint_queue_goal
entity bot_waypoint_queue_nextgoal
entity bot_waypoint_queue_owner
const float DEBUG_NODE_FAIL = 3
const float DEBUG_NODE_SUCCESS = 1
const float DEBUG_NODE_WARNING = 2
vector debuglastnode
entity goalcurrent
float goalcurrent_distance_2d
float goalcurrent_distance_time
float goalcurrent_distance_z
entity goalcurrent_prev
entity goalentity
float goalentity_lock_timeout
bool goalentity_shouldbefrozen
entity goalstack01
entity goalstack02
entity goalstack03
entity goalstack04
entity goalstack05
entity goalstack06
entity goalstack07
entity goalstack08
entity goalstack09
entity goalstack10
entity goalstack11
entity goalstack12
entity goalstack13
entity goalstack14
entity goalstack15
entity goalstack16
entity goalstack17
entity goalstack18
entity goalstack19
entity goalstack20
entity goalstack21
entity goalstack22
entity goalstack23
entity goalstack24
entity goalstack25
entity goalstack26
entity goalstack27
entity goalstack28
entity goalstack29
entity goalstack30
entity goalstack31
float jumpheight_time
vector jumpheight_vec
vector jumpstepheightvec
vector lastteleport_origin
float lastteleporttime
int nav_submerged_state
entity navigation_bestgoal
float navigation_bestrating
bool navigation_dynamicgoal
entity navigation_jetpack_goal
vector navigation_jetpack_point
float navigation_testtracewalk
entity nearestwaypoint
float nearestwaypointtimeout
vector stepheightvec
vector tracewalk_dest
float tracewalk_dest_height
entity wp_goal_prev0
entity wp_goal_prev1

Macro Definition Documentation

◆ navigation_item_add_link

#define navigation_item_add_link ( from_wp,
to_item,
walkable )
Value:
waypoint_addlink_customcost(to_item, from_wp, (walkable ? waypoint_getlinkcost(from_wp, to_item) : 999))
void waypoint_addlink_customcost(entity from, entity to, float c)
float waypoint_getlinkcost(entity from, entity to)

Definition at line 60 of file navigation.qh.

60#define navigation_item_add_link(from_wp, to_item, walkable) \
61 waypoint_addlink_customcost(to_item, from_wp, (walkable ? waypoint_getlinkcost(from_wp, to_item) : 999))

Referenced by navigation_routetogoal().

◆ navigation_item_getlinknum

#define navigation_item_getlinknum ( to_item,
from_wp )
Value:
waypoint_getlinknum(to_item, from_wp)
int waypoint_getlinknum(entity from, entity to)
Definition waypoints.qc:953

Definition at line 57 of file navigation.qh.

Referenced by navigation_routetogoal().

◆ navigation_item_initlinks_ifneeded

#define navigation_item_initlinks_ifneeded ( e)
Value:
#define MACRO_END
Definition macro.qh:7
#define MACRO_BEGIN
Definition macro.qh:6
void waypoint_clearlinks(entity wp)

Definition at line 56 of file navigation.qh.

Referenced by navigation_routetogoal().

◆ navigation_item_iswalkablelink

#define navigation_item_iswalkablelink ( to_item,
from_wp )
Value:
(waypoint_get_assigned_link_cost(to_item, from_wp) < 999)
float waypoint_get_assigned_link_cost(entity w, float i)

Definition at line 58 of file navigation.qh.

Referenced by navigation_routetogoal().

◆ SUBMERGED_NO

#define SUBMERGED_NO   1

Definition at line 101 of file navigation.qh.

Referenced by navigation_check_submerged_state().

◆ SUBMERGED_UNDEFINED

#define SUBMERGED_UNDEFINED   0

Definition at line 100 of file navigation.qh.

Referenced by navigation_check_submerged_state().

◆ SUBMERGED_YES

#define SUBMERGED_YES   2

Definition at line 102 of file navigation.qh.

Referenced by navigation_check_submerged_state().

◆ TELEPORT_USED

#define TELEPORT_USED ( pl,
tele_wp )
Value:
boxesoverlap(tele_wp.absmin, tele_wp.absmax, pl.lastteleport_origin + STAT(PL_MIN, pl), pl.lastteleport_origin + STAT(PL_MAX, pl))
#define STAT(...)
Definition stats.qh:82
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

Definition at line 63 of file navigation.qh.

63#define TELEPORT_USED(pl, tele_wp) \
64 boxesoverlap(tele_wp.absmin, tele_wp.absmax, pl.lastteleport_origin + STAT(PL_MIN, pl), pl.lastteleport_origin + STAT(PL_MAX, pl))

Referenced by navigation_poptouchedgoals().

Function Documentation

◆ botframe_updatedangerousobjects()

void botframe_updatedangerousobjects ( float maxupdate)

Definition at line 1874 of file navigation.qc.

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

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

Referenced by bot_serverframe().

◆ debuggoalstack()

void debuggoalstack ( entity this)

Definition at line 2062 of file navigation.qc.

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

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, org, origin, and vector.

Referenced by havocbot_moveto(), and havocbot_movetogoal().

◆ debugnode()

void debugnode ( entity this,
vector node )

Definition at line 2019 of file navigation.qc.

2020{
2021 if (!IS_PLAYER(this))
2022 return;
2023
2024 if(debuglastnode=='0 0 0')
2025 {
2026 debuglastnode = node;
2027 return;
2028 }
2029
2030 te_lightning2(NULL, node, debuglastnode);
2031 debuglastnode = node;
2032}
#define IS_PLAYER(s)
Definition player.qh:243
vector debuglastnode
Definition navigation.qh:83

References debuglastnode, entity(), IS_PLAYER, NULL, and vector.

Referenced by tracewalk().

◆ debugnodestatus()

void debugnodestatus ( vector position,
float status )

Definition at line 2034 of file navigation.qc.

2035{
2036 vector c;
2037
2038 switch (status)
2039 {
2040 case DEBUG_NODE_SUCCESS:
2041 c = '0 15 0';
2042 break;
2043 case DEBUG_NODE_WARNING:
2044 c = '15 15 0';
2045 break;
2046 case DEBUG_NODE_FAIL:
2047 c = '15 0 0';
2048 break;
2049 default:
2050 c = '15 15 15';
2051 }
2052
2053 te_customflash(position, 40, 2, c);
2054}
const float DEBUG_NODE_SUCCESS
Definition navigation.qh:80
const float DEBUG_NODE_WARNING
Definition navigation.qh:81
const float DEBUG_NODE_FAIL
Definition navigation.qh:82

References DEBUG_NODE_FAIL, DEBUG_NODE_SUCCESS, DEBUG_NODE_WARNING, and vector.

Referenced by tracewalk().

◆ debugresetnodes()

void debugresetnodes ( )

Definition at line 2014 of file navigation.qc.

2015{
2016 debuglastnode = '0 0 0';
2017}

References debuglastnode.

Referenced by tracewalk().

◆ navigation_check_submerged_state()

bool navigation_check_submerged_state ( entity ent,
vector pos )

Definition at line 204 of file navigation.qc.

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

References entity(), IS_PLAYER, SUBMERGED, SUBMERGED_NO, SUBMERGED_UNDEFINED, SUBMERGED_YES, vector, and WATERLEVEL_SUBMERGED.

Referenced by waypoint_gettravelcost().

◆ navigation_clearroute()

void navigation_clearroute ( entity this)

Definition at line 751 of file navigation.qc.

752{
753 this.lastteleporttime = 0;
754 this.goalcurrent_prev = this.goalcurrent;
759 this.goalentity_shouldbefrozen = false;
760 this.goalentity = NULL;
761 this.goalcurrent = NULL;
762 this.goalstack01 = NULL;
763 this.goalstack02 = NULL;
764 this.goalstack03 = NULL;
765 this.goalstack04 = NULL;
766 this.goalstack05 = NULL;
767 this.goalstack06 = NULL;
768 this.goalstack07 = NULL;
769 this.goalstack08 = NULL;
770 this.goalstack09 = NULL;
771 this.goalstack10 = NULL;
772 this.goalstack11 = NULL;
773 this.goalstack12 = NULL;
774 this.goalstack13 = NULL;
775 this.goalstack14 = NULL;
776 this.goalstack15 = NULL;
777 this.goalstack16 = NULL;
778 this.goalstack17 = NULL;
779 this.goalstack18 = NULL;
780 this.goalstack19 = NULL;
781 this.goalstack20 = NULL;
782 this.goalstack21 = NULL;
783 this.goalstack22 = NULL;
784 this.goalstack23 = NULL;
785 this.goalstack24 = NULL;
786 this.goalstack25 = NULL;
787 this.goalstack26 = NULL;
788 this.goalstack27 = NULL;
789 this.goalstack28 = NULL;
790 this.goalstack29 = NULL;
791 this.goalstack30 = NULL;
792 this.goalstack31 = NULL;
793}
float lastteleporttime
Definition api.qh:50
float goalentity_lock_timeout
Definition api.qh:97
const float FLOAT_MAX
Definition float.qh:3
entity goalentity
Definition viewloc.qh:16
bool goalentity_shouldbefrozen
Definition navigation.qh:36
float goalcurrent_distance_2d
Definition navigation.qh:30
float goalcurrent_distance_time
Definition navigation.qh:31
entity goalcurrent_prev
Definition navigation.qh:28
float goalcurrent_distance_z
Definition navigation.qh:29

References entity(), 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().

◆ navigation_dynamicgoal_init()

void navigation_dynamicgoal_init ( entity this,
bool initially_static )

Definition at line 77 of file navigation.qc.

78{
79 this.navigation_dynamicgoal = true;
81 if(initially_static)
82 this.nearestwaypointtimeout = -1;
83 else
85}
entity bot_basewaypoint
Definition api.qh:106
float nearestwaypointtimeout
Definition api.qh:53
entity nearestwaypoint
Definition api.qh:54
bool navigation_dynamicgoal
Definition api.qh:107
float time

◆ navigation_dynamicgoal_set()

void navigation_dynamicgoal_set ( entity this,
entity dropper )

Definition at line 87 of file navigation.qc.

88{
90 if (dropper && dropper.nearestwaypointtimeout && dropper.nearestwaypointtimeout < time + 2)
91 this.nearestwaypoint = dropper.nearestwaypoint;
92 if (this.nearestwaypoint)
93 this.nearestwaypointtimeout += 2;
94}

◆ navigation_dynamicgoal_unset()

void navigation_dynamicgoal_unset ( entity this)

Definition at line 96 of file navigation.qc.

97{
98 if(this.bot_basewaypoint)
100 this.nearestwaypointtimeout = -1;
101}

◆ navigation_findnearestwaypoint()

entity navigation_findnearestwaypoint ( entity ent,
float walkfromwp )

Definition at line 1012 of file navigation.qc.

1013{
1014 entity wp = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, NULL);
1016 {
1017 entity wp2 = navigation_findnearestwaypoint_withdist_except(ent, walkfromwp, 1050, wp);
1018 if (wp && !wp2)
1019 wp.wpflags |= WAYPOINTFLAG_PROTECTED;
1020 }
1021 return wp;
1022}
const int WAYPOINTFLAG_PROTECTED
Definition api.qh:16
int autocvar_g_waypointeditor_auto
Definition cvars.qh:60
entity navigation_findnearestwaypoint_withdist_except(entity ent, float walkfromwp, float bestdist, entity except)

◆ navigation_goalrating_end()

void navigation_goalrating_end ( entity this)

Definition at line 1846 of file navigation.qc.

1847{
1848 if(this.aistatus & AI_STATUS_STUCK)
1849 return;
1850
1851 entity wp = this.goalstack31; // save to wp as this.goalstack31 is set by navigation_routetogoal
1852 this.goalstack31 = NULL;
1853
1855 LOG_DEBUG("best goal ", navigation_bestgoal.classname);
1856
1857 if (wp && this.goalcurrent == wp)
1858 navigation_poproute(this);
1859
1860 // If the bot got stuck then try to reach the farthest waypoint
1861 if (!this.goalentity)
1862 {
1864 {
1865 LOG_DEBUG(this.netname, " cannot walk to any goal");
1866 this.aistatus |= AI_STATUS_STUCK;
1867 }
1868 this.goalentity_shouldbefrozen = false;
1869 }
1870 else
1871 this.goalentity_shouldbefrozen = boolean(STAT(FROZEN, this.goalentity));
1872}
#define boolean(value)
Definition bool.qh:9
int aistatus
Definition bot.qh:20
const int AI_STATUS_STUCK
Definition bot.qh:17
string netname
Definition powerups.qc:20
bool autocvar_bot_wander_enable
Definition cvars.qh:57
#define LOG_DEBUG(...)
Definition log.qh:80
bool navigation_routetogoal(entity this, entity e, vector startposition)
void navigation_poproute(entity this)
entity navigation_bestgoal
Definition navigation.qh:15

◆ navigation_goalrating_start()

void navigation_goalrating_start ( entity this)

Definition at line 1831 of file navigation.qc.

1832{
1833 if(this.aistatus & AI_STATUS_STUCK)
1834 return;
1835
1841 navigation_markroutes(this, wp);
1842 this.goalstack31 = wp; // temporarly save the really close waypoint
1843}
entity navigation_get_really_close_waypoint(entity this)
void navigation_markroutes(entity this, entity fixed_source_waypoint)
void navigation_clearroute(entity this)
entity navigation_jetpack_goal
Definition navigation.qh:77
float navigation_bestrating
Definition navigation.qh:6

◆ navigation_goalrating_timeout()

bool navigation_goalrating_timeout ( entity this)

Definition at line 44 of file navigation.qc.

45{
46 return this.bot_strategytime < time;
47}
float bot_strategytime
Definition bot.qh:70

◆ navigation_goalrating_timeout_force()

void navigation_goalrating_timeout_force ( entity this)

Definition at line 29 of file navigation.qc.

30{
32}
void navigation_goalrating_timeout_expire(entity this, float seconds)
Definition navigation.qc:36

◆ navigation_goalrating_timeout_set()

void navigation_goalrating_timeout_set ( entity this)

Definition at line 20 of file navigation.qc.

21{
22 if(IS_MOVABLE(this.goalentity))
24 else
26}
float autocvar_bot_ai_strategyinterval_movingtarget
Definition cvars.qh:66
float autocvar_bot_ai_strategyinterval
Definition cvars.qh:65
#define IS_MOVABLE(v)
Definition utils.qh:25

Referenced by navigation_unstuck().

◆ navigation_markroutes()

void navigation_markroutes ( entity this,
entity fixed_source_waypoint )

Definition at line 1082 of file navigation.qc.

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

Referenced by navigation_goalrating_start().

◆ navigation_markroutes_checkwaypoint()

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

Definition at line 1054 of file navigation.qc.

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

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

◆ navigation_markroutes_inverted()

void navigation_markroutes_inverted ( entity fixed_source_waypoint)

Definition at line 1172 of file navigation.qc.

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

◆ navigation_markroutes_nearestwaypoints()

float navigation_markroutes_nearestwaypoints ( entity this,
float maxdist )

Definition at line 1025 of file navigation.qc.

1026{
1027 //navigation_testtracewalk = true;
1028 int c = 0;
1029 IL_EACH(g_waypoints, !it.wpconsidered,
1030 {
1031 set_tracewalk_dest(it, this.origin, false);
1032
1033 vector diff = tracewalk_dest - this.origin;
1034 diff.z = max(0, diff.z);
1035 if(vdist(diff, <, maxdist))
1036 {
1037 it.wpconsidered = true;
1038 if (tracewalk(this, this.origin, this.mins, this.maxs,
1039 tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
1040 {
1041 it.wpnearestpoint = tracewalk_dest;
1042 it.wpcost = waypoint_gettravelcost(this.origin, tracewalk_dest, this, it) + it.dmg;
1043 it.wpfire = 1;
1044 it.enemy = NULL;
1045 c = c + 1;
1046 }
1047 }
1048 });
1049 //navigation_testtracewalk = false;
1050 return c;
1051}

References entity(), g_waypoints, and IL_EACH.

Referenced by navigation_markroutes().

◆ navigation_poproute()

void navigation_poproute ( entity this)

Definition at line 847 of file navigation.qc.

848{
849 this.goalcurrent_prev = this.goalcurrent;
853 //print("bot ", etos(this), " pop\n");
854 if(this.goalcurrent == this.goalentity)
855 {
856 this.goalentity = NULL;
858 }
859 this.goalcurrent = this.goalstack01;
860 this.goalstack01 = this.goalstack02;
861 this.goalstack02 = this.goalstack03;
862 this.goalstack03 = this.goalstack04;
863 this.goalstack04 = this.goalstack05;
864 this.goalstack05 = this.goalstack06;
865 this.goalstack06 = this.goalstack07;
866 this.goalstack07 = this.goalstack08;
867 this.goalstack08 = this.goalstack09;
868 this.goalstack09 = this.goalstack10;
869 this.goalstack10 = this.goalstack11;
870 this.goalstack11 = this.goalstack12;
871 this.goalstack12 = this.goalstack13;
872 this.goalstack13 = this.goalstack14;
873 this.goalstack14 = this.goalstack15;
874 this.goalstack15 = this.goalstack16;
875 this.goalstack16 = this.goalstack17;
876 this.goalstack17 = this.goalstack18;
877 this.goalstack18 = this.goalstack19;
878 this.goalstack19 = this.goalstack20;
879 this.goalstack20 = this.goalstack21;
880 this.goalstack21 = this.goalstack22;
881 this.goalstack22 = this.goalstack23;
882 this.goalstack23 = this.goalstack24;
883 this.goalstack24 = this.goalstack25;
884 this.goalstack25 = this.goalstack26;
885 this.goalstack26 = this.goalstack27;
886 this.goalstack27 = this.goalstack28;
887 this.goalstack28 = this.goalstack29;
888 this.goalstack29 = this.goalstack30;
889 this.goalstack30 = this.goalstack31;
890 this.goalstack31 = NULL;
891}

References entity(), 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().

◆ navigation_poptouchedgoals()

int navigation_poptouchedgoals ( entity this)

Definition at line 1630 of file navigation.qc.

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

References absmax, absmin, AI_STATUS_RUNNING, AI_STATUS_WAYPOINT_PERSONAL_GOING, AI_STATUS_WAYPOINT_PERSONAL_REACHED, aistatus, autocvar_sv_maxspeed, 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(), STAT, TELEPORT_USED, time, trace_fraction, vdist, vec2, vector, velocity, view_ofs, vlen2, WAYPOINTFLAG_JUMP, WAYPOINTFLAG_PERSONAL, and WAYPOINTFLAG_TELEPORT.

Referenced by havocbot_movetogoal().

◆ navigation_pushroute()

void navigation_pushroute ( entity this,
entity e )

Definition at line 801 of file navigation.qc.

802{
803 this.goalcurrent_prev = this.goalcurrent;
807 //print("bot ", etos(this), " push ", etos(e), "\n");
808 if(this.goalstack31 == this.goalentity)
809 this.goalentity = NULL;
810 this.goalstack31 = this.goalstack30;
811 this.goalstack30 = this.goalstack29;
812 this.goalstack29 = this.goalstack28;
813 this.goalstack28 = this.goalstack27;
814 this.goalstack27 = this.goalstack26;
815 this.goalstack26 = this.goalstack25;
816 this.goalstack25 = this.goalstack24;
817 this.goalstack24 = this.goalstack23;
818 this.goalstack23 = this.goalstack22;
819 this.goalstack22 = this.goalstack21;
820 this.goalstack21 = this.goalstack20;
821 this.goalstack20 = this.goalstack19;
822 this.goalstack19 = this.goalstack18;
823 this.goalstack18 = this.goalstack17;
824 this.goalstack17 = this.goalstack16;
825 this.goalstack16 = this.goalstack15;
826 this.goalstack15 = this.goalstack14;
827 this.goalstack14 = this.goalstack13;
828 this.goalstack13 = this.goalstack12;
829 this.goalstack12 = this.goalstack11;
830 this.goalstack11 = this.goalstack10;
831 this.goalstack10 = this.goalstack09;
832 this.goalstack09 = this.goalstack08;
833 this.goalstack08 = this.goalstack07;
834 this.goalstack07 = this.goalstack06;
835 this.goalstack06 = this.goalstack05;
836 this.goalstack05 = this.goalstack04;
837 this.goalstack04 = this.goalstack03;
838 this.goalstack03 = this.goalstack02;
839 this.goalstack02 = this.goalstack01;
840 this.goalstack01 = this.goalcurrent;
841 this.goalcurrent = e;
842}

References entity(), 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().

◆ navigation_routerating()

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

Definition at line 1221 of file navigation.qc.

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

◆ navigation_routetogoal()

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

Definition at line 1430 of file navigation.qc.

1431{
1432 // if there is no goal, just exit
1433 if (!e)
1434 return false;
1435
1436 entity teleport_goal = NULL;
1437
1438 this.goalentity = e;
1439
1440 if(e.wpflags & WAYPOINTFLAG_TELEPORT)
1441 {
1442 // force teleport destination as route destination
1443 teleport_goal = e;
1444 navigation_pushroute(this, e.wp00);
1445 this.goalentity = e.wp00;
1446 }
1447
1448 // put the entity on the goal stack
1449 //print("routetogoal ", etos(e), "\n");
1450 navigation_pushroute(this, e);
1451
1452 if(teleport_goal)
1453 e = this.goalentity;
1454
1455 if(e.classname == "waypoint" && !(e.wpflags & WAYPOINTFLAG_PERSONAL))
1456 {
1457 this.wp_goal_prev1 = this.wp_goal_prev0;
1458 this.wp_goal_prev0 = e;
1459 }
1460
1461 if((this.items & IT_JETPACK) && e == this.navigation_jetpack_goal)
1462 return true;
1463
1464 // if it can reach the goal there is nothing more to do
1465 set_tracewalk_dest(e, startposition, true);
1467 && (trace_ent == this || tracewalk(this, startposition, STAT(PL_MIN, this), STAT(PL_MAX, this),
1469 {
1470 return true;
1471 }
1472
1473 entity nearest_wp = NULL;
1474 // see if there are waypoints describing a path to the item
1475 if(e.classname != "waypoint" || (e.wpflags & WAYPOINTFLAG_PERSONAL))
1476 {
1477 e = e.nearestwaypoint;
1478 nearest_wp = e;
1479 }
1480 else if(teleport_goal)
1481 e = teleport_goal;
1482 else
1483 e = e.enemy; // we already have added it, so...
1484
1485 if(e == NULL)
1486 return false;
1487
1488 if(nearest_wp && nearest_wp.enemy && !(nearest_wp.enemy.wpflags & WPFLAGMASK_NORELINK))
1489 {
1490 // often path can be optimized by not adding the nearest waypoint
1491 if (this.goalentity.navigation_dynamicgoal || waypointeditor_enabled)
1492 {
1493 if (nearest_wp.enemy.wpcost < autocvar_bot_ai_strategyinterval_movingtarget)
1494 {
1495 if (vdist(vec2(this.goalentity.origin - nearest_wp.origin), <, 32))
1496 e = nearest_wp.enemy;
1497 else
1498 {
1499 set_tracewalk_dest(this.goalentity, nearest_wp.enemy.origin, true);
1500 if (trace_ent == this || (vdist(tracewalk_dest - nearest_wp.enemy.origin, <, 1050)
1501 && vlen2(tracewalk_dest - nearest_wp.enemy.origin) < vlen2(nearest_wp.origin - nearest_wp.enemy.origin)
1502 && tracewalk(this, nearest_wp.enemy.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
1504 {
1505 e = nearest_wp.enemy;
1506 }
1507 }
1508 }
1509 }
1510 else
1511 {
1512 // NOTE unlike waypoints, items hold incoming links
1514 int link_num = navigation_item_getlinknum(this.goalentity, nearest_wp.enemy);
1515 if (link_num >= 0)
1516 {
1517 if (navigation_item_iswalkablelink(this.goalentity, link_num))
1518 e = nearest_wp.enemy;
1519 }
1520 else // untested link
1521 {
1522 entity wp = nearest_wp.enemy;
1523 entity goal = this.goalentity;
1524 bool walkable = false;
1525 if (checkpvs(wp.origin, goal))
1526 {
1527 set_tracewalk_dest(goal, wp.origin, false);
1528 if (vdist(tracewalk_dest - wp.origin, <, 1050)
1529 && tracewalk(goal, wp.origin, PL_MIN_CONST, PL_MAX_CONST,
1531 {
1532 walkable = true;
1533 e = nearest_wp.enemy;
1534 }
1535 }
1536 navigation_item_add_link(wp, goal, walkable);
1537 }
1538 }
1539 }
1540
1541 for (;;)
1542 {
1543 // add the spawnfunc_waypoint to the path
1544 navigation_pushroute(this, e);
1545 e = e.enemy;
1546
1547 if(e==NULL)
1548 break;
1549 }
1550
1551 return false;
1552}
bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
const int WPFLAGMASK_NORELINK
Definition api.qh:29
const vector PL_MIN_CONST
Definition constants.qh:56
const vector PL_MAX_CONST
Definition constants.qh:55
entity trace_ent
float checkpvs(vector viewpos, entity viewee)
void set_tracewalk_dest(entity ent, vector org, bool fix_player_dest)
bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
#define MAX_CHASE_DISTANCE
Definition navigation.qc:55
void navigation_pushroute(entity this, entity e)
entity wp_goal_prev1
Definition navigation.qh:70
float bot_navigation_movemode
Definition navigation.qh:7
#define navigation_item_getlinknum(to_item, from_wp)
Definition navigation.qh:57
#define navigation_item_iswalkablelink(to_item, from_wp)
Definition navigation.qh:58
#define navigation_item_initlinks_ifneeded(e)
Definition navigation.qh:56
vector tracewalk_dest
Definition navigation.qh:66
float tracewalk_dest_height
Definition navigation.qh:67
entity wp_goal_prev0
Definition navigation.qh:69
#define navigation_item_add_link(from_wp, to_item, walkable)
Definition navigation.qh:60

References autocvar_bot_ai_strategyinterval_movingtarget, bot_navigation_movemode, checkpvs(), entity(), goalcurrent, goalentity, IS_MOVABLE, IT_JETPACK, 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, PL_MAX_CONST, PL_MIN_CONST, set_tracewalk_dest(), STAT, trace_ent, tracewalk(), tracewalk_dest, tracewalk_dest_height, vdist, vec2, vector, 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().

◆ navigation_shortenpath()

bool navigation_shortenpath ( entity this)

Definition at line 1555 of file navigation.qc.

1556{
1557 if (!this.goalstack01 || wasfreed(this.goalstack01))
1558 return false;
1559 if (this.bot_tracewalk_time > time)
1560 return false;
1561 this.bot_tracewalk_time = max(time, this.bot_tracewalk_time) + 0.25;
1562
1563 bool cut_allowed = false;
1564 entity next = this.goalentity;
1565 // evaluate whether bot can discard current route and chase directly a player, trying to
1566 // keep waypoint route as long as possible, as it is safer and faster (bot can bunnyhop)
1567 if (IS_MOVABLE(next))
1568 {
1569 set_tracewalk_dest(next, this.origin, true);
1570 if (vdist(this.origin - tracewalk_dest, <, 200))
1571 cut_allowed = true;
1572 else if (vdist(tracewalk_dest - this.origin, <, MAX_CHASE_DISTANCE)
1573 && vdist(tracewalk_dest - this.goalcurrent.origin, >, 200)
1574 && vdist(this.origin - this.goalcurrent.origin, >, 100)
1575 && checkpvs(this.origin + this.view_ofs, next))
1576 {
1577 if (vlen2(next.origin - this.origin) < vlen2(this.goalcurrent.origin - this.origin))
1578 cut_allowed = true;
1579 else
1580 {
1581 vector deviation = vectoangles(this.goalcurrent.origin - this.origin) - vectoangles(next.origin - this.origin);
1582 while (deviation.y < -180) deviation.y += 360;
1583 while (deviation.y > 180) deviation.y -= 360;
1584 if (fabs(deviation.y) > 25)
1585 cut_allowed = true;
1586 }
1587 }
1588 if (cut_allowed)
1589 {
1590 if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
1592 {
1593 LOG_DEBUG("path optimized for ", this.netname, ", route cleared");
1594 do
1595 {
1596 navigation_poproute(this);
1597 }
1598 while (this.goalcurrent != next);
1599 return true;
1600 }
1601 return false;
1602 }
1603 }
1604
1605 next = this.goalstack01;
1606 // if for some reason the bot is closer to the next goal, pop the current one
1608 && vlen2(this.goalcurrent.origin - next.origin) > vlen2(next.origin - this.origin)
1609 && checkpvs(this.origin + this.view_ofs, next))
1610 {
1611 set_tracewalk_dest(next, this.origin, true);
1612 cut_allowed = true;
1613 }
1614
1615 if (cut_allowed)
1616 {
1617 if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
1619 {
1620 LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
1621 navigation_poproute(this);
1622 return true;
1623 }
1624 }
1625 return false;
1626}
float bot_tracewalk_time
Definition api.qh:37
vector mins
vector maxs
next
Definition all.qh:93
vector vectoangles(vector v)
float max(float f,...)

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().

◆ navigation_unstuck()

void navigation_unstuck ( entity this)

Definition at line 1908 of file navigation.qc.

1909{
1911 return;
1912
1913 bool has_user_waypoints = false;
1915 {
1916 has_user_waypoints = true;
1917 break;
1918 });
1919 if (!has_user_waypoints)
1920 return;
1921
1922 float search_radius = 1000;
1923
1925 {
1926 LOG_DEBUG(this.netname, " stuck, taking over the waypoints queue");
1930 }
1931
1932 if(bot_waypoint_queue_owner!=this)
1933 return;
1934
1936 {
1937 // evaluate the next goal on the queue
1938 float d = vlen2(this.origin - bot_waypoint_queue_goal.origin);
1939 LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with squared distance ", ftos(d));
1941 if (tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
1943 {
1945 {
1948 }
1949 }
1950
1951 // move to a random waypoint while bot is searching for a walkable path;
1952 // this is usually sufficient to unstuck bots from bad spots or when other
1953 // bots of the same team block all their ways
1954 if (!bot_waypoint_queue_bestgoal && (!this.goalentity || random() < 0.1))
1955 {
1959 }
1960
1961 bot_waypoint_queue_goal = bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal;
1962
1964 {
1966 {
1967 LOG_DEBUG(this.netname, " stuck, reachable waypoint found, heading to it");
1971 this.aistatus &= ~AI_STATUS_STUCK;
1972 }
1973 else
1974 {
1975 LOG_DEBUG(this.netname, " stuck, cannot walk to any waypoint at all");
1976 }
1977
1979 }
1980 }
1981 else
1982 {
1983 if(bot_strategytoken!=this)
1984 return;
1985
1986 // build a new queue
1987 LOG_DEBUG(this.netname, " stuck, scanning reachable waypoints within ", ftos(search_radius)," qu");
1988
1989 entity first = NULL;
1990
1991 FOREACH_ENTITY_RADIUS(this.origin, search_radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
1992 {
1993 if(bot_waypoint_queue_goal)
1994 bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = it;
1995 else
1996 first = it;
1997
1998 bot_waypoint_queue_goal = it;
1999 bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = NULL;
2000 });
2001
2002 if (first)
2004 else
2005 {
2006 LOG_DEBUG(this.netname, " stuck, cannot walk to any waypoint at all");
2008 }
2009 }
2010}
const int WAYPOINTFLAG_GENERATED
Definition api.qh:11
entity bot_strategytoken
Definition bot.qh:77
#define FOREACH_ENTITY_RADIUS(org, dist, cond, body)
Definition iter.qh:160
void navigation_goalrating_timeout_set(entity this)
Definition navigation.qc:20
entity bot_waypoint_queue_bestgoal
Definition navigation.qh:88
float bot_waypoint_queue_bestgoalrating
Definition navigation.qh:89
entity bot_waypoint_queue_owner
Definition navigation.qh:85
entity bot_waypoint_queue_goal
Definition navigation.qh:86

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(), FOREACH_ENTITY_RADIUS, 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(), STAT, tracewalk(), tracewalk_dest, tracewalk_dest_height, vlen2, and WAYPOINTFLAG_GENERATED.

Referenced by bot_think().

◆ 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 896 of file navigation.qc.

897{
898 if (vdist(v - org, <, bestdist))
899 {
900 traceline(v, org, true, ent);
901 if (trace_fraction == 1)
902 {
903 if (walkfromwp)
904 {
905 if (tracewalk(ent, v, PL_MIN_CONST, PL_MAX_CONST, v2, v2_height, bot_navigation_movemode))
906 return true;
907 }
908 else
909 {
911 return true;
912 }
913 }
914 }
915 return false;
916}

References bot_navigation_movemode, entity(), org, PL_MAX_CONST, PL_MIN_CONST, trace_fraction, tracewalk(), vdist, and vector.

Referenced by botframe_autowaypoints_fix_from().

◆ tracewalk()

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

Definition at line 274 of file navigation.qc.

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

Referenced by navigation_routetogoal(), navigation_shortenpath(), navigation_unstuck(), and navigation_waypoint_will_link().

Variable Documentation

◆ blacklisted

float blacklisted

Definition at line 75 of file navigation.qh.

◆ bot_basewaypoint

entity bot_basewaypoint

Definition at line 93 of file navigation.qh.

◆ BOT_BUNNYHOP_WP_DETECTION_RANGE

const float BOT_BUNNYHOP_WP_DETECTION_RANGE = 100

◆ bot_navigation_movemode

◆ bot_waypoint_queue_bestgoal

entity bot_waypoint_queue_bestgoal

Definition at line 88 of file navigation.qh.

Referenced by navigation_unstuck().

◆ bot_waypoint_queue_bestgoalrating

float bot_waypoint_queue_bestgoalrating

Definition at line 89 of file navigation.qh.

Referenced by navigation_unstuck().

◆ bot_waypoint_queue_goal

entity bot_waypoint_queue_goal

Definition at line 86 of file navigation.qh.

Referenced by navigation_unstuck().

◆ bot_waypoint_queue_nextgoal

entity bot_waypoint_queue_nextgoal

Definition at line 87 of file navigation.qh.

◆ bot_waypoint_queue_owner

entity bot_waypoint_queue_owner

Definition at line 85 of file navigation.qh.

Referenced by bot_clientdisconnect(), bot_think(), and navigation_unstuck().

◆ DEBUG_NODE_FAIL

const float DEBUG_NODE_FAIL = 3

Definition at line 82 of file navigation.qh.

Referenced by debugnodestatus(), and tracewalk().

◆ DEBUG_NODE_SUCCESS

const float DEBUG_NODE_SUCCESS = 1

Definition at line 80 of file navigation.qh.

Referenced by debugnodestatus(), and tracewalk().

◆ DEBUG_NODE_WARNING

const float DEBUG_NODE_WARNING = 2

Definition at line 81 of file navigation.qh.

Referenced by debugnodestatus(), and tracewalk().

◆ debuglastnode

vector debuglastnode

Definition at line 83 of file navigation.qh.

Referenced by debugnode(), and debugresetnodes().

◆ goalcurrent

◆ goalcurrent_distance_2d

◆ goalcurrent_distance_time

◆ goalcurrent_distance_z

◆ goalcurrent_prev

◆ goalentity

entity goalentity

Definition at line 34 of file navigation.qh.

◆ goalentity_lock_timeout

float goalentity_lock_timeout

Definition at line 35 of file navigation.qh.

◆ goalentity_shouldbefrozen

bool goalentity_shouldbefrozen

◆ goalstack01

◆ goalstack02

◆ goalstack03

◆ goalstack04

entity goalstack04

◆ goalstack05

entity goalstack05

◆ goalstack06

entity goalstack06

◆ goalstack07

entity goalstack07

◆ goalstack08

entity goalstack08

◆ goalstack09

entity goalstack09

◆ goalstack10

entity goalstack10

◆ goalstack11

entity goalstack11

◆ goalstack12

entity goalstack12

◆ goalstack13

entity goalstack13

◆ goalstack14

entity goalstack14

◆ goalstack15

entity goalstack15

◆ goalstack16

entity goalstack16

◆ goalstack17

entity goalstack17

◆ goalstack18

entity goalstack18

◆ goalstack19

entity goalstack19

◆ goalstack20

entity goalstack20

◆ goalstack21

entity goalstack21

◆ goalstack22

entity goalstack22

◆ goalstack23

entity goalstack23

◆ goalstack24

entity goalstack24

◆ goalstack25

entity goalstack25

◆ goalstack26

entity goalstack26

◆ goalstack27

entity goalstack27

◆ goalstack28

entity goalstack28

◆ goalstack29

entity goalstack29

◆ goalstack30

entity goalstack30

◆ goalstack31

◆ jumpheight_time

float jumpheight_time

Definition at line 13 of file navigation.qh.

Referenced by bot_calculate_stepheightvec(), and waypoint_gettravelcost().

◆ jumpheight_vec

◆ jumpstepheightvec

vector jumpstepheightvec

◆ lastteleport_origin

vector lastteleport_origin

Definition at line 73 of file navigation.qh.

◆ lastteleporttime

float lastteleporttime

Definition at line 72 of file navigation.qh.

◆ nav_submerged_state

int nav_submerged_state

Definition at line 99 of file navigation.qh.

◆ navigation_bestgoal

entity navigation_bestgoal

◆ navigation_bestrating

float navigation_bestrating

Definition at line 6 of file navigation.qh.

Referenced by navigation_goalrating_start().

◆ navigation_dynamicgoal

bool navigation_dynamicgoal

Definition at line 94 of file navigation.qh.

◆ navigation_jetpack_goal

entity navigation_jetpack_goal

◆ navigation_jetpack_point

vector navigation_jetpack_point

Definition at line 78 of file navigation.qh.

Referenced by havocbot_movetogoal().

◆ navigation_testtracewalk

float navigation_testtracewalk

Definition at line 8 of file navigation.qh.

Referenced by waypoint_think().

◆ nearestwaypoint

entity nearestwaypoint

Definition at line 38 of file navigation.qh.

◆ nearestwaypointtimeout

float nearestwaypointtimeout

Definition at line 39 of file navigation.qh.

◆ stepheightvec

◆ tracewalk_dest

◆ tracewalk_dest_height

◆ wp_goal_prev0

entity wp_goal_prev0

Definition at line 69 of file navigation.qh.

Referenced by navigation_routetogoal().

◆ wp_goal_prev1

entity wp_goal_prev1

Definition at line 70 of file navigation.qh.

Referenced by navigation_routetogoal().