/* * pop_cdraw.h — ОТРИСОВКА ПЕРСОНАЖА, одна на всех Char. * * В оригинале это два входа с ИДЕНТИЧНЫМ телом (seg008:22F0/2324): * * add_kid_to_objtable add_guard_to_objtable * loadkid() loadshad() * load_fram_det_col() load_fram_det_col() * load_frame_to_obj() load_frame_to_obj() * stuck_lower() stuck_lower() * set_char_collision() set_char_collision() * set_objtile_at_char() set_objtile_at_char() * redraw_at_char() redraw_at_char() * redraw_at_char2() redraw_at_char2() * clip_char() clip_char() * add_objtable(0) add_objtable(1 тень / 2 страж) * * — различаются ТОЛЬКО окном (loadkid/loadshad), набором спрайтов и типом * объекта. У нас до DRAW-CHAR это были два независимых куска кода * (kid_draw в резиденте и pop_guard_draw в банке), и расхождение уже стоило * бага: падающий скелет рисовался поверх верхней грани пола соседней * колонки, потому что порт redraw_at_char2 был только у Кида. Тем же путём * пошли бы тень (ур. 4/5/6/12), визирь (13) и толстяк (12). * * Поэтому здесь ОДИН набор функций, а различия сведены к слоту: * POP_CH_KID — Кид: окно loadkid, атласы chtab_2 (kidp), кадр kid_frame; * POP_CH_OPP — соперник: окно loadshad, атласы chtab_5 (страж/скелет), * кадр pop_gframe. * * Порядок в кадре (задаёт главный цикл, как draw_people): * pop_char_heal(who) — стереть прошлый кадр ЭТОЙ страницы дабл-буфера; * pop_char_draw(who) — спрайт + брызги урона + клинок; * pop_char_fore(who) — передние грани и оверлеи тайлов ПОВЕРХ него. */ #ifndef POP_CDRAW_H #define POP_CDRAW_H #include #define POP_CH_KID 0 #define POP_CH_OPP 1 #define POP_CH_N 2 /* Состояние отрисовки одного слота. Публичное, потому что метрики кадра * (fp*) читает физика из ДРУГОГО банка (char_width_half в * set_char_collision, порядок «кто поверх кого» в pop_bg): данные лежат в * _DATA (W2) и видны всем без трамплина, а вызов аксессора из банка стоил * бы дороже самого чтения. */ typedef struct { /* прямоугольник спрайта по СТРАНИЦАМ дабл-буфера: у каждой своя * видео-ОЗУ и своя ОЗУ-копия, поэтому heal обязан стирать спрайт именно * той страницы, в которую сейчас рисуем */ int x[2], y[2]; uint16_t w[2], h[2]; uint8_t valid[2]; /* НАКЛАДНЫЕ спрайты (клинок + брызги урона) — свой прямоугольник, не * объединение с персонажем: объединение сильно больше суммы двух * (клинок уходит вперёд-вверх), а heal стоит ровно по площади */ int ox[2], oy[2]; uint16_t ow[2], oh[2]; uint8_t ovalid[2]; /* габарит кадра для fore-прохода: fpx — ЛОГИЧЕСКАЯ X (до ×8/7), * fpy — низ спрайта; fpw == 0 — в этом кадре рисовать было нечего */ int fpx, fpy; uint16_t fpw, fph; /* окно fore-клипа слота (объединение «спрайт + накладные»), КОМНАТНЫЙ y */ int cx, cy; uint16_t cw, ch; /* straddle: рендерное смещение по ЛОГИЧЕСКОЙ X, когда комната персонажа * не совпадает с отрисованной (порт xpos_in_drawn_room) */ int render_dx; } pop_cdraw_t; extern pop_cdraw_t pop_cd[POP_CH_N]; /* Стереть прошлый кадр персонажа (спрайт + накладные) на ТЕКУЩЕЙ странице. */ void pop_char_heal(uint8_t who) __banked; /* Нарисовать текущий кадр: спрайт, брызги урона (по флагу pop_kid_hurt / * pop_guard_hurt) и клинок. Загружает окно Char сам — clip_char и футпринт * работают с АКТИВНЫМ персонажем, как в оригинале. */ void pop_char_draw(uint8_t who) __banked; /* Передние грани и оверлеи тайлов ПОВЕРХ персонажа: ставит окно fore-клипа * слота и зовёт общий проход pop_fore_over_char. Отдельным вызовом, а не * хвостом pop_char_draw, потому что порядок в кадре задаёт главный цикл: * между спрайтом и его fore-слоем успевает нарисоваться падающая плита. */ void pop_char_fore(uint8_t who) __banked; /* Straddle-смещение спрайта (см. render_dx). */ void pop_char_set_render_dx(uint8_t who, int dx) __banked; #endif