Смерть на кнопке ломает её насовсем (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:
@@ -2987,3 +2987,101 @@ mid-оверлей) переведены на него. Заодно `pop_chomp
|
||||
запечка» обязана спрашивать САМА функция «кадр по модификатору», а не
|
||||
вызывающий слой: слоёв отрисовки у тайла четыре, и забыть один слишком легко.
|
||||
Для новой анимированной ловушки это теперь обязательный пункт.
|
||||
|
||||
---
|
||||
|
||||
<a id="died-on-button"></a>
|
||||
## DIED-ON-BUTTON. Смерть на кнопке не ломала её: решётка закрывалась обратно
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-18).** Уровень 7 начинается падением, и
|
||||
если не зацепиться за кромку, Кид разбивается на `(2,1)` комнаты 3 — а там
|
||||
кнопка открытия решётки. В оригинале решётка после этого открыта НАСОВСЕМ,
|
||||
у нас отжималась.
|
||||
|
||||
Баг был заведён ещё при закрытии
|
||||
[BUG-LOOSE-BUTTON-1](#bug-loose-button-1) как «`died_on_button` (seg007:776)
|
||||
не портирован», но оказался ДВОЙНЫМ — до недостающей функции ещё и не было
|
||||
пути.
|
||||
|
||||
### Половина 1: физика трупа выключена целиком
|
||||
|
||||
```c
|
||||
void pop_phys_tick(void) __banked
|
||||
{
|
||||
if (pop_kid_dead) return; /* <- вся цепочка, включая check_press */
|
||||
```
|
||||
|
||||
У оригинала `play_kid_frame` (seg000:1231) гейт ровно один — `Char.room != 0`;
|
||||
весь список крутится и на трупе (по «жив/мёртв» разведены `check_spiked`/
|
||||
`check_chomped_kid`, и то через `resurrect_time`). Ранний выход выглядел
|
||||
безобидной экономией — «труп не шевелится», — но `check_press` на мёртвом
|
||||
персонаже делает СОВСЕМ ДРУГОЕ, чем на живом, и именно это выключалось.
|
||||
|
||||
Отсюда наблюдаемое: кнопка получала РОВНО ОДНО нажатие — в кадре самой
|
||||
смерти, потому что `pop_kid_dead` ставит `land()` уже ВНУТРИ цепочки, после
|
||||
раннего возврата. Решётка приоткрывалась и закрывалась.
|
||||
|
||||
Снято в MAME до фикса: Кид `frame 185, action 5 (bumped), alive 0`, тайл
|
||||
`(2,1)` = `0x0F` opener с модификатором `0x12`, openness решётки ползёт
|
||||
вниз 146 → 112. Кадр смерти при этом проходит все проверки `check_press`
|
||||
штатно (`action == ACT_BUMPED`, флаги кадра 185 = `0x49`, бит
|
||||
`FRAME_NEEDS_FLOOR` есть) — то есть путь был закрыт ровно одним `return`.
|
||||
|
||||
«Труп не шевелится» держится и без него, тем же, чем в оригинале: кадр
|
||||
смерти не двигается сам, а уход из комнаты и сотрясение отсечены ВНУТРИ
|
||||
`kid_phys` (там свой `if (pop_kid_dead) return;` перед `pop_check_knock`).
|
||||
|
||||
### Половина 2: сам `died_on_button`
|
||||
|
||||
```c
|
||||
if (Char.alive < 0) pop_trigger_button(...); /* жив — нажатие на 5 кадров */
|
||||
else died_on_button(...); /* мёртв — кнопка СЛОМАНА */
|
||||
```
|
||||
|
||||
Открывалка превращается в обычный пол с нулевым модификатором, а связь
|
||||
дёргается типом «щебень» (`TILE_DEBRIS`) — у `trigger_gate` это отдельная
|
||||
ветка «открыть насовсем». Любая другая кнопка становится заклиненной
|
||||
(`TILE_STUCK` = 5). Тайл пишем и в страницу уровня (переживает выход из
|
||||
комнаты), и в живую `g_fg`, с пометкой на перерисовку своей ячейки и правой.
|
||||
|
||||
Инфраструктура была готова давно: `TILE_DEBRIS` и ветка «насовсем» в
|
||||
`trigger_gate` написаны ещё тогда, с комментарием-ссылкой именно на
|
||||
`died_on_button` — из-за чего механизм и казался реализованным. Опасение
|
||||
старой записи, что нужен «тайл заклиненной кнопки в атласе, а его там нет»,
|
||||
не подтвердилось: `pop_tile_table[5]` (stuck floor) заполнен и уже
|
||||
рисуется — на него подставляется НАЖАТАЯ кнопка-закрывалка.
|
||||
|
||||
### Половина 3 (вылезла сразу): таймер связи переживал рестарт уровня
|
||||
|
||||
Пользователь поймал на первом же прогоне: **до первого падения кнопка
|
||||
рисуется правильно, после — выглядит нажатой с самого начала уровня**, хотя
|
||||
логически не нажата.
|
||||
|
||||
`died_on_button` ставит таймер связи в 5 и заводит trob кнопки — но тайл к
|
||||
этому моменту УЖЕ пол, и trob умирает в первом же обходе
|
||||
(`default: type = -1`), ни разу не уменьшив таймер. У оригинала ровно то же
|
||||
самое, только там `load_level()` перечитывает файл ЦЕЛИКОМ, а наш
|
||||
`pop_level_reset_tiles` восстанавливал одну foretable. Остаток `dl2[18] = 5`
|
||||
переживал респавн, а `pop_tile_code_drawn` рисует кнопку нажатой, пока
|
||||
таймер > 1.
|
||||
|
||||
Фикс — восстанавливать в рестарте и LINKMAP. Отдельная эталонная копия не
|
||||
нужна: в странице уровня LINKMAP остаётся нетронутой, игра правит только
|
||||
ОЗУ-копию `pop_dl2`.
|
||||
|
||||
**Проверка в MAME (полный цикл).**
|
||||
|
||||
| момент | тайл `(2,1)` | `dl2[18]` | `pop_kid_dead` | решётка `(2,6)` |
|
||||
|--------|--------------|-----------|----------------|-----------------|
|
||||
| труп на кнопке | `01` floor | 5 | 1 | `FF` открыта навсегда |
|
||||
| после респавна | `0F` opener | **`00`** | 0 | `00` закрыта |
|
||||
| второе падение | `01` floor | 5 | 1 | открывается заново |
|
||||
|
||||
Плюс попиксельная сверка кадров: решётка, до фикса стоявшая опущенной,
|
||||
поднята. Цена: резидент без изменений, банк 3 +193 Б, банк 8 +22 Б.
|
||||
|
||||
**Осталось невыясненным.** На СТАРОМ поведении openness решётки замирал на
|
||||
112 и дальше не убывал, хотя `animate_door` (совпадает с seg007:0522) обязан
|
||||
досчитать до 0 и снять trob. С фиксом сцена так не воспроизводится
|
||||
(решётка уходит в `FF`), проверить нечем; если всплывёт где-то ещё — это
|
||||
отдельный баг, к `died_on_button` отношения не имеющий.
|
||||
|
||||
Reference in New Issue
Block a user