From 517d225091686f45bce32c9f65167176d3715af5 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 29 Jul 2026 14:23:10 +0300 Subject: [PATCH] =?UTF-8?q?PoP=20roomtest:=20=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=BF=D0=BE=D1=80=D1=82=20bumped=20(seg004)=20?= =?UTF-8?q?=E2=80=94=20=D0=BF=D1=80=D0=B8=D0=B6=D0=B0=D1=82=D0=B8=D0=B5=20?= =?UTF-8?q?Y=20=D0=BA=20=D0=BF=D0=BE=D0=BB=D1=83=20+=20hardbump?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Комната 5, прыжок в решётку: Kid оставался стоять на 6 пикселей выше пола и без приземления-приседания. Шесть пикселей — это dy(-6) кадра frame_25_standing_jump_10: удар обрывал standjump ровно между кадрами 25 и 26, парный dy(+6) не выполнялся. От оригинального bumped() у нас был портирован только хвост (выровнять X к грани + seq_47_bump). Добавлены недостающие ветки: - bumped() — исход удара выбирается по тайлу, НА КОТОРОМ персонаж оказался после отжатия (сквозь стену/верх двери это соседняя клетка, для ворот/зеркала — сама клетка); - bumped_floor — прижимает Y к y_land, ветка fall_y>=22 (только отжать на 5) и выбор сиквенса по кадру: 24/25/40..42/102..106 -> seq_46_hardbump (отскок с приседанием), иначе 47; - bumped_fall — удар выше пола на 15+ px (беззнаковое сравнение оригинала) или не над полом: seq_45, в свободном падении — только гашение fall_x. Гард «уже в отскоке — не рестартить» (наш, от edge-триггера коллизий) перенесён внутрь bumped_floor: выравнивание X/Y идёт всегда, рестарта анимации нет. Проверено в MAME. Co-Authored-By: Claude Opus 5 --- applications/PoP/roomtest/bug_list.md | 2 +- applications/PoP/roomtest/pop_map.c | 78 ++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/applications/PoP/roomtest/bug_list.md b/applications/PoP/roomtest/bug_list.md index 97e17ac..295569a 100644 --- a/applications/PoP/roomtest/bug_list.md +++ b/applications/PoP/roomtest/bug_list.md @@ -431,7 +431,7 @@ Kid ставится на первый пол, `pop_trob_reset()` возвращ | 2 | | | | 3 | | | | 4 | | | -| 5 | | | +| 5 | пофикшено | прыжок в решётку: Kid оставался стоять на 6 px ВЫШЕ пола и без приземления-приседания — от `bumped()` (seg004) был портирован только хвост (`seq_47`), не хватало `bumped_floor` (прижатие Y к полу + `seq_46_hardbump` на кадрах прыжка 24/25/40..42/102..106) и `bumped_fall` | | 6 | | | | 7 | | | | 8 | | | diff --git a/applications/PoP/roomtest/pop_map.c b/applications/PoP/roomtest/pop_map.c index 053f259..ef46da3 100644 --- a/applications/PoP/roomtest/pop_map.c +++ b/applications/PoP/roomtest/pop_map.c @@ -50,6 +50,8 @@ #define SEQ_19_FALL 19 /* stepfall2 (run frames 9/13) */ #define SEQ_20_MEDIUM_LAND 20 #define SEQ_21_FALL_RUNJUMP 21 +#define SEQ_45_BUMPFALL 45 /* удар В ВОЗДУХЕ: отскок и падение */ +#define SEQ_46_HARDBUMP 46 /* удар после прыжка: отскок + ПРИСЕДАНИЕ */ #define SEQ_47_BUMP 47 /* удар в стену: dx(-4) отскок + 50-52 + stand */ /* K4 — зацеп/вис/подтягивание/спуск */ #define SEQ_8_GRAB_STRAIGHT 8 /* прыжок вверх и зацеп (прямо) */ @@ -762,11 +764,58 @@ static void check_action(void) } } +/* bumped_fall (seg004:0522): удар, когда под персонажем НЕ пол ИЛИ он высоко + * над полом — отскок назад и падение (seq_45). В свободном падении сиквенс + * не меняем, только гасим горизонтальную составляющую. */ +static void bumped_fall(void) +{ + Kid.x = (uint8_t)char_dx_forward(-4); + if (Kid.action == ACT_FREEFALL) { + Kid.fall_x = 0; + } else { + kid_set_seq(SEQ_45_BUMPFALL); /* (TODO: bumped_sound) */ + play_seq(); + } +} + +/* bumped_floor (seg004:053B): удар о стену, когда под персонажем ПОЛ. + * Портируется целиком — раньше у нас был только хвост (seq_47), из-за чего + * терялись ДВЕ вещи: прижатие Y к полу и «жёсткий» вариант удара. Симптом + * (комната 5, прыжок в решётку): standjump бампится на кадре 25 — том самом, + * где сиквенс уже сделал dy(−6), а парного dy(+6) ещё не было, — и Kid + * оставался стоять на 6 пикселей ВЫШЕ пола, без приземления-приседания. */ +static void bumped_floor(void) +{ + uint8_t frame; + /* Оригинал сравнивает БЕЗЗНАКОВО: если персонаж НИЖЕ уровня пола, + * разность заворачивается в большое число и тоже даёт «падать». */ + if ((uint16_t)(y_land[Kid.curr_row + 1] - (int16_t)Kid.y) >= 15) { + bumped_fall(); /* высоко над полом — в воздухе */ + return; + } + Kid.y = (uint8_t)y_land[Kid.curr_row + 1]; /* ПРИЖАТЬ к полу */ + if (Kid.fall_y >= 22) { /* влетел быстро — только отжать */ + Kid.x = (uint8_t)char_dx_forward(-5); + return; + } + Kid.fall_y = 0; + if (Kid.action == ACT_BUMPED) return; /* уже в отскоке — не рестартить */ + frame = Kid.frame; + /* Кадры прыжков и начала падения — «жёсткий» удар с приседанием + * (24/25 = standjump, 40..42 = runjump, 102..106 = start_fall). */ + if (frame == 24 || frame == 25 || (frame >= 40 && frame < 43) || + (frame >= 102 && frame < 107)) + kid_set_seq(SEQ_46_HARDBUMP); + else + kid_set_seq(SEQ_47_BUMP); /* (TODO: bumped_sound) */ + play_seq(); +} + /* check_bumped (seg004): если передний край ЗАШЁЛ за грань стены — выровнять - * к грани И проиграть отскок seq_47_bump (dx−4 назад + кадры 50-52 + stand), - * как в оригинале (bumped_floor). Это даёт «шаг назад со звуком» при беге/ - * шаге в стену вместо падения. Уже в отскоке (action bumped) — только - * выравниваем, без рестарта. В падении/висе не трогаем. */ + * к грани и отдать исход в bumped_floor/bumped_fall (порт bumped, seg004). + * Это даёт «шаг назад со звуком» при беге/шаге в стену вместо падения. Уже + * в отскоке (action bumped) — только выравниваем, без рестарта сиквенса. + * В падении/висе не трогаем. */ static void check_bumped(void) { uint8_t t, wt; int8_t tcol; int d; @@ -842,10 +891,23 @@ static void check_bumped(void) if (d >= 0) return; /* ещё не зашёл за грань */ Kid.x = (uint8_t)char_dx_forward((int8_t)d); /* край -> грань */ determine_col(); - if (Kid.action == ACT_BUMPED) return; /* уже в отскоке — не рестартить */ - Kid.fall_y = 0; - kid_set_seq(SEQ_47_BUMP); /* отскок (TODO: bumped_sound) */ - play_seq(); + /* Хвост bumped (seg004:04E4): чем КОНЧИТСЯ удар, решает тайл, на котором + * персонаж оказался после отжатия от грани. Сквозь стену/верх двери он + * стоит на СОСЕДНЕЙ клетке (в сторону толчка), для прочих препятствий + * (ворота, зеркало, кусаки) — на клетке самого препятствия (у ворот пол + * есть, поэтому tile_is_floor их считает полом). */ + { + uint8_t ct = t; + if (Kid.direction < 0) { /* смотрит влево => толчок ВПРАВО */ + if (ct == TILE_DOORTOP || ct == TILE_DOORTOP_FLOOR || ct == TILE_WALL) + ct = get_tile((int8_t)(tcol + 1), Kid.curr_row); + } else { /* смотрит вправо => толчок ВЛЕВО */ + if (ct == TILE_WALL) + ct = get_tile((int8_t)(tcol - 1), Kid.curr_row); + } + if (tile_is_floor(ct)) bumped_floor(); + else bumped_fall(); + } determine_col(); }