Меч в оригинале ОДИН на всех: и Кид, и страж рисуют клинок из chtab_0 (add_sword_to_objtable, seg006:1798). Раньше sword.atl содержал только кадры подъёма/ножен (sword_tbl 35..42), поэтому у стража меча не было видно вовсе. - pop_pack_kid.py пакует chtab_0 целиком (id 0..33, 5168 Б), индекс в атласе = id; - pop_extract_kid_data.py вытаскивает sword_tbl (53 строки) в kid_data.h макро-инициализаторами — таблица ложится в один TU, а не в каждый; - pop_sword_draw (pop_kid.c) — общая точка отрисовки клинка с полным условием оригинала (кадры 229..237 ИЛИ меч обнажён ИЛИ живой страж); зовут и kid_draw, и pop_guard_draw. Раздельный heal накладных спрайтов. Клинок и брызги урона раньше объединялись в один прямоугольник с персонажем, а объединение почти вдвое больше суммы двух (клинок уходит вперёд-вверх) — heal же стоит ровно по площади. Теперь у накладных свой прямоугольник и свой gfx_heal, а объединение осталось ТОЛЬКО для окна fore-клипа: там это 4 сравнения без рисования, но покрыть клинок обязано, иначе он полезет поверх столба. Отладка: DEBUG_SWORD_ROOM — Киду выдаётся меч при входе в комнату 3 (там страж), чтобы не бегать за ним в комнату 15. Бюджет (225 кадров, комната 3): 415 284 – 416 370 = 0.966–0.968 кадра. Против 384 168 – 384 636 до этого шага, то есть +31 700. Разложение по фазам (медианы): process_trobs 83 190, pop_guard_draw 92 483 (спрайт 28 763 + клинок 23 820 + fore_over_char 39 906), kid_draw 59 089, fore поверх Кида + борта 47 483, heal 40 068, логика 76 338, ввод 13 050. Видно, что клинок 21x8 стоит почти как спрайт стража — это фиксированные накладные расходы клипающего блита, а не пиксели; лечится noclip-путём для column-major (см. gfx_blit_noclip_fast). Отдельным шагом. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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/).
Статус
Готово и проверено в MAME: статический фон комнаты 1; Kid — анимация,
управление, коллизия/падение, зацеп/подтягивание/спуск, fore-окклюзия
пола/стены над Kid. В работе: проваливающиеся полы (loose floors) — см.
../docs/loose_floors_plan.md.