The friend across the net is no shambler: he just bleeds, and then he bursts

Two retest findings, one root: the death match borrowed the roster's
body. Gone — nothing spawns, no walk-on card, the living opponent is the
whole picture. His damage reads as blood (bleedO: an anchor per point
taken this game, love to game point, thin drops as ever), the game
point bursts him where he stands, and IT RISES AGAIN brings him back
clean. The heal beat became a card in netplay — a modal freezes this
world while the other phone's keeps moving.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-14 18:10:50 +02:00
1 parent c0b59eee90
commit 4c47295a73
6 files changed
+95 -68

No files matched your search

+8 -22
View File
@@ -79,10 +79,6 @@ export function netApplyShot(m) {
G.phase = 'rally'; G.swung = false; G.rallyNear = null;
O.x = s.x; O.z = s.z; // the strike happened where the ball says it did
O.pose = m.serve ? 'serve' : 'swing'; O.poseT = 0;
if (G.net.death) { // ...and in a death match the PICTURE is the zombie, not O
const rz = zombies.find(z => z.variant === 'r');
if (rz) { rz.x = s.x; rz.z = s.z; if (m.serve) rz.serveHold = 0.4; }
}
}
function netApplyPoint(m) {
@@ -117,7 +113,14 @@ function netStart(side, death) {
G.classic = false;
startMatch();
G.net = n;
G.modal = null; G.modalQ.length = 0; // the DEATH MATCH explainer must not eat the first serve
// THE OPPONENT IS THE FRIEND, NOT A ROSTER BODY: startMatch walked THE SHAMBLER on (spawn +
// name card) because it could not see the swap — take both back. The living O is the whole
// picture (render draws him whenever hideO is false, splatter included — the bench proved it),
// and the score reads on him as blood (bleedO), not as wound skins he does not have.
zombies.length = 0;
G.hideO = false;
G.card = null;
G.modal = null; G.modalQ.length = 0; // ...and the DEATH MATCH explainer must not eat the first serve
}
score.server = side === 'A' ? 'P' : 'O'; // the host serves first, on both scoreboards
score.pts = [0, 0];
@@ -169,23 +172,6 @@ export function netTick(dt) {
O.x += (tx - O.x) * k; O.z += (tz - O.z) * k;
if (O.pose !== 'swing' && O.pose !== 'serve') O.pose = o.m ? 'run' : 'idle';
if (o.m) O.runT += dt;
// DEATH MATCH: the body on screen is the racket zombie; O is only the serve-machinery ghost it
// always is in a match. The zombie shadows O's driven position — stride bookkeeping like the
// bench's walk, so the frames step off ground covered — except while the fall or a named serve
// frame owns the picture. vx is recorded so a fall inherits the run, clamped against snaps.
if (n.death && !G.matchFall) {
const rz = zombies.find(z => z.variant === 'r');
if (rz && !rz.showFrame) {
const dx = O.x - rz.x, step = Math.hypot(dx, O.z - rz.z);
if (step > 0.03) {
rz.dist = (rz.dist || 0) + step;
rz.vx = Math.max(-3, Math.min(3, dx / Math.max(dt, 1e-3)));
if (Math.abs(dx) > 0.02) rz.face = dx > 0 ? 1 : -1;
rz.pose = rz.pose === 'swing' ? 'swing' : 'run';
} else { rz.pose = rz.pose === 'swing' ? 'swing' : 'idle'; rz.vx = 0; }
rz.x = O.x; rz.z = O.z;
}
}
}
}