Уровень 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:
2026-08-11 23:01:58 +03:00
parent e4ef489872
commit 9ecea17ba6
13 changed files with 310 additions and 65 deletions
+39 -17
View File
@@ -879,7 +879,13 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
* страницы своя копия фона). Раньше коридор был фиксирован под ряд 2;
* плита-потолок падает через весь ряд 0, поэтому чистим по фактической
* прошлой позиции. */
if (here && m->prev_y[pg] != MOB_Y_NONE) {
/* Гейта по `here` здесь БЫТЬ НЕ ДОЛЖНО: prev_y[pg] — это след, который
* кусок оставил ИМЕННО НА ЭТОЙ странице, и стереть его надо независимо
* от того, где кусок сейчас. Пока чистка была под `here`, кусок,
* улетевший в комнату снизу (mob_down_a_row), навсегда оставлял себя
* на одной из двух страниц дабл-буфера — «застрявшая плита», видимая
* через кадр (BUG-MOB-STALE-PAGE). */
if (m->prev_y[pg] != MOB_Y_NONE) {
pop_heal_off(MOB_X0(m->x), m->prev_y[pg] - 27, MOB_W, 32);
m->prev_y[pg] = MOB_Y_NONE;
}
@@ -894,14 +900,34 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
if (m->row < 3 && m->y < 226 && MOB_Y_BOUND[m->row + 1] <= m->y) {
uint8_t t = mob_tile_at(m);
if (t == 0 || t == 11) {
m->row++; /* mob_down_a_row */
/* mob_down_a_row (seg007:1387): ряд ниже, а из НИЖНЕГО ряда —
* в комнату СНИЗУ (y -= 192, ряд 0). Именно так кусок пролетает
* несколько комнат подряд: уровень 6, плита (1,7) комнаты 6
* проваливается сквозь пустую шахту комнаты 7 и приземляется на
* кнопку (2,7) комнаты 11. Раньше мы кусок на границе комнаты
* ГАСИЛИ и подменяли одним «переходом вниз» из главного цикла —
* дальше первой комнаты он не летел (BUG-MOB-MULTIROOM). */
m->row++;
if (m->row >= 3) {
m->y = (int16_t)(m->y - 192);
m->row = 0;
m->room = pop_room_link(m->room, 3 /* вниз */);
if (!m->room) { /* улетел из уровня — просто гаснет */
m->active = 0; m->clean = 2; /* дочистить ОБЕ страницы */
return;
}
here = (uint8_t)(m->room == pop_t_room);
}
} else if (!here) {
/* Приземление в ПОКИНУТОЙ комнате: рисовать нечего, сигнальная
* пара pop_loose_landed/pop_debris_at обслуживает только текущую
* комнату — щебень кладём прямо в данные уровня (loose_land пишет
* в curr_room_tiles комнаты curmob.room, а не отрисованной). */
pop_level_set_tile(m->room, (uint8_t)(m->row * 10 + m->col), 0x0E);
m->active = 0; m->clean = 0;
/* Приземление в ПОКИНУТОЙ комнате: рисовать нечего, но щебень и
* КНОПКА под куском обязаны сработать — сигналим главному циклу
* комнатой и тайлом (loose_land, seg007:11E8, работает с
* curmob.room, а не с отрисованной). */
pop_loose_exit_room = m->room;
pop_loose_exit = (uint8_t)(m->row * 10 + m->col + 1);
/* clean = 2 даже для чужой комнаты: пока кусок летел, он мог
* рисоваться в ЭТОЙ, и след остался на обеих страницах. */
m->active = 0; m->clean = 2;
return;
} else if (pop_loose_landed) {
/* сигнал прошлого приземления ещё не разобран (один за кадр) —
@@ -914,15 +940,11 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
return;
}
}
if (m->y - 27 >= POP_PLAYFIELD_H) { /* весь ниже поля (улетел из комнаты) */
/* Приземление в комнате СНИЗУ разбирает главный цикл — но ИМЕННО
* сейчас, когда кусок долетел, а не в момент отрыва плиты: иначе
* кнопка внизу срабатывала, пока плита ещё в воздухе. */
if (!pop_loose_exit) {
pop_loose_exit = (uint8_t)(m->col + 1);
pop_loose_exit_room = m->room;
}
m->active = 0; m->clean = (uint8_t)(here ? 2 : 0);
/* Страховка: кусок ушёл ниже поля, не поймав границу ряда (в норме этого
* не бывает — mob_down_a_row уводит его в комнату снизу). Просто гаснет,
* как у оригинала кусок в комнате 0 (move_loose: `speed = -2`). */
if (m->y - 27 >= POP_PLAYFIELD_H) {
m->active = 0; m->clean = 2;
return;
}
if (!here) return; /* чужая комната — считаем, но не рисуем */