Смерть на кнопке ломает её насовсем (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:
@@ -17,7 +17,6 @@
|
||||
| [SPRITE-ZERO-W0](#sprite-zero-w0) | кадр персонажа изредка отдаёт спрайт 0x0 (залипание уже вылечено) | **редкий** | открыт: нужна трасса маппинга W0 |
|
||||
| [GATE-FORE-KID](#gate-fore-kid) | Кид в проёме ворот виден поверх решётки | окклюзия | **фикс есть, ждёт проверки в MAME** (2026-08-13) |
|
||||
| [FORE-DUP](#fore-dup) | передний слой тайла рисуется дважды при перекрытии объектов | оптимизация | открыт: **сначала замерить**, потом чинить |
|
||||
| [DIED-ON-BUTTON](#died-on-button) | `died_on_button` (seg007:776) не портирован | порт | открыт |
|
||||
| [TORCH-ANIM-RIGHT](#torch-anim-right) | под запечённым пламенем застывают не только челюсти чомпера | **низкий** | открыт: на уровнях 1-4 такого соседства нет |
|
||||
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт |
|
||||
| [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом | **низкий** | маловоспроизводим: ни сценарием, ни попиксельной подгонкой X не поднимается |
|
||||
@@ -303,72 +302,6 @@ check_spiked (seg006:0658): убивает при h>=2 на кадрах б
|
||||
приоритет багов в них низкий. Аналогично 23/24 на уровне 3.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<a id="died-on-button"></a>
|
||||
## DIED-ON-BUTTON. `died_on_button` (seg007:776) не портирован
|
||||
|
||||
Обнаружено при разборе [BUG-LOOSE-BUTTON-1](BUGS_CLOSED.md#bug-loose-button-1).
|
||||
`check_press` (seg006:1707) разбирает ЛЮБОГО мёртвого `Char`, не только Кида:
|
||||
|
||||
```c
|
||||
if (curr_tile2 == tiles_15_opener || curr_tile2 == tiles_6_closer) {
|
||||
if (Char.alive < 0) trigger_button(1, 0, -1); /* жив */
|
||||
else died_on_button(); /* мёртв */
|
||||
}
|
||||
```
|
||||
|
||||
`died_on_button` на **opener** делает тайл обычным полом и форсирует
|
||||
`button_type = tiles_14_debris` — ворота открываются насовсем; на любой другой
|
||||
кнопке ставит `tiles_5_stuck` (заклинена, `link_timer == 0x1F`, связь мертва).
|
||||
|
||||
У Кида эффект живёт до перезапуска уровня (смерть → `is_restart_level` →
|
||||
`play_level` заново зовёт `load_level()`, тайлы перечитываются), а вот когда на
|
||||
кнопке умирает СТРАЖ — перезапуска нет, и кнопка заклинена до конца уровня.
|
||||
|
||||
Что нужно: сам порт `died_on_button`, константа `TILE_STUCK = 5` и тайл
|
||||
заклиненной кнопки в атласе фона (сейчас его там нет).
|
||||
|
||||
### Вторая половина: до `check_press` труп вообще не доходит (2026-08-18)
|
||||
|
||||
Найдено на живом сценарии (пользователь): уровень 7 начинается падением, и
|
||||
если не зацепиться за кромку, Кид разбивается на `(2,1)` комнаты 3 — а это
|
||||
кнопка открытия решётки. В оригинале решётка после этого открыта НАСОВСЕМ,
|
||||
у нас отжимается.
|
||||
|
||||
Оказалось, порта `died_on_button` мало — до него нет пути:
|
||||
|
||||
```c
|
||||
void pop_phys_tick(void) __banked
|
||||
{
|
||||
if (pop_kid_dead) return; /* <- вся физика трупа выключена */
|
||||
```
|
||||
|
||||
У оригинала `play_kid_frame` (seg000:1231) гейт ровно один — `Char.room != 0`;
|
||||
весь список, включая `check_press`, крутится и на трупе (по `alive` разведены
|
||||
только `check_spiked`/`check_chomped_kid`, и то через `resurrect_time`).
|
||||
|
||||
Отсюда наблюдаемое поведение: кнопка получает РОВНО ОДНО нажатие — в кадре
|
||||
самой смерти, потому что `pop_kid_dead` ставит `land()` уже ВНУТРИ цепочки,
|
||||
после раннего возврата. Решётка успевает приоткрыться и потом закрывается.
|
||||
Снято в MAME: Кид `frame 185, action 5 (bumped), alive 0, (2,1) room 3`,
|
||||
`pop_kid_dead = 1`, тайл `(2,1)` = `0x0F` opener, modif `0x12` (индекс связи),
|
||||
openness ворот `(2,6)` ползёт вниз (146 → 112).
|
||||
|
||||
Кадр смерти проходит проверки `check_press` штатно (`action == ACT_BUMPED`,
|
||||
флаги кадра 185 = `0x49`, бит `FRAME_NEEDS_FLOOR` есть) — то есть после снятия
|
||||
раннего возврата труп начнёт давить кнопку КАЖДЫЙ кадр, как живой. Это ещё
|
||||
не оригинал: там на `alive >= 0` уходит `died_on_button`, который делает
|
||||
эффект ПОСТОЯННЫМ и снимает кнопку с тайла. Значит чинить надо обе половины
|
||||
разом, иначе получится «кнопка держится, пока труп лежит» — поведение,
|
||||
которого нет ни в оригинале, ни сейчас.
|
||||
|
||||
**Побочное наблюдение, НЕ проверено:** openness ворот остановился на 112 и
|
||||
дальше не убывал, хотя `animate_door` (у нас совпадает с seg007:0522) обязан
|
||||
досчитать до 0 и снять trob. Довести проверку не удалось — в сцене залип
|
||||
`frozen` (клавиша фриза осталась в raw-битмапе, `2` перестала сниматься).
|
||||
Если подтвердится — это отдельный баг, к `died_on_button` отношения не имеющий.
|
||||
|
||||
---
|
||||
|
||||
<a id="torch-anim-right"></a>
|
||||
|
||||
Reference in New Issue
Block a user