From 4e12aa50d1010e39d93dbdc199b9c8208895b68c Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Mon, 31 Aug 2026 20:52:44 +0300 Subject: [PATCH] =?UTF-8?q?SprPoP:=20=D0=BF=D0=B0=D0=B4=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=81=D0=BA=D0=B2=D0=BE=D0=B7=D1=8C=20=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BD=D1=83=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BF=D1=80=D0=BE=D1=85=D0=BE=D0=B4=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Портировано опциональное исправление SDLPoP (fix_glide_through_wall, seg005 в do_fall). В ванили персонаж, падающий после разворота в беге, может оказаться внутри кладки и лететь «в стене» — баг оригинала, воспроизведённый пользователем в игре и затем на host-тесте. Решением 2026-08-31 фикс взят в ТЕКУЩИЙ билд: играбельность важнее буквальности. Реализация вынесена отдельной функцией glide_through_wall_guard() в pop_map.c намеренно — при разделении VANILLA/ENHANCED это готовая точка отвязки, достаточно не звать её в ванильном режиме. ПРОВЕРКА. Набор t_wall был заранее написан так, чтобы сторожить ЧИСЛО заходов в кладку: до фикса их было ровно два из четырнадцати стартовых позиций, после — ноль. Остальные 15 наборов (в том числе phys с 1733 проверками и grab) остались зелёными. Живая проверка в MAME пользователем: корректно. Ожидание в тесте обновлено ОСОЗНАННО, прежнее число сохранено рядом отдельной константой с пометкой «сколько было до фикса»: оно измерено, и понадобится, когда появится режим VANILLA — там ожидание станет зависеть от режима. ЦЕНА: +57 байт в банке 3 (свободно 3043), резидент и куча не изменились. По скорости попадание только на кадры падения: пересчёт колонки — одно деление, дистанция до кромки считается лишь если персонаж действительно внутри кладки. Документы: в аудите находка 21 переведена в «портировано» с сохранением исходного разбора; в vanilla_vs_bugfixed статус фикса стал ВЗЯТ, сводка пересчитана (5 взято, 32 кандидата в ENHANCED). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY --- applications/SprPoP/docs/sdlpop_audit.md | 14 +++++++- .../SprPoP/docs/vanilla_vs_bugfixed.md | 7 ++-- applications/SprPoP/src/pop_map.c | 35 +++++++++++++++++++ applications/SprPoP/tests/host/t_wall.c | 31 ++++++++-------- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/applications/SprPoP/docs/sdlpop_audit.md b/applications/SprPoP/docs/sdlpop_audit.md index ed078ee..2b047fc 100644 --- a/applications/SprPoP/docs/sdlpop_audit.md +++ b/applications/SprPoP/docs/sdlpop_audit.md @@ -402,7 +402,19 @@ рано, Кид не долетел, врезался в стену и начал падать — но по X он оказался ВНУТРИ стены и падал частично в ней. -### 21. Фикс «скольжения сквозь стену» не портирован — ранг **Г** (соответствие ванили) +### 21. Фикс «скольжения сквозь стену» — ПОРТИРОВАН 2026-08-31 + +> Решением пользователя исправление взято в ТЕКУЩИЙ билд: играбельность +> важнее буквальности. Реализация — `glide_through_wall_guard()` в +> `pop_map.c`, вызывается из `do_fall` в ветке «ещё летим». Цена: +57 +> байт в банке 3, резидент и куча не изменились. +> +> Подтверждено host-тестом: в наборе `t_wall` число заходов в кладку +> упало с двух до нуля, остальные 15 наборов остались зелёными. +> +> Ниже — исходный разбор, по которому принималось решение. + +### 21a. Исходный разбор: было соответствие ванили — ранг **Г** *Оригинал:* в `do_fall` (seg005:37) есть блок `FIX_GLIDE_THROUGH_WALL` с собственным комментарием SDLPoP: «Кид падает сквозь стены после разворота diff --git a/applications/SprPoP/docs/vanilla_vs_bugfixed.md b/applications/SprPoP/docs/vanilla_vs_bugfixed.md index a1aee80..4a38b41 100644 --- a/applications/SprPoP/docs/vanilla_vs_bugfixed.md +++ b/applications/SprPoP/docs/vanilla_vs_bugfixed.md @@ -177,7 +177,7 @@ ENHANCED. | опция | что чинит | статус | |---|---|---| -| `fix_glide_through_wall` | проход сквозь стену при падении после разворота в беге | **В РАБОТЕ** | +| `fix_glide_through_wall` | проход сквозь стену при падении после разворота в беге | **ВЗЯТ** 2026-08-31 — `glide_through_wall_guard()` в `pop_map.c`, точка отвязки для VANILLA | | `fix_jump_through_wall_above_gate` | прыжок в тайл над воротами | НЕТ | | `fix_drop_through_tapestry` | проваливание сквозь гобелен | НЕТ | | `fix_running_jump_through_tapestry` | прыжок с разбега сквозь гобелен | НЕТ | @@ -257,11 +257,10 @@ ENHANCED. | статус | сколько | |---|---:| -| ВЗЯТ | 4 | +| ВЗЯТ | 5 | | ВАНИЛЬ (сознательно) | 4 | -| В РАБОТЕ | 1 | | требует патча `seqtbl` (выполнимо) | 1 | -| НЕТ (кандидаты в ENHANCED) | 33 | +| НЕТ (кандидаты в ENHANCED) | 32 | ## Список кандидатов на BUGFIXED diff --git a/applications/SprPoP/src/pop_map.c b/applications/SprPoP/src/pop_map.c index e3bccd4..630b960 100644 --- a/applications/SprPoP/src/pop_map.c +++ b/applications/SprPoP/src/pop_map.c @@ -898,6 +898,40 @@ static uint8_t check_grab_run_jump(void) return 1; } +/* НЕ ДАТЬ ПРОЛЕТЕТЬ СКВОЗЬ СТЕНУ В ПАДЕНИИ. + * + * Порт опционального исправления SDLPoP (fix_glide_through_wall, seg005 в + * do_fall). В ванили personаж, падающий после разворота в беге, может + * оказаться внутри кладки и лететь «в стене» — баг оригинала, известный и + * воспроизводимый; у нас он ловится host-тестом (tests/host/t_wall.c, + * набор wall_stops_jump_from_left_side). + * + * ВЗЯТО В ТЕКУЩИЙ БИЛД по решению 2026-08-31: играбельность важнее + * буквальности. При разделении VANILLA/ENHANCED эта функция — готовая + * точка отвязки: достаточно не звать её в ванильном режиме + * (docs/vanilla_vs_bugfixed.md). + * + * Условие оригинала: персонаж внутри тайла стены, либо внутри верха двери + * (в обоих вариантах) при движении ВЛЕВО. Порог 8 и сдвиг на 15 назад — + * из исправления; они выбраны так, чтобы вытолкнуть на ту же дистанцию, + * что даёт выталкивание из стены при приземлении. Горизонтальную + * скорость гасим: иначе следующий кадр внесёт персонажа обратно. */ +static void glide_through_wall_guard(void) +{ + uint8_t t; + int d; + + determine_col(); + t = get_tile_at_char(); + if (t != TILE_WALL && + !((t == TILE_DOORTOP || t == TILE_DOORTOP_FLOOR) && Char.direction < 0)) + return; + d = distance_to_edge_weight(); + if (d < 8) return; + Char.x = (uint8_t)char_dx_forward((int8_t)(d - 15)); + Char.fall_x = 0; +} + static void do_fall(void) { uint8_t nrow = (uint8_t)(Char.curr_row + 1); @@ -908,6 +942,7 @@ static void do_fall(void) if (nrow > 4) nrow = 4; /* защита pop_y_land[] от выхода */ if ((uint16_t)pop_y_land[nrow] > (uint16_t)Char.y) { check_grab(); /* ещё летит — попытка зацепа */ + glide_through_wall_guard(); /* и не сквозь кладку (см. выше) */ } else if (Char.curr_row <= 2) { if (get_tile_at_char() == TILE_WALL) in_wall(); diff --git a/applications/SprPoP/tests/host/t_wall.c b/applications/SprPoP/tests/host/t_wall.c index f9e202a..662e432 100644 --- a/applications/SprPoP/tests/host/t_wall.c +++ b/applications/SprPoP/tests/host/t_wall.c @@ -162,21 +162,24 @@ static char jump_right_from(uint8_t x) } } -/* ВАНИЛЬНОЕ ПОВЕДЕНИЕ, А НЕ НАША ОШИБКА. +/* ФИКС ПАДЕНИЯ СКВОЗЬ СТЕНУ ВЗЯТ — ЖДЁМ НОЛЬ. * - * Прыжок вправо через провал даёт ДВА случая из четырнадцати, где Кид - * оказывается в колонке кладки, будучи в воздухе, — то есть «падает - * частично в стене». Это известный баг оригинального PoP: SDLPoP держит - * для него ОТДЕЛЬНОЕ опциональное исправление (FIX_GLIDE_THROUGH_WALL, - * seg005 do_fall), которое мы намеренно не портировали, повторяя ваниль - * (docs/sdlpop_audit.md, находка 21). + * В ванили прыжок вправо через провал давал ДВА случая из четырнадцати, + * где Кид оказывается в колонке кладки, будучи в воздухе, — «падение + * частично в стене». Это баг оригинального PoP, для которого SDLPoP + * держит опциональное исправление (fix_glide_through_wall, seg005 в + * do_fall). * - * Поэтому тест не требует нуля, а СТОРОЖИТ ЧИСЛО: пока их ровно два, мы - * ведём себя как оригинал. Стало больше — значит правка сделала хуже - * ванили; стало меньше — кто-то портировал фикс и об этом нужно знать. - * Проверено: фикс 24 (перезагрузка кадра в in_wall) на это число НЕ - * влияет. */ -#define WALL_VANILLA_GLIDE_CASES 2 + * 2026-08-31 исправление ПОРТИРОВАНО в текущий билд + * (glide_through_wall_guard в pop_map.c), и оба случая исчезли. Поэтому + * ожидание теперь НОЛЬ. + * + * Если когда-нибудь появится режим VANILLA без этого фикса, ожидание + * станет зависеть от режима: 0 в ENHANCED и 2 в ванильном + * (docs/vanilla_vs_bugfixed.md). Число 2 сохранено в имени константы + * именно поэтому — оно измерено, а не выдумано. */ +#define WALL_VANILLA_GLIDE_CASES 2 /* сколько их было ДО фикса */ +#define WALL_EXPECTED_GLIDE_CASES 0 /* сколько ожидаем СЕЙЧАС */ TC_TEST(wall_stops_jump_from_left_side) { @@ -190,7 +193,7 @@ TC_TEST(wall_stops_jump_from_left_side) if (r != 'R' && r != '.' && r != 'h') bad++; } put('\n'); - TC_EQ(bad, WALL_VANILLA_GLIDE_CASES); + TC_EQ(bad, WALL_EXPECTED_GLIDE_CASES); } int main(void)