Меню, статус-строка и оболочка игры: title/intro/cutscene/HoF, POP.CFG, палитры

Эта сессия (меню + текст в служебных полосах):

* Меню: рамка выделения считается от силуэта текста (SEL_PAD сверху и
  снизу), а не «на глаз»; все экраны центрируются в игровых 200 строках
  (UI_CENTER_TOP/UI_CENTER_FIELD) и в них помещаются; Enter и Space —
  равноправные клавиши действия (ui_action_down).
* Settings: убраны SHOW SPRINTER SCREEN и BACK, добавлены DEBUG BAR и
  ABOUT.  About показывает тот же текст, что стартовый Sprinter screen,
  минус строка про клавиши — общий about_text(), чтобы экраны не
  разъехались.  CONTROLS собирается таблицей и центрируется по
  фактическому числу строк.
* GAME PAUSED переехала в нижнюю статус-строку, как в оригинале
  (SDLPoP rect_bottom_text = {193,70,202,250}): это состояние программы,
  а не пункт меню.  POP_HP_Y вынесен в pop_cdraw.h — полосу делят два
  модуля.
* pop_status.c (банк 9) — текст в обеих служебных полосах.  Нижняя:
  порт display_text_bottom + таймера (QUICKSAVE/QUICKLOAD/SOUND ON/OFF,
  24 тика).  Верхняя отладочная переведена с палочек на текст
  «Level ##, Room ##, Speed: …, Sound: …, Immortal #» малым шрифтом, с
  своим форматированием чисел (без printf и без деления).
  Заявка сообщения — запись одного байта pop_status_msg: резидент W1/W2
  не растёт, весь рендер в банке.  Бюджет после правок не изменился
  (_CODE 23981, куча 267 Б).
* Цена вывода: блит глифа ~4,6 тыс. тактов независимо от размера, поэтому
  всё change-driven, отладочная строка перерисовывается ПО ПОЛЯМ, пробелы
  не блитятся вовсе, а вход в комнату заливает только игровое поле
  (pop_screen_fill_field) — борта от комнаты к комнате не меняются.
* Интро: в PV-сцене зазвучали пропавшие эффекты оригинала — закрытие
  ворот (4) и открытие двери покоев (51), из которой входит Джафар.
* docs/status_line_text.md — полная инвентаризация ВСЕХ текстов SDLPoP в
  статус-строке: геометрия, семантика text_time_total как идентификатора
  сообщения, мигание, рестарт по истечении 36/288.

Вместе с этим выкладывается накопленная работа по оболочке полной игры:
автомат состояний (pop_app), title, intro/PV и cutscene, attract-demo,
Hall of Fame, глобальный таймер, настройки и POP.CFG, модуль палитр и
fade, звуковой набор, host-тесты на новые швы.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 13:58:36 +03:00
parent 7fd7f28ffc
commit 47a4b084c4
205 changed files with 8446 additions and 418 deletions
+47 -29
View File
@@ -1,6 +1,9 @@
# От roomtest к полноценной игре — сценарий и оболочка
Статус: **согласованный план, код не начат** (2026-08-21).
Статус: **частично реализовано; аудит обновлён 2026-08-24**. Ранее пометка
«завершены FG0–FG12» была неверной: для многих этапов уже есть код и
host-тесты, но их критерии приёмки на Sprinter ещё не выполнены. Фактический
статус каждого FG приведён в [§14](#14-этапы-реализации).
Этот документ описывает превращение текущего игрового цикла
`roomtest` в законченную игру: заставка, интро, демонстрационный уровень,
@@ -72,17 +75,24 @@ attract loop после демо или финала.
Джаффар, специальные события, checkpoint, переходы уровней, бесшовный
выход 12-го уровня, перенос максимального HP и звуковые эффекты.
Отсутствуют:
Поверх игрового цикла уже добавлены автомат оболочки, title/story, demo
уровень 0, global timer, сценарный интерпретатор, level-flow, ending и Hall
of Fame. Полный маршрут также собирается в HDD-образ.
- верхнеуровневая оболочка приложения;
- title/story sequence и текстовые экраны;
- уровень 0 и записанное управление демо;
- общий cutscene engine и PV-ресурсы;
- сцены между уровнями;
- глобальный таймер и time-expired sequence;
- корректный переход из уровня 14 в ending;
- финальная сцена и Hall of Fame;
- возврат к title без перезапуска программы.
Однако это **не означает готовность оболочки**. На момент аудита остаются
существенные незакрытые места:
- lifecycle палитр: gameplay-переходы используют чёрный барьер без fade;
cold start и полный набор dungeon/palace переходов ещё не прошли приёмку;
- PV intro Princess/Jaffar уже покадровый (актёры, факелы, звёзды, часы,
молния и foreground-колонна); сцены перед 2/4/6 и длинной веткой 12
анимируют факелы, звёзды и песок, а сцены 8/9 и короткая ветка 12 пока
используют статические позы с исходной длительностью;
- demo отображается с игровой палитрой, проходит второй разворот/зацеп и
доходит до боя; после смерти Кида корректно завершает цикл;
- time-expired, ending и Hall of Fame имеют маршрут и реализацию UI, но не
прошли сквозную MAME-проверку вместе с ресурсами и возвратом к title;
- нет полного регресса EMM/FD для каждого перехода состояния.
## 4. Архитектура: автомат состояний приложения
@@ -218,6 +228,13 @@ title -> demo -> title повторяется неограниченно.
Критерий: одинаковый игровой отрезок в NORMAL даёт то же уменьшение времени,
что SDLPoP; сохранение/загрузка не добавляет и не отнимает тики.
Реализация FG4 живёт одним модулем `roomtest/pop_timer.c` в bank 9:
`60:719`, 720 тиков на минуту, счёт только в живом игровом кадре. Settings
хранит `TIME LIMIT: 60 MIN / UNLIMITED` в `POP.CFG`; старый семибайтный v1
payload по-прежнему читается как `60 MIN`. Читы таймера повторяют SDLPoP,
но из-за занятого `+/-` используют F7 (−1 минута, не ниже одной) и F8
(+1 минута). Состояние входит в QuickSave v4.
## 10. Cutscene engine
Сцены SDLPoP состоят из небольшого набора повторяемых команд. Вместо набора
@@ -305,24 +322,26 @@ Hall of Fame хранится на HDD в отдельном версионир
## 14. Этапы реализации
| этап | результат | критерий приёмки |
|---|---|---|
| **FG0** | удалить уровень 15, формализовать 1..14 | HDD не содержит res2015; переход выше 14 невозможен |
| **FG1** | автомат состояний, текущая игра = PLAYING | старт/рестарт/выход проходят без рекурсии и утечки EMM |
| **FG2** | QuickSave/QuickLoad | критерии `quicksave_plan.md`, включая POP.BAK |
| **FG3** | минимальный pause menu | Resume/Save/Load/Restart/Settings/Quit работают |
| **FG4** | глобальный таймер | совпадение с SDLPoP и корректный save/load |
| **FG5** | text/full-screen/fade primitives | тестовые экраны и переходы на Sprinter |
| **FG6** | build info + оригинальный title | точный порядок, корректный пропуск |
| **FG7** | demo level 0 | бесконечный attract loop, ввод начинает игру |
| **FG8** | cutscene interpreter + intro | интро проходит и пропускается без утечек |
| **FG9** | сцены 2/4/6/8/9/12 | правильный вызов один раз перед уровнем |
| **FG10** | time expired | отдельная сцена и возврат на title |
| **FG11** | level 14 -> ending | полный маршрут после Джаффара |
| **FG12** | Hall of Fame | запись HDD, ввод имени, возврат к attract loop |
Легенда аудита: **✓** — критерий этапа закрыт; **~** — код существует, но
критерий приёмки ещё не закрыт; **○** — не начат. Статус отражает состояние
исходников и последней MAME-проверки на 2026-08-24, а не только наличие
модуля в bank 9.
QuickSave допускается реализовать до остальных частей оболочки: FG2 — одна
из ближайших самостоятельных задач.
| этап | статус | результат и фактическое состояние | критерий приёмки |
|---|---|---|---|
| **FG0** | ✓ | `POP_LEVEL_LAST=14`, HDD содержит `res2000..res2014`; `t_flow` отвергает 15 | HDD не содержит res2015; переход выше 14 невозможен |
| **FG1** | ~ | автомат `pop_app` и `t_app` реализованы; сквозной ресурсный lifecycle и контроль EMM/FD ещё не измерены | старт/рестарт/выход проходят без рекурсии и утечки EMM |
| **FG2** | ✓ | QuickSave/QuickLoad с `POP.SAV` и `POP.BAK`; отдельно проверен в MAME 2026-08-22 | критерии `quicksave_plan.md`, включая POP.BAK |
| **FG3** | ✓ | pause menu, Settings, подтверждения и двойной буфер реализованы; меню проверялось в MAME; добавлены SDLPoP-звуки навигации и защита CBL вокруг полного redraw/файловых операций | Resume/Save/Load/Restart/Settings/Quit работают |
| **FG4** | ~ | `pop_timer`, настройка unlimited, F7/F8 и состояние QuickSave реализованы; есть host-тест, но нет буквального сравнения темпа со SDLPoP на всех переходах | совпадение с SDLPoP и корректный save/load |
| **FG5** | ~ | text/full-screen/fade примитивы есть; для входа в первый уровень и границ уровней выбран мгновенный чёрный барьер без fade: CBL и яркая новая палитра включаются только после подготовки обеих страниц; Level 1 проверен в MAME | тестовые экраны и переходы на Sprinter |
| **FG6** | ~ | title-ресурсы и порядок кадров реализованы; Enter на title и Esc на первом story в MAME переводят прямо в `FIRST_LEVEL`, минуя demo; полная cold-boot приёмка fade остаётся в FG5 | основной титул/Presents/название/Mechner идут в точном порядке `show_title()`; Enter/Space/Esc/стрелки прерывают ожидание; story/intro продолжит FG8 |
| **FG7** | ✓ | level 0, исходная таблица `demo_moves`, demo HP=4 и блокировка игрового UI реализованы; исправлены зеркалирование auto-control, боевой AI Кида и завершение после смерти; в MAME demo проходит разворот/зацеп, доходит до боя и возвращается в attract-цикл без повторного убийства | `res2000.bin`, исходная `demo_moves`, demo HP=4; бесконечный attract loop, любой ввод начинает чистую новую игру; Pause/QuickSave/читы/таймер отключены |
| **FG8** | ~ | data-driven interpreter и покадровый PV intro работают; в MAME проверены актёры, факелы, звёзды 1x1, часы/песок, palette-0 lightning и foreground-колонна; Enter/Esc переводят прямо в `FIRST_LEVEL`; временный темп 12,5 FPS и TODO точного pacing записаны в `impl_diff.md` | story/PV intro проходит, любой raw-ввод пропускает его без удержания EMM-страниц |
| **FG9** | ~ | `pop_flow` корректно маршрутизирует 2/4/6/8/9/12 и ветку <=5 минут (`t_flow`); 2/4/6 и длинная 12 уже обновляют часы, песок, факелы и звёзды каждые 5 кадров Sprinter; длительности всех веток сверены с SDLPoP: 2/4/6/12 — 2,6 с, 8 — 6,0 с, 9 — 7,2 с; входная клавиша gameplay/Shift+L поглощается до сцены, а новое нажатие делает skip; анимации мыши/Princess в 8/9 и разворот Princess в короткой 12 ещё статичны | таблица flow переводит в CUTSCENE ровно перед 2/4/6/8/9/12; scene 12 выбирает короткий вариант при <=5 минутах |
| **FG10** | ~ | переход TIME_EXPIRED и экран существуют, но это ещё статическая PV-стадия; сквозной MAME-маршрут не принят | PV-сцена истечения с пропуском, затем возврат на title/attract; новая игра сбрасывает таймер |
| **FG11** | ~ | room 5 уровня 14 переводит в ENDING (`t_flow`); объятие/мышь заменены статической стадией, полный маршрут не принят | room 5 уровня 14 переводит в ENDING; PV-финал и Hail-экран возвращают управление оболочке |
| **FG12** | ~ | версионированный `POP.HOF`, ввод имени и восстановление после повреждённого файла реализованы; нужна сквозная MAME-проверка ending → HOF → title | версионированный `POP.HOF`, ввод имени raw-клавиатурой, повреждённый файл = пустая таблица, затем title/attract |
## 15. Проверки
@@ -346,4 +365,3 @@ QuickSave допускается реализовать до остальных
- replay/recording;
- точная эмуляция SDL video/controller options;
- профиль ENHANCED и индивидуальные switches fixes.