SprPoP: мёртвое тело больше не приземляется в присед, надпись смерти не залипает
Два независимых фикса, оба проверены в MAME. 1. ПРИЗЕМЛЕНИЕ МЁРТВОГО (симптом «убили Кида, а он сел этажом ниже»). Оригинал спрашивает у приземляющегося, жив ли он (seg005:0173): вся развязка «мягко / средне / разбиться» отведена ЖИВОМУ, телу — своя ветка (добить HP, звук падения насмерть, seq_22). У нас развилки не было, и в глаза это не бросалось только из-за высоты: тело, сброшенное ударом с ОДНОГО ряда, набирает fall_y < 22 — урона нет, «последнее HP» не тратится, ветка «разбился» не выбирается никогда. Труп уходил в мягкое приземление и садился (кадр 109). Цена — один тест байта на вызов land(), то есть на событие касания земли, а не на кадр. Живой путь не изменился ни на операцию. 2. ЗАЛИПАВШАЯ НАДПИСЬ «Press Button to Continue». Счётчик кадров смерти живёт снаружи главного витка и потому переживает возврат на заставку. Ответ игрока кнопкой его обнулял, а выход по таймауту (24 с молчания -> title) уходил мимо сброса. Дальше счётчик оставался израсходованным на всю сессию, и в следующей игре ПЕРВАЯ же смерть мгновенно уводила в title, не показав надписи; лечилось только перезапуском программы. Сброс поставлен на входе в игровой маршрут — закрывает и остальные боковые дороги (выпадение за нижнюю границу, смена уровня). Здесь же довезена связка находок 12/13 аудита: смерть безоружного у обрыва уходит в свою последовательность (seq_81), а прижатие к полу осталось страховкой для прочих веток — снять его целиком не вышло дважды, подробности в комментарии guards.c. Тесты: t_death дополнен обеими сторонами развилки (мёртвый обязан разбиться, живой с той же высоты — сесть без урона), 18 проверок; все 16 наборов host-тестов зелёные. В доску записан CLIMB-VS-GUARD: Кид подтягивается к стражу этажом выше — у нас удар порой смертелен, в оригинале Кид срывается без урона. Цепочка засчитывания удара сверена с оригиналом и совпадает дословно, расходятся входные данные. Лучшая зацепка — ЗВУК: оригинал играет взмах клинка (11) при любом уколе, до всякой проверки попадания, а у нас слышен упор в стену (8) — значит страж не атакует, а сталкивается. Набор звуков проверен и не виноват. Отложено по решению пользователя. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
| [SND-PACE-DEAD](#snd-pace-dead) | пейсинг сцен по насосу CBL не включается: признак «часы идут» вычисляется двумя чтениями подряд | **тайминг/звук** | **снят 2026-08-28**: ветка удалена, сцена на единых часах по лучу |
|
||||
| [PV-RENDER-BOUND](#pv-render-bound) | сцена с принцессой рисуется дороже бюджета: ~49 тиков/с вместо 60, музыка уезжает от картинки | производительность | **исправлено 2026-08-28**: кадр разложен на блоки по интервалу, удешевлять не понадобилось |
|
||||
| [MUS-LEFT-TEAR](#mus-left-tear) | `pop_mus_left` (16 бит, пишет прерывание) читается из главного цикла неатомарно — возможен ложный «трек кончился» | **потенциальный** | открыт: хазард показан рассуждением, в прогоне не проявился |
|
||||
| [CLIMB-VS-GUARD](#climb-vs-guard) | Кид подтягивается к стражу этажом выше: у нас удар засчитывается и убивает, в оригинале Кид просто срывается без урона; страж при этом способен провалиться сквозь пол вслед за Кидом | бой/физика | открыт: цепочка удара сверена — совпадает, расходятся входные данные (2026-08-31) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1313,3 +1314,83 @@ uint16_t pop_music_left(void) { uint16_t a, b;
|
||||
раз в кадр, задержка прерывания ничтожна против 11,7 мс периода насоса),
|
||||
но двойное чтение не трогает состояние прерываний вовсе — на фоне
|
||||
[cbl_w0_bios_conflict](../../PoP/roomtest/BUGS_CLOSED.md) это плюс.
|
||||
|
||||
|
||||
## CLIMB-VS-GUARD
|
||||
|
||||
Кид стоит рядом 2,6, страж — этажом выше на 1,6. Кид тянется подтянуться
|
||||
на 1,6.
|
||||
|
||||
**Оригинал (SDLPoP).** Страж машет мечом, Кид срывается обратно на 2,6
|
||||
**без потери HP**.
|
||||
|
||||
**У нас.** Тот же замах убивает Кида на месте. Если Кид безоружен, это
|
||||
мгновенная смерть (ветка «заколот без меча», HP разом в ноль) — и дальше
|
||||
тело падает, что до 2026-08-31 давало отдельный симптом «мёртвый
|
||||
вприсядку» (закрыт развилкой в `land()`, см. коммит того же дня).
|
||||
|
||||
**Наблюдение сверх того (пользователь, 2026-08-31).** В этой же связке
|
||||
поведение расходится сильнее: страж провалился с ряда 1 на ряд 2 ВМЕСТЕ с
|
||||
Кидом — причём Кид ушёл в провал в колонке 7 (там дыра), а страж между
|
||||
колонками 5 и 6, где на ряду 1 пол ЕСТЬ. То есть страж проваливается
|
||||
сквозь целый пол. Это может быть тем же корнем, что и удар: обоим нужен
|
||||
корректный ряд/колонка персонажа в момент подтягивания.
|
||||
|
||||
**Что уже проверено статически (2026-08-31).** Вся цепочка засчитывания
|
||||
удара сверена с оригиналом и совпадает ДОСЛОВНО:
|
||||
|
||||
- гейт по кадру Кида (нулевой кадр и кадры выхода по лестнице пропускают
|
||||
разбор целиком) — `pop_check_sword_hurting`;
|
||||
- приоритет стража при встречном попадании (отметка «ранен» у Кида
|
||||
снимается) — `pop_check_sword_hurt`;
|
||||
- требование ОДНОГО ряда у бьющего и жертвы — `check_hurting`;
|
||||
- кадры удара (укол/третий удар), диапазон дистанции (8 для безоружной
|
||||
жертвы, 12 для вооружённой, верхняя граница 29);
|
||||
- формула расстояния `pop_char_opp_dist` — совпадает с `char_opp_dist`.
|
||||
|
||||
Значит расходятся не правила, а ВХОДНЫЕ данные: ряд, колонка или X
|
||||
персонажа во время виса/подтягивания. Наиболее вероятный кандидат —
|
||||
дистанция: висящий вплотную под кромкой в оригинале не дотягивает до
|
||||
нижнего порога 8, а у нас пара пикселей переводит его через порог.
|
||||
|
||||
**Как чинить.** Не гадать — замерить на живой сцене: в момент, когда
|
||||
`Opp.action` становится «ранен», снять у обоих `curr_row`, `curr_col`, `x`,
|
||||
`direction` и сравнить с теми же величинами в SDLPoP на том же кадре
|
||||
(метод — lldb-трасса живого SDLPoP, как в
|
||||
[[sdlpop_odd_pixel_char_x]]). Отдельно снять, почему страж теряет опору:
|
||||
`get_tile_at_char` под ним в кадре провала.
|
||||
|
||||
**Уточнение пользователя (2026-08-31, важное).** Оригинальное поведение —
|
||||
Кид сорвался без потери HP — ВОСПРОИЗВОДИТСЯ и у нас: исход сильно зависит
|
||||
от того, где именно стоит страж. То есть расхождение не абсолютное, а
|
||||
пороговое, и это прямо подкрепляет версию про ДИСТАНЦИЮ: пара пикселей
|
||||
переводит расстояние через нижний порог засчитывания удара (8 для
|
||||
безоружной жертвы), и удар из «мимо» становится смертельным. Значит
|
||||
искать надо не потерянную ветку, а сдвиг координаты/порога — сравнивать
|
||||
`pop_char_opp_dist` в момент замаха при ОДИНАКОВОЙ расстановке.
|
||||
|
||||
**ЗВУК КАК ИНДИКАТОР ПУТИ (пользователь, 2026-08-31) — лучшая зацепка.**
|
||||
В той же сцене оригинал играет ВЗМАХ (звук 11, «клинок движется»), а у нас
|
||||
слышен звук, похожий на упор Кида в стену (звук 8, `bumped`).
|
||||
|
||||
Почему это важно. Звук 11 оригинал играет в `check_hurting` СРАЗУ на
|
||||
кадре укола — ДО проверки расстояния и до отметки «ранен». То есть он
|
||||
звучит при ЛЮБОМ уколе, попал тот или нет. Значит его отсутствие
|
||||
означает не «промахнулись», а «до укола дело вообще не дошло»: страж не в
|
||||
кадре укола, либо разбор вышел раньше (меч не вынут / ряды не совпали).
|
||||
А звучащий вместо него упор в стену говорит, что у нас сработало
|
||||
СТОЛКНОВЕНИЕ, а не атака.
|
||||
|
||||
Набор звуков проверен и НЕ виноват: в `assets/packed/SND/snd.idx` слот 11
|
||||
на месте и содержит собственный короткий сэмпл (1280 Б), слот 8 — другой
|
||||
(1664 Б). Раскладка не сдвинута.
|
||||
|
||||
Отсюда рабочая версия: в этой связке оригинал ведёт стража по ветке
|
||||
«атака с промахом», а мы — по ветке «столкновение с персонажем»
|
||||
(`bump_into_opponent` / `check_bumped`). Это же объясняет и провалившегося
|
||||
сквозь пол стража: столкновение двигает его координату, а не атака.
|
||||
Проверять надо ветку выбора действия стража, а не только дистанцию.
|
||||
|
||||
**Решение пользователя:** отложено на будущее (2026-08-31) — поведение в
|
||||
этой связке расходится широко, чинить нужно целиком, а не по одному
|
||||
симптому.
|
||||
|
||||
Reference in New Issue
Block a user