Files
Sprinter-SDCC/applications/PoP/roomtest/pop_demo.c
T
snark13 47a4b084c4 Меню, статус-строка и оболочка игры: title/intro/cutscene/HoF, POP.CFG, палитры
Эта сессия (меню + текст в служебных полосах):

* Меню: рамка выделения считается от силуэта текста (SEL_PAD сверху и
  снизу), а не «на глаз»; все экраны центрируются в игровых 200 строках
  (UI_CENTER_TOP/UI_CENTER_FIELD) и в них помещаются; Enter и Space —
  равноправные клавиши действия (ui_action_down).
* Settings: убраны SHOW SPRINTER SCREEN и BACK, добавлены DEBUG BAR и
  ABOUT.  About показывает тот же текст, что стартовый Sprinter screen,
  минус строка про клавиши — общий about_text(), чтобы экраны не
  разъехались.  CONTROLS собирается таблицей и центрируется по
  фактическому числу строк.
* GAME PAUSED переехала в нижнюю статус-строку, как в оригинале
  (SDLPoP rect_bottom_text = {193,70,202,250}): это состояние программы,
  а не пункт меню.  POP_HP_Y вынесен в pop_cdraw.h — полосу делят два
  модуля.
* pop_status.c (банк 9) — текст в обеих служебных полосах.  Нижняя:
  порт display_text_bottom + таймера (QUICKSAVE/QUICKLOAD/SOUND ON/OFF,
  24 тика).  Верхняя отладочная переведена с палочек на текст
  «Level ##, Room ##, Speed: …, Sound: …, Immortal #» малым шрифтом, с
  своим форматированием чисел (без printf и без деления).
  Заявка сообщения — запись одного байта pop_status_msg: резидент W1/W2
  не растёт, весь рендер в банке.  Бюджет после правок не изменился
  (_CODE 23981, куча 267 Б).
* Цена вывода: блит глифа ~4,6 тыс. тактов независимо от размера, поэтому
  всё change-driven, отладочная строка перерисовывается ПО ПОЛЯМ, пробелы
  не блитятся вовсе, а вход в комнату заливает только игровое поле
  (pop_screen_fill_field) — борта от комнаты к комнате не меняются.
* Интро: в PV-сцене зазвучали пропавшие эффекты оригинала — закрытие
  ворот (4) и открытие двери покоев (51), из которой входит Джафар.
* docs/status_line_text.md — полная инвентаризация ВСЕХ текстов SDLPoP в
  статус-строке: геометрия, семантика text_time_total как идентификатора
  сообщения, мигание, рестарт по истечении 36/288.

Вместе с этим выкладывается накопленная работа по оболочке полной игры:
автомат состояний (pop_app), title, intro/PV и cutscene, attract-demo,
Hall of Fame, глобальный таймер, настройки и POP.CFG, модуль палитр и
fade, звуковой набор, host-тесты на новые швы.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 13:58:36 +03:00

74 lines
3.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_demo.c — воспроизведение attract-demo SDLPoP, банк 9 (FG7).
*
* Это не отдельная физика и не сценарные телепорты. Таблица custom->demo_moves
* подаёт ровно те же control_* в pop_ctrl_auto_move(), через которые идут
* игрок и автоконтроль персонажей. Поэтому демо проверяет настоящий маршрут
* level 0, а не его нарисованную имитацию.
*/
#include <stdint.h>
#include <kbd_raw.h>
#include "pop_ctrl.h"
#include "pop_guard.h"
#include "pop_map.h" /* hitp_curr — смерть demo имеет приоритет над AI */
#include "pop_demo.h"
typedef struct {
uint8_t time;
int8_t move;
} demo_move_t;
/* data.h SDLPoP: демо пробегает уровень 0 до комнаты 24. Последний -1
* означает «больше не менять уже поданный control_*», а не ввод. */
static const demo_move_t demo_moves[] = {
{0x00, 0}, {0x01, 1}, {0x0D, 0}, {0x1E, 1}, {0x25, 5},
{0x2F, 0}, {0x30, 1}, {0x41, 0}, {0x49, 2}, {0x4B, 0},
{0x63, 2}, {0x64, 0}, {0x73, 5}, {0x80, 6}, {0x88, 3},
{0x9D, 7}, {0x9E, 0}, {0x9F, 1}, {0xAB, 4}, {0xB1, 0},
{0xB2, 1}, {0xBC, 0}, {0xC1, 1}, {0xCD, 0}, {0xE9, -1},
/* do_auto_moves читает moves[demo_index] ещё после сдвига индекса.
* Это недостижимая метка из data.h, не команда: она держит индекс в
* границах, пока demo_time доходит до 0xFE. */
{0xFF, -2}
};
static uint8_t demo_time;
static uint8_t demo_index;
void pop_demo_begin(void) __banked
{
demo_time = 0;
demo_index = 0;
}
uint8_t pop_demo_tick(void) __banked
{
uint8_t index;
int8_t move;
/* Урон мечом сводится ПОСЛЕ этого вызова в предыдущем игровом кадре.
* На следующем тике HP уже ноль, но pop_kid_dead ещё не поднят: обычный
* pop_ctrl_tick делает это в ctrl_kid_death(), а demo обходит его своим
* AI. Без этого гарда AI снова управлял мёртвым Кидом, возвращал его в
* стойку и страж убивал его по кругу. Attract-demo при смерти кончается;
* текущий главный цикл ещё дорисует один последний кадр и уйдёт в title. */
if (hitp_curr == 0) return 1;
/* do_demo(): в бою запись времени/кнопок стоит, Кидом управляет тот же
* combat AI, что стражами, но с отдельным skill 10. */
if (pop_demo_kid_ai()) return 0;
if (demo_time >= 0xFE) return 1;
++demo_time;
index = demo_index;
if (demo_moves[index].time <= demo_time) ++demo_index;
else index = (uint8_t)(demo_index - 1);
move = demo_moves[index].move;
pop_ctrl_auto_move(move);
return (uint8_t)(demo_time >= 0xFE);
}
uint8_t pop_demo_user_input(void) __banked
{
return kbd_raw_any_down();
}