.float speed;
+void navigation_goalrating_timeout_set(entity this)
+{
+ if(IS_MOVABLE(this.goalentity))
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval_movingtarget;
+ else
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+}
+
+void navigation_goalrating_timeout_force(entity this)
+{
+ this.bot_strategytime = 0;
+}
+
+bool navigation_goalrating_timeout(entity this)
+{
+ return this.bot_strategytime < time;
+}
+
void navigation_dynamicgoal_init(entity this, bool initially_static)
{
this.navigation_dynamicgoal = true;
IL_EACH(g_waypoints, it != ent && it != except,
{
if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
+ {
+ if(!autocvar_g_waypointeditor && walkfromwp && !ent.navigation_dynamicgoal)
+ {
+ waypoint_clearlinks(ent); // initialize wpXXmincost fields
+ navigation_item_addlink(it, ent);
+ }
return it;
+ }
});
vector org = ent.origin;
{
if (this.goalentity.navigation_dynamicgoal || autocvar_g_waypointeditor)
{
- SET_TRACEWALK_DESTCOORDS(e, nearest_wp.enemy.origin, dest, dest_height);
+ SET_TRACEWALK_DESTCOORDS(this.goalentity, nearest_wp.enemy.origin, dest, dest_height);
if(vdist(dest - nearest_wp.enemy.origin, <, 1050))
if(tracewalk(this, nearest_wp.enemy.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), dest, dest_height, bot_navigation_movemode))
e = nearest_wp.enemy;
// removes any currently touching waypoints from the goal stack
// (this is how bots detect if they reached a goal)
-void navigation_poptouchedgoals(entity this)
+int navigation_poptouchedgoals(entity this)
{
+ int removed_goals = 0;
if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
{
// make sure jumppad is really hit, don't rely on distance based checks
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
}
navigation_poproute(this);
+ ++removed_goals;
}
else
- return;
+ return removed_goals;
}
// If for some reason the bot is closer to the next goal, pop the current one
if(vlen2(this.goalcurrent.origin - this.origin) > vlen2(this.goalstack01.origin - this.origin))
if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
{
- vector dest = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
- dest.z = this.goalstack01.absmin.z;
- float dest_height = this.goalstack01.absmax.z - this.goalstack01.absmin.z;
+ vector dest = '0 0 0';
+ float dest_height = 0;
+ SET_TRACEWALK_DESTCOORDS(this.goalstack01, this.origin, dest, dest_height);
if(tracewalk(this, this.origin, this.mins, this.maxs, dest, dest_height, bot_navigation_movemode))
{
LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
navigation_poproute(this);
+ ++removed_goals;
if(this.goalcurrent && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
- return;
+ return removed_goals;
// TODO this may also be a nice idea to do "early" (e.g. by
// manipulating the vlen() comparisons) to shorten paths in
// general - this would make bots walk more "on rails" than
}
navigation_poproute(this);
+ ++removed_goals;
if(this.goalcurrent && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
- return;
+ return removed_goals;
}
}
}
}
navigation_poproute(this);
+ ++removed_goals;
if(this.goalcurrent && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
- return;
+ return removed_goals;
}
+ return removed_goals;
+}
+
+entity navigation_get_really_close_waypoint(entity this)
+{
+ entity wp = this.goalcurrent;
+ if(!wp || vdist(wp.origin - this.origin, >, 50))
+ wp = this.goalcurrent_prev;
+ if(!wp)
+ return NULL;
+ if(wp.classname != "waypoint")
+ {
+ wp = wp.nearestwaypoint;
+ if(!wp)
+ return NULL;
+ }
+ if(vdist(wp.origin - this.origin, >, 50))
+ {
+ IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+ {
+ if(vdist(it.origin - this.origin, <, 50))
+ {
+ wp = it;
+ break;
+ }
+ });
+ }
+ if(wp.wpflags & WAYPOINTFLAG_TELEPORT)
+ return NULL;
+
+ vector dest = '0 0 0';
+ float dest_height = 0;
+ SET_TRACEWALK_DESTCOORDS(wp, this.origin, dest, dest_height);
+ if (!tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), dest, dest_height, bot_navigation_movemode))
+ return NULL;
+ return wp;
}
// begin a goal selection session (queries spawnfunc_waypoint network)
this.navigation_jetpack_goal = NULL;
navigation_bestrating = -1;
+ entity wp = navigation_get_really_close_waypoint(this);
navigation_clearroute(this);
navigation_bestgoal = NULL;
- navigation_markroutes(this, NULL);
+ navigation_markroutes(this, wp);
}
// ends a goal selection session (updates goal stack to the best goal)
// evaluate the next goal on the queue
float d = vlen2(this.origin - bot_waypoint_queue_goal.origin);
LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with distance ", ftos(d));
- vector dest = (bot_waypoint_queue_goal.absmin + bot_waypoint_queue_goal.absmax) * 0.5;
- dest.z = bot_waypoint_queue_goal.absmin.z;
- float dest_height = bot_waypoint_queue_goal.absmax.z - bot_waypoint_queue_goal.absmin.z;
+ vector dest = '0 0 0';
+ float dest_height = 0;
+ SET_TRACEWALK_DESTCOORDS(bot_waypoint_queue_goal, this.origin, dest, dest_height);
if(tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), dest, dest_height, bot_navigation_movemode))
{
if( d > bot_waypoint_queue_bestgoalrating)
{
LOG_DEBUG(this.netname, " stuck, reachable waypoint found, heading to it");
navigation_routetogoal(this, bot_waypoint_queue_bestgoal, this.origin);
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_timeout_set(this);
this.aistatus &= ~AI_STATUS_STUCK;
}
else