Configuration file (lba2.cfg)

August 18, 2026 · View on GitHub

lba2.cfg stores user preferences and last-save info. Read at startup, written at exit. Options changed in the menu (see MENU.md) are persisted here. This doc distinguishes original keys from community additions so future changes can be tracked.

Path and discovery

  • Filename: lba2.cfg (SOURCES/COMMON.H line 83: CFG_NAME)
  • User config path: GetCfgPath(PathConfigFile, ..., CFG_NAME)directoriesCfgDir + filename (SOURCES/DIRECTORIES.CPP)
  • Default (assets): GetDefaultCfgPath()directoriesResDir + filename (same folder as LBA2.HQR, i.e. the game assets directory)
  • If user config missing: copy from assets to config dir (SOURCES/INITADEL.C). If the assets folder has no lba2.cfg, the engine writes an embedded copy (generated at build time from SOURCES/LBA2.CFG via cmake/embed_lba2_cfg.cmake) into the user config path instead of exiting.
  • Default config source: Prefer the file in the asset directory (directoriesResDir). The repo has SOURCES/LBA2.CFG and SOURCES/CONFIG/LBA2.CFG as reference/templates. See GAME_DATA.md for where assets live.

File format

  • DefFile format: Key: value or Key= value, ; comments (LIB386/SYSTEM/DEFFILE.CPP)
  • API: DefFileBufferInit(file, buffer, size), DefFileBufferReadString/ReadValue/ReadValueDefault, DefFileBufferWriteString/WriteValue

Lifecycle

  • Read: ReadConfigFile() in SOURCES/CONFIG_FILE.CPP, invoked from InitProgram()
  • Write: WriteConfigFile() in the same file, called from TheEndInfo()
  • Not to be confused with SOURCES/CONFIG.CPP, which is the in-game key-binding menu
  • Options menu changes globals only; config is written once at exit. No intermediate saves when changing options.
  • A setting forced for one run is not written back. The write serialises globals, so without this a flag whose own help says "this run only" would leave its value in the player's config for every later launch. --fixed-timestep, --language, --vsync and LBA2_TEXFILTER go through Settings_ValueToPersist in SOURCES/SETTINGS.H, which puts the stored preference back while the live value is still the one that was forced. Host test: tests/settings/. --resolution reaches the same end differently: Res_ResolutionShouldPersist is false for it, so WriteConfigFile leaves ResolutionX/Y as it found them. Only two things make a resolution a preference to keep, the config's own value and a resolution picked during the run (Display submenu, resolution console verb); an auto-detected one is left out of the file entirely so it re-derives from the display each launch.
  • Which flags may write is declared in CLI_ARGS.CPP's writes column, printed under --help-all as "[keeps this in your settings]", and held to by tests/automation/test_cli_flag_contract.sh. Only six may: --profile, --pick-game-dir and --bind-game-dir, whose job is to record a choice; --load, because restoring a save makes its player the current one and the config records that in LastSave exactly as loading from the menu does; and --exec / --exec-at, which carry console commands and so carry whatever those commands persist. Everything else must leave the settings byte-identical.

Keys: what each does

Accepted values

KeyTypeAccepted valuesDefaultClamping / notes
LastSavestringPlayer name, max 100 chars(empty)Used for quick load
Shadowint1–33Overwritten by DetailLevel when leaving Options. 1=none on extras, 2=no impact shadows, 3=full
AllCamerasint0, 110=OFF, 1=ON
FollowCameraint0, 10Auto camera (user-facing name; Enhanced Edition–style third-person follow in exterior). Config key stays FollowCamera for stability. 0=classic (default), 1=auto. Also reads legacy key AutoCameraCenter
ReverseStereoint0, 100=OFF, 1=ON
DetailLevelint0–330=min (no rain, no sea, no horizon), 1=486, 2=base Pentium, 3=max. Drives Shadow, RainEnable, MaxPolySea, FlagDrawHorizon
FullScreenint0, 110=small videos, 1=fullscreen videos. Invalid values → 1
DisplayFullScreenint0, 110=windowed display, 1=fullscreen display. Invalid values → 0
FlagDisplayTextstringON, OFFONCase-insensitive. Any other value → ON
WaveVolumeint0–12797Sample/SFX volume
VoiceVolumeint0–127112Voice volume
MusicVolumeint0–127127Music/jingle volume (stored as JingleVolume in code)
CDVolumeint0–12766CD audio volume (no-op when no CD); still supported in config but no longer shown in the in-game volume submenu
MasterVolumeint0–127127Master volume, scales samples and music
Input0_1..Input35_2intKey scancodesDefKeysDefault9536 inputs × 2 keys each (MAX_INPUT_SLOTS in INPUT_BINDINGS.H). Only read when WinMode=1
WinModeint0, 100=ignore Input* keys, use defaults; 1=read Input* keys. WriteInputConfig always writes WinMode=1
CompressSaveint0, 110=uncompressed saves, 1=compressed
Versionint0–5, distributor ID0 (UNKNOWN_VERSION)Which publisher's edition this is (DistribVersion): Activision, EA, Virgin, regional variants. Installer-written; set via the distrib console command. See VERSIONS.md
Version_USintany-1 when absentRead into Version_US and never used anywhere. Unrelated to Version. See VERSIONS.md
ShowDistribLogoint0, 11 when Version is declared, 0 when it is notWhether the publisher splash is drawn. Set via the distrib logo console command. The default is derived rather than stored, because a release that declares nothing ships no publisher branding either and a value read off the data is not grounds for showing one. Read only, never written back. See VERSIONS.md
LanguagestringEnglish, Français, Deutsch, Español, Italiano, PortuguesEnglishMust match TabLanguage[] exactly (case-insensitive)
LanguageCDstringSame as LanguageEnglishVoice CD language; only used with CDROM build
FlagKeepVoicestringON, OFFONKeep voice files on HD
MenuMouseint0, 111 = menu cursor, hover/left-click confirm, wheel for sliders and save list; 0 = keyboard/joystick only (classic)
TextureFilterint0–20Filtered texture sampling in the software fillers. 0=off (unchanged output), 1=horizontal 2-tap, 2=bilinear 4-tap. LBA2_TEXFILTER overrides for one run without persisting. See GFX_OPTIONS.md
FixedTimestepint0–100 (ms)16Sim throttle, so movement is frame-rate independent above 60 fps; 0 restores the historical per-frame simulation. Set by the fixedtimestep console verb; --fixed-timestep overrides for one run without persisting. See MOVEMENT_FRAMERATE.md
VSyncint0, 11Cap the frame rate to the display refresh. Invalid values → 1. Set by the Display submenu's toggle and the vsync console verb; --vsync <on|off> overrides for one run without persisting. The Display submenu prints it, so a UI capture has to pin it; see CONTROL.md
DitherShadingint0, 10Ordered dither on Gouraud shade rows, softening the 16-step ramp banding. See GFX_OPTIONS.md

Original keys (Adeline)

KeyPurposeSourceMenu
LastSavePlayer name for quick loadReadConfigFile / WriteConfigFile(implicit)
ShadowShadow quality (1–3)ReadConfigFile / WriteConfigFileOptions → Detail
AllCamerasScenario cameras ON/OFFReadConfigFile / WriteConfigFileOptions
ReverseStereoStereo invertReadVolumeSettings / WriteVolumeSettingsOptions, cvar snd_reverse_stereo
DetailLevelGraphics detail (0–3)ReadConfigFile / WriteConfigFileOptions
FullScreenVideo playback sizeReadConfigFile / WriteConfigFileOptions → Advanced options
DisplayFullScreenWindow/display fullscreen toggleReadConfigFile / WriteConfigFileOptions → Advanced options
FlagDisplayTextShow subtitles during voiceReadConfigFile / WriteConfigFileOptions → Advanced options
WaveVolume, VoiceVolume, MusicVolume, MasterVolumeVolume slidersReadVolumeSettings / WriteVolumeSettingsOptions → Sound volume, cvars snd_wave snd_voice snd_music snd_master
CDVolumeCD audio volumeReadVolumeSettings / WriteVolumeSettingsconfig only, cvar snd_cd
Input0_1..Input35_2, WinModeKeyboard mappingsReadInputConfig / WriteInputConfigOptions → Keyboard
CompressSaveSave compression formatReadConfigFile(installer)
VersionDistributor edition (DistribVersion)ReadConfigFile / distrib console(installer; distrib console)
Version_USNone; read but never usedReadConfigFile(never written)
ShowDistribLogoPublisher splash on or offReadConfigFile / distrib logo console(distrib logo console)
LanguageInstall, Demo, PathInstallNone; installer bookkeeping, never read(installer only)(installer)
Language, LanguageCD, FlagKeepVoiceLanguage / voice CDMESSAGE.CPP, ReadConfigFile / WriteConfigFileOptions → Choose language

Note: FlagKeepVoice remains installer / CONFIG-tool managed. Language and LanguageCD are now also written by the in-game Options menu.

Community / modernized additions

KeyPurposeSourceMenu
MenuMouseOptional mouse UX in game menus (FlagMenuMouse in code). Default 1 (on). Set 0 to match classic keyboard/joystick-only menus. See MENU.mdReadConfigFile / WriteConfigFileOptions → Advanced options
FollowCameraAuto camera for exterior scenes (0=classic, 1=auto). Community addition, not in original game; menu label is "Auto camera" / "Classic camera"ReadConfigFile / WriteConfigFileOptions → Advanced options
TextureFilter, DitherShadingSoftware-rasterizer smoothing, both off by default. Console cvars gfx_texfilter / gfx_ditherReadConfigFile / WriteConfigFileconsole only

How a key is declared

A key is one row in a table, in the module that owns the setting. The cfg reader, the cfg writer and the console's cvar table all read that table rather than naming the setting, so adding a key is a single row and its rule, not merely its range, reaches every surface that can write it: the console hands a typed value to the setting's owner rather than deciding for itself, so a key answers the console and the config file the same way. The row type is T_SETTING in SOURCES/SETTINGS.H.

Three tables exist today: BootSettings in SOURCES/CONFIG_FILE.CPP for the boot and display keys, FollowCamSettings in SOURCES/FOLLOWCAM.CPP for the Auto camera's, and AudioSettings in SOURCES/AMBIANCE.CPP for the volumes and the stereo swap. Row order is the file's key order, which players see: the config is rewritten in table order, so moving a row reorders every existing lba2.cfg on the next save.

A row states what happens to a value outside its range, because the engine does not do one thing here, it does four. This is the vocabulary behind the "Clamping / notes" column above:

RuleMeaningExample key
SETTING_CLAMPmove it to the nearer boundDetailLevel
SETTING_OR_DEFAULTout of range counts as unset, so the default standsFullScreen, TextureFilter
SETTING_TRUTHYany non-zero is onFollowCamHDRecompose
SETTING_RAWno range at all; whatever the file said standsAllCameras, Shadow

Picking the wrong one is invisible to a normal config: a file the engine wrote holds only in-range values, so the rules can only differ on a value the engine did not write. They are covered by a host test in tests/settings/ rather than by any read-write comparison.

Two further columns, both optional:

  • legacy names an older spelling to read when the current key is absent, so a renamed key keeps working and moves to its new name on the next write. FollowCamera reads AutoCameraCenter this way.
  • stored / forced mark a key some flag can force for one run. The reader keeps what the file held, and the writer puts that back rather than the forced value, which is what stops --fixed-timestep or --vsync leaving a one-run choice behind. See the lifecycle note above.

Not everything is a row. Keys that are not a single integer stay hand-written: LastSave and Language are strings, the key bindings and volumes have their own blocks (ReadInputConfig / ReadVolumeSettings), and ResolutionX/Y follow the separate rule described above. Side effects of a setting, applying fullscreen or swapping stereo, run after the table has loaded the values rather than inside it.

Code reference

ConceptFileFunction/Symbol
Config read/writeCONFIG_FILE.CPPReadConfigFile, WriteConfigFile, BootSettings
Setting declarationSETTINGS.HT_SETTING, Settings_Coerce, Settings_ValueToPersist
Per-module tablesFOLLOWCAM.CPPFollowCamSettings, FollowCam_ReadConfig, FollowCam_WriteConfig
Volume persistenceAMBIANCE.CPPReadVolumeSettings, WriteVolumeSettings
Input persistenceINPUT.CPPReadInputConfig, WriteInputConfig
Config pathDIRECTORIES.CPPGetCfgPath, GetDefaultCfgPath
DefFile APILIB386/SYSTEM/DEFFILE.CPPDefFileBufferInit, DefFileBufferRead*, DefFileBufferWrite*

Cross-references