P1: чомпер перерисовывался неизменной позой — минус 110 802 такта

Позиция заводилась с НЕПОЛНЫМ диагнозом.  Я приписал 190 260 тактов
пометке от факела (пламя лежит в ячейке правого соседа, то есть поверх
чомпера, и запекается каждый кадр).  Правка по этому диагнозу не дала
ничего: 769 002 против 768 684.

Зонд pop_dbg_kind показал факт: все 312 перерисовок прогона — вид
POP_RD_CHOMP, полная, и ни одной от факела.  Собственная пометка чомпера
просто перебивала пометку соседа.

Настоящая причина нашлась сверкой с animate_chomper (seg007:0448).
Оригинал заканчивает её так:

    if ((curr_modifier & 0x7F) < 6) redraw_at_trob();

то есть перерисовывает чомпер только пока фаза меньше 6 — пять кадров из
пятнадцати.  Это не оптимизация оригинала, а следствие таблицы поз:
chomper_fram1 = {3,2,0,1,4,3,3}, и с фазы 5 до конца круга поза одна и та
же.  Мы метили тайл каждый кадр, пока trob жив, а живёт он всё время, пока
Кид в том же ряду — то есть платили полный draw_tile плюс heal 32x64 за
неизменную картинку в двух третях кадров.

Сделано:

  1. пометка только при фазе < 6; на фазе 5 — обе страницы дабл-буфера
     (она последняя рисуемая, её поза обязана лечь на обе; вторую страницу
     пометка догоняет в кадре фазы 6, где поза та же — CHOMP_FRAM1[6] == 3);
  2. новый вид POP_RD_CHOMP_ANIM -> pop_chomp_anim_draw: три блита графики
     чомпера поверх свежего пламени, без heal и без остальных слоёв — порт
     ветки redraw_frames_anim (seg008:0211), где оригинал делает ровно
     draw_tile_anim_topright / draw_tile_anim_right / draw_tile_anim и
     никакого wipe;
  3. приоритет полной перерисовки над anim в pop_set_redraw: у оригинала
     это два независимых счётчика и full побеждает, а у нас вид один на
     тайл, и без проверки исход решал бы порядок trob'ов в списке.

Обе половины работают — замер даёт 40 % полных перерисовок и 60 % лёгких.
Работа 768 684 -> 657 882 (медиана), зелёная 294 510 -> 183 420.  В 40 %
кадров цена прежняя: там поза реально меняется, это честная работа.

Циан не сдвинулся ни на такт, то есть надежда P3 (Кид перестанет будиться
каждый кадр) пока не оправдалась — метки продолжают его будить.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 11:30:01 +03:00
parent f81b30eb68
commit de68eb5cec
7 changed files with 198 additions and 20 deletions
+26 -6
View File
@@ -730,7 +730,7 @@ void pop_process_trobs(uint8_t cur_room) __banked
* случай «застыл справа от факела» в BUGS_OPEN.md как открытый:
* пики и меч рядом с факелом на уровнях 1-4 не встретились. */
if (trob_rcode[i] == TILE_CHOMP)
pop_set_redraw((uint8_t)(tp + 1), POP_RD_CHOMP, 1);
pop_set_redraw((uint8_t)(tp + 1), POP_RD_CHOMP_ANIM, 1);
}
}
if (room == cur_room && code == TILE_SPIKE) {
@@ -749,11 +749,31 @@ void pop_process_trobs(uint8_t cur_room) __banked
pop_set_redraw(tp, POP_RD_SPIKE, (uint8_t)(type < 0 ? 2 : 1));
}
if (room == cur_room && code == TILE_CHOMP) {
/* Кадр меняется каждый тик, пока trob жив — как у пик, метим
* текущую страницу; последний кадр (челюсти встали) — обе,
* иначе на второй странице дабл-буфера застынет предыдущая поза
* и чомпер дрожит через кадр. */
pop_set_redraw(tp, POP_RD_CHOMP, (uint8_t)(type < 0 ? 2 : 1));
/* ТОЛЬКО ПОКА ФАЗА < 6 — как в оригинале (animate_chomper,
* seg007:0448 заканчивается `if ((curr_modifier & 0x7F) < 6)
* redraw_at_trob();`).
*
* Это не оптимизация оригинала, а точное следствие таблицы поз:
* CHOMP_FRAM1 = {3,2,0,1,4,3,3}, то есть с фазы 5 и до конца
* круга (POP_CHOMPER_SPEED = 15) поза одна и та же — 3.
* Перерисовывать её десять кадров подряд значит рисовать ровно
* ту же картинку, а стоит это 190 260 тактов НА КАДР: полный
* draw_tile плюс heal 32x64, 24 % работы кадра в 11/15
* (замер 2026-08-19).
*
* На фазе 5 метим ОБЕ страницы дабл-буфера: она последняя
* рисуемая, и её поза обязана лечь на обе, иначе на второй
* останется поза фазы 4 и чомпер будет дрожать через кадр.
* Сходится и по кадрам: вторую страницу эта пометка догоняет в
* кадре фазы 6, где поза та же самая (CHOMP_FRAM1[6] == 3).
*
* Про type < 0 отдельной ветки больше нет: trob снимается сам
* только при frame >= 6 (см. animate_chomper выше), то есть
* когда перерисовки уже не идут, а на экране с фазы 5 лежит
* финальная поза на обеих страницах. */
uint8_t ph = (uint8_t)(mod[tp] & 0x7F);
if (ph < 6)
pop_set_redraw(tp, POP_RD_CHOMP, (uint8_t)(ph == 5 ? 2 : 1));
}
if (room == cur_room && code == TILE_GATE) {
/* draw_trob (seg007:01E6), которым заканчивается animate_door: