SprPoP: звук мигания, равномерные часы, полоса HP после рестарта, надпись ждёт мелодию

Четыре правки прогона 2026-08-31.  Две ПРОВЕРЕНЫ пользователем в MAME
(звук мигания, порядок «мелодия -> надпись»), две ждут проверки — образ
собран.

ЗВУК МИГАНИЯ (проверено).  Упаковщик научился синтезировать ноты PC-
спикера в обычный сэмпл: заголовок с темпом, тройки «частота + длина»,
меандр на нашей частоте вывода.  Берём из нот ТОЛЬКО номера, которых нет
ни в оцифровке, ни среди мелодий, — иначе синтез перекрыл бы музыку,
которую мы играем из MUS/.  На поставке SDLPoP это ровно один номер: 38,
сигнал под мигание «Press Button»; 31, 34 и 42 там пустые заглушки.
Громкость по слуховой проверке снижена вдвое (44 -> 22): на полном
размахе сигнал перекрикивал игру.  EXE не меняется — раскладка читается с
диска, набор занял те же 9 страниц.

НАДПИСЬ ЖДЁТ МЕЛОДИЮ (проверено).  Порядок оригинала: ветка мёртвого
(seg006:1351) на седьмом шаге выходит, пока звук играет, и «Press Button»
появляется только после музыки смерти.  Чтобы ожидание не было
принудительным, три быстрых пути (Ctrl+A, обе быстрые загрузки, пункты
меню) музыку глушат — оригинал при Ctrl+A делает то же (seg000:0617).
Обычная кнопка во время мелодии не действует: она ответ НА надпись.

ЧАСЫ (ждёт проверки).  Тик стоит столько кадров ЛУЧА, сколько их в кадре
режима NORMAL, поэтому FAST/FASTEST больше не ускоряют время.  Считаем
ФАКТИЧЕСКИ прошедшие кадры луча, а не ожидаемый делитель: логический кадр
не всегда укладывается в бюджет, и часы «по делителю» шли рывками (первый
прогон это показал — «несколько секунд быстро, потом притормаживание»).
Вклад одного вызова ограничен, иначе пауза и меню прыгнули бы вперёд.
Четыре новых теста: NORMAL не сдвинулся ни на тик (и вне боя, и в бою),
FAST и FASTEST держат реальное время.

ПОЛОСА HP ПОСЛЕ Ctrl+A (ждёт проверки).  Корень: счётчик считает
СТРАНИЦЫ, а тратился по КАДРАМ — между двумя вызовами переворота может не
быть, и оба прохода уходили в одну страницу, вторая оставалась с
делениями прошлого боя.  Теперь проход тратится только при смене
gfx_get_draw_page().  Плюс полная чистка всей ширины при инвалидации:
старая полоса могла заходить под статус-текст, где щадящая чистка её не
трогала; текст сразу перезапрашивается.

Все 16 наборов host-тестов зелёные, check_bank_calls чист.

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 23:10:35 +03:00
parent decbec79de
commit 63bfd997a9
14 changed files with 326 additions and 26 deletions
+20 -1
View File
@@ -14,16 +14,35 @@ uint8_t pop_timer_minutes;
uint16_t pop_timer_ticks;
uint8_t pop_show_time;
/* Накопленные кадры луча, ещё не сложившиеся в тик. Живёт между кадрами:
* при FAST логический кадр короче эталона, и остаток переносится вперёд. */
static uint8_t tick_acc;
void pop_timer_new_game(void) __banked
{
pop_timer_minutes = POP_TIMER_START_MINUTES;
pop_timer_ticks = POP_TIMER_START_TICKS;
pop_show_time = 0;
tick_acc = 0;
}
uint8_t pop_timer_tick(uint8_t enabled, uint8_t may_run) __banked
uint8_t pop_timer_tick(uint8_t enabled, uint8_t may_run,
uint8_t spent, uint8_t base) __banked
{
if (!enabled || !may_run || pop_timer_minutes == 0) return 0;
/* ХОД ЧАСОВ ОТВЯЗАН ОТ ТЕМПА. Тик стоит `base` кадров луча — столько,
* сколько их в кадре режима NORMAL. При NORMAL spent == base, и тик
* приходится ровно на кадр, как было всегда; в быстрых режимах кадр
* короче, остаток копится, и за то же РЕАЛЬНОЕ время выходит столько
* же тиков. Цикла не нужно: spent никогда не больше base (быстрые
* режимы кадр только УКОРАЧИВАЮТ) — значит не больше тика за вызов. */
/* Пауза, меню и загрузка сюда не заходят вовсе, поэтому за время их
* работы кадры луча накапливаются мимо нас. Ограничиваем вклад одного
* вызова: иначе после меню часы прыгнули бы вперёд на всю паузу. */
if (spent > (uint8_t)(base + base)) spent = base;
tick_acc = (uint8_t)(tick_acc + spent);
if (tick_acc < base) return 0;
tick_acc = (uint8_t)(tick_acc - base);
--pop_timer_ticks;
if (pop_timer_ticks != 0) {