diff --git a/applications/PoP/roomtest/bug_list.md b/applications/PoP/roomtest/bug_list.md index 47693f0..bd57e71 100644 --- a/applications/PoP/roomtest/bug_list.md +++ b/applications/PoP/roomtest/bug_list.md @@ -18,7 +18,7 @@ | ID | что | тип | статус | |----|-----|-----|--------| | [BUG-CHEAT-FIGHT-1](#bug-cheat-fight-1) | `+`/`−` в бою с вынутым мечом → Кид теряет управление | Major (чит) | открыт | -| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрывшуюся решётку (0,9) комнаты 5 | Major | **ждёт сценария**: прогоном 2026-08-07 не воспроизведён | +| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрытую решётку шва (комн. 8 -> 6) | Major | **воспроизведён, корень найден 2026-08-08**: история флагов коллизии не привязана к комнате | | [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом | **низкий** | маловоспроизводимый: ни сценарием, ни попиксельной подгонкой X не поднимается | | [BUG-CHOMP-JUMP-1](#bug-chomp-jump-1) | прыжок с места вплотную к чомперу: кадр с отступом назад | **низкий** | маловоспроизводимый: на повторе не поднялся; на пререлиз | | [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт | @@ -193,7 +193,89 @@ Smoke-прогон уровня 3 (пользователь, 2026-08-05) дал # Открытые баги уровня 1 -## BUG-GATE-PASS-1. Проход сквозь закрывшуюся решётку — ЖДЁТ СЦЕНАРИЯ +## BUG-GATE-PASS-1. Проход сквозь закрывшуюся решётку — **КОРЕНЬ НАЙДЕН 2026-08-08** + +> **ВОСПРОИЗВЕДЁН И РАЗОБРАН.** Сценарий: уровень 1, комната 8, ряд 0, +> `Kid.x = 170`, лицом ВПРАВО, решётка шва (комната 8, колонка 9) ЗАКРЫТА. +> Разбежаться вправо и НЕ ОТПУСКАТЬ клавишу. Кид проходит сквозь решётку и +> убегает вглубь комнаты 6. +> +> Ниже — новый разбор; всё, что было раньше (гипотеза про x > 205), не +> подтвердилось и оставлено в конце для истории. + +### Корень: история флагов коллизии индексируется НЕ ТАК, как в оригинале + +Сняты две трассы — наша (брейкпоинт на резидентном `kid_tick`) и оригинала +(SDLPoP, собран с `POP_TRACE=1`, печать в `play_kid_frame` + маркеры в +`bumped` и `exit_room`). Стартовая позиция совпала до пикселя, поэтому +сравнение построчное. + +**Оригинал:** + +``` +LEAVE dir=1 x=61 cxl=184 cxr=201 room=6 смена комнаты — ШТАТНАЯ +BUMPED dx=-2 push=-1 x=63 tile=4 col=9 и СРАЗУ бамп о решётку, откат +KID f=15 x=60 act=0 col=-1 room=6 drawn=6 сел за решёткой, стоит +``` + +**Мы:** + +``` +x 170 -> 196 бегом, col 7 -> 8 -> 9, НИ ОДНОГО бампа +x=198 -> room 8 -> 6 +при удержании ВПРАВО доезжает до col 1 комнаты 6 и бежит дальше +``` + +Смена комнаты в этой точке правильна и у нас, и у оригинала: `leave_room` +(seg002:423) вправо блокируют ТОЛЬКО `doortop`-тайлы, решётки в списке нет, а +порог `char_x_right >= 201` совпадает с плоскостью ворот +(`x_bump[9+FIRST_ONSCREEN_COLUMN] + TILE_MIDX + wall_dist_from_left[1]` += 191 + 10). Оригинал полагается не на запрет ухода, а на бамп СРАЗУ ПОСЛЕ +перехода. + +**Почему бамп есть у них и нет у нас.** `check_collisions` (seg004:0004) +хранит флаги так: + +```c +row_coll_flags_ptr[tile_col] = curr_flags; // индекс — колонка В РАЗРЕШЁННОЙ комнате +row_coll_room_ptr [tile_col] = curr_room; // и рядом — НОМЕР ЭТОЙ КОМНАТЫ +... +if (curr_row_coll_room[column] >= 0 && + prev_coll_room[column] == curr_row_coll_room[column]) { /* только тогда сравниваем */ } +``` + +То есть история привязана к паре **(колонка внутри своей комнаты, комната)**. +Решётка комнаты 8 и до перехода, и после лежит в слоте 9 с `room = 8` — +переход 8->6 историю НЕ рвёт, переход флага 0->1 виден, бамп срабатывает. + +У нас массив `coll_prev/coll_curr` индексируется колонкой ОТНОСИТЕЛЬНО +отрисованной комнаты (−2…11). При смене комнаты все индексы уезжают на 10, +сопоставить прошлый кадр с текущим нечем, и `enter_room` вынужден звать +`pop_coll_invalidate()`; тот ставит «прошлые флаги = уже перекрывал» (3), то +есть ПОДАВЛЯЕТ бамп на кадре входа. А к следующему кадру Кид уже за +плоскостью ворот — перехода 0->1 не будет никогда. + +### Что делать + +Порт индексации оригинала: хранить флаги в 10 слотах ПО КОЛОНКЕ РАЗРЕШЁННОЙ +комнаты плюс параллельный массив её номера, и сравнивать prev/curr только при +совпадении номеров. Тогда `pop_coll_invalidate()` не нужен вовсе — история +сама «не совпадает» там, где колонка сменила комнату. + +**Осторожно:** это сердце коллизии, вокруг которого разбирался +BUG-SEAM-PINGPONG (см. `bug_closed.md`). После правки обязателен прогон +швов: комнаты 6/8 первого уровня в обе стороны, осторожный шаг и разбег, плюс +проверка, что пинг-понг не вернулся. + +**Инструмент для сверки готов:** SDLPoP собран с трассой, включается +`POP_TRACE=1` (правки в `seg000.c` play_kid_frame, `seg004.c` bumped, +`seg002.c` exit_room, чтение переменной — `main.c`). Сборка на macOS: +`make CFLAGS="-std=gnu99 -O2 -I/opt/homebrew/include -Wno-implicit-function-declaration" LIBS="-L/opt/homebrew/lib -lSDL2 -lSDL2_image"` +(в системе нет pkg-config, штатный Makefile без этого не собирается). + +--- + +### История: прежний разбор (гипотеза НЕ подтвердилась) **Статус: наблюдался один раз (2026-08-03), воспроизвести не удалось ни тогда, ни прогоном всех комнат уровня 1 (2026-08-07).** Заведён, чтобы