# wolf_3d_dart Core non-Flutter Wolfenstein 3D runtime package used by both CLI and Flutter hosts. ## What This Package Provides `wolf_3d_dart` contains the platform-neutral simulation/runtime surface: - engine and session lifecycle, - game-data loading and data types, - renderer backends and frame-buffer abstractions, - menu state/navigation models, - input/audio host abstractions, - entity and gameplay logic. ## Public Library Surfaces Primary entry libraries in `lib/`: - `wolf_3d_engine.dart` — engine exports and runtime contracts. - `wolf_3d_data.dart` / `wolf_3d_data_types.dart` — game-data discovery and DTOs. - `wolf_3d_renderer.dart` — rendering/backends integration points. - `wolf_3d_audio.dart` — audio interfaces and host backends. - `wolf_3d_input.dart` — input abstractions. - `wolf_3d_menu.dart` — menu models/managers and the registry-backed `WolfMenuPresentation` helpers for hosts. - `wolf_3d_host.dart` — host-level glue contracts. Implementation details live under `lib/src/`. ## Setup From this directory: ```bash dart pub get ``` ## Development Commands From this directory: ```bash dart analyze dart test ``` ## Architecture Notes - Hosts own platform concerns (windowing, lifecycle, platform input wiring). - This package owns deterministic engine/frame progression and shared game logic. - Frame-buffer sizing is controlled by hosts through engine APIs. - Rendering code is maintained under `lib/src/rendering/`. - Menu coordination is split under `lib/src/menu/manager/`; public consumers should prefer `lib/wolf_3d_menu.dart` or the internal barrel at `lib/src/menu/menu_manager.dart` instead of reaching into individual implementation files. - Menu presentation is selected through `AssetRegistry.menuPresentation`, which keeps retail/shareware/Spear variants and user-defined menu overrides aligned with the rest of the registry system. ## Custom Menus Custom menu support is split across two registry modules: - `MenuPicModule` maps symbolic menu keys such as `MenuPicKey.title` or an episode selection entry to concrete VGA picture indices in `WolfensteinData.vgaImages`. - `MenuPresentationModule` defines the palette indices and higher-level menu art lookups that renderers and hosts consume. That split is intentional: - `MenuPicModule` answers "which image index represents this menu asset for this game/mod?" - `MenuPresentationModule` answers "which colors and optional art should the UI use?" In practice, most custom variants will either: - reuse an existing `MenuPicModule` and only change colors/presentation, or - provide both a custom `MenuPicModule` and a matching `MenuPresentationModule` when the menu art layout itself changes. ### Using Menu Presentation From Loaded Data Once game data has been loaded, bind menu presentation through the active registry: ```dart final WolfMenuPresentation menu = WolfMenuPresentation(data); final int panelColor = menu.panelColor; final VgaImage? title = menu.title; final VgaImage? episode1 = menu.episodeOption(0); ``` This is the normal path for renderers and any UI that should track the active game variant automatically. ### Fallback Presentation Before Data Loads Host-owned screens that appear before game data discovery can still use menu-consistent colors: ```dart const WolfMenuPresentation classicMenu = WolfMenuPresentation.classic(); const WolfMenuPresentation spearMenu = WolfMenuPresentation.spear(); ``` Those fallback constructors expose colors without requiring a loaded `WolfensteinData` instance. Art getters return `null` until real data is attached. ### Implementing A Custom MenuPicModule Use `MenuPicModule` when your mod changes which VGA pictures back the classic menu keys: ```dart class ModMenuPics extends MenuPicModule { const ModMenuPics(); @override MenuPicRef? resolve(MenuPicKey key) { switch (key) { case MenuPicKey.title: return const MenuPicRef(140); case MenuPicKey.optionTitle: return const MenuPicRef(141); case MenuPicKey.customizeTitle: return const MenuPicRef(142); default: return null; } } @override MenuPicKey episodeKey(int episodeIndex) { switch (episodeIndex) { case 0: return MenuPicKey.episode1; case 1: return MenuPicKey.episode2; case 2: return MenuPicKey.episode3; default: return MenuPicKey.episode1; } } @override MenuPicKey difficultyKey(Difficulty difficulty) { switch (difficulty) { case Difficulty.easy: return MenuPicKey.skill1; case Difficulty.medium: return MenuPicKey.skill2; case Difficulty.hard: return MenuPicKey.skill3; case Difficulty.expert: return MenuPicKey.skill4; } } } ``` Returning `null` from `resolve` means that the key is not provided by that module. ### Implementing A Custom MenuPresentationModule Use `MenuPresentationModule` when you want to change menu colors, point existing menu concepts at different art, or selectively omit optional art: ### Custom Menu Presentation Example ```dart class ModMenuPresentation extends MenuPresentationModule { const ModMenuPresentation(); @override int get backgroundIndex => 111; @override int get panelIndex => 97; @override int get borderIndex => 87; @override int get emphasisIndex => 10; @override int get warningIndex => 14; @override int get mutedIndex => 8; @override int get selectedTextIndex => 19; @override int get unselectedTextIndex => 23; @override int get disabledTextIndex => 4; @override int get headerTextIndex => 15; @override VgaImage? controlBackground(WolfensteinData data) => null; @override VgaImage? title(WolfensteinData data) => null; @override VgaImage? heading(WolfensteinData data) => null; @override VgaImage? selectedMarker(WolfensteinData data) => null; @override VgaImage? unselectedMarker(WolfensteinData data) => null; @override VgaImage? optionsLabel(WolfensteinData data) => null; @override VgaImage? customizeLabel(WolfensteinData data) => null; @override VgaImage? credits(WolfensteinData data) => null; @override VgaImage? episodeOption(WolfensteinData data, int episodeIndex) => null; @override VgaImage? difficultyOption(WolfensteinData data, Difficulty difficulty) => null; @override VgaImage? mappedPic(WolfensteinData data, int index) => null; } final registry = AssetRegistry( sfx: mySfxModule, music: myMusicModule, entities: myEntityModule, hud: myHudModule, menu: myMenuPicModule, menuPresentation: const ModMenuPresentation(), ); ``` The presentation module should treat its image-returning methods as optional hooks: - return a `VgaImage` when that surface has variant-specific art, - return `null` when the presentation intentionally has no image for that concept, - use `mappedPic(...)` only for legacy numeric menu art lookups that still matter for a renderer path. ### Wiring A Fully Custom Registry To ship a complete custom menu variant, provide both modules through `AssetRegistry` when loading data: ```dart final registry = AssetRegistry( sfx: mySfxModule, music: myMusicModule, entities: myEntityModule, hud: myHudModule, menu: const ModMenuPics(), menuPresentation: const ModMenuPresentation(), ); ``` If your menu art still follows the built-in retail/shareware layout, you may not need a custom `MenuPicModule`. In that case, keep the built-in module and only swap `menuPresentation`. ### Choosing The Right Extension Point - Change colors only: implement `MenuPresentationModule`. - Change symbolic menu art mapping: implement `MenuPicModule`. - Change both colors and art layout: implement both modules. - Build a host setup screen before data loads: use `WolfMenuPresentation.classic()` or `WolfMenuPresentation.spear()`. For most host code, prefer the public `wolf_3d_menu.dart` surface instead of importing internal files directly. ## Non-Goals - Flutter widgets/screens are not part of this package. - Bundled app assets are handled by `wolf_3d_assets`. ## Troubleshooting - **Parity regressions**: run targeted tests under `test/engine/` and `test/entities/`. - **Host integration issues**: verify host packages/apps are using exported surfaces from `lib/` rather than private `src/` paths. ## Related Modules - Flutter integration layer: [`../wolf_3d_flutter/README.md`](../wolf_3d_flutter/README.md) - Shared packaged assets: [`../wolf_3d_assets/README.md`](../wolf_3d_assets/README.md) - CLI host app: [`../../apps/wolf_3d_cli/README.md`](../../apps/wolf_3d_cli/README.md) - GUI host app: [`../../apps/wolf_3d_gui/README.md`](../../apps/wolf_3d_gui/README.md) - Workspace overview: [`../../README.md`](../../README.md)