# Pause Menu: Vanilla Game Settings Integration Plan **Status:** Planned (not implemented) **Date:** 2026-07-04 **Related prototype:** `ui/views/CommonwealthOnline/pause-menu/` **Related inject pattern:** `plugin/src/F4TMainMenuInject.cpp` This document records the agreed approach for opening Fallout 4’s built-in settings from the Commonwealth Online custom pause UI, without showing QUICKSAVE, LOAD, QUIT, and the rest of the vanilla pause list. --- ## Goal From the custom pause menu **SETTINGS → GAME SETTINGS → OPEN FALLOUT 4 SETTINGS**: 1. Show **only** the vanilla settings panel (right column: Audio, Display, etc.). 2. **Hide** the entire left pause column (QUICKSAVE, SAVE, LOAD, INSTALLED, MODS, HELP, SETTINGS, QUIT). 3. When the player presses **B / Escape** and backs out of settings, **restore the custom PrismaUI pause menu**. Multiplayer options stay in the custom HTML **MULTIPLAYER SETTINGS** tab. This plan is only for the full vanilla game settings UI. --- ## Why not simpler approaches ### PrismaUI always on top PrismaUI_F4 composites HTML in the D3D11 `Present` hook, **after** the full game frame (including all Scaleform menus). While a PrismaUI view is shown, it sits above PauseMenu and any settings UI. So you **cannot** truly interleave: ```text PauseMenu (left list) < custom UI < Settings panel ``` You only get: ```text all Scaleform < PrismaUI (while the view is visible) ``` ### Settings is not a standalone menu In Fallout 4, settings is the **pause menu with SETTINGS selected**: left list + right settings panel in the same StartMenu / PauseMenu UI. Hiding PrismaUI and “opening settings” alone still shows QUICKSAVE, LOAD, QUIT, etc. ### Render-to-texture inside SWF Possible in principle (custom `IMenu`, Ultralight → texture → Scaleform image) so custom UI participates in the menu stack. That is a large research project. Editing MainMenu / PauseMenu ActionScript is fragile (crashes already seen on main menu AS changes), which is why Multiplayer uses list inject + PrismaUI instead. **Decision:** Do not use RTT/SWF hosting for this feature. Use runtime GFx + menu lifecycle, same class of work as main-menu inject. --- ## Chosen approach Treat vanilla settings as a **modal sub-flow** owned by C++: ```text CustomPause → VanillaSettingsOnly → CustomPause ``` | Phase | What the player sees | PrismaUI | PauseMenu | | --- | --- | --- | --- | | Custom pause | CO map / left nav / settings tabs | Shown + focused | Closed, or open but fully covered / unused | | Vanilla settings only | Right-hand settings panel only | Hidden + unfocused | Open; left column hidden; navigated into settings | | Back from settings | Custom pause again | Shown + focused | Closed or reset; left column restored if needed | This is the **opposite** of Multiplayer inject: remove / hide pause rows and chrome instead of inserting a row. --- ## Technical background ### Shared StartMenu UI - `RE::PauseMenu` and `RE::MainMenu` both inherit `RE::StartMenuBase`. - Title and pause share the same list pattern the inject already uses: - `MainPanel_mc.List_mc` - `MainPanel_mc.List_mc.entryList` - Pause mode is detectable via the movie variable `PauseMode` (main-menu inject **skips** inject when `PauseMode` is true). - `StartMenuBase` exposes useful targets, including `mainPanel`, `settingsCategoryList`, and `settingsList`. ### Existing inject pattern to mirror `F4TMainMenuInject.cpp`: - Resolves `entryList` on the live GFx movie. - Inserts a row (`text` + logical `index`). - Calls `listWidget.Invoke("InvalidateData")`. - Hooks `InitMainList` so the list is re-applied after the game rebuilds it. - Opens the browser by handling item press / returning to `MAIN_STATE`. Pause settings work should follow the same style: **runtime GFx only**, no SWF decompile, scoped to a dedicated flow flag. --- ## Implementation plan ### 1. Bridge from HTML Prototype already stubs: - `window.CommonwealthOnlineUI.openGameSettings` Wire this to F4SE (same pattern as server browser interop): JS invoke → plugin enters `VanillaSettingsOnly`. ### 2. Enter `VanillaSettingsOnly` On `openGameSettings`: 1. Set a plugin flag, e.g. `g_vanillaSettingsFromCustomPause = true`. 2. Ensure `PauseMenu` is open (open it if the custom pause flow did not already leave it open for pause state). 3. Resolve pause-mode `MainPanel_mc.List_mc.entryList`. 4. **Hide the entire left column** via GFx `SetVisible(false)` on `MainPanel_mc` / list (preferred for “only settings visible”). Optionally also strip `entryList` to only SETTINGS as a safety net so nothing in the left list remains activatable if visibility fails. 5. **Open settings** programmatically: - Discover SETTINGS logical `index` in pause mode by logging `entryList` while paused (indices differ from title screen; do not reuse `kLoadIndex` / `kMultiplayerIndex`). - Select SETTINGS and invoke the same open path the list uses (mirror `OpenMultiplayerMenu` / item-press handling), **or** drive `currentState` / settings panel if a stable GFx path is found. 6. **Hide and unfocus** the PrismaUI pause view so input goes to vanilla settings. Player should see only the settings panel (and game blur / pause chrome that is not the left list). ### 3. Stay in settings While `g_vanillaSettingsFromCustomPause`: - If `InitMainList` (or equivalent) rebuilds the pause list, **re-hide** the left column (and re-strip if stripping). - Do not run title-screen Multiplayer inject on this menu. - Do not show the custom pause UI. ### 4. Exit back to custom pause Detect leave-settings / back: - PauseMenu `currentState` returns from settings toward main pause list, and/or - Settings panel closes, and/or - B / Escape after settings (prefer detecting state, not only the key). On exit: 1. Restore left column visibility (and full `entryList` if stripped). 2. Close `PauseMenu` if it was only opened for this flow, **or** hide it immediately so the player never sees QUICKSAVE / LOAD / QUIT. 3. Clear `g_vanillaSettingsFromCustomPause`. 4. **Show + focus** the PrismaUI pause view (settings tab / game settings pane as appropriate). 5. Ensure Escape handling returns to custom UI behavior (JS `keydown` / plugin focus), same idea as the server browser. **Important:** Vanilla often backs from settings **to the pause list**, then B again closes pause. For this flow, the first back from settings should go **straight to custom UI**, with no flash of the full pause list. Hide/close PauseMenu as soon as settings is left. ### 5. Abort / edge cases - Player force-closes menus, loads, or quits: clear the flag, restore list visibility, do not leave PauseMenu permanently stripped. - Custom pause closed while settings open: still clear flag and restore vanilla pause to a normal state. - Resolution / safe area: left-column hide is clip-based, so it should not need a transparent “hole” rect (unlike a PrismaUI mask approach). --- ## State machine (summary) ```text openGameSettings() [CustomPause] ──────────────────────────► [VanillaSettingsOnly] ▲ │ │ settings back / Escape │ └────────────────────────────────────────────┘ restore list, close/hide PauseMenu, Show+Focus PrismaUI pause view ``` --- ## Alternatives considered (not chosen for v1) | Approach | Why not for v1 | | --- | --- | | Transparent PrismaUI hole over settings panel | Possible, but alignment and input focus are harder; left list still exists underneath | | Hide PrismaUI only (full pause menu) | Shows QUICKSAVE / LOAD / QUIT — fails the goal | | Custom `IMenu` + Ultralight render-to-texture | Correct for true stack interleaving; too large for this feature | | Patch PauseMenu.swf ActionScript | Crash risk; project already avoided this on main menu | | Reimplement all FO4 settings in HTML | Huge scope; vanilla settings already work | --- ## Discovery checklist (before coding) Run in-game with F4SE logging while PauseMenu is open: 1. Confirm `PauseMode == true` on the pause movie. 2. Dump `MainPanel_mc.List_mc.entryList` entries (`text`, `index`) and note SETTINGS index. 3. Confirm `SetVisible(false)` on the left panel clip hides the whole column without breaking the settings panel. 4. Find a reliable way to open settings (item press invoke vs `currentState` / menuObj members). 5. Find a reliable “left settings” signal for returning to custom UI. 6. Confirm B / Escape order: settings → (must not show list) → custom UI. --- ## Suggested implementation order 1. Pause menu PrismaUI view wired like the server browser (show/hide/focus), without vanilla settings yet. 2. `openGameSettings` bridge → open PauseMenu, hide PrismaUI (accept full pause list temporarily). 3. Hide left column + auto-open settings. 4. Exit detection → restore custom pause with no list flash. 5. `InitMainList` re-apply while flag is set. 6. Polish: abort paths, logging, controller + keyboard. --- ## Files likely involved | Area | Path | | --- | --- | | HTML / bridge stub | `ui/views/CommonwealthOnline/pause-menu/script.js` | | Reusable settings UI | `ui/views/CommonwealthOnline/settings/` (`CO_Settings.create`) | | Pause PrismaUI (new, similar to browser) | `plugin/src/F4TPrismaUI.cpp` (or dedicated pause module) | | Pause list hide / settings open (new) | e.g. `plugin/src/F4TPauseMenuSettings.cpp` — mirror `F4TMainMenuInject.cpp` | | Types | `RE::PauseMenu`, `RE::StartMenuBase` in CommonLibF4 | | Prototype UI copy | `ui/views/CommonwealthOnline/pause-menu/` (embeds `../settings/`) | --- ## Success criteria - From custom pause, player can open full vanilla game settings. - Left pause column never visible during that flow. - No QUICKSAVE / LOAD / QUIT (or other pause actions) reachable during that flow. - B / Escape from settings returns to custom pause, not a bare vanilla pause list. - Normal title-screen Multiplayer inject unchanged. - No permanent PauseMenu SWF edits. --- ## Manual test checklist (when implemented) - Server / game running; custom pause opens in-game via PrismaUI. - SETTINGS → GAME SETTINGS → OPEN FALLOUT 4 SETTINGS. - Only settings panel visible; left column absent. - Change a setting (e.g. audio slider); confirm it applies. - B / Escape returns to custom pause (settings tab), no flash of vanilla list. - Open settings again; still correct. - Quit flow / reload; pause menu not permanently broken if opened without custom UI (if vanilla pause remains reachable at all). - Controller and keyboard both work in vanilla settings and after return. --- ## References - Main menu inject (add row): `plugin/src/F4TMainMenuInject.cpp` - PrismaUI view lifecycle: `ThirdParty/framework-F4-Conversion/docs/view-lifecycle.md` - PrismaUI architecture (Present overlay): `ThirdParty/framework-F4-Conversion/README.md` - Pause menu prototype settings UI: `ui/views/CommonwealthOnline/pause-menu/` - Menu flags / depth (Scaleform stack): `RE::UI_MENU_FLAGS`, `RE::UI_DEPTH_PRIORITY`