Плиты нижнего ряда пропадали без кадров падения: draw_mob рисует и соседей

Уровень 11 комната 14: плита ряда 2 уходит в комнату снизу на первом же
move_loose (спавн y=191 при границе ряда 188), а у нас кусок в чужой комнате
не рисовался вовсе — плита исчезала мгновенно.  Оригинал (seg007:13E5)
рисует его ещё три кадра, выглядывающим из нижней кромки (+192), и
симметрично из комнаты сверху (−189).

У куска появилась экранная координата draw_y; по ней идут отрисовка, heal,
порядок относительно Кида, пометки соседа и оверлей, отбор в проходе — по
ней же, а не по комнате.  Ссылки вверх/вниз кэшируются.

Цена (13/23): зелёная 419 562 -> 427 242, работа 880 272 -> 888 984.
Первый вариант стоил втрое дороже (445 248) из-за безусловной пометки по
прошлой нарисованной позиции — у куска из соседней комнаты она в 192
пикселях, и объединение растягивалось на весь экран; гейт вернул 18 000.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 18:55:39 +03:00
parent 0832445614
commit ed5615a95a
2 changed files with 146 additions and 20 deletions
+66
View File
@@ -3238,3 +3238,69 @@ MAME на резидентном `pop_dbg_trap`; сборщик — `collect_kid
`pop_cd[].fpw`. Подозрение на паддинг кадров в атласе
(`png_strip_padding_tradeoff`) либо на мой пересчёт переднего края мимо
боевого `char_x_forward_edge`. Проверять отдельно.
---
<a id="mob-neighbour-room"></a>
## MOB-NEIGHBOUR-ROOM. Плиты нижнего ряда пропадали без кадров падения
**Наблюдение (пользователь, 2026-08-18).** Уровень 11, комната 14: Кид бежит
по ряду проваливающихся плит, они трясутся и «падают сразу полностью
пропадая, а должен быть промежуточный кадр». Догадка пользователя — «для
плит на 2-ом ряду мы рисуем только тряску» — оказалась верной по симптому и
почти верной по причине.
**Корень.** Порт `draw_mob` (seg007:13E5) был неполным. У оригинала кусок
рисуется НЕ ТОЛЬКО в своей комнате:
```c
if (curmob.room == drawn_room) { if (curmob.y >= 210) return; }
else if (curmob.room == room_B) { if (ABS((sbyte)ypos) >= 18) return; curmob.y += 192; }
else if (curmob.room == room_A) { if (curmob.y < 174) return; ypos = curmob.y - 189; }
else return;
```
У нас на этом месте стояло `if (!mt_here) return;` — «чужая комната: считаем,
но не рисуем».
Почему страдал ИМЕННО ряд 2: кусок спавнится на `y_loose_land[row+1]`, для
ряда 2 это **191**, а граница ряда `y_something[3]` — **188**. То есть на
ПЕРВОМ же `move_loose` он уходит в комнату снизу и у нас переставал
рисоваться мгновенно. Ряды 0 и 1 летят внутри комнаты, поэтому там всё было
видно. Промежуточных кадров ровно три — пока `|y| < 18`.
**Фикс.** У куска появилась отдельная ЭКРАННАЯ координата `draw_y` (своя
комната / +192 из комнаты снизу / −189 из комнаты сверху, `MOB_Y_NONE` =
не рисуется). По ней идут отрисовка, `prev_y`/heal, порядок относительно
Кида, пометки соседа и оверлей; отбор в проходе отрисовки — по `draw_y`, а не
по комнате. Ссылки вверх/вниз кэшируются (иначе `pop_room_link` мапил бы W0
каждый кадр).
Вторым заходом пришлось поправить `mob_overlay_neighbour`: ряд там уже считался
по `draw_y`, а габарит спрайта и вызов `pop_mob_overlay_tile` остались по `y` —
для куска из соседней комнаты это расходится на 192, и пересечение с габаритом
тайла считалось заведомо неверно (порядок переднего слоя).
**Цена — и урок про то, ЧТО именно дорого.** Замер 13/23:
| секция | до | первый вариант | после гейта |
|---|---:|---:|---:|
| работа | 880 272 | 898 578 | **888 984** |
| зелёная | 419 562 | 445 248 | **427 242** |
| циан | 380 202 | 379 818 | 378 864 |
Первый вариант метил «фон трогали» по ПРОШЛОЙ нарисованной позиции
безусловно. У куска, видимого из соседней комнаты, она отличается от `y` на
192 — объединение прямоугольников растягивалось почти на весь экран и тянуло
за собой лишние перерисовки. Гейт `m->room != pop_t_room` вернул 18 000 из
26 000.
Я сперва списал рост на клипованный блит (кусок у кромки по определению
клипуется, а клипованный путь дороже: 14 088 против 10 422) — замер это
опроверг: дело было в пометке. Остаток +7 680 в зелёной (+1,8 %) —
собственно отрисовка трёх кадров на плиту; зелёная остаётся ниже растрового
кадра 430 000.
Host-тесты 5106 проверок без расхождений (`pop_room.c` они не линкуют —
проверка визуальная, в MAME: уровень 11 комната 14, отделившаяся плита видна
три кадра).