applications/PoP/roomtest: fore-слой поверх Kid (передние тайлы)

Порт SDLPoP seg003 redraw_at_char + seg008 set_char_collision: после
kid_draw передний слой (fore_id = foretable-кусок) тайлов ФУТПРИНТА
спрайта Kid перерисовывается ПОВЕРХ него — то, что по изометрии перед
персонажем (передние грани колонн/ворот/большой колонны/щебня).  Стены и
факелы имеют fore_id=0 → остаются сзади (в статическом фоне).

- pop_bg: pop_fore_over_kid(obj_x,obj_y,w,h,dir) — считает футпринт
  (char_x_left/right, col_from_x, y_to_row_mod4) рядов top..bottom ×
  колонок left..right (≤2×2=4 тайла) и рисует fore_id каждого в
  GFX_BANK_SPRITE (видео-ОЗУ; kid_heal восстановит из теневого фона,
  fore в нём запечён pop_room_draw).
- pop_kid: kid_fp_obj_x/y/width/height — метрики последнего кадра
  (obj_x ЛОГИЧЕСКАЯ, до ×8/7) для футпринта.
- roomtest: вызов pop_fore_over_kid после kid_draw.

Проверено в MAME: Kid, идя влево мимо колонны под навесом (row1 col3),
корректно уходит ЗА её переднюю грань (скрывается) и выходит с другой
стороны; задние колонны/факелы остаются сзади.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 21:34:32 +03:00
parent ea57a03543
commit 78f2aaec1a
5 changed files with 81 additions and 0 deletions
+51
View File
@@ -392,3 +392,54 @@ void pop_room_draw(uint8_t room_num,
draw_tile(row, col);
gfx_set_bank(GFX_BANK_NORMAL);
}
/* ---- fore-over-Kid (порт seg003 redraw_at_char + seg008 set_char_collision) --
* Передний слой (fore_id = foretable-кусок) тайлов ФУТПРИНТА спрайта Kid
* — рядов top..bottom × колонок left..right (<= 2×2 = 4 тайла) — рисуется
* ПОВЕРХ Kid: то, что по изометрии перед ним (передние грани колонн/ворот/
* большой колонны/щебня). Стены и факелы имеют fore_id=0 → остаются сзади.
* Рисуем в GFX_BANK_SPRITE (видео-ОЗУ, 0xFF прозрачен); kid_heal восстановит
* из теневого фона (fore в нём уже запечён pop_room_draw). obj_x — ЛОГИЧЕСКАЯ
* X кадра Kid (до ×8/7), obj_y — низ спрайта, w/h — размер, dir — направление. */
static int8_t col_from_x(int xpos) /* get_tile_div_mod: колонка (58/14) */
{
int x = xpos - 58;
int xh = x / 14;
if (x % 14 < 0) xh--; /* округление вниз для отрицательных */
return (int8_t)xh;
}
static int8_t y_to_row(int y) /* y_to_row_mod4 (TILE_SIZEY=63) */
{
return (int8_t)((y + 60) / 63 % 4 - 1);
}
static void fore_tile(int row, int col) /* fore одного тайла, если fore_id≠0 */
{
uint8_t code = tile_code(row, col);
const piece *t = &tile_table[code];
if (t->fore_id) {
int x = COL_XH[col] * 8;
int dmy = 63 * row + 62;
fore_b(t->fore_id, t->fore_x * 8 + x, t->fore_y + dmy);
}
}
void pop_fore_over_kid(int obj_x, int obj_y, uint16_t w, uint16_t h, int8_t dir)
{
int wh = (int)((w + 1) >> 1); /* char_width_half */
int xl = obj_x / 2 + 58; /* char_x_left (58-база) */
int xr;
int8_t cL, cR, rT, rB, r, c;
if (dir >= 0) xl -= wh; /* лицом вправо: левый край внутрь */
xr = xl + wh;
cL = col_from_x(xl); if (cL < 0) cL = 0; else if (cL > 9) cL = 9;
cR = col_from_x(xr); if (cR < 0) cR = 0; else if (cR > 9) cR = 9;
rB = y_to_row(obj_y); if (rB < 0) rB = 0; else if (rB > 2) rB = 2;
rT = y_to_row(obj_y - (int)h + 1); if (rT < 0) rT = 0; else if (rT > 2) rT = 2;
gfx_set_bank(GFX_BANK_SPRITE); /* видео-ОЗУ, heal восстановит */
for (r = rT; r <= rB; r++)
for (c = cL; c <= cR; c++)
fore_tile(r, c);
gfx_set_bank(GFX_BANK_NORMAL);
}
+6
View File
@@ -29,4 +29,10 @@ void pop_room_draw(uint8_t room_num,
const uint8_t *fg, const uint8_t *bg,
const uint8_t *lcol_fg, const uint8_t *lcol_bg);
/* Перерисовать передний слой (fore) тайлов футпринта Kid ПОВЕРХ него —
* звать ПОСЛЕ kid_draw. obj_x — ЛОГИЧЕСКАЯ X кадра (до ×8/7), obj_y — низ
* спрайта, w/h — размер кадра, dir — направление Kid (<0 влево). Метрики
* берутся из pop_kid (kid_fp_*). См. redraw_at_char/set_char_collision. */
void pop_fore_over_kid(int obj_x, int obj_y, uint16_t w, uint16_t h, int8_t dir);
#endif
+12
View File
@@ -167,6 +167,15 @@ static int kid_lx, kid_ly;
static uint16_t kid_lw, kid_lh;
static uint8_t kid_lvalid;
/* Метрики последнего 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;
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; }
/* Восстановить фон из теневой копии на месте ПРЕДЫДУЩЕГО кадра Kid. */
void kid_heal(void)
{
@@ -190,6 +199,8 @@ void kid_draw(void)
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). Коллизия — в
@@ -215,6 +226,7 @@ void kid_draw(void)
gfx_set_bank(GFX_BANK_NORMAL);
kid_lx = bx; kid_ly = top;
kid_lw = w; kid_lh = h; kid_lvalid = 1;
kid_fp_w = w; kid_fp_h = h; /* размер кадра для футпринта fore */
}
gfx_w0_unmap();
}
+8
View File
@@ -60,4 +60,12 @@ void kid_draw(void);
* вместо перерисовки всего экрана. Звать ПЕРЕД kid_tick/kid_draw. */
void kid_heal(void);
/* Метрики последнего kid_draw для футпринта fore-over-Kid (pop_bg
* pop_fore_over_kid): obj_x — ЛОГИЧЕСКАЯ X кадра (до ×8/7), obj_y — низ
* спрайта, w/h — размер кадра. */
int kid_fp_obj_x(void);
int kid_fp_obj_y(void);
uint16_t kid_fp_width(void);
uint16_t kid_fp_height(void);
#endif
+4
View File
@@ -49,6 +49,8 @@ int main(void)
pop_map_set(room1_fg); /* карта для коллизии/падения (K3) */
kid_init(SEQ_STAND, 1, 1, 0);
kid_draw();
pop_fore_over_kid(kid_fp_obj_x(), kid_fp_obj_y(),
kid_fp_width(), kid_fp_height(), Kid.direction);
if (pop_ctrl_init() != 0) { /* raw-канал клавиатуры (забирает ввод у DSS) */
closegraph();
@@ -69,6 +71,8 @@ int main(void)
kid_init(SEQ_STAND, 1, 1, 0);
}
kid_draw(); /* нарисовать новый кадр */
pop_fore_over_kid(kid_fp_obj_x(), kid_fp_obj_y(),
kid_fp_width(), kid_fp_height(), Kid.direction);
}
pop_ctrl_close();