Смерть на кнопке ломает её насовсем (died_on_button, seg007:776)

Уровень 7 начинается падением; разбившись на кнопке открытия решётки
(комната 3, тайл 2,1), Кид в оригинале открывает решётку НАСОВСЕМ, а у нас
она закрывалась обратно.  Чинить пришлось три места.

1. pop_phys_tick выходил по pop_kid_dead, то есть check_press до трупа не
   доходил вовсе.  У оригинала play_kid_frame гейтится только Char.room
   != 0.  Кнопка получала одно нажатие — в кадре смерти, потому что флаг
   ставит land() уже внутри цепочки.  «Труп не шевелится» держит внутренний
   выход в kid_phys, он остался.

2. Портирован died_on_button: открывалка → пол + связь дёргается типом
   «щебень» (открыть насовсем), прочие кнопки → TILE_STUCK.  Ветки по
   Char.alive в check_press не было вовсе.

3. Рестарт уровня восстанавливал только foretable, а died_on_button
   оставляет таймер связи нажатым (trob кнопки умирает сразу — тайл уже
   пол).  Остаток переживал респавн, и кнопка рисовалась нажатой с первого
   кадра.  pop_level_reset_tiles теперь возвращает и LINKMAP.

Проверено в MAME по всему циклу: смерть → FF (открыта навсегда), респавн →
кнопка цела и не нажата, второе падение → снова ломается.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 15:27:36 +03:00
parent b49ba15666
commit 6feab5d2f2
4 changed files with 182 additions and 71 deletions
+20 -1
View File
@@ -192,7 +192,24 @@ int8_t pop_room_col_landing(uint8_t room, uint8_t col) __banked
}
/* Рестарт уровня (порт load_level из цикла play_level, seg003:57): вернуть
* foretable в исходное состояние из эталонной копии. */
* в исходное состояние ВСЁ, что игра правит в данных уровня.
*
* Это foretable (из эталонной копии — сами данные мы правим на месте) И
* ТАБЛИЦА СВЯЗЕЙ. Про вторую легко забыть, потому что мутирует в ней ровно
* одно поле — таймер нажатия кнопки в младших битах LINKMAP, — но забыть
* дорого: `pop_tile_code_drawn` рисует кнопку НАЖАТОЙ, пока таймер > 1, и
* ненулевой остаток показывает её нажатой с первого кадра уровня.
*
* Оставить такой остаток особенно легко из died_on_button: он ставит таймер
* в 5 и заводит trob кнопки, но тайл к этому моменту УЖЕ пол — trob умирает
* в первом же обходе (`default: type = -1`), не успев ни разу уменьшить
* таймер. У оригинала ровно то же самое, просто там load_level перечитывает
* весь файл целиком, и вопроса не возникает (найдено пользователем
* 2026-08-18: уровень 7, комната 3, кнопка (2,1) после первого же респавна).
*
* LINKMAP в странице уровня остаётся ЭТАЛОННЫМ: игра правит только
* ОЗУ-копию pop_dl2 (pop_doorlink2_set), обратно в страницу не пишет никто —
* поэтому отдельная pristine-копия, как у foretable, тут не нужна. */
void pop_level_reset_tiles(void) __banked
{
uint16_t i;
@@ -203,6 +220,8 @@ void pop_level_reset_tiles(void) __banked
dst = (uint8_t *)(LVL_DATA_OFF + BP_FG);
src = (const uint8_t *)LVL_PRISTINE_OFF;
for (i = 0; i < 24u * ROOM_TILES; i++) dst[i] = src[i];
src = (const uint8_t *)(LVL_DATA_OFF + BP_LINKMAP);
for (i = 0; i < 256; i++) pop_dl2[i] = src[i];
gfx_w0_unmap();
}