Add opt-in phone gameplay recording and JSON export

This commit is contained in:
wuwi committed 2026-09-07 10:19:38 +02:00
1 parent ede1f48152
commit fe64242090
8 files changed
+394 -12

No files matched your search

+6 -1
View File
@@ -15,6 +15,7 @@ import { voice, zombieDuck, aww } from './audio.js';
import { zombies, pellets, extras, shots, spawnRacketZombie, spawnChapterBoss, spawnZombie, explode, killPlayer } from './zombies.js';
import { cheer, aside, endBurst, deliverTin, showModal, logSwing, advancePoint, scoreKey } from './gameplay.js';
import { startDrillStream } from './drill.js';
import { recordEvent } from './recorder.js';
import { netClose, netJudging, netSendPoint, netSendDead } from './net.js'; // runtime-only cycle: net calls back into startMatch/matchReady/netMatchWon
// the court is mopped up (or was already clear): play advances to whatever the won game earned —
@@ -422,6 +423,7 @@ export function startMatch(cup = false, draw = null, train = 0) {
rules: ['ONE GAME PER BODY — HOW FAR CAN YOU GET?',
{ lead: 'POINTS DRAW BLOOD', hot: true, pips: TUNE.matchPlayerHp }] });
}
recordEvent('run_start');
matchOpponent();
matchReady();
zombieDuck(true);
@@ -692,11 +694,13 @@ function matchOpponent() {
// matchPoint divides the same way, so the wound stages spread across the whole round instead of
// being spent in game one — the body enters game two already missing what game one cost it.
zb.hp = zb.hpMax = TUNE.matchOppHp * (cup ? cup.rounds[cup.round].need : 1);
recordEvent('opponent', { traits: { ...zb.foe } });
G.interlude = { introT: 1.6 }; // the duel machinery IS the match machinery
}
export function endMatch() {
if (!G.match) return;
recordEvent('run_end', { outcome: 'ended' });
G.match = null; G.interlude = false; G.matchFall = null; // a latch left armed outlives its mode
zombies.length = 0; shots.length = 0;
zombieDuck(false);
@@ -982,7 +986,7 @@ function matchGameLost() {
G.phase = 'over'; G.overT = 1.8;
}
export function resolveInterlude(side) {
export function resolveInterlude(side, reason = 'unspecified') {
if (!G.interlude) return;
// THE MATCH HOOK: a settled point feeds the game score instead of ending the interlude — the
// interlude is permanent while a match runs (it is what keeps the serving tennis-like and the
@@ -992,6 +996,7 @@ export function resolveInterlude(side) {
// for the picture still reaches its ordinary bounce-2 / rolled-out calls, and they land here.
// G.matchEarly exempts the deciding resolution ITSELF — the latch goes up before it runs.
if (G.match.decided && !G.matchEarly) { ball.active = false; return; }
if (!G.match.ending) recordEvent('point', { winner: side, reason });
// netplay (death match): this phone judged the live flight — the verdict crosses the wire
// before it is applied, exactly as pointTo does for classic. netJudging() is false while a
// remote verdict is being applied, which is what stops the echo.