From c6cadd0140da6f28197c962e54030f826c03a126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=9F=D0=B5=D1=82=D1=80=D0=BE=D0=B2?= Date: Wed, 5 Aug 2026 22:50:26 +0300 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=BA=D1=80=D1=8B=D1=82=D1=8B=20BU?= =?UTF-8?q?G-GRAB-1=20=D0=B8=20BUG-GATEMOD-1;=20BUG-SPIKE-1=20=E2=80=94=20?= =?UTF-8?q?=D0=B2=20=D0=BD=D0=B8=D0=B7=D0=BA=D0=BE=D0=BF=D1=80=D0=B8=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=82=D0=B5=D1=82=D0=BD=D1=8B=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Оба фикса подтверждены игрой, записи с разбором корней переехали в bug_closed.md. BUG-GATE-PASS-1 остался ждать сценария, но его оговорка про BUG-GATEMOD-1 обновлена (тот закрыт). BUG-SPIKE-1 понижен до низкого приоритета: маловоспроизводим, смертельность пик подтверждена замером. Co-Authored-By: Claude Opus 5 --- applications/PoP/roomtest/bug_closed.md | 146 +++++++++++++++++++++++ applications/PoP/roomtest/bug_list.md | 147 +----------------------- 2 files changed, 149 insertions(+), 144 deletions(-) diff --git a/applications/PoP/roomtest/bug_closed.md b/applications/PoP/roomtest/bug_closed.md index 9e6dd7e..2316914 100644 --- a/applications/PoP/roomtest/bug_closed.md +++ b/applications/PoP/roomtest/bug_closed.md @@ -11,6 +11,152 @@ --- +## BUG-GRAB-1. Прыжок с места через провал в 3 тайла: зацепа нет — **ЗАКРЫТ 2026-08-05** + +**Проверено в игре (пользователь):** «зацеп работает». Физика была верна с +самого начала, чинить пришлось клавиатуру — [BUG-KBD-5](#bug-kbd-5). + +> **Итог 2026-08-05.** Физика тут ни при чём — виновата клавиатура. +> Зажатый Shift снимался автоповтором зажатой стрелки, поэтому к кадрам +> 102…106 (окно зацепа) движок видел Shift отпущенным. Полный разбор и +> фикс — [BUG-KBD-5](bug_closed.md#bug-kbd-5); поведение Shift в MAME +> проверено замером карты `_kbdraw_down`. Осталось подтвердить сам зацеп +> живой игрой; версии 2 и 3 ниже проверять только если он всё ещё не выйдет. + + +**Симптом.** Уровень 2, комната 9. Перепрыгнув на (1,1), Кид должен +вернуться обратно: разбегаться негде, поэтому он встаёт на самый край +плиты, прыгает с места и **цепляется руками за (1,5)**, после чего +подтягивается. У нас Кид с зажатым Shift всё равно срывается. + +**Что уже точно известно (и не надо перепроверять).** + +1. **Физика прыжка у нас совпадает с оригиналом кадр в кадр.** Сверено по + логу SDLPoP против трассы харнесса при одинаковом старте `x=95`: + + ``` + кадр 16 18 22 23 24 25 102 103 104 105 + SDLPoP 95 97 105 112 121 126 128 130 131 133 + наш 95 97 105 112 121 126 128 130 131 133 + ``` + Совпадает и по `y`, и по колонке/ряду, и по приземлению на 107–108. + +2. **В оригинале зацеп срабатывает на кадре 106, а не 102..105.** + `check_grab` зовётся из ДВУХ мест: ветка «в воздухе» в `check_action` + (кадры 102..105) и `do_fall` (seg005) для `actions_4_in_freefall`. + Успешная попытка из лога: + + ``` + GRAB try f=106 x=135 y=166 col=4 row=2 fall_y=18 + GRAB probe x=127 col=4 through=0 front_above=3 modif=0 + GRAB can_grab=1 + GRAB OK dist=9 + -> f=91 x=136 y=181 col=5 row=2 act=2 (повис) + ``` + Наш `do_fall` (`pop_map.c`) `check_grab()` из этой ветки тоже зовёт — + то есть структура на месте, расходится что-то внутри. + +3. **По харнессу зацеп у нас РАБОТАЕТ**: окно стартовых `x = 91…95`, и + короткий шаг ставит Кида ровно туда (91 после первого нажатия, 95 после + второго). Зафиксировано тестом `t_grab`. + +**Отсюда главный вопрос был: почему харнесс говорит «работает», а живая +машина — «нет».** Расхождение между ними и оказалось уликой; версии +выдвигались по убыванию правдоподобия, и сработала первая: + +- **Shift не доезжает до движка — ПОДТВЕРЖДЕНО, это и была причина.** + Харнесс подменяет клавиатуру и потому этот путь не проверяет вовсе, а у + нас есть история проблем ровно с «Shift + стрелки» (KBD-1, BUG-KBD-3/4). + Замер в MAME: при зажатом Shift и зажатой стрелке бит `LSh` в + `_kbdraw_down` стоял в нуле. Разбор — [BUG-KBD-5](bug_closed.md#bug-kbd-5). +- **Сцена харнесса не равна комнате 9.** Там изолированная комната + (соседи — стена), а в игре слева комната 8; кромки шва участвуют в + `get_tile`. Проверять чтением `Kid.x` в момент прыжка: попал ли он в + окно 91…95 вообще. +- **Расхождение в `check_grab`.** Наш вариант зовёт `determine_col()` + там, где оригинал зовёт `load_fram_det_col()` (перезагрузка кадра + + колонка). Для Кида это обычно одно и то же (`cur_frame` в фазе физики + принадлежит ему), но проверить стоит. + +**Инструменты готовы.** В SDLPoP включена отладка (пометка `DBG-GRAB`): +`JMP` — покадровая трасса прыжка/падения/виса, `GRAB try|probe|fail|OK` — +вход в `check_grab` и причина отказа. Снимается поиском по `DBG-GRAB`. + +**Найдено попутно, отдельным наблюдением.** После касания площадки на +кадрах 107–108 (x=140) оба движка снова падают, но X расходится: SDLPoP +уводит Кида на 134 (колонка 4), мы — на 141 (колонка 5). Похоже на разную +отработку `in_wall()` у стены (2,7). На зацеп не влияет. + +--- + +--- + +## BUG-GATEMOD-1. Ворота стартуют закрытыми, хотя в уровне открыты — **ЗАКРЫТ 2026-08-05** + +**Проверено в игре (пользователь).** + +**Симптом (пользователь, 2026-08-04).** Уровень 2, комната 13: решётка +между (2,5) и (2,6) обязана быть ОТКРЫТА в начале и захлопнуться, когда Кид +нажмёт кнопку (2,4) — после этого назад дороги нет. У нас она закрыта +сразу, кнопка бессмысленна, проход не работает. + +**Корень.** Модификатор тайла в ФАЙЛЕ уровня и модификатор в РАНТАЙМЕ — +разные величины; оригинал переводит их при загрузке в `load_alter_mod` +(seg008:198E), которую зовёт `alter_mods_allrm` из `load_level`: + +```c +case tiles_4_gate: *modif = (*modif == 1) ? 188 : 0; break; +case tiles_11_loose:*modif = 0; break; +case tiles_10_potion:*modif <<= 3; break; +``` + +Наш `pop_trob_modif` портировал из неё **только зелье**. Для ворот +`bg = 1` — это «открыты» (Table 8 спецификации DAT), а в рантайме открытость +измеряется высотой подъёма 0..188; мы клали в рантайм-модификатор сырую +единицу, то есть «закрыты на 1/188». + +**Фикс.** Ветки ворот и loose дописаны в ленивую инициализацию +`pop_trob_modif` (`pop_trob.c`). Ветка СТЕН не портируется намеренно: у нас +`pop_bg` считает связи кладки по типам соседей прямо при отрисовке +(`wall_modifier`), сохранённый модификатор стены не читается. + +**Что это ещё задевает.** Решётка (0,9) комнаты 5 уровня 1 тоже имеет +`bg = 1`, то есть обязана стартовать открытой — Кид сваливается в комнату 1 +именно через неё, и она захлопывается у него за спиной. Закрывает её +стартовый триггер `do_startpos` (seg003:167): для уровней с +`tbl_entry_pose == 1` оригинал ВИРТУАЛЬНО ЖМЁТ кнопку комнаты 5 (0,2) — + +```c +// Special event: press button + falling entry +get_tile(5, 2, 0); trigger_button(0, 0, -1); seqtbl_offset_char(seq_7_fall); +``` + +Замер в SDLPoP (лог по кадрам): `gate(5,0,9)` идёт `188 → 148 → 88 → 8 → 0`, +шаги 40/60/80 — это `gate_close_speeds`, то есть быстрое закрытие +(`trigger_gate` вернул тип 3). У нас этот триггер портирован, и закрытие +работает. + +Полный список ворот с `bg = 1`: ур. 1 комн. 5 (0,9); ур. 2 комн. 13 (1,5). +Остальные ворота уровней 1–3 имеют `bg = 2` → 0, и для них ничего не +меняется (при модификаторе 2 и 0 и отрисовка, и `can_bump_into_gate` дают +одно и то же). + +**Побочная находка: чит обхода комнат отматывал мир.** После фикса +пользователь увидел «ворота снова открылись», пройдя `+` в комнату 2 и `-` +обратно. Причина не в воротах: `ROOMNAV` звал `pop_trob_reset()` перед +`enter_room`, тот обнулял `room_seen[]`, и `pop_trob_modif()` перечитывал +модификаторы из уровня заново — то есть чит откатывал открытые/закрытые +ворота, выдвинутые пики и нажатые кнопки. Пока ворота с `bg=1` ошибочно +стартовали закрытыми, откат был не виден. `pop_trob_reset()` из навигации +убран: она обязана только телепортировать, исходное состояние даёт +перезапуск уровня. Замер, который это показал: `room_modif` комнаты 5 +после `+`/`-` = `00 00 0B 00 09 00 08 01 00 BC` — последний байт 0xBC = 188, +файловое значение. + +--- + +--- + ## BUG-GUARD-DEAF-1. Страж не оборачивался на вернувшегося Кида — **ЗАКРЫТ 2026-08-05** **Наблюдение (пользователь, 2026-08-05).** Уровень 2, комната 11, идёт бой diff --git a/applications/PoP/roomtest/bug_list.md b/applications/PoP/roomtest/bug_list.md index 8d383ef..d0f8257 100644 --- a/applications/PoP/roomtest/bug_list.md +++ b/applications/PoP/roomtest/bug_list.md @@ -27,14 +27,12 @@ BUG-GATE-PASS-1 — однократное наблюдение прохода | ID | что | тип | статус | |----|-----|-----|--------| -| [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом (h=1 → пробег безвреден, острия видны на экране) | Minor | **не воспроизводится по требованию; смертельность подтверждена замером** | -| [BUG-GRAB-1](#bug-grab-1) | ур. 2 комн. 9: прыжок с места через 3 тайла — нет зацепа за кромку | Major | **причина найдена (клавиатура, BUG-KBD-5), фикс есть, ждёт игровой проверки** | -| [BUG-GATEMOD-1](#bug-gatemod-1) | ворота стартуют закрытыми, хотя в уровне открыты | Major | **фикс есть, ждёт проверки** | | [Уровень 2](#уровень-2) | остальные баги с приёмки | — | принимаются по ходу | -| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрывшуюся решётку (0,9) комнаты 5 | Major | **перепроверить после [BUG-GATEMOD-1](#bug-gatemod-1)** — та же решётка стартовала не в том состоянии | +| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрывшуюся решётку (0,9) комнаты 5 | Major | **ждёт сценария** (BUG-GATEMOD-1, из-за которого решётка стартовала не в том состоянии, закрыт — перепроверить) | | [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт | | [T-2](#t-2) | Кид перерисовывается в покое | оптимизация | открыт | | [обход 24 комнат](#обход-всех-24-комнат-уровня-1) | таблица заполнена на 5 строк из 24 | ревизия | открыт | +| [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом | **низкий** | маловоспроизводимый: ни сценарием, ни попиксельной подгонкой X не поднимается | --- @@ -84,7 +82,7 @@ Smoke-прогон уровня 3 (пользователь, 2026-08-05) дал стеной). -## BUG-SPIKE-1. Пики не убивают бегущего Кида — НЕ ВОСПРОИЗВОДИТСЯ, ЖДЁТ СЦЕНАРИЯ +## BUG-SPIKE-1. Пики залипают выдвинутыми — НИЗКИЙ ПРИОРИТЕТ, МАЛОВОСПРОИЗВОДИМ > **Статус 2026-08-05, вечер.** Пользователь **повторить не смог**, а замер > (ниже) показал, что чистый пробег по убранным пикам убивает штатно. То @@ -186,145 +184,6 @@ check_spiked (seg006:0658): убивает при h>=2 на кадрах б --- - -## BUG-GRAB-1. Прыжок с места через провал в 3 тайла: зацепа нет — **ПРИЧИНА НАЙДЕНА, ФИКС ЕСТЬ, ЖДЁТ ИГРОВОЙ ПРОВЕРКИ** - -> **Итог 2026-08-05.** Физика тут ни при чём — виновата клавиатура. -> Зажатый Shift снимался автоповтором зажатой стрелки, поэтому к кадрам -> 102…106 (окно зацепа) движок видел Shift отпущенным. Полный разбор и -> фикс — [BUG-KBD-5](bug_closed.md#bug-kbd-5); поведение Shift в MAME -> проверено замером карты `_kbdraw_down`. Осталось подтвердить сам зацеп -> живой игрой; версии 2 и 3 ниже проверять только если он всё ещё не выйдет. - - -**Симптом.** Уровень 2, комната 9. Перепрыгнув на (1,1), Кид должен -вернуться обратно: разбегаться негде, поэтому он встаёт на самый край -плиты, прыгает с места и **цепляется руками за (1,5)**, после чего -подтягивается. У нас Кид с зажатым Shift всё равно срывается. - -**Что уже точно известно (и не надо перепроверять).** - -1. **Физика прыжка у нас совпадает с оригиналом кадр в кадр.** Сверено по - логу SDLPoP против трассы харнесса при одинаковом старте `x=95`: - - ``` - кадр 16 18 22 23 24 25 102 103 104 105 - SDLPoP 95 97 105 112 121 126 128 130 131 133 - наш 95 97 105 112 121 126 128 130 131 133 - ``` - Совпадает и по `y`, и по колонке/ряду, и по приземлению на 107–108. - -2. **В оригинале зацеп срабатывает на кадре 106, а не 102..105.** - `check_grab` зовётся из ДВУХ мест: ветка «в воздухе» в `check_action` - (кадры 102..105) и `do_fall` (seg005) для `actions_4_in_freefall`. - Успешная попытка из лога: - - ``` - GRAB try f=106 x=135 y=166 col=4 row=2 fall_y=18 - GRAB probe x=127 col=4 through=0 front_above=3 modif=0 - GRAB can_grab=1 - GRAB OK dist=9 - -> f=91 x=136 y=181 col=5 row=2 act=2 (повис) - ``` - Наш `do_fall` (`pop_map.c`) `check_grab()` из этой ветки тоже зовёт — - то есть структура на месте, расходится что-то внутри. - -3. **По харнессу зацеп у нас РАБОТАЕТ**: окно стартовых `x = 91…95`, и - короткий шаг ставит Кида ровно туда (91 после первого нажатия, 95 после - второго). Зафиксировано тестом `t_grab`. - -**Отсюда главный вопрос был: почему харнесс говорит «работает», а живая -машина — «нет».** Расхождение между ними и оказалось уликой; версии -выдвигались по убыванию правдоподобия, и сработала первая: - -- **Shift не доезжает до движка — ПОДТВЕРЖДЕНО, это и была причина.** - Харнесс подменяет клавиатуру и потому этот путь не проверяет вовсе, а у - нас есть история проблем ровно с «Shift + стрелки» (KBD-1, BUG-KBD-3/4). - Замер в MAME: при зажатом Shift и зажатой стрелке бит `LSh` в - `_kbdraw_down` стоял в нуле. Разбор — [BUG-KBD-5](bug_closed.md#bug-kbd-5). -- **Сцена харнесса не равна комнате 9.** Там изолированная комната - (соседи — стена), а в игре слева комната 8; кромки шва участвуют в - `get_tile`. Проверять чтением `Kid.x` в момент прыжка: попал ли он в - окно 91…95 вообще. -- **Расхождение в `check_grab`.** Наш вариант зовёт `determine_col()` - там, где оригинал зовёт `load_fram_det_col()` (перезагрузка кадра + - колонка). Для Кида это обычно одно и то же (`cur_frame` в фазе физики - принадлежит ему), но проверить стоит. - -**Инструменты готовы.** В SDLPoP включена отладка (пометка `DBG-GRAB`): -`JMP` — покадровая трасса прыжка/падения/виса, `GRAB try|probe|fail|OK` — -вход в `check_grab` и причина отказа. Снимается поиском по `DBG-GRAB`. - -**Найдено попутно, отдельным наблюдением.** После касания площадки на -кадрах 107–108 (x=140) оба движка снова падают, но X расходится: SDLPoP -уводит Кида на 134 (колонка 4), мы — на 141 (колонка 5). Похоже на разную -отработку `in_wall()` у стены (2,7). На зацеп не влияет. - ---- - - -## BUG-GATEMOD-1. Ворота стартуют закрытыми, хотя в уровне открыты — **ФИКС ЕСТЬ, ЖДЁТ ПРОВЕРКИ** - -**Симптом (пользователь, 2026-08-04).** Уровень 2, комната 13: решётка -между (2,5) и (2,6) обязана быть ОТКРЫТА в начале и захлопнуться, когда Кид -нажмёт кнопку (2,4) — после этого назад дороги нет. У нас она закрыта -сразу, кнопка бессмысленна, проход не работает. - -**Корень.** Модификатор тайла в ФАЙЛЕ уровня и модификатор в РАНТАЙМЕ — -разные величины; оригинал переводит их при загрузке в `load_alter_mod` -(seg008:198E), которую зовёт `alter_mods_allrm` из `load_level`: - -```c -case tiles_4_gate: *modif = (*modif == 1) ? 188 : 0; break; -case tiles_11_loose:*modif = 0; break; -case tiles_10_potion:*modif <<= 3; break; -``` - -Наш `pop_trob_modif` портировал из неё **только зелье**. Для ворот -`bg = 1` — это «открыты» (Table 8 спецификации DAT), а в рантайме открытость -измеряется высотой подъёма 0..188; мы клали в рантайм-модификатор сырую -единицу, то есть «закрыты на 1/188». - -**Фикс.** Ветки ворот и loose дописаны в ленивую инициализацию -`pop_trob_modif` (`pop_trob.c`). Ветка СТЕН не портируется намеренно: у нас -`pop_bg` считает связи кладки по типам соседей прямо при отрисовке -(`wall_modifier`), сохранённый модификатор стены не читается. - -**Что это ещё задевает.** Решётка (0,9) комнаты 5 уровня 1 тоже имеет -`bg = 1`, то есть обязана стартовать открытой — Кид сваливается в комнату 1 -именно через неё, и она захлопывается у него за спиной. Закрывает её -стартовый триггер `do_startpos` (seg003:167): для уровней с -`tbl_entry_pose == 1` оригинал ВИРТУАЛЬНО ЖМЁТ кнопку комнаты 5 (0,2) — - -```c -// Special event: press button + falling entry -get_tile(5, 2, 0); trigger_button(0, 0, -1); seqtbl_offset_char(seq_7_fall); -``` - -Замер в SDLPoP (лог по кадрам): `gate(5,0,9)` идёт `188 → 148 → 88 → 8 → 0`, -шаги 40/60/80 — это `gate_close_speeds`, то есть быстрое закрытие -(`trigger_gate` вернул тип 3). У нас этот триггер портирован, и закрытие -работает. - -Полный список ворот с `bg = 1`: ур. 1 комн. 5 (0,9); ур. 2 комн. 13 (1,5). -Остальные ворота уровней 1–3 имеют `bg = 2` → 0, и для них ничего не -меняется (при модификаторе 2 и 0 и отрисовка, и `can_bump_into_gate` дают -одно и то же). - -**Побочная находка: чит обхода комнат отматывал мир.** После фикса -пользователь увидел «ворота снова открылись», пройдя `+` в комнату 2 и `-` -обратно. Причина не в воротах: `ROOMNAV` звал `pop_trob_reset()` перед -`enter_room`, тот обнулял `room_seen[]`, и `pop_trob_modif()` перечитывал -модификаторы из уровня заново — то есть чит откатывал открытые/закрытые -ворота, выдвинутые пики и нажатые кнопки. Пока ворота с `bg=1` ошибочно -стартовали закрытыми, откат был не виден. `pop_trob_reset()` из навигации -убран: она обязана только телепортировать, исходное состояние даёт -перезапуск уровня. Замер, который это показал: `room_modif` комнаты 5 -после `+`/`-` = `00 00 0B 00 09 00 08 01 00 BC` — последний байт 0xBC = 188, -файловое значение. - ---- - # Ручная перепроверка фиксов (2026-08-03)