Вариант B: кусок с завёрнутым рядом рисуется под всем (корзина 30)
Порт правила оригинала, разобранного в 272cf8f. y_to_row_mod4 даёт −1 и
для куска выше потолка, и для ушедшего ниже комнаты; get_tilepos_nominus
сводит оба в тайл 30, а объекты тайла 30 рисуются в redraw_needed_tiles
ПЕРВЫМИ, до всего обхода тайлов.
Что сделано:
- defer = 0 для таких кусков: они под всем, включая Кида. Раньше
сравнение рядов читало −1 как «обходится последним» = «поверх всего»;
- оверлею отдаётся ориентир 3 («раньше любого ряда 2,1,0») вместо сырого
−1 — гейт other_overlay_tile перестал отбрасывать возврат соседа, из-за
чего тело плиты не возвращалось и оставался только её торец из
переднего слоя;
- в набор перекрываемых тайлов добавлена СВОЯ клетка (только для этого
случая: у куска в обычном ряду объект вливается в midtable после частей
своего тайла, и перерисовывать её нельзя).
Отладочная обвязка разбора (журнал решений оверлея, маска перекрывающих
тайлов) снята; счётчик перерисовок за кадр в pop_redraw_needed оставлен —
он дешёвый и пригодится для HEAL-WIDTH.
ЗАМЕР 13/23, 3032 кадра, против тега mob-order-B-start:
работа 888 984 -> 913 848 (+24 864)
синяя 159 804 -> 159 810
зелёная 427 242 -> 440 418 (+13 176)
циан 378 864 -> 393 000 (+14 136)
Период кадра не изменился: 4 растра в 23 кадрах, 5 в двух.
Зелёная вышла за растровый кадр (440 418 против 430 000). Детализация:
pop_loose_tick 185 826, из них pop_loose_mob_tick 168 180; тробы +
redraw_needed 337 800. Разбор и план возврата тактов — HEAL-WIDTH.
Визуальная проверка комнаты 14 за пользователем: поймать кадр с куском
снимками мне не удалось.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3337,3 +3337,46 @@ draw_tile_anim(); draw_tile_bottom(0); draw_loose(0);
|
||||
`draw_tile_anim_right` — то есть анимированной правой грани СОСЕДА (пики,
|
||||
ворота, loose). Симптома на это пока не видели; если всплывёт «правая грань
|
||||
соседа под персонажем/куском» — смотреть сюда.
|
||||
|
||||
### Вариант B: порт корзины 30 (2026-08-18)
|
||||
|
||||
Реализовано то, что разобрано в коммите `272cf8f`. Кусок, у которого ряд
|
||||
объекта вне 0..2 (`y_to_row_mod4` даёт −1 и «выше потолка», и «ниже пола»),
|
||||
считается объектом ТАЙЛА 30 — а такие оригинал рисует ПЕРВЫМИ, до всего
|
||||
обхода тайлов. Два следствия:
|
||||
|
||||
- `defer = 0` — кусок идёт под всем, включая Кида (раньше сравнение рядов
|
||||
давало обратное: «−1 обходится последним» читалось как «поверх»);
|
||||
- оверлею отдаётся ориентир **3** («раньше любого ряда обхода 2,1,0»)
|
||||
вместо сырого −1, и в набор перекрываемых тайлов добавляется **своя
|
||||
клетка** — у куска в обычном ряду её перерисовывать нельзя, там объект
|
||||
вливается в midtable уже после частей своего тайла.
|
||||
|
||||
**Замер 13/23 (3032 кадра, зонды фаз + детализация зелёной):**
|
||||
|
||||
| секция | тег `mob-order-B-start` | после B | дельта |
|
||||
|---|---:|---:|---:|
|
||||
| работа | 888 984 | **913 848** | +24 864 |
|
||||
| синяя | 159 804 | 159 810 | +6 |
|
||||
| зелёная | 427 242 | **440 418** | +13 176 |
|
||||
| циан | 378 864 | 393 000 | +14 136 |
|
||||
|
||||
Период кадра не изменился: 4 растра в 23 кадрах, 5 в двух — как и до правки.
|
||||
|
||||
**Зелёная вышла за растровый кадр** (440 418 против 430 000) при цели
|
||||
400 000. Детализация показывает, где именно:
|
||||
|
||||
| участок зелёной | максимум |
|
||||
|---|---:|
|
||||
| `pop_loose_tick` целиком | 185 826 |
|
||||
| — из них `pop_loose_mob_tick` | **168 180** |
|
||||
| — циклы по тайлам | 23 736 |
|
||||
| — `check_loose_fall_on_kid` | 5 868 |
|
||||
| тробы + `pop_redraw_needed` | 337 800 |
|
||||
| шов и прочее | 11 964 |
|
||||
|
||||
(максимумы взяты по разным кадрам, поэтому не складываются в общий).
|
||||
|
||||
Основной кандидат на возврат этих тактов — задача
|
||||
[HEAL-WIDTH](TASKS_OPEN.md#heal-width): heal'ы кусков и плит берут ширину по
|
||||
клеткам, а фактический след — 58/57.
|
||||
|
||||
@@ -1203,13 +1203,6 @@ static void mob_spawn(uint8_t room, int row, int col)
|
||||
m->defer = 0;
|
||||
m->prev_y[0] = m->prev_y[1] = MOB_Y_NONE;
|
||||
m->draw_y = MOB_Y_NONE;
|
||||
{ /* ВРЕМЕННО: журнал решения оверлея — копим за весь полёт */
|
||||
uint8_t k = (uint8_t)(m - mobs);
|
||||
pop_dbg_pass[k] = 0;
|
||||
pop_dbg_ovl[k * 4 + 2] = 0;
|
||||
pop_dbg_ovl[k * 4 + 3] = 0;
|
||||
pop_dbg_tiles[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Отрыв куска в ТЕКУЩЕЙ комнате (обычный случай — pop_loose_tick). */
|
||||
@@ -1497,7 +1490,18 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
{
|
||||
int8_t mrow = pop_y_to_row((int16_t)mt_m->draw_y); /* y_to_row_mod4 */
|
||||
uint8_t over;
|
||||
if (mrow != pop_bg_obj_row) over = (mrow < pop_bg_obj_row); /* ряды идут 2,1,0 */
|
||||
if (mrow < 0 || mrow > 2) {
|
||||
/* КОРЗИНА 30 (get_tilepos_nominus, seg006:110). Ряд объекта вне
|
||||
* комнаты: y_to_row_mod4 берёт остаток по 4, поэтому «выше
|
||||
* потолка» и «ниже пола» дают одно и то же −1, а оригинал сводит
|
||||
* оба в тайл 30. Объекты этого тайла рисуются ПЕРВЫМИ —
|
||||
* draw_objtable_items_at_tile(30) стоит в redraw_needed_tiles до
|
||||
* всего обхода тайлов. Значит кусок под ВСЕМ, включая Кида; до
|
||||
* сих пор сравнение рядов давало обратное («−1 обходится
|
||||
* последним» = поверх). */
|
||||
over = 0;
|
||||
}
|
||||
else if (mrow != pop_bg_obj_row) over = (mrow < pop_bg_obj_row); /* ряды идут 2,1,0 */
|
||||
else if (mt_m->col != pop_bg_obj_col) over = (mt_m->col > pop_bg_obj_col);
|
||||
else over = (mt_m->draw_y > pop_cd[POP_CH_KID].fpy);
|
||||
/* РИСОВАНИЯ ЗДЕСЬ БОЛЬШЕ НЕТ — только решение, в какой проход кусок
|
||||
@@ -1586,30 +1590,30 @@ static void mob_overlay_neighbour(const mob_t *m)
|
||||
{
|
||||
int8_t r = pop_y_to_row((int16_t)m->draw_y);
|
||||
int8_t rt = pop_y_to_row((int16_t)(m->draw_y - 18));
|
||||
int8_t c = (int8_t)(m->col + 1);
|
||||
/* КОРЗИНА 30 оригинала (get_tilepos_nominus, seg006:110): ряд объекта вне
|
||||
* комнаты. y_to_row_mod4 берёт остаток по 4, поэтому «выше потолка» и
|
||||
* «ниже пола» дают одно и то же −1 — оригинал сводит оба случая в тайл 30
|
||||
* и рисует такие объекты ПЕРВЫМИ, до всего обхода тайлов
|
||||
* (draw_objtable_items_at_tile(30) в redraw_needed_tiles).
|
||||
*
|
||||
* Отсюда два отличия от обычного куска:
|
||||
* - ориентир «тайл объекта» = 3, то есть РАНЬШЕ любого ряда обхода
|
||||
* (2,1,0). Сюда уходил сырой −1, и гейт other_overlay_tile
|
||||
* `row > pop_bg_obj_row` читал его наоборот — «объект поверх всего» —
|
||||
* и соседа не возвращал вовсе (тело плиты пропадало, оставался
|
||||
* только её торец из переднего слоя);
|
||||
* - перекрыть кусок должна и СВОЯ клетка, а не только сосед справа:
|
||||
* после объекта у оригинала рисуются ВСЕ тайлы. У куска в обычном
|
||||
* ряду своя клетка не перерисовывается — там объект вливается в
|
||||
* midtable уже ПОСЛЕ частей своего тайла. */
|
||||
uint8_t b30 = (uint8_t)(r < 0 || r > 2);
|
||||
int8_t oref = b30 ? (int8_t)3 : r;
|
||||
int8_t c, cend = (int8_t)(m->col + 1);
|
||||
int ytop, ybot;
|
||||
uint8_t *dbg = &pop_dbg_ovl[(m - mobs) * 4]; /* ВРЕМЕННО: журнал решения */
|
||||
{ /* ВРЕМЕННО: перебор ВСЕХ тайлов, чьи габариты пересекаются со спрайтом
|
||||
* куска — чтобы понять, скольким тайлам реально нужно лечь поверх. */
|
||||
int8_t rr, kk;
|
||||
int t0 = m->draw_y - (int)mob_spr[2] + 1, t1 = m->draw_y;
|
||||
for (rr = -1; rr <= 2; rr++)
|
||||
for (kk = 0; kk <= 1; kk++) {
|
||||
int8_t cc = (int8_t)(m->col + kk);
|
||||
if (cc > 9) continue;
|
||||
if (pop_tile_code(rr, cc) &&
|
||||
t1 >= 63 * rr + 2 && t0 <= 63 * rr + 66)
|
||||
pop_dbg_tiles[m - mobs] |= (uint8_t)(1 << ((rr + 1) * 2 + kk));
|
||||
}
|
||||
}
|
||||
dbg[0] = (uint8_t)(r + 128); dbg[1] = (uint8_t)(rt + 128);
|
||||
dbg[2] |= 1;
|
||||
if (c > 9) return;
|
||||
dbg[2] |= 2;
|
||||
/* Габарит куска — по ЭКРАННОЙ координате, как и ряд выше: у куска,
|
||||
* видимого из соседней комнаты, draw_y отличается от y на 192, и
|
||||
* сравнение с габаритом тайла по y давало заведомо ложный ответ. */
|
||||
ytop = m->draw_y - (int)mob_spr[2] + 1; /* верх спрайта куска */
|
||||
if (cend > 9) cend = 9;
|
||||
/* Габарит куска — по ЭКРАННОЙ координате: у куска, видимого из соседней
|
||||
* комнаты, draw_y отличается от y на 192. */
|
||||
ytop = m->draw_y - (int)mob_spr[2] + 1;
|
||||
ybot = m->draw_y;
|
||||
/* ПРЕДУСЛОВИЯ ПРОВЕРЯЕМ ЗДЕСЬ, до вызова в банк 2. pop_mob_overlay_tile
|
||||
* живёт в банке 2, то есть каждый вызов из банка 7 платит межбанковый
|
||||
@@ -1620,21 +1624,15 @@ static void mob_overlay_neighbour(const mob_t *m)
|
||||
* ничего не рисовало.
|
||||
*
|
||||
* Габарит тайла берём ПОЛНЫМ (63*row+2 .. +66) — какая именно часть
|
||||
* соседа окажется поверх куска, решит уже окно клипа внутри. Сужать по
|
||||
* реальной высоте кусков нельзя: у колонн и зеркала база высокая. */
|
||||
if (r >= 0 && r <= 2 && pop_tile_code(r, c)) dbg[2] |= 4;
|
||||
if (r >= 0 && r <= 2 && ybot >= 63 * r + 2 && ytop <= 63 * r + 66) dbg[2] |= 8;
|
||||
if (r >= 0 && r <= 2 && pop_tile_code(r, c) &&
|
||||
ybot >= 63 * r + 2 && ytop <= 63 * r + 66) {
|
||||
dbg[2] |= 0x10; dbg[3]++;
|
||||
pop_mob_overlay_tile(r, c, r, (int8_t)m->col, m->x, m->draw_y, mob_spr[2]);
|
||||
}
|
||||
if (rt != r && rt >= 0 && rt <= 2 && pop_tile_code(rt, c)) dbg[2] |= 0x20;
|
||||
if (rt != r && rt >= 0 && rt <= 2 && ybot >= 63 * rt + 2 && ytop <= 63 * rt + 66) dbg[2] |= 0x40;
|
||||
if (rt != r && rt >= 0 && rt <= 2 && pop_tile_code(rt, c) &&
|
||||
ybot >= 63 * rt + 2 && ytop <= 63 * rt + 66) {
|
||||
dbg[2] |= 0x80; dbg[3]++;
|
||||
pop_mob_overlay_tile(rt, c, r, (int8_t)m->col, m->x, m->draw_y, mob_spr[2]);
|
||||
* соседа окажется поверх куска, решит уже окно клипа внутри. */
|
||||
for (c = b30 ? (int8_t)m->col : cend; c <= cend; c++) {
|
||||
if (c < 0) continue;
|
||||
if (r >= 0 && r <= 2 && pop_tile_code(r, c) &&
|
||||
ybot >= 63 * r + 2 && ytop <= 63 * r + 66)
|
||||
pop_mob_overlay_tile(r, c, oref, (int8_t)m->col, m->x, m->draw_y, mob_spr[2]);
|
||||
if (rt != r && rt >= 0 && rt <= 2 && pop_tile_code(rt, c) &&
|
||||
ybot >= 63 * rt + 2 && ytop <= 63 * rt + 66)
|
||||
pop_mob_overlay_tile(rt, c, oref, (int8_t)m->col, m->x, m->draw_y, mob_spr[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1650,10 +1648,6 @@ static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
||||
mob_t *m = &mobs[i];
|
||||
/* Отбор по draw_y, а НЕ по комнате: кусок, только что провалившийся
|
||||
* в комнату снизу, ещё виден из нашей (см. mob_tick_one). */
|
||||
pop_dbg_pass[i] |= 1;
|
||||
if (m->active) pop_dbg_pass[i] |= 2;
|
||||
if (m->draw_y != MOB_Y_NONE) pop_dbg_pass[i] |= 4;
|
||||
if ((uint8_t)(m->defer != 0) == want_defer) pop_dbg_pass[i] |= 8;
|
||||
if (!m->active || m->draw_y == MOB_Y_NONE) continue;
|
||||
if ((uint8_t)(m->defer != 0) != want_defer) continue;
|
||||
for (j = n; j > 0 && mobs[order[j - 1]].draw_y < m->draw_y; j--)
|
||||
@@ -1670,10 +1664,8 @@ static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
||||
* в кадр пересечения границы пометка указывала на прежний тайл, и
|
||||
* передняя часть колонны кусок не перекрывала — ровно ОДИН кадр,
|
||||
* как и наблюдалось (прогон 2026-08-13, комната 23, колонка 8). */
|
||||
pop_dbg_pass[order[i]] |= 0x10;
|
||||
mob_mark_neighbour(&mobs[order[i]]);
|
||||
mob_render(&mobs[order[i]], pg);
|
||||
pop_dbg_pass[order[i]] |= 0x20;
|
||||
mob_overlay_neighbour(&mobs[order[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user