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

+20 -1
View File
@@ -4,7 +4,7 @@
// (zombies <-> gameplay is a runtime-only import cycle, same pattern as input.)
import { TUNE, UI, COURT, CONTACT, BOSS_ART, bossArt, WEAPONS, BARREL_WEAPONS, woundStage, zombieH, EATEN_BURST, EATEN_SUMMARY, EATEN_FEED_R } from './config.js';
import { G, P, ball, score, sendBoy, setupPoint } from './state.js';
import { G, P, O, ball, score, sendBoy, setupPoint } from './state.js';
import { splat, moan, pock, thud, zap, voice, boom, swish, shriek, aww, sfx , whoosh, flame } from './audio.js';
import { drillKill, drillCaught } from './drill.js';
import { splatPoint, cheer, spentBall, aside, grantWeapon, endBurst, sliceCarom } from './gameplay.js';
@@ -921,6 +921,24 @@ function gushProne(zb) {
}
}
// NETPLAY DEATH MATCH: the opponent is the LIVING O — a human sprite with no wound skins to climb
// (Oliver: "the normal opponent does not have wound states — this was the reason I said increased
// dynamic bleeding"). So the score reads on him as BLOOD: each point taken off him this game opens
// another anchor and thickens the flow, love → game point, and the burst (matchGameWon) resets it
// with the body. Same thin-drop discipline as bleed() — more EMISSIONS, never heavier drops.
const O_BLEED = [[0.12, 1.55, 0.9], [-0.22, 1.2, 0.8], [0.16, 0.9, 0.7]];
function bleedO() {
const k = Math.min(3, score.pts[0]); // points off them THIS game
if (!k || G.hideO || parts.length > 120) return;
for (const w of O_BLEED.slice(0, k)) {
if (Math.random() > 0.14 * k) continue; // ramps: one light nick → gushing at game point
parts.push({
x: O.x + w[0] + (Math.random() * 2 - 1) * 0.04, y: w[1] + (Math.random() * 2 - 1) * 0.04, z: O.z + (Math.random() * 2 - 1) * 0.04,
vx: (Math.random() * 2 - 1) * 0.35, vy: w[2] * (0.6 + Math.random() * 0.5), vz: (Math.random() * 2 - 1) * 0.3,
t: 0.3 + Math.random() * 0.3, dark: Math.random() < 0.55 });
}
}
function bleed(zb) {
if (parts.length > 90) return;
let wounds;
@@ -962,6 +980,7 @@ export function updateParts(dt) {
export function updateZombies(dt) {
moanT -= dt;
if (moanT <= 0) { moan(); moanT = 2.5 + Math.random() * 4; }
if (G.net && G.net.death && G.match) bleedO(); // the friend's damage, read as blood (see bleedO)
if (G.mode === 'splatter') { // transition spawns are scripted, not timed
G.splatT += dt;