diff --git a/applications/PoP/docs/l9_invert_plan.md b/applications/PoP/docs/l9_invert_plan.md index 379c815..82e7be0 100644 --- a/applications/PoP/docs/l9_invert_plan.md +++ b/applications/PoP/docs/l9_invert_plan.md @@ -306,7 +306,26 @@ vflip-двойник. Тем самым зеркалятся и полная о `g0` станут чисто «полевыми» (деления HP уедут в константы резидента), и исключений в кэше не останется — эту задачу логично сделать ДО II.4. -## II.5 Клип +## II.5 Клип — ЧАСТЬ СДЕЛАНА 2026-08-12 (поле), остаётся clip_char + +**Клип ПОЛЯ сделан.** Симптом (нашёл пользователь): после телепорта в +перевёрнутом виде ниже поля — мусор. Причина: спрайты, которые в обычном +виде торчат ВЫШЕ поля (полоса кладки у потолка, её режет `pop_t_clip_top`), +после отражения торчат НИЖЕ и лезут в борт, где живёт полоса HP. + +Фикс в `blit_b_clip`: при перевороте режем по ОБЕИМ границам поля всегда, а +не по `pop_t_clip_top` — зеркальный спрайт может вылезти и там, где в +обычном виде клип не ставили. Плюс в `pop_blit_b` быстрый путь (без клипа) +теперь пропускает в клипующий всё, что выходит за поле. + +Проверено в MAME: телепорт по комнатам в перевёрнутом виде — борта чистые, +комнаты рисуются зеркально (факелы, чомперы, пол). То есть **переходы +между комнатами в перевёрнутом виде работают**. + +Осталось из этого пункта: `clip_char` (верх поля ↔ низ) и клип падающей +плиты — они про ПЕРСОНАЖЕЙ и падающие объекты, то есть идут вместе с II.4. + +### Контракт (исходное описание) - `clip_char` (`pop_map.c:2287`, таблица `y_clip[5] = {-60,3,66,129,192}`) — режет верх спрайта по линии ряда; при перевороте линия становится нижней. diff --git a/applications/PoP/roomtest/pop_tile.c b/applications/PoP/roomtest/pop_tile.c index be265d5..7db8baf 100644 --- a/applications/PoP/roomtest/pop_tile.c +++ b/applications/PoP/roomtest/pop_tile.c @@ -268,8 +268,18 @@ void pop_cd_clear(uint8_t p) static void blit_b_clip(const uint8_t *img, int x, int top, int w, int h) { int dx = x, dy = top, dw = w, dh = h, sx = 0, sy = 0; - if (pop_t_clip_top && dy < pop_t_clip_top) { /* полоса у потолка */ - sy = pop_t_clip_top - dy; dy = pop_t_clip_top; dh -= sy; + if (!pop_upside) { + if (pop_t_clip_top && dy < pop_t_clip_top) { /* полоса у потолка */ + sy = pop_t_clip_top - dy; dy = pop_t_clip_top; dh -= sy; + } + } else { + /* ПЕРЕВОРОТ: то, что в обычном виде торчало ВЫШЕ поля (полоса кладки + * у потолка), теперь торчит НИЖЕ него — и без обрезки лезет в борт, + * где живёт полоса HP (баг «мусор ниже 192», найден пользователем). + * Режем по границам поля ВСЕГДА, а не по pop_t_clip_top: зеркальный + * спрайт может вылезти и там, где в обычном виде клип не ставили. */ + if (dy < POP_YOFF) { sy = POP_YOFF - dy; dy = POP_YOFF; dh -= sy; } + if (dy + dh > POP_CLIP_BOTTOM) dh = POP_CLIP_BOTTOM - dy; } if (pop_t_fclip_on) { /* окно fore-слоя */ if (dx < pop_t_fclip_x0) { int d = pop_t_fclip_x0 - dx; sx += d; dx += d; dw -= d; } @@ -341,6 +351,13 @@ void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom) * (замер: 4617 против 13288 тактов на спрайт 32×3; gfx_blit * платит за клип/16-бит/split, а не за пиксели). W3-скобку * ставит сама libbgi: из кода с --w3 её вызывать нельзя. */ + /* В перевёрнутом виде быстрый путь годится, только если спрайт + * целиком внутри поля: иначе он залезет в борт (см. blit_b_clip). */ + if (pop_upside && (top < POP_YOFF || top + (int)h > POP_CLIP_BOTTOM)) { + blit_b_clip(img, x, top, (int)w, (int)h); + gfx_w0_unmap(); + return; + } if (x >= 0 && top >= 0 && w < 256 && h < 256 && x + (int)w <= 320 && top + (int)h <= 256) { if (pop_upside) gfx_blit_noclip_vflip(x, top, img);