Таблицы анимации Кида: kid_data.bin -> KID\kid.ani

Все ресурсы Кида теперь зовутся kid.*: kid.arc (атласы), kid.pal
(палитра), kid.ani (кадры + seqtbl). Расширение .ani говорит о
содержимом: это не «какие-то данные», а таблица кадров и байткод
последовательностей движения.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 22:02:14 +03:00
parent 7e6b38cca6
commit 0086ac80c2
12 changed files with 21 additions and 21 deletions
+2 -2
View File
@@ -142,7 +142,7 @@ KID_DATA := $(KID_PAGES) $(KID_VPAGES) $(KID_DIR)/kid.pal \
$(KID_DIR)/sword.atl $(KID_DIR)/sword_v.atl
# Таблицы анимации (кадры+seqtbl) — отдельный бинарь в EMM-странице, его
# делает pop_extract_kid_data.py (не упаковщик спрайтов) — своё правило ниже.
KID_BIN := $(KID_DIR)/kid_data.bin
KID_BIN := $(KID_DIR)/kid.ani
# АРХИВ KID. Шестьдесят файлов в одном: замер 2026-08-25 — `open` 51,4 мс
# против 32,6 мс на чтение 16 КБ, то есть на одних только открытиях набор
@@ -150,7 +150,7 @@ KID_BIN := $(KID_DIR)/kid_data.bin
# упаковщик печатает в kid_arc.h (константы ARC_KID_*).
KID_ARC := $(KID_DIR)/kid.arc
# В архив идут только атласы. Палитру читает gfx_pal_fload прямо в
# видеопамять, а kid_data.bin — host-тесты своей файловой заглушкой; ради
# видеопамять, а kid.ani — host-тесты своей файловой заглушкой; ради
# двух файлов заводить обходные пути незачем.
KID_ARC_SRC := $(KID_PAGES) $(KID_VPAGES) $(KID_DIR)/sword.atl \
$(KID_DIR)/sword_v.atl
+2 -2
View File
@@ -16,11 +16,11 @@
/* Смещение данных в странице анимации; ниже 0x100 — ISR-стаб W0. */
#define KD_DATA_OFF 0x100u
extern uint8_t kdat_blk; /* EMM-блок страницы kid_data.bin */
extern uint8_t kdat_blk; /* EMM-блок страницы kid.ani */
extern uint8_t kdat_page; /* её номер (маппится в W0 на время play_seq) */
extern uint8_t kdat_ok; /* данные загружены */
/* Файловый обмен с W3 делает общий резидентный bank_load_file(), поэтому
* оркестратор загрузки kid_data.bin целиком живёт в холодном банке 8. */
* оркестратор загрузки kid.ani целиком живёт в холодном банке 8. */
#endif /* _POP_KID_H */
+2 -2
View File
@@ -9,13 +9,13 @@
#define SEQTBL_BASE 0x196Eu
/* {image, dx, dy, flags, sword}; chtab = sword>>6 (0=kid).
* САМА таблица кадров и seqtbl лежат в kid_data.bin (EMM-
* САМА таблица кадров и seqtbl лежат в kid.ani (EMM-
* страница); здесь только тип и размеры. */
typedef struct { uint8_t image; int8_t dx, dy; uint8_t flags, sword; } kframe;
#define KID_NFRAMES 241
#define KID_SEQTBL_LEN 2310
/* Раскладка kid_data.bin: кадры (KID_NFRAMES*5), затем seqtbl. */
/* Раскладка kid.ani: кадры (KID_NFRAMES*5), затем seqtbl. */
#define KID_BIN_FRAMES_OFF 0
#define KID_BIN_SEQTBL_OFF 1205
/* Таблица кадров СТРАЖА (frame_tbl_guard, seg006:372): индекс
+1 -1
View File
@@ -205,7 +205,7 @@ void pop_guard_free(void) __banked
* ДИАПАЗОН — весь, а не «обычный случай». Отрицательные X реальны:
* obj_x = 2*fwd 116 уходит в минус, как только fwd < 58 (левее
* x_bump[5]), то есть у левой кромки комнаты — это не экзотика. По
* фактическим данным кадров (kid_data.bin: dx Кида −5..+10, стража
* фактическим данным кадров (kid.ani: dx Кида −5..+10, стража
* 2..+10) при x типа uint8_t и render_dx ∈ {140, 0, +140} полный
* диапазон obj_x = −416..695; таблица кроет −448..703 с запасом.
* Деление ниже поэтому недостижимо и оставлено страховкой на случай
+1 -1
View File
@@ -1028,7 +1028,7 @@ static void intro_restore_game_palette(void)
*
* Движок общий с игрой, и это главное: последовательности крутит наш
* play_seq (pop_kid_play/pop_guard_play), кадры принцессы берутся из
* таблицы КАТСЦЕН (kid_data.bin, KID_BIN_CFRAMES_OFF), мышь и Кид — из
* таблицы КАТСЦЕН (kid.ani, KID_BIN_CFRAMES_OFF), мышь и Кид — из
* таблицы Кида, как в оригинале (frame_table_kid общая для kid и mouse).
* Отличается только ОТРИСОВКА: спрайты принцессы лежат в PV-атласах, а
* Кид/мышь — в игровых kid-атласах, поэтому в pv.pal под них отведена
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* pop_kboot.c — ЗАГРУЗКА ресурсов Кида: атласы chtab_2 (kid0..27.atl) и
* страница таблиц анимации (kid_data.bin). БАНК 8.
* страница таблиц анимации (kid.ani). БАНК 8.
*
* Отрабатывает раз за игру (и на выходе — освобождение), поэтому места в
* резиденте W1 не занимает: контракт с интерпретатором — _pop_kid.h, там
+1 -1
View File
@@ -54,7 +54,7 @@ uint8_t kid_npages;
* kid_set_seq / pop_char_set_seq. */
static const uint16_t kid_seq_off[KID_NSEQ] = KID_SEQ_OFF_INIT;
/* ---- Данные анимации в EMM-странице (kid_data.bin) ------------------ *
/* ---- Данные анимации в EMM-странице (kid.ani) ----------------------- *
* Таблица кадров (241*5 Б) и seqtbl (2310 Б) занимали 3.5 КБ в _CODE окна
* W1/W2 — самый дефицитный ресурс. Теперь они лежат в отдельной EMM-
* странице, которая маппится в W0 РОВНО на время play_seq (раз за тик), а
+1 -1
View File
@@ -32,7 +32,7 @@ extern uint8_t pop_next_level;
int pop_kid_load(uint8_t npages) __banked;
/* Данные анимации (таблица кадров + seqtbl) — отдельная EMM-страница
* (kid_data.bin): в _CODE окна W1/W2 они занимали 3.5 КБ. Грузить ДО
* (kid.ani): в _CODE окна W1/W2 они занимали 3.5 КБ. Грузить ДО
* первого kid_init/play_seq. 0 — OK, -1 — ошибка (без них Kid не оживёт).
* Страница маппится в W0 внутри play_seq, раз за тик. */
int pop_kid_data_load(const char *path) __banked;
+2 -2
View File
@@ -897,8 +897,8 @@ int pop_boot(void) __banked
pop_cd_init(); /* метка «фон трогали» — пустые диапазоны */
/* pop_cheats/speed применит pop_settings_apply после pop_sfx_init. */
pop_guard_reset();
if (pop_kid_data_load("KID\\kid_data.bin") != 0) { /* кадры+seqtbl в EMM-странице */
printf("kid_data.bin load failed\n");
if (pop_kid_data_load("KID\\kid.ani") != 0) { /* кадры+seqtbl в EMM-странице */
printf("kid.ani load failed\n");
return -1;
}
pop_guard_load(); /* атласы стража (GUARD\\g0..g4) */
+1 -1
View File
@@ -25,7 +25,7 @@ static uint8_t sc_fg[30];
void sc_init(void)
{
kid_blob_install(); /* таблицы туда, куда смотрит pop_kid */
pop_kid_data_load("KID\\KID_DATA.BIN");
pop_kid_data_load("KID\\KID.ANI");
pop_kid_hp_newgame();
}
@@ -96,19 +96,19 @@ def main():
f.write("#ifndef KID_DATA_H\n#define KID_DATA_H\n#include <stdint.h>\n\n")
f.write("#define SEQTBL_BASE 0x%04Xu\n\n" % SEQTBL_BASE)
# frame table и seqtbl В .h НЕ ПОПАДАЮТ — они уезжают в kid_data.bin
# frame table и seqtbl В .h НЕ ПОПАДАЮТ — они уезжают в kid.ani
# (EMM-страница): 3.5 КБ в _CODE окна W1/W2 нам дороже, чем один
# gfx_w0_map за тик. См. applications/PoP/docs/layout_plan_v2.md §5.1.
f.write("/* {image, dx, dy, flags, sword}; chtab = sword>>6 (0=kid).\n"
" * САМА таблица кадров и seqtbl лежат в kid_data.bin (EMM-\n"
" * САМА таблица кадров и seqtbl лежат в kid.ani (EMM-\n"
" * страница); здесь только тип и размеры. */\n")
f.write("typedef struct { uint8_t image; int8_t dx, dy; "
"uint8_t flags, sword; } kframe;\n")
f.write("#define KID_NFRAMES %d\n" % len(frames))
f.write("#define KID_SEQTBL_LEN %d\n\n" % len(seqtbl))
# раскладка kid_data.bin (смещения ОТ НАЧАЛА ДАННЫХ страницы)
f.write("/* Раскладка kid_data.bin: кадры (KID_NFRAMES*5), затем seqtbl. */\n")
# раскладка kid.ani (смещения ОТ НАЧАЛА ДАННЫХ страницы)
f.write("/* Раскладка kid.ani: кадры (KID_NFRAMES*5), затем seqtbl. */\n")
f.write("#define KID_BIN_FRAMES_OFF 0\n")
f.write("#define KID_BIN_SEQTBL_OFF %d\n" % (len(frames) * 5))
f.write("/* Таблица кадров СТРАЖА (frame_tbl_guard, seg006:372): индекс\n"
@@ -148,9 +148,9 @@ def main():
f.write(emit_c(vals, 12, fmt).replace("\n", " \\\n") + " \\\n}\n")
f.write("\n#endif\n")
# kid_data.bin: кадры (по 5 байт) + seqtbl подряд
# kid.ani: кадры (по 5 байт) + seqtbl подряд
os.makedirs(OUT_BIN_DIR, exist_ok=True)
binpath = os.path.join(OUT_BIN_DIR, "kid_data.bin")
binpath = os.path.join(OUT_BIN_DIR, "kid.ani")
with open(binpath, "wb") as b:
for (img, dx, dy, fl, sw) in frames:
b.write(bytes((img & 0xFF, dx & 0xFF, dy & 0xFF, fl & 0xFF, sw & 0xFF)))
@@ -159,7 +159,7 @@ def main():
b.write(bytes((img & 0xFF, dx & 0xFF, dy & 0xFF, fl & 0xFF, sw & 0xFF)))
for (img, dx, dy, fl, sw) in cframes:
b.write(bytes((img & 0xFF, dx & 0xFF, dy & 0xFF, fl & 0xFF, sw & 0xFF)))
print(f"kid_data.bin: {len(frames)*5 + len(seqtbl) + len(gframes)*5 + len(cframes)*5} Б "
print(f"kid.ani: {len(frames)*5 + len(seqtbl) + len(gframes)*5 + len(cframes)*5} Б "
f"(кадры Kid + seqtbl + кадры стража + кадры катсцен) -> {binpath}")
print(f"kid_data.h: {len(frames)} кадров, seqtbl {len(seqtbl)} Б, "