PoP roomtest: страж — спрайты, таблица кадров и появление в комнате
Шаги 1-2 из плана стражей: 1. Спрайты (chtab_5_guard, база 750). Новый упаковщик pop_pack_guard.py: data/GUARD/res751..784 -> GUARD\g0..g4.atl (5 EMM-страниц, адресация id>>3 / id&7, как у Kid). Палитра берётся НЕ из PNG, а из res10.bin (guard_palettes: 7 палитр по 16 цветов, 6-бит) по level.guards_color — на уровне 1 у обоих стражей color = 2; группа слотов 0x90..0x9F добавлена в общий kid.pal. 2. Таблица кадров стража у оригинала СВОЯ (frame_tbl_guard, seg006:372, 41 запись) и индексируется как frame + add_frame - 149, где add_frame = 70 для кадров 102..106. Она дописана в kid_data.bin (3515 -> 3720 Б, смещение в KID_BIN_GFRAMES_OFF); pop_kid получил pop_kid_data_frame() — чтение кадра из ЛЮБОЙ таблицы страницы данных. 3. Появление: pop_level_guard() читает guards_tile/dir/color/skill из уровня, pop_guard_enter() ставит стража по enter_guard (seg002:0112) + pos_guards (seg003): row из тайла, y = y_land[row+1], x из колонки, charid = guard, sword сложен, alive = -1, HP = 3. Отрисовка pop_guard_draw() — та же математика, что kid_draw (load_frame_to_obj + calc_screen_x_coord), но атлас стража и своя таблица кадров; heal по странице дабл-буфера, как у Kid. Интерпретатора последовательностей у стража ПОКА НЕТ: кадр ставится напрямую (166 = frame_166_stand_inactive, что и даёт seq_77 при входе в комнату). play_seq для произвольного персонажа + ИИ — следующая фаза. Проверено в MAME: в комнате 3 страж появляется на своём месте (ряд 1, кол 7) и рисуется; цвета совпадают с эталонным рендером спрайта в палитре color=2. ВНИМАНИЕ по памяти: куча W2 просела до 805 Б (было 2349). Перед ИИ стражей нужен шаг 5 плана (данные: room_modif 720 Б, dl1/dl2 512 Б, _kbdraw_down 512 Б) либо вынос кода отрисовки стража в резидент W3. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,15 @@
|
||||
* pop_guard.c — состояние стража (W1/W2). См. pop_guard.h.
|
||||
* Логика — в банке (guards.c), отрисовка — из главного цикла.
|
||||
*/
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
#include "pop_guard.h"
|
||||
#include "pop_geom.h"
|
||||
#include "pop_level.h"
|
||||
#include "pop_kid.h" /* play_seq/kid_set_seq пока общие (seqtbl один) */
|
||||
#include "pop_bg.h" /* POP_YOFF — вертикальное центрирование */
|
||||
#include "kid_data.h"
|
||||
|
||||
pop_char_t Guard;
|
||||
uint8_t guardhp_curr, guardhp_max;
|
||||
@@ -36,3 +44,122 @@ void pop_guard_kill(void)
|
||||
guardhp_curr = 0;
|
||||
Guard.alive = 0;
|
||||
}
|
||||
|
||||
/* ---- Атласы стража (chtab_5, база 750): g[id>>3], idx id&7 ---------- */
|
||||
#define GUARD_PAGES 5
|
||||
static atlas_t gp[GUARD_PAGES];
|
||||
static uint8_t g_ok;
|
||||
|
||||
/* Прямоугольник последней отрисовки ПО СТРАНИЦЕ дабл-буфера (как у Kid:
|
||||
* heal обязан стирать спрайт именно той страницы, в которую рисуем). */
|
||||
static int gx_l[2], gy_l[2];
|
||||
static uint16_t gw_l[2], gh_l[2];
|
||||
static uint8_t gvalid[2];
|
||||
|
||||
/* Кадр стража (порт cur_frame для Char): таблица у стражей СВОЯ
|
||||
* (frame_tbl_guard), и индексируется как frame + add_frame − 149, где
|
||||
* add_frame = 70 для кадров 102..106 (seg006:535). */
|
||||
static kframe gframe;
|
||||
|
||||
int pop_guard_load(void)
|
||||
{
|
||||
static const char *const names[GUARD_PAGES] = {
|
||||
"GUARD\\g0.atl", "GUARD\\g1.atl", "GUARD\\g2.atl",
|
||||
"GUARD\\g3.atl", "GUARD\\g4.atl"
|
||||
};
|
||||
uint8_t i;
|
||||
for (i = 0; i < GUARD_PAGES; i++)
|
||||
if (atlas_load(&gp[i], names[i]) != 0) return -1;
|
||||
g_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pop_guard_free(void)
|
||||
{
|
||||
uint8_t i;
|
||||
if (!g_ok) return;
|
||||
for (i = 0; i < GUARD_PAGES; i++) atlas_free(&gp[i]);
|
||||
g_ok = 0;
|
||||
}
|
||||
|
||||
/* load_frame для стража (seg006:0293 ветка charid_2_guard). */
|
||||
static void guard_load_frame(void)
|
||||
{
|
||||
int16_t idx = (int16_t)Guard.frame;
|
||||
if (idx >= 102 && idx < 107) idx += 70; /* add_frame */
|
||||
idx -= 149;
|
||||
if (idx < 0 || idx >= KID_NGFRAMES) { gframe.image = 255; return; }
|
||||
pop_kid_data_frame(KID_BIN_GFRAMES_OFF, (uint8_t)idx, (uint8_t *)&gframe);
|
||||
}
|
||||
|
||||
void pop_guard_enter(uint8_t room)
|
||||
{
|
||||
uint8_t tile, color, skill;
|
||||
int8_t dir;
|
||||
pop_guard_reset();
|
||||
if (!pop_level_guard(room, &tile, &dir, &color, &skill)) return;
|
||||
/* enter_guard (seg002:0112) + pos_guards (seg003): X считается из
|
||||
* колонки тайла, а не берётся из файла. */
|
||||
Guard.room = room;
|
||||
Guard.curr_row = (int8_t)(tile / 10);
|
||||
Guard.y = (uint8_t)pop_y_land[Guard.curr_row + 1];
|
||||
Guard.x = (uint8_t)(pop_x_bump[(tile % 10) + FIRST_ONSCREEN_COLUMN] + TILE_SIZEX);
|
||||
Guard.curr_col = (int8_t)(tile % 10);
|
||||
Guard.direction = dir;
|
||||
Guard.charid = CHARID_2_GUARD;
|
||||
Guard.sword = 0; /* sword_0_sheathed */
|
||||
Guard.alive = -1;
|
||||
Guard.action = 1; /* actions_1_run_jump */
|
||||
Guard.fall_x = Guard.fall_y = 0;
|
||||
/* seq_77_guard_stand_inactive даёт кадр 166 (frame_166_stand_inactive,
|
||||
* seqtbl.c:266). Интерпретатор последовательностей для стража придёт
|
||||
* вместе с ИИ (следующая фаза) — сейчас ставим кадр напрямую, чтобы
|
||||
* страж просто СТОЯЛ и было что рисовать/убивать читом. */
|
||||
Guard.frame = 166;
|
||||
guardhp_max = guardhp_curr = 3; /* get_guard_hp: skill 0, уровень 1 */
|
||||
guardhp_delta = 0;
|
||||
guard_load_frame();
|
||||
}
|
||||
|
||||
void pop_guard_heal(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void pop_guard_draw(void)
|
||||
{
|
||||
int obj_x, obj_y, top, fwd;
|
||||
uint8_t page, idx, p, flip;
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
|
||||
if (!g_ok || Guard.charid == 0 || gframe.image == 255) return;
|
||||
/* load_frame_to_obj (seg008:1728) — та же математика, что у Kid. */
|
||||
fwd = (int)Guard.x + ((Guard.direction < 0) ? -gframe.dx : gframe.dx);
|
||||
obj_x = (fwd << 1) - 116;
|
||||
obj_y = (int)Guard.y + gframe.dy;
|
||||
if ((int8_t)(gframe.flags ^ Guard.direction) >= 0) obj_x++;
|
||||
obj_x = obj_x * 8 / 7; /* calc_screen_x_coord */
|
||||
|
||||
page = (uint8_t)(gframe.image >> 3);
|
||||
idx = (uint8_t)(gframe.image & 7);
|
||||
if (page >= GUARD_PAGES) return;
|
||||
img = (const uint8_t *)atlas_image(&gp[page], idx);
|
||||
gfx_w0_map(gp[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) {
|
||||
int bx = obj_x;
|
||||
flip = (uint8_t)(Guard.direction >= 0); /* спрайты нарисованы влево */
|
||||
if (flip) bx -= (int)w;
|
||||
top = obj_y - (int)h + 1;
|
||||
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;
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user