diff --git a/AGENTS.md b/AGENTS.md index 3071562..b33aa74 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,7 +14,7 @@ The implementation is split into focused modules (files) under the `src/MarcerGa - MarcerGameDvdLauncher/NavigationController.cs: Encapsulates selection, scrolling and relative-path navigation logic (cursor, page up/down, per-directory remembered selection/state); uses named scroll-fraction constants. - MarcerGameDvdLauncher/MenuRenderer.cs: Console rendering logic — efficient per-line redraw, double-buffering, configurable color selection via injected `AppColorConfig`, and the help box overlay. - MarcerGameDvdLauncher/InputController.cs: Handles key events (arrow keys, Enter, Backspace, PageUp/Down, `*`, `?`, ESC) and the associated navigation/drawing logic; owns `ReloadGameEntries` and the virtual `Favorites` folder integration. -- MarcerGameDvdLauncher/HatariLauncher.cs: Responsible for validating the Hatari executable and starting Hatari with the configured argument template (replaces `{cfg}` and `{zip}`). +- MarcerGameDvdLauncher/HatariLauncher.cs: Responsible for validating the Hatari executable and starting Hatari with the configured argument template (replaces `{cfg}` and `{zip}`). Exposes `DefaultConfigFile` constant (`MarcerGameDvd-Hatari.cfg`); when `Hatari.ConfigFile` is empty in `launcher.config.json`, the bundled config from the executable directory is used automatically. - MarcerGameDvdLauncher/FavoritesService.cs: Manages the favorites/bookmark system — toggling favorites on ZIPs, persisting them to `favorites.txt` (via `DefaultFileName` constant), and providing the virtual `Favorites` folder view (via `FavoritesRootName` constant). - MarcerGameDvdLauncher/UIErrorService.cs: Centralized UI error presentation using the console message helper. diff --git a/README.md b/README.md index 8f810bd..d7b9bd0 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,7 @@ Download the ZIP for your platform from the [Releases](https://github.com/anomal ### 💻 System Requirements - **.NET Runtime 10** or later ([download](https://dotnet.microsoft.com/download/dotnet/10.0)) -- **Hatari Emulator** with a working configuration file - - Windows: native Hatari - - Linux / macOS: Hatari via Wine or native build +- **Hatari Emulator** (Windows native, or Linux/macOS via Wine or native build) — a Hatari configuration file (`MarcerGameDvd-Hatari.cfg`) is bundled with the launcher and used automatically when `Hatari.ConfigFile` is empty. ### ⚡ Quick Start @@ -71,7 +69,7 @@ The launcher reads `launcher.config.json` from the same directory as the executa "PatchDirectory": "C:\\Games\\Hatari\\PATCH", "Hatari": { "Executable": "C:\\Tools\\hatari\\hatari.exe", - "ConfigFile": "C:\\Tools\\hatari\\hatari-st.cfg", + "ConfigFile": "", "ArgsTemplate": "-c \"{cfg}\" --disk-a \"{zip}\"" }, "Colors": { @@ -93,7 +91,7 @@ The launcher reads `launcher.config.json` from the same directory as the executa | `RootDirectory` | ✅ | Game root folder. Navigation never leaves this directory. | | `PatchDirectory` | ❌ | Optional overlay/patch directory merged at runtime. | | `Hatari.Executable` | ✅ | Path to the Hatari executable. Validated at startup. | -| `Hatari.ConfigFile` | ✅ | Path to the Hatari configuration file. | +| `Hatari.ConfigFile` | ❌ | Path to a Hatari configuration file. If empty, the bundled `MarcerGameDvd-Hatari.cfg` (shipped with the launcher) is used automatically. | | `Hatari.ArgsTemplate` | ✅ | Argument template. Must contain `{zip}`, optionally `{cfg}`. | | `Colors` | ❌ | Optional color overrides. See [Color Scheme](#-color-scheme) below. Missing or invalid values fall back to defaults. | diff --git a/src/MarcerGameDvdLauncher/HatariLauncher.cs b/src/MarcerGameDvdLauncher/HatariLauncher.cs index 8859025..fc5ee6a 100644 --- a/src/MarcerGameDvdLauncher/HatariLauncher.cs +++ b/src/MarcerGameDvdLauncher/HatariLauncher.cs @@ -5,6 +5,11 @@ namespace MarcerGameDvdLauncher { public class HatariLauncher { + // The Hatari configuration file that is shipped with the launcher. + // When Hatari.ConfigFile is not set in launcher.config.json, this file + // (resolved relative to the executable directory) is used automatically. + public const string DefaultConfigFile = "MarcerGameDvd-Hatari.cfg"; + private readonly string _exePath; private readonly string _cfgPath; private readonly string _argsTemplate; diff --git a/src/MarcerGameDvdLauncher/LauncherApp.cs b/src/MarcerGameDvdLauncher/LauncherApp.cs index 4cffe86..44744d1 100644 --- a/src/MarcerGameDvdLauncher/LauncherApp.cs +++ b/src/MarcerGameDvdLauncher/LauncherApp.cs @@ -63,8 +63,15 @@ namespace MarcerGameDvdLauncher if (!File.Exists(cfg.Hatari.Executable)) throw new InvalidOperationException($"Hatari executable not found: {cfg.Hatari.Executable}"); - // Also validate the Hatari config file (if provided) - if (!string.IsNullOrWhiteSpace(cfg.Hatari.ConfigFile) && !File.Exists(cfg.Hatari.ConfigFile)) + // If no Hatari config file was specified, fall back to the bundled + // MarcerGameDvd-Hatari.cfg that ships with the launcher. + if (string.IsNullOrWhiteSpace(cfg.Hatari.ConfigFile)) + { + cfg.Hatari.ConfigFile = Path.Combine(exeDir, HatariLauncher.DefaultConfigFile); + } + + // Validate the Hatari config file (either user-specified or bundled fallback) + if (!File.Exists(cfg.Hatari.ConfigFile)) throw new InvalidOperationException($"Hatari configuration file not found: {cfg.Hatari.ConfigFile}"); if (string.IsNullOrWhiteSpace(cfg.Hatari.ArgsTemplate) || !cfg.Hatari.ArgsTemplate.Contains("{zip}")) throw new InvalidOperationException("Hatari.ArgsTemplate must contain the {zip} placeholder."); diff --git a/src/MarcerGameDvdLauncher/launcher.config.example.json b/src/MarcerGameDvdLauncher/launcher.config.example.json index 2c8e2c8..a211056 100644 --- a/src/MarcerGameDvdLauncher/launcher.config.example.json +++ b/src/MarcerGameDvdLauncher/launcher.config.example.json @@ -3,7 +3,7 @@ "PatchDirectory": "C:\\Games\\Hatari\\PATCH", "Hatari": { "Executable": "C:\\Tools\\hatari\\hatari.exe", - "ConfigFile": "C:\\Tools\\hatari\\hatari-st.cfg", + "ConfigFile": "", "ArgsTemplate": "-c \"{cfg}\" --disk-a \"{zip}\"" }, "Colors": {