#include <common/constants.qh>
#include <common/net_linked.qh>
-#include <common/triggers/trigger/jumppads.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
.float speed;
// rough simulation of walking from one point to another to test if a path
// can be traveled, used for waypoint linking and havocbot
// if end_height is > 0 destination is any point in the vertical segment [end, end + end_height * eZ]
+// INFO: the command sv_cmd trace walk is useful to test this function in game
bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
{
if(autocvar_bot_debug_tracewalk)
//print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n");
// Evaluate path using jetpack
- if(g_jetpack)
if(this.items & IT_JETPACK)
if(autocvar_bot_ai_navigation_jetpack)
if(vdist(this.origin - goal_org, >, autocvar_bot_ai_navigation_jetpack_mindistance))
LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel));
// enough fuel ?
- if(this.ammo_fuel>fuel)
+ if(this.ammo_fuel>fuel || (this.items & IT_UNLIMITED_WEAPON_AMMO))
{
// Estimate cost
// (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
{
- LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
+ LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
navigation_poproute(this);
}
}
{
// make sure jumppad is really hit, don't rely on distance based checks
// as they may report a touch even if it didn't really happen
- if(this.lastteleporttime > 0
- && time - this.lastteleporttime < ((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) ? 2 : 0.15))
+ if(this.lastteleporttime > 0 && TELEPORT_USED(this, this.goalcurrent))
{
- if (this.jumppadcount && !boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax,
- this.lastteleport_origin + STAT(PL_MIN, this), this.lastteleport_origin + STAT(PL_MAX, this)))
- {
- return;
- }
-
if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
{
else
return removed_goals;
}
+ else if (this.lastteleporttime > 0)
+ {
+ // sometimes bot is pushed so hard (by a jumppad or a shot) that ends up touching the next
+ // teleport / jumppad / warpzone present in its path skipping check of one or more goals
+ // if so immediately fix bot path by removing skipped goals
+ entity tele_ent = NULL;
+ if (this.goalstack01 && (this.goalstack01.wpflags & WAYPOINTFLAG_TELEPORT))
+ tele_ent = this.goalstack01;
+ else if (this.goalstack02 && (this.goalstack02.wpflags & WAYPOINTFLAG_TELEPORT))
+ tele_ent = this.goalstack02;
+ else if (this.goalstack03 && (this.goalstack03.wpflags & WAYPOINTFLAG_TELEPORT))
+ tele_ent = this.goalstack03;
+ if (tele_ent && TELEPORT_USED(this, tele_ent))
+ {
+ if (this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
+ if (tele_ent.wpflags & WAYPOINTFLAG_PERSONAL && tele_ent.owner == this)
+ {
+ this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
+ this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
+ }
+ while (this.goalcurrent != tele_ent)
+ {
+ navigation_poproute(this);
+ ++removed_goals;
+ }
+ navigation_poproute(this);
+ this.lastteleporttime = 0;
+ ++removed_goals;
+ return removed_goals;
+ }
+ }
// Loose goal touching check when running
if(this.aistatus & AI_STATUS_RUNNING)
void navigation_unstuck(entity this)
{
- float search_radius = 1000;
-
if (!autocvar_bot_wander_enable)
return;
+ bool has_user_waypoints = false;
+ IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_GENERATED),
+ {
+ has_user_waypoints = true;
+ break;
+ });
+ if (!has_user_waypoints)
+ return;
+
+ float search_radius = 1000;
+
if (!bot_waypoint_queue_owner)
{
LOG_DEBUG(this.netname, " stuck, taking over the waypoints 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));
set_tracewalk_dest(bot_waypoint_queue_goal, this.origin, false);
- if (tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
+ if (tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
{
if( d > bot_waypoint_queue_bestgoalrating)