PoP roomtest: пики — редрой каждый кадр, полный draw_tile; пламя без heal

Выдвинутая пика живёт ТОЛЬКО в видео-ОЗУ (банк SPRITE, в запечённый фон не
входит), а kid_heal каждый кадр возвращает под спрайтом Кида печёный фон —
то есть стирает попавшие под него части остриёв.  Редрой «только при смене
видимой сигнатуры» их не возвращал: hold держится 15 кадров (modif
0x8F..0x81) с неизменным кадром 5.  Итог по дампу VRAM (комната 14, Kid на
(2,7), modif 0x8E): у спрайта 132 стёрто третье остриё (x 245..247), у 138 —
прямое целиком (x 258..260) и низ наклонного, страницы дабл-буфера
расходились на 8 пикселей.  SDLPoP: animate_spike (seg007:0353) зовёт
redraw_21h БЕЗУСЛОВНО, вне всяких if — редрой каждый кадр, пока trob жив.

pop_spike_redraw переписан на честный redraw_tile_height (seg007:0218):
heal + ПОЛНЫЙ draw_tile своего тайла и правого соседа.  Рисовать только два
спрайта остриёв нельзя — теряется порядок слоёв внутри тайла
(draw_tile_anim_right идёт ПЕРВЫМ, база и fore соседа ложатся поверх), и
остриё лезло на колонну (2,9).  draw_tile заодно сам восстанавливает вклад
соседних пик (ветка lcode==2), так что две пики подряд больше не гасят
друг друга.

Пламя факела: heal убран.  Оригинал рисует его blitters_0_no_transp (seg008
draw_tile_anim_right), все 9 кадров лежат на общем канвасе 16x18 и бокс
центрирован в ячейке — непрозрачный блит сам полностью накрывает предыдущий
кадр.  Кадры пакуются с opaque=True (POT_FLAME_IDS).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 11:34:07 +03:00
parent e143ee010a
commit 723da3c5c1
5 changed files with 60 additions and 47 deletions
+17 -21
View File
@@ -626,28 +626,21 @@ void pop_loose_shake_draw(int row, int col)
* heal берёт печёный статич. фон, поверх — динамич. кадр (шипы над полом). */
void pop_spike_redraw(int row, int col)
{
int x = COL_XH[col] * 8;
int dmy = 63 * row + 62; /* как в draw_tile (dby-3) */
uint8_t sm = g_bg[row * 10 + col]; /* живой modif пики (room_modif) */
uint8_t sf = (sm & 0x80) ? 5 : sm; /* видимый кадр (hold 0x80..0x8F → 5) */
/* Шипы выдвигаются выше линии пола (env_b на dmy-7) — heal с запасом
* вверх (63*row+34 .. +74) покрывает и остриё, и сам пол; ширина 64 =
* тайл + правый сосед (остриё рисуется в его ячейке).
* heal вернул из ОЗУ-копии ВЕСЬ печёный статичный фон (база пик 127, пол,
* грани соседей — всё, что рисовал бы полный draw_tile при modif=0).
* Единственное, что реально анимируется — два спрайта острия (LEFT в своей
* ячейке + RIGHT в соседней, оба по sf). Поэтому вместо 2×draw_tile
* (десятки блитов статики поверх идентичного фона = идемпотентно) рисуем
* РОВНО эти два острия — пиксель-в-пиксель тот же результат, во много раз
* дешевле (порт redraw_21h: draw_tile_anim + draw_tile_anim_right). */
int x = COL_XH[col] * 8;
/* Порт redraw_21h -> redraw_tile_height (seg007:0218): wipe + ПОЛНЫЙ
* redraw ДВУХ тайлов — своего и правого соседа (остриё рисуется в его
* ячейке). Именно ПОЛНЫЙ: рисовать только два спрайта остриёв нельзя —
* порядок слоёв внутри тайла (draw_tile_anim_right идёт ПЕРВЫМ, база и
* fore соседа ложатся ПОВЕРХ) тогда теряется, и остриё лезет на колонну
* справа. Заодно draw_tile сам восстанавливает вклад соседних пик:
* в ячейке col — правое остриё пики col-1 (ветка lcode==2).
* Шипы выдвигаются выше линии пола (dmy-7), поэтому heal с запасом вверх
* (63*row+34 .. +74); ширина 64 = обе ячейки. */
heal_off(x, 63 * row + 34, 64, 40);
gfx_set_bank(GFX_BANK_SPRITE);
if (sf > 0 && sf < 10) {
if (SPIKES_FRAM_LEFT[sf]) /* остриё в своей ячейке */
env_b(SPIKES_FRAM_LEFT[sf], x, dmy - 2);
if (col + 1 < 10 && SPIKES_FRAM_RIGHT[sf]) /* остриё в ячейке соседа */
env_b(SPIKES_FRAM_RIGHT[sf], COL_XH[col + 1] * 8, dmy - 7);
}
draw_tile(row, col);
if (col + 1 < 10)
draw_tile(row, col + 1);
gfx_set_bank(GFX_BANK_NORMAL);
}
@@ -723,7 +716,10 @@ void pop_torch_draw(int row, int col, uint8_t modif)
int x = (col + 1 < 10 ? COL_XH[col + 1] : COL_XH[col] + 4) * 8 + 8;
int yb = 63 * row + 62 - 40;
if (modif >= 9) return;
heal_off(x - 1, yb - 18, 18, 19);
/* heal НЕ нужен: оригинал рисует пламя blitters_0_no_transp (seg008
* draw_tile_anim_right), и все 9 кадров лежат на общем канвасе 16x18 —
* непрозрачный блит сам полностью накрывает предыдущий кадр. Кадры
* упакованы с opaque=True (pop_pack_bg POT_FLAME_IDS). */
gfx_set_bank(GFX_BANK_SPRITE);
pot_b((uint8_t)(modif + 1), x, yb);
gfx_set_bank(GFX_BANK_NORMAL);