Разбор порядка отрисовки падающей плиты: найден корень, выбран вариант B
СИМПТОМ (пользователь, ур.11 к.14). Кусок, отвалившийся от плиты нижнего ряда, рисуется ПОВЕРХ соседней трясущейся плиты; при этом передний торец соседа лежит поверх куска — порядок противоречив в разных частях перекрытия. КОРЕНЬ. draw_mob (seg007:13E5) считает ряд объекта как y_to_row_mod4(y) = (y+60)/63 % 4 - 1. Из-за % 4 ряд 3 (кусок ушёл ниже комнаты) и ряд −1 (кусок у потолка) дают ОДНО значение −1. Оригинал прогоняет его через get_tilepos -> get_tilepos_nominus и получает тайл 30, а объекты с тайлом 30 рисуются в redraw_needed_tiles ПЕРВЫМИ, до всего обхода тайлов. Мы же передаём сырой −1 в мид-оверлей как «тайл объекта», и гейт `row > pop_bg_obj_row` читает его как «объект в последнем ряду обхода», то есть «объект поверх всего», и отбрасывает возврат соседа. Один и тот же −1 у нас значит «сверху», у оригинала — «снизу». Торец при этом виден потому, что приходит из ДРУГОГО слоя: draw_loose кладёт loose_fram_bottom в backtable и foretable, минуя ptr_add_table, — тело плиты обязан вернуть мид-оверлей, а его и выключает гейт. ЧТО ПРОВЕРЕНО ЗАМЕРОМ (журнал решений в pop_dbg_ovl/pop_dbg_pass, зонды ВРЕМЕННЫЕ и будут сняты): - на застывшем кадре: слот draw_y=194, r=−1, rt=2, оверлей позван, внутри отбрасывается гейтом; - пропуск оверлея на последнем кадре полёта ЗАКОНЕН: габарит куска уже ниже габарита тайла, перекрывать нечего; - в 13/23 кусок перекрывают 2-4 тайла (накопленно за полёт), включая СВОЮ клетку, — то есть «сосед справа» покрытие не исчерпывает; - перерисовок тайлов за кадр в 13/23: максимум 6, в покое 0. ТУПИКИ, чтобы не ходить второй раз. Клип объекта тут ни при чём: add_mob_to_objtable ставит clip.right = 40, но клип применяется только при chtab_flip_clip[chtab_id], а для chtab_6_environment там 0 — поле игнорируется и в оригинале. Пункт MOB-CLIP-RIGHT закрывается как несуществующий. Добавлять торец плиты в мид-оверлей тоже не надо: в foretable он уже кладётся из fore_tile. ВЫБРАН ВАРИАНТ B: классифицировать ряд объекта (вне 0..2 = корзина 30), отдавать оверлею ориентир «раньше любого тайла» и расширить набор перекрываемых тайлов на СВОЮ клетку. Переносить проход отрисовки не нужно — heal при этом не участвует, работа та же (оверлей = два блита в окне клипа), разница с узким вариантом A всего один-два оверлея на кусок. Заодно записана ОБЯЗАТЕЛЬНАЯ задача HEAL-WIDTH: ширины точечных heal'ов взяты по клеткам (64), а фактический след плиты — 58/57 (замерено по атласам: верх 32, правая грань 26 в подземелье и 25 во дворце). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1203,6 +1203,13 @@ 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). */
|
||||
@@ -1581,7 +1588,24 @@ static void mob_overlay_neighbour(const mob_t *m)
|
||||
int8_t rt = pop_y_to_row((int16_t)(m->draw_y - 18));
|
||||
int8_t c = (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 давало заведомо ложный ответ. */
|
||||
@@ -1598,12 +1622,20 @@ 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)
|
||||
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)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
||||
@@ -1618,6 +1650,10 @@ 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--)
|
||||
@@ -1634,8 +1670,10 @@ 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