mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 08:55:38 +00:00
89 lines
4.3 KiB
Text
89 lines
4.3 KiB
Text
|
|
// pong/state.ne — every mutable variable the game touches.
|
||
|
|
//
|
||
|
|
// As in the war example, keeping these as globals means helper
|
||
|
|
// functions can read and write without taking parameters and
|
||
|
|
// returning values — the 6502's 8-register ABI makes every extra
|
||
|
|
// parameter an extra LDA/STA pair, so the shorter call signatures
|
||
|
|
// pay for themselves in the hot loop.
|
||
|
|
|
||
|
|
// ── Paddles ──────────────────────────────────────────────
|
||
|
|
//
|
||
|
|
// Two parallel u8 arrays indexed by `side` (SIDE_LEFT = 0, SIDE_RIGHT = 1).
|
||
|
|
// `paddle_y[i]` — top-edge y of paddle i
|
||
|
|
// `paddle_long[i]` — remaining LONG-paddle hits (0 = normal)
|
||
|
|
// `paddle_fast[i]` — 1 if catcher's next hit doubles ball x velocity
|
||
|
|
// `paddle_multi[i]` — 1 if catcher's next hit spawns two extra balls
|
||
|
|
// `score[i]` — current score (0..WIN_SCORE)
|
||
|
|
// `is_cpu[i]` — 1 if this side is CPU-controlled
|
||
|
|
var paddle_y: u8[2] = [96, 96]
|
||
|
|
var paddle_long: u8[2] = [0, 0]
|
||
|
|
var paddle_fast: u8[2] = [0, 0]
|
||
|
|
var paddle_multi: u8[2] = [0, 0]
|
||
|
|
var score: u8[2] = [0, 0]
|
||
|
|
var is_cpu: u8[2] = [1, 1]
|
||
|
|
|
||
|
|
// ── Balls ────────────────────────────────────────────────
|
||
|
|
//
|
||
|
|
// Parallel u8 arrays, one slot per ball up to MAX_BALLS. Each
|
||
|
|
// ball's velocity is stored as a (magnitude, sign) pair so the
|
||
|
|
// existing u8-only arithmetic suffices — sign 0 means +x right
|
||
|
|
// / +y down, sign 1 means -x left / -y up.
|
||
|
|
//
|
||
|
|
// `ball_active[i]` — 1 if this slot is in play, 0 if free
|
||
|
|
// `ball_x[i]` — top-left x in px
|
||
|
|
// `ball_y[i]` — top-left y in px
|
||
|
|
// `ball_dx[i]` — x speed in px/frame
|
||
|
|
// `ball_dy[i]` — y speed in px/frame
|
||
|
|
// `ball_dx_sign[i]` — 0 = moving right, 1 = moving left
|
||
|
|
// `ball_dy_sign[i]` — 0 = moving down, 1 = moving up
|
||
|
|
var ball_active: u8[3] = [0, 0, 0]
|
||
|
|
var ball_x: u8[3] = [0, 0, 0]
|
||
|
|
var ball_y: u8[3] = [0, 0, 0]
|
||
|
|
var ball_dx: u8[3] = [0, 0, 0]
|
||
|
|
var ball_dy: u8[3] = [0, 0, 0]
|
||
|
|
var ball_dx_sign: u8[3] = [0, 0, 0]
|
||
|
|
var ball_dy_sign: u8[3] = [0, 0, 0]
|
||
|
|
|
||
|
|
// ── Powerup ──────────────────────────────────────────────
|
||
|
|
//
|
||
|
|
// Single-slot powerup entity. `powerup_kind == PWR_NONE` means
|
||
|
|
// nothing is on screen; any other value is the current kind plus
|
||
|
|
// its position and velocity. `powerup_timer` counts frames since
|
||
|
|
// spawn so we can despawn after POWERUP_LIFE_FRAMES.
|
||
|
|
var powerup_kind: u8 = 0
|
||
|
|
var powerup_x: u8 = 0
|
||
|
|
var powerup_y: u8 = 0
|
||
|
|
var powerup_dx_sign: u8 = 0
|
||
|
|
var powerup_dy_sign: u8 = 0
|
||
|
|
var powerup_timer: u16 = 0
|
||
|
|
var powerup_cooldown:u16 = 0 // counts down to the next spawn
|
||
|
|
|
||
|
|
// ── Game mode + phase machine ────────────────────────────
|
||
|
|
var mode: u8 = 0 // 0/1/2 — CPU vs CPU / human vs CPU / human vs human
|
||
|
|
var phase: u8 = 0 // one of the P_* constants
|
||
|
|
var phase_timer: u8 = 0 // frames spent in the current phase
|
||
|
|
var serving_side:u8 = 0 // which side serves next (alternates)
|
||
|
|
|
||
|
|
// ── Title menu ────────────────────────────────────────────
|
||
|
|
var title_cursor: u8 = 0
|
||
|
|
var title_timer: u8 = 0
|
||
|
|
var title_blink: u8 = 0
|
||
|
|
var title_debounce: u8 = 0
|
||
|
|
|
||
|
|
// ── Victory state ─────────────────────────────────────────
|
||
|
|
var winner: u8 = 0
|
||
|
|
var victory_timer: u16 = 0
|
||
|
|
|
||
|
|
// ── RNG ──────────────────────────────────────────────────
|
||
|
|
//
|
||
|
|
// 8-bit Galois LFSR state. Seeded from the title frame counter at
|
||
|
|
// the moment the title transitions to gameplay so the shuffle of
|
||
|
|
// the first serve direction and powerup kinds is deterministic
|
||
|
|
// once a user commits. The jsnes headless harness always hits the
|
||
|
|
// title autopilot at the same frame, so the seed is stable there
|
||
|
|
// too.
|
||
|
|
var rng_state: u8 = 0xA7
|
||
|
|
|
||
|
|
// ── Global free-running frame counter ────────────────────
|
||
|
|
var global_tick: u16 = 0
|