Смерть на кнопке ломает её насовсем (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:
@@ -58,6 +58,7 @@
|
||||
#define TILE_TORCH_DEBRIS 30 /* факел + щебень (loose_land) */
|
||||
#define TILE_SPIKE 2 /* пики */
|
||||
#define TILE_CLOSER 6 /* кнопка-закрывалка (DROP) */
|
||||
#define TILE_STUCK 5 /* заклиненная кнопка (died_on_button) */
|
||||
#define TILE_POTION 10 /* зелье */
|
||||
#define TILE_SWORD 22 /* меч на полу */
|
||||
#define TILE_OPENER 15 /* кнопка-открывалка (RAISE, 0x0F) */
|
||||
@@ -2144,6 +2145,47 @@ static void make_loose_fall(int pos, uint8_t modifier)
|
||||
pop_loose_modif[pos] = modifier;
|
||||
}
|
||||
|
||||
/* died_on_button (seg007:0776): на кнопке КТО-ТО УМЕР — эффект становится
|
||||
* ПОСТОЯННЫМ, а сама кнопка с тайла снимается.
|
||||
*
|
||||
* Открывалка превращается в обычный пол с нулевым модификатором, а связь
|
||||
* дёргается типом «щебень» (TILE_DEBRIS) — у trigger_gate это отдельная
|
||||
* ветка «открыть насовсем»: недооткрытые ворота получают trob-тип 2, уже
|
||||
* открытые — modif 0xFF (открыты навсегда). Любая другая кнопка становится
|
||||
* заклиненной (TILE_STUCK): нажатой она и останется.
|
||||
*
|
||||
* ЗАЧЕМ ЭТО ВООБЩЕ НУЖНО. Труп не «держит» кнопку — он её ЛОМАЕТ. Разница
|
||||
* видна сразу: держал бы — ворота закрылись бы, как только тело убрали или
|
||||
* уровень перезапустили. У Кида перезапуск всё равно перечитывает тайлы, а
|
||||
* вот когда на кнопке гибнет СТРАЖ, перезапуска нет и кнопка заклинена до
|
||||
* конца уровня.
|
||||
*
|
||||
* Тайл пишем и в страницу уровня (переживёт выход из комнаты, как do_pickup),
|
||||
* и в живую g_fg отрисованной комнаты — вместе с пометкой на перерисовку
|
||||
* своей ячейки и правой (у кнопки и пола разные правые грани). */
|
||||
static void died_on_button(uint8_t room, uint8_t tp, uint8_t code)
|
||||
{
|
||||
uint8_t *mod = pop_trob_modif(room);
|
||||
uint8_t modifier = mod[tp]; /* индекс связи — ДО затирания */
|
||||
uint8_t button_type = code;
|
||||
uint8_t newtile;
|
||||
if (code == TILE_OPENER) {
|
||||
newtile = TILE_FLOOR;
|
||||
mod[tp] = 0;
|
||||
button_type = TILE_DEBRIS; /* trigger_gate: «открыть насовсем» */
|
||||
} else {
|
||||
newtile = TILE_STUCK;
|
||||
}
|
||||
pop_level_set_tile(room, tp, newtile);
|
||||
if (room == g_room) {
|
||||
g_fg[tp] = newtile;
|
||||
pop_set_redraw(tp, POP_RD_FLOOR, 2); /* обе страницы */
|
||||
if (tp % 10 < 9)
|
||||
pop_set_redraw((uint8_t)(tp + 1), POP_RD_FLOOR, 2);
|
||||
}
|
||||
pop_trigger_button(room, tp, button_type, modifier);
|
||||
}
|
||||
|
||||
/* check_press (seg006:0EC8, упрощ.): Kid стоит на loose → make_loose_fall;
|
||||
* frame 79 (прыжок вверх) с loose СВЕРХУ → пробить сверху. */
|
||||
static void check_press(void)
|
||||
@@ -2191,8 +2233,14 @@ static void check_press(void)
|
||||
* (curr_col = −1 или 10). Комнату и tilepos берём резолвнутые,
|
||||
* иначе индекс связи читается из чужого тайла (см. tile_room_of). */
|
||||
uint8_t btn_room = tile_room_of(Char.curr_col, Char.curr_row, &tp);
|
||||
if ((t == TILE_OPENER || t == TILE_CLOSER) && btn_room)
|
||||
pop_trigger_button(btn_room, tp, t, pop_trob_modif(btn_room)[tp]);
|
||||
if ((t == TILE_OPENER || t == TILE_CLOSER) && btn_room) {
|
||||
/* seg006:1707 — ЖИВОЙ жмёт кнопку на 5 кадров, МЁРТВЫЙ ломает её
|
||||
* насовсем. `alive < 0` = жив (соглашение оригинала). */
|
||||
if (Char.alive < 0)
|
||||
pop_trigger_button(btn_room, tp, t, pop_trob_modif(btn_room)[tp]);
|
||||
else
|
||||
died_on_button(btn_room, tp, t);
|
||||
}
|
||||
else if (t == TILE_LOOSE) {
|
||||
/* loose живёт в СВОЕЙ комнате (make_loose_fall работает с g_fg),
|
||||
* поэтому здесь по-прежнему координаты персонажа. */
|
||||
@@ -3008,7 +3056,20 @@ static void guard_phys(void)
|
||||
* физика меняет персонажу всё — координаты, ряд/колонку, кадр, seq. */
|
||||
void pop_phys_tick(void) __banked
|
||||
{
|
||||
if (pop_kid_dead) return; /* труп на пиках — без физики (только seq смерти) */
|
||||
/* РАННЕГО ВЫХОДА ПО pop_kid_dead ЗДЕСЬ НЕТ — и это принципиально.
|
||||
* У оригинала play_kid_frame (seg000:1231) гейт ровно один, `Char.room
|
||||
* != 0`: вся цепочка крутится и на ТРУПЕ. Стоял `if (pop_kid_dead)
|
||||
* return;` — дёшево и почти незаметно, но вместе с физикой он выключал
|
||||
* check_press, а тот на мёртвом персонаже делает совсем не то, что на
|
||||
* живом (died_on_button — кнопка ломается насовсем). Наблюдалось как
|
||||
* «Кид разбился на кнопке открытия решётки, а решётка закрылась»
|
||||
* (уровень 7, комната 3, тайл 2,1): кнопка получала РОВНО ОДНО нажатие —
|
||||
* в кадре самой смерти, потому что pop_kid_dead ставит land() уже внутри
|
||||
* цепочки. Разбор — BUGS_CLOSED.md#died-on-button.
|
||||
*
|
||||
* «Труп не шевелится» держится не этим выходом, а тем же, чем в
|
||||
* оригинале: кадр смерти не двигается сам (dx/dy нулевые, sequence
|
||||
* кончился), а уход из комнаты и сотрясение отсечены внутри kid_phys. */
|
||||
pop_loadkid_and_opp();
|
||||
kid_phys();
|
||||
pop_savekid_and_opp();
|
||||
|
||||
Reference in New Issue
Block a user