Меню, статус-строка и оболочка игры: 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>
This commit is contained in:
@@ -35,6 +35,11 @@ MEMORY ?= huge # small-раскладка + банки кода в W
|
||||
# ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том
|
||||
# же ALLOCS — иначе сравниваются не правки, а уровни оптимизации.
|
||||
ALLOCS ?= 3000
|
||||
# Build info не хранится вручную в C: ID и дата извлекаются Make из текущего
|
||||
# commit. Переопределения удобны для воспроизводимой release-сборки.
|
||||
BUILD_ID ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo dev)
|
||||
BUILD_DATE ?= $(shell git log -1 --format=%cs 2>/dev/null || echo unknown)
|
||||
BUILD_FLAGS := -DPOP_BUILD_ID=\"$(BUILD_ID)\" -DPOP_BUILD_DATE=\"$(BUILD_DATE)\"
|
||||
# Единственный список банковых исходников: из него строятся И ключи
|
||||
# sprinter-cc, И зависимости roomtest.exe. Раньше эти списки жили отдельно,
|
||||
# поэтому добавленные pop_shadow.c/pop_sfx_cold.c компилировались, но make не
|
||||
@@ -49,8 +54,20 @@ BANK7_SRCS := pop_room.c pop_redraw.c
|
||||
BANK8_SRCS := roomtest_cold.c pop_level_cold.c pop_kboot.c pop_guard_cold.c \
|
||||
pop_shadow.c pop_sfx_cold.c pop_qsave.c pop_qsave_coldio.c \
|
||||
pop_level_qsave.c
|
||||
# Банк 9 — оболочка: menu/settings/config/font, автомат, global timer,
|
||||
# title, attract-demo и таблица рекордов. Здесь остаются небольшие редкие
|
||||
# верхнеуровневые точки входа, но не рендеры крупных заставок.
|
||||
BANK9_SRCS := pop_menu.c pop_status.c pop_config.c pop_app.c pop_timer.c pop_ui.c pop_title.c pop_demo.c \
|
||||
pop_flow.c pop_hof.c
|
||||
# Банк 10 — единый владелец экранных палитр/fade. Он намеренно отделён от UI:
|
||||
# его будут вызывать и игровой lifecycle, и все cutscene-ветки.
|
||||
BANK10_SRCS := pop_pal.c
|
||||
# Банк 11 — тяжёлая кинематика заставок: интерпретатор сценария и renderer
|
||||
# story/PV. Так анимации не вытесняют menu/config из банка оболочки.
|
||||
BANK11_SRCS := pop_cutscene.c pop_intro.c
|
||||
BANKED_SRCS := $(BANK1_SRCS) $(BANK2_SRCS) $(BANK3_SRCS) $(BANK4_SRCS) \
|
||||
$(BANK5_SRCS) $(BANK6_SRCS) $(BANK7_SRCS) $(BANK8_SRCS)
|
||||
$(BANK5_SRCS) $(BANK6_SRCS) $(BANK7_SRCS) $(BANK8_SRCS) \
|
||||
$(BANK9_SRCS) $(BANK10_SRCS) $(BANK11_SRCS)
|
||||
BANK_FLAGS := $(foreach f,$(BANK1_SRCS),--bank 1=$(f)) \
|
||||
$(foreach f,$(BANK2_SRCS),--bank 2=$(f)) \
|
||||
$(foreach f,$(BANK3_SRCS),--bank 3=$(f)) \
|
||||
@@ -58,9 +75,12 @@ BANK_FLAGS := $(foreach f,$(BANK1_SRCS),--bank 1=$(f)) \
|
||||
$(foreach f,$(BANK5_SRCS),--bank 5=$(f)) \
|
||||
$(foreach f,$(BANK6_SRCS),--bank 6=$(f)) \
|
||||
$(foreach f,$(BANK7_SRCS),--bank 7=$(f)) \
|
||||
$(foreach f,$(BANK8_SRCS),--bank 8=$(f))
|
||||
$(foreach f,$(BANK8_SRCS),--bank 8=$(f)) \
|
||||
$(foreach f,$(BANK9_SRCS),--bank 9=$(f)) \
|
||||
$(foreach f,$(BANK10_SRCS),--bank 10=$(f)) \
|
||||
$(foreach f,$(BANK11_SRCS),--bank 11=$(f))
|
||||
EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) \
|
||||
$(BANK_FLAGS) $(PROF_FLAGS)
|
||||
$(BANK_FLAGS) $(PROF_FLAGS) $(BUILD_FLAGS)
|
||||
# Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по
|
||||
# умолчанию, пока идёт работа с производительностью; make PROF=0 выключает.
|
||||
# Каждая фаза кадра красит бордюр в свой цвет, высота полосы на скриншоте
|
||||
@@ -70,29 +90,29 @@ PROF_FLAGS := -DPROF_BORDER=$(PROF)
|
||||
# Стартовый уровень (отладка): make LEVEL=9 — начать сразу с девятого.
|
||||
# Дефолт держим на отлаживаемом сейчас уровне; для «настоящей» игры — LEVEL=1.
|
||||
# Константа объявлена в pop_tune.h (её видят обе половины главного цикла).
|
||||
LEVEL ?= 11
|
||||
LEVEL ?= 1
|
||||
PROF_FLAGS += -DFIRST_LEVEL=$(LEVEL)
|
||||
# Стартовая КОМНАТА и позиция Кида в ней (отладка): make ROOM=15 POS=2 —
|
||||
# начать прямо в целевой комнате оптимизации, минуя проход уровня. POS —
|
||||
# тайл 0..29, то есть row*10+col. Дефолт — сцена 11/15 (Кид в 0,2), по
|
||||
# которой сняты замеры в docs/perf_l11_room15.md. make ROOM= (пусто)
|
||||
# возвращает штатный старт из данных уровня.
|
||||
ROOM ?= 15
|
||||
ROOM ?=
|
||||
POS ?= 2
|
||||
ifneq ($(strip $(ROOM)),)
|
||||
PROF_FLAGS += -DDBG_START_ROOM=$(ROOM) -DDBG_START_POS=$(POS)
|
||||
endif
|
||||
EXTRA_SRCS := pop_vflip.c pop_pace.c pop_sfx.c pop_state.c pop_draw.c pop_tile.c pop_kid.c pop_level.c pop_geom.c pop_guard.c pop_qsave_io.c
|
||||
EXTRA_SRCS := pop_vflip.c pop_pace.c pop_sfx.c pop_state.c pop_draw.c pop_tile.c \
|
||||
pop_kid.c pop_level.c pop_geom.c pop_guard.c pop_qsave_io.c
|
||||
|
||||
BG_DIR := $(CURDIR)/../poc/res/bg
|
||||
KID_DIR := $(CURDIR)/../poc/res/kid
|
||||
LVL_DIR := $(CURDIR)/../SDLPoP/data/LEVELS
|
||||
# ВСЕ уровни игры (res2001..res2015, по 2305 Б = 34 КБ на всех): переход
|
||||
# уровень→уровень и чит Shift+L требуют, чтобы файл следующего лежал на
|
||||
# диске. res2000 — демо-уровень, в скоуп не входит.
|
||||
LVL_NUMS := 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
|
||||
# res2000 — attract-demo; res2001..res2014 — штатная игра. res2015/copy
|
||||
# protection намеренно не пакуется и не существует в маршруте загрузчика.
|
||||
LVL_NUMS := 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
|
||||
LVL_DATA := $(foreach n,$(LVL_NUMS),$(LVL_DIR)/res20$(n).bin)
|
||||
# ДВА тайлсета: pop_* — подземелье (уровни 1-3, 7-9, 12, 13, 15),
|
||||
# ДВА тайлсета: pop_* — подземелье (уровни 1-3, 7-9, 12, 13),
|
||||
# pal_* — дворец (4-6, 10, 11, 14). Раскладка id у них общая, различаются
|
||||
# файлы и палитра тайлсета (*tile.pal, 32 записи). chtab_1 (pop_pot.atl:
|
||||
# пламя, меч-предмет, зелья) от набора не зависит — один на оба.
|
||||
@@ -148,15 +168,50 @@ SHADOW_DATA := $(foreach n,0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||
# ЗВУКОВЫЕ ЭФФЕКТЫ — оригинальная оцифровка, приведённая к частоте CBL
|
||||
# (10 937,5 Гц, 8 бит моно). 8 страниц по 16 КБ; см. ../docs/sound_plan.md.
|
||||
SND_DIR := $(CURDIR)/../poc/res/sound
|
||||
SND_DATA := $(foreach n,0 1 2 3 4 5 6 7,$(SND_DIR)/s$(n).bin)
|
||||
# Число файлов задаёт упаковщик (POP_SND_PAGES в pop_sound_tbl.h): с
|
||||
# 2026-08-25 звук не режется по границе страницы, поэтому страниц стало 10.
|
||||
# Список ОБЯЗАН совпадать: недостающий файл — это молча пропавшие эффекты.
|
||||
SND_DATA := $(foreach n,0 1 2 3 4 5 6 7 8 9,$(SND_DIR)/s$(n).bin)
|
||||
|
||||
# UI: два исходных шрифта SDLPoP в одном EMM-атласе. Файл короче страницы:
|
||||
# хвост использует menu для временного snapshot палитры (без расхода W2).
|
||||
FONT_DIR := $(CURDIR)/../poc/res/font
|
||||
FONT_ATL := $(FONT_DIR)/font.atl
|
||||
FONT_DATA := $(FONT_ATL)
|
||||
# TITLE: четыре готовые композиции `show_title()` до story/intro. Каждая
|
||||
# режется на пять полос высотой <=49 px, так что runtime держит ровно одну
|
||||
# EMM-страницу во время рисования, а не отдельный framebuffer.
|
||||
TITLE_DIR := $(CURDIR)/../poc/res/title
|
||||
TITLE_SCENES := 0 1 2 3
|
||||
TITLE_PARTS := 0 1 2 3 4
|
||||
TITLE_DATA := $(TITLE_DIR)/title.pal \
|
||||
$(foreach s,$(TITLE_SCENES),$(foreach p,$(TITLE_PARTS),$(TITLE_DIR)/t$(s)_$(p).atl))
|
||||
# PV/INTRO: story и fallback-стадии режутся на полосы. Для настоящего PV
|
||||
# intro есть ещё чистый фон `b0_*` и шесть <=16K actor-атласов: они остаются
|
||||
# в EMM на время сцены, а не перечитывают полный 320x200 кадр с HDD.
|
||||
PV_DIR := $(CURDIR)/../poc/res/pv
|
||||
PV_STORY := 0 1 2 3 4
|
||||
PV_SCENES := 0 1 2 3 4 5 6 7
|
||||
PV_PARTS := 0 1 2 3 4
|
||||
PV_ANIM := $(foreach p,$(PV_PARTS),$(PV_DIR)/b0_$(p).atl) \
|
||||
$(PV_DIR)/a0.atl $(PV_DIR)/a1.atl $(PV_DIR)/a2.atl \
|
||||
$(PV_DIR)/j0.atl $(PV_DIR)/j1.atl \
|
||||
$(PV_DIR)/j2.atl $(PV_DIR)/h0.atl $(PV_DIR)/t0.atl
|
||||
PV_DATA := $(PV_DIR)/story.pal $(PV_DIR)/pv.pal \
|
||||
$(foreach s,$(PV_STORY),$(foreach p,$(PV_PARTS),$(PV_DIR)/s$(s)_$(p).atl)) \
|
||||
$(foreach s,$(PV_SCENES),$(foreach p,$(PV_PARTS),$(PV_DIR)/p$(s)_$(p).atl)) \
|
||||
$(PV_ANIM)
|
||||
|
||||
EXTRA_DATA := $(BG_DATA) $(KID_DATA) $(KID_BIN) $(GUARD_DATA) $(SKEL_DATA) \
|
||||
$(VIZIER_DATA) $(SHADOW_DATA) $(SND_DATA) $(LVL_DATA)
|
||||
$(VIZIER_DATA) $(SHADOW_DATA) $(SND_DATA) $(FONT_DATA) $(TITLE_DATA) $(PV_DATA) $(LVL_DATA)
|
||||
# Образ HDD для MAME: ресурсы раскладываются ПО КАТАЛОГАМ (8.3, как в DSS),
|
||||
# чтобы корень диска не зарастал десятками .atl.
|
||||
# BG\ — фон (env/wall/fore/pot)
|
||||
# KID\ — персонаж (kid0..27, палитра, меч, таблицы анимации)
|
||||
# GUARD\ — стражи (появятся здесь же)
|
||||
# FONT\ — текстовый атлас pause/settings UI
|
||||
# TITLE\ — нарезанные композиции оригинальной заставки
|
||||
# PV\ — story и Princess/Jaffar intro, нарезанные полосами
|
||||
# LEVELS\ — уровни
|
||||
HDD_PACK_ARGS := $(EXAMPLE).exe \
|
||||
$(foreach f,$(BG_DATA),BG:$(f)) \
|
||||
@@ -166,6 +221,9 @@ HDD_PACK_ARGS := $(EXAMPLE).exe \
|
||||
$(foreach f,$(VIZIER_DATA),VIZIER:$(f)) \
|
||||
$(foreach f,$(SHADOW_DATA),SHADOW:$(f)) \
|
||||
$(foreach f,$(SND_DATA),SND:$(f)) \
|
||||
$(foreach f,$(FONT_DATA),FONT:$(f)) \
|
||||
$(foreach f,$(TITLE_DATA),TITLE:$(f)) \
|
||||
$(foreach f,$(PV_DATA),PV:$(f)) \
|
||||
$(foreach f,$(LVL_DATA),LEVELS:$(f))
|
||||
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
@@ -185,6 +243,9 @@ SHADOW_STAMP := $(RESOURCE_STAMP_DIR)/shadow
|
||||
SOUND_STAMP := $(RESOURCE_STAMP_DIR)/sound
|
||||
KID_STAMP := $(RESOURCE_STAMP_DIR)/kid
|
||||
KID_BIN_STAMP := $(RESOURCE_STAMP_DIR)/kid-bin
|
||||
FONT_STAMP := $(RESOURCE_STAMP_DIR)/font
|
||||
TITLE_STAMP := $(RESOURCE_STAMP_DIR)/title
|
||||
PV_STAMP := $(RESOURCE_STAMP_DIR)/pv
|
||||
|
||||
$(RESOURCE_STAMP_DIR):
|
||||
mkdir -p $@
|
||||
@@ -237,14 +298,62 @@ $(KID_BIN_STAMP): $(TC)/pop_extract_kid_data.py | $(RESOURCE_STAMP_DIR)
|
||||
kid_data.h $(KID_BIN): $(KID_BIN_STAMP)
|
||||
@test -f $@ || { $(MAKE) -B $(KID_BIN_STAMP); test -f $@; }
|
||||
|
||||
$(FONT_STAMP): $(PROJ_ROOT)/toolchain/pop_extract_font.py \
|
||||
$(CURDIR)/../SDLPoP/src/menu.c $(CURDIR)/../SDLPoP/src/seg009.c | $(RESOURCE_STAMP_DIR)
|
||||
cd $(PROJ_ROOT) && python3 toolchain/pop_extract_font.py
|
||||
touch $@
|
||||
$(FONT_ATL) pop_font.h: $(FONT_STAMP)
|
||||
@test -f $@ || { $(MAKE) -B $(FONT_STAMP); test -f $@; }
|
||||
|
||||
$(TITLE_STAMP): $(PROJ_ROOT)/toolchain/pop_pack_title.py \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res51.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res52.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res53.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res54.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res55.png | $(RESOURCE_STAMP_DIR)
|
||||
cd $(PROJ_ROOT) && python3 toolchain/pop_pack_title.py
|
||||
touch $@
|
||||
$(TITLE_DATA): $(TITLE_STAMP)
|
||||
@test -f $@ || { $(MAKE) -B $(TITLE_STAMP); test -f $@; }
|
||||
|
||||
$(PV_STAMP): $(PROJ_ROOT)/toolchain/pop_pack_intro.py \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res41.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res42.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res43.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res44.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res45.png \
|
||||
$(CURDIR)/../SDLPoP/data/TITLE/res51.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res801.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res805.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res816.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res851.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res870.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res901.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res920.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res951.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res953.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res959.png \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res981.png \
|
||||
$(foreach n,802 803 804 806 807 808 809 810 811 812 813 814 815 817,$(CURDIR)/../SDLPoP/data/PV/res$(n).png) \
|
||||
$(foreach n,852 853 854 855 856 857 858 859 860 861 862 863 864,$(CURDIR)/../SDLPoP/data/PV/res$(n).png) \
|
||||
$(CURDIR)/../SDLPoP/data/PV/res952.png \
|
||||
$(foreach n,151 152 153 154 155 156 157 158 159,$(CURDIR)/../SDLPoP/data/PRINCE/res$(n).png) | $(RESOURCE_STAMP_DIR)
|
||||
cd $(PROJ_ROOT) && python3 toolchain/pop_pack_intro.py
|
||||
touch $@
|
||||
$(PV_DATA): $(PV_STAMP)
|
||||
@test -f $@ || { $(MAKE) -B $(PV_STAMP); test -f $@; }
|
||||
|
||||
# Явные цели позволяют собирать ресурсы без `make -B`, который по смыслу
|
||||
# принудительно пересобирает также libc, libbgi и само приложение.
|
||||
resources-bg: $(BG_DATA)
|
||||
resources-kid: $(KID_DATA) $(KID_BIN)
|
||||
resources-actors: $(GUARD_DATA) $(SKEL_DATA) $(VIZIER_DATA) $(SHADOW_DATA)
|
||||
resources-sound: $(SND_DATA)
|
||||
resources-font: $(FONT_DATA)
|
||||
resources-title: $(TITLE_DATA)
|
||||
resources-pv: $(PV_DATA)
|
||||
resources-levels: $(LVL_DATA)
|
||||
resources: resources-bg resources-kid resources-actors resources-sound resources-levels
|
||||
resources: resources-bg resources-kid resources-actors resources-sound resources-font resources-title resources-pv resources-levels
|
||||
resources-rebuild:
|
||||
$(MAKE) -B resources
|
||||
|
||||
@@ -263,10 +372,10 @@ hdd: resources
|
||||
# широкий: цена лишней полной сборки ниже риска получить stale-бинарник.
|
||||
LOCAL_HEADERS := $(wildcard *.h)
|
||||
$(EXAMPLE).exe: Makefile $(PROJ_ROOT)/app.mk $(BANKED_SRCS) $(LOCAL_HEADERS) \
|
||||
$(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
||||
$(BG_DATA) $(KID_DATA) $(KID_BIN) $(FONT_DATA) $(TITLE_DATA) $(PV_DATA) $(LVL_DATA)
|
||||
|
||||
clean-resources:
|
||||
rm -rf $(RESOURCE_STAMP_DIR)
|
||||
|
||||
.PHONY: resources resources-rebuild resources-bg resources-kid resources-actors relink \
|
||||
resources-sound resources-levels clean-resources
|
||||
resources-sound resources-font resources-title resources-pv resources-levels clean-resources
|
||||
|
||||
Reference in New Issue
Block a user