From d5f5e8981a9cef46f589f9e77120bc1578051de9 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Sat, 1 Aug 2026 15:44:17 -0600 Subject: [PATCH] feat(excitebike): add cool-zone speed boost and cooldown feedback - Allow bikes to exceed normal turbo speed when holding through cool zones with turbo engaged, rewarding track knowledge - Emit 'cooldown' event when entering cool zones to clear center msg - Add coolZoneBoostSpeed tune constant (240) with design documentation - Update physics invariant checks to use new speed cap --- src/games/excitebike/ExcitebikeGame.js | 3 +++ src/games/excitebike/ExcitebikeLogic.js | 6 ++++++ tools/verifyExcitebike.js | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/games/excitebike/ExcitebikeGame.js b/src/games/excitebike/ExcitebikeGame.js index 5fea42b..b49b3a9 100644 --- a/src/games/excitebike/ExcitebikeGame.js +++ b/src/games/excitebike/ExcitebikeGame.js @@ -707,6 +707,9 @@ export default class ExcitebikeGame extends Phaser.Scene { this.crt.pulse(0.6, 240); } break; + case 'cooldown': + if (ev.isPlayer) this.setCenterMsg(''); + break; case 'lap': if (ev.isPlayer) playSound(this, SFX.EIGHTBIT_ACTIVATE); break; diff --git a/src/games/excitebike/ExcitebikeLogic.js b/src/games/excitebike/ExcitebikeLogic.js index 8e6066e..c60cf69 100644 --- a/src/games/excitebike/ExcitebikeLogic.js +++ b/src/games/excitebike/ExcitebikeLogic.js @@ -61,6 +61,10 @@ export const TUNE = { heatRiseRate: 1 / 7, heatFallRate: 1 / 5, coolZoneRate: 1 / 1.2, + // Holding turbo through a cool zone also kicks the bike past its normal + // ceiling — a real reward for finding the chevrons, not just a way to + // dodge heat. Coasting through one gets no speed bonus, only the cooling. + coolZoneBoostSpeed: 240, overheatMs: 4000, // Lanes. @@ -437,6 +441,7 @@ function stepBike(state, b, input) { b.state = STATE.RIDING; b.stateMs = 0; b.temp = 0; + emit(state, { type: 'cooldown', bike: b.index, isPlayer: b.isPlayer }); } return; } @@ -462,6 +467,7 @@ function stepBike(state, b, input) { else if (input.a) target = TUNE.speedAccel; if (surf === SURFACE.MUD && grounded(b)) target = Math.min(target, TUNE.mudSpeedCap); + else if (surf === SURFACE.COOL && grounded(b) && turbo) target = TUNE.coolZoneBoostSpeed; if (b.vx < target) { b.vx = Math.min(target, b.vx + TUNE.accelRate * DT); diff --git a/tools/verifyExcitebike.js b/tools/verifyExcitebike.js index 85f6217..95c20c8 100644 --- a/tools/verifyExcitebike.js +++ b/tools/verifyExcitebike.js @@ -422,7 +422,7 @@ section('4. Physics invariants'); for (const b of state.bikes) { seenStates.add(b.state); if (![b.x, b.vx, b.y, b.vy, b.lane, b.pitch, b.temp].every(Number.isFinite)) nan += 1; - if (b.vx > TUNE.speedTurbo + 1 || b.vx < -0.001) overSpeed += 1; + if (b.vx > TUNE.coolZoneBoostSpeed + 1 || b.vx < -0.001) overSpeed += 1; if (b.temp < -0.001 || b.temp > 1.001) badTemp += 1; if (b.lane < -0.001 || b.lane > LANE_COUNT - 1 + 0.001) badLane += 1; if (b.state === STATE.RIDING && b.y < -0.5) sunk += 1; @@ -431,7 +431,7 @@ section('4. Physics invariants'); } check('nothing ever goes NaN', nan === 0, `${nan} samples`); - check('speed never exceeds the turbo cap', overSpeed === 0, `${overSpeed} samples`); + check('speed never exceeds the cool-zone boost cap', overSpeed === 0, `${overSpeed} samples`); check('temperature stays in 0..1', badTemp === 0, `${badTemp} samples`); check('bikes stay on the four lanes', badLane === 0, `${badLane} samples`); check('a riding bike never sinks below the ground', sunk === 0, `${sunk} samples`);