Files
Sprinter-SDCC/applications/PoP/roomtest/NEXT_SESSION.md
T
2026-08-18 15:28:19 +03:00

15 KiB
Raw Blame History

Точка входа для следующей сессии (обновлено 2026-08-12, ночь)

Файл для старта с чистого контекста: где всё стоит, что делать первым, какие грабли уже собраны. Читать целиком — он короткий. Дальше по ссылкам: TASKS_OPEN.md (доска), BUGS_OPEN.md (открытые баги), CLAUDE.md.


1. СЛЕДУЮЩАЯ ЗАДАЧА: smoke-прогон уровня 9 и регресс 1-8

Переворот (зелье инверсии) доведён и принят пользователем 2026-08-12: фон, персонажи, клинок, полоса HP, факелы, окклюзия передних граней и переходы между комнатами работают зеркально; чит U и зелёное зелье идут одним путём. Осталось пройти сам уровень 9 живьём и убедиться, что на уровнях 1-8 ничего не поехало (весь слой фона теперь спрашивает pop_upside).

Что смотреть на прогоне в первую очередь:

  • вис на кромке и спуск в перевёрнутом виде — это новый срез clip_char (он режет кадр СНИЗУ вместо верха); тело должно уходить за кладку, а не ложиться поверх неё;
  • бой со стражем перевёрнутым — у соперника свой зеркальный набор (g*_v.atl), а тень рисуется атласами Кида, отдельных файлов ей не надо;
  • зелье в другой комнате — переворот перерисовывает не комнату, а чистит факелы и отражает страницу; проверить, что после смены комнаты и возврата фон остаётся чистым.

Открытый риск (пока не проявился, но проверить осознанно): имена зеркальных атласов kid10_v.atlkid27_v.atl9 символов до точки, а DSS работает по 8.3. Если часть кадров Кида в перевёрнутом виде рисуется обычными (неперевёрнутыми) — это оно; лечится переименованием в pop_pack_kid.py (например k10v.atl) плюс те же имена в pop_kboot.c.

Дальше по плану — уровни 10/11 (по анализу нового в них нет) и MEM-COLD2 п.3, если снова понадобится место.

Ощущенческий хвост прежний — GRAB-KBD-TIMING, разбирается после готовности всех уровней (решение пользователя).

2. Состояние репозитория

Всё закоммичено, main чист. tests-host: 6 наборов проходят ([char] 65, [geom] 3144, [grab] 55, [mouse] 17, [phys] 1727, [wall] 1).

Коммиты 2026-08-12 (сверху — свежие):

хеш что
7f5c99b чистка факелов при перевороте — в СТАРОЙ системе координат
c9aa6d9 переворот: не перерисовывать комнату, стирать только запечённое пламя
948d8f0 переворот: перерисовка вместо отражения, переключение на границе кадра, clip_char
5b6664f зеркальные кадры персонажей — готовыми файлами *_v.atl
c4dd2c7 отсев тайлов по fore-окну — в ЛОГИЧЕСКИХ координатах
7551906 L9-INVERT II.4: персонажи рисуются перевёрнутыми
055d6d7 чтение файлов нельзя выносить в банк (код банка сам живёт в W3)
147cb18 резидент: pop_kid/pop_guard/main расколоты по частоте вызова
5d31ed0 резидент: pop_redraw + холодная половина pop_level в банки
f541c0a клип поля при перевороте (мусор в бортах)

Уровни 1-8 проходятся, уровень 9 ждёт прогона.

3. Раскладка кода после разгрузки резидента

Куча выросла 902 → 5795 Б (_CODE 25 628 → 20 569). Кандидатов выбирали не по размеру, а по тому, КТО зовёт: если единственный вызывающий уже в банке, код едет к нему и трамплин не появляется вовсе.

банк модули
1 guards.c
2 pop_bg.c
3 pop_map.c
4 pop_cdraw.c + pop_kdraw.c (клинок, блит по id — прямые вызовы)
5 pop_ctrl.c
6 pop_trob.c
7 pop_room.c + pop_redraw.c
8 roomtest_cold.c + pop_level_cold.c + pop_kboot.c + pop_guard_cold.c

Внутренние контракты: _pop_level.h, _pop_kid.h, _pop_kdraw.h. В них же записаны два правила, которые линкер НЕ проверяет:

  1. Банковый модуль не маппит W3 — он в этом окне и исполняется (через W0 можно). Поэтому pop_level_read_file и pop_kid_data_load остались в резиденте: первый же вызов из банка улетал в halt по мусору.
  2. Прямые вызовы между модулями одного банка корректны только пока они действительно в одном банке; меняешь раскладку в Makefile — проверь пары.

4. Переворот (L9-INVERT) — как он устроен

  • Флаги: pop_upside_want (пишут зелье, смерть Кида, чит U) и pop_upside (читают все слои). Переключение — ОДНО место, начало кадра, вместе с pop_flip_screen. Оригиналу этого не нужно (он рисует в offscreen неперевёрнутым и зеркалит на выводе) — расхождение записано в ../docs/impl_diff.md.
  • Сам переворот: чистка запечённого пламени (pop_torch_wipe, 0..4 тайла) + отражение страницы акселератором + прямая копия во вторую. 904 247 тактов = 2.1 кадра. Вариант с полной перерисовкой комнаты (как redraw_screen в оригинале) стоил 6 245 477 = 14.5 кадра — отвергнут.
  • Спрайты персонажей: column-major, вертикальное зеркало для них не бесплатно, поэтому второй набор файлов делает упаковщик (vflip_cols в pop_pack_kid.py). Загрузка одной страницы с диска — 970 003 такта, разворот той же страницы в рантайме — 12 645 582; поэтому файлы. pop_vflip_load_all() идемпотентна и зовётся откуда угодно (сейчас — старт и смена уровня, если это POP_UPSIDE_LEVEL; задел под загрузку в интро).
  • Координаты: у окна fore-клипа ДВЕ пары границ — экранная (pop_t_fclip_y0/y1, по ней режется блит) и логическая (pop_t_fclip_ly0/ly1, по ней идут ВСЕ отсевы тайлов). Смешать их — и передние грани перестают перекрывать персонажа.

5. Состояние окружения

  • MAME запущена с мостом, на HDD — roomtest с LEVEL=9. Стартовый уровень теперь параметр сборки: make LEVEL=9 (дефолт 9; для «настоящей» игры — LEVEL=1), константа объявлена в pop_tune.h.
  • ПРАВИЛО ПОЛЬЗОВАТЕЛЯ: перед сборкой образа — make clean, потом make, потом make hdd (memory mame_build_clean_rule). После пересборки образа MAME обязана пройти полный рестарт (memory mame_hdd_rebuild_restart): остановка через exit в дебаггере, затем run_bridge.sh.
  • Тайминги моста (правило пользователя, длиннее не ждать; они же в docs/mame-autotest.md §10): старт run_bridge.sh6 сgo8 сkeyseq d:{ENTER} + keyseq roomtest{ENTER}5 с → программа работает. Весь цикл перезапуска ~20 секунд.
  • MCP-инструменты mame-z80 работают (в отличие от прошлой сессии): press_key, screenshot, read_logical_memory, debugger_command. Профилирование — bpset <addr> + print totalcycles, затем out и снова print totalcycles; кадр = 430 000 тактов.
  • Адреса состояния смещаются после КАЖДОЙ пересборки — брать из .sprinter-cc-roomtest/roomtest.map заново. Банковые функции лежат по 0x0008XXXX; для брейкпоинта брать младшие 16 бит (0xC912 и т.п.).
  • SDLPoP собран с отладочной информацией (-O0 -g3).
  • НЕ ПРИБРАНО: в SDLPoP/src/seg008.c диагностический fprintf с меткой DBGMIRROR в начале add_objtable.

6. Остальное открытое

  • FORE-DUP — передний слой тайла рисуется дважды при перекрытии объектов. Картинку не портит, тратит такты. Сначала замерить, потом чинить.
  • TORCH-ANIM-RIGHT — под запечённым пламенем могут застыть пики/меч/зелье справа от факела.
  • GATE-FORE-KID — Кид в проёме ворот виден поверх решётки; портирован только шовный случай.
  • Долгие: BUG-SPIKE-1, BUG-CHOMP-JUMP-1, L3-COLOR, L1-SPEED, TUNE-1.
  • Вид тени (OR+XOR) отложен до готовности всех уровней — ../docs/shadow_render.md.

7. Грабли, собранные 2026-08-12 (вечер/ночь)

  • return 1; из ветки у SDCC 4.5 может не положить единицу в A — функция возвращает мусор. Годами маскировался (в A случайно оставался ненулевой байт) и вылез ровно на __banked. Репро — docs/bugs/sdcc-z80-ret-const-lost/, обход — один выход через переменную. Аудит всех .asm roomtest: других мест нет.
  • Банковый модуль не может маппить W3 (см. §3). Симптом — halt по мусору в 0xC4xx на первом же вызове.
  • Логические и экранные координаты при перевороте — разные системы. Три бага подряд из одного корня: отсев тайлов по fore-окну, clip_char, чистка факелов. Правило: всё, что считается ИЗ РЯДА комнаты (63*row + …), — логическое; всё, что режет блит, — экранное.
  • Пламя факела ЗАПЕКАЕТСЯ в ОЗУ-копию (heal'а у него нет, следующий кадр накрывает предыдущий непрозрачно). Любое отражение/копирование страницы тащит его с собой — перед такими операциями звать pop_torch_wipe.
  • pop_upside переключать в середине кадра нельзя: остаток кадра рисуется зеркально поверх ещё неперевёрнутой картинки, и запечённые транзиенты остаются в комнате навсегда.
  • Перенос константы между файлами — потерянное значение. При выносе FIRST_LEVEL в pop_tune.h записал дефолт 1, и игра молча стартовала с первого уровня вместо девятого; заметил пользователь. Теперь это параметр сборки (make LEVEL=N).
  • make -C tests-host не пересобирает по изменению заголовков — при правке прототипов (особенно __banked) обязателен make -C tests-host clean, иначе стаб и вызывающий разъезжаются по ABI и тест врёт.

Грабли 2026-08-10/11

  • Не оценивать железо по своей же memory-заметке. Дважды поправлял пользователь: accel умеет не только копирование (есть AND/OR/XOR) и умеет работать с обычной RAM, а не только с видео (docs/part2/accelerator_doc.txt: «supports data blocks transfer of RAM and Video-RAM», не поддерживает только ROM и FastRAM). Проверять по драйверу MAME и докам, а не по памяти.
  • lldb через FIFO — плохая идея. Работает надёжно: fprintf(stderr, …) прямо в SDLPoP, пересборка (секунды) и чтение stdout.
  • Доска отставала от кода на три задачи. Перед планированием — сверять TASKS_OPEN.md с кодом грепом, а не верить записи.
  • Диапазон obj_x = 416..695 (посчитан из kid_data.bin).