From d1bc97c589518beaf3da01953e9d13c97c198cf3 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Mon, 20 Jul 2026 21:26:21 +0300 Subject: [PATCH] =?UTF-8?q?roomtest:=20=D0=BE=D0=B1=D0=BB=D0=BE=D0=BC?= =?UTF-8?q?=D0=BA=D0=B8=20=D1=83=D0=BF=D0=B0=D0=B2=D1=88=D0=B5=D0=B3=D0=BE?= =?UTF-8?q?=20loose=20=D0=B2=20=D0=BA=D0=BE=D0=BC=D0=BD=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=20=D1=81=D0=BD=D0=B8=D0=B7=D1=83=20(debris)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loose-пол room1(2,6) при падении даёт кусок, который в оригинале улетает в комнату снизу (links.down) и приземляется на первый floor, превращая его в debris (порт move_loose/loose_land seg007). Для room1(2,6): room2(0,6)=empty пролёт → room2(1,6)=floor приземление → debris. Минимальная реализация (без анимации полёта куска, только персистентный результат — мини-версия P0 из docs/gates_spikes_plan.md): - pop_map: сигнал pop_loose_fell (tilepos+1 упавшего loose). - pop_level: pop_room_col_landing(room,col) — ряд первого floor сверху вниз (пустые ряды пролетаются), иначе -1. - roomtest: при pop_loose_fell вычисляет debris-приземление в комнате снизу → персистентный override (dbr_room/dbr_pos, живёт между переходами) → enter_room применяет поверх загруженных тайлов (floor→debris 0x0E). Проверено в MAME: провал loose room1(2,6) → debris в room2(1,6), сохраняется при повторных входах. Co-Authored-By: Claude Opus 4.8 --- applications/PoP/roomtest/pop_level.c | 17 +++++++++++++++ applications/PoP/roomtest/pop_level.h | 5 +++++ applications/PoP/roomtest/pop_map.c | 2 ++ applications/PoP/roomtest/pop_map.h | 4 ++++ applications/PoP/roomtest/roomtest.c | 31 ++++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/applications/PoP/roomtest/pop_level.c b/applications/PoP/roomtest/pop_level.c index 4dde111..9b30372 100644 --- a/applications/PoP/roomtest/pop_level.c +++ b/applications/PoP/roomtest/pop_level.c @@ -137,6 +137,23 @@ int pop_room_load(uint8_t room, uint8_t *fg, uint8_t *bg, return 0; } +int8_t pop_room_col_landing(uint8_t room, uint8_t col) +{ + const uint8_t *rf; + int8_t row, res = -1; + if (!lvl_ok || room < 1 || room > 24 || col > 9) return -1; + gfx_w0_map(lvl_page); + rf = room_fg_ptr(room); + for (row = 0; row < 3; row++) { /* кусок пролетает пустые ряды */ + uint8_t t = (uint8_t)(rf[row * 10 + col] & 0x1F); + if (t == 0) continue; /* empty — дальше вниз */ + if (t == 1) res = row; /* floor — приземление → debris */ + break; /* первый не-пустой тайл — стоп */ + } + gfx_w0_unmap(); + return res; +} + uint8_t pop_room_link(uint8_t room, uint8_t side) { uint8_t v; diff --git a/applications/PoP/roomtest/pop_level.h b/applications/PoP/roomtest/pop_level.h index ed581a4..2af1aea 100644 --- a/applications/PoP/roomtest/pop_level.h +++ b/applications/PoP/roomtest/pop_level.h @@ -41,6 +41,11 @@ int pop_room_load(uint8_t room, uint8_t *fg, uint8_t *bg, * 0, если стороны нет. Для переходов между комнатами (L2/L3). */ uint8_t pop_room_link(uint8_t room, uint8_t side); +/* Ряд приземления падающего loose-куска в колонке col комнаты room: первый + * НЕ-пустой тайл сверху вниз; возвращает его ряд, если это floor (→ debris), + * иначе -1 (пролетел/крушение о стену). */ +int8_t pop_room_col_landing(uint8_t room, uint8_t col); + /* Стартовая позиция уровня (блок @2112): комната / поза / направление. */ uint8_t pop_level_start_room(void); uint8_t pop_level_start_pos(void); diff --git a/applications/PoP/roomtest/pop_map.c b/applications/PoP/roomtest/pop_map.c index b1c3575..37ecae8 100644 --- a/applications/PoP/roomtest/pop_map.c +++ b/applications/PoP/roomtest/pop_map.c @@ -86,6 +86,7 @@ static int8_t g_infrontx; /* колонка «перед персонаже /* ---- Карта комнаты ------------------------------------------------- */ uint8_t pop_fell_out; /* 1 = Kid пересёк НИЖНЮЮ границу (см. pop_map.h) */ uint8_t pop_leave_dir; /* уход вбок/вверх: 0=нет; 1=left,2=right,3=up (side+1) */ +uint8_t pop_loose_fell; /* 0=нет; иначе tilepos+1 упавшего loose (кусок улетел вниз) */ static uint8_t *g_fg; /* fg[30], row*10+col (МУТАБЕЛЬНАЯ — loose→empty) */ static uint8_t g_curr_tile; /* = curr_tile2: тайл последнего get_tile */ static uint8_t g_obj_xl; /* позиция внутри тайла (get_tile_div_mod) */ @@ -763,6 +764,7 @@ void pop_loose_tick(void) pop_loose_bake_empty(pos / 10, pos % 10); /* запечь пусто на ТЕКУЩЕЙ странице сразу */ loose_bake[pos] = 1; /* + вторая страница следующим кадром */ pop_loose_mob_spawn(pos / 10, pos % 10); /* отрыв падающего куска (L4) */ + pop_loose_fell = (uint8_t)(pos + 1); /* сигнал приложению: кусок улетел */ continue; } pop_loose_shake_draw(pos / 10, pos % 10); /* дрожащий кадр */ diff --git a/applications/PoP/roomtest/pop_map.h b/applications/PoP/roomtest/pop_map.h index 693f56f..e19c8f9 100644 --- a/applications/PoP/roomtest/pop_map.h +++ b/applications/PoP/roomtest/pop_map.h @@ -39,6 +39,10 @@ extern uint8_t pop_loose_modif[30]; void pop_loose_tick(void); void pop_loose_reset(void); /* сброс loose-состояния при смене комнаты */ +/* Установлен в tilepos+1 в кадре, когда loose-пол упал (кусок улетел ВНИЗ). + * Приложение: определить debris-приземление в комнате снизу. Снять (=0). */ +extern uint8_t pop_loose_fell; + /* check_knock (seg003): по флагу knock (play_seq) тряхнуть loose-полы ряда * приземления/удара. Зовётся из pop_phys_tick. */ void pop_check_knock(void); diff --git a/applications/PoP/roomtest/roomtest.c b/applications/PoP/roomtest/roomtest.c index 96a8deb..64b62e0 100644 --- a/applications/PoP/roomtest/roomtest.c +++ b/applications/PoP/roomtest/roomtest.c @@ -27,13 +27,33 @@ static uint8_t room_fg[30], room_bg[30]; static uint8_t lcol_fg[3], lcol_bg[3], rcol_fg[3], rcol_bg[3], below_fg[10]; static uint8_t cur_room; /* номер текущей комнаты (для переходов) */ +/* Персистентные debris-переопределения (упавший loose-кусок приземлился в + * комнате снизу → floor стал debris). Минимальный per-room override: живёт + * между переходами, применяется в enter_room поверх загруженных тайлов. + * (Полноценное per-room modifier-состояние — в docs/gates_spikes_plan.md, P0.) */ +#define TILE_DEBRIS 0x0E +#define DEBRIS_OVR_MAX 4 +static uint8_t dbr_room[DEBRIS_OVR_MAX], dbr_pos[DEBRIS_OVR_MAX], dbr_cnt; + +static void add_debris_override(uint8_t room, uint8_t pos) +{ + uint8_t i; + for (i = 0; i < dbr_cnt; i++) + if (dbr_room[i] == room && dbr_pos[i] == pos) return; /* уже есть */ + if (dbr_cnt < DEBRIS_OVR_MAX) { + dbr_room[dbr_cnt] = room; dbr_pos[dbr_cnt] = pos; dbr_cnt++; + } +} + /* Загрузить комнату room в рабочие массивы и отрисовать её фон в ОБЕ * страницы дабл-буфера (у каждой своя видео-ОЗУ/теневая копия). Оставляет * активной страницу 1 — вызывающий восстанавливает нужную draw-страницу. */ static void enter_room(uint8_t room) { - uint8_t pg; + uint8_t pg, i; pop_room_load(room, room_fg, room_bg, lcol_fg, lcol_bg, rcol_fg, rcol_bg, below_fg); + for (i = 0; i < dbr_cnt; i++) /* применить debris-переопределения */ + if (dbr_room[i] == room) room_fg[dbr_pos[i]] = TILE_DEBRIS; pop_map_set(room_fg); pop_map_set_edges(pop_room_link(room, 0), pop_room_link(room, 1), pop_room_link(room, 2), pop_room_link(room, 3), @@ -151,6 +171,15 @@ int main(void) } pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */ /* — ДО Kid, чтобы Kid всегда был поверх плиты) */ + if (pop_loose_fell) { /* упавший кусок → debris в комнате снизу */ + uint8_t fcol = (uint8_t)((pop_loose_fell - 1) % 10); + uint8_t down = pop_room_link(cur_room, LINK_DOWN); + pop_loose_fell = 0; + if (down) { + int8_t lrow = pop_room_col_landing(down, fcol); + if (lrow >= 0) add_debris_override(down, (uint8_t)(lrow * 10 + fcol)); + } + } kid_draw(); /* нарисовать новый кадр (детект выхода за поле) */ pop_fore_over_kid(kid_fp_obj_x(), kid_fp_obj_y(), kid_fp_width(), kid_fp_height(),