Phase 8: polish and end-to-end test
Banner text rendering (PRESS FIRE / HARE WINS! / SCOOT WINS!): - src/banner.c, src/banner.h: new module; renders NUL-terminated ASCII text in any character row of the multicolor bitmap, using the same 4x8 custom font as the score bar. Truncates to 40 chars, centers in the row, clears the row first. - src/score.c, src/score.h: font extended from 8 to 16 entries — added P, F, W, I, N, !, space (and one reserved). font_lookup() maps ASCII to font index. - src/game.c: TITLE renders 'PRESS FIRE' in row 1 below the score bar; GAMEOVER renders 'HARE WINS!' or 'SCOOT WINS!' based on last_winner (set by game_enter_win_p1/p2). Other states clear row 1 on entry. State transition stinger: - src/audio.c, src/audio.h: audio_play_stinger(voice, duration) starts a low square-wave burst that auto-cleans up via audio_advance_stinger (called from audio_state_step). A 5-frame stinger is fired on every state transition; the per-state voice is chosen to avoid colliding with the new state's audio (TITLE/READY: voice 0/1 free, WAIT: voice 2 free, DRAW: voice 0 free, WIN/GAMEOVER: voice 2 free). Stinger is silenced by the next audio_state_enter() via the existing audio_stop() call. TITLE border flash changed from 12.5 Hz to 1 Hz (50 on, 50 off). Build system: - src/build.sh: added -O0/-O1/-O2/-O3/-Os/-g flag handling. Both default (-O1) and -O3 builds produce a 43913-byte .prg (well under the 51308-byte LOAD"*",8,1 limit). - src/main.c: pinned #pragma stacksize(0x400) — the oscar64 default is the same, but pinning makes the layout predictable across optimization levels. -O3 needs this exact size; larger values cause 'Cannot place stack section' link errors because the optimizer's larger code section leaves less room in the stack/heap gap. - src/tick.c: marked frame_tick_handler __noinline so -O3 doesn't inline the entire state machine (6000+ bytes) into the IRQ handler. With __noinline, the handler is 136 bytes — small enough for the raster line budget. - src/game.h: marked game_step __noinline for the same reason. The .prg is 173 blocks (out of 202 max), well within the BASIC load area. Both default and -O3 builds run cleanly in the oscar64 built-in emulator.
This commit is contained in:
+33
@@ -44,6 +44,39 @@ extern byte score_p1;
|
||||
// Player 2 (Scoot) score, 0..5.
|
||||
extern byte score_p2;
|
||||
|
||||
// --- custom 4x8 font index constants ------------------------------------
|
||||
//
|
||||
// The font (defined in score.c) is a 16-entry table of 4x8 characters.
|
||||
// Each entry is 8 bytes (one byte per row, top 4 bits = the 4 pixels of
|
||||
// the row, MSB = leftmost pixel). Bottom 4 bits of every byte are 0.
|
||||
// Total font size = 16 * 8 = 128 bytes. The original 8 chars (H/A/R/E/
|
||||
// S/C/O/T) are the score bar labels; the new 8 chars (P/F/I/W/N/! and
|
||||
// ' ' plus one reserved) are used by the banner renderer for the
|
||||
// "PRESS FIRE" prompt and the "HARE WINS!" / "SCOOT WINS!" banners.
|
||||
#define FONT_COUNT 16
|
||||
|
||||
#define CHAR_H 0
|
||||
#define CHAR_A 1
|
||||
#define CHAR_R 2
|
||||
#define CHAR_E 3
|
||||
#define CHAR_S 4
|
||||
#define CHAR_C 5
|
||||
#define CHAR_O 6
|
||||
#define CHAR_T 7
|
||||
#define CHAR_P 8
|
||||
#define CHAR_F 9
|
||||
#define CHAR_W 10
|
||||
#define CHAR_I 11
|
||||
#define CHAR_N 12
|
||||
#define CHAR_EXCL 13
|
||||
#define CHAR_SPACE 14
|
||||
#define CHAR_RESERVED 15
|
||||
|
||||
// Look up the font index for a given ASCII char. Returns
|
||||
// CHAR_RESERVED for any char not in the font. Used by the banner
|
||||
// renderer when given a string of ASCII text.
|
||||
byte font_lookup(char c);
|
||||
|
||||
// score_init() — zero both scores. Called once at startup.
|
||||
// (The variables already default to 0 in BSS; this is for symmetry with
|
||||
// the future per-state initialization in Phase 4.)
|
||||
|
||||
Reference in New Issue
Block a user