diff --git a/projects/mazegame/emul/rom/mazegame.rom b/projects/mazegame/emul/rom/mazegame.rom index ad58873..c94b34b 100644 Binary files a/projects/mazegame/emul/rom/mazegame.rom and b/projects/mazegame/emul/rom/mazegame.rom differ diff --git a/projects/mazegame/mazegame.c b/projects/mazegame/mazegame.c index 0d360f6..6870226 100644 --- a/projects/mazegame/mazegame.c +++ b/projects/mazegame/mazegame.c @@ -726,25 +726,29 @@ static const u16 g_DefaultPal[16] = { 0x0171, 0x0373, 0x0661, 0x0664, 0x0411, 0x0265, 0x0555, 0x0777 }; -// Fade palette entry [idx] through brightness sequence 1..7..7..6..0 -// (mirrors BASIC GOSUBs 100/300/500/700: FOR I=1 TO 30: NEXT I ≈ 5 VBlanks) -static void LogoFade(u8 idx, u8 delay_halts) +// Fade a set of palette entries up (black->white) and back down to black +// together, so a stroke made of several palette entries shimmers as one shape. +static void LogoFadeSet(const u8* idx, u8 n, u8 delay_halts) { static const u8 seq[15] = {1,2,3,4,5,6,7,7,6,5,4,3,2,1,0}; for (u8 s = 0; s < 15; s++) { - u8 lvl = seq[s]; - u16 c = ((u16)lvl << 8) | ((u16)lvl << 4) | lvl; - VDP_SetPaletteEntry(idx, c); + u16 c = ((u16)seq[s] << 8) | ((u16)seq[s] << 4) | seq[s]; + for (u8 k = 0; k < n; k++) VDP_SetPaletteEntry(idx[k], c); for (u8 h = 0; h < delay_halts; h++) Halt(); } } -// GOSUB 1000 inner body: set all 4 palette entries to the same grey level, 5 Halts each. -static void LogoFadeAllColors(u8 lvl) -{ - u16 c = ((u16)lvl << 8) | ((u16)lvl << 4) | lvl; - for (u8 idx = 2; idx <= 5; idx++) { VDP_SetPaletteEntry(idx, c); Halt(); Halt(); Halt(); Halt(); Halt(); } -} +// The logo is an "F" and "H" combined, sharing the left vertical stroke and the +// middle crossbar. Each stroke shimmers in and out on its own before the whole +// logo lights up. Because the stem and crossbars overlap, the two crossing +// points get their OWN palette entries (6, 7) that are lit during BOTH the +// crossbar's turn and the stem's turn — so neither the horizontals nor the +// verticals ever show a gap. Strokes are partitioned (no shared pixels): +// pal2 = top crossbar arms pal3 = stem (excl. crossings) pal6 = top crossing +// pal4 = middle crossbar arms pal5 = right leg pal7 = middle crossing +// Origin X is even so the byte-aligned HMMV fills land on pixel boundaries. +#define LOGO_OX 110 // logo origin X (even: keeps HMMV fills pixel-aligned) +#define LOGO_OY 73 // logo origin Y static void ShowLogoAnimation(void) { @@ -756,30 +760,45 @@ static void ShowLogoAnimation(void) VDP_ClearVRAM(); VDP_DisableSprite(); - // Blank all 16 palette entries before enabling display + // Blank all 16 palette entries so the strokes stay invisible until faded in. for (u8 i = 0; i < 16; i++) VDP_SetPaletteEntry(i, 0); - // Draw FH logo using HMMV fills. - // pal2=f-crossbar, pal3=spine, pal4=h-crossbar, pal5=h-right-leg. - // Draw crossbars first, then spine overwrites their centre, then right leg. - VDP_CommandHMMV(118, 75, 28, 5, 0x22); VDP_CommandWait(); // f-crossbar - VDP_CommandHMMV(118, 90, 28, 4, 0x44); VDP_CommandWait(); // h-crossbar - VDP_CommandHMMV(122, 73, 10, 34, 0x33); VDP_CommandWait(); // spine - VDP_CommandHMMV(140, 88, 6, 19, 0x55); VDP_CommandWait(); // h right leg + // Draw the strokes. They are partitioned so no two share a pixel; the two + // stem/crossbar crossings are separate fills (pal6, pal7). Local x12..21 is + // the stem column; crossbars are split into left/right arms around it. + VDP_CommandHMMV(LOGO_OX + 12, LOGO_OY + 0, 10, 2, 0x33); VDP_CommandWait(); // stem: above top bar + VDP_CommandHMMV(LOGO_OX + 12, LOGO_OY + 7, 10, 10, 0x33); VDP_CommandWait(); // stem: between bars + VDP_CommandHMMV(LOGO_OX + 12, LOGO_OY + 21, 10, 13, 0x33); VDP_CommandWait(); // stem: below mid bar + VDP_CommandHMMV(LOGO_OX + 8, LOGO_OY + 2, 4, 5, 0x22); VDP_CommandWait(); // top bar: left arm + VDP_CommandHMMV(LOGO_OX + 22, LOGO_OY + 2, 12, 5, 0x22); VDP_CommandWait(); // top bar: right arm + VDP_CommandHMMV(LOGO_OX + 12, LOGO_OY + 2, 10, 5, 0x66); VDP_CommandWait(); // top crossing + VDP_CommandHMMV(LOGO_OX + 8, LOGO_OY + 17, 4, 4, 0x44); VDP_CommandWait(); // mid bar: left arm + VDP_CommandHMMV(LOGO_OX + 22, LOGO_OY + 17, 8, 4, 0x44); VDP_CommandWait(); // mid bar: right arm + VDP_CommandHMMV(LOGO_OX + 12, LOGO_OY + 17, 10, 4, 0x77); VDP_CommandWait(); // middle crossing + VDP_CommandHMMV(LOGO_OX + 30, LOGO_OY + 15, 4, 19, 0x55); VDP_CommandWait(); // right leg VDP_EnableDisplay(TRUE); - // Phase 1: verticals – spine then right leg, each fades in and out - LogoFade(3, 5); - LogoFade(5, 5); + // Reveal order: each horizontal shimmers, then each vertical, then the total. + // Each crossbar lights its arms + its crossing; the stem lights its body + + // both crossings — so every stroke appears as a complete shape. + static const u8 fadeTop[2] = {2, 6}; // top crossbar + static const u8 fadeMid[2] = {4, 7}; // middle crossbar + static const u8 fadeStem[3] = {3, 6, 7}; // left stem + static const u8 fadeLeg[1] = {5}; // right leg + static const u8 fadeAll[6] = {2, 3, 4, 5, 6, 7}; + LogoFadeSet(fadeTop, 2, 5); + LogoFadeSet(fadeMid, 2, 5); + LogoFadeSet(fadeStem, 3, 5); + LogoFadeSet(fadeLeg, 1, 5); - // Phase 2: horizontals – f-crossbar then h-crossbar, each fades in and out - LogoFade(2, 5); - LogoFade(4, 5); - - // Phase 3: complete FH – all four colors fade in together and hold - for (u8 lvl = 1; lvl <= 7; lvl++) LogoFadeAllColors(lvl); + // The total: all strokes fade up together and hold. + for (u8 lvl = 1; lvl <= 7; lvl++) { + u16 c = ((u16)lvl << 8) | ((u16)lvl << 4) | lvl; + for (u8 k = 0; k < 6; k++) VDP_SetPaletteEntry(fadeAll[k], c); + for (u8 h = 0; h < 5; h++) Halt(); + } for (u8 h = 0; h < 150; h++) Halt(); // Restore MSX2 default palette so SCREEN 0 text mode remains visible. @@ -961,6 +980,14 @@ void main(void) VDP_ClearVRAM(); VDP_DisableSprite(); // Software-only sprites: disable VDP hardware sprite layer + // Single-page horizontal scrolling (R#25 SP2=1). The default SP2=0 scrolls + // across TWO pages (512px), so a non-zero R#26/R#27 offset wraps the *next* + // VRAM page into the entering edge instead of column 0..63 of this page — + // which made the entering strip appear on the wrong side during horizontal + // scroll. SP2=1 makes the offset wrap within one 256px page, which is the + // behaviour the horizontal path in ScrollDraw() relies on. + VDP_SetHorizontalMode(R25_SP2); + // Software sprite: initialize direction and frame for this game. g_SprDir = SPR_SOUTH; // face south (toward exit) at game start g_SprFrame = 0;