PoP roomtest: отрисовка стража в резидент W3 + fore-окклюзия + off-by-one спрайта
Разгрузка 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>
This commit is contained in:
@@ -1,21 +1,25 @@
|
||||
/*
|
||||
* pop_guard.c — состояние стража (W1/W2). См. pop_guard.h.
|
||||
* Логика — в банке (guards.c), отрисовка — из главного цикла.
|
||||
* pop_guard.c — СОСТОЯНИЕ и ЛОГИКА стража (W1/W2). См. pop_guard.h.
|
||||
*
|
||||
* Здесь только то, что должно оставаться достижимым из банка (guards.c):
|
||||
* поля Guard, HP, вход в комнату, чит-убийство, чтение кадра из таблицы.
|
||||
* ОТРИСОВКА — в pop_gdraw.c, резиденте W3 (её зовёт лишь главный цикл).
|
||||
*/
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
#include <stdint.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 "pop_kid.h" /* pop_kid_data_frame — таблицы в EMM-странице */
|
||||
#include "kid_data.h"
|
||||
|
||||
pop_char_t Guard;
|
||||
uint8_t guardhp_curr, guardhp_max;
|
||||
int8_t guardhp_delta;
|
||||
|
||||
/* Кадр стража (порт cur_frame для Char). Глобальный, а не статик: его
|
||||
* заполняет логика (W1/W2), а читает отрисовка из резидента W3. */
|
||||
kframe pop_gframe;
|
||||
|
||||
uint8_t pop_guard_present(void)
|
||||
{
|
||||
return (uint8_t)(Guard.charid != 0 && Guard.alive < 0 && guardhp_curr != 0);
|
||||
@@ -45,51 +49,16 @@ void pop_guard_kill(void)
|
||||
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, где
|
||||
/* load_frame для стража (seg006:0293 ветка charid_2_guard): таблица у
|
||||
* стражей СВОЯ (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)
|
||||
void pop_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);
|
||||
if (idx < 0 || idx >= KID_NGFRAMES) { pop_gframe.image = 255; return; }
|
||||
pop_kid_data_frame(KID_BIN_GFRAMES_OFF, (uint8_t)idx, (uint8_t *)&pop_gframe);
|
||||
}
|
||||
|
||||
void pop_guard_enter(uint8_t room)
|
||||
@@ -118,48 +87,5 @@ void pop_guard_enter(uint8_t room)
|
||||
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();
|
||||
pop_guard_load_frame();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user