Files
Sprinter-SDCC/applications/SprPoP/docs/keys_plan.md
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

12 KiB
Raw Blame History

План: перевод управления на раскладку keys.txt

Целевая раскладка — keys.txt, она же раскладка SDLPoP. Здесь разобрано, что у нас уже есть, что стоит не на той клавише и каких функций нет вовсе, плюс порядок работ. Кода этот документ не меняет.

1. Принципы

Раскладка — не самоцель. Часть строк keys.txt — это функции SDLPoP, которых у нас нет вообще (воскрешение, замедленное падение, осмотр соседних комнат). Поэтому работа делится на две разные по цене части: переназначить клавишу (минуты) и реализовать функцию (от часа до дня). Смешивать их в одной фазе нельзя — иначе простые переименования застрянут за сложным.

Механику сверять с SDLPoP. Для каждой новой функции — сначала найти её в assets/orig/SDLPoP/src/, потом писать (правило проекта, memory pop_check_sdlpop_first). Особенно для читов: Shift+S/Shift+T — это не «прибавить HP», а конкретные add_life/set_health_life.

Кромка против удержания. Игровые клавиши (стрелки, Shift) читаются как удержание — это held-state, ради которого и заводился <kbd_raw.h>. Все служебные и читерские — как НОВОЕ нажатие (edge), иначе одно касание сработает столько раз, сколько кадров клавиша была внизу. В коде уже есть оба образца: read_user_control() для первого, intro_skip_requested() и hof_* для второго.

Где живёт обработчик. Служебный слой — pop_frame_ui() в sprpop_cold.c (банк 8), читы — pop_cheat.h + вызовы из главного цикла. После переноса pop_config/pop_hof в банк 10 в банке 9 свободно 4436 байт, в банке 8 — 1786; новые обработчики лучше класть в 8-й или 10-й, а не в 9-й.

Ctrl-комбинации уже поддержаны: Ctrl+S/Ctrl+M проверяют KBD_LCTRL || KBD_RCTRL вместе с буквой (sprpop_cold.c:518). Тот же приём годится для Ctrl+A, Ctrl+R, Ctrl+V, Ctrl+Q, Ctrl+B.

2. Что есть сейчас

Движение и бой — совпадает, кроме диагоналей

keys.txt у нас статус
Left / Right / Up / Down стрелки, read_input() есть
Down+Left/Right — прыжок на месте комбинация стрелок есть
Shift — поднять предмет KBD_LSHIFT/KBD_RSHIFT есть
Shift+Left/Right — осторожный шаг комбинация есть
Up+Left / Up+Right — прыжок в сторону комбинация есть
Home / Page Up — то же самое НЕТ: читаются только стрелки
Up на бегу — прыжок с разбега есть
Shift в падении — зацеп есть
Бой: Left/Right/Shift/Up есть
Бой: Down — убрать меч проверить отдельно

Служебные

keys.txt у нас статус
Esc — пауза/меню KBD_MENU = 0x76 есть
Backspace — меню НЕТ (в оригинале это основная клавиша меню, Esc — дублёр)
Space — показать остаток времени НЕТ (Space занят только в меню и вводе имени)
Ctrl+A — рестарт уровня только пунктом меню НЕТ клавиши
Ctrl+R — вернуться в заставку НЕТ
Ctrl+S — звук вкл/выкл Ctrl+S есть, совпадает
Ctrl+M — музыка вкл/выкл Ctrl+M есть, совпадает
Ctrl+V — версия pop_build_info_show() есть, зовётся на старте НЕТ клавиши
Ctrl+Q / F10 — выход F10 в двух местах половина (см. §3)
F6 / F9 — quicksave/load совпадает есть
F12 — скриншот помечено опциональным, не делаем

Читы

keys.txt у нас статус
Shift+L — следующий уровень совпадает есть
K — убить стража совпадает есть
[ / ] — сдвинуть Кида на пиксель совпадает есть
+ / — минута времени у нас это F7/F8, а +/ заняты обходом комнат конфликт, см. §3
Shift+I — перевернуть экран у нас это U переназначить
R — воскресить Кида НЕТ функции
Shift+W — замедленное падение НЕТ функции
Shift+S — вернуть одну единицу HP НЕТ функции
Shift+T — добавить HP НЕТ функции
T — показывать таймер НЕТ функции

Осмотр комнат — нет целиком

H / J / U / N (соседняя комната слева/справа/сверху/снизу) и Ctrl+B (вернуться к Кида) не реализованы. У нас есть отладочный обход комнат по номеру (+/, ROOMNAV в sprpop.c) — это другое: он ТЕЛЕПОРТИРУЕТ Кида, а H/J/U/N только смотрят, не двигая его.

Наше сверх keys.txt

I — бессмертие, P — режим скорости, 1/2 — стоп-кадр, +/ — обход комнат. Всё это отладочное и в оригинале отсутствует; выбросить или оставить — решение пользователя (§6).

3. Конфликты, которые надо решить до кодинга

К1. +/: время или комнаты. keys.txt отдаёт их под ±минуту, у нас на них обход комнат, а время висит на F7/F8. В pop_cheat.h это записано как осознанный выбор («Numpad +/- уже принадлежат ROOMNAV»). Варианты: вернуть +/ времени и увести ROOMNAV на другие клавиши; оставить как есть и разойтись с keys.txt; либо развести по контексту (ROOMNAV — только в отладочной сборке). Развилка требует решения.

К2. U занят. Сейчас U — переворот экрана, а keys.txt хочет U под «посмотреть комнату сверху», переворот — на Shift+I. Разрешается само, если делать К5 и К7 одной фазой.

К3. S без Ctrl. Звук у нас требует Ctrl, и это правильно, но keys.txt хочет ещё и Shift+S (вернуть HP). Проверка обязана различать Ctrl+S, Shift+S и голое S, иначе они будут срабатывать вместе. То же для T: T (таймер) против Shift+T (добавить HP).

К4. Два выхода. F10 живёт в pop_frame_ui() (только в игре) и, с коммита 808c2a5, в kbd_idle() (везде). Дублирование безвредное, но лишнее: проверку в pop_frame_ui стоит убрать, оставив одну точку. Заодно повесить туда же Ctrl+Q.

4. Порядок работ

Фаза A — переназначения, функции уже есть. Дёшево и не трогает логику.

  • Shift+I вместо U для переворота экрана (К2).
  • Backspace как основная клавиша меню, Esc оставить дублёром.
  • Ctrl+V на существующий pop_build_info_show().
  • Ctrl+Q рядом с F10, убрать дубль F10 из pop_frame_ui (К4).
  • Ctrl+A на существующий путь POP_MENU_RESTART_LEVEL.
  • Решение по К1 и правка +//F7/F8.

Фаза B — мелкие новые функции.

  • Space — показать остаток времени. Механика есть (pop_timer, статус- строка); нужен показ на несколько секунд, как text_time_total оригинала.
  • T — постоянный показ таймера (минуты:секунды) в статус-строке.
  • Ctrl+R — возврат в заставку. Автомат это умеет (POP_APP_EV_RESTART_INTRO), нужен только вход с клавиши.

Фаза C — читы, требующие правки игровой логики. Каждый — сверка с SDLPoP до кодинга.

  • Shift+S / Shift+T — HP: аналоги малого и большого красного зелья.
  • R — воскрешение Кида: сложнее прочих, поднимает мёртвого персонажа и должен согласоваться с уже существующим гейтом «мёртв» (memory pop_level_restart_scope).
  • Shift+W — замедленное падение.

Фаза D — осмотр соседних комнат (H/J/U/N + Ctrl+B). Самое крупное: нужен показ комнаты, в которой Кида нет, с возвратом. У нас уже разобрана модель kid_room ≠ drawn_room (memory pop_seam_room_model, room_model_plan.md) — это её прямое применение, и именно поэтому фаза идёт последней.

Фаза E — F12 скриншот. Помечен опциональным; предлагаю не делать вовсе: файл на 80 КБ и запись на диск посреди кадра.

5. Открытые вопросы

  1. К1 — кому отдать +/: времени (как keys.txt) или обходу комнат?
  2. Что делать с нашими сверхштатными клавишами (I бессмертие, P скорость, 1/2 стоп-кадр): оставить как есть, увести под отладочную сборку или выбросить?
  3. Нужны ли Home/Page Up как дублёры диагональных прыжков — на IBM-клавиатуре Sprinter они есть, но комбинация Up+Left уже работает.
  4. Фазы C и D — делать ли их вообще: это читы и отладочный осмотр, к прохождению игры отношения не имеющие.