Ultima meccanica di gameplay: se hai meno di 60 stamina puoi comunque
tentare il salto, ma rischi di cadere nell'abisso. La probabilita' di
caduta e' proporzionale a quanto stamina ti manca da 60:
- 60 stamina: 0% caduta (salto sicuro)
- 30 stamina: 50% caduta
- 0 stamina: 100% caduta
Se cadi: il giocatore salta verso la cella intermedia (vuoto) invece di
quella di atterraggio, poi cade velocemente verso il basso (animazione
fall_offset, 2x pixel per frame) e game over con la schermata di morte.
Differenza chiave: il salto sicuro atterra a distanza 2; il salto fallito
si ferma a distanza 1 (sopra l'abisso) e cade.
Quando il giocatore raggiunge la botola (vittoria/finale), invece di
pulire subito lo schermo, il giocatore scende di pochi pixel verso il
basso (descend_offset) per 30 frame prima che appaia la schermata
Going Deeper / finale.
- descend_offset: variabile globale, incrementata durante game_over_timer
- render.c: y_offset negativo (discesa graduale, >>1 = meta' pixel)
- player_logic.c: rimossa la dissolvenza immediata, avviata l'animazione
- engine.c: animazione durante il timer, max 12 step (~6 pixel)
Aggiunge hint_shown_once: le istruzioni appaiono solo la prima volta
che si gioca il livello 1. Se il giocatore muore e riprova, o torna al
titolo e ricomincia, le istruzioni non si rimostrano.
SELECT in gioco rimane disponibile per rivederle quando si vuole.
Premendo START nel menu titolo appare l'introduzione narrativa:
'You were walking alone in the dead of night. Without warning, an
unnatural darkness consumed the world around you. Your only comfort
is a faint torch. The path behind you is gone. Descend deeper into
the unknown.'
Si chiude con un tasto qualsiasi, poi avvia la partita.
Usa il Window layer come le altre schermate testuali.
Ripristina anche death.c e instructions.c dai commit precedenti.
SELECT nel menu titolo mostra i crediti: titolo, autore (Matteo B.),
strumenti (GBDK 2020, SDCC SM83, PyBoy). B per tornare al titolo.
Usa il Window layer (come le istruzioni) per non corrompere il BG map.
Ricrea i file src/screens/ rimossi da make clean (death.c,
instructions.c, screens.c) e aggiunge credits.c.
Schermata istruzioni mostrata all'inizio del livello 1, chiudibile con B,
ri-apribile in gioco con SELECT. Testo con font IBM (stesso pattern del
finale game_over==3 e della sconfitta game_over==1).
Contenuto: titolo, obiettivo (find the hatch), controlli (DPAD walk,
A jump abyss, B run), istruzioni di chiusura (press B, select help).
Per fare spazio: rimosso claimed.png (schermata di morte ora testuale
con lo stesso font, stesso pattern del finale).
Maze size grows +2/level from 7x7 to 21x21 (cap MAX_MAP_SIZE=21, reached
at level 8). Additional difficulty axes scale with level:
- +1 ghost per level (up to MAX_ENEMIES=8); enemy state moved to arrays,
enemy_logic.c rewritten as a multi-entity loop (own AI, render at OAM
2+i*2, staggered cooldowns).
- Ghost cooldown shrinks: 60 -> ~11 frames between steps.
- Stamina recharge slows: 60 -> 144 frames per point.
- Fog tightens to 3x3 (fog_radius=1) from level 7.
Fog rendering uses a dynamic 16-row centered flush (with wrap) instead of
the fixed rows 2-17 / full 32x32, so the fog stays correct on big mazes
without the multi-frame stall of the full flush.
Game ends after level 8: reaching the hatch at level 8 sets game_over=3
(finale) instead of 2. Finale screen reloads the IBM font and writes
'YOU ESCAPED / THE DARKNESS / LEVEL 8 CLEARED / PRESS START' into the BG
map; START returns to the title (new game starts at level 1).
Verified via PyBoy: sizes 7..21, fog 2->1 at L7, enemies 1..8 (distinct,
on floor, can catch the player), cooldown/recharge scaling, L1 hatch ->
game_over=2, L8 hatch -> game_over=3, finale renders + START->title->L1.
The maze side length is now a runtime global 'map_size' (MAP_SIZE=7 at
level 1, +2 per level, capped at MAX_MAP_SIZE=17), while the maze array
is allocated with the MAX_MAP_SIZE bound. All modules (maze DFS, fog
rendering, player/enemy bounds, hatch and enemy-spawn placement) now use
map_size at runtime.
- globals: maze[MAX_MAP_SIZE][MAX_MAP_SIZE], map_size global, MAX_MAP_SIZE=17.
- maze.c: DFS on map_size; stack/valid arrays made static (WRAM) and sized
for the max maze to avoid hardware-stack overflow; hatch min distance
scales with map_size/2.
- engine.c: sets map_size from level before generate_maze; enemy spawn min
distance scales with map_size/2.
- render.c: flush the full 32x32 background map (the old rows 2-17
optimization broke for large mazes where the 5x5 fog window wraps outside
that range); dynamic bounds; signed/unsigned casts.
- player_logic/enemy_logic: dynamic map_size bounds.
Verified via PyBoy: sizes 7,9,11,13,15,17,17 across levels 1-7, each with
a hatch; rendering and movement intact at 17x17 and at 7x7.
Run (B + direction):
- player_logic.c: while holding B + direction with stamina >= 10, each tile
takes 8 frames instead of 16 (move_progress += 2, LERP >>4 unchanged) and
costs 10 stamina per tile. DAS_REPEAT_RUN=2 chains tiles fluidly.
- Falls back silently to normal walk when stamina < 10.
Level progression:
- New global 'level' (starts at 1). title->game resets to 1; reaching the
hatch (victory/Going Deeper) + START increments before engine_init (new
maze); defeat + START resets to 1.
- Top-left HUD 'L<n>' via 3 sprites (OAM 23-25) from new level.png asset
(glyphs L, 0-9), generated by scripts/generate_level.py and converted
with png2asset -keep_duplicate_tiles for predictable tile ordering.
- VRAM base aligned to an EVEN index (8x16 hardware ignores tile LSB) and
placed after the stamina load claim to avoid the shared BG tile block.
- update_level_display() called every frame; hides during game over/title.
Docs: README, doc/gameplay.md and the technical report updated.