diff --git a/doc/gameplay.md b/doc/gameplay.md index 3e632c5..48536f0 100644 --- a/doc/gameplay.md +++ b/doc/gameplay.md @@ -49,7 +49,7 @@ Oltre alla dimensione, ci sono altri **assi di difficoltà** che scalano col liv - **Stamina più lenta**: `stamina_recharge_rate = 60 + 12*(level-1)` — la barra si ricarica più lentamente. - **Nebbia più stretta**: `fog_radius = 1` (3x3) dal livello 7 (invece di 2 / 5x5). -**Il gioco finisce dopo il livello 8 con un finale tragico**: superare la botola al livello 8 setta `game_over = 3` (finale) invece di 2 (Going Deeper). Non e' una fuga: la schermata finale (sfondo nero, BGP invertito, testo chiaro col font IBM ricaricato) recita "YOUR TRAIL HAS / RUN OUT, / YOU ARE TRAPPED. / JUST ANOTHER SCREAM / FROM THE DARK. / GAME OVER"; START torna al titolo (nuova partita dal livello 1). La musica e' la stessa tragica sequenza del Game Over (128 note, noise channel). +**Il gioco finisce dopo il livello 8 con un finale tragico**: superare la botola al livello 8 setta `game_over = 3` (finale) invece di 2 (Going Deeper). Non e' una fuga: la schermata finale (sfondo nero, BGP invertito, testo chiaro col font IBM ricaricato) recita "YOUR TORCH HAS / RUN OUT, / YOU ARE TRAPPED. / JUST ANOTHER SCREAM / FROM THE DARK. / GAME OVER"; START torna al titolo (nuova partita dal livello 1). **Musica dedicata**: un brano originale piu' ricco e coerente (192 step, 24 accordi) — un lamento discendente in Re minore (Dm–C–Bb–A7) che si intensifica con arpeggi alti (lo "scream"), poi cola nell'abisso col basso che scende fino al Do piu' grave e sfuma nel silenzio. Tre canali: CH1 melodia, CH2 basso, CH4 rintocco (toll medio, crash al climax, tonfo profondo nell'abisso). Tempo sommesso (14 frame/nota). Poiché con labirinti grandi la finestra fog-of-war, proiettata in coordinate isometriche assolute, può cadere fuori dal vecchio range di righe flussato (2-17) a causa del wrapping della mappa 32x32, `draw_map` ora usa un flush **dinamico a 16 righe** centrato sulla iso_y del centro di disegno (con gestione del wrap via due `set_bkg_tiles`). Questo mantiene le prestazioni del progetto originale (16 righe = 512 byte) coprendo la nebbia in qualunque posizione. diff --git a/src/sound.c b/src/sound.c index dcb300d..4594569 100644 --- a/src/sound.c +++ b/src/sound.c @@ -25,6 +25,9 @@ static volatile uint8_t victory_music_step = 0; static volatile uint8_t title_music_timer = 0; static volatile uint8_t title_music_step = 0; +static volatile uint8_t finale_music_timer = 0; +static volatile uint8_t finale_music_step = 0; + // Note frequencies calculation: (2048 - (131072 / frequency)) #define R 0 #define N_C2 44 @@ -188,6 +191,60 @@ const uint16_t title_melody[32] = { N_E2, N_B2, N_E3, N_B2, N_GS3, N_E3, N_B2, N_E2 // E }; +const uint16_t finale_ch1_seq[192] = { + N_A4, R, N_F4, R, N_D4, R, N_A3, R, + N_A4, N_F4, N_D4, N_A3, N_F4, N_D4, N_A3, R, + N_G4, R, N_E4, R, N_C4, R, N_G3, R, + N_F4, R, N_D4, R, N_AS3, R, N_F3, R, + N_E4, R, N_CS4, R, N_A3, R, N_E3, R, + N_A4, N_F4, N_D4, N_A3, N_A4, N_F4, N_D4, R, + N_A4, N_A4, N_G4, N_F4, N_E4, N_F4, N_D4, R, + N_G4, N_F4, N_E4, N_D4, N_C4, N_D4, N_E4, R, + N_F4, N_F4, N_E4, N_D4, N_C4, N_AS3, N_A3, R, + N_E4, N_E4, N_D4, N_CS4, N_B3, N_CS4, N_E4, R, + N_A5, R, N_A5, N_G5, N_F5, N_E5, N_D5, R, + N_A5, N_F5, N_D5, N_A4, N_F5, N_D5, N_A4, R, + N_G5, R, N_G5, N_F5, N_E5, N_D5, N_C5, R, + N_F5, R, N_F5, N_E5, N_D5, N_C5, N_AS4, R, + N_E5, N_E5, N_F5, N_E5, N_CS5, N_A4, N_CS5, R, + N_D5, N_C5, N_B4, N_A4, N_G4, N_F4, N_E4, R, + N_A4, N_G4, N_F4, N_E4, N_D4, N_C4, N_AS3, N_A3, + N_D4, R, N_C4, R, N_AS3, R, N_A3, R, + N_D4, R, N_C4, R, N_AS3, R, N_A3, R, + N_E3, R, R, R, N_A3, R, R, R, + N_D3, R, R, R, R, R, R, R, + N_D3, R, R, R, N_C2, R, R, R, + N_C2, R, R, R, R, R, R, R, + R, R, R, R, R, R, R, R +}; + +const uint16_t finale_ch2_seq[192] = { + N_D3, R, R, R, R, R, R, R, + N_A2, R, R, R, R, R, R, R, + N_C3, R, R, R, R, R, R, R, + N_AS2, R, R, R, R, R, R, R, + N_A2, R, R, R, N_E3, R, R, R, + N_D3, R, R, R, R, R, R, R, + N_D3, R, N_A2, R, N_D3, R, N_A2, R, + N_C3, R, N_G2, R, N_C3, R, N_G2, R, + N_AS2, R, N_F2, R, N_AS2, R, N_F2, R, + N_A2, R, N_E3, R, N_A2, R, N_E3, R, + N_D3, R, R, R, N_A2, R, R, R, + N_D3, R, N_A2, R, N_D3, R, N_A2, R, + N_C3, R, N_G2, R, N_C3, R, N_G2, R, + N_AS2, R, N_F2, R, N_AS2, R, N_F2, R, + N_A2, R, N_E3, R, N_A2, R, N_E3, R, + N_D3, N_C3, N_AS2, N_A2, N_G2, N_F2, N_E2, R, + N_A2, N_G2, N_F2, N_E2, N_D3, N_C3, N_AS2, N_A2, + N_D3, R, N_C3, R, N_AS2, R, N_A2, R, + N_D3, R, N_C3, R, N_AS2, R, N_A2, R, + N_A2, R, R, R, N_E3, R, R, R, + N_D3, R, R, R, R, R, R, R, + N_D3, R, R, R, N_C2, R, R, R, + N_C2, R, R, R, R, R, R, R, + R, R, R, R, R, R, R, R +}; + void sound_reset_music_state(void) { music_timer = 0; music_step = 0; @@ -197,6 +254,8 @@ void sound_reset_music_state(void) { victory_music_step = 0; title_music_timer = 0; title_music_step = 0; + finale_music_timer = 0; + finale_music_step = 0; } static void play_note(uint16_t reg_val) { @@ -240,6 +299,40 @@ void play_gameover_step(uint8_t step) { } } +void play_finale_step(uint8_t step) { + if (step < 192) { + uint16_t n1 = finale_ch1_seq[step]; + if (n1 != R) { + NR10_REG = 0x00; + NR11_REG = 0x80; + NR12_REG = 0xA2; // soft, long fade: somber melody + NR13_REG = n1 & 0xFF; + NR14_REG = (n1 >> 8) | 0x80; + } + uint16_t n2 = finale_ch2_seq[step]; + if (n2 != R) { + NR21_REG = 0x80; + NR22_REG = 0xD1; // deep bass, slow fade + NR23_REG = n2 & 0xFF; + NR24_REG = (n2 >> 8) | 0x80; + } + // CH4 noise toll at the start of each chord (every 8 steps): + // mid toll by default, crash at the scream climax, deep toll in the abyss. + if (step % 8 == 0) { + NR41_REG = 0x01; + NR42_REG = 0xB2; + if (step >= 160) { + NR43_REG = 0x70; // deep toll (abyss) + } else if (step == 80 || step == 88 || step == 112) { + NR43_REG = 0x42; // crash (climax) + } else { + NR43_REG = 0x68; // mid toll + } + NR44_REG = 0x80; + } + } +} + void play_victory_step(uint8_t step) { if (step < 96) { uint16_t n1 = next_level_seq[step]; @@ -296,7 +389,7 @@ void play_music_tick(void) { if (game_over) { // ENDGAME if (game_over_timer == 0) { // Se il ritardo di fine partita è terminato - if (game_over == 1 || game_over == 3) { // Defeat (Ghost) o Finale tragico + if (game_over == 1) { // Defeat (Ghost) gameover_music_timer++; if (gameover_music_timer >= 10) { // 10 frames per note (~6 notes/sec) gameover_music_timer = 0; @@ -305,6 +398,15 @@ void play_music_tick(void) { gameover_music_step++; } } + } else if (game_over == 3) { // Finale tragico (brano dedicato, piu' lento) + finale_music_timer++; + if (finale_music_timer >= 14) { // 14 frames per note (~4 notes/sec, somber) + finale_music_timer = 0; + if (finale_music_step < 192) { + play_finale_step(finale_music_step); + finale_music_step++; + } + } } else if (game_over == 2) { // Next Level (Going Deeper) victory_music_timer++; if (victory_music_timer >= 15) { // 15 frames per note = 4 notes/sec diff --git a/src/sound.h b/src/sound.h index f5db889..e7e737e 100644 --- a/src/sound.h +++ b/src/sound.h @@ -18,6 +18,7 @@ void play_music_tick(void); // Call to manually play a note from the game over / victory sequences void play_gameover_step(uint8_t step); +void play_finale_step(uint8_t step); void play_victory_step(uint8_t step); #endif