af5f0a4638
Разгрузка W1/W2 перед ИИ стражей (вариант 2 из двух обсуждённых). 1. pop_guard.c разделён по окнам: состояние/логика (Guard, HP, enter, kill, load_frame) остаются в W1/W2 — их обязан видеть банк guards.c; ОТРИСОВКА уехала в новый pop_gdraw.c, собираемый как --w3 (резидент). Правило границы: резидент = только то, что рисует и зовётся исключительно из главного цикла. Кадр стража стал глобальным (pop_gframe): заполняет логика, читает резидент. 2. Страж не окклюдировался передними гранями тайлов — рисовался поверх столба. В оригинале любой Char это запись midtable, а foretable рисуется после всех midtable (draw_tile_fore, seg008:690), т.е. столб перекрывает всех одинаково. Футпринт персонажа выделен из pop_fore_over_kid в char_footprint(), поверх него добавлен pop_fore_over_char() — слой fore + полоса потолка, без оверлеев поз виса/полёта/подъёма (у стража их нет; появятся — портируем redraw_at_char2 общим кодом, а не догадками). 3. Упаковщик стража: тот же off-by-one, что уже ловили у Kid. load_chtab_from_file(id_chtab_5_guard, 750) даёт images[0] = res751, а рисование индексирует images[frame.image] — значит image=N это res(751+N), а не res(750+N). Из-за сдвига frame_166_stand_inactive рисовался как res767 (выпад) вместо res768 (стойка). Проверено в MAME: страж в комнатах 3 и 21 стоит в правильной позе; окклюзия подтверждена патчем Guard.x в живой сессии — при заходе за столб спрайт корректно срезается его передней гранью. Память: _CODE 26 149 -> 25 703, куча W2 805 -> 1245 Б, резидент W3 11 656 -> 12 819 (свободно 3565 Б), банк 1 236/16384 Б. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
83 lines
3.8 KiB
C
83 lines
3.8 KiB
C
/*
|
|
* pop_guard.h — СОСТОЯНИЕ стража и точки входа в его логику.
|
|
*
|
|
* Разделение по окнам (docs/layout_plan_v2.md §4, подтверждено пробником
|
|
* tests/w3bankgfx):
|
|
* - СОСТОЯНИЕ живёт здесь, в W1/W2. Писучие статики __banked-модуля
|
|
* линкуются В СТРАНИЦУ БАНКА и снаружи не читаются, поэтому банк —
|
|
* только код;
|
|
* - ЛОГИКА (ИИ, боёвка) — в guards.c, собираемом как --bank 1=guards.c;
|
|
* - ОТРИСОВКА стража — в pop_gdraw.c, РЕЗИДЕНТЕ W3 (--w3): её зовёт
|
|
* только главный цикл, а из банка резидент недостижим. Так код
|
|
* отрисовки не занимает дефицитные W1/W2 (куча).
|
|
*
|
|
* Поля char_type — как в оригинале (types.h:302), чтобы порт seg005/seg006
|
|
* ложился один в один.
|
|
*/
|
|
#ifndef POP_GUARD_H
|
|
#define POP_GUARD_H
|
|
|
|
#include <stdint.h>
|
|
#include "kid_data.h" /* kframe */
|
|
|
|
/* charids (types.h:320) — нужны хотя бы для «скелет не убивается читом». */
|
|
#define CHARID_0_KID 0
|
|
#define CHARID_1_SHADOW 1
|
|
#define CHARID_2_GUARD 2
|
|
#define CHARID_4_SKELETON 4
|
|
#define CHARID_5_PRINCESS 5
|
|
|
|
typedef struct {
|
|
uint8_t frame;
|
|
uint8_t x, y;
|
|
int8_t direction;
|
|
int8_t curr_col, curr_row;
|
|
uint8_t action;
|
|
int8_t fall_x, fall_y;
|
|
uint8_t room;
|
|
uint8_t repeat;
|
|
uint8_t charid;
|
|
uint8_t sword;
|
|
int8_t alive; /* -1 = жив (как в оригинале), 0 = убит */
|
|
uint16_t curr_seq;
|
|
} pop_char_t;
|
|
|
|
extern pop_char_t Guard; /* страж ТЕКУЩЕЙ комнаты (как в оригинале) */
|
|
extern uint8_t guardhp_curr, guardhp_max;
|
|
extern int8_t guardhp_delta; /* <0 = в этом кадре отняли HP */
|
|
|
|
/* Текущий кадр стража (порт cur_frame для Char): заполняет логика в W1/W2,
|
|
* читает отрисовка в резиденте W3. image == 255 — рисовать нечего. */
|
|
extern kframe pop_gframe;
|
|
void pop_guard_load_frame(void);
|
|
|
|
/* Есть ли живой страж в отрисованной комнате (для главного цикла). */
|
|
uint8_t pop_guard_present(void);
|
|
|
|
/* Атласы стража (GUARD\\g0..g4.atl) — грузить ДО initgraph, как Kid.
|
|
* 0 — OK, -1 — ошибка (тогда страж просто не рисуется). */
|
|
int pop_guard_load(void);
|
|
void pop_guard_free(void);
|
|
|
|
/* Вход в комнату: поднять стража из данных уровня (порт enter_guard,
|
|
* seg002:0112) либо убрать его, если в комнате стража нет. */
|
|
void pop_guard_enter(uint8_t room);
|
|
|
|
/* Нарисовать текущий кадр стража на back-странице (банк GFX_BANK_SPRITE,
|
|
* как kid_draw) и стереть прошлый (heal). Реализация — pop_gdraw.c
|
|
* (резидент W3), поэтому звать ТОЛЬКО из главного цикла, не из банка. */
|
|
void pop_guard_heal(void);
|
|
void pop_guard_draw(void);
|
|
|
|
/* Убрать стража со сцены (смена комнаты / инициализация). */
|
|
void pop_guard_reset(void);
|
|
|
|
/* Чит «убить стража» (seg000:786, K): скелета не берёт. Вызывать только
|
|
* при включённых читах — проверку делает вызывающий. */
|
|
void pop_guard_kill(void);
|
|
|
|
/* Тик логики стража — В БАНКЕ (guards.c). Состояние берёт отсюда. */
|
|
void pop_guard_tick(void) __banked;
|
|
|
|
#endif
|