SprPoP: три находки прогона 2026-08-31 — звук мигания, часы в быстрых режимах, полоса HP после рестарта

Разбор без правок кода; все три отмечены как задачи по решению пользователя.

SND-SPEAKER-38 (TASKS_OPEN, P1).  Надпись «Press Button» мигает молча.
Наш код не виноват: pop_dead_prompt зовёт звук 38 на каждом появлении,
как оригинал, но слот 38 в наборе ПУСТ.  Причина — три параллельных
набора звука у оригинала: оцифровка (0-23, 44-49, 51), мелодии (24-43
частично, 50, 52-56) и ноты PC-спикера (весь диапазон).  Звук 38 есть
ТОЛЬКО среди нот спикера, поэтому провалился между нашими конвейерами.
Полная ревизия: не оцифровка и не мелодия — номера 31, 34, 38, 42, из них
31/34/42 пустые заглушки, реально звучит ровно один — 38.  Решение
выбрано пользователем: синтезировать ноты в PCM и класть в наш атлас;
формат разобран по спецификации Princed и записан в задачу.

TIME-SPEED (TASKS_OPEN, P1).  Часы уменьшаются на каждом логическом кадре
(как оригинал), но длину кадра у нас меняет режим скорости — в FAST
минута проходит на треть быстрее.  Разная длина кадра в игре и в бою есть
и в оригинале (поправка пользователя), поэтому замедление часов в бою не
трогаем; вопрос только в наших добавочных режимах.  Два варианта с
рекомендацией оставить как есть.

HP-BAR-RESTART (BUGS_OPEN).  После гибели и Ctrl+A (у нас это рестарт
уровня) на одной из страниц остаётся полоса по результатам боя.  Механизм
перерисовки на месте — счётчик страниц, все холодные пути его взводят.
Подозреваемый: пока висит статус-текст, стирание чистит только края и не
трогает середину, а полоса стража при большом запасе HP заходит именно
туда.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY
This commit is contained in:
2026-08-31 22:31:32 +03:00
parent b0e7130d0b
commit decbec79de
2 changed files with 132 additions and 0 deletions
+39
View File
@@ -39,6 +39,7 @@
| [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) |
| [HP-BAR-RESTART](#hp-bar-restart) | после гибели и Ctrl+A на ОДНОЙ из двух страниц остаётся полоса HP по результатам боя | дабл-буфер/UI | открыт: разбор есть (2026-08-31) |
---
@@ -1394,3 +1395,41 @@ uint16_t pop_music_left(void) { uint16_t a, b;
**Решение пользователя:** отложено на будущее (2026-08-31) — поведение в
этой связке расходится широко, чинить нужно целиком, а не по одному
симптому.
## HP-BAR-RESTART
**Симптом (пользователь, 2026-08-31).** Гибель на 2-м уровне, возврат к
началу по Ctrl+A: строка HP на одном из двух экранов остаётся отрисованной
по результатам боя. Замечание там же: «в начале уровня она отрисовывается
только в один экран».
**Что уже известно.**
Ctrl+A у нас — РЕСТАРТ УРОВНЯ (`sprpop_cold.c`, тот же путь, что пункт меню
`POP_MENU_RESTART_LEVEL`), а не возврат в заставку.
Перерисовка полосы устроена счётчиком страниц, а не флагом:
`pop_hp_invalidate` ставит `hp_todo = 2`, и `pop_hp_draw` тратит по одной
странице за кадр (`src/pop_cdraw.c`). Все четыре холодных пути
(старт уровня, вход в комнату, быстрая загрузка, возврат из меню)
инвалидацию зовут — механизм на месте.
**Главный подозреваемый — зона статус-строки.** Полоса HP делит строку со
статус-текстом, и пока текст висит (`pop_status_ticks != 0`), стирание
чистит ТОЛЬКО края — левее `POP_STATUS_L` и правее `POP_STATUS_R`, —
а середину не трогает, чтобы текст не мигал. При старте уровня текст как
раз висит («LEVEL 2»), поэтому всё, что от прошлой полосы попало в
середину, там и остаётся. Полоса стража рисуется справа налево от 314 и
при большом запасе HP заходит именно в эту незачищаемую зону.
**Что проверить при взятии в работу.**
1. Значения `POP_STATUS_L`/`POP_STATUS_R` против реальной ширины полос:
при скольких делениях полоса стража (или Кида) заходит под текст.
2. Уходят ли оба прохода `hp_todo` в РАЗНЫЕ страницы на старте уровня —
если между ними нет переворота, обе перерисовки лягут в одну.
3. Возможное решение: на старте уровня чистить полосу во всю ширину
независимо от статус-текста (текст всё равно перерисовывается заново
через `pop_status_invalidate`), либо запоминать максимальную ширину
прошлой полосы и стирать по ней.