BUG-TORCH-CHOMP-2: застывший чомпер накрывался пламенем факела
Регрессия от BUG-TORCH-CHOMP-1 (пламя перевели на запекание в фон). Аргумент «запекать безопасно, кадры пламени самонакрываются» верен для пикселей самого факела, но не для чужой графики в той же ячейке: пламя рисуется в клетке ПРАВОГО СОСЕДА (seg008:560), и челюсти чомпера возвращал поверх огня только его собственный trob — пока анимация жива. SDLPoP так не делает: animate_torch (seg007:0241) заканчивается вызовом set_redraw_anim_right(), который метит правого соседа, а redraw_needed (seg008:0178) рисует его слой строго в порядке draw_tile_anim_topright -> draw_tile_anim_right (пламя) -> draw_tile_anim (СВОЯ графика тайла). То есть челюсти возвращаются поверх огня КАЖДЫЙ кадр факела, независимо от собственной анимации чомпера. У нас пламя рисуется напрямую, минуя механизм пометок, — этой второй половины не было. Фикс: после pop_torch_draw метим правого соседа POP_RD_CHOMP на ОДНУ страницу (факел анимируется каждый кадр -> обе страницы получат свою перерисовку по очереди). Порядок сходится сам: блок факелов идёт до pop_redraw_needed. Код соседа читается в том же префетче кодов тайлов (trob_rcode[]), чтобы не свапать W0 второй раз за кадр. Банк 6 +104 Б. Осознанное расхождение (оригинал метит соседа безусловно, мы — только под чомпера) заведено открытым: TORCH-ANIM-RIGHT в bug_list.md. Слой draw_tile_anim рисует ещё пики/зелье/меч, но такого соседства на уровнях 1-4 не встретилось, а безусловная пометка стоит перерисовки тайла каждый кадр на каждый факел. tests-host: все 5 наборов прошли. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2206,3 +2206,51 @@ BUG-SEAM-PINGPONG (см. `bug_closed.md`). Приёмка:
|
||||
(ср. закрытый BUG-SEAM-PINGPONG). Второй кандидат — `char_height` в
|
||||
`can_bump_into_gate()`: если он берётся не от того кадра, решётка может
|
||||
перестать считаться препятствием раньше времени.
|
||||
|
||||
---
|
||||
|
||||
## BUG-TORCH-CHOMP-2. Застывший чомпер накрывается пламенем факела — ЗАКРЫТ 2026-08-10
|
||||
|
||||
Симптом (уровень 4, скриншот пользователя): пока чомпер щёлкает, всё в
|
||||
порядке; как только его анимация кончается, пламя соседнего факела ложится
|
||||
ПОВЕРХ челюстей.
|
||||
|
||||
Регрессия от фикса [BUG-TORCH-CHOMP-1](#bug-torch-chomp-1): там пламя
|
||||
перевели на ЗАПЕКАНИЕ в фон (`GFX_BANK_NORMAL`), чтобы `heal` соседнего
|
||||
чомпера не съедал огонь. Аргумент «запекать безопасно, кадры пламени
|
||||
самонакрываются» верен для СОБСТВЕННЫХ пикселей факела, но не для чужой
|
||||
графики в той же ячейке: пламя рисуется в клетке ПРАВОГО СОСЕДА
|
||||
(`x = (col+1)*32 + 8`, seg008:560), и если сосед — чомпер, огонь ложится на
|
||||
его челюсти. Пока trob чомпера жив, `pop_set_redraw(tp, POP_RD_CHOMP, ...)`
|
||||
возвращает их поверх каждый кадр; как только анимация кончилась и trob
|
||||
умер, возвращать стало нечем.
|
||||
|
||||
**Как это устроено в оригинале** (и почему у него бага нет).
|
||||
`animate_torch` (seg007:0241) заканчивается вызовом `set_redraw_anim_right()`
|
||||
— он метит `redraw_frames_anim` у ПРАВОГО СОСЕДА (seg007:0101). А
|
||||
`redraw_needed` (seg008:0178) рисует помеченный слой строго в порядке
|
||||
|
||||
```
|
||||
draw_tile_anim_topright();
|
||||
draw_tile_anim_right(); <- пламя ЛЕВОГО соседа (факела)
|
||||
draw_tile_anim(); <- СВОЯ графика тайла: челюсти чомпера
|
||||
```
|
||||
|
||||
То есть челюсти возвращаются поверх огня **каждый кадр факела**, независимо
|
||||
от того, жива ли собственная анимация чомпера. У нас пламя рисуется
|
||||
напрямую из `pop_process_trobs`, минуя механизм пометок, — этой второй
|
||||
половины не было.
|
||||
|
||||
**Фикс** (`pop_trob.c`): после `pop_torch_draw` метим правого соседа
|
||||
`pop_set_redraw(tp + 1, POP_RD_CHOMP, 1)`, если там чомпер. Одна страница:
|
||||
факел анимируется каждый кадр, значит обе страницы дабл-буфера получат свою
|
||||
перерисовку по очереди. Порядок сходится сам — блок факелов стоит ДО
|
||||
`pop_redraw_needed`. Код соседа читается в том же префетче кодов тайлов
|
||||
(`trob_rcode[]`), чтобы не свапать W0 второй раз за кадр. Банк 6: +104 Б.
|
||||
|
||||
**Осознанное расхождение** — оригинал метит соседа БЕЗУСЛОВНО, мы только под
|
||||
чомпера. Безусловная пометка = перерисовка тайла каждый кадр на каждый
|
||||
факел; слой `draw_tile_anim` рисует ещё пики, зелье и меч (seg008:0644),
|
||||
поэтому теоретически «застыть под пламенем» могут и они — заведено открытым
|
||||
в `bug_list.md` (TORCH-ANIM-RIGHT). На уровнях 1–4 такого соседства не
|
||||
встретилось.
|
||||
|
||||
@@ -303,3 +303,29 @@ if (curr_tile2 == tiles_15_opener || curr_tile2 == tiles_6_closer) {
|
||||
|
||||
Что нужно: сам порт `died_on_button`, константа `TILE_STUCK = 5` и тайл
|
||||
заклиненной кнопки в атласе фона (сейчас его там нет).
|
||||
|
||||
---
|
||||
|
||||
## TORCH-ANIM-RIGHT. Под пламенем могут застыть не только челюсти чомпера
|
||||
|
||||
Открыто 2026-08-10 при закрытии
|
||||
[BUG-TORCH-CHOMP-2](bug_closed.md#bug-torch-chomp-2).
|
||||
|
||||
Пламя факела запекается в фон и рисуется в ячейке ПРАВОГО СОСЕДА. Оригинал
|
||||
после каждого кадра факела метит этого соседа (`set_redraw_anim_right`,
|
||||
seg007:0101) и перерисовывает весь его слой `anim` поверх огня; мы метим
|
||||
только когда сосед — чомпер. Слой `draw_tile_anim` (seg008:0644) рисует
|
||||
также **пики, зелье и меч** — если такой тайл окажется справа от факела и
|
||||
будет в статике, пламя накроет и его.
|
||||
|
||||
На уровнях 1–4 такого соседства не встретилось, поэтому расширять пометку
|
||||
(она стоит перерисовки тайла каждый кадр на каждый факел) заранее не стали.
|
||||
|
||||
**Как проверять:** поставить факел слева от пики/меча/зелья в тестовой
|
||||
комнате и дождаться статики; либо пройти уровни 5+ и смотреть на клетку
|
||||
справа от каждого факела.
|
||||
|
||||
**Как чинить, если встретится:** там же, в ветке факела `pop_process_trobs`,
|
||||
добавить в `trob_rcode`-проверку нужные коды и соответствующий вид пометки
|
||||
(`POP_RD_SPIKE` / `POP_RD_FLOOR`), а зелье — переставить в порядке обхода
|
||||
так, чтобы оно рисовалось ПОСЛЕ факела.
|
||||
|
||||
@@ -42,6 +42,11 @@ typedef struct { uint8_t room, tilepos; int8_t type; } trob_t;
|
||||
static trob_t trobs[TROBS_MAX];
|
||||
static uint8_t trobs_count;
|
||||
static uint8_t trob_code[TROBS_MAX]; /* префетч кодов тайлов на кадр (1 map W0) */
|
||||
/* Код ПРАВОГО соседа — заполняется только у факелов (0 у остальных). Нужен
|
||||
* потому, что пламя рисуется в ячейке соседа и запекается в фон: если у
|
||||
* соседа своя anim-графика, её надо вернуть ПОВЕРХ огня. Читается в том же
|
||||
* префетче, чтобы не свапать W0 второй раз за кадр. */
|
||||
static uint8_t trob_rcode[TROBS_MAX];
|
||||
|
||||
/* Последняя НАРИСОВАННАЯ draw-сигнатура тайла (spike: modifier; button:
|
||||
* признак «нажата» = таймер связи >1). Редрой пики/кнопки — ТОЛЬКО при её
|
||||
@@ -499,8 +504,15 @@ void pop_process_trobs(uint8_t cur_room) __banked
|
||||
{
|
||||
uint8_t k;
|
||||
pop_level_access_begin();
|
||||
for (k = 0; k < trobs_count; k++)
|
||||
trob_code[k] = pop_level_tile_raw(trobs[k].room, trobs[k].tilepos);
|
||||
for (k = 0; k < trobs_count; k++) {
|
||||
uint8_t tp = trobs[k].tilepos;
|
||||
uint8_t c = pop_level_tile_raw(trobs[k].room, tp);
|
||||
trob_code[k] = c;
|
||||
trob_rcode[k] = 0;
|
||||
if ((c == TILE_TORCH || c == TILE_TORCH_DEBRIS) && TP_COL[tp] < 9)
|
||||
trob_rcode[k] = (uint8_t)(pop_level_tile_raw(trobs[k].room,
|
||||
(uint8_t)(tp + 1)) & 0x1F);
|
||||
}
|
||||
pop_level_access_end();
|
||||
}
|
||||
|
||||
@@ -570,8 +582,34 @@ void pop_process_trobs(uint8_t cur_room) __banked
|
||||
* __divuchar + __moduchar — на два факела это четыре вызова за
|
||||
* кадр (замер MAME). Тайл всегда 0..29. */
|
||||
uint8_t trow = TP_ROW[tp], tcol = TP_COL[tp];
|
||||
if (code == TILE_POTION) pop_potion_draw(trow, tcol, mod[tp]);
|
||||
else pop_torch_draw(trow, tcol, mod[tp]);
|
||||
if (code == TILE_POTION) {
|
||||
pop_potion_draw(trow, tcol, mod[tp]);
|
||||
} else {
|
||||
pop_torch_draw(trow, tcol, mod[tp]);
|
||||
/* Порт set_redraw_anim_right (seg007:0101): animate_torch метит
|
||||
* ПРАВОГО СОСЕДА, и redraw_needed рисует его слой anim в
|
||||
* порядке draw_tile_anim_topright -> draw_tile_anim_right
|
||||
* (пламя) -> draw_tile_anim (СВОЯ графика тайла). То есть в
|
||||
* оригинале челюсти чомпера возвращаются поверх огня КАЖДЫЙ
|
||||
* кадр факела, а не только пока жива их собственная анимация.
|
||||
*
|
||||
* У нас пламя запекается напрямую (pop_torch_draw), минуя
|
||||
* механизм пометок, поэтому у ЗАСТЫВШЕГО чомпера возвращать
|
||||
* его было нечем — огонь накрывал челюсти (баг найден на
|
||||
* уровне 4). Метим сосед-тайл сами, ОДНУ страницу: факел
|
||||
* анимируется каждый кадр, значит обе страницы получат свою
|
||||
* перерисовку по очереди. Порядок сходится: этот блок идёт
|
||||
* ДО pop_redraw_needed.
|
||||
*
|
||||
* РАСХОЖДЕНИЕ С ОРИГИНАЛОМ (осознанное): он метит соседа
|
||||
* безусловно, мы — только когда там чомпер. Безусловная
|
||||
* пометка = перерисовка тайла каждый кадр на каждый факел,
|
||||
* а слой anim рисует ещё пики/зелье/меч (seg008:644). Их
|
||||
* случай «застыл справа от факела» в bug_list как открытый:
|
||||
* пики и меч рядом с факелом на уровнях 1-4 не встретились. */
|
||||
if (trob_rcode[i] == TILE_CHOMP)
|
||||
pop_set_redraw((uint8_t)(tp + 1), POP_RD_CHOMP, 1);
|
||||
}
|
||||
}
|
||||
if (room == cur_room && code == TILE_SPIKE) {
|
||||
/* ПИКИ — редрой КАЖДЫЙ кадр, пока trob жив: animate_spike
|
||||
|
||||
Reference in New Issue
Block a user