SprPoP: заставку можно прервать в любой её точке, F10 — выход

Три места, где нажатие раньше не работало или работало наполовину.

FADE.  fade_run() был замкнутым циклом на 2,13 с без опроса клавиш, а на
стыке экранов их два: пропуск работал внутри сценария, но не между его
шагами, и заставка ощущалась невыключаемой.  Добавлены прерываемые
варианты (pop_ui_fade_*_skip, обёртки в pop_pal) — отдельными функциями,
а не флагом в прежних: в меню паузы и на переходе уровня прерывать
нечего, и менять там поведение молча не следует.  Прерванный fade всё
равно доводит палитру до конца, экран не остаётся на промежуточной
ступени.  Подключено в интерпретаторе сценария, сцене с принцессой,
четырёх катсценах cut_*, титрах и таблице рекордов.

ПРОЯВЛЕНИЕ ПОЛОСАМИ.  pop_screen_present_ltr() была void и нажатие
ГЛОТАЛА: полосы схлопывались, картинка появлялась целиком — и всё,
вызывающий о нажатии не узнавал.  На заставке это выглядело как
«клавиша срабатывает наполовину».  Теперь возвращает признак прерывания,
и он проброшен по маршруту: первый экран истории, титры финала, логотип
между «свадьбой» и титрами.

Везде считается КРОМКА нажатия от входа, как в сценах: клавиша, которой
закончили предыдущий экран, ещё зажата, и принимать её за новое нажатие
нельзя — иначе весь маршрут заставки схлопывался бы сам собой.

F10 — НЕМЕДЛЕННЫЙ ВЫХОД, откуда угодно.  Проверка стоит в kbd_idle(), а
этот хук висит на gfx_wait_vsync, то есть вызывается везде, где программа
ждёт кадр: заставка, титры, fade, проявление полосами, меню, игра.  Одна
точка вместо десятка по циклам ожидания.  Флаг pop_quit_req резидентный —
взводится и читается без трамплина из любого банка.  Проверка в НАЧАЛЕ
витка автомата обязательна: заставку прерывает любая клавиша, и без неё
F10 успевал уронить программу в загрузку уровня перед закрытием.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 12:49:01 +03:00
parent 31b82661eb
commit 808c2a5349
9 changed files with 96 additions and 35 deletions
+15 -2
View File
@@ -119,9 +119,16 @@ uint8_t pop_menu_request;
/* Обёртка ради типа: хук — void(*)(void), а kbd_raw_poll возвращает
* «было ли что вычерпано». Приводить указатель кастом не хочется. */
/* F10 (PS/2 set 2 — 0x09): немедленный выход. Проверяем ЗДЕСЬ, а не в
* каждом цикле ожидания: idle-хук висит на gfx_wait_vsync, то есть
* вызывается везде, где программа ждёт кадр — заставка, титры, fade,
* проявление полосами, меню, игра. Одна точка вместо десятка. */
#define KBD_KEY_F10 0x09
static void kbd_idle(void)
{
kbd_raw_poll();
if (kbd_raw_down(KBD_KEY_F10)) pop_quit_req = 1;
}
/* seq_2_stand (types.h seqids) — Kid стоит, ждёт ввода. */
@@ -282,6 +289,12 @@ int main(void)
for (;;) {
uint8_t is_demo;
/* F10 в любой точке — выходим, не начиная следующий маршрут. Проверка
* стоит В НАЧАЛЕ витка: заставку и титры прерывает ЛЮБАЯ клавиша (это
* штатный «пропустить в игру»), и без этой строки F10 успел бы уронить
* нас в загрузку уровня перед тем, как программа закроется. */
if (pop_quit_req) break;
/* Title -> intro -> demo — три самостоятельных состояния. Сцены не
* вызывают gameplay рекурсивно: после каждого return следующий маршрут
* выбирается только pop_app_dispatch(). */
@@ -364,7 +377,7 @@ int main(void)
demo_new_game = 0;
demo_finished = 0;
while (!quit && (pop_app_state == POP_APP_PLAYING ||
while (!quit && !pop_quit_req && (pop_app_state == POP_APP_PLAYING ||
pop_app_state == POP_APP_DEMO)) {
PROF(2); /* ввод + heal */
@@ -926,7 +939,7 @@ int main(void)
if (is_demo && demo_finished) break;
}
if (quit) break;
if (quit || pop_quit_req) break;
/* Restart Game завершает только игровой цикл. Следующая итерация
* верхнего автомата начинает title/intro с самого первого экрана. */
if (pop_app_state == POP_APP_TITLE) continue;