f4b4852d51
roomtest: - QuickSave/QuickLoad (F6/F9): снапшот 'POPQ' v3 в POP.SAV/POP.BAK на HDD, транзакционная запись (POP.NEW -> rename, откат при ошибке), XOR-контрольная сумма payload'а; сериализация всех игровых переменных через W0-примитивы pop_qs_*; pop_qsave_process() на границе кадра вне Char-окон - pop_qsave_restore_room(): полная перезагрузка комнаты после загрузки (карта/края/швы, сброс bake-кэша, перерисовка обеих страниц, инвалидация кэшей спрайтов и HP) - сериализаторы в pop_map/pop_loose_mob/pop_trob/pop_guard_ai (+ восстановление инвариантов: mobs_live, trob_drawn, redraw) - immortal-чит 2 уровня: уровень 2 поглощает только малый урон Kid'а libc/libbgi: - bank_load_file()/bank_save_file() — резидентное файловое I/O в банк, без правила W3 (путь читается до переключения страницы) - gfx_w0_page_prepare(page) — подготовка W0-окна (IRQ/NMI-стабы) одной функцией; atlas_load.c и roomtest переведены на новые примитивы; ручные ISR-стабы удалены sprinter-cc / сборка: - --bank N=FILE.c: автогенерация n_banks (_n_banks_auto.c), ручные const n_banks удалены из тестов - roomtest/app.mk: ресурсы через stamp-файлы (.resource-stamps/) — один запуск упаковщика на группу вместо N под -B; HDD_PACK_ARGS
320 lines
14 KiB
Markdown
320 lines
14 KiB
Markdown
# 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.
|
||
|