DRAW-CHAR: отрисовка одна на всех Char; разгрузка банка 2 (90.4% -> 72.9%)
DRAW-CHAR. Отрисовка персонажа сведена к одному набору функций над Char — как физика после GUARD-PHYS. В оригинале add_kid_to_objtable (seg008:22F0) и add_guard_to_objtable (seg008:2324) имеют идентичное тело и различаются окном (loadkid/loadshad), набором спрайтов и типом объекта, а redraw_at_char/redraw_at_char2 гейтов по charid не имеют вовсе. pop_gdraw.c -> pop_cdraw.c: pop_char_draw/heal/fore(who), слот POP_CH_KID / POP_CH_OPP; состояние слотов pop_cd[] в _DATA — читается из любого банка без трамплина. Проход окклюзии тоже один (pop_fore_over_char), pop_fore_over_kid больше нет. Починилось само (расхождения, которые и были ценой дублирования): у соперника не было clip_char; у Кида не было клипа полем 192 и ветки брызг «мёртв/падение»; char_width_half СТРАЖА считался по спрайту КИДА. Замер: _CODE 24 881 -> 20 524 (куча 2023 -> 6333), BANK2 -265, итого -3.2 КБ. Проверено пользователем в MAME; циан-полоса профиля подросла — оптимизация заведена отдельной задачей DRAW-COST. MEM-BANK2, шаг 1: общие «листья» слоя фона в РЕЗИДЕНТ (pop_tile.c/.h). Ограничение платформы: писучие данные банка лежат в _DATA и видны всем, а const-таблицы — в странице банка, из другого банка их не прочитать; трамплин же выбирается объявлением, то есть __banked на листе бьёт и по горячим вызывающим (654 такта). W1 замаплено всегда — оттуда обе половины зовут листья прямым call и читают таблицы напрямую. MEM-BANK2, шаг 2: дедуп внутри банка. wall_pattern 808 -> 394 и wall_rnd 786 -> 654: четыре ветки по виду стены отличались только набором кусков и числами в одной серии prandom — сведены к таблицам WP_PARTS и WR_RULE, порядок вызовов prandom сохранён дословно. Заодно: kid_seq_off больше не static const в kid_data.h (230 Б мёртвой копии в каждом из 9 модулей) — генератор pop_extract_kid_data.py отдаёт макро-инициализатор, массив определяет один pop_kid.c. Итог: BANK2 14 815 -> 11 942 (72.9 %, свободно 4442 Б), _CODE 22 556, куча 4301 Б. tests-host зелёные (65/39/53/1723/1); в MAME комната 1 совпала с дорефакторным снимком попиксельно (0 из 227 520), комната 3 — та же раскладка кладки. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,10 +31,21 @@ int8_t knock;
|
||||
uint8_t pop_next_level;
|
||||
|
||||
|
||||
/* ---- Атласы Kid (прямая адресация image>>3) ------------------------ */
|
||||
/* ---- Атласы Kid (прямая адресация image>>3) ------------------------ *
|
||||
* НЕ static: набор спрайтов слота POP_CH_KID общей отрисовки персонажей
|
||||
* (pop_cdraw.c, банк 4). Отдан как есть, а не через аксессор: читается раз
|
||||
* в кадр из другого банка, и вызов стоил бы дороже самого чтения. */
|
||||
#define KID_MAXPAGES 28
|
||||
static atlas_t kidp[KID_MAXPAGES];
|
||||
static uint8_t kid_npages;
|
||||
atlas_t kidp[KID_MAXPAGES];
|
||||
uint8_t kid_npages;
|
||||
|
||||
/* Таблица «seq_id -> адрес в seqtbl» (original_seqtbl_offsets). Определена
|
||||
* ЗДЕСЬ, а не в kid_data.h: заголовок включают почти все модули PoP, и
|
||||
* `static const` в нём размножал таблицу мёртвой копией по каждому TU —
|
||||
* 230 Б × 9 модулей, из них 460 Б в дефицитном резиденте W1/W2 (замер
|
||||
* 2026-08-08). Наружу таблица не нужна: смену последовательности делают
|
||||
* kid_set_seq / pop_char_set_seq. */
|
||||
static const uint16_t kid_seq_off[KID_NSEQ] = KID_SEQ_OFF_INIT;
|
||||
|
||||
/* chtab_0 «меч в руке» (add_sword_to_objtable, seg006:1798): клинок —
|
||||
* ОТДЕЛЬНЫЙ спрайт поверх персонажа, один и тот же атлас у Кида и у стража.
|
||||
@@ -113,7 +124,7 @@ uint8_t pop_sword_draw(const pop_char_t *ch, const kframe *fr,
|
||||
|
||||
/* Блит спрайта chtab_2 (атласы Kid) по ЕГО id, левым верхним углом в (x,y).
|
||||
* Нужен полосе HP: она рисует id 216/217 из тех же атласов, что и кадры
|
||||
* Кида, а держать вторую копию раскладки в pop_gdraw ни к чему. */
|
||||
* Кида, а держать вторую копию раскладки в pop_cdraw ни к чему. */
|
||||
void pop_kid_img_blit(uint8_t image, int x, int y)
|
||||
{
|
||||
uint8_t pg = (uint8_t)(image >> 3); /* раскладка атласов: 8 спрайтов/стр. */
|
||||
@@ -129,7 +140,7 @@ void pop_kid_img_blit(uint8_t image, int x, int y)
|
||||
* ради бесплатного горизонтального флипа), поэтому блит обязан быть
|
||||
* колоночным. Row-major gfx_blit_noclip выдал бы марку транспонированной.
|
||||
* noclip БЕЗ проверки (CLIP-1): единственный вызывающий — полоса HP
|
||||
* (pop_gdraw.c), у неё координаты фиксированные и заведомо на экране. */
|
||||
* (pop_cdraw.c), у неё координаты фиксированные и заведомо на экране. */
|
||||
if (w && h) gfx_blit_cols_part_noclip(x, y, img, 0, 0, 0);
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
@@ -207,9 +218,11 @@ static uint8_t kdat_blk, kdat_page, kdat_ok;
|
||||
/* Текущий кадр (порт глобала cur_frame, seg006): 5 байт вместо таблицы.
|
||||
* Заполняется load_frame для АКТИВНОГО персонажа (Char), поэтому на
|
||||
* выходе из play_seq его надо сохранить в кэш своего персонажа: страж
|
||||
* тикает ПОСЛЕ Кида, и без разделения kid_draw взял бы кадр стража. */
|
||||
* тикает ПОСЛЕ Кида, и без разделения отрисовка Кида взяла бы кадр стража. */
|
||||
static kframe cur_frame;
|
||||
static kframe kid_frame; /* кадр Kid для kid_draw */
|
||||
/* Кадр Кида для отрисовки — пара к pop_gframe соперника; читает общая
|
||||
* отрисовка (pop_cdraw.c), поэтому не static. */
|
||||
kframe kid_frame;
|
||||
|
||||
/* Char (seg006): АКТИВНЫЙ персонаж. Интерпретатор последовательностей в
|
||||
* оригинале работает не с Kid и не с Guard, а с этой копией, а вокруг
|
||||
@@ -349,7 +362,7 @@ static void load_frame(void)
|
||||
* персонажа, а не в save*-функциях. Раньше кэш писали pop_savekid/
|
||||
* pop_saveshad, и любое окно Char БЕЗ play_seq (окна боёвки
|
||||
* check_sword_hurting / check_sword_hurt) записывало Киду кадр, который
|
||||
* на самом деле принадлежал СТРАЖУ: kid_draw брал его image из атласа
|
||||
* на самом деле принадлежал СТРАЖУ: отрисовка брала его image из атласа
|
||||
* Кида и рисовал произвольную позу. Теперь владелец один — тот, для
|
||||
* кого кадр реально загружен. */
|
||||
if (Char.charid == CHARID_0_KID) kid_frame = cur_frame;
|
||||
@@ -519,292 +532,6 @@ void kid_tick(void)
|
||||
pop_kid_play();
|
||||
}
|
||||
|
||||
/* Отрисовка текущего кадра: obj_x=(char_x+dx)*2-116, obj_y=char_y+dy
|
||||
* (seg008.c:1728 load_frame_to_obj). НИЗ спрайта на obj_y, левый край
|
||||
* на obj_x. Калибровка XOFF/YOFF — сверить с эталоном.
|
||||
*
|
||||
* Зеркалирование (K2a): спрайты Kid хранятся ЛИЦОМ ВЛЕВО (как в оригинале).
|
||||
* seg008.c:864 — флип, когда персонаж смотрит ВПРАВО (direction==dir_0_right
|
||||
* ==0), и тогда xpos -= image->w (draw_mid). Реализуем бесплатным
|
||||
* горизонтальным флипом column-major спрайта (gfx_blit_cols flip=1):
|
||||
* зеркало происходит ВНУТРИ [x,x+w), поэтому при флипе подаём x=obj_x-w,
|
||||
* чтобы «hot-point» кадра остался на месте.
|
||||
*
|
||||
* Kid рисуется банком GFX_BANK_SPRITE (только видео-ОЗУ, НЕ теневая копия
|
||||
* — 0xFF прозрачен), чтобы kid_heal() мог восстановить чистый фон из
|
||||
* теневой копии (фон запёкся в неё при pop_room_draw). Прямоугольник
|
||||
* последней отрисовки запоминается для heal. */
|
||||
#define KID_XOFF 0
|
||||
#define KID_YOFF 0
|
||||
|
||||
/* Прямоугольник последней отрисовки Kid — ПО СТРАНИЦЕ (0/1). У каждой
|
||||
* графической страницы своя ОЗУ-копия/видео-ОЗУ, поэтому heal должен
|
||||
* стирать пиксели Kid именно той страницы, в которую сейчас рисуем
|
||||
* (при дабл-буфере страница чередуется — прошлый Kid на этой странице
|
||||
* был 2 логических кадра назад). В однобуфере используется только [0]. */
|
||||
static int kid_lx[2], kid_ly[2];
|
||||
static uint16_t kid_lw[2], kid_lh[2];
|
||||
static uint8_t kid_lvalid[2];
|
||||
|
||||
/* ОТДЕЛЬНЫЙ прямоугольник накладных спрайтов (клинок chtab_0, брызги урона).
|
||||
* Раньше он объединялся с прямоугольником персонажа — но объединение сильно
|
||||
* больше суммы двух: клинок уходит вперёд-вверх, и общий габарит выходил
|
||||
* почти вдвое шире и выше самого Kid, а heal стоит ровно по площади.
|
||||
* Поэтому heal делаем двумя вызовами по своим прямоугольникам, а объединение
|
||||
* оставляем ТОЛЬКО для окна fore-клипа (там это 4 сравнения, без рисования —
|
||||
* зато клинок/брызги честно уходят под передние грани тайлов). */
|
||||
static int kid_ox[2], kid_oy[2];
|
||||
static uint16_t kid_ow[2], kid_oh[2];
|
||||
static uint8_t kid_ovalid[2];
|
||||
|
||||
/* Добавить накладной спрайт в overlay-прямоугольник страницы dp. Клинок и
|
||||
* брызги в одном кадре встречаются редко и оба маленькие — их объединение
|
||||
* дешевле третьего слота. */
|
||||
static void kid_overlay_add(uint8_t dp, int x, int y, uint16_t w, uint16_t h)
|
||||
{
|
||||
if (!kid_ovalid[dp]) {
|
||||
kid_ox[dp] = x; kid_oy[dp] = y; kid_ow[dp] = w; kid_oh[dp] = h;
|
||||
kid_ovalid[dp] = 1;
|
||||
return;
|
||||
}
|
||||
{
|
||||
int x0 = kid_ox[dp], y0 = kid_oy[dp];
|
||||
int x1 = x0 + (int)kid_ow[dp], y1 = y0 + (int)kid_oh[dp];
|
||||
if (x < x0) x0 = x;
|
||||
if (y < y0) y0 = y;
|
||||
if (x + (int)w > x1) x1 = x + (int)w;
|
||||
if (y + (int)h > y1) y1 = y + (int)h;
|
||||
kid_ox[dp] = x0; kid_oy[dp] = y0;
|
||||
kid_ow[dp] = (uint16_t)(x1 - x0); kid_oh[dp] = (uint16_t)(y1 - y0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Окно fore-клипа = объединение «персонаж + накладные». Считается по
|
||||
* прямоугольникам, ничего не рисует. */
|
||||
static void kid_fore_clip(uint8_t dp)
|
||||
{
|
||||
int x0, y0, x1, y1;
|
||||
if (!kid_lvalid[dp] && !kid_ovalid[dp]) { pop_fore_set_clip(0, 0, 0, 0); return; }
|
||||
if (!kid_ovalid[dp]) {
|
||||
pop_fore_set_clip(kid_lx[dp], kid_ly[dp] + POP_YOFF,
|
||||
(int)kid_lw[dp], (int)kid_lh[dp]);
|
||||
return;
|
||||
}
|
||||
if (!kid_lvalid[dp]) {
|
||||
pop_fore_set_clip(kid_ox[dp], kid_oy[dp] + POP_YOFF,
|
||||
(int)kid_ow[dp], (int)kid_oh[dp]);
|
||||
return;
|
||||
}
|
||||
x0 = kid_lx[dp] < kid_ox[dp] ? kid_lx[dp] : kid_ox[dp];
|
||||
y0 = kid_ly[dp] < kid_oy[dp] ? kid_ly[dp] : kid_oy[dp];
|
||||
x1 = kid_lx[dp] + (int)kid_lw[dp];
|
||||
y1 = kid_ly[dp] + (int)kid_lh[dp];
|
||||
if (kid_ox[dp] + (int)kid_ow[dp] > x1) x1 = kid_ox[dp] + (int)kid_ow[dp];
|
||||
if (kid_oy[dp] + (int)kid_oh[dp] > y1) y1 = kid_oy[dp] + (int)kid_oh[dp];
|
||||
pop_fore_set_clip(x0, y0 + POP_YOFF, x1 - x0, y1 - y0);
|
||||
}
|
||||
|
||||
/* Метрики последнего kid_draw для футпринта fore-over-Kid (pop_bg):
|
||||
* obj_x — ЛОГИЧЕСКАЯ X кадра (ДО ×8/7), obj_y — низ, w/h — размер. */
|
||||
static int kid_fp_x, kid_fp_y;
|
||||
static uint16_t kid_fp_w, kid_fp_h;
|
||||
/* Рендер-смещение по ЛОГИЧЕСКОЙ X (straddle у шва, порт xpos_in_drawn_room):
|
||||
* ∓140 когда комната Kid ≠ отрисованной; 0 обычно. */
|
||||
static int kid_render_dx;
|
||||
void pop_kid_set_render_dx(int dx) { kid_render_dx = dx; }
|
||||
int kid_fp_obj_x(void) { return kid_fp_x; }
|
||||
int kid_fp_obj_y(void) { return kid_fp_y; }
|
||||
uint16_t kid_fp_width(void) { return kid_fp_w; }
|
||||
uint16_t kid_fp_height(void) { return kid_fp_h; }
|
||||
|
||||
/* draw_hurt_splash (seg006:2003): «брызги» урона поверх персонажа — спрайт
|
||||
* chtab_2_kid id 218 (res619.png; в наших атласах это image 218, стр. 27).
|
||||
* Позиция от кадра Kid: obj_y −= 15, obj_x += 5 ВПЕРЁД (obj_dx_forward).
|
||||
* Кадры смерти/падения (185, 106..110) и пик (177) в оригинале смещают
|
||||
* иначе — тут только общий случай + «на пиках» (порт по мере надобности).
|
||||
* Рисовать ПОСЛЕ kid_draw (splash кладётся в objtable позже Kid). */
|
||||
#define KID_SPLASH_IMAGE 218
|
||||
|
||||
void kid_draw_splash(void)
|
||||
{
|
||||
int obj_x = kid_fp_x, obj_y = kid_fp_y - 15;
|
||||
uint8_t page = KID_SPLASH_IMAGE >> 3, idx = KID_SPLASH_IMAGE & 7;
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
if (page >= kid_npages) return;
|
||||
if (Kid.frame == 177) /* напоролся на пики */
|
||||
obj_y = kid_fp_y, obj_x -= (Kid.direction < 0) ? -5 : 5;
|
||||
else
|
||||
obj_x += (Kid.direction < 0) ? -5 : 5;
|
||||
obj_x = obj_x * 8 / 7; /* лог. X -> экран (calc_screen_x_coord) */
|
||||
img = (const uint8_t *)atlas_image(&kidp[page], idx);
|
||||
gfx_w0_map(kidp[page].page);
|
||||
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
|
||||
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
|
||||
if (w && h) {
|
||||
uint8_t flip = (Kid.direction >= 0);
|
||||
int bx = obj_x;
|
||||
int top = obj_y - (int)h + 1;
|
||||
if (flip) bx -= (int)w;
|
||||
gfx_set_bank(GFX_BANK_SPRITE);
|
||||
if (pop_onscreen_cols(bx, top + POP_YOFF, w, h))
|
||||
gfx_blit_cols_part_noclip(bx, top + POP_YOFF, img, flip, 0, 0);
|
||||
else
|
||||
gfx_blit_cols(bx, top + POP_YOFF, img, flip);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
pop_clip_sprite(bx, w, top + POP_YOFF, (int)h);
|
||||
/* Брызги — накладной спрайт: свой прямоугольник heal (см.
|
||||
* kid_overlay_add), окно fore пересчитываем объединением. */
|
||||
{
|
||||
uint8_t dp = gfx_get_draw_page();
|
||||
kid_overlay_add(dp, bx, top, w, h);
|
||||
kid_fore_clip(dp);
|
||||
}
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
/* Восстановить фон из теневой копии на месте ПРЕДЫДУЩЕГО кадра Kid.
|
||||
*
|
||||
* pop_heal_fast, а не голый gfx_heal: прямоугольник тут — это ровно тот
|
||||
* прямоугольник, который kid_draw нарисовал noclip-ядром, то есть в
|
||||
* подавляющем большинстве кадров он заведомо на экране. Клипающий путь
|
||||
* остаётся для straddle (kid_render_dx = ∓140) и падения ниже поля —
|
||||
* там координата реально уходит за экран. */
|
||||
void kid_heal(void)
|
||||
{
|
||||
uint8_t p = gfx_get_draw_page();
|
||||
if (kid_lvalid[p]) /* +YOFF: центрирование */
|
||||
pop_heal_fast(kid_lx[p], kid_ly[p] + POP_YOFF, kid_lw[p], kid_lh[p]);
|
||||
if (kid_ovalid[p])
|
||||
pop_heal_fast(kid_ox[p], kid_oy[p] + POP_YOFF, kid_ow[p], kid_oh[p]);
|
||||
kid_lvalid[p] = kid_ovalid[p] = 0;
|
||||
}
|
||||
|
||||
void kid_draw(void)
|
||||
{
|
||||
kframe fr = kid_frame; /* кадр Kid, сохранённый savekid */
|
||||
int fwd, obj_x, obj_y, top;
|
||||
uint8_t page, idx;
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
|
||||
/* Окно fore-слоя по умолчанию пустое: на любом раннем выходе (нет
|
||||
* кадра / страница не загружена) перекрывать нечего, и fore-проход
|
||||
* не должен трогать экран. */
|
||||
pop_fore_set_clip(0, 0, 0, 0);
|
||||
if (fr.image == 255)
|
||||
return; /* пустой кадр */
|
||||
/* +kid_render_dx: straddle-смещение (∓140) когда комната Kid ≠
|
||||
* отрисованной — спрайт за кромкой. Коллизия (Kid.x в pop_map) НЕ
|
||||
* смещается: она в кадре комнаты Kid; смещение только рендерное. */
|
||||
fwd = (int)Kid.x + ((Kid.direction < 0) ? -fr.dx : fr.dx) + kid_render_dx;
|
||||
obj_x = (fwd << 1) - 116;
|
||||
obj_y = (int)Kid.y + fr.dy;
|
||||
if ((int8_t)(fr.flags ^ Kid.direction) >= 0)
|
||||
obj_x++; /* even/odd pixel (в ЛОГИЧЕСКОЙ координате) */
|
||||
kid_fp_x = obj_x; /* ЛОГИЧЕСКАЯ X (до ×8/7) — для футпринта fore */
|
||||
kid_fp_y = obj_y;
|
||||
/* seg008 calc_screen_x_coord: логическая X (280 шир = 28px/тайл) ->
|
||||
* экран (320 шир = 32px/тайл), ×320/280 = ×8/7. БЕЗ этого Kid уезжает
|
||||
* влево от тайлов тем сильнее, чем правее (col9 ~36px). Коллизия — в
|
||||
* логической системе (не масштабируется). */
|
||||
obj_x = obj_x * 8 / 7;
|
||||
|
||||
page = (uint8_t)(fr.image >> 3);
|
||||
idx = (uint8_t)(fr.image & 7);
|
||||
if (page >= kid_npages)
|
||||
return; /* страница не загружена */
|
||||
img = (const uint8_t *)atlas_image(&kidp[page], idx);
|
||||
gfx_w0_map(kidp[page].page);
|
||||
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
|
||||
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
|
||||
if (w && h) {
|
||||
uint8_t flip = (Kid.direction >= 0); /* dir_0_right -> зеркало */
|
||||
int bx = obj_x + KID_XOFF;
|
||||
int skip = 0; /* строк спрайта срезано сверху */
|
||||
int ct, cr;
|
||||
uint16_t vis_w = w; /* видимая ширина (клип справа) */
|
||||
if (flip)
|
||||
bx -= (int)w; /* seg008: xpos -= image->w */
|
||||
top = obj_y - (int)h + 1 + KID_YOFF;
|
||||
uint8_t dp = gfx_get_draw_page(); /* в какую страницу рисуем */
|
||||
/* clip_char (seg006:1749): тайл над головой = стена/пол → всё выше
|
||||
* линии полосы своего ряда НЕ рисуется. Иначе Kid просвечивает
|
||||
* сквозь щели кладки при спуске/висе.
|
||||
*
|
||||
* Окно Char обязательно: clip_char работает с АКТИВНЫМ персонажем
|
||||
* (в оригинале он и зовётся внутри add_kid_to_objtable, то есть под
|
||||
* loadkid), а к моменту отрисовки в Char лежит тот, кто тикал
|
||||
* последним — страж. Выгружать назад нечего: clip_char только
|
||||
* читает. */
|
||||
pop_loadkid();
|
||||
ct = pop_clip_char_top(kid_fp_x, obj_y, w, h);
|
||||
if (ct > top) {
|
||||
skip = ct - top;
|
||||
if (skip >= (int)h) skip = (int)h; /* обрезан целиком */
|
||||
}
|
||||
/* clip_char, вторая половина: правый косяк двери уровня. Дверь
|
||||
* рисуется ПОД персонажем (вся в backtable), поэтому спрятать его
|
||||
* можно только срезав спрайт — см. pop_clip_char_right. */
|
||||
cr = pop_clip_char_right();
|
||||
if (cr) {
|
||||
int avail = cr - bx;
|
||||
if (avail <= 0) vis_w = 0; /* весь спрайт за косяком */
|
||||
else if (avail < (int)w) vis_w = (uint16_t)avail;
|
||||
}
|
||||
gfx_set_bank(GFX_BANK_SPRITE); /* видео-ОЗУ, без теневой копии */
|
||||
if (skip < (int)h && vis_w) { /* +YOFF: центрирование */
|
||||
/* noclip-ядро ширину не ограничивает, поэтому при обрезке справа
|
||||
* идём общим путём: это редкие кадры (подъём в двери уровня раз
|
||||
* за уровень), цена подготовки тут не видна. */
|
||||
if (vis_w == w && pop_onscreen_cols(bx, top + skip + POP_YOFF, w,
|
||||
(uint16_t)((int)h - skip)))
|
||||
gfx_blit_cols_part_noclip(bx, top + skip + POP_YOFF, img, flip,
|
||||
(uint8_t)skip, 0);
|
||||
else
|
||||
gfx_blit_cols_part_w(bx, top + skip + POP_YOFF, img, flip,
|
||||
skip, 0, (uint8_t)(vis_w == w ? 0 : vis_w));
|
||||
}
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
/* клип СВОЕГО выхода за поле (падение ниже поля / верхний борт) —
|
||||
* узко, только по прямоугольнику Кида и только при выходе. */
|
||||
pop_clip_sprite(bx, w, top + skip + POP_YOFF, (int)h - skip);
|
||||
/* heal чистит ТОЛЬКО нарисованное: иначе стирается кромка пола над
|
||||
* срезом (мусор/дыра в кладке на второй странице дабл-буфера). */
|
||||
kid_lx[dp] = bx; kid_ly[dp] = top + skip;
|
||||
kid_lw[dp] = vis_w; kid_lh[dp] = (uint16_t)((int)h - skip);
|
||||
kid_lvalid[dp] = (skip < (int)h && vis_w != 0);
|
||||
kid_fp_w = w; kid_fp_h = h; /* размер кадра для футпринта fore */
|
||||
}
|
||||
/* add_sword_to_objtable (seg006:1798): клинок отдельным спрайтом поверх
|
||||
* Kid — со СВОИМ прямоугольником heal (kid_overlay_add). */
|
||||
{
|
||||
int sx, sy; uint16_t sw, sh;
|
||||
if (pop_sword_draw(&Kid, &fr, obj_x, obj_y, &sx, &sy, &sw, &sh))
|
||||
kid_overlay_add(gfx_get_draw_page() & 1, sx, sy, sw, sh);
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
/* Окно fore-слоя = объединение «Kid + клинок» (с обрезкой clip_char):
|
||||
* fore-проход вернёт куски тайлов ТОЛЬКО поверх него, а не целыми
|
||||
* тайлами — см. pop_bg.c, fclip_on. Ставим и когда рисовать нечего:
|
||||
* нулевое окно = fore-проход не трогает экран, что и правильно. */
|
||||
kid_fore_clip(gfx_get_draw_page() & 1);
|
||||
}
|
||||
|
||||
/* Вернуть окно fore-клипа на прямоугольник ПОСЛЕДНЕГО кадра Kid.
|
||||
*
|
||||
* Окно (pop_fore_set_clip) — одно на всех, и его ставит КАЖДЫЙ, кто рисует
|
||||
* персонажа: kid_draw в конце — своё, pop_guard_draw в конце — своё. Пока
|
||||
* страж рисовался строго ДО Кида, к моменту pop_fore_over_kid в окне
|
||||
* оказывался Kid, и всё сходилось само. Как только порядок стал
|
||||
* переменным (guard_over_kid в roomtest.c — порядок задаёт обход тайлов),
|
||||
* при «страж поверх» окно оставалось СТРАЖЬИМ и fore-проход Кида отсекался
|
||||
* целиком: Кид рисовался поверх передних столбов.
|
||||
*
|
||||
* Поэтому окно восстанавливается явно перед pop_fore_over_kid, а не
|
||||
* держится «по счастливому порядку вызовов». */
|
||||
void kid_fore_clip_restore(void)
|
||||
{
|
||||
kid_fore_clip(gfx_get_draw_page() & 1);
|
||||
}
|
||||
/* Отрисовка кадра (load_frame_to_obj, heal, клип, брызги, клинок) живёт в
|
||||
* pop_cdraw.c — ОДНА на всех Char, см. DRAW-CHAR. Отсюда она получает
|
||||
* атласы Кида (kidp/kid_npages) и его кадр (kid_frame). */
|
||||
|
||||
Reference in New Issue
Block a user