1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-09 09:18:01 +00:00
nescript/examples/war/title_state.ne

131 lines
4.5 KiB
Text
Raw Normal View History

2026-04-15 15:22:20 +00:00
// 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)
2026-04-15 15:22:20 +00:00
// 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.
2026-04-15 15:22:20 +00:00
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
}
}
}