Всё проверено пользователем в MAME.
1. Переход 6 -> 7 падением. leave_room (seg002:0504) для «вниз» на уровне 6
из комнаты 1 даёт особый результат −2, главный цикл (seg000:0893) читает
его как ++next_level; вход на 7-м (set_start_pos, seg003:0196) ставит Кида
в комнату 17 и сразу переводит экран на комнату под ней. Проверка ОБЯЗАНА
идти раньше связи вниз: у комнаты 1 сосед снизу есть (шахта, комната 3).
2. BUG-BALCONY-RIGHT: правая половина портала не рисовалась. id 12 стоял в
FORE_ENV_IDS (в tile_table он fore_id ЗЕЛЬЯ), но зелье рисуется из
chtab_1, а в chtab_6 под этим номером — правая часть арки балкона 32x62,
идущая в backtable. Спрайт уезжал в fore-атлас, env-страница получала
дырку (idx 12: w=0 h=0). Найдено трассой POP_TRACE_BT + чтением каталога
.atl; дифф комнаты с оригиналом 1151 -> 375.
3. BUG-BELOWROW-WALL: жёлтые треугольники в шахте падения. load_rowbelow
(seg008:368) при отсутствующей комнате снизу подставляет tiles_0_empty
колонкам 1..9 и tiles_20_wall только левому краю; у нас стеной забивались
все 11 позиций.
4. BUG-MOB-MULTIROOM: честный mob_down_a_row (seg007:1387) — кусок переходит
в комнату снизу и летит дальше. Плита (1,7) комнаты 6 пролетает шахту
комнаты 7 и жмёт кнопку (2,7) комнаты 11, открывая ворота комнаты 18.
5. BUG-MOB-STALE-PAGE: чистка следа куска стояла под гейтом «в отрисованной
комнате» — улетевший вниз оставлял себя на одной из страниц навсегда.
6. BUG-CHAR-STALE-PAGE: тень застывала на двух страницах в РАЗНЫХ позах.
Прямоугольник и valid пишутся внутри `if (w && h)`, а снимок состояния
брался безусловно — при нулевом спрайте слот залипал «тихим». Остаток
(почему спрайт нулевой) заведён как SPRITE-ZERO-W0 в BUGS_OPEN.
NEXT_SESSION переписан: следующая задача — зацеп за край пола в свободном
падении (вход на уровень 7). tests-host 5/5, size-check чист.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Задача заведена активной на доске по решению пользователя (palace был
отложен 2026-08-04, но уровень 4 уже гоняется в MAME и зеркало —
единственное, что мешает пройти его сюжетно). Механика целиком сверена по
SDLPoP, таблица соответствий в TASKS_OPEN.
Шаг 1 — АТЛАС. tile_table[0x0D] = база 75, фронт 77 (наша таблица
совпадает с SDLPoP байт в байт). Тайла 13 НЕТ НИ В ОДНОМ уровне
статически: перебор всех 15 res200N.bin даёт ноль попаданий (санити
разбора: ур.1 без чомпера, ур.3 с 18, ур.4 с паласными 25..29). Значит
render_room эти id не увидит и на месте зеркала был бы чёрный провал —
грабли memory pop_atlas_dynamic_ids. Добавлены MIRROR_ENV_IDS = {75,77} в
pop_pack_bg.py, 77 ещё и в FORE_ENV_IDS. Оба набора переупакованы:
fore 17 -> 18 спрайтов, все страницы EMM в пределах 16 КБ.
Шаг 2 — ПОСТАНОВКА. place_mirror() в pop_trob.c по переходу
pop_leveldoor_open 0/2 -> 1 (условие оригинала, seg007:0457 — иначе тайл
ставился бы заново каждый кадр открытой двери). Пишет тайл 13 в комнату 4,
колонку 4, ряд 0; если комната уже на экране — POP_RD_FLOOR на обе
страницы. Банк 6 3450 -> 3518.
НЕ ПРОВЕРЕНО В MAME: нужно нажать плиту выхода на уровне 4 и дойти до
комнаты 4. Отдельный вопрос к проверке — не устареет ли g_fg коллизии,
если игрок окажется в комнате 4 в момент постановки.
Дальше по плану: 4 (прыжок сквозь + рождение тени), 5 (клип тени),
3 (отражение — косметика, самое дорогое).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Скелет (L3-SKEL, ассеты + механика):
- pop_pack_guard.py получил параметр набора (GUARD/SKEL): атлас скелета
poc/res/skel/g0..g3.atl (28 кадров), палитра — из его res750.pal (на ур. 3
curr_guard_color = 0, оригинал палитру не подменяет);
- pop_guard_load выбирает набор по tbl_guard_type и перезагружается ПРИ СМЕНЕ
УРОВНЯ (load_lev_spr, seg000:1092) — без этого скелет рисовался атласом
стража и был невидим;
- load_frame: charid_4_skeleton идёт по таблице стража (seg006:529), тень —
только в кадрах 150..189. Пока ветка была одна (charid_2_guard), скелет
получал image из таблицы Кида (180 при 28 спрайтах) и не рисовался;
- check_skel (seg002:1042), ветка charid_4 в enter_guard, возрождение в
комнате 3 при падении (seg002:252), autocontrol_skeleton;
- leveldoor_open (seg007:456) — новый флаг, сбрасывается стартом уровня.
Цвета стражей (BUG-GUARD-COLOR-1, закрыт):
- все 7 палитр res10.bin -> pop_guard_pal.h, заливка 16 слотов по
guards_color комнаты перед отрисовкой (set_chtab_palette, seg003:257).
Проверено в MAME: ур. 2 комн. 11 = цвет 1, комн. 7 = цвет 3, полоса HP
меняется вместе со стражем. Грабля: gfx_pal_load отдаёт указатель в BIOS,
а тот читает только #4000-#BFFF — таблицу из банка копируем в стек.
Кэш соседних комнат (BUG-SWORD-GHOST-1, закрыт):
- pop_map кэширует fg соседей слева/справа ЦЕЛИКОМ и резолвит col -10..19.
Было -2..11, дальше мнимая стена: луч видимости упирался в неё (страж
после follow_guard в col 12), Кид прятал меч посреди боя и не мог достать
обратно. +48 байт W2.
Окклюзия соперника:
- pop_fore_over_char получил проход other_overlay_tile (порядок midtable,
seg008:1B06) и расширение перебора объединённым прямоугольником
«персонаж + клинок + брызги» — падающий скелет больше не рисуется поверх
кладки и верхней грани пола;
- клип полем 192 строк (reset_obj_clip, seg006:0507) для спрайта, клинка
(общий pop_sword_draw) и брызг — спрайт не залезает на полосу HP;
- ROOMNAV после смерти Кида делает честный pop_start_level: телепорт
«оживлял» мёртвого мимо старта уровня, оставляя живого скелета рядом с
вернувшейся кучей костей.
Ассеты чомпера (под L3-CHOMP): весь набор кадров в атласе явным списком
(101-105 низ, 111-113 верх, 106-110 фронт, 114-123 кровь mono-силуэтом) —
render_room анимированные тайлы пропускает, и в атласе не было ни одного.
Число EMM-страниц не изменилось.
Тесты: tests-host все 5 наборов зелёные, t_char вырос до 65 проверок
(резолв колонок за краем комнаты, возрождение скелета); в testkit добавлен
гард «код наехал на данные» (DATA_LOC).
Доски: TASKS.md разнесён на TASKS_OPEN/TASKS_CLOSED, закрытые баги с
разбором корней — в bug_closed.md; заведены DRAW-CHAR (отрисовка одна на всех
Char, как физика после GUARD-PHYS) и L3-COLOR (зелёная кладка уровня 3:
level_var_palettes = ресурс 20, есть в MSDOS/PRINCE.DAT).
В roomtest.c временно оставлен автостоп на падении соперника (отладка
падений скелета) — помечен ВРЕМЕННО.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>