Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified engine/argus/progs.dat
Binary file not shown.
Binary file modified game/argus/progs.dat
Binary file not shown.
731 changes: 731 additions & 0 deletions runs/coop_e1m2_waterfix.log

Large diffs are not rendered by default.

2,068 changes: 2,068 additions & 0 deletions runs/waterfix_dm4.log

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions src/argus.qc
Original file line number Diff line number Diff line change
Expand Up @@ -6433,6 +6433,37 @@ void() Argus_AI =
self.ar_pending = 1;
self.ar_mode = 0;
}
else if (self.waterlevel >= 2
&& self.ar_feettype == CONTENT_WATER
&& tp_z > self.origin_z + 64
&& !self.ar_hopswim && !self.ar_hoplift
&& !self.ar_hoptrain && !self.ar_hopjump
&& !self.ar_hoprj)
{
// DISPLACED VERTICALLY, INTO WATER. `to` is flattened
// above, so a steering node directly overhead reads
// zero horizontal distance and the 340 guard never
// sees it. On e1m2 a companion fell off the z 308
// platform into the flooded court and kept steering at
// the seat it had been walking to, 137u over its head,
// behind a lip 108-120u above the surface that no
// vault reaches. It swam at that node for a whole
// session: 622 swim events, two routes, pinned inside
// one cell.
//
// 64 is the water vault's reach (320 up under gravity
// 800 apexes at 64). Above that a swimmer is not
// getting there, so treat it as displacement and
// re-plan - Argus_NearestNode is swim-aware now and
// will start the new route from a pool seat, which on
// e1m2 reaches 167 of 198 nodes through the swim-exit
// links. Every typed hop is exempt: a swim exit,
// a lift and a train all legitimately target a node
// above, and the e1m2 swim links rise 112u.
self.ar_node = world;
self.ar_pending = 1;
self.ar_mode = 0;
}
else if (vlen (to) < 48
&& (fabs (tp_z - self.origin_z) < 48
|| (self.origin_z - tp_z > 0
Expand Down
52 changes: 48 additions & 4 deletions src/argus_nav.qc
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,38 @@ entity(entity n, entity bot) Argus_GetNext =

entity(vector p) Argus_NearestNode =
{
local entity n, cand, best, bestv;
local entity n, cand, best, bestv, bestany;
local vector d, eye;
local float dist, bd, bdv, i;
local float dist, bd, bdv, bda, i, inwater, ceil;

// A SWIMMER CANNOT REACH A NODE HIGH ABOVE THE WATER. Nothing used
// to say so, and on e1m2 that pinned a companion in one cell for a
// whole session: floating at z 171 in the flooded court, the
// nearest node by distance was the platform seat 137u overhead
// (WATDBG "nodez 308"), whose lip stands 108 to 120u above the
// surface - three times what the water vault's 320 up can clear.
// The bot swam at it for 128 s. The routed dive could not save it
// either: that fires only when the node is BELOW, and this one is
// above, so the vertical drive fell through to the surface tread.
// The pool floor seats it could actually have used sit 79u down
// and lead, through eight swim-exit links, to 167 of the map's
// 198 nodes.
//
// So when the query point is in water, a node more than a vault
// above it is not a candidate. Position-based, not bot-based, so
// it applies to a start node without touching a dry goal's node.
// bestany keeps the unfiltered pick: a pool whose every node is
// out of reach should still route badly rather than not at all.
// A swimmer's reachable set is what it can swim to: nodes at or
// below the query point. Anything above needs the lip to be within
// the vault, and a hard height cut is the wrong instrument - a
// ceiling of 64 still let e1m2 start a 20-hop route from a seat 61u
// up (ARGEVT route 20 from '1585 1185 208'), which the bot then
// stalled under 228 times. So this is a PREFERENCE, not a cut: an
// at-or-below candidate always beats one above, and a node above is
// taken only when nothing below exists.
inwater = (pointcontents (p) == CONTENT_WATER);
ceil = p_z + 8;

// Local neighbor fast-path (#146):
// Continuous locomotion rarely jumps across the map. If the calling
Expand All @@ -442,7 +471,7 @@ entity(vector p) Argus_NearestNode =
d = n.origin - p;
d_z = d_z * 2;
dist = vlen (d);
if (dist < 200)
if (dist < 200 && !(inwater && n.origin_z > ceil))
{
traceline (eye, n.origin + '0 0 8', TRUE, self);
if (trace_fraction == 1)
Expand Down Expand Up @@ -484,15 +513,27 @@ entity(vector p) Argus_NearestNode =

best = world;
bestv = world;
bestany = world;
bd = 999999;
bdv = 999999;
bda = 999999;
eye = p + '0 0 22';
n = find (world, classname, "argus_node");
while (n != world)
{
d = n.origin - p;
d_z = d_z * 2;
dist = vlen (d);
if (dist < bda)
{
bda = dist;
bestany = n;
}
if (inwater && n.origin_z > ceil)
{
n = find (n, classname, "argus_node");
continue; // out of a swimmer's reach
}
if (dist < bd)
{
bd = dist;
Expand Down Expand Up @@ -522,7 +563,10 @@ entity(vector p) Argus_NearestNode =
// them), and the bot then beelined the whole way into a wall
if (bestv != world && bdv <= bd * 2 + 100)
return bestv;
return best;
if (best != world)
return best;
return bestany; // every node was out of reach; route badly
// rather than not at all
};

// ---------------------------------------------------------------- search
Expand Down