/* * 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 /* ---- то, что холодная половина берёт у главного цикла ---------------- */ /* Рабочие массивы комнаты: заполняет вход в комнату (банк), читают и он, и * главный цикл (шов, 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; /* Смена уровня целиком (катсцена, гашение, загрузка, палитра, звук). * back — страница кадра главного цикла. 0 — ок, -1 — сбой. */ int8_t pop_level_change(uint8_t back) __banked; /* Клавиши служебного слоя. Живут здесь, а не в roomtest.c: сам обработчик * (pop_frame_ui) переехал в банк, а главный цикл о них больше не знает. */ #define KBD_QUICKSAVE 0x0B /* F6, PS/2 set 2 */ #define KBD_QUICKLOAD 0x01 /* F9, PS/2 set 2 */ #define KBD_MENU 0x76 /* Esc — открыть pause menu (edge) */ #define KBD_QUIT 0x09 /* F10 — отладочный немедленный выход (был на Esc, * пока меню не готово рисовать — см. план MS4) */ /* Меню, F10 и QuickSave/Load на границе кадра. restart_level/dead_reset — * флаги для главного цикла. 0 — продолжаем, 1 — Restart Game, 2 — Quit, * -1 — сбой. */ int8_t pop_frame_ui(uint8_t *restart_level, uint8_t *dead_reset) __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 */