Files
Sprinter-SDCC/applications/PoP/roomtest/pop_kid.h
T
snark13 055d6d7c89 Фикс: чтение файлов нельзя выносить в банк — банковый код сам живёт в W3
Первый запуск после разгрузки встал в halt по мусору в 0xC40E.  Причина:
pop_level_read_file и pop_kid_data_load маппят страницу данных в W3 на время
read() (файл читается по 0xC000), а модули банка исполняются ИЗ ЭТОГО ЖЕ
окна — после sprinter_page_w3() следующая инструкция приходит уже из чужой
страницы.  Обе функции вернулись в резидент; в банке остался код, который
ходит через W0 (gfx_w0_map) или окон не трогает вовсе.

Правило записано в _pop_level.h и _pop_kid.h: банковый модуль НЕ маппит W3
(через W0 — можно).  Поэтому же в резиденте живёт весь libbgi.

Куча 6095 Б (было 902 до разгрузки).  Проверено в MAME: игра стартует,
комната рисуется, Кид управляем.  tests-host 6/6.
2026-08-12 22:17:18 +03:00

132 lines
7.9 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_kid.h — движок анимации/движения Kid (Фаза K1): интерпретатор
* seqtbl (play_seq) + frame_table. Порт SDLPoP seg006.c. Данные —
* kid_data.h (pop_extract_kid_data.py).
*
* K1: только проигрывание последовательностей кадров с авторскими
* смещениями (движение = SEQ_DX/DY + frame.dx/dy). Управление (K2) и
* коллизия карты (K3) — отдельно.
*/
#ifndef POP_KID_H
#define POP_KID_H
#include <stdint.h>
#include "pop_char.h"
#include "kid_data.h" /* kframe — тип кадра для pop_sword_draw */
#include <sprite.h> /* atlas_t — набор спрайтов Кида (см. kidp ниже) */
/* Состояние персонажа — общий тип для Кида, стража и Char (pop_char.h). */
extern pop_char_t Kid;
/* Флаг сотрясения (seg006 knock): +1 = KNOCK_UP (ряд выше), -1 = KNOCK_DOWN
* (свой ряд). Ставит play_seq, читает/сбрасывает pop_check_knock. */
extern int8_t knock;
/* Порт next_level (seg000): END_LEVEL в play_seq инкрементит — «уровень
* пройден». Читает и обнуляет главный цикл. Пока уровень один, поэтому
* там рестарт того же уровня; загрузка следующего — levels_plan.md. */
extern uint8_t pop_next_level;
/* Загрузить npages атласов Kid (kid0..kid{npages-1}.atl). ДО initgraph.
* 0 — OK, -1 — ошибка. */
int pop_kid_load(uint8_t npages) __banked;
/* Данные анимации (таблица кадров + seqtbl) — отдельная EMM-страница
* (kid_data.bin): в _CODE окна W1/W2 они занимали 3.5 КБ. Грузить ДО
* первого kid_init/play_seq. 0 — OK, -1 — ошибка (без них Kid не оживёт).
* Страница маппится в W0 внутри play_seq, раз за тик. */
int pop_kid_data_load(const char *path);
/* Прочитать кадр из таблицы страницы данных: tbl_off — KID_BIN_FRAMES_OFF
* (Kid) или KID_BIN_GFRAMES_OFF (страж, своя таблица frame_tbl_guard).
* Маппит страницу сама; для горячего цикла есть cur_frame. */
void pop_kid_data_frame(uint16_t tbl_off, uint8_t idx, uint8_t *out5);
void pop_kid_data_free(void) __banked;
/* Атлас chtab_0 «меч в руке» (sword.atl) — спрайт клинка поверх Kid в кадрах
* подъёма меча/убирания в ножны (add_sword_to_objtable, seg006:1798).
* Грузить ДО initgraph, как и страницы Kid. 0 — OK, -1 — ошибка (тогда
* кадры рисуются без клинка). */
int pop_sword_load(void) __banked;
void pop_kid_free(void) __banked;
/* Сама отрисовка клинка (pop_sword_draw) и блит спрайта chtab_2 по id
* (pop_kid_img_blit) переехали в pop_kdraw.c — БАНК 4, к единственному
* вызывающему (pop_cdraw.c). Их объявления — в _pop_kdraw.h. */
/* Инициализировать Kid: последовательность seq_id, клетка col/row,
* направление dir (-1/0). Ставит x/y по x_bump/y_land. */
void kid_init(uint8_t seq_id, int8_t col, int8_t row, int8_t dir);
/* Один логический тик: play_seq() — продвинуть последовательность до
* следующего кадра (применить SEQ_DX/DY/ACTION/...). */
void kid_tick(void);
/* play_seq напрямую (для pop_map start_fall — переход в fall-seq в тот же
* physics-шаг, как оригинал). */
void play_seq(void); /* работает с Char — см. pop_kid_play ниже */
/* Активный персонаж (порт Char, seg006) и его загрузка/выгрузка.
* Интерпретатор последовательностей общий для Kid и стража: у них общая
* seqtbl, но РАЗНЫЕ таблицы кадров (load_frame выбирает по Char.charid). */
extern pop_char_t Char;
/* Соперник активного персонажа (порт Opp): ставится вместе с Char через
* pop_loadshad_and_opp. Читают ИИ стража и боёвка (char_opp_dist). */
extern pop_char_t Opp;
void pop_loadkid(void);
void pop_savekid(void);
void pop_savekid_state(void); /* Kid = Char, кадр не трогаем */
void pop_loadshad(void);
void pop_saveshad(void);
void pop_loadshad_and_opp(void); /* Char = Guard, Opp = Kid (seg006:841) */
void pop_saveshad_and_opp(void); /* Guard = Char, Kid = Opp */
void pop_loadkid_and_opp(void); /* Char = Kid, Opp = Guard */
void pop_savekid_and_opp(void); /* Kid = Char, Guard = Opp */
/* Дистанция до соперника в системе Char: >0 впереди, <0 за спиной,
* 999 — разные комнаты (порт char_opp_dist, seg006:2135). */
int16_t pop_char_opp_dist(void);
/* Прокрутить последовательность персонажа целиком (load + play_seq +
* save). Звать вместо голого play_seq. */
void pop_char_set_seq(uint8_t seq_id); /* seq активного персонажа */
void pop_kid_play(void);
void pop_guard_play(void);
/* load_fram_det_col (seg006:0144) — перезагрузить cur_frame под АКТИВНОГО
* персонажа (Char) и пересчитать его колонку. Звать сразу после pop_loadkid/
* pop_loadshad и ДО диспетчера control(), как это делают play_kid_frame /
* play_guard_frame (seg000:1209/1246): cur_frame один на всех, и без этого
* геометрия одного персонажа считается по кадру другого. */
void pop_load_fram_det_col(void);
/* Только load_frame (seg006:0293), БЕЗ determine_col. Нужен там, где
* оригинал зовёт голый load_frame и пересчёт колонки по x был бы вреден —
* например в jump_through_mirror, где ось отражения берётся из curr_col. */
void pop_load_frame(void);
/* Какая таблица кадров у персонажа (seg006:0293): 1 — стража, 0 — Кида.
* Нужна не только load_frame, но и отрисовке — набор атласов обязан
* совпадать с таблицей (тень ходит кадрами и спрайтами КИДА, а дерётся
* кадрами стража). */
uint8_t pop_frame_tbl_is_guard(int8_t charid, uint8_t frame);
/* Поля текущего кадра kid_frames[Kid.frame] (pop_map, без дублирования
* таблицы во втором TU). */
int8_t kid_cur_dx(void);
int8_t kid_cur_dy(void);
uint8_t kid_cur_flags(void);
/* Сменить последовательность (Kid.curr_seq = kid_seq_off[seq_id]) — единая
* точка для pop_ctrl/pop_map (иначе каждый дублировал бы kid_seqtbl ~2.3КБ). */
void kid_set_seq(uint8_t seq_id);
/* Атласы Кида (chtab_2) и его текущий кадр — набор слота POP_CH_KID общей
* отрисовки персонажей (pop_cdraw.c). Наружу отданы как данные, а не через
* аксессоры: читаются раз в кадр из другого банка, где вызов стоил бы
* дороже самого чтения (данные в _DATA видны всем без трамплина). */
extern atlas_t kidp[];
extern uint8_t kid_npages;
extern kframe kid_frame;
#endif