Уровень 6: переход на 7-й, портал, многокомнатное падение плиты
Всё проверено пользователем в 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>
This commit is contained in:
@@ -2461,3 +2461,132 @@ if (tile_left == tiles_26_lattice_down && curr_tile == tiles_12_doortop) {
|
||||
4. Что именно рисует оригинал в тайле — трасса `POP_TRACE_BT=1` (печать в
|
||||
`add_backtable`, `src/seg008.c`, выводит room/row/col/id/размер). Она
|
||||
сразу показала `id=6 w=32 h=63` рядом со «своим» `id=85 w=32 h=4`.
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-belowrow-wall"></a>
|
||||
## BUG-BELOWROW-WALL. Жёлтые треугольники в шахте падения — ЗАКРЫТ
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11).** Уровень 6, комната 3 (шахта под
|
||||
комнатой 1): в нижнем ряду под пустыми тайлами (2,4)-(2,6) торчат жёлтые
|
||||
треугольники.
|
||||
|
||||
**Корень.** `load_rowbelow` (seg008:368) при ОТСУТСТВУЮЩЕЙ комнате снизу
|
||||
подставляет РАЗНЫЕ кромки: колонкам 1..9 — `tiles_0_empty`, и только левому
|
||||
краю (тайл из `room_BL`) — `tiles_20_wall`. У нас `pop_room_load` забивал
|
||||
стеной все одиннадцать позиций `below_fg`, а стена в роли соседа снизу-слева
|
||||
даёт `topright` стены — её грань и лезла треугольниками.
|
||||
|
||||
**Фикс.** `below_fg[0..9] = 0`, `below_fg[10] = 20`.
|
||||
|
||||
**Проверено:** комната 3 совпала с картой SDLPoP — 300 пикселей расхождения,
|
||||
все они силуэт Кида. Опасение «не пропадёт ли законный треугольник в (1,3)»
|
||||
снято тем же сравнением: грань стены в колонке 3 и скос у её основания на
|
||||
месте у обоих. Оговорка пользователя: эталон брался из `--screenshot-level`,
|
||||
живая сверка в SDLPoP — потом.
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-balcony-right"></a>
|
||||
## BUG-BALCONY-RIGHT. Правая половина портала не рисовалась — ЗАКРЫТ
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11).** Уровень 6, комната 18: «закрытый
|
||||
портал показывается некорректно» — у арки балкона нет правой половины,
|
||||
решётка обрывается, справа чёрный провал.
|
||||
|
||||
**Корень — не в движке, а в УПАКОВЩИКЕ АТЛАСОВ.** `id 12` стоял в
|
||||
`FORE_ENV_IDS` (`toolchain/pop_pack_bg.py`), потому что в `tile_table` он
|
||||
числится `fore_id` ЗЕЛЬЯ (0x0A). Но зелье рисуется из `chtab_1`
|
||||
(`add_foretable(id_chtab_1_...)`; у нас `pop_potion_flask`), а в `chtab_6`
|
||||
под номером 12 лежит ПРАВАЯ ЧАСТЬ АРКИ БАЛКОНА 32x62, и она идёт в
|
||||
backtable. Из-за списка спрайт уезжал в `pal_fore.atl`, а `pal_env0.atl`
|
||||
получал дырку: `idx 12: w=0 h=0`. Движок берёт правую грань соседа из
|
||||
env-атласа — и не рисовал ничего.
|
||||
|
||||
**Как найдено.** Трасса оригинала `POP_TRACE_BT=1` показала в спорном тайле
|
||||
`BT room=18 r=1 c=7 ch=6 id=12 w=32 h=62`; дальше — чтение каталога
|
||||
`pal_env0.atl` напрямую (запись 12 пустая) и `pal_fore.atl` (она там).
|
||||
|
||||
**Фикс.** `id 12` убран из `FORE_ENV_IDS`; в env-атласе он занял своё место.
|
||||
Дифф комнаты с оригиналом 1151 -> 375 (остаток — Кид и пламя).
|
||||
**Проверено пользователем:** «портал отрисовался корректно».
|
||||
|
||||
**Урок:** список `FORE_ENV_IDS` собирается по `tile_table.fore_id`, но
|
||||
`fore_id` НЕ значит «спрайт из chtab_6» — у зелья, меча и пламени он
|
||||
указывает в `chtab_1`. Прежде чем вносить номер в этот список, проверять,
|
||||
из какой таблицы спрайт берётся.
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-mob-multiroom"></a>
|
||||
## BUG-MOB-MULTIROOM. Плита не пролетала несколько комнат — ЗАКРЫТ
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11).** Уровень 6: плита (1,7) комнаты 6
|
||||
должна пролететь НЕСКОЛЬКО комнат и упасть на кнопку, открывающую решётку.
|
||||
«Плита просто падает и ничего не открывается.»
|
||||
|
||||
**Корень.** У оригинала кусок живёт в списке mobs и спускается ряд за рядом:
|
||||
`mob_down_a_row` (seg007:1387) из НИЖНЕГО ряда переводит его в комнату снизу
|
||||
(`y -= 192`, ряд 0), и так сколько угодно комнат. У нас кусок на границе
|
||||
комнаты ГАСИЛСЯ, а «переход вниз» подменялся сигналом главному циклу — он
|
||||
искал посадку в комнате снизу через `pop_room_col_landing`. Для колонки 7
|
||||
комнаты 7 (сквозная шахта) посадки нет — кусок исчезал.
|
||||
|
||||
**Фикс.** Честный `mob_down_a_row` в `mob_tick_one` (`pop_room.c`);
|
||||
приземление в НЕ отрисованной комнате сигналит комнатой и тайлом, а щебень
|
||||
и кнопку ставит главный цикл (порт `loose_land`, seg007:11E8).
|
||||
|
||||
Путь в этом сценарии: комната 6 (1,7) -> сквозная шахта комнаты 7 -> кнопка
|
||||
(2,7) комнаты 11, а она по LINKLOC открывает ворота (1,9) комнаты 18 — те
|
||||
самые у портала. **Проверено пользователем:** ворота открываются.
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-mob-stale-page"></a>
|
||||
## BUG-MOB-STALE-PAGE. Улетевшая плита оставалась на одной странице — ЗАКРЫТ
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11).** Сразу после предыдущего фикса:
|
||||
«в одном из кадров дабл-буфера осталась падающая плита».
|
||||
|
||||
**Корень.** Чистка прошлого кадра куска стояла под гейтом «кусок в
|
||||
ОТРИСОВАННОЙ комнате»: `if (here && m->prev_y[pg] != MOB_Y_NONE)`. Как
|
||||
только кусок уходил вниз через `mob_down_a_row`, гейт закрывался — и след,
|
||||
оставленный им на этой странице, не стирал уже никто.
|
||||
|
||||
**Фикс.** Гейт убран: `prev_y[pg]` — след ИМЕННО НА ЭТОЙ странице, стирать
|
||||
его надо независимо от того, где кусок сейчас. Плюс `clean = 2` во всех
|
||||
ветках гашения, чтобы дочищались обе страницы. **Проверено пользователем.**
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-char-stale-page"></a>
|
||||
## BUG-CHAR-STALE-PAGE. Тень застывала на двух страницах в РАЗНЫХ позах
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11, редкий — пойман дважды).** Уровень
|
||||
6, комната с тенью: «Тень застряла в двух разных кадрах в разных позициях».
|
||||
|
||||
**Замер в отладчике (состояние было живым).** `Guard` = кадр 15 (stand),
|
||||
x = 0x51 — то есть персонаж В ПОКОЕ. А слот отрисовки `pop_cd[OPP]`:
|
||||
|
||||
```
|
||||
страница 0: x=25 y=85 w=34 h=38 valid=1 <- ЛЕЖАЩАЯ поза
|
||||
страница 1: x=41 y=78 w=12 h=41 valid=1 <- стойка
|
||||
```
|
||||
|
||||
**Корень.** В `pop_char_draw` (`pop_cdraw.c`) прямоугольник и `valid[dp]`
|
||||
пишутся ВНУТРИ `if (w && h)`, а снимок состояния для пропуска перерисовки
|
||||
(`cd_sig_make`) брался БЕЗУСЛОВНО, в самом конце функции. Если спрайт
|
||||
кадра нулевой (пустая запись атласа), блок рисования пропускался — `x/y/w/h`
|
||||
и `valid` оставались от ПРОШЛОГО кадра этой страницы, а сигнатура
|
||||
обновлялась на текущее состояние. Дальше `cd_quiet` видел `valid = 1` и
|
||||
совпавшую сигнатуру, то есть считал «на странице нарисовано ровно то, что
|
||||
надо», и слот залипал навсегда: `heal` не звался, старый спрайт оставался.
|
||||
|
||||
**Фикс.** `cd_sig_make` вызывается только когда кадр реально рисовали
|
||||
(`if (w && h)`). Без снимка слот не будет «тихим», и следующий кадр
|
||||
начнётся с `heal` — старое сотрётся само.
|
||||
|
||||
**ОСТАЁТСЯ ОТКРЫТЫМ (в BUGS_OPEN):** почему спрайт кадра оказался нулевым.
|
||||
Фикс убирает залипание, но кадр, для которого атлас отдал 0x0, всё равно
|
||||
не нарисуется. Подозрение — конкуренция за окно W0 между `atlas_image` и
|
||||
чтением данных уровня; проверять трассировкой маппинга.
|
||||
|
||||
Reference in New Issue
Block a user