1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 08:55:38 +00:00
nescript/examples/war/title_state.ne
Claude 9137b1f713
examples/war: polish pass + README entry + plan close-out
End-of-implementation polish for the War example after the
compiler bugs were fixed:

- Title state now calls draw_big_war_banner instead of inlining
  12 draws — same pixel output, fewer lines.
- P_WAR_BURY redraws the previous round's face-up cards while
  the noise thumps fire so the table doesn't look empty for
  24 frames between the WAR banner and the new face-ups.
- Drop draw_word_war from render.ne (orphaned by the BIG WAR
  metasprite).
- Refresh comments in background.ne (now references the real
  felt tile) and deal_state.ne (drop the stale FRAMES_DEAL_STEP
  reference now that the deal pace is hard-coded at 2 frames).
- README.md and examples/README.md gain a war row.
- PLAN.md marks every implementation step complete and records
  the design revisions made along the way.
- Refresh the war audio hash to match the new ROM (the title
  screen helper change shifts one frame of pulse-2 timing
  enough to flip the FNV-1a). The frame-180 PNG is unchanged.

https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 16:08:03 +00:00

130 lines
4.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// war/title_state.ne — the Title state.
//
// Draws a big "WAR" banner, a 3-option menu with a cursor, and a
// blinking "PRESS A" prompt. Autopilot: if the player doesn't
// press anything for TITLE_AUTO_FRAMES frames the menu auto-
// commits to "0 PLAYERS" so the jsnes golden capture reaches
// gameplay by frame 180.
//
// The cursor navigates with D-pad up/down; A or Start confirms.
// Debouncing is done via title_debounce — one key press per
// press rather than per frame held.
state Title {
on enter {
title_cursor = 1
title_timer = 0
title_blink = 0
title_debounce = 0
start_music TitleTheme
}
on frame {
global_tick += 1
title_timer += 1
title_blink += 1
if title_blink >= 60 {
title_blink = 0
}
if title_debounce > 0 {
title_debounce -= 1
}
// ── Big "WAR" title banner ───────────────────────
// Three 16×16 metasprite letters (BIG W, A, R), drawn
// via the same helper the in-game tie-break uses. Each
// letter is 8px wide (BIG_*_TL / BIG_*_TR side-by-side);
// letters land at x = 100, 120, 140 with the helper's
// internal 20-px stride.
draw_big_war_banner(100, 32)
// Subtitle "CARD GAME" in 8x8 font under the banner.
// 8 letter sprites at y=64 — exactly at the per-scanline
// limit. The space between "CARD" and "GAME" is just a
// skipped tile column, so it doesn't burn an OAM slot.
draw_letter(96, 64, 2) // C
draw_letter(104, 64, 0) // A
draw_letter(112, 64, 17) // R
draw_letter(120, 64, 3) // D
draw_letter(136, 64, 6) // G
draw_letter(144, 64, 0) // A
draw_letter(152, 64, 12) // M
draw_letter(160, 64, 4) // E
// ── Menu options ─────────────────────────────────
// Three lines vertically stacked. Each row is "X PLAYER"
// (no S — plural is implied) so the row never exceeds 7
// sprites and stays under the per-scanline limit even
// when the cursor sprite shares the same row.
draw_digit(88, 104, 0)
draw_word_player(104, 104)
draw_digit(88, 120, 1)
draw_word_player(104, 120)
draw_digit(88, 136, 2)
draw_word_player(104, 136)
// Cursor sits to the left of the selected option.
var cursor_y: u8 = 104 + (title_cursor << 4) // 104, 120, 136
draw Tileset at: (72, cursor_y) frame: TILE_CURSOR
// ── Blinking "PRESS A" prompt ────────────────────
if title_blink < 30 {
draw_word_press(96, 184)
draw_letter(144, 184, 0) // A
}
// ── Input handling ───────────────────────────────
if title_debounce == 0 {
if button.up {
if title_cursor > 0 {
title_cursor -= 1
}
title_debounce = 10
title_timer = 0
play FlipCard
}
if button.down {
if title_cursor < 2 {
title_cursor += 1
}
title_debounce = 10
title_timer = 0
play FlipCard
}
if button.a or button.start {
// Commit the selection and seed the RNG from the
// current global tick so each user-visible start
// produces a different shuffle.
mode = title_cursor
rng_seed((global_tick & 0xFF) as u8)
transition Deal
}
}
// ── Autopilot for the headless harness ───────────
if title_timer >= TITLE_AUTO_FRAMES {
mode = 0
rng_seed((global_tick & 0xFF) as u8)
transition Deal
}
}
on exit {
stop_music
// Translate the menu selection into the two a_is_cpu /
// b_is_cpu flags the play state reads each frame.
if mode == MODE_CPU_VS_CPU {
a_is_cpu = 1
b_is_cpu = 1
}
if mode == MODE_HUMAN_VS_CPU {
a_is_cpu = 0
b_is_cpu = 1
}
if mode == MODE_HUMAN_VS_HUMAN {
a_is_cpu = 0
b_is_cpu = 0
}
}
}