# Pause menu и Settings для Sprinter PoP Статус: **согласованный план, код не начат** (2026-08-21). Связанные документы: - [`full_game_plan.md`](full_game_plan.md) — автомат состояний, title, demo, cutscenes и ending; - [`quicksave_plan.md`](quicksave_plan.md) — состав и восстановление снимка. ## 1. Решения - Программа работает только с HDD; настройки, QuickSave и Hall of Fame всегда могут быть постоянными файлами. - Основной pause menu обязательно содержит QuickSave и QuickLoad. - QuickSave имеет один слот `POP.SAV`; предыдущая корректная запись хранится как `POP.BAK`. - Первая версия имеет один профиль `VANILLA`. Под этим именем пока понимается **текущее поведение roomtest**, включая уже встроенные исправления. - Дизайн файла и API предусматривает будущий `ENHANCED`, но аудит и переключение fixes сейчас не выполняются. - Уровень 15/copy protection отсутствует. - Моды, levelsets и меню Mods отложены. ## 2. Что есть в SDLPoP `src/menu.c` содержит: - Resume, QuickSave, QuickLoad, Restart Level, Settings, Restart Game, Quit; - General, Gameplay, Visuals, Mods, Controls; - toggle/number/key controls, пояснения, scroll и confirmation dialogs; - большой список fixes/enhancements и custom level options. На Sprinter не переносятся SDL-специфичные параметры: fullscreen, hardware acceleration, scaling, aspect ratio, rumble. UI берёт структуру SDLPoP, но набор настроек соответствует платформе. ## 3. Pause menu первой версии ```text RESUME QUICKSAVE QUICKLOAD RESTART LEVEL SETTINGS RESTART GAME QUIT ``` Поведение: - `Esc` в `PLAYING` открывает меню; повторный Esc или Resume возвращает игру; - игра, логический таймер и звуковой насос ставятся на паузу согласованно; - QuickSave/QuickLoad только взводят запрос, фактическая операция идёт на безопасной границе кадра; - QuickLoad disabled/показывает `NO QUICKLOAD`, если нет валидных SAV/BAK; - Restart Level и Restart Game требуют подтверждения; - Quit требует подтверждения и закрывает файлы/каналы штатным путём; - меню недоступно в demo, cutscene, time-expired и ending; - отдельная debug-комбинация немедленного выхода может остаться только в отладочной сборке. ## 4. Settings первой версии ```text GENERAL Sound ON / OFF Show Sprinter screen ON / OFF Restore defaults... GAMEPLAY Speed NORMAL / FAST / FASTEST Gameplay profile VANILLA Cheats ON / OFF CONTROLS Show key bindings BACK ``` `Gameplay profile: VANILLA` показывается read-only: место в модели уже есть, но пользователь не может выбрать ещё не реализованный ENHANCED. Отладочные параметры `ROOMNAV`, border profiling, stop-frame и переключение double buffering не являются пользовательскими Settings. Они остаются compile-time/debug функциями и скрываются из release UI. ## 5. Модель настроек Игровой код не должен читать UI-структуры. Единственный runtime-контракт: ```c typedef enum { POP_PROFILE_VANILLA = 0, POP_PROFILE_ENHANCED = 1 } pop_gameplay_profile_t; typedef struct { uint8_t sound_enabled; uint8_t speed_mode; uint8_t gameplay_profile; uint8_t cheats_enabled; uint8_t show_build_info; uint16_t enhancement_flags; } pop_settings_t; ``` В первой версии загрузчик принимает только `POP_PROFILE_VANILLA`. Значение ENHANCED из более нового/ручного файла заменяется на VANILLA с диагностикой, а не включает частично реализованный режим. Будущий профиль задаёт маску возможностей централизованно: ```text VANILLA -> текущий согласованный набор ENHANCED -> будущий рекомендуемый набор fixes CUSTOM -> только если позже действительно понадобится ``` До отдельного аудита существующие `fix_exit_door`, feather guard behavior, jump grab и sound priorities не переключаются и считаются частью текущего VANILLA. ## 6. Файл POP.CFG Бинарный, компактный, версионированный формат: ```text +0 "PCFG" magic, 4 Б +4 format_version 1 Б +5 payload_size 2 Б +7 payload фиксированные поля little-endian .. checksum 2 Б ``` Требования: - путь рядом с exe/в выделенном каталоге игры на HDD; - неизвестная версия, неверная длина или checksum -> defaults; - неизвестные будущие хвостовые поля можно пропустить по `payload_size`; - запись только после Apply/выхода из Settings, не на каждый шаг курсора; - ошибка записи не завершает игру: показать сообщение и оставить runtime значения; - Restore defaults меняет RAM только после подтверждения и затем сохраняет. CFG не содержит состояние уровня, QuickSave или Hall of Fame. ## 7. QuickSave / QuickLoad в меню Детальный состав снимка и порядок восстановления — в [`quicksave_plan.md`](quicksave_plan.md). Здесь фиксируется UI и файловая транзакция. ### Один слот и backup Файлы: ```text POP.SAV текущий слот POP.BAK предыдущий валидный слот POP.NEW временный файл во время записи ``` Безопасная запись: 1. записать полный снимок в `POP.NEW`; 2. закрыть файл; 3. повторно открыть/прочитать заголовок и checksum; 4. старый валидный `POP.SAV` перенести/скопировать в `POP.BAK`; 5. `POP.NEW` сделать новым `POP.SAV`; 6. при любой ошибке сохранить прежний `POP.SAV`. Точную последовательность rename/copy выбрать после характеризации DSS. Если атомарный rename не гарантирован, использовать copy + fsync/close и никогда не удалять единственную валидную копию до проверки новой. ### Загрузка 1. проверить `POP.SAV`; 2. если он отсутствует/повреждён/несовместим — проверить `POP.BAK`; 3. при валидном BAK показать `LOAD BACKUP?`; 4. несовместимая версия — `INCOMPATIBLE SAVE`, без частичной загрузки; 5. после успеха закрыть menu, перерисовать обе страницы, перезапустить звук. ### Сообщения Минимальный набор: ```text QUICKSAVED QUICKLOADED NO QUICKLOAD SAVE ERROR INCOMPATIBLE SAVE LOAD BACKUP? ``` Сообщение показывается UI-слоем, но операция завершается до возврата в игровой кадр. ## 8. Restart Level / Restart Game Restart Level: - использует существующий штатный reset текущего уровня; - не перечитывает CFG; - не меняет `POP.SAV`; - сбрасывает состояние, которое сбрасывает текущая реализация roomtest. Restart Game: - подтверждение; - завершить текущий gameplay session; - освободить level/atlas/temporary EMM; - создать новую игру с уровня 1 и новым глобальным таймером; - настройки оставить; - QuickSave не удалять. ## 9. Controls Первая версия только показывает активную раскладку. Переназначение клавиш откладывается: raw PS/2 канал имеет особенности Shift и расширенных кодов, поэтому generic key-binding UI требует отдельного проекта. Экран должен перечислить минимум: - движение и Shift/action; - Esc/menu; - F6/F9 QuickSave/QuickLoad; - Ctrl+S sound; - P speed; - доступные cheats, только если они включены. ## 10. UI renderer и ввод Меню использует общую с title текстовую подсистему: - фиксированный bitmap font без `_gfx_font_buf` на 2 КБ в W2; - фон/рамка и выделенная строка; - вертикальная навигация, left/right для значения, Enter, Esc; - edge-triggered клавиши поверх существующего `kbd_raw`; - двойная буферизация либо один заранее сохранённый фон menu; - строки и холодный код — в отдельном банке, постоянное состояние — в W2. Первый UI может быть визуально простым. Критично отсутствие потери клавиш, предсказуемая пауза и отсутствие повреждения игрового back buffer. ## 11. Диалоги Общий диалог подтверждения: ```text RESTART LEVEL? RESTART GAME? QUIT GAME? RESTORE DEFAULTS? LOAD BACKUP? YES / NO ``` Диалог не выполняет действие напрямую: он возвращает решение автомату меню, который формирует команду приложению. Так UI не зависит от gameplay-модулей. ## 12. Будущий ENHANCED Не реализуется сейчас, но дизайн обязан позволять: - добавить второй профиль без смены всего UI; - хранить `enhancement_flags` в CFG; - отличать технические исправления порта (всегда включены) от изменений оригинальной механики; - провести аудит уже встроенных исправлений; - покрыть каждый переключаемый fix host/MAME тестом; - при необходимости добавить Advanced screen, не раздувая основной menu. До этого момента нельзя рассыпать проверки `if (enhanced)` по горячему коду. Сначала составляется реестр и выбирается минимальная битовая модель. ## 13. Этапы реализации | этап | результат | критерий приёмки | |---|---|---| | **MS0** | определить команды app/menu и структуру settings | UI не вызывает gameplay internals напрямую | | **MS1** | проверить запись/rename/copy на HDD DSS | crash/power-loss сценарий не теряет обе копии save | | **MS2** | `POP.CFG`: defaults, load, validate, save | повреждённый CFG безопасно даёт defaults | | **MS3** | QuickSave hotkeys + POP.SAV/BAK | полный критерий `quicksave_plan.md` | | **MS4** | минимальный pause menu | все семь пунктов доступны и корректно паузят игру | | **MS5** | General/Gameplay Settings | значения применяются и переживают рестарт | | **MS6** | dialogs + backup recovery | подтверждения и fallback на POP.BAK | | **MS7** | Controls help | полная актуальная раскладка на экране | | **MS8** | интеграция с title/build info | CFG применяется до первого экрана | QuickSave (`MS1/MS3`) можно реализовать раньше визуального menu: сначала F6/F9 и сообщения, затем подключить те же команды к пунктам UI. ## 14. Тесты - Host: CFG round-trip, defaults, bad magic/version/size/checksum. - Host: menu navigation, disabled items, confirmations, команды приложению. - Host: SAV invalid -> BAK valid; оба invalid -> NO QUICKLOAD. - MAME: F6, изменение сцены, F9; затем рестарт программы и повторный F9. - MAME: прервать запись/испортить SAV — BAK остаётся загружаемым. - MAME: pause на бое/падении, Resume не меняет состояние и таймер. - MAME: Settings сохраняются после полного выхода и запуска с HDD. - Проверка лимита 8 DSS handles на каждом error path. - `make size-check`; menu/text строки не должны съесть резидентный бюджет. ## 15. Не входит в план - Mods и выбор levelset; - уровень 15/copy protection; - несколько save slots; - replay/recording; - key rebinding; - SDL visual/controller options; - фактическая реализация ENHANCED и individual fix switches.