/* * pop_kboot.c — ЗАГРУЗКА ресурсов Кида: атласы chtab_2 (kid0..27.atl) и * страница таблиц анимации (kid_data.bin). БАНК 8. * * Отрабатывает раз за игру (и на выходе — освобождение), поэтому места в * резиденте W1 не занимает: контракт с интерпретатором — _pop_kid.h, там * же дескриптор страницы данных. */ #include #include #include #include #include #include "pop_kid.h" #include "_pop_kid.h" #include "kid_data.h" #include "pop_vflip.h" #include "pop_guard.h" /* pop_guard_vflip_load — зеркала соперника */ #include "pop_arc.h" #include "kid_arc.h" /* Серии в архиве обязаны лежать подряд — так их кладёт список в Makefile, * и только поэтому индекс считается сложением. Если порядок собьётся, * сборка встанет здесь, а не рассыплется картинкой на экране. */ #if (ARC_KID_KID27 - ARC_KID_KID0) != 27 #error "kid0..kid27 в архиве не подряд" #endif #if (ARC_KID_KID27_V - ARC_KID_KID0_V) != 27 #error "kid0_v..kid27_v в архиве не подряд" #endif #define KID_MAXPAGES 28 /* Таблица архива живёт на стеке вызывающего (4 байта на запись, здесь 232) * — держать её постоянно незачем, а W2 у игры и без того тесный. */ int pop_kid_load(uint8_t npages) __banked { uint8_t tbl[ARC_KID_COUNT * POP_ARC_REC]; pop_arc_t arc; uint8_t i; if (npages > KID_MAXPAGES) npages = KID_MAXPAGES; if (pop_arc_open_id(&arc, POP_ARC_KID, tbl, ARC_KID_COUNT) < 0) return -1; for (i = 0; i < npages; i++) if (pop_arc_atlas(&arc, tbl, (uint8_t)(ARC_KID_KID0 + i), &kidp[i]) != 0) { pop_arc_close(&arc); return -1; } /* Меч — из того же открытого архива: без него кадры 229+ идут без * клинка, а второй open стоил бы дороже самого чтения. */ { atlas_t sword; if (pop_arc_atlas(&arc, tbl, ARC_KID_SWORD, &sword) == 0) (void)pop_sword_take(&sword); } pop_arc_close(&arc); kid_npages = npages; return 0; } void pop_kid_free(void) __banked { uint8_t i; for (i = 0; i < kid_npages; i++) atlas_free(&kidp[i]); kid_npages = 0; } int pop_kid_data_load(const char *path) __banked { uint8_t blk, page; int n; blk=mem_alloc_pages(1); if (!blk) return -1; page=mem_get_page(blk,0); n=bank_load_file(page,KD_DATA_OFF,path,16384-KD_DATA_OFF); if (n < (int)(KID_BIN_SEQTBL_OFF + KID_SEQTBL_LEN)) { mem_free_block(blk); return -1; } gfx_w0_page_prepare(page); kdat_blk=blk; kdat_page=page; kdat_ok=1; return 0; } void pop_kid_data_free(void) __banked { if (kdat_ok) { mem_free_block(kdat_blk); kdat_ok = 0; } } /* ---- Зеркальный набор (зелье инверсии, уровень 9) -------------------- * * Грузится ОДНИМ вызовом и откуда угодно: со старта игры, из показа интро * или при входе на уровень с зельем — см. pop_vflip.h. Внутри обычный * atlas_load (он резидентный и сам мапит W3, банку это разрешено делать * только через него). Идемпотентна. */ int pop_vflip_load_all(void) __banked { uint8_t tbl[ARC_KID_COUNT * POP_ARC_REC]; pop_arc_t arc; uint8_t i; int res = 0; if (pop_vflip_ready()) return 0; if (pop_arc_open_id(&arc, POP_ARC_KID, tbl, ARC_KID_COUNT) < 0) return -1; for (i = 0; i < kid_npages; i++) { atlas_t m; if (pop_arc_atlas(&arc, tbl, (uint8_t)(ARC_KID_KID0_V + i), &m) != 0 || pop_vflip_take(&kidp[i], &m) != 0) res = -1; } { atlas_t sword_v; if (pop_arc_atlas(&arc, tbl, ARC_KID_SWORD_V, &sword_v) != 0 || pop_sword_vflip_take(&sword_v) != 0) res = -1; } pop_arc_close(&arc); if (pop_guard_vflip_load() != 0) res = -1; return res; }