Files
Sprinter-SDCC/applications/SprPoP/src/pop_pal.c
T
snark13 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>
2026-08-27 12:12:28 +03:00

134 lines
4.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_pal.c — владелец порядка «load logical palette -> apply brightness».
*
* Снимок физически хранит pop_ui (в хвосте FONT.ATL), потому что только тот
* модуль владеет страницей шрифта. Здесь остаётся политика: kid.pal всегда
* дополняют живые слоты тайлсета и Тени, а file-load никогда не считается
* показом яркого кадра сам по себе.
*/
#include <stdint.h>
#include <graphics.h>
#include <gfx.h>
#include "pop_bg.h"
#include "pop_shadow.h"
#include "pop_guard.h"
#include "pop_pal.h"
#include "pop_ui.h" /* POP_COL_OUTSIDE */
static void pal_file_load(const char *path, const char *fallback)
{
if (gfx_pal_fload(0, path) < 0) gfx_pal_fload(0, fallback);
gfx_pal_sync();
pop_ui_palette_snapshot();
}
void pop_pal_black(void) __banked
{
pop_ui_palette_black();
}
void pop_pal_snapshot(void) __banked
{
pop_ui_palette_snapshot();
}
void pop_pal_apply(uint8_t fade) __banked
{
pop_ui_palette_dim(fade, 0);
}
void pop_pal_fade_out(uint8_t steps) __banked
{
pop_ui_fade_out(steps);
}
void pop_pal_fade_in(uint8_t steps) __banked
{
pop_ui_fade_in(steps);
}
uint8_t pop_pal_fade_out_skip(uint8_t steps) __banked
{
return pop_ui_fade_out_skip(steps);
}
uint8_t pop_pal_fade_in_skip(uint8_t steps) __banked
{
return pop_ui_fade_in_skip(steps);
}
/* Слот «вне игрового поля» (POP_COL_OUTSIDE) — всегда ЧЁРНЫЙ.
*
* Это ещё один ДИНАМИЧЕСКИЙ слот поверх файловой палитры: kid.pal содержит
* все 256 записей и кладёт в единицу свой цвет, а нам она нужна чёрной —
* иначе борта и полоса HP станут цветными. Ставим после каждого
* file-load, рядом с тайлсетом/Тенью/соперником (см. pop_pal_game_load). */
void pop_pal_outside_apply(void) __banked
{
gfx_pal_set(0, POP_COL_OUTSIDE, 0, 0, 0);
gfx_pal_set(1, POP_COL_OUTSIDE, 0, 0, 0);
}
void pop_pal_flash_white(uint8_t on) __banked
{
uint8_t color = on ? 255 : 0;
gfx_pal_set(0, 0, color, color, color);
gfx_pal_set(1, 0, color, color, color);
}
void pop_pal_menu_dim(uint8_t fade) __banked
{
pop_ui_palette_dim(fade, 1);
}
void pop_pal_game_load(void) __banked
{
pal_file_load("KID\\kid.pal", "a:\\kid.pal");
/* kid.pal содержит все 256 записей и намеренно затирает эти три
* динамических диапазона (тайлсет, Тень, набор соперника).
* Восстановить их надо ДО snapshot. */
pop_bg_pal_apply();
pop_shadow_pal_apply();
pop_guard_pal_apply();
pop_pal_outside_apply();
pop_ui_palette_snapshot();
}
void pop_pal_level_load(uint8_t full) __banked
{
if (full) {
pop_pal_game_load();
return;
}
/* При обычной границе уровня меняются только env/wall и набор соперника. */
pop_bg_pal_apply();
pop_guard_pal_apply();
pop_pal_outside_apply();
pop_ui_palette_snapshot();
}
void pop_pal_title_load(void) __banked
{
pal_file_load("TITLE\\title.pal", "a:\\title.pal");
}
/* ЕДИНСТВЕННОЕ ОТЛИЧИЕ ФИНАЛА ОТ ИНТРО — цвет фона текстовой рамки.
* load_title_images(bgcolor) SDLPoP красит его в #100060 на титрах и в
* #800000 в end_sequence (seg001:586); у нас фон запечён отдельным
* индексом POP_PAL_STORY_BG именно ради этой подмены. Она делается ПОСЛЕ
* файла и до нового снимка — как тайлсет/Тень в pop_pal_game_load. */
void pop_pal_story_load(uint8_t ending) __banked
{
pal_file_load("PV\\story.pal", "a:\\story.pal");
if (!ending) return;
gfx_pal_set(0, POP_PAL_STORY_BG, 0x80, 0, 0);
gfx_pal_set(1, POP_PAL_STORY_BG, 0x80, 0, 0);
pop_ui_palette_snapshot();
}
void pop_pal_pv_load(void) __banked
{
pal_file_load("PV\\pv.pal", "a:\\pv.pal");
}