BUG-GATE-PASS-1 закрыт: смоук уровня 1 пройден, запись переехала в bug_closed.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1739,7 +1739,7 @@ Kid ставится на первый пол. Номер комнаты — п
|
||||
Вторая волна того же прогона (вечер) дала ещё четыре наблюдения — BUG-KBD-4,
|
||||
BUG-RESPAWN-2, BUG-DRAWORDER-1, BUG-LOOSE-2, — все закрыты, разборы выше.
|
||||
Тогда же закрыт как невоспроизводящийся BUG-SEAM-DRAW-1 и заведён
|
||||
BUG-GATE-PASS-1, который остаётся открытым (ждёт сценария).
|
||||
BUG-GATE-PASS-1 (он закрыт ниже, 2026-08-09).
|
||||
|
||||
---
|
||||
|
||||
@@ -1807,3 +1807,167 @@ pop_guard_hurt = 0;`), а не безусловно — это и экономи
|
||||
**Цвет брызг** зависит от палитры стража (слоты `0x90..0x9F`), поэтому он
|
||||
изменится вместе с [BUG-GUARD-COLOR-1](bug_list.md#bug-guard-color-1) —
|
||||
отдельной работы не требует.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-gate-pass-1"></a>
|
||||
## BUG-GATE-PASS-1. Проход сквозь закрывшуюся решётку — **ЗАКРЫТ 2026-08-09**
|
||||
|
||||
**Приёмка:** смоук-прогон уровня 1 (пользователь, 2026-08-09) — с проблемного
|
||||
`x` Кид больше сквозь решётку не пробегает, пинг-понг у шва не вернулся.
|
||||
|
||||
> **ВОСПРОИЗВЕДЁН И РАЗОБРАН.** Сценарий: уровень 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 не будет никогда.
|
||||
|
||||
### Фикс сделан 2026-08-09 (вариант B — сдвиг истории), ЖДЁТ ПРИЁМКИ В MAME
|
||||
|
||||
Рассматривались два пути:
|
||||
|
||||
- **A, дословный порт.** 10 слотов + параллельный массив номера комнаты,
|
||||
индекс по колонке разрешённой комнаты, бамп только при совпадении номеров;
|
||||
`pop_coll_invalidate()` тогда не нужен вовсе. **Не взят:** оригиналу
|
||||
хватает десяти слотов только потому, что он перебирает узкое окно вокруг
|
||||
Кида, а мы намеренно считаем все четырнадцать колонок (FIX_COLL_FLAGS,
|
||||
чтобы не оставалось протухших ячеек) — при таком переборе колонки −2/−1 и
|
||||
8/9 сядут в одни слоты 8/9. То есть A тянет за собой ещё и сужение окна.
|
||||
- **B, сдвиг истории (сделано).** Индексацию оставляем свою, но при
|
||||
БОКОВОМ переходе историю не выбрасываем, а перенумеровываем на 10 слотов:
|
||||
`check_leave` двигает `x` ровно на ∓140 = 10 тайлов, координата грани
|
||||
(`pop_x_bump`) едет на те же 140 вместе с габаритом Кида, значит сами
|
||||
флаги инвариантны — меняется только номер слота.
|
||||
|
||||
Реализация: `pop_coll_shift(int8_t dcol)` в `pop_map.c` сдвигает
|
||||
`coll_curr/above/below` (не `prev` — его на следующем кадре всё равно
|
||||
перезапишет `move_coll_to_prev`), освободившиеся слоты = 3 («уже
|
||||
перекрывал», бампа нет — ровно то, что в оригинале даёт несовпадение номера
|
||||
комнаты). `enter_room_side` зовёт её сразу после `pop_map_set_edges`:
|
||||
`side == 0` (ушёл влево) → `+10`, `side == 1` (вправо) → `−10`. Переходы
|
||||
вверх/вниз и все прочие входы в комнату остаются на полной инвалидации —
|
||||
там колонки не сдвигаются, но тайлы под ними уже из другой комнаты.
|
||||
|
||||
Расхождение с дословным вариантом A записано в `../docs/impl_diff.md` (D-1).
|
||||
|
||||
**Осторожно:** это сердце коллизии, вокруг которого разбирался
|
||||
BUG-SEAM-PINGPONG (см. `bug_closed.md`). Приёмка:
|
||||
|
||||
1. Комнаты 6 ↔ 8 уровня 1, закрытая решётка, **обе** стороны.
|
||||
2. Мелким шагом (упереться) И с разбега (не пройти насквозь) — сценарий
|
||||
выше воспроизводится с `Kid.x = 170`, комната 8, ряд 0, лицом вправо.
|
||||
3. Пинг-понг у шва не вернулся (экран не перескакивает туда-сюда).
|
||||
4. `make -C tests-host` — прошли все 5 наборов (2026-08-09).
|
||||
|
||||
**Инструмент для сверки готов:** 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).** Заведён, чтобы
|
||||
наблюдение не потерялось; закрывать нельзя — ни как исправленный, ни как
|
||||
«не баг», пока нет надёжного сценария. Оговорка: BUG-GATEMOD-1, из-за
|
||||
которого решётка стартовала не в том состоянии, с тех пор закрыт, и
|
||||
наблюдение могло быть его следствием.
|
||||
|
||||
**Что наблюдалось.** Комната 5: Кид стоял НА тайле решётки (0,9)
|
||||
и ждал, пока она опустится. После закрытия пошёл вправо — прошёл в комнату 1
|
||||
и упал на (1,1).
|
||||
|
||||
**Что уже измерено и в чём загвоздка.** Сразу после наблюдения повторить не
|
||||
получилось: в том же месте Кид стоит на `x = 196`, `col = 9`, и решётка его
|
||||
ДЕРЖИТ — то есть штатно.
|
||||
|
||||
Арифметика оригинала объясняет разницу. `is_obstacle` (seg004) ставит
|
||||
плоскость блокировки в `x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX`, для
|
||||
колонки 9 это **x = 205**. При этом «колонка 9» по `get_tile_div_mod_m7` —
|
||||
это `x ∈ [191, 205)`. Пока `curr_col == 9`, Кид гарантированно левее
|
||||
плоскости и обязан блокироваться; чтобы пройти, он должен оказаться **правее
|
||||
205**, то есть уже на дальней стороне решётки, — и тогда уход вправо законен:
|
||||
решётка закрылась у него за спиной, в оригинале она блокирует плоскость, а не
|
||||
весь тайл.
|
||||
|
||||
Отсюда рабочая гипотеза: в момент наблюдения Кид стоял правее 205 (успел зайти
|
||||
по тайлу дальше, пока решётка была поднята), и поведение штатное. Но повторить
|
||||
эту позу и снять `x` пока не удалось, поэтому гипотеза НЕ подтверждена.
|
||||
|
||||
**Что снять в следующий раз** (без этих чисел вопрос не закрыть):
|
||||
|
||||
1. `Kid.x` и `Kid.curr_col` в момент, когда решётка уже закрылась, а Кид ещё
|
||||
стоит на её тайле — до шага вправо;
|
||||
2. модификатор решётки (openness) комнаты 5, тайл 9 — `can_bump_into_gate()`
|
||||
считает её препятствием только пока `(modif >> 2) + 6 < char_height`, то
|
||||
есть пока она опустилась достаточно низко относительно РОСТА кадра;
|
||||
3. `Kid.x` покадрово на самом шаге вправо — где именно перестал блокировать.
|
||||
|
||||
Быстрый способ снять первое: отладочный стоп-кадр (**1** заморозить, **2**
|
||||
продолжить), затем чтение `_Kid` из отладчика MAME; подгонка позы по пикселю —
|
||||
читы `[`/`]`.
|
||||
|
||||
**Возможный корень, если гипотеза не подтвердится.** Проверка идёт по колонке,
|
||||
которая на шве уже принадлежит СОСЕДНЕЙ комнате (`curr_row_coll_room[]` в
|
||||
оригинале); у нас межкомнатная коллизия на шве — исторически проблемное место
|
||||
(ср. закрытый BUG-SEAM-PINGPONG). Второй кандидат — `char_height` в
|
||||
`can_bump_into_gate()`: если он берётся не от того кадра, решётка может
|
||||
перестать считаться препятствием раньше времени.
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
| ID | что | тип | статус |
|
||||
|----|-----|-----|--------|
|
||||
| [BUG-CHEAT-FIGHT-1](#bug-cheat-fight-1) | `+`/`−` в бою с вынутым мечом → Кид теряет управление | Major (чит) | открыт |
|
||||
| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрытую решётку шва (комн. 8 -> 6) | Major | **фикс сделан 2026-08-09** (сдвиг истории флагов, вариант B) — ждёт приёмки в MAME |
|
||||
| [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом | **низкий** | маловоспроизводимый: ни сценарием, ни попиксельной подгонкой X не поднимается |
|
||||
| [BUG-CHOMP-JUMP-1](#bug-chomp-jump-1) | прыжок с места вплотную к чомперу: кадр с отступом назад | **низкий** | маловоспроизводимый: на повторе не поднялся; на пререлиз |
|
||||
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт |
|
||||
| ~~T-2~~ | Кид перерисовывается в покое | оптимизация | **ЗАКРЫТ 2026-08-08** — [DRAW-COST шаг 1](TASKS_OPEN.md#draw-cost) |
|
||||
| ~~BUG-GATE-PASS-1~~ | проход сквозь закрытую решётку шва | Major | **ЗАКРЫТ 2026-08-09** — [bug_closed.md](bug_closed.md#bug-gate-pass-1), смоук уровня 1 пройден |
|
||||
|
||||
---
|
||||
|
||||
@@ -190,168 +190,6 @@ Smoke-прогон уровня 3 (пользователь, 2026-08-05) дал
|
||||
|
||||
---
|
||||
|
||||
# Открытые баги уровня 1
|
||||
|
||||
<a id="bug-gate-pass-1"></a>
|
||||
## 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 не будет никогда.
|
||||
|
||||
### Фикс сделан 2026-08-09 (вариант B — сдвиг истории), ЖДЁТ ПРИЁМКИ В MAME
|
||||
|
||||
Рассматривались два пути:
|
||||
|
||||
- **A, дословный порт.** 10 слотов + параллельный массив номера комнаты,
|
||||
индекс по колонке разрешённой комнаты, бамп только при совпадении номеров;
|
||||
`pop_coll_invalidate()` тогда не нужен вовсе. **Не взят:** оригиналу
|
||||
хватает десяти слотов только потому, что он перебирает узкое окно вокруг
|
||||
Кида, а мы намеренно считаем все четырнадцать колонок (FIX_COLL_FLAGS,
|
||||
чтобы не оставалось протухших ячеек) — при таком переборе колонки −2/−1 и
|
||||
8/9 сядут в одни слоты 8/9. То есть A тянет за собой ещё и сужение окна.
|
||||
- **B, сдвиг истории (сделано).** Индексацию оставляем свою, но при
|
||||
БОКОВОМ переходе историю не выбрасываем, а перенумеровываем на 10 слотов:
|
||||
`check_leave` двигает `x` ровно на ∓140 = 10 тайлов, координата грани
|
||||
(`pop_x_bump`) едет на те же 140 вместе с габаритом Кида, значит сами
|
||||
флаги инвариантны — меняется только номер слота.
|
||||
|
||||
Реализация: `pop_coll_shift(int8_t dcol)` в `pop_map.c` сдвигает
|
||||
`coll_curr/above/below` (не `prev` — его на следующем кадре всё равно
|
||||
перезапишет `move_coll_to_prev`), освободившиеся слоты = 3 («уже
|
||||
перекрывал», бампа нет — ровно то, что в оригинале даёт несовпадение номера
|
||||
комнаты). `enter_room_side` зовёт её сразу после `pop_map_set_edges`:
|
||||
`side == 0` (ушёл влево) → `+10`, `side == 1` (вправо) → `−10`. Переходы
|
||||
вверх/вниз и все прочие входы в комнату остаются на полной инвалидации —
|
||||
там колонки не сдвигаются, но тайлы под ними уже из другой комнаты.
|
||||
|
||||
Расхождение с дословным вариантом A записано в `../docs/impl_diff.md` (D-1).
|
||||
|
||||
**Осторожно:** это сердце коллизии, вокруг которого разбирался
|
||||
BUG-SEAM-PINGPONG (см. `bug_closed.md`). Приёмка:
|
||||
|
||||
1. Комнаты 6 ↔ 8 уровня 1, закрытая решётка, **обе** стороны.
|
||||
2. Мелким шагом (упереться) И с разбега (не пройти насквозь) — сценарий
|
||||
выше воспроизводится с `Kid.x = 170`, комната 8, ряд 0, лицом вправо.
|
||||
3. Пинг-понг у шва не вернулся (экран не перескакивает туда-сюда).
|
||||
4. `make -C tests-host` — прошли все 5 наборов (2026-08-09).
|
||||
|
||||
**Инструмент для сверки готов:** 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).** Заведён, чтобы
|
||||
наблюдение не потерялось; закрывать нельзя — ни как исправленный, ни как
|
||||
«не баг», пока нет надёжного сценария. Оговорка: BUG-GATEMOD-1, из-за
|
||||
которого решётка стартовала не в том состоянии, с тех пор закрыт, и
|
||||
наблюдение могло быть его следствием.
|
||||
|
||||
**Что наблюдалось.** Комната 5: Кид стоял НА тайле решётки (0,9)
|
||||
и ждал, пока она опустится. После закрытия пошёл вправо — прошёл в комнату 1
|
||||
и упал на (1,1).
|
||||
|
||||
**Что уже измерено и в чём загвоздка.** Сразу после наблюдения повторить не
|
||||
получилось: в том же месте Кид стоит на `x = 196`, `col = 9`, и решётка его
|
||||
ДЕРЖИТ — то есть штатно.
|
||||
|
||||
Арифметика оригинала объясняет разницу. `is_obstacle` (seg004) ставит
|
||||
плоскость блокировки в `x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX`, для
|
||||
колонки 9 это **x = 205**. При этом «колонка 9» по `get_tile_div_mod_m7` —
|
||||
это `x ∈ [191, 205)`. Пока `curr_col == 9`, Кид гарантированно левее
|
||||
плоскости и обязан блокироваться; чтобы пройти, он должен оказаться **правее
|
||||
205**, то есть уже на дальней стороне решётки, — и тогда уход вправо законен:
|
||||
решётка закрылась у него за спиной, в оригинале она блокирует плоскость, а не
|
||||
весь тайл.
|
||||
|
||||
Отсюда рабочая гипотеза: в момент наблюдения Кид стоял правее 205 (успел зайти
|
||||
по тайлу дальше, пока решётка была поднята), и поведение штатное. Но повторить
|
||||
эту позу и снять `x` пока не удалось, поэтому гипотеза НЕ подтверждена.
|
||||
|
||||
**Что снять в следующий раз** (без этих чисел вопрос не закрыть):
|
||||
|
||||
1. `Kid.x` и `Kid.curr_col` в момент, когда решётка уже закрылась, а Кид ещё
|
||||
стоит на её тайле — до шага вправо;
|
||||
2. модификатор решётки (openness) комнаты 5, тайл 9 — `can_bump_into_gate()`
|
||||
считает её препятствием только пока `(modif >> 2) + 6 < char_height`, то
|
||||
есть пока она опустилась достаточно низко относительно РОСТА кадра;
|
||||
3. `Kid.x` покадрово на самом шаге вправо — где именно перестал блокировать.
|
||||
|
||||
Быстрый способ снять первое: отладочный стоп-кадр (**1** заморозить, **2**
|
||||
продолжить), затем чтение `_Kid` из отладчика MAME; подгонка позы по пикселю —
|
||||
читы `[`/`]`.
|
||||
|
||||
**Возможный корень, если гипотеза не подтвердится.** Проверка идёт по колонке,
|
||||
которая на шве уже принадлежит СОСЕДНЕЙ комнате (`curr_row_coll_room[]` в
|
||||
оригинале); у нас межкомнатная коллизия на шве — исторически проблемное место
|
||||
(ср. закрытый BUG-SEAM-PINGPONG). Второй кандидат — `char_height` в
|
||||
`can_bump_into_gate()`: если он берётся не от того кадра, решётка может
|
||||
перестать считаться препятствием раньше времени.
|
||||
|
||||
---
|
||||
|
||||
# Оптимизация отрисовки (записано 2026-07-29)
|
||||
|
||||
Не баги — план работ. Оба пункта про одно: у оригинала пометка тайла к
|
||||
|
||||
Reference in New Issue
Block a user