Уровни 12 и 13: тень, Джафар, падающие плиты + разбор слоёв
Уровень 12 (тень) — порт seg002/seg006: - check_shadow: подъём тени в комнате 15 по условию «меч подобран», init_shad_12, вход падением (seq 7); - autocontrol_shadow_level12: ждать Кида, бой, сближение, СЛИЯНИЕ; - общий урон (ранил тень — ранил себя) и check_killed_shadow (убил тень — убил себя); - таймер вспышки слияния 42 -> -1, sword_disappears при уходе из комнаты 18, появление плит в комнатах 2/13 после слияния. Переход 12 -> 13 бесшовный: двери у уровня нет, он кончается фактом попадания в комнату 23 (tbl_seamless_exit); флаг pop_seamless не даёт сбросить HP. Чит навигации по комнатам этот триггер придерживает — иначе комнату 23 двенадцатого уровня не посмотреть в принципе. Уровень 13 (Джафар): guard_notice_timer (фора после встречи), on_guard_killed + Jaffar_exit, check_fall_flo (гряда плит сверху) и три исключения loose-механики. Плюс спрайты визиря VIZIER.DAT — без них он рисовался обычным стражем; заодно цвет из данных комнаты применяется только к обычному стражу, как в оригинале. Падающие плиты — семь дефектов, найденных прогонами: - MOB_MAX 4 -> 14: check_fall_flo роняет шесть плит разом, лишние терялись без щебня; - одиночные сигналы посадки/провала больше не затираются в кадре; - честный loose_fall: сбитая плита рождается в том же кадре, от места удара, с половинной скоростью; - при снятии плиты метится и сосед справа (висел передний торец); - heal и отрисовка кусков разнесены на два прохода; - куски рисуются ПОСЛЕ фона, порядок между собой — по убыванию y (compare_curr_objs для пары 0x80 сортирует наоборот); - wall_pattern убран из ceil_over_kid_tile: у оригинала узор из draw_tile_bottom идёт в фон, а не в передний слой. Хост-тесты: два новых набора, t_shadow (45 проверок) и t_jaffar (44). TK_ROOMS 8 -> 24 — спецсобытия адресуют комнаты по реальным номерам. Осознанные расхождения (docs/impl_diff.md): нет мигания Кида спрайтами тени при слиянии, чит навигации не запускает бесшовный переход, чит K убивает через штатный путь смерти. Открытым остаётся разбор слоёв: MOB-CLIP-RIGHT, MID-OVERLAY-LAYER, GUARD-FALLOUT-VICTORY, BG-ONCE (BUGS_OPEN.md / TASKS_OPEN.md). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,18 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Фазы loose-плит: массив ТЕКУЩЕЙ комнаты (pop_map) и персистентный per-room
|
||||
* (pop_trob) плюс постановка trob. Объявлены здесь, а не включением обоих
|
||||
* заголовков: нужна ровно одна ячейка каждому — падающий кусок срывает
|
||||
* плиту, в которую врезался (loose_fall, см. mob_break_loose). */
|
||||
extern uint8_t pop_loose_modif[30];
|
||||
uint8_t *pop_trob_modif(uint8_t room) __banked;
|
||||
void pop_add_trob(uint8_t room, uint8_t tilepos, int8_t type) __banked;
|
||||
/* remove_loose для ОДНОГО тайла — снять плиту с карты немедленно (честный
|
||||
* loose_fall, см. mob_break_loose). Живёт в pop_map: там рабочая копия
|
||||
* тайлов комнаты и фазы плит. */
|
||||
void pop_loose_remove(uint8_t room, uint8_t tilepos) __banked;
|
||||
|
||||
/* ---- Тайлсет: подземелье / дворец ----------------------------------- *
|
||||
* Порт tbl_envir_ki[tbl_level_type[level]] (seg000:1108): оригинал под один
|
||||
* и тот же набор id грузит РАЗНЫЙ .DAT — VDUNGEON или VPALACE. У нас так
|
||||
@@ -809,9 +821,17 @@ void pop_loose_bake_empty(int row, int col) __banked
|
||||
* куска не хватает: в комнате 7 плиты (0,5) и (0,6) соседние, Kid роняет обе
|
||||
* подряд, и второй спавн затирал состояние первого — его пиксели оставались
|
||||
* висеть в воздухе (на каждой странице на своей y → мерцание), а щебень
|
||||
* появлялся только под одной плитой. 4 слота: больше одновременно падающих
|
||||
* плит в одной комнате практически не бывает (в оригинале 14). */
|
||||
#define MOB_MAX 4
|
||||
* появлялся только под одной плитой.
|
||||
*
|
||||
* Слотов СТОЛЬКО ЖЕ, СКОЛЬКО В ОРИГИНАЛЕ (14). Было 4 с обоснованием
|
||||
* «больше одновременно падающих плит в одной комнате практически не
|
||||
* бывает» — неверным ровно с уровня 13: check_fall_flo роняет ШЕСТЬ разом
|
||||
* (комнаты 23 и 16), а с учётом плит, которые эти куски сбивают по дороге
|
||||
* (loose_fall), в воздухе бывает и больше. Лишний кусок молча терялся
|
||||
* (`if (!m) return`), то есть тайл исчезал, а щебня на месте посадки не
|
||||
* появлялось — найдено прогоном 2026-08-13, комната 16, тайл (1,5).
|
||||
* Цена — 150 байт W2. */
|
||||
#define MOB_MAX 14
|
||||
typedef struct {
|
||||
uint8_t active; /* 0 нет; 1 падает */
|
||||
uint8_t clean; /* кадров дочистки после конца полёта (2 = обе стр.) */
|
||||
@@ -823,7 +843,12 @@ typedef struct {
|
||||
int8_t row, col; /* тайл-позиция куска (для окклюзии соседа) */
|
||||
uint8_t room; /* curmob.room: кусок падает В СВОЕЙ комнате, не в текущей */
|
||||
} mob_t;
|
||||
static mob_t mobs[MOB_MAX];
|
||||
/* НЕ static намеренно: статики банкового модуля в карту символов не
|
||||
* попадают, и разобрать зависший кадр по слотам (y каждого куска, порядок,
|
||||
* defer) в отладчике нечем — адреса просто нет. Снято 2026-08-13 для
|
||||
* разбора артефактов множественного падения; наружу таблица не объявлена и
|
||||
* никем не читается. */
|
||||
mob_t mobs[MOB_MAX];
|
||||
|
||||
/* Кусок «приземлился» (порт loose_land): 0 = нет, иначе tilepos+1 тайла, на
|
||||
* который он лёг → приложение/pop_map ставит debris + do_knock. */
|
||||
@@ -837,7 +862,7 @@ static const int16_t MOB_Y_LAND[5] = {2, 65, 128, 191, 254};
|
||||
static const int16_t MOB_Y_BOUND[5] = {-1, 62, 125, 188, 25};
|
||||
#define MOB_Y_NONE 0x7FFF
|
||||
|
||||
void pop_loose_mob_spawn(int row, int col) __banked
|
||||
static void mob_spawn(uint8_t room, int row, int col)
|
||||
{
|
||||
uint8_t i;
|
||||
mob_t *m = 0;
|
||||
@@ -850,7 +875,7 @@ void pop_loose_mob_spawn(int row, int col) __banked
|
||||
m->y = MOB_Y_LAND[row + 1]; /* y_loose_land: низ куска в момент отрыва */
|
||||
m->row = (int8_t)row;
|
||||
m->col = (int8_t)col;
|
||||
m->room = pop_t_room; /* curmob.room (add_mob, seg007:1010) */
|
||||
m->room = room; /* curmob.room (add_mob, seg007:1010) */
|
||||
m->speed = 0;
|
||||
m->active = 1;
|
||||
m->clean = 0;
|
||||
@@ -858,6 +883,55 @@ void pop_loose_mob_spawn(int row, int col) __banked
|
||||
m->prev_y[0] = m->prev_y[1] = MOB_Y_NONE;
|
||||
}
|
||||
|
||||
/* Отрыв куска в ТЕКУЩЕЙ комнате (обычный случай — pop_loose_tick). */
|
||||
void pop_loose_mob_spawn(int row, int col) __banked
|
||||
{
|
||||
mob_spawn(pop_t_room, row, col);
|
||||
}
|
||||
|
||||
/* Копия куска ОТ ПОЗИЦИИ УДАРА — порт хвоста loose_fall (seg007:1085):
|
||||
* curmob.y += 6; mob_down_a_row(); add_mob();
|
||||
* то есть новый кусок заводится не из тайла, а из места, где его сбили:
|
||||
* на 6 пикселей ниже и рядом ниже, со скоростью УЖЕ ПОДЕЛЁННОЙ пополам.
|
||||
* Через границу комнаты — как mob_down_a_row: y −= 192, ряд 0, комната снизу. */
|
||||
static void mob_spawn_copy(const mob_t *src)
|
||||
{
|
||||
uint8_t i;
|
||||
mob_t *m = 0;
|
||||
int16_t y = (int16_t)(src->y + 6);
|
||||
int8_t row = (int8_t)(src->row + 1);
|
||||
uint8_t room = src->room;
|
||||
|
||||
if (row >= 3) {
|
||||
y = (int16_t)(y - 192);
|
||||
row = 0;
|
||||
room = pop_room_link(room, 3 /* вниз */);
|
||||
if (!room) return; /* ушло из уровня — куску негде лететь */
|
||||
}
|
||||
for (i = 0; i < MOB_MAX; i++)
|
||||
if (!mobs[i].active && !mobs[i].clean) { m = &mobs[i]; break; }
|
||||
if (!m) return;
|
||||
m->x = src->x;
|
||||
m->y = y;
|
||||
m->row = row;
|
||||
m->col = src->col;
|
||||
m->room = room;
|
||||
m->speed = src->speed; /* уже half (loose_fall делит ДО add_mob) */
|
||||
m->active = 1;
|
||||
m->clean = 0;
|
||||
m->defer = 0;
|
||||
m->prev_y[0] = m->prev_y[1] = MOB_Y_NONE;
|
||||
}
|
||||
|
||||
/* Отрыв куска в ЧУЖОЙ комнате: плита, которую Кид расшатал и убежал, всё
|
||||
* равно проваливается (animate_loose в pop_trob крутит её trob по своей
|
||||
* комнате, как do_trobs оригинала). Летит и садится кусок дальше сам —
|
||||
* mob_tick_one давно умеет чужую комнату (mob_tile_at / pop_loose_exit). */
|
||||
void pop_loose_mob_spawn_at(uint8_t room, int row, int col) __banked
|
||||
{
|
||||
mob_spawn(room, row, col);
|
||||
}
|
||||
|
||||
/* Габарит куска по X: left/bottom (41/43, w=32) с mob_x; right (42, w=26)
|
||||
* с mob_x+32 → ПРАВЫЙ пиксель = mob_x+57 (замерено в pop_env1.atl, НЕ +46:
|
||||
* ширина 42 = 26, не ~14). Коридор heal и клип ОБЯЗАНЫ покрыть ВСЮ ширину
|
||||
@@ -905,6 +979,29 @@ static uint8_t mob_tile_at(mob_t *m)
|
||||
return (uint8_t)(pop_level_tile(m->room, (uint8_t)(m->row * 10 + m->col)) & 0x1F);
|
||||
}
|
||||
|
||||
/* loose_fall (seg007:1082) — падающий кусок пробил ЕЩЁ ОДНУ расшатанную
|
||||
* плиту. Порт дословный, три действия В ОДНОМ КАДРЕ:
|
||||
* 1. налетевший кусок тормозится вдвое (`curmob.speed >>= 1`);
|
||||
* 2. сбитый тайл снимается с карты немедленно (`remove_loose`);
|
||||
* 3. на месте удара заводится ВТОРОЙ кусок — копия налетевшего, сдвинутая
|
||||
* на 6 пикселей и ряд вниз (`curmob.y += 6; mob_down_a_row; add_mob`).
|
||||
* То есть в столбце дальше летят ДВА куска, и это правильное поведение
|
||||
* оригинала, а не дефект.
|
||||
*
|
||||
* Здесь стоял обходной путь: плите ставилась фаза «падает следующим кадром»,
|
||||
* а всю работу делал pop_loose_tick. Цена оценивалась как «один кадр
|
||||
* задержки» и оказалась выше: защита «один сигнал pop_loose_fell на кадр»
|
||||
* придерживает провал, пока главный цикл не разберёт предыдущий, и на 13-м
|
||||
* уровне (плиты сыплются пачкой) вторая плита появлялась через несколько
|
||||
* кадров — уже после того, как первая улетела с экрана, — да ещё и с высоты
|
||||
* покоя тайла, а не от места удара (найдено прогоном 2026-08-13). */
|
||||
static void mob_break_loose(mob_t *m)
|
||||
{
|
||||
m->speed >>= 1;
|
||||
pop_loose_remove(m->room, (uint8_t)(m->row * 10 + m->col));
|
||||
mob_spawn_copy(m);
|
||||
}
|
||||
|
||||
static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
{
|
||||
uint8_t here;
|
||||
@@ -921,6 +1018,19 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
* на одной из двух страниц дабл-буфера — «застрявшая плита», видимая
|
||||
* через кадр (BUG-MOB-STALE-PAGE). */
|
||||
if (m->prev_y[pg] != MOB_Y_NONE) {
|
||||
/* Ширина/высота — по СЛЕДУ, а не по спрайту. Спрайт куска целиком
|
||||
* влезает в 64x32 (41: 32x13 с y-3, 42: 26x15 с x+32,y-1, 43: 32x3),
|
||||
* но mob_render рисует ещё и ЦЕЛЫЙ соседний тайл поверх правой части
|
||||
* (окклюзия грани пола), причём в GFX_BANK_SPRITE — то есть мимо
|
||||
* теневой копии фона. Всё, что тот тайл нарисовал вне коридора
|
||||
* heal'а, не стиралось никогда: кусок улетал, а в соседнем столбце
|
||||
* оставался обрезок пола (найдено прогоном 2026-08-13). Коридор
|
||||
* расширен до площади, которую реально может тронуть эта
|
||||
* перерисовка: столбец соседа по ширине и ряд по высоте.
|
||||
*
|
||||
* ЗАДЕЛ: правильнее не перерисовывать соседа вовсе, а КЛИПОВАТЬ
|
||||
* правую часть куска — оригинал так и делает (add_mob_to_objtable,
|
||||
* seg007:1161: clip.right = 40). Тогда коридор вернётся к 64x32. */
|
||||
pop_heal_off(MOB_X0(m->x), m->prev_y[pg] - 27, MOB_W, 32);
|
||||
m->prev_y[pg] = MOB_Y_NONE;
|
||||
}
|
||||
@@ -929,11 +1039,19 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
if (m->speed < 29) m->speed += 3;
|
||||
m->y += m->speed;
|
||||
/* move_loose (seg007:1126): низ куска пересёк границу своего ряда —
|
||||
* смотрим тайл этого ряда. Пусто/loose — валится дальше (порт
|
||||
* loose_fall «плита ломает плиту» не нужен: в ряду ниже её нет);
|
||||
* пол — приземление (loose_land: debris + do_knock). */
|
||||
* смотрим тайл этого ряда. Пусто/loose — валится дальше, пол —
|
||||
* приземление (loose_land: debris + do_knock). Через LOOSE кусок именно
|
||||
* ПРОЛЕТАЕТ, как через пустоту, — но по дороге СРЫВАЕТ её (loose_fall,
|
||||
* seg007:1082).
|
||||
*
|
||||
* Здесь раньше стояло «порт loose_fall не нужен: в ряду ниже её нет» —
|
||||
* допущение, верное для уровней 1-11 и сломавшееся на 13-м: комната 16,
|
||||
* плиты (1,6) и (1,7), на которые сверху сыплется гряда из комнаты 1.
|
||||
* Куски пролетали сквозь них правильно, а сами плиты оставались целыми и
|
||||
* нарисованными (найдено прогоном 2026-08-13). */
|
||||
if (m->row < 3 && m->y < 226 && MOB_Y_BOUND[m->row + 1] <= m->y) {
|
||||
uint8_t t = mob_tile_at(m);
|
||||
if (t == 11) mob_break_loose(m);
|
||||
if (t == 0 || t == 11) {
|
||||
/* mob_down_a_row (seg007:1387): ряд ниже, а из НИЖНЕГО ряда —
|
||||
* в комнату СНИЗУ (y -= 192, ряд 0). Именно так кусок пролетает
|
||||
@@ -953,6 +1071,14 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
}
|
||||
here = (uint8_t)(m->room == pop_t_room);
|
||||
}
|
||||
} else if (!here && pop_loose_exit) {
|
||||
/* Сигнал прошлой посадки в чужой комнате ещё не разобран (он
|
||||
* ОДИН на кадр) — держим кусок на границе ряда и садим следующим
|
||||
* кадром, как это уже сделано для pop_loose_landed ниже. Без
|
||||
* этого второй кусок затирал первый, и из нескольких плит,
|
||||
* улетевших в одну дыру, щебень оставляла только одна (найдено
|
||||
* прогоном 2026-08-13, уровень 13). */
|
||||
m->y = MOB_Y_BOUND[m->row + 1];
|
||||
} else if (!here) {
|
||||
/* Приземление в ПОКИНУТОЙ комнате: рисовать нечего, но щебень и
|
||||
* КНОПКА под куском обязаны сработать — сигналим главному циклу
|
||||
@@ -996,9 +1122,47 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
if (mrow != pop_bg_obj_row) over = (mrow < pop_bg_obj_row); /* ряды идут 2,1,0 */
|
||||
else if (m->col != pop_bg_obj_col) over = (m->col > pop_bg_obj_col);
|
||||
else over = (m->y > pop_cd[POP_CH_KID].fpy);
|
||||
if (over) { m->defer = 1; return; }
|
||||
/* РИСОВАНИЯ ЗДЕСЬ БОЛЬШЕ НЕТ — только решение, в какой проход кусок
|
||||
* пойдёт. Пока heal и вывод шли в одной итерации, heal СЛЕДУЮЩЕГО
|
||||
* куска срезал верхнюю кромку уже нарисованного предыдущего: на 13-м
|
||||
* уровне куски идут лесенкой в соседних столбцах с разницей ~20 px
|
||||
* по y, и перекрытие гарантировано (артефакт «чёрный бар», найден
|
||||
* прогоном 2026-08-13, комната 23). Теперь сперва тикают ВСЕ куски
|
||||
* (то есть heal'ятся все), и только потом рисуются. */
|
||||
m->defer = over;
|
||||
}
|
||||
mob_render(m, pg);
|
||||
}
|
||||
|
||||
/* Один проход отрисовки кусков. want_defer: 0 — те, что под Kid (идут сразу
|
||||
* после фона), 1 — те, что поверх него (после персонажей).
|
||||
*
|
||||
* Порядок внутри прохода — ПО y, но ПО УБЫВАНИЮ: сперва нижние, последним
|
||||
* верхний. Это НЕ описка и не общее правило «ниже = поверх»: сравнение двух
|
||||
* объектов в оригинале (compare_curr_objs, seg008:1572) разводит два случая,
|
||||
*
|
||||
* оба объекта — падающие плиты (тип 0x80): y1 < y2 → по УБЫВАНИЮ
|
||||
* любая другая пара: y1 > y2 → по возрастанию
|
||||
*
|
||||
* то есть между СОБОЙ куски укладываются наоборот, чем всё остальное: верхний
|
||||
* ложится поверх нижнего. Видно на паре из loose_fall (сбитая плита летит в
|
||||
* 6 пикселях под налетевшей): при общем правиле нижняя перекрывала верхнюю,
|
||||
* и это поймал прогон 2026-08-13.
|
||||
*
|
||||
* Порядок «кусок против Кида» здесь ни при чём — его решает defer выше, и там
|
||||
* действует обычное правило. */
|
||||
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
||||
{
|
||||
uint8_t order[MOB_MAX], n = 0, i, j;
|
||||
for (i = 0; i < MOB_MAX; i++) {
|
||||
mob_t *m = &mobs[i];
|
||||
if (!m->active || m->room != pop_t_room) continue;
|
||||
if ((uint8_t)(m->defer != 0) != want_defer) continue;
|
||||
for (j = n; j > 0 && mobs[order[j - 1]].y < m->y; j--)
|
||||
order[j] = order[j - 1];
|
||||
order[j] = i;
|
||||
n++;
|
||||
}
|
||||
for (i = 0; i < n; i++) mob_render(&mobs[order[i]], pg);
|
||||
}
|
||||
|
||||
void pop_loose_mob_tick(void) __banked
|
||||
@@ -1010,6 +1174,15 @@ void pop_loose_mob_tick(void) __banked
|
||||
* (DRAW-COST). Взводим ДО тика: кусок может исчезнуть прямо в нём, а
|
||||
* стереть себя ему всё равно надо будет. */
|
||||
if (mobs[i].active || mobs[i].clean)
|
||||
/* Метка «фон трогали вот здесь» обязана покрывать ВЕСЬ коридор
|
||||
* heal'а, а не габарит спрайта. Иначе персонаж, попавший в
|
||||
* расширенную часть коридора, стирается heal'ом, но перерисовать
|
||||
* себя не просит (pop_char_skip_mask его пропускает) — и просто
|
||||
* исчезает с экрана. Ровно это и случилось, когда коридор
|
||||
* расширили под транзитную перерисовку соседа (прогон
|
||||
* 2026-08-13: в комнате 23 после падения гряды пропадал Кид).
|
||||
* Запас сверху — на путь, пройденный за кадр (speed до 29): heal
|
||||
* стирает ПРОШЛУЮ позицию, она выше текущей. */
|
||||
pop_cd_touch(MOB_X0(mobs[i].x), mobs[i].y - 27 + POP_YOFF, MOB_W, 64);
|
||||
mob_tick_one(&mobs[i], pg);
|
||||
}
|
||||
@@ -1042,6 +1215,24 @@ static void mob_render(mob_t *m, uint8_t pg)
|
||||
* границе рядов. Порт draw_mob (seg007:13E5). */
|
||||
int8_t r = pop_y_to_row((int16_t)m->y);
|
||||
int8_t rt = pop_y_to_row((int16_t)(m->y - 18));
|
||||
/* ОКНО = КОРИДОР HEAL ЭТОГО КУСКА, ни пикселем шире. draw_tile
|
||||
* рисует тайл ЦЕЛИКОМ (пол, грани, верх кладки ряда ниже — порядка
|
||||
* 64x63), причём в GFX_BANK_SPRITE, то есть мимо теневой копии фона.
|
||||
* Всё, что он клал за пределами коридора, не стиралось НИКОГДА:
|
||||
* кусок улетал, а в соседнем столбце оставался обрезок пола
|
||||
* (найдено прогоном 2026-08-13).
|
||||
*
|
||||
* Расширять под это heal НЕЛЬЗЯ: heal — самая дорогая операция
|
||||
* кадра, а на 13-м уровне таких кусков одновременно шесть. Поэтому
|
||||
* режем не heal под перерисовку, а перерисовку под heal — тем же
|
||||
* окном, которым fore-слой отсекает лишние тайлы. */
|
||||
pop_t_fclip_x0 = MOB_X0(m->x);
|
||||
pop_t_fclip_x1 = MOB_X0(m->x) + MOB_W;
|
||||
pop_t_fclip_y0 = m->y - 27 + POP_YOFF;
|
||||
pop_t_fclip_y1 = pop_t_fclip_y0 + 32;
|
||||
pop_t_fclip_ly0 = pop_t_fclip_y0; /* переворота у кусков нет */
|
||||
pop_t_fclip_ly1 = pop_t_fclip_y1;
|
||||
pop_t_fclip_on = 1;
|
||||
if (r < 0) pop_t_clip_top = POP_YOFF; /* полоса у потолка — только срез */
|
||||
draw_tile(r, m->col + 1);
|
||||
pop_t_clip_top = 0;
|
||||
@@ -1050,19 +1241,30 @@ static void mob_render(mob_t *m, uint8_t pg)
|
||||
draw_tile(rt, m->col + 1);
|
||||
pop_t_clip_top = 0;
|
||||
}
|
||||
pop_t_fclip_on = 0;
|
||||
}
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
/* клип СВОЕГО выхода за поле (верхний борт / статус-полоса) — по ВСЕЙ ширине */
|
||||
pop_clip_sprite(MOB_X0(m->x), MOB_W, m->y - 26 + POP_YOFF, 30);
|
||||
}
|
||||
|
||||
/* Отрисовка кусков, идущих ПОД Kid. Звать ПОСЛЕ pop_redraw_needed(): фон
|
||||
* кадра обязан быть полностью готов до любого спрайта.
|
||||
*
|
||||
* Раньше куски рисовались внутри pop_loose_mob_tick, то есть ДО разбора
|
||||
* пометок перерисовки, и перепечатка тайла ложилась поверх уже нарисованного
|
||||
* куска — окно задней стены, передняя грань пола (найдено прогоном
|
||||
* 2026-08-13, комнаты 16 и 23). */
|
||||
void pop_loose_mob_draw(void) __banked
|
||||
{
|
||||
mob_draw_pass(gfx_get_draw_page() & 1, 0);
|
||||
}
|
||||
|
||||
/* Отложенная отрисовка куска ПОВЕРХ Kid (он ниже Kid по obj_y). Звать
|
||||
* после отрисовки персонажей, до fore-слоя. */
|
||||
void pop_loose_mob_draw_over(void) __banked
|
||||
{
|
||||
uint8_t pg = gfx_get_draw_page() & 1, i;
|
||||
for (i = 0; i < MOB_MAX; i++)
|
||||
if (mobs[i].defer) { mobs[i].defer = 0; mob_render(&mobs[i], pg); }
|
||||
mob_draw_pass(gfx_get_draw_page() & 1, 1);
|
||||
}
|
||||
|
||||
/* Позиция падающего куска для check_loose_fall_on_kid (pop_map): колонка и
|
||||
|
||||
Reference in New Issue
Block a user