Доки: план меню (рендер, restart без подтверждения), QSAVE закрыт
menu_settings_plan.md: - §10 переписан: выбран Вариант A — текстовые строки + собственный растровый рендерер в новом банке; референс SDLPoP (hc_small_font / hc_font — один рендерер, два шрифта); шрифт как ассет из паковщика, прототип MS4 — системный CP866 ZG; двуязычность eng/rus через пару (таблица строк CP866, файл шрифта) - Restart Level / Restart Game выполняются сразу, без подтверждения (§3, §8, из §11 убраны диалоги RESTART *?) - §13 MS4: текстовый рендерер + два шрифта; §14: host-тест рендерера quicksave_plan.md: статус «РЕАЛИЗОВАНО и проверено в MAME» (v0.6-pop-quicksave), документ оставлен справочником по формату 'POPQ' TASKS_OPEN/TASKS_CLOSED: запись QSAVE переехала в закрытые с полным протоколом; docs/README.md аннотации обновлены
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# `applications/PoP/docs` — индекс + сводка по форматам ресурсов
|
||||
|
||||
## Индекс документов (актуальность на 2026-08-01)
|
||||
## Индекс документов (актуальность на 2026-08-22)
|
||||
|
||||
**Живые планы — читать перед работой:**
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
| [`perf_green_phase.md`](perf_green_phase.md) | **ЗЕЛЁНАЯ фаза (слой фона)**: раскладка тактов, способы ускорения (G1..G6), журнал правок — рабочий документ между сессиями. 2026-08-17 |
|
||||
| [`perf_cyan_phase.md`](perf_cyan_phase.md) | **ЦИАН фаза (персонажи + передний слой)**: раскладка тактов, способы ускорения (C1..C7), журнал правок — рабочий документ между сессиями. 2026-08-17 |
|
||||
| [`perf_backlog.md`](perf_backlog.md) | Отложенная оптимизация отрисовки с замерами 2026-08-10 + **как мерить** (wait-state'ы, границы кадра). Позиции 1–7 переехали в фазовые документы выше |
|
||||
| [`quicksave_plan.md`](quicksave_plan.md) | **QuickSave/QuickLoad**: разбор (это enhancement SDLPoP, в оригинале 1989 его НЕТ), инвентаризация нашего состояния, формат снимка, шаги QS1..QS6. План, код не начат. 2026-08-17 |
|
||||
| [`quicksave_plan.md`](quicksave_plan.md) | **QuickSave/QuickLoad** (✅ реализовано, F6/F9, POP.SAV+BAK): разбор (это enhancement SDLPoP, в оригинале 1989 его НЕТ), инвентаризация нашего состояния, формат снимка 'POPQ' v3, шаги QS1..QS6. Справочник. 2026-08-22 |
|
||||
| [`full_game_plan.md`](full_game_plan.md) | **Полноценная игра**: app state machine, title/intro, demo level 0, таймер, cutscenes, уровни 1..14, ending и Hall of Fame. Уровень 15 исключён. 2026-08-21 |
|
||||
| [`menu_settings_plan.md`](menu_settings_plan.md) | **Pause menu и Settings**: QuickSave/QuickLoad в основном menu, `POP.CFG`, один `POP.SAV` + `POP.BAK`, текущий VANILLA и задел под ENHANCED. 2026-08-21 |
|
||||
| [`menu_settings_plan.md`](menu_settings_plan.md) | **Pause menu и Settings**: QuickSave/QuickLoad в основном menu, `POP.CFG`, один `POP.SAV` + `POP.BAK`, текущий VANILLA и задел под ENHANCED; §10 — выбор UI-рендера (текстовые строки + свой растровый рендерер, референс SDLPoP: два шрифта), restart без подтверждения. 2026-08-22 |
|
||||
| [`levels_plan.md`](levels_plan.md) | Следующий этап: уровни 2+, второй тайлсет, читы SDLPoP |
|
||||
| [`levels_12_15_plan.md`](levels_12_15_plan.md) | **Уровни 12/13** (тень, Джафар, падающие плиты) + что такое 14/15 и 0. 2026-08-13 |
|
||||
| [`midtable_analysis.md`](midtable_analysis.md) | **Слои отрисовки**: как устроены back/mid/fore и objtable в оригинале, чего стоит порт, развилки. 2026-08-13 |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Pause menu и Settings для Sprinter PoP
|
||||
|
||||
Статус: **согласованный план, код не начат** (2026-08-21).
|
||||
Статус: **согласованный план, код не начат** (2026-08-21; обновлён
|
||||
2026-08-22 — решение о рендеринге UI см. §10, Restart Level/Game без
|
||||
подтверждения).
|
||||
|
||||
Связанные документы:
|
||||
|
||||
@@ -54,7 +56,9 @@ QUIT
|
||||
- QuickSave/QuickLoad только взводят запрос, фактическая операция идёт на
|
||||
безопасной границе кадра;
|
||||
- QuickLoad disabled/показывает `NO QUICKLOAD`, если нет валидных SAV/BAK;
|
||||
- Restart Level и Restart Game требуют подтверждения;
|
||||
- Restart Level и Restart Game выполняются сразу, БЕЗ подтверждения
|
||||
(2026-08-22): обе операции дёшево обратимы — Restart Level перечитывает
|
||||
уровень, после Restart Game можно тут же сделать QuickLoad из POP.SAV;
|
||||
- Quit требует подтверждения и закрывает файлы/каналы штатным путём;
|
||||
- меню недоступно в demo, cutscene, time-expired и ending;
|
||||
- отдельная debug-комбинация немедленного выхода может остаться только в
|
||||
@@ -210,7 +214,7 @@ Restart Level:
|
||||
|
||||
Restart Game:
|
||||
|
||||
- подтверждение;
|
||||
- выполняется сразу, без подтверждения;
|
||||
- завершить текущий gameplay session;
|
||||
- освободить level/atlas/temporary EMM;
|
||||
- создать новую игру с уровня 1 и новым глобальным таймером;
|
||||
@@ -234,14 +238,117 @@ Restart Game:
|
||||
|
||||
## 10. UI renderer и ввод
|
||||
|
||||
Меню использует общую с title текстовую подсистему:
|
||||
### 10.1. Выбор способа отрисовки: текст против спрайт-атласов
|
||||
|
||||
- фиксированный bitmap font без `_gfx_font_buf` на 2 КБ в W2;
|
||||
- фон/рамка и выделенная строка;
|
||||
- вертикальная навигация, left/right для значения, Enter, Esc;
|
||||
- edge-triggered клавиши поверх существующего `kbd_raw`;
|
||||
- двойная буферизация либо один заранее сохранённый фон menu;
|
||||
- строки и холодный код — в отдельном банке, постоянное состояние — в W2.
|
||||
Ограничение платформы: стандартный текстовый вывод libbgi (`outtextxy`)
|
||||
не годится — он тянет системный знакогенератор в `_gfx_font_buf` (2 КБ
|
||||
статики в W2) плюс жирный резидентный код, а W1/W2 забиты игрой
|
||||
(тот же вывод зафиксирован комментарием в `roomtest_cold.c`, где отладочный
|
||||
борд рисуется палочками именно поэтому). Значит, любой вариант требует
|
||||
СВОЕЙ реализации вывода меню, живущей в отдельном банке (память на банк
|
||||
есть; скорость не критична — меню работает на паузе).
|
||||
|
||||
Рассматривались два подхода.
|
||||
|
||||
**Вариант A — текстовые строки + собственный растровый рендерер.**
|
||||
|
||||
Плюсы:
|
||||
- минимальные данные: шрифт 2–4 КБ + таблицы строк по сотни байт на язык;
|
||||
- весь динамический текст бесплатно: значения опций (ON/OFF,
|
||||
NORMAL/FAST/FASTEST), сообщения (`QUICKSAVED`, `INCOMPATIBLE SAVE`),
|
||||
диалоги (`LOAD BACKUP?`), экран Controls, будущий ввод инициалов
|
||||
Hall of Fame — без текстового движка HoF вообще не сделать;
|
||||
- правка формулировки = правка C-строки, мгновенные итерации;
|
||||
- локализация = вторая таблица строк (+ вторая половина глифов);
|
||||
- **решающий аргумент: так сделано в самом SDLPoP** — см. §10.2.
|
||||
|
||||
Минусы:
|
||||
- надо написать рендерер (блиттер глифа + строка + центрирование +
|
||||
подсветка) — небольшой, но свой;
|
||||
- вид определяется качеством шрифта-ассета.
|
||||
|
||||
**Вариант B — готовые спрайт-атласы** (атлас главного меню с активными/
|
||||
неактивными пунктами, атлас вложенного меню, атлас каждой опции
|
||||
On/Off и т.д.).
|
||||
|
||||
Плюсы:
|
||||
- аутентичный вид: любая типографика/декор запекаются при упаковке;
|
||||
- вывод = существующий блит атласов, текстовый движок не нужен;
|
||||
- язык = другой файл атласа с диска, ноль логики.
|
||||
|
||||
Минусы:
|
||||
- комбинаторика ассетов: 7 пунктов × состояния + вложенные меню + значения
|
||||
всех опций + все сообщения + все диалоги ≈ десятки КБ raw на язык до RLE;
|
||||
второй язык удваивает;
|
||||
- любая правка текста = перегенерация ассетов + перекладка ресурсов;
|
||||
- динамический текст (HoF initials) всё равно потребует шрифтового движка —
|
||||
получили бы ОБЕ системы сразу.
|
||||
|
||||
**Решение (2026-08-22): Вариант A**, шрифт — ассет. Спрайты остаются только
|
||||
для нетекстового декора (рамка/фон меню, маркер выделения — как arrowheads
|
||||
в SDLPoP). Титульный экран — полноэкранная картинка, тема `full_game_plan.md`.
|
||||
|
||||
### 10.2. Референс: как устроено меню в SDLPoP
|
||||
|
||||
`SDLPoP/src/menu.c` + текстовый движок `seg009` — источник структуры:
|
||||
|
||||
- **Текстовые строки + встроенный пропорциональный bitmap-шрифт**
|
||||
`hc_small_font_data[]` (menu.c:2488): символы 32..126, каждый глиф —
|
||||
монохромное изображение переменной ширины; `font_type`
|
||||
{first_char, last_char, space_between_chars, height_above_baseline, chtab}.
|
||||
Никаких per-item атласов, хотя SDL_ttf доступен.
|
||||
- Вывод — портированный движок оригинального DOS PoP (seg009):
|
||||
`draw_text_character` → `method_3_blit_mono(image, x, y, textblit,
|
||||
textcolor)`; `get_line_width` для центрирования; перенос по словам.
|
||||
Тем же движком рисуются in-game тексты и copy protection.
|
||||
- Пункты меню — data-driven C-структуры `{id, previous, next, required,
|
||||
char text[32]}` + таблицы `pause_menu_items[]` / `settings_menu_items[]`;
|
||||
`required` — указатель на флаг disabled, такие пункты пропускаются при
|
||||
навигации (prev/next пересчитываются).
|
||||
- Выделенный пункт = смена цвета текста (bright-white против обычного) +
|
||||
рамка-контур `draw_rect_contours(selection_box, lightgray)`; НЕ отдельный
|
||||
спрайт «активного пункта».
|
||||
- Фон меню — затемнение замороженного игрового кадра:
|
||||
`draw_rect_with_alpha(black, alpha=120)`, внизу просвечивает «GAME PAUSED».
|
||||
- Settings — декларативная таблица `setting_type` со стилями TOGGLE / NUMBER /
|
||||
TEXT_ONLY / KEY, геттером/сеттером/increase/decrease значения, строкой-
|
||||
explanation внизу экрана, скроллом длинных списков и фокусом «левая половина
|
||||
(список) / правая половина (значения)».
|
||||
- Диалоги — один общий `draw_confirmation_dialog(text)` + обработчик
|
||||
результата; диалог возвращает решение автомату меню.
|
||||
- Мини-спрайты только для декора значений (arrowheads up/down/left/right).
|
||||
- Навигация озвучена (menu tick), ввод клавиатура+мышь, hover по прямоугольникам.
|
||||
|
||||
### 10.3. Наша реализация
|
||||
|
||||
- Новый банк (свободный номер, автонумерация sprinter-cc): код рендерера,
|
||||
шрифт, таблицы строк, автомат меню. Резидентно — только request-flag и
|
||||
вызов процесса на границе кадра (паттерн pop_qsave_io).
|
||||
- Рендерер портирует контракт seg009, упрощённо: `font_type` + массив
|
||||
глифов переменной ширины, блит монохромного глифа в теневую страницу
|
||||
через W0-окно (как весь остальной код рисования), `draw_string(x,y,color)`
|
||||
+ центрирование по сумме ширин. Пропорциональность — сразу, API не меняется
|
||||
от моноширинного.
|
||||
- Шрифт — АССЕТ, генерируемый паковщиком toolchain из TTF (красивый, сразу
|
||||
с кириллицей), а НЕ системный ZG. Быстрый прототип для MS4 — системный
|
||||
CP866 знакогенератор через существующий `bios_get_zg` в буфер банка
|
||||
(паттерн `gfx_load_default_font`, но буфер в банке, не `_gfx_font_buf`);
|
||||
потом файл шрифта заменяется без смены API.
|
||||
- Двуязычность (eng/rus): строки храним в CP866 — латиница и кириллица одним
|
||||
байтовым порядком, одна кодировка на оба алфавита. Локаль = пара
|
||||
(указатель на таблицу строк, файл шрифта); переключатель — одна настройка.
|
||||
Русские строки длиннее английских ~10–15% — раскладку экранов и ширину
|
||||
колонок закладывать по русской. Второй язык можно добавить позже без
|
||||
переделки: сначала eng.
|
||||
- Подсветка выделенного пункта: инверсия прямоугольника или контур + цвет,
|
||||
как в SDLPoP. Цвета текста брать из стабильного диапазона палитры
|
||||
0x3A..0x3F (его никто не перезаписывает, проверено на борде-индикаторе).
|
||||
- Фон открытого меню: затемнение замороженного кадра (запечь тёмный прямоуг.
|
||||
в теневую копию страницы поверх сохранённого фона) — двойную перерисовку
|
||||
игры под меню делать не нужно, игра стоит.
|
||||
- Навигация: вверх/вниз по пунктам, left/right для значения, Enter/Esc;
|
||||
edge-triggered поверх существующего `kbd_raw`. Звук навигации — menu tick
|
||||
из имеющихся сэмплов.
|
||||
|
||||
Первый UI может быть визуально простым. Критично отсутствие потери клавиш,
|
||||
предсказуемая пауза и отсутствие повреждения игрового back buffer.
|
||||
@@ -251,8 +358,6 @@ Restart Game:
|
||||
Общий диалог подтверждения:
|
||||
|
||||
```text
|
||||
RESTART LEVEL?
|
||||
RESTART GAME?
|
||||
QUIT GAME?
|
||||
RESTORE DEFAULTS?
|
||||
LOAD BACKUP?
|
||||
@@ -286,7 +391,7 @@ YES / NO
|
||||
| **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 | все семь пунктов доступны и корректно паузят игру |
|
||||
| **MS4** | текстовый рендерер + два шрифта (малый для пунктов, крупный для сообщений) + минимальный pause menu | рендерер строк (глифы, локали, центрирование); все семь пунктов доступны и корректно паузят игру |
|
||||
| **MS5** | General/Gameplay Settings | значения применяются и переживают рестарт |
|
||||
| **MS6** | dialogs + backup recovery | подтверждения и fallback на POP.BAK |
|
||||
| **MS7** | Controls help | полная актуальная раскладка на экране |
|
||||
@@ -298,7 +403,9 @@ F6/F9 и сообщения, затем подключить те же кома
|
||||
## 14. Тесты
|
||||
|
||||
- Host: CFG round-trip, defaults, bad magic/version/size/checksum.
|
||||
- Host: menu navigation, disabled items, confirmations, команды приложению.
|
||||
- Host: меню navigation, disabled items, confirmations, команды приложению.
|
||||
- Host: рендерер строк — вывод глифов обеих локалей, центрирование,
|
||||
ширина строки для малого и крупного шрифта.
|
||||
- Host: SAV invalid -> BAK valid; оба invalid -> NO QUICKLOAD.
|
||||
- MAME: F6, изменение сцены, F9; затем рестарт программы и повторный F9.
|
||||
- MAME: прервать запись/испортить SAV — BAK остаётся загружаемым.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# QuickSave / QuickLoad — разбор оригинала и план реализации
|
||||
|
||||
Статус: **план, код не начат** (2026-08-17). Задача на доске —
|
||||
Статус: **РЕАЛИЗОВАНО и проверено в MAME** (2026-08-22; F6/F9, POP.SAV +
|
||||
POP.BAK — см. коммит `v0.6-pop-quicksave`). Документ оставлен как
|
||||
справочник по формату снимка и разбору. Задача на доске —
|
||||
[`../roomtest/TASKS_OPEN.md#qsave`](../roomtest/TASKS_OPEN.md#qsave).
|
||||
|
||||
---
|
||||
|
||||
@@ -11,6 +11,33 @@
|
||||
|
||||
---
|
||||
|
||||
## QuickSave
|
||||
|
||||
<a id="qsave"></a>
|
||||
### QSAVE. QuickSave / QuickLoad — **РЕАЛИЗОВАНО И ПРОВЕРЕНО 2026-08-22** (коммит f4b4852, тэг v0.6-pop-quicksave)
|
||||
|
||||
F6/F9 в roomtest. Формат снимка `'POPQ'` v3: заголовок
|
||||
{P,O,P,Q,ver=3,level,reserved}, payload всех игровых переменных (Kid/Guard
|
||||
через qs_char, HP, fight seed, читы speed/immortal/sound с range-валидацией
|
||||
на загрузке), хвост = размер payload + XOR-контрольная сумма (старший байт =
|
||||
инвертированный XOR). Носитель — файл на HDD: транзакционная запись
|
||||
`unlink POP.NEW → bank_save_file → rename SAV→BAK → rename NEW→SAV`
|
||||
с откатом; загрузка пробует POP.SAV, потом POP.BAK; при другом уровне —
|
||||
`pop_next_level+pop_level_switch`. Сериализация через резидентные W0-примитивы
|
||||
`pop_qs_*` (паттерн request-flag + `pop_qsave_process()` на границе кадра вне
|
||||
Char-окон); сериализаторы добавлены в pop_map/pop_loose_mob/pop_trob/
|
||||
pop_guard_ai с восстановлением инвариантов (mobs_live, trob_drawn, redraw).
|
||||
Дабл-буфер закрыт `pop_qsave_restore_room()`: полная перезагрузка комнаты +
|
||||
перерисовка ОБЕИХ страниц + инвалидация кэшей спрайтов и HP. Три ГСЧ
|
||||
(`pop_t_seed`, `trob_seed`, `pop_fight_seed`) — все в payload.
|
||||
Файловое I/O — новые `bank_load_file`/`bank_save_file` libc (без правила W3).
|
||||
|
||||
Критерий приёмки выполнен: сохранить, выйти по ESC, запустить заново,
|
||||
загрузить — оказались там же; проверено в MAME. Полный разбор и формат —
|
||||
[`../docs/quicksave_plan.md`](../docs/quicksave_plan.md) (теперь справочник).
|
||||
|
||||
---
|
||||
|
||||
## Уровни: спецсобытия
|
||||
|
||||
<a id="l8-mouse"></a>
|
||||
|
||||
@@ -1090,37 +1090,12 @@ SPIKE-BAKED, а до того — мерцание плиты, ради кото
|
||||
раскладки в `tests-host/README.md`).
|
||||
|
||||
|
||||
### <a id="qsave"></a>QSAVE. QuickSave / QuickLoad
|
||||
### <a id="qsave"></a>QSAVE. QuickSave / QuickLoad — ЗАКРЫТА 2026-08-22
|
||||
|
||||
> **План целиком — [`../docs/quicksave_plan.md`](../docs/quicksave_plan.md)**
|
||||
> (разбор SDLPoP, инвентаризация нашего состояния, формат снимка, порядок
|
||||
> восстановления, разбиение на шаги QS1…QS6, риски). Изучено 2026-08-17,
|
||||
> **код не начат.**
|
||||
|
||||
Оговорка, с которой начинается план: **в оригинале 1989 года этого нет
|
||||
вовсе**, QuickSave — enhancement SDLPoP (`seg000.c`, `USE_QUICKSAVE`,
|
||||
F6/F9). Значит повторяем не букву, а устройство.
|
||||
|
||||
Что взять у SDLPoP без изменений: снимок — плоский список полей, один обход
|
||||
на запись и на чтение (`#define process(x)`), совместимость держится
|
||||
строкой версии и ничем больше; клавиша только взводит флаг, работа идёт
|
||||
**между кадрами**; состояние ОТРИСОВКИ не сохраняется вовсе — комната
|
||||
перерисовывается с нуля.
|
||||
|
||||
Чем наш случай тяжелее: уровень лежит в EMM-странице, а не в ОЗУ;
|
||||
`room_modif`/`trobs` — `static` в банковом `pop_trob.c` (нужны
|
||||
сериализаторы); ГСЧ у нас **три** (`pop_t_seed`, `trob_seed`,
|
||||
`pop_fight_seed`), и пропуск любого даст «загрузилось, но играется иначе»;
|
||||
и главное — **дабл-буфер**: перерисовать после загрузки надо ОБЕ страницы,
|
||||
иначе старая картинка мигнёт через кадр.
|
||||
|
||||
Носитель — **файл** (`QUICKSAVE.SAV`, ≈1,9 КБ), EMM-страница отвергнута:
|
||||
она не переживает рестарт программы, а именно рестарт — тот случай, ради
|
||||
которого QuickSave и нужен (сцену каскада на 13/23 воспроизводит только
|
||||
`ESC` → запуск заново). Мгновенный EMM-слот остаётся необязательным QS6.
|
||||
|
||||
**Критерий приёмки:** сохранить, выйти по `ESC`, запустить roomtest заново,
|
||||
загрузить — и оказаться там же.
|
||||
**Закрыта** (F6/F9, POP.SAV + POP.BAK, коммит f4b4852, тэг v0.6-pop-quicksave).
|
||||
Протокол и устройство — [`TASKS_CLOSED.md`](TASKS_CLOSED.md#qsave);
|
||||
формат снимка и разбор SDLPoP —
|
||||
[`../docs/quicksave_plan.md`](../docs/quicksave_plan.md).
|
||||
|
||||
### <a id="l1-speed"></a>L1-SPEED. Игра идёт быстрее оригинала (найдено 2026-08-01) — ЗАКРЫТА 2026-08-19
|
||||
|
||||
|
||||
Reference in New Issue
Block a user