#include "navigation.qh"
-#include <server/defs.qh>
-#include <server/miscfunctions.qh>
-#include "cvars.qh"
-
-#include "bot.qh"
-#include "waypoints.qh"
-
-#include <common/t_items.qh>
-
-#include <common/items/_mod.qh>
-
#include <common/constants.qh>
-#include <common/net_linked.qh>
+#include <common/items/_mod.qh>
#include <common/mapobjects/func/ladder.qh>
+#include <common/mapobjects/trigger/hurt.qh>
#include <common/mapobjects/trigger/jumppads.qh>
+#include <common/net_linked.qh>
+#include <common/stats.qh>
+#include <common/weapons/_all.qh>
+#include <server/bot/api.qh>
+#include <server/bot/default/bot.qh>
+#include <server/bot/default/cvars.qh>
+#include <server/bot/default/waypoints.qh>
+#include <server/items/items.qh>
.float speed;
return this.bot_strategytime < time;
}
+ERASEABLE
void navigation_goalrating_timeout_extend_if_needed(entity this, float seconds)
{
this.bot_strategytime = max(this.bot_strategytime, time + seconds);
bool navigation_checkladders(entity e, vector org, vector m1, vector m2, vector end, vector end2, int movemode)
{
- IL_EACH(g_ladders, it.classname == "func_ladder",
+ IL_EACH(g_ladders, true,
{
if(it.bot_pickup)
- if(boxesoverlap(org + m1 + '-1 -1 -1', org + m2 + '1 1 1', it.absmin, it.absmax))
- if(boxesoverlap(end, end2, it.absmin + vec2(m1) + '-1 -1 0', it.absmax + vec2(m2) + '1 1 0'))
+ if(boxesoverlap(org + m1, org + m2, it.absmin, it.absmax))
+ if(boxesoverlap(end, end2, it.absmin + vec2(m1), it.absmax + vec2(m2)))
{
vector top = org;
top.z = it.absmax.z + (PL_MAX_CONST.z - PL_MIN_CONST.z);
vector pm1 = ent.origin + ent.mins;
vector pm2 = ent.origin + ent.maxs;
- if (autocvar_g_waypointeditor && !IS_BOT_CLIENT(ent))
+ if (waypointeditor_enabled && !IS_BOT_CLIENT(ent))
{
// this code allows removing waypoints in the air and seeing jumppad/telepport waypoint links
// FIXME it causes a bug where a waypoint spawned really close to another one (max 16 qu)
}
else
{
- if(autocvar_g_waypointeditor && e.nearestwaypointtimeout >= 0 && time > e.nearestwaypointtimeout)
+ if(waypointeditor_enabled && e.nearestwaypointtimeout >= 0 && time > e.nearestwaypointtimeout)
e.nearestwaypoint = NULL;
if ((!e.nearestwaypoint || e.navigation_dynamicgoal)
if(e.navigation_dynamicgoal)
e.nearestwaypointtimeout = time + 2;
- else if(autocvar_g_waypointeditor)
+ else if(waypointeditor_enabled)
e.nearestwaypointtimeout = time + 3 + random() * 2;
}
nwp = e.nearestwaypoint;
this.wp_goal_prev0 = e;
}
- if(g_jetpack)
- if(e==this.navigation_jetpack_goal)
+ if((this.items & IT_JETPACK) && e == this.navigation_jetpack_goal)
return true;
// if it can reach the goal there is nothing more to do
if(nearest_wp && nearest_wp.enemy && !(nearest_wp.enemy.wpflags & WPFLAGMASK_NORELINK))
{
// often path can be optimized by not adding the nearest waypoint
- if (this.goalentity.navigation_dynamicgoal || autocvar_g_waypointeditor)
+ if (this.goalentity.navigation_dynamicgoal || waypointeditor_enabled)
{
if (nearest_wp.enemy.wpcost < autocvar_bot_ai_strategyinterval_movingtarget)
{
if(this.lastteleporttime > 0 && TELEPORT_USED(this, this.goalcurrent))
{
if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
+ if((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) && this.goalcurrent.owner==this)
{
this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
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)
+ if ((tele_ent.wpflags & WAYPOINTFLAG_PERSONAL) && tele_ent.owner == this)
{
this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
}
// Loose goal touching check when running
- if(this.aistatus & AI_STATUS_RUNNING)
- if(this.goalcurrent.classname=="waypoint")
- if(vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed)) // if -really- running
- {
- if(vdist(this.origin - this.goalcurrent.origin, <, 150))
+ // check goalstack01 to make sure waypoint isn't the final goal
+ if((this.aistatus & AI_STATUS_RUNNING) && this.goalcurrent.classname == "waypoint" && !(this.goalcurrent.wpflags & WAYPOINTFLAG_JUMP)
+ && this.goalstack01 && !wasfreed(this.goalstack01) && vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed))
+ {
+ vector gco = this.goalcurrent.origin;
+ float min_dist = BOT_BUNNYHOP_WP_DETECTION_RANGE;
+ // also detect waypoints when bot is way above them but with a narrower horizontal range
+ // so to increase chances bot ends up in the standard range (optimizes nearest waypoint finding)
+ if(vdist(this.origin - gco, <, min_dist)
+ || (vdist(vec2(this.origin - gco), <, min_dist * 0.5) && vdist(this.origin - eZ * 1.5 * min_dist - gco, <, min_dist)))
{
traceline(this.origin + this.view_ofs , this.goalcurrent.origin, true, NULL);
if(trace_fraction==1)
{
// Detect personal waypoints
if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
+ if((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) && this.goalcurrent.owner==this)
{
this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
navigation_poproute(this);
++removed_goals;
- if(this.goalcurrent && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
+ if(this.goalcurrent && (this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT))
return removed_goals;
}
}
if(this.goalcurrent.classname == "waypoint" && !this.goalcurrent.wpisbox)
{
gc_min = this.goalcurrent.origin - '1 1 1' * 12;
- gc_max = this.goalcurrent.origin + '1 1 1' * 12;
+ gc_max = this.goalcurrent.origin + '1 1 1' * 12 + eZ * (jumpheight_vec.z + STAT(PL_MIN, this).z);
}
- if (time < this.ladder_time)
+ if (this.ladder_entity)
{
if (!boxesoverlap(this.absmin, this.absmax - eZ * STAT(PL_MAX, this).z, gc_min, gc_max))
break;
// Detect personal waypoints
if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
- if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
+ if((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) && this.goalcurrent.owner==this)
{
this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
wp = this.goalcurrent_prev;
if(!wp)
return NULL;
- if(wp != this.goalcurrent_prev && vdist(wp.origin - this.origin, >, 50))
+ float min_dist = ((this.aistatus & AI_STATUS_RUNNING) ? BOT_BUNNYHOP_WP_DETECTION_RANGE : 50);
+ if(wp != this.goalcurrent_prev && vdist(wp.origin - this.origin, >, min_dist))
{
wp = this.goalcurrent_prev;
if(!wp)
if(!wp)
return NULL;
}
- if(vdist(wp.origin - this.origin, >, 50))
+ if(vdist(wp.origin - this.origin, >, min_dist))
{
wp = NULL;
IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)),
{
- if(vdist(it.origin - this.origin, <, 50))
+ if(vdist(it.origin - this.origin, <, min_dist))
{
wp = it;
break;