if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
if(this.goalstack01 && !wasfreed(this.goalstack01))
+ if (!(this.goalstack01.wpflags & WAYPOINTFLAG_JUMP))
{
vector gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
// return true when bot isn't getting closer to the current goal
bool havocbot_checkgoaldistance(entity this, vector gco)
{
+ if (this.bot_stop_moving_timeout > time)
+ return false;
float curr_dist_z = max(20, fabs(this.origin.z - gco.z));
float curr_dist_2d = max(20, vlen(vec2(this.origin - gco)));
float distance_time = this.goalcurrent_distance_time;
return;
}
else if(!this.jumppadcount && !this.goalcurrent.wphardwired
+ && !(this.goalcurrent_prev && this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP)
&& GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR) > ROCKETJUMP_DAMAGE())
{
if(this.velocity.z < 0)
vector flat_diff = vec2(diff);
offset = max(32, current_speed * cos(deviation.y * DEG2RAD) * 0.3) * flatdir;
vector actual_destorg = this.origin + offset;
- if (!this.goalstack01 || this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER))
+ if (this.goalcurrent_prev && this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP)
+ {
+ if (time > this.bot_stop_moving_timeout
+ && fabs(deviation.y) > 20 && current_speed > maxspeed * 0.4
+ && vdist(vec2(this.origin - this.goalcurrent_prev.origin), <, 50))
+ {
+ this.bot_stop_moving_timeout = time + 0.1;
+ }
+ if (current_speed > autocvar_sv_maxspeed * 0.9
+ && vlen2(flat_diff) < vlen2(vec2(this.goalcurrent_prev.origin - destorg))
+ && vdist(vec2(this.origin - this.goalcurrent_prev.origin), >, 50)
+ && vdist(vec2(this.origin - this.goalcurrent_prev.origin), <, 150)
+ )
+ {
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ // avoid changing route while bot is jumping a gap
+ navigation_goalrating_timeout_extend_if_needed(this, 1.5);
+ }
+ }
+ else if (!this.goalstack01 || this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER))
{
if (vlen2(flat_diff) < vlen2(offset))
{
turning = true;
}
- LABEL(jump_check);
+ LABEL(jumpobstacle_check);
dir = flatdir = normalize(actual_destorg - this.origin);
if (turning || fabs(deviation.y) < 50) // don't even try to jump if deviation is too high
actual_destorg = destorg;
turning = false;
this.bot_tracewalk_time = time + 0.25;
- goto jump_check;
+ goto jumpobstacle_check;
}
s = trace_fraction;
// don't artificially reduce max jump height in real-time
bool unreachable = false;
s = CONTENT_SOLID;
- if(trace_fraction == 1 && this.jumppadcount == 0 && !this.goalcurrent.wphardwired )
+ if (trace_fraction == 1 && !this.jumppadcount && !this.goalcurrent.wphardwired
+ && !(this.goalcurrent_prev && this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP) )
if((IS_ONGROUND(this)) || (this.aistatus & AI_STATUS_RUNNING) || (this.aistatus & AI_STATUS_ROAMING) || PHYS_INPUT_BUTTON_JUMP(this))
{
// Look downwards
return this.bot_strategytime < time;
}
+void navigation_goalrating_timeout_extend_if_needed(entity this, float seconds)
+{
+ this.bot_strategytime = max(this.bot_strategytime, time + seconds);
+}
+
#define MAX_CHASE_DISTANCE 700
bool navigation_goalrating_timeout_can_be_anticipated(entity this)
{
vector pm2 = ent.origin + ent.maxs;
// do two scans, because box test is cheaper
- IL_EACH(g_waypoints, it != ent && it != except && !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+ IL_EACH(g_waypoints, it != ent && it != except && !(it.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)),
{
if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
{
next = this.goalstack01;
// if for some reason the bot is closer to the next goal, pop the current one
- if (!IS_MOVABLE(next) // already checked in the previous case
+ if (!IS_MOVABLE(next) && !this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)
&& vlen2(this.goalcurrent.origin - next.origin) > vlen2(next.origin - this.origin)
&& checkpvs(this.origin + this.view_ofs, next))
{
if(vdist(wp.origin - this.origin, >, 50))
{
wp = NULL;
- IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+ IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)),
{
if(vdist(it.origin - this.origin, <, 50))
{
wp.model = "";
}
+entity waypoint_get(vector m1, vector m2)
+{
+ if (m1 == m2)
+ {
+ m1 -= '8 8 8';
+ m2 += '8 8 8';
+ }
+ IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax), { return it; });
+
+ return NULL;
+}
+
entity waypoint_spawn(vector m1, vector m2, float f)
{
if(!(f & (WAYPOINTFLAG_PERSONAL | WAYPOINTFLAG_GENERATED)) && m1 == m2)
{
- vector em1 = m1 - '8 8 8';
- vector em2 = m2 + '8 8 8';
- IL_EACH(g_waypoints, boxesoverlap(em1, em2, it.absmin, it.absmax),
- {
- return it;
- });
+ entity wp_found = waypoint_get(m1, m2);
+ if (wp_found)
+ return wp_found;
}
// spawn only one destination waypoint for teleports teleporting player to the exact same spot
// otherwise links loaded from file would be applied only to the first destination
IL_EACH(g_jumppads, boxesoverlap(wp_from.absmin, wp_from.absmax, it.absmin, it.absmax),
{
jp = it;
+ break;
});
+ if (!jp)
+ return;
+
float cost = trigger_push_get_push_time(jp, wp_to.origin);
wp_from.wp00 = wp_to;
wp_from.wp00mincost = cost;
bool start_wp_is_spawned;
vector start_wp_origin;
-void waypoint_clear_start_wp(entity pl)
+void waypoint_clear_start_wp(entity pl, bool warn)
{
start_wp_is_spawned = false;
start_wp_origin = '0 0 0';
pl.wp_locked = NULL;
- LOG_INFO("^xf80Start waypoint has been cleared\n");
+ if (warn)
+ LOG_INFO("^xf80Start waypoint has been cleared.\n");
}
-void waypoint_spawn_fromeditor(entity pl, bool at_crosshair)
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp)
{
entity e = NULL, jp = NULL;
vector org = pl.origin;
jp = it;
break;
});
- if (jp && start_wp_is_spawned)
+ }
+ if (jp || is_jump_wp)
+ {
+ if (start_wp_is_spawned)
start_wp_is_spawned = false;
- LOG_INFO("^xf80Spawning start waypoint\n");
+ LOG_INFO("^xf80Spawning start waypoint...\n");
}
int ctf_flags = havocbot_symmetry_origin_order;
bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
ctf_flags = 2;
int wp_num = ctf_flags;
- if(!PHYS_INPUT_BUTTON_CROUCH(pl) && !at_crosshair)
+ if(!PHYS_INPUT_BUTTON_CROUCH(pl) && !at_crosshair && !is_jump_wp)
{
// snap waypoint to item's origin if close enough
IL_EACH(g_items, true,
vector start_org = '0 0 0';
if (start_wp_is_spawned)
{
- LOG_INFO("^xf80Spawning destination waypoint\n");
+ LOG_INFO("^xf80Spawning destination waypoint...\n");
start_org = start_wp_origin;
}
// save org as it can be modified spawning symmetrycal waypoints
- vector org_save = org;
+ vector initial_origin = '0 0 0';
+ bool initial_origin_is_set = false;
LABEL(add_wp);
if (!pl.wp_locked)
pl.wp_locked = e;
}
+ else if (is_jump_wp)
+ {
+ entity wp_found = waypoint_get(org, org);
+ if (wp_found && !(wp_found.wpflags & WAYPOINTFLAG_JUMP))
+ {
+ LOG_INFO("Error: can't spawn a jump waypoint over an existent waypoint of a different type\n");
+ return;
+ }
+ e = waypoint_spawn(org, org, WAYPOINTFLAG_JUMP | WAYPOINTFLAG_NORELINK);
+ if (!pl.wp_locked)
+ pl.wp_locked = e;
+ }
else
e = waypoint_spawn(org, org, 0);
if(!e)
{
LOG_INFOF("Couldn't spawn waypoint at %v\n", org);
if (start_wp_is_spawned)
- waypoint_clear_start_wp(pl);
+ waypoint_clear_start_wp(pl, true);
return;
}
+ if (!initial_origin_is_set)
+ {
+ initial_origin = e.origin;
+ initial_origin_is_set = true;
+ }
+
entity start_wp = NULL;
if (start_wp_is_spawned)
{
{
// should not happen
LOG_INFOF("Couldn't find start waypoint at %v\n", start_org);
- waypoint_clear_start_wp(pl);
+ waypoint_clear_start_wp(pl, true);
return;
}
- waypoint_addlink_for_custom_jumppad(start_wp, e);
+ waypoint_addlink(start_wp, e);
}
- waypoint_schedulerelink(e);
+ if (!(jp || is_jump_wp))
+ waypoint_schedulerelink(e);
bprint(strcat("Waypoint spawned at ", vtos(e.origin), "\n"));
if (start_wp_is_spawned)
goto add_wp;
}
}
-
- if (jp)
+ if (jp || is_jump_wp)
{
if (!start_wp_is_spawned)
{
// we've just created a custom jumppad waypoint
// the next one created by the user will be the destination waypoint
start_wp_is_spawned = true;
- start_wp_origin = org_save;
+ start_wp_origin = initial_origin;
}
}
else if (start_wp_is_spawned)
{
- waypoint_clear_start_wp(pl);
+ waypoint_clear_start_wp(pl, false);
}
}
if (e.wpflags & WAYPOINTFLAG_GENERATED)
{
if (start_wp_is_spawned)
- waypoint_clear_start_wp(pl);
+ waypoint_clear_start_wp(pl, true);
return;
}
}
if (start_wp_is_spawned)
- waypoint_clear_start_wp(pl);
+ waypoint_clear_start_wp(pl, true);
}
void waypoint_removelink(entity from, entity to)
{
- if (from == to || (from.wpflags & WAYPOINTFLAG_NORELINK))
+ if (from == to || (from.wpflags & WAYPOINTFLAG_NORELINK && !(from.wpflags & WAYPOINTFLAG_JUMP)))
return;
entity fromwp31_prev = from.wp31;
float height = from.z - to.z;
if(height > jumpheight_vec.z && autocvar_sv_gravity > 0)
{
- float height_cost = sqrt(height / (autocvar_sv_gravity / 2));
+ float height_cost;
+ if (boolean(from_ent.wpflags & WAYPOINTFLAG_JUMP))
+ height_cost = jumpheight_time + sqrt((height + jumpheight_vec.z) / (autocvar_sv_gravity / 2));
+ else
+ height_cost = sqrt(height / (autocvar_sv_gravity / 2));
c = waypoint_getlinearcost(vlen(vec2(to - from))); // xy distance cost
if(height_cost > c)
c = height_cost;
{
if (from == to || waypoint_islinked(from, to))
return;
- if (c == -1 && (from.wpflags & WAYPOINTFLAG_NORELINK))
+ if (c == -1 && (from.wpflags & WAYPOINTFLAG_NORELINK) && !(from.wpflags & WAYPOINTFLAG_JUMP))
return;
if(c == -1)
void waypoint_addlink(entity from, entity to)
{
- waypoint_addlink_customcost(from, to, -1);
+ if ((from.wpflags & WAYPOINTFLAG_NORELINK) && !(from.wpflags & (WAYPOINTFLAG_JUMP)))
+ waypoint_addlink_for_custom_jumppad(from, to);
+ else
+ waypoint_addlink_customcost(from, to, -1);
}
// relink this spawnfunc_waypoint
//traceline(this.origin, it.origin, false, NULL);
//if (trace_fraction == 1)
- if (this.wpisbox)
+ if (this.wpisbox || this.wpflags & WAYPOINTFLAG_JUMP)
relink_walkculled += 0.5;
else
{
relink_walkculled += 0.5;
}
- if (it.wpisbox)
+ if (it.wpisbox || it.wpflags & WAYPOINTFLAG_JUMP)
relink_walkculled += 0.5;
else
{
}
++c;
- if ((wp_from.wpflags & WAYPOINTFLAG_NORELINK) && !(wp_from.wpflags & WAYPOINTFLAG_GENERATED))
- waypoint_addlink_for_custom_jumppad(wp_from, wp_to);
- else
- waypoint_addlink(wp_from, wp_to);
+ waypoint_addlink(wp_from, wp_to);
}
fclose(file);