diff --git a/applications/PoP/roomtest/pop_cdraw.c b/applications/PoP/roomtest/pop_cdraw.c index ff6bf55..cec00e9 100644 --- a/applications/PoP/roomtest/pop_cdraw.c +++ b/applications/PoP/roomtest/pop_cdraw.c @@ -414,17 +414,7 @@ static uint8_t cd_quiet(uint8_t who, uint8_t p) * * Для skip_mask объединение по-прежнему годится: там вопрос «рядом ли * два слота», и загрубление в бОльшую сторону безопасно. */ - const pop_cdraw_t *q = &pop_cd[who]; - int y0 = q->y[p] + POP_YOFF; - if (pop_cd_hit(p, q->x[p], y0, - q->x[p] + (int)q->w[p] - 1, y0 + (int)q->h[p] - 1)) - return 0; - if (q->ovalid[p]) { - int oy = q->oy[p] + POP_YOFF; - if (pop_cd_hit(p, q->ox[p], oy, - q->ox[p] + (int)q->ow[p] - 1, oy + (int)q->oh[p] - 1)) - return 0; - } + if (pop_cd_hit_slot(who, p)) return 0; } return cd_sig_same(who, p); } diff --git a/applications/PoP/roomtest/pop_cdraw.h b/applications/PoP/roomtest/pop_cdraw.h index 3545047..25f233e 100644 --- a/applications/PoP/roomtest/pop_cdraw.h +++ b/applications/PoP/roomtest/pop_cdraw.h @@ -129,6 +129,9 @@ extern uint8_t pop_cd_ymin[2][10], pop_cd_ymax[2][10]; /* Задели ли прямоугольник (ЭКРАННЫЕ координаты, x1/y1 включительно) то, * что трогали на странице p. Резидент (pop_tile.c). */ uint8_t pop_cd_hit(uint8_t p, int x0, int y0, int x1, int y1); +/* То же для СЛОТА персонажа: спрайт и накладной, координаты изнутри pop_cd + * (см. тело — там про цену пяти аргументов). */ +uint8_t pop_cd_hit_slot(uint8_t who, uint8_t p); void pop_cd_clear(uint8_t p); /* снять метку страницы целиком */ void pop_cd_init(void); /* пустые диапазоны на обеих страницах */ void pop_cd_touch(int x, int y, int w, int h); diff --git a/applications/PoP/roomtest/pop_tile.c b/applications/PoP/roomtest/pop_tile.c index 2d6b0b3..9f15b7b 100644 --- a/applications/PoP/roomtest/pop_tile.c +++ b/applications/PoP/roomtest/pop_tile.c @@ -306,6 +306,52 @@ void pop_cd_touch(int x, int y, int w, int h) /* Задел ли прямоугольник (ЭКРАННЫЕ координаты, x1/y1 ВКЛЮЧИТЕЛЬНО) то, что * трогали на странице p. Резидент: зовёт pop_cdraw.c из банка 4 прямым * вызовом, без трамплина. */ +/* Прямоугольник слота против метки — БЕЗ передачи пяти аргументов. + * + * pop_cd_hit принимает (p, x0, y0, x1, y1): три последних идут стеком, и + * функция целиком уезжает в IX-фрейм — 45 % её тактов уходит на `-n(ix)` + * (замер asm 2026-08-19). А зовут её из cd_quiet дважды на слот, то есть + * до восьми раз за кадр. Здесь координаты берутся прямо из pop_cd, и + * аргументов остаётся два. + * + * Спрайт и накладной проверяются РАЗДЕЛЬНО — объединённый bbox ловит + * касания углом, которых нет (разбор в cd_quiet, pop_cdraw.c). */ +static int hit_x, hit_y; /* аргументы hit_rect — file-scope, не стек */ +static uint16_t hit_w, hit_h; +static uint8_t hit_p; + +static uint8_t hit_rect(void) +{ + int8_t c0, c1, c; + uint8_t ya, yb; + int x1 = hit_x + (int)hit_w - 1; + int y1 = hit_y + (int)hit_h - 1; + if (!hit_w || !hit_h) return 0; + if (x1 < 0 || hit_x > 319) return 0; + if (y1 < 0 || hit_y > 255) return 0; + ya = (uint8_t)(hit_y < 0 ? 0 : hit_y); + yb = (uint8_t)(y1 > 255 ? 255 : y1); + c0 = (int8_t)((hit_x < 0 ? 0 : hit_x) >> 5); + c1 = (int8_t)((x1 > 319 ? 319 : x1) >> 5); + for (c = c0; c <= c1; c++) + if (ya <= pop_cd_ymax[hit_p][c] && yb >= pop_cd_ymin[hit_p][c]) return 1; + return 0; +} + +uint8_t pop_cd_hit_slot(uint8_t who, uint8_t p) +{ + const pop_cdraw_t *s = &pop_cd[who]; + if (!(pop_cd_dirty & (1 << p))) return 0; + hit_p = p; + hit_x = s->x[p]; hit_y = s->y[p] + POP_YOFF; + hit_w = s->w[p]; hit_h = s->h[p]; + if (hit_rect()) return 1; + if (!s->ovalid[p]) return 0; + hit_x = s->ox[p]; hit_y = s->oy[p] + POP_YOFF; + hit_w = s->ow[p]; hit_h = s->oh[p]; + return hit_rect(); +} + uint8_t pop_cd_hit(uint8_t p, int x0, int y0, int x1, int y1) { int8_t c0, c1, c;