Уровень 4: skip по маске тайлов + порт loose_land, ворота 0xFF, пламя в фон

ОПТИМИЗАЦИЯ.  Метка «фон трогали» была одним union-прямоугольником на
страницу, и три факела комнаты склеивались в полосу x 40..280 на всю
комнату — Кид, стоящий между крайними факелами, терял пропуск перерисовки
и каждый кадр платил полным fore-проходом.  Теперь это маска тайлов
(uint16_t pop_cd_dmask[2][3]: бит = колонка, слово = ряд, набор = страница),
проверка — три AND через резидентный pop_cd_hit.  Гранулярность тайла — это
гранулярность оригинала (redraw_frames_anim[tilepos], set_wipe;
подтайловое уточнение там только по высоте, wipe_heights).  Замер на (1,7):
циан 233 515 -> 24 781, работа за кадр 517 609 -> 306 553, период 4 -> 3
растровых кадра.

BUG-LOOSE-BUTTON-1.  Упавшая плита не нажимала кнопку.  Три слоя: порт
loose_land не звал trigger_button вовсе; pop_room_col_landing считала
площадкой только чистый пол, а у оригинала их семь (пол, пика, обе кнопки,
зелье, оба факела); сигнал приходил в момент ОТРЫВА плиты, из-за чего
ворота начинали открываться, пока она ещё в воздухе.  Нажатие в оригинале
ОДНО, но с button_type = tiles_14_debris — это «открыть НАСОВСЕМ»
(modifier 0xFF), и кнопка съедается.  Посадка в комнате снизу переехала на
новый сигнал pop_loose_exit (взводит mob_tick_one, когда кусок ушёл ниже
поля).

BUG-GATE-FF-1.  0xFF был перегружен: сторожевое «тайла нет» в gate_modif и
живое «открыто навсегда» из trigger_gate.  gate_passable заворачивал Кида в
воротах, нарисованных открытыми.  Мёртвая ветка убрана.

BUG-TORCH-CHOMP-1.  Чомпер (0,7) комнаты 23 healит x 224..255 / y 30..93 и
стирал пламя факела (0,6), которое рисуется в ячейке правого соседа.  Фикс —
запекать пламя (GFX_BANK_NORMAL): у факела все девять кадров на общем
канвасе 16x18 и непрозрачны, протухнуть в ОЗУ-копии нечему, а heal чомпера
сам возвращает огонь и кладёт челюсти поверх — z-порядок как в оригинале.
Пузырёк зелья так нельзя (ползёт вверх, нужен heal) — остаётся в SPRITE.

Заведено открытым: died_on_button (seg007:776) не портирован — нужен тайл
tiles_5_stuck в атласе.

Проверено пользователем в MAME (уровень 4: плита 16(1,1) -> кнопка 17(0,1)
-> ворота 23(0,9); комната 23 с чомпером и факелом); make -C tests-host —
все 5 наборов.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 17:52:04 +03:00
parent 6a824dd7ab
commit 4718bff767
13 changed files with 364 additions and 47 deletions
+31 -6
View File
@@ -252,6 +252,10 @@ static uint8_t room_label_redraw;
* терялась: разбитые плиты и выпитые зелья «возвращались» при возврате в
* комнату (BUG-LVLSTATE-1). */
#define TILE_DEBRIS 0x0E
#define TILE_CLOSER 0x06
#define TILE_OPENER 0x0F
#define TILE_TORCH 0x13
#define TILE_TORCH_DEBRIS 0x1E
#define TILE_EMPTY 0x00
#define TILE_FLOOR 0x01
@@ -815,15 +819,36 @@ int main(void)
gfx_set_draw_page(back);
}
}
if (pop_loose_fell) { /* упавший кусок → debris в комнате снизу */
if (pop_loose_fell) { /* remove_loose: сама плита исчезла */
uint8_t fpos = (uint8_t)(pop_loose_fell - 1);
uint8_t fcol = (uint8_t)(fpos % 10);
uint8_t down = pop_room_link(cur_room, LINK_DOWN);
pop_loose_fell = 0;
pop_level_set_tile(cur_room, fpos, TILE_EMPTY); /* сама плита исчезла */
pop_level_set_tile(cur_room, fpos, TILE_EMPTY);
}
if (pop_loose_exit) { /* кусок долетел до низа комнаты — посадка ниже */
uint8_t fcol = (uint8_t)(pop_loose_exit - 1);
uint8_t from = pop_loose_exit_room;
uint8_t down = pop_room_link(from, LINK_DOWN);
pop_loose_exit = 0;
if (down) {
int8_t lrow = pop_room_col_landing(down, fcol);
if (lrow >= 0) pop_level_set_tile(down, (uint8_t)(lrow * 10 + fcol), TILE_DEBRIS);
if (lrow >= 0) {
uint8_t lpos = (uint8_t)(lrow * 10 + fcol);
uint8_t tt = pop_level_tile(down, lpos);
/* Кусок сел в комнате СНИЗУ — кнопка там нажимается так
* же, как в своей (loose_land, seg007:11E8): на opener
* подставляется button_type = щебень, то есть «открыть
* НАСОВСЕМ» (modifier 0xFF). Второе место того же
* порта: своя комната — в pop_map.c. */
if (tt == TILE_OPENER || tt == TILE_CLOSER)
pop_trigger_button(down, lpos,
(uint8_t)(tt == TILE_OPENER ? TILE_DEBRIS : tt),
pop_trob_modif(down)[lpos]);
/* На факеле остаётся отдельный тайл «факел с щебнем»
* (seg007:1067), а не обычный щебень. */
pop_level_set_tile(down, lpos,
(uint8_t)((tt == TILE_TORCH || tt == TILE_TORCH_DEBRIS)
? TILE_TORCH_DEBRIS : TILE_DEBRIS));
}
}
}
if (pop_ceil_fell) { /* провалилась плита-ПОТОЛОК (ряд 2 комнаты сверху) */
@@ -905,7 +930,7 @@ int main(void)
* для неё снят. ПОСЛЕ отрисовки, а не до: слой фона этого же кадра
* взводит бит и обязан быть учтён. Всё, что рисуется ниже
* (mob поверх Кида, борта), взводит его заново само. */
pop_cd_dirty = (uint8_t)(pop_cd_dirty & ~(1 << back));
pop_cd_clear(back);
pop_room_clip_borders(); /* почистить борта — только в кадрах падения (гейт) */
/* Пейсинг 3 кадра, затем tear-free флип на vblank: draw уже