From 7ae691b070660e201d6f3017aaa70e81672c0a8e Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Mon, 17 Aug 2026 17:17:04 +0300 Subject: [PATCH] =?UTF-8?q?Fore=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BB=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D0=B2=D0=B5=D1=80=D1=85=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=B4=D0=B0=D1=8E=D1=89=D0=B5=D0=B9=20=D0=BF=D0=BB=D0=B8=D1=82?= =?UTF-8?q?=D1=8B:=20=D0=B2=20=D1=80=D0=B0=D0=B7=D0=B1=D0=BE=D1=80=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BC=D0=B5=D1=82=D0=BE=D0=BA=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=B1=D1=8B=D0=BB=D0=BE=20=D1=80=D1=8F=D0=B4=D0=B0=20-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Найдено пользователем (2026-08-17, уровень 1 комната 6): падающая плита (-1,5) перекрывает собой кромку потолка (-1,6), чего физически быть не может. Дыра архитектурная: pop_fore_needed обходил только ряды 0..2, ряда -1 в переднем слое не было вовсе. Сверено с оригиналом. redraw_needed_tiles (seg008:1B06) обходит ряды 2,1,0, а ПОТОМ отдельным проходом ряд 2 комнаты сверху (redraw_needed_above), и его draw_tile_fore кладёт куски в FOREtable. Падающая плита идёт в MIDtable (draw_mobs). draw_tables рисует back -> mid -> fore (seg008:1373), поэтому у оригинала кромка потолка оказывается поверх плиты сама собой. Порт: - pop_fore_needed: проход по ряду -1 добавлен и идёт ПОСЛЕДНИМ, как в оригинале. Свой набор пометок (rdfa/rdfa_pending) — как и у самих перерисовок ряда -1 (rda_*), это отдельный проход, а не 11-я колонка; - новый лист pop_ceil_fore_tile_b (pop_bg.c) — тот же redraw_needed_above, что уже рисовался над персонажем (ceil_over_kid_tile), плюс окно клипа ровно на полосу столбца и ov_mark (полоса идёт банком без тени, на второй странице её восстановит pop_fore_heal); - mob_mark_neighbour помечает ряд -1, пока кусок достаёт до кромки. Кромка живёт в трёх верхних строках поля (dby = 2 при клипе по POP_YOFF), спрайт куска занимает mob_y-16 .. mob_y, отсюда условие mob_y <= 18 — три кадра после отрыва (y = 2, 5, 11 при ускорении 3). Помечаются ОБА столбца, которые кусок накрывает по x (mob_x .. mob_x+62 = col и col+1); именно поэтому страдал сосед. По бюджету работа появляется только в эти три кадра на кусок и попадает в циановую фазу, где сейчас запас (270 тыс. из 400 тыс.). Замер на ур.13 — следующим шагом. 8 наборов tests-host зелёные. Co-Authored-By: Claude Opus 5 --- applications/PoP/roomtest/pop_bg.c | 25 +++++++++++++++++++++++ applications/PoP/roomtest/pop_bg.h | 5 +++++ applications/PoP/roomtest/pop_redraw.c | 28 +++++++++++++++++++++++++- applications/PoP/roomtest/pop_redraw.h | 4 ++++ applications/PoP/roomtest/pop_room.c | 17 ++++++++++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/applications/PoP/roomtest/pop_bg.c b/applications/PoP/roomtest/pop_bg.c index 3b0b1af..22d37c0 100644 --- a/applications/PoP/roomtest/pop_bg.c +++ b/applications/PoP/roomtest/pop_bg.c @@ -901,6 +901,31 @@ void pop_fore_tile_b(int row, int col) __banked pop_t_fclip_on = saved; } +/* Передний слой полосы кладки У ПОТОЛКА (ряд −1) для ОДНОГО столбца — вход для + * прохода по пометкам (pop_fore_needed, ряд −1 идёт там последним). + * + * Тот же redraw_needed_above (seg008:0221), что и над персонажем: обход ряда −1 + * стоит в redraw_needed_tiles ПОСЛЕДНИМ, а его draw_tile_fore кладёт куски в + * foretable, то есть поверх midtable (там лежат падающие плиты) и поверх + * объектов. Без этого кусок, пролетающий у потолка, накрывает собой кромку + * потолка — физически невозможная картинка (найдено пользователем 2026-08-17, + * уровень 1 комната 6: плита (−1,5) перекрывала потолок (−1,6)). + * + * Окно — ровно полоса этого столбца: передние куски потолка живут в трёх + * верхних строках (dby = 2 при клипе по POP_YOFF), рисовать шире незачем. + * ov_mark — как у персонажа: полоса рисуется банком без тени, и на второй + * странице её надо будет восстановить (pop_fore_heal). */ +void pop_ceil_fore_tile_b(int col) __banked +{ + int x = POP_COL_XH[col] * 8; + ov_mark(x, 0, 64, CEIL_BAND_H); + pop_t_clip_top = POP_YOFF; + pop_t_win_set(x, POP_YOFF, 64, CEIL_BAND_H); + ceil_over_kid_tile(col); + pop_t_win_clear(); + pop_t_clip_top = 0; +} + /* Банк на ВЕСЬ проход пометок, а не на каждый тайл: помеченных тайлов за * кадр бывает больше десятка, и две смены банка на каждый — заметная доля * прохода, который сам по себе дешёвый. */ diff --git a/applications/PoP/roomtest/pop_bg.h b/applications/PoP/roomtest/pop_bg.h index 1f417c2..f962a22 100644 --- a/applications/PoP/roomtest/pop_bg.h +++ b/applications/PoP/roomtest/pop_bg.h @@ -173,6 +173,11 @@ void pop_loose_mob_reset(void) __banked; /* убрать все куски (С * первый же тайл с тем же номером получил бы копию вместо честной запечки. */ void pop_bake_forget(void) __banked; +/* Передний слой полосы кладки у потолка (ряд −1) для одного столбца — зовёт + * проход по пометкам, ряд −1 в нём последний (порт redraw_needed_above + + * порядка redraw_needed_tiles, seg008:1B06). */ +void pop_ceil_fore_tile_b(int col) __banked; + /* Смена комнаты: куски продолжают падать в СВОИХ комнатах (do_mobs крутит * mobs[] независимо от drawn_room), сбрасывается только heal-история. */ void pop_loose_mob_room_changed(void) __banked; diff --git a/applications/PoP/roomtest/pop_redraw.c b/applications/PoP/roomtest/pop_redraw.c index 9f7a579..5b23a3b 100644 --- a/applications/PoP/roomtest/pop_redraw.c +++ b/applications/PoP/roomtest/pop_redraw.c @@ -23,6 +23,13 @@ static uint8_t rd_pending; * страницам дабл-буфера (запекают фон), а эти транзиентны. */ static uint8_t rdf[NTILES]; static uint8_t rdf_pending; +/* Передний слой РЯДА −1 (полоса кладки у потолка). Отдельным набором, как и + * сами перерисовки ряда −1 (rda_*): у оригинала это вообще другой проход — + * redraw_needed_tiles сначала обходит ряды 2,1,0, а ПОТОМ ряд 2 комнаты сверху + * (seg008:1B06), и его draw_tile_fore кладёт куски в foretable, то есть поверх + * midtable, где лежат падающие плиты, и поверх объектов. */ +static uint8_t rdfa[NCOLS]; +static uint8_t rdfa_pending; void pop_redraw_reset(void) __banked { @@ -31,8 +38,10 @@ void pop_redraw_reset(void) __banked for (i = 0; i < NCOLS; i++) { rda_kind[i] = 0; rda_cnt[i] = 0; } rd_pending = 0; for (i = 0; i < NTILES; i++) rdf[i] = 0; + for (i = 0; i < NCOLS; i++) rdfa[i] = 0; pop_fore_pass_end(); rdf_pending = 0; + rdfa_pending = 0; } void pop_set_redraw_fore(uint8_t tilepos) __banked @@ -42,19 +51,36 @@ void pop_set_redraw_fore(uint8_t tilepos) __banked rdf[tilepos] = 1; } +/* То же для полосы кладки У ПОТОЛКА (ряд −1). Ставит падающий кусок, когда + * его спрайт достаёт до кромки потолка: иначе кусок накрывает эту кромку + * собой, чего быть не может (найдено пользователем 2026-08-17, ур.1 к.6 — + * плита (−1,5) перекрывала потолок (−1,6)). */ +void pop_set_redraw_fore_above(uint8_t col) __banked +{ + if (col >= NCOLS) return; + if (!rdfa[col]) rdfa_pending++; + rdfa[col] = 1; +} + /* Разбор пометок переднего слоя: тайлы обходятся в том же порядке, что и * фон, и рисуются ПОСЛЕ всех объектов кадра — как foretable у оригинала * (draw_tables, seg008:1373: back -> mid -> fore). */ void pop_fore_needed(void) __banked { uint8_t i, row = 0, col = 0; - if (!rdf_pending) return; + if (!rdf_pending && !rdfa_pending) return; pop_fore_pass_begin(); for (i = 0; i < NTILES; i++) { if (rdf[i]) { rdf[i] = 0; pop_fore_tile_b(row, col); } if (++col == 10) { col = 0; row++; } } rdf_pending = 0; + /* Ряд −1 — ПОСЛЕДНИМ, как в redraw_needed_tiles (seg008:1B06). */ + if (rdfa_pending) { + for (i = 0; i < NCOLS; i++) + if (rdfa[i]) { rdfa[i] = 0; pop_ceil_fore_tile_b(i); } + rdfa_pending = 0; + } } void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages) __banked diff --git a/applications/PoP/roomtest/pop_redraw.h b/applications/PoP/roomtest/pop_redraw.h index a53a459..11a47a5 100644 --- a/applications/PoP/roomtest/pop_redraw.h +++ b/applications/PoP/roomtest/pop_redraw.h @@ -50,6 +50,10 @@ void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages) __banked; * * Разбор (pop_fore_needed) звать ПОСЛЕ отрисовки всех объектов кадра. */ void pop_set_redraw_fore(uint8_t tilepos) __banked; + +/* Пометить передний слой полосы у потолка (ряд −1), столбец col. Ставит + * падающий кусок, достающий до кромки потолка. */ +void pop_set_redraw_fore_above(uint8_t col) __banked; void pop_fore_needed(void) __banked; void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages) __banked; diff --git a/applications/PoP/roomtest/pop_room.c b/applications/PoP/roomtest/pop_room.c index efc7ee3..f0c021a 100644 --- a/applications/PoP/roomtest/pop_room.c +++ b/applications/PoP/roomtest/pop_room.c @@ -1449,6 +1449,23 @@ 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); + /* ПОЛОСА У ПОТОЛКА (ряд −1). Её передние куски (нижняя кромка потолка и + * кадр плиты-потолка) живут в трёх верхних строках поля — dby = 2 при + * клипе по POP_YOFF, — а спрайт куска занимает mob_y−16 .. mob_y. Значит + * кусок закрывает кромку, пока mob_y − 16 <= 2, то есть mob_y <= 18: три + * кадра после отрыва (y = 2, 5, 11 при ускорении 3). Помечаем ОБА + * столбца, которые кусок накрывает по x (mob_x .. mob_x+62 — это col и + * col+1). + * + * Без этого кусок оказывался ПОВЕРХ кромки потолка соседней колонки — + * физически невозможно (найдено пользователем 2026-08-17, ур.1 к.6: + * плита (−1,5) перекрывала потолок (−1,6)). В оригинале порядок даёт + * сама структура таблиц: кусок идёт в midtable (draw_mobs), а полоса + * потолка — в foretable, и та рисуется позже (draw_tables, seg008:1373). */ + if (m->y <= 18) { + pop_set_redraw_fore_above((uint8_t)m->col); + if (m->col + 1 <= 9) pop_set_redraw_fore_above((uint8_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));