Падающие плиты: передний слой по пометкам, честные спрайты, замер кадра

Слой fore переведён на пометки ОБЪЕКТОВ вместо окна вокруг персонажа —
порт set_redraw_fore/redraw_frames_fore (seg007:0550, seg008:214):
pop_set_redraw_fore + pop_fore_needed + pop_fore_tile_b, пометки ставит
падающий кусок вокруг себя (draw_mob, seg007:1147).

Ключевая правка: пометки соседа считаются в ПРОХОДЕ ОТРИСОВКИ, а не в
тике.  Стояли в цикле тика — то есть по позиции ДО mob_tick_one, а кусок
рисовался уже по новой; пока он летит внутри ряда, тайлы совпадают, но в
кадр пересечения границы пометка указывала на прежний тайл и колонна кусок
не перекрывала.  Ровно один кадр, как и наблюдалось.

Спрайты падающего куска: obj_id = 10 (add_mob_to_objtable, seg007:1170),
части берутся по этому индексу — 70/74/72, а не 41/43/42 (плита В ПОКОЕ).
Отсюда была «цельная ровная плита» вместо двух половин со сдвигом.

Убрана подпорка «перерисовать соседний тайл поверх куска»: тащила на плиту
чужой узор и окно и стоила по полной отрисовке тайла на кусок за кадр.
Коридор heal сужен по высоте 32 -> 24 (реальный след спрайта 16 px).
gfx_set_bank вынесен из потайлового цикла в обрамление прохода.

Выяснено и зафиксировано: clip.right = 40 в add_mob_to_objtable — МЁРТВЫЕ
данные.  set_clip_rect вызывается под chtab_flip_clip[chtab_id], а для
окружения флаг равен нулю — оригинал падающие куски не клипует вовсе.
Портировать нечего; две попытки это сделать были ошибочны.

Замер кадра (маркеры m1..m4, оставлены временно для проверки правок):
покой 196 614 тактов (15,2 % кадра при периоде 1 290 000), во время
падения гряды среднее 222 667, пик 1 428 990 — то есть 111 % кадра,
шесть кадров подряд за пределом.  Логика неизменна (88 020), растут фон
(до 887 376) и спрайты (до 660 792).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 21:38:59 +03:00
parent c31930dcad
commit 50e4eda2ad
8 changed files with 123 additions and 1 deletions
+37 -1
View File
@@ -21,6 +21,7 @@
#include "pop_tile.h" /* общие листья слоя фона (резидент): блит, тайлы, таблица */
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
#include "pop_state.h"
#include "pop_redraw.h" /* пометки тайлов: сосед падающего куска (draw_mob) */
#include "pop_geom.h"
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев */
@@ -1165,6 +1166,30 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
*
* Порядок «кусок против Кида» здесь ни при чём — его решает defer выше, и там
* действует обычное правило. */
/* Пометки СОСЕДА СПРАВА — порт draw_mob (seg007:1147). Оригинал каждый
* кадр помечает тайл col+1 в ряду куска сразу двумя пометками:
*
* set_redraw2(tilepos, 1); // фон соседа — рисуется ДО куска
* set_redraw_fore(tilepos, 1); // его передние части — ПОСЛЕ куска
*
* и повторяет их для второго ряда, если кусок висит на границе (ypos-18).
* Так правая часть куска (спрайт 72 лежит в столбце col+1) прячется за
* передней гранью соседнего пола, а передние части чужого тайла — колонна,
* например, — ложатся поверх куска.
*
* Здесь была подпорка: целый соседний тайл рисовался ПОВЕРХ куска прямо в
* mob_render. Она тащила на плиту чужой узор и окно и стоила по полной
* отрисовке тайла на кусок за кадр (MOB-CLIP-RIGHT). */
static void mob_mark_neighbour(const mob_t *m)
{
int8_t r = pop_y_to_row((int16_t)m->y);
int8_t rt = pop_y_to_row((int16_t)(m->y - 18));
int8_t c = (int8_t)(m->col + 1);
if (c > 9) return;
if (r >= 0 && r <= 2) pop_set_redraw_fore((uint8_t)(r * 10 + c));
if (rt != r && rt >= 0 && rt <= 2) pop_set_redraw_fore((uint8_t)(rt * 10 + c));
}
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
{
uint8_t order[MOB_MAX], n = 0, i, j;
@@ -1177,7 +1202,18 @@ static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
order[j] = i;
n++;
}
for (i = 0; i < n; i++) mob_render(&mobs[order[i]], pg);
for (i = 0; i < n; i++) {
/* Пометки соседа ставятся ЗДЕСЬ, а не в тике: у оригинала draw_mob
* (seg007:1147) считает ряд от той же координаты, по которой кусок
* рисуется. Стояли они в цикле тика — то есть по позиции ДО
* mob_tick_one, а рисовался кусок уже по новой. Пока он летит
* внутри ряда, старый и новый тайл совпадают и разницы не видно; но
* в кадр пересечения границы пометка указывала на прежний тайл, и
* передняя часть колонны кусок не перекрывала — ровно ОДИН кадр,
* как и наблюдалось (прогон 2026-08-13, комната 23, колонка 8). */
mob_mark_neighbour(&mobs[order[i]]);
mob_render(&mobs[order[i]], pg);
}
}
void pop_loose_mob_tick(void) __banked