Приёмка ур. 2–3: сквозь стену, клин в шве, бар под плитой, глухой страж

Четыре разбора с прогонов пользователя; три бага закрыты, четвёртый
(BUG-SPIKE-1, пики) заведён с замером и гипотезой.

BUG-JUMPWALL-1 (Critical) — недолетевший прыжок проходил СКВОЗЬ стену.
check_collisions держал флаги перекрытия ОДНОГО ряда, а оригинал
(seg004:0004) — трёх, и move_coll_to_prev (seg004:00DF) берёт «прошлые»
флаги из нужного.  Наш prev=3 («уже перекрывал») подавлял бамп ровно на
кадре смены ряда, а в падении ряд меняется почти каждый кадр — переход 0→1
на стене приходился как раз на него.  Порт трёх рядов дословно.
Воспроизведено и закрыто на харнессе (новый набор t_wall: свип по 20
стартовым X, 4 давали проход сквозь кладку); 1723 трассы t_phys НЕ
изменились — правка поведение-сохраняющая.  Живьём подтвердил пользователь.

BUG-GUARD-DEAF-1 (Major) — is_guard_notice не взводился НИГДЕ, поэтому
неактивный страж не оборачивался на Кида за спиной никогда.  Портированы
все пять мест оригинала: опкод SOUND в play_seq (звуки 0..2), bumped_sound,
мягкое/среднее приземление, обрушенная плита, щелчок кнопки.  Ждёт
игровой проверки боем в комнате 11 уровня 2.

BUG-SEAM-WEDGE-1 — клин кладки в пустом (2,0).  Сосед угла снизу-слева
лежит в комнате по диагонали (room_BL); мы безусловно считали его стеной,
оригинал (load_rowbelow, seg008:368) — только когда такой комнаты нет.
Ряд «снизу» стал 11-байтным: [10] = тайл (0,9) диагональной комнаты.

BUG-LOOSE-3 — чёрный бар под упавшей плитой-потолком.  pop_ceil_bake_empty
стирал полосу и восстанавливал только два тайла ряда −1, а в полосу лезет
графика соседа слева и верхушки ряда 0.  Теперь перерисовываются ряды −1 и
0, колонки col−1..col+1.  Проверено попиксельной сверкой с эталонной
перерисовкой: 0 различий.

Плюс карта связности комнат уровней 1–3 (TASKS.md): на ур. 2 недостижимых
нет, на ур. 3 это 23 и 24 — те же односторонние ссылки, что дали 13/18/24
на уровне 1, только комнаты полностью пустые.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Александр Петров
2026-08-05 21:29:37 +03:00
parent 4737ec323c
commit dc8b2b7115
19 changed files with 544 additions and 33 deletions
+93
View File
@@ -11,6 +11,99 @@
---
## BUG-JUMPWALL-1. Недолетевший прыжок проходил СКВОЗЬ стену — **ЗАКРЫТ 2026-08-05**
**Симптом (пользователь, приёмка уровня 3).** Комната 14: Кид на (0,8)
лицом влево, прыжок с места — пролетает сквозь кладку и падает в комнату 13
на (2,3). Обобщение пользователя (оно и оказалось верным): «если Кид
прыгает, недолетает и должен врезаться в стену и упасть ВДОЛЬ неё, у нас он
летит по свободной траектории, как будто ему никто не мешает».
**Корень — упрощение в `check_collisions`, про которое там же стояла
оговорка.** Оригинал (seg004:0004) каждый кадр считает флаги перекрытия для
ТРЁХ рядов (`curr`/`above`/`below`), а `move_coll_to_prev` (seg004:00DF) в
начале следующего кадра выбирает из них тот, что соответствует ряду прошлого
кадра. Так «прошлые» флаги остаются настоящими и на кадре СМЕНЫ РЯДА.
У нас ряд был один, и на смене ряда `prev` заполнялся тройками («уже
перекрывал всё»), что подавляло бамп на этом кадре. В падении ряд меняется
почти каждый кадр, а переход флага 0→1 на стене приходится ровно на него —
поэтому удар не регистрировался и `bumped_fall` (который и гасит `fall_x`)
не вызывался.
**Как ловили.** Не в MAME, а на харнессе: набор
[`tests-host/t_wall.c`](tests-host/t_wall.c) — комната 14 уровня 3 с
подложенным дном шахты, свип по всей ширине стартовой плиты (x = 177..196).
Из 20 стартовых позиций 4 давали проход сквозь кладку (Кид оказывался в
колонке 4 при стене в колонке 5). Первый вариант сценария (одна стартовая
X, из центра плиты) БАГА НЕ ПОКАЗАЛ — отсюда свип.
**Фикс.** Три ряда как в оригинале + дословный `move_coll_to_prev`
(включая условия ±3 на заворот ряда при смене комнаты). Цена — 3×14
`get_tile` на кадр вместо 14, банк 3 +115 Б.
**Чем проверено.** `t_wall` зелёный; **все 1723 существующие трассы
`t_phys` не изменились ни на байт** — правка поведение-сохраняющая для
всего остального. В живой игре подтвердил пользователь: «ударились и
падаем вертикально вниз».
---
## BUG-SEAM-WEDGE-1. Клин кладки в пустом углу (2,0) — **ЗАКРЫТ 2026-08-05**
**Симптом (пользователь, приёмка уровня 3).** Комната 18: в тайле (2,0)
нарисован кусок кладки, хотя по данным там пусто.
**Корень.** У тайла (2,0) «сосед снизу-слева» — это колонка −1 ряда 3, то
есть тайл ЧУЖОЙ комнаты (`room_BL` — левая от нижней). `load_rowbelow`
(seg008:368) резолвит его через `get_tile_to_draw(room_left, 9, 0, …)` и
подставляет стену ТОЛЬКО когда такой комнаты нет. Мы клали стену
безусловно, а `draw_topright` для стены рисует угловой кусок — он и был
клином. Для комнаты 18 диагональ — комната 13, её тайл (0,9) пуст, значит
рисовать нечего.
**Фикс.** Ряд «снизу» стал одиннадцатибайтным: `[0..9]` — колонки комнаты
снизу, `[10]` — тайл (0,9) комнаты снизу-слева (дефолт «стена», если её
нет). Затронуты `pop_level.c` (заполнение), `pop_bg.c` (чтение),
`roomtest.c` (размер массива).
**Проверено** в MAME: комната 18 уровня 3, клина нет.
---
## BUG-LOOSE-3. Чёрный бар под упавшей плитой-потолком — **ЗАКРЫТ 2026-08-05**
**Симптом (пользователь, приёмка уровня 2).** Комната 6: Кид сбивает
плиту-потолок (−1,2) — плита падает, но на её месте остаётся чёрный бар.
Два уточнения пользователя оказались диагностическими:
1. «бар попал в фоновое изображение» — Кид прыгает поверх, уходит, бар
остаётся → чернота лежит в ОЗУ-копии, и heal возвращает её каждый кадр;
2. «когда возвращаемся в комнату после выхода — бара нет» → статическая
отрисовка комнаты рисует всё правильно, виновата ЗАПЕЧКА.
**Корень.** `pop_ceil_bake_empty` стирал полосу потолка чёрной плитой
(`bar`, банк NORMAL — пишет и в ОЗУ-копию) шириной 64 px, а восстанавливал
только ДВА тайла ряда −1: `(1,col)` и `(1,col+1)`. Но куски тайлов
рисуются ВВЕРХ от своей нижней грани и свисают ВПРАВО, поэтому в стёртую
полосу попадает графика и соседа СЛЕВА, и тайлов ряда 0 — их верхушки.
Незакрашенным оставался прямоугольник ~13×3 px.
**Замер (он же метод).** Плита роняется без игры — записью
`pop_ceil_modif[col] = 1` в отладчике MAME (это ровно то, что делает
`make_loose_fall` для потолка). Дальше попиксельная сверка скриншота
«после запечки» со скриншотом «комната перерисована заново» (выйти и
вернуться): различие локализовалось в прямоугольник **экранные x 230..255,
y 47..52** при полосе потолка y 44..52.
**Фикс.** Запечка восстанавливает всё, чья графика попадает в полосу:
ряды −1 И 0, колонки `col1..col+1`.
**Проверено:** та же попиксельная сверка после фикса даёт **0 различий** в
полосе; пользователь подтвердил в игре.
---
## BUG-RJUMP-1. Разбег-прыжок не берёт провал в три тайла — **ЗАКРЫТ 2026-08-04**
**Симптом (пользователь, приёмка уровня 2).** Комната 1: Кид с разбегу