/* * pop_app.c — таблица переходов оболочки, БАНК 9 (FG1). * * Модуль не рисует и не выделяет память. Это чистая политика переходов, * поэтому её можно проверять host-тестом без DSS/MAME. Жизненный цикл * ресурсов остаётся у enter/leave соответствующих состояний. */ #include "pop_app.h" pop_app_state_t pop_app_state; void pop_app_reset(void) __banked { pop_app_state = POP_APP_BOOT; } uint8_t pop_app_dispatch(pop_app_event_t event) __banked { pop_app_state_t next = pop_app_state; uint8_t accepted = 0; switch (pop_app_state) { case POP_APP_BOOT: if (event == POP_APP_EV_BOOT_READY) { next = POP_APP_BUILD_INFO; accepted = 1; } break; case POP_APP_BUILD_INFO: if (event == POP_APP_EV_BUILD_DONE) { next = POP_APP_TITLE; accepted = 1; } break; case POP_APP_TITLE: if (event == POP_APP_EV_INTRO_STARTED) { next = POP_APP_INTRO; accepted = 1; } else if (event == POP_APP_EV_DEMO_STARTED) { next = POP_APP_DEMO; accepted = 1; } else if (event == POP_APP_EV_NEW_GAME) { next = POP_APP_LEVEL_LOAD; accepted = 1; } break; case POP_APP_INTRO: if (event == POP_APP_EV_CUTSCENE_FINISHED) { next = POP_APP_DEMO; accepted = 1; } else if (event == POP_APP_EV_NEW_GAME) { next = POP_APP_LEVEL_LOAD; accepted = 1; } break; case POP_APP_DEMO: if (event == POP_APP_EV_DEMO_FINISHED) { next = POP_APP_TITLE; accepted = 1; } else if (event == POP_APP_EV_NEW_GAME) { next = POP_APP_LEVEL_LOAD; accepted = 1; } break; case POP_APP_LEVEL_LOAD: if (event == POP_APP_EV_LEVEL_READY) { next = POP_APP_PLAYING; accepted = 1; } break; case POP_APP_PLAYING: if (event == POP_APP_EV_PAUSE) { next = POP_APP_PAUSE_MENU; accepted = 1; } else if (event == POP_APP_EV_CUTSCENE_STARTED) { next = POP_APP_CUTSCENE; accepted = 1; } else if (event == POP_APP_EV_LEVEL_FINISHED) { next = POP_APP_LEVEL_LOAD; accepted = 1; } else if (event == POP_APP_EV_TIME_EXPIRED) { next = POP_APP_TIME_EXPIRED; accepted = 1; } else if (event == POP_APP_EV_ENDING_STARTED) { next = POP_APP_ENDING; accepted = 1; } else if (event == POP_APP_EV_RESTART_INTRO) { /* start_game() прямо из геймплея: так оригинал уходит в title, * когда игрок не нажал кнопку за 288 тиков после смерти * (seg000:958). Раньше это событие принимал только pause menu. */ next = POP_APP_TITLE; accepted = 1; } break; case POP_APP_PAUSE_MENU: if (event == POP_APP_EV_RESUME) { next = POP_APP_PLAYING; accepted = 1; } else if (event == POP_APP_EV_RESTART_INTRO) { /* Restart Game начинает заново именно title/intro. Сброс новой * игры произойдёт позже общим LEVEL_LOAD после skip/attract. */ next = POP_APP_TITLE; accepted = 1; } break; case POP_APP_CUTSCENE: if (event == POP_APP_EV_CUTSCENE_FINISHED) { next = POP_APP_LEVEL_LOAD; accepted = 1; } break; case POP_APP_TIME_EXPIRED: if (event == POP_APP_EV_CUTSCENE_FINISHED) { next = POP_APP_TITLE; accepted = 1; } break; case POP_APP_ENDING: if (event == POP_APP_EV_ENDING_FINISHED) { /* Таблица рекордов — ХВОСТ end_sequence, а не отдельный экран * по желанию: она же дослушивает победную тему и гасит экран * перед возвратом в начало (seg001:5F1). */ next = POP_APP_HALL_OF_FAME; accepted = 1; } break; case POP_APP_HALL_OF_FAME: if (event == POP_APP_EV_HOF_FINISHED) { next = POP_APP_TITLE; accepted = 1; } break; case POP_APP_QUIT: default: break; } if (event == POP_APP_EV_QUIT && pop_app_state != POP_APP_QUIT) { next = POP_APP_QUIT; accepted = 1; } if (!accepted) return 0; pop_app_state = next; return 1; }