Repository navigation
restoHack v1.1.8
Downloads
-
Linux Static Binary: restoHack-v1.1.8-linux-x86_64-static.tar.gz
- Statically linked, runs on any x86_64 Linux
- No dependencies required
-
Source Code: restoHack-v1.1.8-source.tar.gz
- Full source for building on any platform
- Requires CMake, C compiler, and ncurses
-
Raspberry Pi Pico (RP2040): hack.uf2 + hack-volume.uf2
- Bare-metal build on rp2040-console, built from this tag by @neuhaus (#27)
- Hold BOOTSEL and copy each file to the board in turn; checksums in SHA256SUMS-pico.txt
Verification
Verify downloads with SHA256 checksums:
sha256sum -c SHA256SUMS
sha256sum -c SHA256SUMS-pico.txt # Pico imagesWhat's New
Added
qwertzoption for QWERTZ keyboards (off by default): withHACKOPTIONS=qwertzthe key labelled Z moves northwest and the one labelled Y zaps, as in NetHack'sswap_yz. Contributed by @neuhaus; a counted zap (2y) replayed as a move until fixed before merge. CI now checks the bindings and the counted replay (.github/scripts/qwertz-test.exp). (#29, #40)- README: link to the bare-metal Raspberry Pi Pico (RP2040) port by @neuhaus. (#26)
Changed
- dev/ soak setup: hardened lane runnable (
run-hardened.py,run-all.py --hardened, in the default set);--seed-offsetfor fresh dungeons per soak and--only-runto replay one run; enhanced mode adds</>and terminal shrink/restore cycles; moves drain output instead of sleeping (1000-step runs practical); non-zero game exit now fails a run; soak recipe in dev/README. - dev/ sanitizer harness: runners start (H1), cleanup stays inside the lane's hackdir (H3), sanitizer log files and failed quits now fail runs (H2, H4),
--stepshonoured, README fixed (H5); test builds (-DHACK_TEST_SEED) seed the game RNG fromHACK_SEEDso runs replay; hardened lane now configures (RelWithDebInfo,_FORTIFY_SOURCE=3). - README: Hack 1.0.3 is dated 1985 (not 1984); security and strength-overflow claims reworded to match what was actually fixed; protoHack description credits Brian Harvey and Dan Stormont for preserving and publishing Fenlason's source.
- README: current status updated to v1.1.7.
- HISTORY_OF_HACK.md: replaced a misquoted
struct monstwith the verbatim original; fixed a misattributed Fenlason quote; Rogue trip dated to summer 1981 (per TIMELINE); custody dates and protoHack's role corrected; removed uncited sections (Dark Ages, Digital Archaeology, Technical Legacy, Philosophy, Conclusion). - TIMELINE/COMPARISON:
READ_Me→READ_ME; 82-1 tape submitter and licensing wording corrected. - Package descriptions (CPack), CODING_STANDARDS, dev/README: Hack 1.0.3 is dated 1985; removed unsourced "94.2%/100% authentic" figures.
- TODO: save-system plan marked as shipped in v1.1.5.
- COMPARISON.md re-synced from protoHack after a source audit (line refs, counts, Hack 1.0 differences, stat-line survival, mechanics dated by the source).
- HISTORY_OF_HACK.md: Hack 1.0 has 62 monster types; "unique" names corrected (wumpus survives as Hack 1.0's NOWORM fallback); mklev merged in 1.0.2.
- TIMELINE: Harvey's account of sending JOVE to USENIX (jonmacs/jove#34); Bresnick vs Craddock on Jay's school year.
- README: FreeBSD CI ran on Cirrus until its June 2026 shutdown; Linux and macOS are CI-tested on GitHub Actions.
Fixed
- STABILITY: Shrinking the terminal below 80x24 mid-game exited without saving (
check_resize()re-ranstartup(), whose size check callserror()). The newterm_getsize()re-reads the size viaTIOCGWINSZ, and the game now waits on the "TERMINAL TOO SMALL" screen until the window is big enough; EOF there saves and exits throughhangup(). (#21) - MEMORY: Save/restore leaks from the original code.
save_engravings()dropped the engraving list without freeing it on every level save;dorecover()read the current level twice and leaked the first copy (monsters, objects, gold, traps, engravings, worm segments). Engravings are now freed as they're written, and the newfreelev()frees the first copy before the reread. (#23) - MEMORY:
savelev()cleared the worm segment lists without freeing them, leaking every worm segment on each level save (stairs, level teleport,S, and the level copies during restore); also in the original code. Segments are now freed as they're written. - STABILITY:
enexto()hung when the nearest free square was 49 or more columns away: itsxchar(signed char) loop counters wrapped past 127, so the scan never ended. Nowint. (#38) - STABILITY:
getlock()closed the lock file descriptor a second time whenveryold()closed it and then failed to unlink a stale lock; the caller now owns the descriptor. (#32) - STABILITY: The lock name was copied from
plnamewith the destination's size (35 bytes from a 32-byte array); now bounded byPL_NSIZ. Latent, asplnameis always terminated. (#33) - STABILITY:
freeobj()/freegold()dereferenced the list pointer before their NULL check could run, so a missing object crashed instead of reachingpanic(); also in the original code. (#34) - STABILITY:
RND()divides by zero for a modulus of 0; it now returns 0 for non-positive arguments. Latent: level generation never passes one (checked over 1000 seeds of every dungeon level). (#36) - CORRECTNESS: A nymph stealing cursed armor always said "you start taking" off: the curse bit was cleared before the message tested it; also in the original code. Now uses the saved value. (#35)
- CORRECTNESS:
hack.o_init.cdeclaredbwrite()/mread()asint (int, char *, int), conflicting with theirvoid (int, char *, unsigned)definitions (undefined behavior). (#30) - CORRECTNESS:
safe_strcat()/safe_strcpy()(hack.objnam.c) rejected pointers outside an assumed 64-bit address range, which breaks on targets such as WebAssembly; now a NULL check only. (#30) - Removed a duplicated
scrsymtest inmpickgold()/mpickgems()introduced during modernization. (#37) - Help file: the diagonal directions were listed swapped (
y: ne, u: nw, b: se, n: sw); the original 1985 file has the same error and is kept unchanged indocs/historical/. (#39)
Building from Source
tar xzf restoHack-v1.1.8-source.tar.gz
cd restoHack-v1.1.8
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/hack