Repository navigation
Digger v0.5
115 commits since v0.4. This release adds eDRF, a new recording format that plays back the same way every time. It also makes NetSim online play much more robust, fixes a number of long-standing gameplay bugs, and fixes the buzzy SDL sound.
✨ Highlights
- eDRF recordings. An eDRF stores the controls pressed on every tick, the random seed of each round, each level's map, and regular checkpoints (MD5 hashes) of the whole game state. Playback feeds the recorded input through the normal input code and checks every checkpoint, so any divergence is detected and reported. Recordings named
*.edrfare written in this format. To convert an old DRF, play it back while recording:/R:x.edrf /E:x.drf. A recording cut short by quitting the program still plays back up to where it stops. Quitting a game (F10, or either NetSim player leaving) is recorded too. - Take over a playback. Use
/T:tick, or the cheat key (Ctrl-T, or T with SDL), to take control from the next tick. This now works for eDRFs too. Any/Rrecording continues with your input, and the game drops back to normal speed. - Meaningful
/Eexit status:0reached the end,1recording unreadable,2eDRF diverged,3stopped early,4eDRF ends before its game does. - Redefine keys from the title screen with K (the key itself can be redefined).
🌐 NetSim (online two-player)
- Replays a two-Digger eDRF over NetSim with two Digger instances.
- Each round gets a random seed again, and both peers share it. Before this, every round started with seed 0.
- Many SIP/session robustness fixes:
- Gives up on a peer that doesn't answer an INVITE after 5 s.
- Keeps a call whose ACK is lost while the peer's frames still arrive.
- Resends with exponential backoff, capped at a quarter of the sync timeout.
- SIP messages that can't be sent are retried on the SIP timers.
- Each call and transaction gets its own SIP IDs.
- The answering side waits for the caller without hitting the sync timeout.
- The wait for the peer's first frame can be quit.
- Only one side hangs up when both players leave on the same frame.
- No more
SO_REUSEADDRon sockets. Uses microsippy'sDEFAULT_UDP_PORT, and the waiting peer can listen on any address. - Better diagnostics: timestamped log lines (SIP included), the reason a session failed carried through to hangup and game end, and the game position on each log line.
- Default sync timeout raised to 5 s.
- Test hooks are now behind
DIGGER_INSTRUMENTATION. - microsippy updated: INVITE transactions run to completion, lingering transactions are evicted, memory is aligned, the byte order is the host's, and
%zuis avoided for MinGW.
🎮 Gameplay fixes
- The title screen's two-player simultaneous mode is now really simultaneous. It used to fall into alternating-player logic and write past
digdat[]. - High scores follow the game mode picked on the title screen. Before, they stayed on the startup mode's table and could overwrite another mode's table.
- A dead Digger's gravestone no longer eats monsters while the other Digger is in bonus mode.
- A bag kill scores in full (250) for the remaining Digger when the other one is out of lives. It used to be split 125/125, even with a dead player.
- A monster whose Digger is dead chases the player's other Digger (fixes a
digdat[-1]read). - Player 2's fireball is removed when their round of an alternating game ends.
- Player 1 of a one-player game no longer reads a level map before the first one.
- A single Digger's death takes the same number of ticks with or without music. Playback now goes the same way every time, and each death takes 16 more ticks than before.
- The Gauntlet clock counts in game ticks, so it's correct at any playback speed.
- Both scores are shown when a level of an alternating game starts.
- The title screen's Hobbin now transforms by bumping into the Nobbin, as in the game.
- Arguments after the last
/Por/Enow apply to that playback (e.g.DIGGER /E:GAME.DRF /Q /S:0). - Better messages when a recording can't be played back, or can't be replayed over NetSim.
🔊 Sound
- SDL output is no longer overdriven. A leftover 8-bit→16-bit conversion scaled every sample 128× too high, which clipped most of the music.
- The main tune comes back after an extra life is gained on the last life.
- Fixed sound ack/command-queue assertions.
/Qno longer opens the audio device, and a full command queue drops the command instead of asserting.
🕸️ Web build
- Settings and high scores persist in
localStorage. - The CONTROLS panel is built from the actual key bindings (player 2 included).
- Favicon added. The canvas is pixelated only at whole-number device pixel ratios. The nonexistent F11 SETTINGS button is gone.
🛠️ Build, packaging & CI
- CMake: link-time optimisation and hidden symbols, libatomic linked when needed, minimum version 3.10.
- macOS package bundles SDL3 for Homebrew's
sdl2-compat. - Dependencies: zlib 1.3.2, Emscripten 6.0.11. SDL and zlib versions are now set in one place.
- Safety fixes: bounds-checked
GetINIString(), the score file path built in aPATH_MAXbuffer, and stricter warnings (-Werrorin all CI builds). - CI: ASan, MSan and UBSan runs (GCC and Clang), and Ubuntu 26.04. The Docker job builds on Debian 13, uses ccache and lld, and tests each platform in its own container. The Windows build runs the quick tests.
- Tests: eDRF playbacks, NetSim replays on localhost (including quits by either player, synthetic packet loss, and multi-game runs), new two-Digger and Gauntlet recordings, and a parallel test runner.
New Contributors
Full Changelog: v0.4...v0.5