Files
Sprinter-SDCC/applications/SprPoP/src/pop_status.h
T
snark13 76f02e76db SprPoP: раскладка управления — фазы A и B плана keys_plan.md
Приводим клавиши к keys.txt (раскладка SDLPoP).  Работа делится надвое, и
здесь только то, что не трогает игровую логику: переназначения (A) и три
мелкие функции поверх готовых механизмов (B).  Читы, требующие правки
логики, и осмотр соседних комнат — фазы C и D, отложены.

ПЕРЕНАЗНАЧЕНИЯ (A)

  U            -> Shift+I   переворот экрана; U отдан «комнате сверху»
  Esc          -> Backspace меню; Esc остаётся дублёром, как у SDLPoP
  F7 / F8      -> - / +     ±минута, основной ряд и цифровой блок
  - / +        -> Ctrl+- / Ctrl++  обход комнат (наш отладочный телепорт)
  I            -> Ctrl+I    бессмертие
  P            -> Ctrl+P    режим скорости
  1 и 2        -> Ctrl+F    стоп-кадр, теперь одной клавишей
  F10 в игре   -> Ctrl+Q    вторая клавиша выхода; F10 ловится глобально

Плюс новое на готовых путях: Ctrl+A — рестарт уровня, Ctrl+V — версия
сборки (функция была, её показывал только старт), Ctrl+D — отладочная
строка (тот же тумблер, что в Settings; POP.CFG не пишем), Home / Page Up —
дублёры диагональных прыжков (у SDLPoP это не отдельное действие, а те же
Up+Left / Up+Right, поэтому просто добавляются к стрелкам).

Все наши сверхштатные клавиши ушли под Ctrl, чтобы не занимать голые буквы
из раскладки, и вписаны в keys.txt отдельным разделом.  Ctrl+B намеренно
не занята: keys.txt держит её под «вернуться в комнату Кида» (фаза D).

ФУНКЦИИ (B)

  Space  «сколько осталось» (seg000:612).  Не печатает сама: поднимает тот
         же pop_show_time, которым пользуется автоматическое объявление
         минут, и строку собирает time_msg() — «59 MINUTES LEFT» и «11
         SECONDS LEFT» остаются в одном месте.
  T      постоянный показ таймера.  Переиспользует поле DBG_F_TIME
         отладочной строки, своего рендера нет.  У верхней полосы теперь
         три состояния, и отслеживается РЕЖИМ (0 нет / 1 таймер / 2 всё),
         а не флаг: переход «таймер -> полоса» тоже перерисовывает всё.
  Ctrl+R возврат в заставку — тот же переход, что «Restart Game» в меню.

ДВЕ ЛОВУШКИ, найденные по дороге

  Модификатор обязан входить в САМО значение, а не в условие блока: с
  `if (ctrl) { nav = ...; nav_prev = nav; }` при отпускании Ctrl кромка
  застревала ненулевой и следующее нажатие глохло.

  Один скан-код на два чита: Shift+I и Ctrl+I — это 0x43 в обоих случаях.
  По той же причине ±минута требует ОТПУЩЕННОГО Ctrl (иначе сработает и
  время, и обход комнат), а T — отпущенных Shift и Ctrl (Shift+T отдан
  «добавить HP» в фазе C).

Обработчики положены в pop_frame_ui (банк 8), а не в резидент: там куча
всего 308 байт.  Проверено в MAME: Ctrl+D поднимает строку
«Level 1, Room 1, Speed: NORMAL...», T — один таймер 59:30 без подписей,
Space — watchpoint на pop_show_time ловит запись значения 2 (именно
обработчик клавиши, автообъявление пишет 1).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 15:22:21 +03:00

90 lines
5.9 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.
/*
* pop_status.h — ТЕКСТ в двух служебных полосах экрана (банк 9).
*
* Нижняя (полоса HP) — статус-строка оригинала: порт display_text_bottom
* (seg008:2644) и пары text_time_total/text_time_remaining. Полный
* разбор всех сообщений SDLPoP — ../docs/status_line_text.md.
* Верхняя — наша отладочная строка (была палочками, теперь текст).
*
* ЗАЯВКА — ОДИН БАЙТ. `pop_status_msg` лежит в W2 и пишется откуда
* угодно простым присваиванием: ни трамплина, ни функции. Всё остальное
* (таймер, перерисовка на обеих страницах, шрифт) делает pop_status_frame()
* из банка 9 — один банковый вызов на кадр, рядом с прежним ярлыком
* комнаты. Так в резиденте W1/W2 не появляется ни кода, ни таблиц строк.
*/
#ifndef POP_STATUS_H
#define POP_STATUS_H
#include <stdint.h>
/* Сообщения нижней полосы. Порядок = таблица строк в pop_status.c. */
enum {
POP_MSG_NONE = 0,
POP_MSG_QUICKSAVE, /* F6 успешно */
POP_MSG_NO_QUICKSAVE, /* F6 не удалось */
POP_MSG_QUICKLOAD, /* F9 успешно */
POP_MSG_NO_QUICKLOAD, /* F9 нечего грузить / битый слот */
POP_MSG_SOUND_ON, /* Ctrl+S */
POP_MSG_SOUND_OFF,
POP_MSG_MUSIC_ON, /* Ctrl+M */
POP_MSG_MUSIC_OFF,
POP_MSG_LEVEL, /* «LEVEL N» — строка собирается с номером */
POP_MSG_MINUTES, /* «N MINUTES LEFT» */
POP_MSG_SECONDS, /* «N SECONDS LEFT» / «1 SECOND LEFT» */
POP_MSG_EXPIRED, /* «TIME HAS EXPIRED!» */
POP_MSG_PRESS_BUTTON, /* Кид мёртв — ждём кнопку (висит бессрочно)*/
POP_MSG_N
};
/* Заявка/текущее сообщение. Пишется откуда угодно: 0 — снять строку,
* POP_MSG_* — показать. Повторная заявка того же номера продлевает показ
* только если строка уже погасла (как у оригинала: он тоже сравнивает). */
extern uint8_t pop_status_msg;
/* Постоянный показ таймера (клавиша T); независим от отладочной полосы. */
extern uint8_t pop_show_timer;
/* Показать сообщение НЕМЕДЛЕННО, до конца кадра: строка выкладывается в
* видимую страницу прямо сейчас. Нужна там, где сразу за вызовом идёт
* длинная операция (QuickSave/QuickLoad): обычная заявка напечаталась бы
* уже ПОСЛЕ фриза, когда объяснять его поздно. */
void pop_status_show_now(uint8_t msg) __banked;
/* Порт show_level (seg008:25A8): заявить «LEVEL N» на старте уровня.
* Сама решает, показывать ли (демо-уровень и финальные номера молчат) —
* вызывающему условий знать не нужно. */
void pop_status_level(void) __banked;
/* Сколько логических кадров сообщение ещё висит; 0 — не висит. Читает
* pop_hp_draw (банк 4), чтобы не затирать чужой текст своим фоном. */
extern uint8_t pop_status_ticks;
/* Горизонтальные границы ТЕКСТА в полосе HP. Ровно промежуток между
* делениями Кида (слева) и стража (справа) — как rect_bottom_text
* {193,70,202,250} у оригинала. */
#define POP_STATUS_L 70
#define POP_STATUS_R 250
/* Раз в логический кадр, ПОСЛЕ pop_hp_draw: тик таймера, перерисовка
* нижней строки и обновление верхней отладочной. Всё change-driven —
* пока ничего не менялось, не рисует вовсе. */
void pop_status_frame(uint8_t room) __banked;
/* Кид мёртв: показать «Press Button to Continue» и ждать кнопку. frames —
* сколько кадров прошло со смерти (труп должен успеть лечь). Возвращает 1
* ОДИН раз, когда игрок нажал — вызывающему остаётся перезапустить уровень.
* Логика живёт в банке, потому что резидент W1 переполнен, а зовут её лишь
* в кадрах смерти.
*
* Возвращает: 0 — ждём дальше; 1 — игрок нажал Enter/Shift, перезапустить
* УРОВЕНЬ; 2 — 288 тиков истекли, уйти в title (порт start_game). */
uint8_t pop_dead_prompt(uint16_t frames) __banked;
/* Заставить перерисовать ОБЕ страницы: звать после того, как полосы
* затёрли чужим содержимым (вход в комнату, выход из меню). */
void pop_status_invalidate(void) __banked;
/* Стереть полосу сообщения на текущей странице (меню пишет туда своё). */
void pop_status_wipe(void) __banked;
#endif /* POP_STATUS_H */