PoP roomtest: клинок в атласе целиком + раздельный heal накладных спрайтов
Меч в оригинале ОДИН на всех: и Кид, и страж рисуют клинок из chtab_0 (add_sword_to_objtable, seg006:1798). Раньше sword.atl содержал только кадры подъёма/ножен (sword_tbl 35..42), поэтому у стража меча не было видно вовсе. - pop_pack_kid.py пакует chtab_0 целиком (id 0..33, 5168 Б), индекс в атласе = id; - pop_extract_kid_data.py вытаскивает sword_tbl (53 строки) в kid_data.h макро-инициализаторами — таблица ложится в один TU, а не в каждый; - pop_sword_draw (pop_kid.c) — общая точка отрисовки клинка с полным условием оригинала (кадры 229..237 ИЛИ меч обнажён ИЛИ живой страж); зовут и kid_draw, и pop_guard_draw. Раздельный heal накладных спрайтов. Клинок и брызги урона раньше объединялись в один прямоугольник с персонажем, а объединение почти вдвое больше суммы двух (клинок уходит вперёд-вверх) — heal же стоит ровно по площади. Теперь у накладных свой прямоугольник и свой gfx_heal, а объединение осталось ТОЛЬКО для окна fore-клипа: там это 4 сравнения без рисования, но покрыть клинок обязано, иначе он полезет поверх столба. Отладка: DEBUG_SWORD_ROOM — Киду выдаётся меч при входе в комнату 3 (там страж), чтобы не бегать за ним в комнату 15. Бюджет (225 кадров, комната 3): 415 284 – 416 370 = 0.966–0.968 кадра. Против 384 168 – 384 636 до этого шага, то есть +31 700. Разложение по фазам (медианы): process_trobs 83 190, pop_guard_draw 92 483 (спрайт 28 763 + клинок 23 820 + fore_over_char 39 906), kid_draw 59 089, fore поверх Кида + борта 47 483, heal 40 068, логика 76 338, ввод 13 050. Видно, что клинок 21x8 стоит почти как спрайт стража — это фиксированные накладные расходы клипающего блита, а не пиксели; лечится noclip-путём для column-major (см. gfx_blit_noclip_fast). Отдельным шагом. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -42,4 +42,31 @@ static const uint16_t kid_seq_off[KID_NSEQ] = {
|
||||
0x21FC,0x2240,0x2257,
|
||||
};
|
||||
|
||||
/* sword_tbl (seg006:2047): клинок отдельным спрайтом chtab_0.
|
||||
* Индекс — sword_frame (кадр.sword & 0x3F), id 255 = клинка нет.
|
||||
* Смещения x/y — ЭКРАННЫЕ (применяются после calc_screen_x_coord),
|
||||
* x — «вперёд» по направлению персонажа. */
|
||||
#define KID_NSWORD 51
|
||||
#define KID_SWORD_ID_INIT { \
|
||||
0xFF,0x00,0x05,0x01,0x02,0x06,0x07,0x03,0x04,0x1E,0x08,0x09, \
|
||||
0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x13,0x11, \
|
||||
0x11,0x07,0x01,0x1C,0x08,0x04,0x04,0x0A,0x0D,0x0D,0x0D,0x14, \
|
||||
0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0xFF,0xFF,0x1D,0x08,0x1F, \
|
||||
0x20,0x21,0x08, \
|
||||
}
|
||||
#define KID_SWORD_DX_INIT { \
|
||||
0,0,-9,7,17,7,0,17,16,12,13,7, \
|
||||
10,10,22,28,13,0,0,21,14,21,22,7, \
|
||||
15,0,7,14,7,6,9,11,24,19,21,7, \
|
||||
14,14,14,28,28,21,14,14,21,0,8,14, \
|
||||
14,7,8, \
|
||||
}
|
||||
#define KID_SWORD_DY_INIT { \
|
||||
0,-9,-29,-25,-26,-14,-5,-16,-19,-9,-34,-25, \
|
||||
-16,-11,-21,-23,-35,-38,-29,-19,-23,-22,-23,-13, \
|
||||
-18,-8,-27,-28,-27,-23,-21,-18,-23,-23,-23,-32, \
|
||||
-32,-31,-29,-28,-28,-25,-22,-25,-25,-16,-37,-24, \
|
||||
-24,-14,-37, \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
#include "pop_guard.h"
|
||||
#include "pop_kid.h" /* pop_sword_draw — клинок общий с Кидом */
|
||||
#include "pop_bg.h" /* POP_YOFF, pop_fore_over_char */
|
||||
#include "kid_data.h"
|
||||
|
||||
@@ -29,6 +30,13 @@ static int gx_l[2], gy_l[2];
|
||||
static uint16_t gw_l[2], gh_l[2];
|
||||
static uint8_t gvalid[2];
|
||||
|
||||
/* Клинок — ОТДЕЛЬНЫМ прямоугольником, не объединением со стражем: объединение
|
||||
* почти вдвое больше суммы двух (клинок уходит вперёд-вверх), а heal стоит
|
||||
* ровно по площади. Объединение считаем только для окна fore-клипа. */
|
||||
static int sx_l[2], sy_l[2];
|
||||
static uint16_t sw_l[2], sh_l[2];
|
||||
static uint8_t svalid[2];
|
||||
|
||||
int pop_guard_load(void) __banked
|
||||
{
|
||||
static const char *const names[GUARD_PAGES] = {
|
||||
@@ -54,15 +62,20 @@ void pop_guard_heal(void) __banked
|
||||
{
|
||||
uint8_t p = gfx_get_draw_page() & 1;
|
||||
if (gvalid[p]) gfx_heal(gx_l[p], gy_l[p] + POP_YOFF, gw_l[p], gh_l[p]);
|
||||
gvalid[p] = 0;
|
||||
if (svalid[p]) gfx_heal(sx_l[p], sy_l[p] + POP_YOFF, sw_l[p], sh_l[p]);
|
||||
gvalid[p] = svalid[p] = 0;
|
||||
}
|
||||
|
||||
void pop_guard_draw(void) __banked
|
||||
{
|
||||
int obj_x, obj_y, top, fwd, fp_x, bx0 = 0, top0 = 0;
|
||||
int obj_x, obj_y, top, fwd, fp_x;
|
||||
uint8_t page, idx, p, flip;
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
/* Окно fore-клипа — по ОБЪЕДИНЁННОМУ габариту «страж + клинок»; сам
|
||||
* футпринт (pop_fore_over_char) считается по спрайту стража, поэтому
|
||||
* w/h ниже НЕ трогаем. */
|
||||
int clip_x = 0, clip_y = 0; uint16_t clip_w = 0, clip_h = 0;
|
||||
|
||||
if (!g_ok || Guard.charid == 0 || pop_gframe.image == 255) return;
|
||||
/* load_frame_to_obj (seg008:1728) — та же математика, что у Kid. */
|
||||
@@ -85,17 +98,41 @@ void pop_guard_draw(void) __banked
|
||||
flip = (uint8_t)(Guard.direction >= 0); /* спрайты нарисованы влево */
|
||||
if (flip) bx -= (int)w;
|
||||
top = obj_y - (int)h + 1;
|
||||
bx0 = bx; top0 = top;
|
||||
p = gfx_get_draw_page() & 1;
|
||||
gfx_set_bank(GFX_BANK_SPRITE);
|
||||
gfx_blit_cols_part(bx, top + POP_YOFF, img, flip, 0, 0);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
gx_l[p] = bx; gy_l[p] = top; gw_l[p] = w; gh_l[p] = h; gvalid[p] = 1;
|
||||
clip_x = bx; clip_y = top; clip_w = w; clip_h = h;
|
||||
}
|
||||
/* Клинок стража — тот же chtab_0, что у Кида (add_sword_to_objtable,
|
||||
* seg006:1798): у ЖИВОГО стража меч в руке всегда. Свой прямоугольник
|
||||
* heal; окно fore-клипа — объединение (без него клинок полез бы поверх
|
||||
* переднего столба). */
|
||||
{
|
||||
int sx, sy; uint16_t sw, sh;
|
||||
if (pop_sword_draw(&Guard, &pop_gframe, obj_x, obj_y,
|
||||
&sx, &sy, &sw, &sh)) {
|
||||
p = gfx_get_draw_page() & 1;
|
||||
sx_l[p] = sx; sy_l[p] = sy; sw_l[p] = sw; sh_l[p] = sh;
|
||||
svalid[p] = 1;
|
||||
if (!clip_w) {
|
||||
clip_x = sx; clip_y = sy; clip_w = sw; clip_h = sh;
|
||||
} else {
|
||||
int x1 = clip_x + (int)clip_w, y1 = clip_y + (int)clip_h;
|
||||
if (sx < clip_x) clip_x = sx;
|
||||
if (sy < clip_y) clip_y = sy;
|
||||
if (sx + (int)sw > x1) x1 = sx + (int)sw;
|
||||
if (sy + (int)sh > y1) y1 = sy + (int)sh;
|
||||
clip_w = (uint16_t)(x1 - clip_x);
|
||||
clip_h = (uint16_t)(y1 - clip_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
/* Окно fore-слоя = прямоугольник стража (см. pop_bg.c, fclip_on):
|
||||
* без него проход возвращал ЦЕЛЫЕ тайлы — 432 К тактов на кадр. */
|
||||
pop_fore_set_clip(bx0, top0 + POP_YOFF, (int)w, (int)h);
|
||||
/* Окно fore-слоя = прямоугольник стража с клинком (см. pop_bg.c,
|
||||
* fclip_on): без него проход возвращал ЦЕЛЫЕ тайлы — 432 К тактов. */
|
||||
pop_fore_set_clip(clip_x, clip_y + POP_YOFF, (int)clip_w, (int)clip_h);
|
||||
/* Передние грани тайлов ПОВЕРХ стража: в оригинале персонаж — запись
|
||||
* midtable, а foretable рисуется после всех midtable-записей, поэтому
|
||||
* колонна/кромка пола перекрывает ЛЮБОГО персонажа, не только Kid
|
||||
|
||||
@@ -28,15 +28,15 @@ int8_t knock;
|
||||
static atlas_t kidp[KID_MAXPAGES];
|
||||
static uint8_t kid_npages;
|
||||
|
||||
/* chtab_0 «меч в руке» (add_sword_to_objtable, seg006:1798): отдельный
|
||||
* спрайт клинка поверх Kid в кадрах «нашёл меч»/убирание в ножны (229..237).
|
||||
* Из sword_tbl взяты только строки 35..42 — те, что адресуют эти кадры (бой
|
||||
* не портирован); индекс в атласе = sword_frame − 35. Смещения таблицы —
|
||||
* в ЭКРАННЫХ пикселях: оригинал применяет их ПОСЛЕ calc_screen_x_coord. */
|
||||
#define SWORD_SF_LO 35
|
||||
#define SWORD_SF_HI 42
|
||||
static const int8_t SWORD_DX[8] = { 7, 14, 14, 14, 28, 28, 21, 14 };
|
||||
static const int8_t SWORD_DY[8] = {-32,-32,-31,-29,-28,-28,-25,-22 };
|
||||
/* chtab_0 «меч в руке» (add_sword_to_objtable, seg006:1798): клинок —
|
||||
* ОТДЕЛЬНЫЙ спрайт поверх персонажа, один и тот же атлас у Кида и у стража.
|
||||
* Таблица sword_tbl (kid_data.h, генерится из seg006) индексируется
|
||||
* sword_frame = кадр.sword & 0x3F; id 255 = клинка в этом кадре нет.
|
||||
* Смещения — в ЭКРАННЫХ пикселях: оригинал применяет их ПОСЛЕ
|
||||
* calc_screen_x_coord, x — «вперёд» по направлению персонажа. */
|
||||
static const uint8_t SWORD_ID[KID_NSWORD] = KID_SWORD_ID_INIT;
|
||||
static const int8_t SWORD_DX[KID_NSWORD] = KID_SWORD_DX_INIT;
|
||||
static const int8_t SWORD_DY[KID_NSWORD] = KID_SWORD_DY_INIT;
|
||||
static atlas_t swordp;
|
||||
static uint8_t sword_ok;
|
||||
|
||||
@@ -47,6 +47,46 @@ int pop_sword_load(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add_sword_to_objtable (seg006:1798). Клинок рисуется, если персонаж в
|
||||
* кадрах подъёма/ножен, ИЛИ держит меч, ИЛИ это ЖИВОЙ страж (у стража меч
|
||||
* в руке всегда, даже пока sword ещё sheathed). Страницу W0 оставляем
|
||||
* замапленной — вызывающий делает gfx_w0_unmap сам. */
|
||||
uint8_t pop_sword_draw(const pop_char_t *ch, const kframe *fr,
|
||||
int obj_x, int obj_y,
|
||||
int *rx, int *ry, uint16_t *rw, uint16_t *rh)
|
||||
{
|
||||
uint8_t sf, id, flip;
|
||||
const uint8_t *simg;
|
||||
uint16_t w, h;
|
||||
int bx, top;
|
||||
|
||||
if (!sword_ok) return 0;
|
||||
if (!((ch->frame >= 229 && ch->frame < 238) ||
|
||||
ch->sword != 0 ||
|
||||
(ch->charid == CHARID_2_GUARD && ch->alive < 0)))
|
||||
return 0;
|
||||
sf = (uint8_t)(fr->sword & 0x3F);
|
||||
if (sf == 0 || sf >= KID_NSWORD) return 0;
|
||||
id = SWORD_ID[sf];
|
||||
if (id == 0xFF) return 0;
|
||||
|
||||
simg = (const uint8_t *)atlas_image(&swordp, id);
|
||||
gfx_w0_map(swordp.page);
|
||||
w = (uint16_t)(simg[0] | ((uint16_t)simg[1] << 8));
|
||||
h = (uint16_t)(simg[2] | ((uint16_t)simg[3] << 8));
|
||||
if (!w || !h) return 0;
|
||||
|
||||
flip = (uint8_t)(ch->direction >= 0);
|
||||
bx = obj_x + ((ch->direction < 0) ? -(int)SWORD_DX[sf] : (int)SWORD_DX[sf]);
|
||||
top = obj_y + (int)SWORD_DY[sf] - (int)h + 1;
|
||||
if (flip) bx -= (int)w;
|
||||
gfx_set_bank(GFX_BANK_SPRITE);
|
||||
gfx_blit_cols_part(bx, top + POP_YOFF, simg, flip, 0, 0);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
*rx = bx; *ry = top; *rw = w; *rh = h;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pop_kid_load(uint8_t npages)
|
||||
{
|
||||
static const char *const names[KID_MAXPAGES] = {
|
||||
@@ -371,6 +411,64 @@ 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;
|
||||
@@ -417,23 +515,12 @@ void kid_draw_splash(void)
|
||||
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);
|
||||
/* Прямоугольник splash расширяет область heal ЭТОЙ страницы: иначе
|
||||
* брызги останутся на экране после кадра. */
|
||||
/* Брызги — накладной спрайт: свой прямоугольник heal (см.
|
||||
* kid_overlay_add), окно fore пересчитываем объединением. */
|
||||
{
|
||||
uint8_t dp = gfx_get_draw_page();
|
||||
if (kid_lvalid[dp]) {
|
||||
int x0 = kid_lx[dp] < bx ? kid_lx[dp] : bx;
|
||||
int y0 = kid_ly[dp] < top ? kid_ly[dp] : top;
|
||||
int x1 = kid_lx[dp] + (int)kid_lw[dp];
|
||||
int y1 = kid_ly[dp] + (int)kid_lh[dp];
|
||||
if (bx + (int)w > x1) x1 = bx + (int)w;
|
||||
if (top + (int)h > y1) y1 = top + (int)h;
|
||||
kid_lx[dp] = x0; kid_ly[dp] = y0;
|
||||
kid_lw[dp] = (uint16_t)(x1 - x0); kid_lh[dp] = (uint16_t)(y1 - y0);
|
||||
/* Окно fore-слоя расширяем тем же объединением: брызги
|
||||
* тоже должны уходить под передние грани тайлов. */
|
||||
pop_fore_set_clip(x0, y0 + POP_YOFF, x1 - x0, y1 - y0);
|
||||
}
|
||||
kid_overlay_add(dp, bx, top, w, h);
|
||||
kid_fore_clip(dp);
|
||||
}
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
@@ -445,7 +532,9 @@ void kid_heal(void)
|
||||
uint8_t p = gfx_get_draw_page();
|
||||
if (kid_lvalid[p])
|
||||
gfx_heal(kid_lx[p], kid_ly[p] + POP_YOFF, kid_lw[p], kid_lh[p]); /* +YOFF: центрирование */
|
||||
kid_lvalid[p] = 0;
|
||||
if (kid_ovalid[p])
|
||||
gfx_heal(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)
|
||||
@@ -518,57 +607,16 @@ void kid_draw(void)
|
||||
kid_fp_w = w; kid_fp_h = h; /* размер кадра для футпринта fore */
|
||||
}
|
||||
/* add_sword_to_objtable (seg006:1798): клинок отдельным спрайтом поверх
|
||||
* Kid. Прямоугольник heal расширяем объединением — иначе клинок, выйдя
|
||||
* за габарит Kid, оставит след. */
|
||||
if (sword_ok && Kid.frame >= 229 && Kid.frame < 238) {
|
||||
uint8_t sf = (uint8_t)(fr.sword & 0x3F);
|
||||
if (sf >= SWORD_SF_LO && sf <= SWORD_SF_HI) {
|
||||
uint8_t si = (uint8_t)(sf - SWORD_SF_LO);
|
||||
const uint8_t *simg = (const uint8_t *)atlas_image(&swordp, si);
|
||||
uint16_t sw, sh;
|
||||
gfx_w0_map(swordp.page);
|
||||
sw = (uint16_t)(simg[0] | ((uint16_t)simg[1] << 8));
|
||||
sh = (uint16_t)(simg[2] | ((uint16_t)simg[3] << 8));
|
||||
if (sw && sh) {
|
||||
uint8_t sflip = (Kid.direction >= 0);
|
||||
int sbx = obj_x + ((Kid.direction < 0) ? -(int)SWORD_DX[si]
|
||||
: (int)SWORD_DX[si]);
|
||||
int stop = obj_y + (int)SWORD_DY[si] - (int)sh + 1;
|
||||
uint8_t dp = gfx_get_draw_page() & 1;
|
||||
if (sflip) sbx -= (int)sw;
|
||||
gfx_set_bank(GFX_BANK_SPRITE);
|
||||
gfx_blit_cols_part(sbx, stop + POP_YOFF, simg, sflip, 0, 0);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
if (!kid_lvalid[dp]) {
|
||||
kid_lx[dp] = sbx; kid_ly[dp] = stop;
|
||||
kid_lw[dp] = sw; kid_lh[dp] = sh;
|
||||
kid_lvalid[dp] = 1;
|
||||
} else {
|
||||
int x0 = kid_lx[dp], y0 = kid_ly[dp];
|
||||
int x1 = x0 + (int)kid_lw[dp], y1 = y0 + (int)kid_lh[dp];
|
||||
if (sbx < x0) x0 = sbx;
|
||||
if (stop < y0) y0 = stop;
|
||||
if (sbx + (int)sw > x1) x1 = sbx + (int)sw;
|
||||
if (stop + (int)sh > y1) y1 = stop + (int)sh;
|
||||
kid_lx[dp] = x0; kid_ly[dp] = y0;
|
||||
kid_lw[dp] = (uint16_t)(x1 - x0);
|
||||
kid_lh[dp] = (uint16_t)(y1 - y0);
|
||||
}
|
||||
}
|
||||
}
|
||||
* 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-слоя = итоговый прямоугольник спрайта (с клинком и
|
||||
* обрезкой clip_char): fore-проход вернёт куски тайлов ТОЛЬКО поверх
|
||||
* него, а не целыми тайлами — см. pop_bg.c, fclip_on. Ставим и когда
|
||||
* рисовать нечего (kid_lvalid=0): нулевое окно = fore-проход не
|
||||
* трогает экран, что и правильно — перекрывать нечего. */
|
||||
{
|
||||
uint8_t dp = gfx_get_draw_page() & 1;
|
||||
if (kid_lvalid[dp])
|
||||
pop_fore_set_clip(kid_lx[dp], kid_ly[dp] + POP_YOFF,
|
||||
(int)kid_lw[dp], (int)kid_lh[dp]);
|
||||
else
|
||||
pop_fore_set_clip(0, 0, 0, 0);
|
||||
}
|
||||
/* Окно fore-слоя = объединение «Kid + клинок» (с обрезкой clip_char):
|
||||
* fore-проход вернёт куски тайлов ТОЛЬКО поверх него, а не целыми
|
||||
* тайлами — см. pop_bg.c, fclip_on. Ставим и когда рисовать нечего:
|
||||
* нулевое окно = fore-проход не трогает экран, что и правильно. */
|
||||
kid_fore_clip(gfx_get_draw_page() & 1);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "pop_char.h"
|
||||
#include "kid_data.h" /* kframe — тип кадра для pop_sword_draw */
|
||||
|
||||
/* Состояние персонажа — общий тип для Кида, стража и Char (pop_char.h). */
|
||||
extern pop_char_t Kid;
|
||||
@@ -43,6 +44,15 @@ void pop_kid_data_free(void);
|
||||
int pop_sword_load(void);
|
||||
void pop_kid_free(void);
|
||||
|
||||
/* Нарисовать клинок chtab_0 поверх персонажа (порт add_sword_to_objtable,
|
||||
* seg006:1798) — общая точка для Кида и стража: меч в оригинале ОДИН на
|
||||
* всех. obj_x/obj_y — та же опорная точка, что у спрайта персонажа.
|
||||
* Возвращает 1 и прямоугольник клинка (для heal), 0 — клинка нет.
|
||||
* Страницу W0 оставляет замапленной: вызывающий делает gfx_w0_unmap. */
|
||||
uint8_t pop_sword_draw(const pop_char_t *ch, const kframe *fr,
|
||||
int obj_x, int obj_y,
|
||||
int *rx, int *ry, uint16_t *rw, uint16_t *rh);
|
||||
|
||||
/* Инициализировать 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);
|
||||
|
||||
@@ -73,6 +73,12 @@ uint8_t pop_cheats;
|
||||
* Убирается закомментированием ОДНОЙ строки ниже. */
|
||||
#define ROOMNAV 1
|
||||
|
||||
/* ОТЛАДКА БОЁВКИ: выдавать Киду меч сразу при входе в комнату с этим
|
||||
* номером (в комнате 3 стоит страж уровня 1). Иначе каждый прогон надо
|
||||
* бежать за мечом в комнату 15. Убрать, когда боёвку можно будет
|
||||
* проверять штатным путём. */
|
||||
#define DEBUG_SWORD_ROOM 3
|
||||
|
||||
/* Рабочая копия ТЕКУЩЕЙ комнаты (W2, мутабельная: loose→empty) + срезы
|
||||
* соседей для кромок. Заполняются pop_room_load из уровня. File-scope,
|
||||
* чтобы enter_room переключал комнату без длинного списка параметров. */
|
||||
@@ -196,6 +202,9 @@ static void enter_room(uint8_t room)
|
||||
* Kid.room == Guard.room нужно уже сейчас: без него луч видимости
|
||||
* стража никогда не срабатывает. */
|
||||
Kid.room = room;
|
||||
#ifdef DEBUG_SWORD_ROOM
|
||||
if (room == DEBUG_SWORD_ROOM) pop_have_sword = 1;
|
||||
#endif
|
||||
pop_loose_reset(); /* loose-состояние не тянем из старой комнаты */
|
||||
pop_trob_room_changed(); /* отложенные перерисовки пик — не из старой комнаты */
|
||||
pop_trob_anim_room(room); /* факелы/зелья: стартовая фаза + trob */
|
||||
|
||||
Reference in New Issue
Block a user