879f2bae319a915d73c3a422bc525932f8ff7ba0
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7377bf6a2c |
SprPoP: заставка и музыка сразу после запуска, а не через несколько секунд
От запуска до проявления титула проходило ~3 с чёрного экрана в тишине: pop_boot читал ВСЕ ресурсы игры до первого пикселя, а pop_title_show перед fade_in вычитывал целиком трек заставки (248 КБ). Старт разбит на три фазы (sprpop_cold.c): - pop_boot() — настройки, POP.CFG, графика, чёрный экран, FONT.ATL; - pop_boot_sound() — snd.idx + ОДНА страница snd.arc, индекс музыки, CBL; - pop_boot_rest() — остальные страницы звука, kid.ani, Тень, атласы Кида; идемпотентно, между кусками доливает трек. pop_title_show теперь: fade_in -> pop_boot_sound -> pop_music_stream(54) -> pop_boot_rest под стоящим титулом. Порядок «сначала fade_in, потом тема» сохранён как у show_title (seg000.c:1981). Первый такт заставки укорочен на фактически потраченное время (часы насоса 85,4 Гц -> кадры луча сдвигами), иначе сцена уехала бы относительно музыки. title_wait доливает трек по полстраницы за кадр. Музыка играет с ПЕРВОЙ страницы: pop_music_stream уже был (игровые джинглы), кольцо won не понадобилось — m54 это 16 страниц из 20 доступных. Звук поднимается в два приёма (pop_sfx_init_begin/finish): насосу для тишины нужен ровно один блок, и упаковщик обязан класть его первым блоком страницы 0 (tools/pop_idx.py) — значит для открытия CBL хватает ОДНОЙ страницы (33 мс вместо 440). Пока набор неполон, pop_sfx_play пропускает эффекты; заявки на музыку проходят. Четыре загрузки из boot УБРАНЫ, а не отложены: атлас фона, страж, уровень 1 и pop_pal_game_load — их и так делает pop_level_switch на входе в любой уровень (а pop_new_game_load ещё и палитру перед ним), и оба маршрута в игру, LEVEL_LOAD и DEMO, упираются в него. Это ~0,77 с на ровном месте. Так же устроен оригинал: init_game_main до заставки читает только меч, пламя, звуки и палитры, а chtab_5/6/7 грузит load_lev_spr на старте уровня. Страховка на случай пропуска заставки в первую секунду — идемпотентный pop_boot_rest() в начале pop_new_game_load и pop_level_switch. FONT.ATL остаётся в минимальной фазе, и это не про шрифт: снимок палитры физически лежит в хвосте его страницы (pop_ui.c), а вся машинерия яркости начинается с `if (!font_ready) return`. С отложенным шрифтом заставка возникала разом на полной яркости — поймано пользователем. Проверено в MAME: титул виден сразу и проявляется полосами, pop_mus_left убывает (трек стримится), pop_snd_pages=10 (набор дочитался), цепочка титул -> интро -> пропуск -> уровень 1 работает. Банк 8: 95,5 % (732 Б). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DSYUpuaQpKr48kBav2iiV4 |
||
|
|
2349481b86 |
SprPoP: звуковые эффекты без перелинковки — раскладка уехала на диск
Часть II плана music_runtime_index_plan.md (SI0..SI4). gen/pop_sound_tbl.h БОЛЬШЕ НЕ ГЕНЕРИРУЕТСЯ: раскладка набора читается из SND/snd.idx (формат PSI1, писатель и разборщик — tools/pop_idx.py, 22 теста в make test-tools). Один и тот же sprpop.exe работает с набором SDLPoP (9 страниц) и MSDOS (10) — sha256 бинарника при смене набора не меняется. Заодно умолчание источника эффектов переведено на SDLPoP (SND_SRC=sdlpop): сборка обязана работать без оригинального дистрибутива DOS. У кого он есть, включает лучший набор явно — make SND_SRC=msdos (там полнее оцифровка: в SDLPoP звук 48 spiked пустой). Устройство: pop_snd_tbl/pop_snd_page/pop_snd_pages — резидентные данные (pop_snd_data.c), тип и инварианты — рукописный pop_snd_tbl.h. Записи читаются ОДНИМ read прямо в таблицу, поэтому sizeof(pop_snd_ent_t) == 5 стало частью дискового контракта: проверяется статически и полем размера записи в заголовке. POP_SND_PAGES как compile-time размер набора исчез — вместо него POP_SND_MAX_PAGES (вместимость, 16) и runtime pop_snd_pages. Цена: таблица переехала из _CODE в _DATA, суммарный резидент почти не изменился (куча 239 -> 229 Б); банк 8 +601 Б на чтение и валидацию. Валидация не доверяет файлу: заголовок целиком плюс каждая запись (страница, смещение, кратность блоку, непересечение с блоком тишины, выход за последнюю страницу). Последнее считается В БЛОКАХ — байтовый адрес конца не влезает в uint16, а 32-битная арифметика на Z80 дорога. НЕТ ИНДЕКСА — ЭФФЕКТОВ НЕТ, НО МУЗЫКА ИГРАЕТ. Первая версия просто возвращала ошибку, и игра становилась непроходимой: тишину льёт первый блок набора, без набора CBL не открывался, а с ним вставала музыка (её блоки считает тот же насос) — заставка ждала конца трека вечно. Теперь поднимается пустой набор с блоком тишины. Заливается ровно 128 байт и под DI: gfx_w0_page_prepare ставит в страницу IRQ-стабы, и заливка всей страницы затирала их — первое же прерывание давало чёрный экран. Грабли сборки: смена SND_SRC тихо давала неверный результат (sdlpop -> msdos -> sdlpop оставлял чужой набор в assets/packed). Причина не в логике, а в секундной гранулярности mtime. Лечение убирает время из решения: смена варианта сносит stamp'ы своего семейства, а упаковка, сборка архива и копия индекса делаются одним рецептом. То же получила и музыка (MUSIC_FMT). Проверено в MAME: таблица в памяти совпадает с файлом из образа побайтово; один EXE поднимает оба набора; отладочный --order reverse (30 из 31 записей отличаются от штатных) звучит правильно; битый индекс выключает эффекты, не роняя игру; без индекса PV-сцена проходит с музыкой; Ctrl+S работает в обоих режимах. Разбор — docs/sound_plan.md §10. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY |
||
|
|
ea8efdb0fd |
SprPoP: обобщить HDD-сборку и очистить метаданные
Добавить общий каталог назначения для HDD и удалить локальную копию упаковщика.\n\nУбрать устаревшие generated-имена ресурсов, выводить число страниц Kid из kid.arc и ограничить звуковую таблицу горячим модулем.\n\nЗафиксировать планы runtime-индексов музыки и PCM-эффектов. |
||
|
|
31b82661eb |
SprPoP: автономное приложение, выделенное из roomtest
Порт PoP переехал в applications/SprPoP — приложение, которое собирается само: код, оригинальные данные, конверторы ресурсов и сборка внутри одной папки. Наружу знает единственный путь — корень тулчейна (SPRINTER_ROOT, по умолчанию ../..). applications/PoP/roomtest ЗАМОРОЖЕНА и остаётся архивом закрытых задач, багов и исполненных планов. Скопировано из applications/PoP/roomtest@4b74478. Перенос проверен побайтово: собранный sprpop.exe совпал с roomtest.exe того же коммита, все 39 дисковых ресурсов и все 16 генерируемых заголовков — тоже, host- тесты зелёные (15/15). Раскладка: src/ рукописный C (roomtest.c -> sprpop.c) gen/ генерируемые заголовки, в репозитории assets/orig/ оригинальные данные игры, вне репозитория (копирайт) assets/packed/ то, что ложится на диск, в раскладке диска tools/ конверторы; все пути — в одном tools/paths.py build/ выход: exe, каталоги ресурсов, hdd/, промежуточные atl/ Сборка ресурсов: assets/packed и gen — версионируемые ВХОДЫ, а не то, что пересчитывается каждым make. Автоматика построена на ОТСУТСТВИИ файла, а не на таймстемпах: git не хранит времена, и в свежем клоне сравнение по времени превращалось бы в лотерею. Недостающий ресурс или заголовок чинится сам, рекурсивным вызовом в ветку генерации. Музыка собирается из любого из четырёх наборов записей (make music-mp3, music-mt32, ...); набор входит в имя stamp'а, поэтому смена набора сама делает музыку устаревшей. Длины реплик больше не захардкожены: упаковщик печатает их в gen/pop_music_ticks.h, и шкала сцены выражена через них — иначе mt32 (реплики на 6% длиннее) молча ломал катсцену. Тулчейн: в app.mk два обратносовместимых крючка (SRC_DIR/BUILD_DIR), HDD_IMG стал ?=; команда сборки roomtest не изменилась. Корневой make host-tests переключён на SprPoP. Подгонка тайминга катсцены с принцессой (PV_MAGIC_LEAD): сцена render-bound и идёт ~49 тиков/с вместо 60, из-за чего кода реплики приходила раньше молнии. Это обход, а не лечение; разбор с замерами — docs/BUGS_OPEN.md, записи SND-PACE-DEAD, PV-RENDER-BOUND, MUS-LEFT-TEAR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |