Files
Sprinter-SDCC/applications/PoP/roomtest
snark13 8dc53e6b57 L5-SHADOW: тень уровня 5 крадёт зелье (спецсобытие комнаты 24)
Порт seg002: check_shadow (0064), do_init_shad (0000), do_auto_moves (1089),
autocontrol_shadow_level5 (1157) + таблица shad_drink_move (data.h:866).

Механика.  При входе в комнату 24 уровня 5, если зелье (кол 3, ряд 0) ещё
на месте, слот соперника занимает ТЕНЬ — и занимает его ВМЕСТО стража:
enter_guard в этой комнате оригинал не зовёт НИКОГДА (в данных страж есть,
guards_tile[23] = 8, но check_shadow уходит в return до него — в том числе
когда зелье уже выпито).  Поэтому pop_check_shadow вернула 1 = «событие
обработано, стража не поднимать», и вызов стоит ПЕРЕД pop_guard_enter.

Тень стоит, пока не откроются ворота комнаты (openness >= 80), затем
проигрывает ЗАПИСЬ ходов: подойти, взять, выпить, развернуться, уйти за
левый край.  do_auto_moves — тот же движок, что у демо-режима заставки;
тонкость выбора записи (при достигнутом времени индекс сдвигается, а ход
берётся из ещё не сдвинутой записи) портирована дословно.

Три вещи, найденные по дороге:

1. ГЕЙТ ВЫКЛЮЧЕННОГО ПЕРСОНАЖА.  play_guard_frame (seg000:1248) начинается
   с `if (Guard.direction != dir_56_none)`, и clear_char выключает
   персонажа именно так — он не трогает charid.  У нас гейт был только по
   charid, поэтому ушедшая за край тень продолжала тикать: do_auto_moves за
   концом таблицы отдаёт последнюю запись {0x31,1} = «вперёд», тень
   разворачивалась, вбегала обратно, пробегала верхний ряд и падала в проём
   (наблюдение пользователя в MAME).  Гейт добавлен и в pop_guard_tick, и в
   pop_guard_phys_tick.

2. ЭФФЕКТ ЗЕЛЬЯ — ТОЛЬКО КИДУ.  proc_get_object (seg006:16CB) начинается с
   `if (Char.charid != charid_0_kid || ...) return`: предмет забирает любой
   персонаж, а эффект достаётся только Киду.  На этом стоит всё спецсобытие
   — тень пьёт, зелье исчезает и не достаётся никому.  Без проверки
   hitp_delta уходил бы Киду, то есть тень его ЛЕЧИЛА бы.

3. ВЕТКА ТЕНИ в check_guard_fallout (seg002:0241): исчезает, только если
   реально падает (action == 4).  Была помечена в коде как «появится с
   L3-SKEL» — на самом деле она про тень.

Чит ROOMNAV: телепорт ставил Кида в первый попавшийся пол, то есть почти
всегда (0,0).  Теперь ищет пол С МАКСИМАЛЬНЫМ Y (ряд 2 -> 1 -> 0, по
просьбе пользователя): в комнате 24 старая посадка была вплотную к тени, и
вместо сцены кражи начиналась схватка, которой там быть не должно.

Отладочный тумблер POP_DBG_SHADOW_NOWAIT (pop_tune.h, по умолчанию 0) —
посмотреть сцену, не проходя уровень до кнопки.

Проверено в MAME (уровень 5, комната 24): при закрытых воротах тень стоит
за левым краем и не видна; с тумблером — подошла, выпила (зелье исчезло),
развернулась, ушла за край, выключилась и НЕ вернулась.  tests-host 5/5,
make size-check OK.  Цена: резидент +102 Б (24637 -> 24739), банк 1
+368 Б, банк 3 +11 Б.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 17:22:10 +03:00
..

roomtest

Живой прототип порта Prince of Persia: комната 1 уровня 1 отрисовывается реальной композицией слоёв-тайлов, по ней бегает и прыгает Kid под управлением с клавиатуры. Служит стендом для переноса механик движка (анимация, коллизия, падение, зацеп, окклюзия, проваливающиеся полы) до их выделения в переиспользуемый код.

Правила разработки и порядок слоёв рендера — CLAUDE.md.

Быстрый старт

make        # собрать roomtest.exe (ассеты упакуются автоматически)
make run    # собрать, упаковать на дискету и запустить в MAME

Клавиши в запущенном тесте: ←/→ бег, ↓ присед, ↑+→ прыжок, Shift шаг, ESC выход.

Отладка рисования:

  • SPACE — тумблер дабл-буфера (в однобуфере баги рисования видны без мерцания-через-кадр).
  • 1 — заморозить кадр (frozen: tick/draw/flip пропускаются, картинка стоит), 2 — снять заморозку и продолжить. Приём для разбора транзиентных артефактов (тряска/падение loose, поза Kid): поймать проблемный кадр на 1, спокойно рассмотреть/снять пиксели — в т.ч. удалённо из MAME MCP-моста, пока анимация стоит.

Эталон вида комнаты — ../toolchain/1.1-2.png.

Модули

  • roomtest.c — главный цикл (дабл-буфер, порядок tick/draw).
  • pop_bg.c — фон комнаты композицией тайлов + fore-окклюзия + loose-полы.
  • pop_kid.c — анимация/движение Kid (интерпретатор seqtbl).
  • pop_ctrl.c — управление с клавиатуры (диспетчер control).
  • pop_map.c — коллизия с картой, физика падения, loose-полы.
  • room1_data.h — карта комнаты 1; kid_data.h — данные анимации Kid (оба генерируются скриптами ../toolchain/).

Статус (2026-08-07)

Уровни 1 и 2 приняты (пользователь прошёл все комнаты обоих, крупных багов нет): комнаты и переходы, Kid (анимация, управление, коллизия/падение, зацеп/подтягивание/спуск, окклюзия), кнопки и ворота, пики, проваливающиеся полы, дверь уровня и переход на следующий уровень, меч и бой, стражи с ИИ, HP и зелья, чекпойнт уровня 3.

Уровень 3 играется, но не принят: нет чомперов и скелета. Не сделано вовсе: звук, таймер/HUD времени, меню и сохранения.

Что берём в работу сейчас — TASKS_OPEN.md (сделанное с протоколами замеров — TASKS_CLOSED.md); открытые баги — BUGS_OPEN.md, закрытые с разбором корней — BUGS_CLOSED.md; план следующих уровней — ../docs/levels_plan.md.