PoP roomtest: clip_char (верхняя обрезка спрайта) + подстановка нажатой кнопки
Спуск Кида с кнопки (room8, кромка (0,6)) рисовался неверно: Кид просвечивал в щель между кнопкой и ближним столбом, а ближняя рука была срезана до одного оторванного пикселя. Две независимые причины. 1. Не был портирован clip_char() (seg006:1749) — оригинал перед add_objtable обрезает спрайт персонажа сверху по y_clip[curr_row+1], когда тайл над головой стена или пол. Порт: pop_clip_char_top() (pop_map.c, метрики по set_char_collision) + новый примитив gfx_blit_cols_part() в libbgi (блит column-major с пропуском skip верхних строк; обрезка сверху бесплатна — колонка непрерывна в ОЗУ, сдвигается только старт). gfx_blit_cols стал тонкой обёрткой над ним. kid_heal чистит уже ОБРЕЗАННЫЙ прямоугольник, иначе стирается кромка пола над срезом. 2. climb_overlay_tile (порт draw_floor_overlay, seg008:1E3A) выбирал ветку по СЫРОМУ коду тайла, а get_tile_to_draw (seg008:240) подменяет нажатую кнопку на floor/stuck. Тайл-кнопка не проходил тест floor → уходил в draw_other_overlay, который кладёт поверх Кида ВЕСЬ тайл вместо узкой кромки floor_left_overlay[frame-137]. Фикс — tile_code_drawn(): одна подстановка на все слои (fore_only_tile/overlay_mid_tile перестали её дублировать, W3 −293 Б). Проверено покадрово в MAME (шаг gv + снимок): кадры спуска 148..138 чистые, после приземления на кнопке мусора нет. Заодно: gfx_heal_noclip() (пара к gfx_blit_noclip; heal 11658 -> 8982 тактов) и rest_pending в pop_trob — холостой проход по 30 тайлам только когда есть отложенные редрои пик/кнопок (pop_process_trobs 89-111К -> 70-92К тактов). START_ROOM временно = 8 (отладка спуска с кнопки), вернуть на 6/старт уровня. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1050,6 +1050,54 @@ void pop_loose_tick(void)
|
||||
/* y_to_row_mod4 (seg006): ряд по y с оборотом mod4 (TILE_SIZEY=63). */
|
||||
static int8_t y_to_row(int16_t y) { return (int8_t)(((y + 60) / 63) % 4 - 1); }
|
||||
|
||||
/* ---- clip_char (seg006:1749), первый блок: обрезка спрайта СВЕРХУ ----- *
|
||||
* Оригинал перед add_objtable кладёт в objtable прямоугольник клипа; блиттер
|
||||
* рисует персонажа только внутри него. Верхняя граница: если тайл НАД
|
||||
* головой (ряд char_top_row) — стена или пол, всё выше линии своей полосы
|
||||
* (y_clip[curr_row+1]) не рисуется. Без этого Kid, ушедший головой под пол
|
||||
* (спуск с кромки/кнопки, вис), просвечивает сквозь щели кладки.
|
||||
*
|
||||
* Хитрость исходника: `X == wall || tile_is_floor(curr_tile2)` — curr_tile2
|
||||
* ставит сам get_tile, т.е. это просто «тайл X = стена ИЛИ пол».
|
||||
*
|
||||
* Метрики габарита — порт set_char_collision (seg006:0723); в отличие от
|
||||
* check_spike_below колонки берутся get_tile_div_mod БЕЗ −7.
|
||||
*
|
||||
* Возврат: КОМНАТНЫЙ y верхней границы (0 = клипа нет). */
|
||||
int pop_clip_char_top(int obj_x, int obj_y, uint16_t w, uint16_t h)
|
||||
{
|
||||
static const int16_t y_clip[5] = { -60, 3, 66, 129, 192 };
|
||||
int wh = ((int)w + 1) >> 1; /* char_width_half */
|
||||
int xl = obj_x / 2 + 58; /* char_x_left */
|
||||
int xr, top_y, clip_y;
|
||||
int8_t cL, cR, trow, clip_row;
|
||||
uint8_t t;
|
||||
|
||||
if (Kid.direction >= 0) xl -= wh; /* лицом вправо: левый край внутрь */
|
||||
xr = xl + wh; /* char_x_right */
|
||||
top_y = obj_y - (int)h + 1; /* char_top_y */
|
||||
if (top_y >= 192) top_y = 0; /* весь спрайт ниже комнаты */
|
||||
trow = y_to_row((int16_t)top_y); /* char_top_row */
|
||||
cL = get_tile_div_mod(xl); if (cL < 0) cL = 0;
|
||||
cR = get_tile_div_mod(xr); if (cR > 9) cR = 9;
|
||||
|
||||
t = get_tile(cL, trow);
|
||||
if (t != TILE_WALL && !tile_is_floor(t)) return 0;
|
||||
/* кадр 79 (прыжок вверх) / 81 (зацеп) в стойке клипятся и по одной грани */
|
||||
if (!(Kid.action == 0 && (Kid.frame == 79 || Kid.frame == 81))) {
|
||||
t = get_tile(cR, trow);
|
||||
if (t != TILE_WALL && !tile_is_floor(t)) return 0;
|
||||
}
|
||||
|
||||
clip_row = (int8_t)(Kid.curr_row + 1);
|
||||
if (clip_row < 0 || clip_row > 4) return 0;
|
||||
clip_y = y_clip[clip_row];
|
||||
/* ряд 0 — клип безусловный; иначе только когда линия реально режет спрайт */
|
||||
if (clip_row == 1 || (clip_y < obj_y && clip_y - 15 < top_y))
|
||||
return clip_y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check_leave_below (порт leave_room, seg002: leave_dir=3 при chary>=211):
|
||||
* Kid пересёк нижнюю границу комнаты (провал в дыру ИЛИ спуск-зацеп/climbdown
|
||||
* — единый триггер по y). Репроекция в кадр комнаты снизу (goto_other_room
|
||||
|
||||
Reference in New Issue
Block a user