v0.10.0
Second tagged release of the fork. ~30 merged PRs since v0.9.0: first-launch folder picker, gamepad-friendly saves, console give/slide, macOS DMG + Linux tarball joining the AppImage and Windows ZIP, a UB hardening pass from new clang-tidy CI, restored ScaleSprite distance scaling (most visible: the magic ball receding properly in exteriors), and a refactor laying the foundation for the widescreen work.
Welcomes @b-tuma as a new contributor (gamepad D-pad navigation, #79).
Binaries for Linux (AppImage + tarball, x86_64 + aarch64), macOS (Apple Silicon DMG), and Windows (x64 ZIP) attached below. Smoke-tested against a clean debian:stable-slim container with no SDL3 / X11 / audio deps preinstalled. macOS DMG still needs the right-click → Open Gatekeeper bypass on first launch (Developer ID + notarization deferred); see the README inside the DMG.
New features (opt-in)
- Cross-platform first-launch folder picker: when no retail game data is found via the usual discovery paths (
./data,../LBA2,LBA2_GAME_DIR,--game-dir), the engine now prompts for the install folder via the native system file dialog instead of exiting with an error. Picked path is persisted to a user-config file for next run; pass--pick-game-dirto force the picker again. Works on Windows, macOS, and Linux (zenity / xdg-desktop-portal-* on Linux, with explanatory fallback text when no backend is installed) (#107, #111). - Save/load list now navigable with gamepad D-pad (#79).
- Auto-named saves for gamepad users: gamepad input on the save-name prompt skips text entry and writes a scene-aware default name in the form
<scene> - YYYY-MM-DD HH-MM-SS(e.g.Citadel Island - 2026-05-17 14-30-00). The scene portion is localised across the six menu languages (sourced from the retailTEXT.HQRfile 2); the date/time portion is fixed%Y-%m-%d %H-%M-%S. Long names clip with a marquee in the save list; post-save success chime + "Game saved" overlay (#151). - Console
givecommand now actually grants inventory items instead of only playing the found-object cinematic. It takes an item name (give conch), with the numeric index still accepted as a fallback; rungivewith no arguments to list every item name. Countable items accept an optional count (give gem 5,give money 5000,give clover 3) (#143) — see docs/CONSOLE.md. - Console
slidecommand jumps directly to a distributor/bumper slide (Adeline, EA, etc.); companiondistribcommand lists the available slide IDs (#116).
Stability & fixes
ScaleSpritescaled path restored. A 2024 ASM→CPP port had stripped the scaled-output branches, leaving the function effectively unscaled for months. The most visible symptom in-game: world-space sprites that should shrink with distance no longer did — the magic ball, for example, stayed the same size as it flew away from Twinsen in exterior scenes instead of receding with distance. The regression went unnoticed because the existing test only varied numerator/x/y, not the scale factor. Mirrored back fromSCALESPTASM, and the test matrix extended to cover factor sweeps (#148).TempoRealAngleextern conflict in savegame load:DEBUG_TOOLS=ONbuilds failed to compile because PR #62's stride-retry refactor introduced a wrong-typedextern S32 TempoRealAnglenext to the existing file-scopeT_REAL_VALUE_HRdefinition. Default builds were unaffected (the block is#if-gated out). Fix removes the redundant extern (#146).GereExtrasno longer reads uninitialised old-position memory (#142).- Undefined-behaviour hardening pass from the static-analysis sweep: shift-by-32 UB in the
POLYGOURdither rotate, signed-overflow inI_WEAPON_7/A_FLIPbit masks, andTheEndCheckFilemarkednoreturnto close null-deref paths flagged downstream (#140). deffileconfig parser: signed-charEOL desync and self-aliasingstrcpycleaned up. Bug A was user-reported: alba2.cfgcontainingLanguage: Français(or any other Latin-1 high-bit byte) corrupted on successive rewrites — 21 strayçaislines spliced in and all 144 keyboard + gamepad bindings reset to zero. Bug B was an overlappingstrcpy(FileName, file)caught by ASan against the GOG TLBA2 Classic package on shutdown. Both were old, both UB. Host-only regression test added underhost_quick(#115, #132).- Terrain vertex projection: dropped the no-op / off-by-one
+0.5rounding bias that desynced terrain vertex positions from the rest of the scene (#145).
Refactoring
- Framebuffer dimensions extracted to
RESOLUTION_X/RESOLUTION_Yin a newLIB386/H/SYSTEM/RESOLUTION.H. Cinema bars and sort-tree preclip now route throughModeDesiredX/Yinstead of hardcoded640/480. Foundation for the widescreen / higher-resolution rendering work (#134).
Game data, config, and UX
lba2.cfgdefaults modernised for the open-source era: fullscreen on by default (DisplayFullScreen=1), Version row defaults tightened to match the shipping engine (#117).
Tools
scripts/dev/extract_lba2_gog_media.pyextracts the retail media tree from the GOG Original EditionLBA2.GOGbin/cue image (ISO9660 reader with no externalmount/isoinfodependency). Lets users with the GOG install seed./datawithout owning the original CDs (#119, #123).
Cross-platform & build
- macOS native release artifact: a portable DMG with the
.appbundle inside, drag-to-Applications layout, native multi-resolution.icnsicon, and anInfo.plistpopulated from the sameLBA2_*cache vars that drive the runtime window title,.desktopentry, AppImage labels, and Windows resource. Built for arm64 (Apple Silicon) on tag push; static-linked SDL3, no.dylibdependencies, ad-hoc codesigned to satisfy Apple Silicon's mandatory bundle integrity check. First launch still needs the right-click → Open Gatekeeper bypass (Developer ID + notarization deferred); documented in the README inside the DMG, and the Sequoia (15+)xattr -dr com.apple.quarantinerecovery flow is spelled out in docs/RELEASING.md. Intel-Mac users can produce a local DMG viascripts/dev/build-macos-release.sh --preset macos_x86_64while hosted Intel runners are unreliable (#102, #103, #105, #106, #149). - Linux binary tarball release artifact alongside the AppImage: same static-linked single-binary layout, drop-in for distros where AppImage FUSE is a hassle.
libxtst-devadded to the tarball build deps after the first CI run surfaced the missing X11 link (#124, #125). - Post-release smoke-test script (
scripts/dev/verify-release.sh) downloads each published Linux artifact, runs the discovery self-tests, and reports per-asset pass/fail. Pointers added to the releasing recipe and announcement steps (#126, #127). - Rolling
latestpre-release: every push tomaintriggers a CI build of all three platforms (Linux AppImages, Windows ZIP, macOS DMG) and force-updates alatest-tagged GitHub Release. Marked pre-release; the most recent stable tag keeps GitHub's "Latest" promotion. Lets community testers grab bleeding-edge main builds without cloning + building (#108) — see docs/RELEASING.md "Rolling latest pre-release". - Release workflow hardening: low-friction release-target additions, CI path filters so doc-only pushes skip the heavy matrix, pinned
setup-sdlSHA + per-arch cache discriminator after a stale-cache drift incident (#129, #130).
CI & developer workflow
clang-tidystatic-analysis pass wired into CI, with a tuned check-list that silences bulk-noise categories (Watcom-era idioms, C-style casts in ported code) while keeping the high-signal UB / memory-safety / portability checks. The first analysis pass produced the UB-hardening fixes listed above (#139, #141).- Docs-only gate for the required build/test checks so README/CHANGELOG edits don't block on the full matrix (#136).
- Optional
pre-commithook runningcheck-format.shfor contributors who'd rather catch clang-format mismatches locally than in CI (#133).
Documentation
- docs/WIDESCREEN.md — phased plan (A–E) for the widescreen / higher-resolution work, with the framebuffer-extraction refactor above as its first landed phase (#135).
- docs/CI.md — map of the CI workflow surface (matrix builds, gates, release flow) so contributors can reason about a failing job without spelunking the YAML (#137).
- docs/SPRITES.md — sprite/blit pipeline reference, including the
ScaleSpritepath layout and the test gap that hid the scaled-path regression for months. - docs/AUDIO.md extended with the retail audio asset inventory: what's ADPCM-WAV, what's MIDI, and which backend owns which path.
Contributors
Welcome to a new contributor since v0.9.0: @b-tuma — gamepad D-pad navigation for the save/load list (#79).
Full Changelog: v0.9.0...v0.10.0