cd_quiet: сравнение снимка без построения структуры — минус 8 016

cd_sig_make СТРОИТ структуру из тринадцати полей в стековом кадре (то есть
через -n(ix)), и только потом шёл побайтовый цикл сравнения.  А зовётся
проверка четыре раза за кадр: pop_char_skip_mask дважды, и в ней по два
слота.

Новый cd_sig_same сравнивает поля прямо с источником, с ранним выходом на
первом расхождении — у двигающегося персонажа это обычно первое же поле.
cd_sig_make остался: он нужен pop_char_draw, чтобы снимок записать.

Замер 11/15, лёгкая позиция: участок «mob_draw + guard_over_kid +
skip_mask» 47 883 -> 43 875, циан 59 265 -> 55 257, синяя 223 902 ->
219 753, работа кадра 464 796 -> 456 780.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 16:33:31 +03:00
parent 52bcc65a62
commit 379c513087
+29 -8
View File
@@ -344,6 +344,34 @@ static void cd_sig_make(uint8_t who, cd_sig_t *g)
g->dx = pop_cd[who].render_dx;
}
/* Совпадает ли снимок страницы с ТЕКУЩИМ состоянием персонажа.
*
* Отдельно от cd_sig_make намеренно: тот СТРОИТ структуру, и для проверки
* это лишняя работа — тринадцать записей в стековый кадр (а значит через
* `-n(ix)`), после которых идёт побайтовый цикл сравнения. А зовут проверку
* четыре раза за кадр: pop_char_skip_mask дважды, и в ней по два слота.
* Здесь сравниваем поля прямо с источником, и первое же расхождение
* заканчивает работу — у ДВИГАЮЩЕГОСЯ персонажа это обычно первое поле. */
static uint8_t cd_sig_same(uint8_t who, uint8_t p)
{
const pop_char_t *ch = (who == POP_CH_KID) ? &Kid : &Guard;
const cd_sig_t *g = &cd_sig[who][p];
if (g->frame != ch->frame) return 0;
if (g->x != ch->x) return 0;
if (g->y != ch->y) return 0;
if (g->dir != ch->direction) return 0;
if (g->action != ch->action) return 0;
if (g->ccol != ch->curr_col) return 0;
if (g->crow != ch->curr_row) return 0;
if (g->sword != ch->sword) return 0;
if (g->charid != ch->charid) return 0;
if (g->room != ch->room) return 0;
if (g->hurt != (uint8_t)((who == POP_CH_KID) ? pop_kid_hurt : pop_guard_hurt))
return 0;
if (g->dx != pop_cd[who].render_dx) return 0;
return 1;
}
/* Габарит слота на странице: спрайт + накладные (клинок/брызги). y —
* КОМНАТНЫЙ (как в pop_cd), перевод в экранный делает вызывающий. */
static void cd_bbox(uint8_t who, uint8_t p, int *x0, int *y0, int *x1, int *y1)
@@ -366,9 +394,6 @@ static void cd_bbox(uint8_t who, uint8_t p, int *x0, int *y0, int *x1, int *y1)
* ни перепроверяй за кадр. */
static uint8_t cd_quiet(uint8_t who, uint8_t p)
{
cd_sig_t g;
const uint8_t *a, *b;
uint8_t i;
/* Соперника на сцене нет и на ЭТОЙ странице от него ничего не осталось —
* стирать и рисовать нечего, слот «тихий». Без этого пустой слот каждый
* кадр честно проходил heal + вход в pop_char_draw + fore-проход и стоил
@@ -401,11 +426,7 @@ static uint8_t cd_quiet(uint8_t who, uint8_t p)
return 0;
}
}
cd_sig_make(who, &g);
a = (const uint8_t *)&g; b = (const uint8_t *)&cd_sig[who][p];
for (i = 0; i < sizeof(cd_sig_t); i++)
if (*a++ != *b++) return 0;
return 1;
return cd_sig_same(who, p);
}
/* Запас вокруг габарита соседа: за кадр персонаж проходит заметно меньше