Files
Sprinter-SDCC/applications/PoP/roomtest/roomtest_cold.h
T
snark13 47a4b084c4 Меню, статус-строка и оболочка игры: 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>
2026-08-25 13:58:36 +03:00

105 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* roomtest_cold.h — контракт между главным циклом (резидент W1/W2) и его
* ХОЛОДНОЙ половиной, вынесенной в банк (roomtest_cold.c).
*
* Зачем. В режиме huge под кучу остаётся то, что не занял _CODE+_DATA, и к
* уровню 8 запас упал ниже килобайта. Главный цикл при этом наполовину
* состоит из кода, который отрабатывает РАЗ НА УРОВЕНЬ (старт/рестарт) или
* вообще только по отладочной клавише (обход комнат, лейбл номера) — держать
* его в дефицитном окне незачем. Кадровый путь (tick/draw/флип) остался в
* резиденте целиком: цена выноса — один трамплин на вызов, а он тут ноль раз
* за обычный кадр.
*
* Что ОСТАЛОСЬ в roomtest.c и почему: enter_room_side (её зовут и холодная
* половина, и переходы между комнатами в кадре падения) и рабочие массивы
* комнаты — они же и есть то состояние, ради которого функция вообще
* существует; банковый модуль читает их как обычные глобалы (данные банков
* линкуются в общий _DATA, --bank-data мы не включаем).
*/
#ifndef ROOMTEST_COLD_H
#define ROOMTEST_COLD_H
#include <stdint.h>
/* ---- то, что холодная половина берёт у главного цикла ---------------- */
/* Рабочие массивы комнаты: заполняет вход в комнату (банк), читают и он, и
* главный цикл (шов, straddle, чит-навигация). Данные банковых модулей
* линкуются в общий _DATA, поэтому обе половины видят их как обычные
* глобалы — в банк уехал только КОД. */
extern uint8_t room_fg[30], room_bg[30];
extern uint8_t lcol_fg[6], lcol_bg[3], rcol_fg[6], rcol_bg[3], below_fg[11];
extern uint8_t above_fg[10], above_mod[10];
extern uint8_t kid_room; /* РЕАЛЬНАЯ комната Kid (straddle) */
extern uint8_t seam_sig[3]; /* последняя нарисованная openness в шве */
extern uint8_t seam_rows, seam_redraw;
/* Сигнатура ряда шва: openness ворот соседа либо «кнопка нажата». Живёт в
* резиденте — её зовёт и кадровый путь главного цикла, и вход в комнату. */
uint8_t seam_row_sig(const uint8_t *m, const uint8_t *lfg, uint8_t r);
extern uint8_t cur_room; /* её номер (drawn_room) */
extern uint8_t pop_checkpoint; /* checkpoint (seg000:270) — ставит уход */
/* влево из комнаты 7 уровня 3 */
/* Вход в комнату. side — куда ушёл КИД (0 L, 1 R, 2 U, 3 D); 0xFF = «не
* переход за Кидом» (старт уровня, респавн, чит-навигация): от этого
* зависит, пойдёт ли страж следом. enter_room — обёртка с 0xFF.
* Обе в банке 8: зовутся раз на комнату, а кода там на полтора килобайта. */
void enter_room_side(uint8_t room, uint8_t side) __banked;
void enter_room(uint8_t room) __banked;
/* Пересобрать только производные кэши и обе страницы после QuickLoad.
* Игровые таймеры, trobs, mobs и персонажей не изменяет. */
void pop_qsave_restore_room(uint8_t room) __banked;
/* ---- холодная половина ----------------------------------------------- */
/* start_level (seg003:0055) + do_startpos + set_start_pos: поставить Кида в
* стартовую позицию уровня. Один вход и для запуска, и для рестарта после
* смерти / выпадения из уровня — в оригинале это буквально один путь. */
void pop_start_level(void) __banked;
/* ОТЛАДОЧНЫЙ обход комнат по номеру ('+' / ''). dir: 1 — следующая,
* 2 — предыдущая. Ставит Кида на подходящий пол новой комнаты и выводит
* его из боя. Возвращает 1, если комната сменилась (вызывающий обязан
* вернуть себе draw-страницу и обнулить счётчик кадров смерти). */
uint8_t pop_dbg_roomnav(uint8_t dir) __banked;
/* Читы по фронту нажатия (K/I/S/Shift+L/U/[/]/F7/F8). В банке: раз в кадр,
* а резидент W1/W2 переполнен — см. шапку функции. */
void pop_cheat_tick(void) __banked;
/* Кто рисуется ПОЗЖЕ — Кид или соперник (порядок обхода тайлов оригинала,
* set_objtile_at_char + sort_curr_objs). 1 = соперник поверх. Зовётся раз
* в кадр, поэтому живёт в банке: трамплин на кадр дешевле полукилобайта
* резидента. */
uint8_t guard_over_kid(void) __banked;
/* Перевернуть уже нарисованное (зелье инверсии, уровень 9): две копии
* акселератором + инвалидация слотов персонажей и полосы HP. Звать РАЗ на
* переключение, по флагу pop_upside_dirty. */
void pop_flip_screen(void) __banked;
/* ---- Запуск / смена уровня / завершение ------------------------------ *
* Три куска главного цикла с частотой «раз за игру» или «раз на уровень».
* В резиденте от них остались только вызовы. */
/* Загрузить ресурсы, поднять графику и палитру, поставить Кида на старт и
* нарисовать первый экран. 0 — OK, -1 — фатально (сообщение уже выведено). */
int pop_boot(void) __banked;
/* Перейти на pop_next_level: файл уровня, спрайты соперника, тайлсет,
* старт. На время I/O закрывает CBL и оставляет его закрытым: caller обязан
* вызвать pop_sfx_start ПОСЛЕ palette/fade/восстановления snapshot. Если
* файла нет — молча остаться на текущем. -1 — фатально. */
int pop_level_switch(void) __banked;
/* Чистый старт настоящей игры после Enter/Esc на title/intro/credits либо
* клавиши в attract-demo. Ждёт отпускания клавиши, сбрасывает состояние
* новой игры, загружает FIRST_LEVEL и проявляет его первый кадр. */
int pop_new_game_load(void) __banked;
/* Снять idle-хук, закрыть ввод и графику, отдать все ресурсы. */
void pop_shutdown(void) __banked;
#endif /* ROOMTEST_COLD_H */