Уровень 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
+26 -2
View File
@@ -54,6 +54,8 @@
#define TILE_WALL 20
#define TILE_LOOSE 11 /* проваливающийся пол */
#define TILE_DEBRIS 14 /* щебень (упавший loose) */
#define TILE_TORCH 19 /* факел */
#define TILE_TORCH_DEBRIS 30 /* факел + щебень (loose_land) */
#define TILE_SPIKE 2 /* пики */
#define TILE_CLOSER 6 /* кнопка-закрывалка (DROP) */
#define TILE_POTION 10 /* зелье */
@@ -319,7 +321,14 @@ uint8_t pop_gate_modif(int8_t col, int8_t row) __banked
static uint8_t gate_passable(int8_t col, int8_t row)
{
uint8_t gm = gate_modif(col, row);
if (gm == 0xFF) return 0;
/* Ветки `if (gm == 0xFF) return 0;` здесь БЫТЬ НЕ ДОЛЖНО: 0xFF — это не
* только сторожевое «тайла нет» из gate_modif, но и живой модификатор
* «ворота открыты НАСОВСЕМ» (trigger_gate по button_type = щебень,
* seg007:623). Значение это появилось только когда заработал порт
* loose_land, и ворота выходили нарисованными открытыми (отрисовка
* клампит modl>188 -> 188), но непроходимыми. Сторож сюда не приходит:
* зовут нас только там, где тайл ТОЧНО ворота, а (0xFF>>2)+6 = 69 и так
* больше любого fph. */
return (uint8_t)((gm >> 2) + 6) >= (uint8_t)CD_ACT->fph;
}
@@ -2126,9 +2135,24 @@ void pop_loose_tick(void) __banked
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
uint8_t r = 0, c = pos;
uint8_t tt = (uint8_t)(g_fg[pos] & 0x1F); /* тайл, НА который села плита */
pop_loose_landed = 0;
while (c >= 10) { c -= 10; r++; }
g_fg[pos] = TILE_DEBRIS;
/* Плита, севшая на КНОПКУ, её нажимает (seg007:11E8, ветки
* tiles_15_opener / tiles_6_closer). Тонкость: на opener оригинал
* подставляет button_type = tiles_14_debris, а это у trigger_gate
* отдельная ветка «открыть НАСОВСЕМ» (возврат 2 -> animate_door
* доводит створку и ставит modifier 0xFF, после чего ворота
* заморожены и обычный opener их больше не трогает). Сама кнопка
* съедается: тайл станет щебнем ниже, нажаться второй раз нечему.
* Модификатор (индекс LINKLOC) тайл не меняет, берём его как есть. */
if (tt == TILE_OPENER || tt == TILE_CLOSER)
pop_trigger_button(g_room, pos,
(uint8_t)(tt == TILE_OPENER ? TILE_DEBRIS : tt),
pop_trob_modif(g_room)[pos]);
/* На факеле — отдельный тайл «факел с щебнем» (seg007:1067). */
g_fg[pos] = (uint8_t)((tt == TILE_TORCH || tt == TILE_TORCH_DEBRIS)
? TILE_TORCH_DEBRIS : TILE_DEBRIS);
/* Перерисовка ПО ПЛОЩАДИ ПОЛА (не LOOSE_GONE: та стирает и верх стены
* ряда ниже — оставался чёрный прямоугольник под тайлом). Обе
* страницы дабл-буфера. */