PoP roomtest: нажатая кнопка-closer, таблица падающих кусков, фон-покой при запечке
Кнопка-closer (tiles_6) в нажатом состоянии рисуется как tiles_5_stuck
(get_tile_to_draw seg008:2FE), но её грани — env id 35 (правая) и 36
(нижняя) — не попадали в атлас: pop_pack_bg собирает набор спрайтов
прогоном render_room по статике уровней, а тайла 5 статически в уровнях
нет. Итог — чёрный провал на месте нижней грани. Добавлены явным
набором STUCK_ENV_IDS (как loose/пики/ворота). Заодно OPENER_NOFLOOR_ENV_IDS
= {148}: левая половина кнопки-opener, когда слева пусто (draw_tile_base
seg008:0A8E) — ветка была не реализована ни в pop_bg, ни в render_room.
bake_rest: при ЗАПЕЧКЕ статического фона (запись идёт в ОЗУ-копию
акселератора, из неё восстанавливает heal) get_loose_frame возвращает
кадр ПОКОЯ. Иначе транзиентный кадр тряски соседней плиты консервируется
в копии, а так как запечка идёт двумя кадрами (по одному на страницу
дабл-буфера) — на страницах застывают РАЗНЫЕ кадры, вечное мерцание.
mobs[MOB_MAX] вместо одиночных статиков: две плиты, упавшие подряд,
теряли первый кусок (застывал в воздухе) и оставляли щебень только от
одной. Плюс отложенная допечка прошлого приземления ПЕРЕД разбором
нового и ограничение чёрного бара в pop_loose_bake_empty низом тайла.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -445,9 +445,21 @@ static const uint8_t LOOSE_FRAM_LEFT[12] = {41,69,41,70,70,41,41,41,70,70,70,0
|
|||||||
static const uint8_t LOOSE_FRAM_RIGHT[12] = {42,71,42,72,72,42,42,42,72,72,72,0};
|
static const uint8_t LOOSE_FRAM_RIGHT[12] = {42,71,42,72,72,42,42,42,72,72,72,0};
|
||||||
static const uint8_t LOOSE_FRAM_BOTTOM[12] = {43,73,43,74,74,43,43,43,74,74,74,0};
|
static const uint8_t LOOSE_FRAM_BOTTOM[12] = {43,73,43,74,74,43,43,43,74,74,74,0};
|
||||||
|
|
||||||
|
/* Режим ЗАПЕЧКИ статического фона (запись идёт и в ОЗУ-копию акселератора,
|
||||||
|
* из которой потом восстанавливает heal). В этом режиме дрожащие кадры
|
||||||
|
* ЧУЖИХ плит рисовать НЕЛЬЗЯ: транзиентный кадр законсервируется в копии, а
|
||||||
|
* так как запечка идёт двумя кадрами (по одному на страницу дабл-буфера),
|
||||||
|
* на страницах застынут РАЗНЫЕ кадры — вечное мерцание. Пример: упала плита
|
||||||
|
* (0,6); её запечка перерисовывает и соседа, а правый угол СОСЕДНЕЙ плиты
|
||||||
|
* (0,5), который рисуется в ячейке (0,6), был в этот момент в тряске.
|
||||||
|
* Фон обязан быть состоянием ПОКОЯ — анимация каждый кадр кладётся поверх
|
||||||
|
* (банк SPRITE, только видео-ОЗУ). */
|
||||||
|
static uint8_t bake_rest;
|
||||||
|
|
||||||
/* get_loose_frame (seg008:761): индекс дрожащего кадра по модификатору. */
|
/* get_loose_frame (seg008:761): индекс дрожащего кадра по модификатору. */
|
||||||
static uint8_t get_loose_frame(uint8_t m)
|
static uint8_t get_loose_frame(uint8_t m)
|
||||||
{
|
{
|
||||||
|
if (bake_rest) return 0; /* запекаем фон → кадр покоя */
|
||||||
if (m & 0x80) { m &= 0x7F; if (m > 10) return 1; }
|
if (m & 0x80) { m &= 0x7F; if (m > 10) return 1; }
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -555,6 +567,8 @@ static void draw_tile(int row, int col)
|
|||||||
uint8_t base_id = t->base_id;
|
uint8_t base_id = t->base_id;
|
||||||
if (code == 11) /* loose: левая грань (анимир.) */
|
if (code == 11) /* loose: левая грань (анимир.) */
|
||||||
base_id = LOOSE_FRAM_LEFT[get_loose_frame(pop_loose_modif[row * 10 + col])];
|
base_id = LOOSE_FRAM_LEFT[get_loose_frame(pop_loose_modif[row * 10 + col])];
|
||||||
|
else if (code == 0x0F && lcode == 0) /* opener, слева пусто */
|
||||||
|
base_id = 148; /* левая половина без пола */
|
||||||
if (base_id)
|
if (base_id)
|
||||||
env_b(base_id, x, t->base_y + dmy);
|
env_b(base_id, x, t->base_y + dmy);
|
||||||
}
|
}
|
||||||
@@ -686,8 +700,10 @@ void pop_ceil_bake_empty(int col)
|
|||||||
bar(x, POP_YOFF, x + 63, POP_YOFF + CEIL_BAND_H); /* стереть плиту в ОЗУ-копии */
|
bar(x, POP_YOFF, x + 63, POP_YOFF + CEIL_BAND_H); /* стереть плиту в ОЗУ-копии */
|
||||||
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
||||||
g_clip_top = POP_YOFF;
|
g_clip_top = POP_YOFF;
|
||||||
|
bake_rest = 1; /* фон = покой (см. bake_rest) */
|
||||||
draw_tile(-1, col); /* тайл уже EMPTY → колодец наверх */
|
draw_tile(-1, col); /* тайл уже EMPTY → колодец наверх */
|
||||||
if (col + 1 < 10) draw_tile(-1, col + 1);
|
if (col + 1 < 10) draw_tile(-1, col + 1);
|
||||||
|
bake_rest = 0;
|
||||||
g_clip_top = 0;
|
g_clip_top = 0;
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
}
|
}
|
||||||
@@ -742,8 +758,10 @@ void pop_floor_bake(int row, int col)
|
|||||||
setfillstyle(SOLID_FILL, BLACK);
|
setfillstyle(SOLID_FILL, BLACK);
|
||||||
bar(x, yb + 26, x + 59, yb + 64);
|
bar(x, yb + 26, x + 59, yb + 64);
|
||||||
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
||||||
|
bake_rest = 1; /* фон = покой (см. bake_rest) */
|
||||||
draw_tile(row, col);
|
draw_tile(row, col);
|
||||||
if (col + 1 < 10) draw_tile(row, col + 1);
|
if (col + 1 < 10) draw_tile(row, col + 1);
|
||||||
|
bake_rest = 0;
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,19 +782,29 @@ void pop_loose_bake_empty(int row, int col)
|
|||||||
* стирает ЗАПЕЧЁННЫЙ пиксель-в-пиксель loose-пол с обоих тайлов, иначе
|
* стирает ЗАПЕЧЁННЫЙ пиксель-в-пиксель loose-пол с обоих тайлов, иначе
|
||||||
* heal вернул бы старый пол из ОЗУ-копии. Ширина 40 — кусок пола
|
* heal вернул бы старый пол из ОЗУ-копии. Ширина 40 — кусок пола
|
||||||
* заходит на x+32..+40. */
|
* заходит на x+32..+40. */
|
||||||
|
/* НИЗ строго 63*row+65 = низ собственной графики плиты (bottom_id 43/73/74
|
||||||
|
* стоит ровно на dby; base 41/69/70 — до dmy=62; правая грань 42/66/67 —
|
||||||
|
* до dby-1). Ниже начинается СТЕНА ряда ниже (высокий спрайт), которую
|
||||||
|
* здесь не перерисовываем: заливка на 9 строк глубже оставляла ЧЁРНЫЙ БОКС
|
||||||
|
* под соседним столбом, причём в ОЗУ-копии — то есть heal возвращал его
|
||||||
|
* снова, и на второй странице дабл-буфера его не было → мерцание.
|
||||||
|
* Тот же урок уже учтён в pop_floor_bake. */
|
||||||
|
yb += POP_YOFF;
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
setfillstyle(SOLID_FILL, BLACK);
|
setfillstyle(SOLID_FILL, BLACK);
|
||||||
bar(x, yb + POP_YOFF, x + 39, yb + 28 + POP_YOFF); /* сам тайл: +40 (кусок пола заходит вправо; сосед перерисуется) */
|
bar(x, yb, x + 39, POP_YOFF + 63 * row + 65); /* сам тайл: +40 (кусок пола заходит вправо; сосед перерисуется) */
|
||||||
if (col + 1 < 10)
|
if (col + 1 < 10)
|
||||||
bar(xr, yb + POP_YOFF, xr + 31, yb + 28 + POP_YOFF); /* сосед: РОВНО 32 — не залезть в col+2 (его не перерисовываем) */
|
bar(xr, yb, xr + 31, POP_YOFF + 63 * row + 65); /* сосед: РОВНО 32 — не залезть в col+2 (его не перерисовываем) */
|
||||||
/* Новый статич. фон: сам тайл (empty → «стена вниз» topright комнаты
|
/* Новый статич. фон: сам тайл (empty → «стена вниз» topright комнаты
|
||||||
* снизу) + правый сосед (его левая грань: был loose-край env_b(42),
|
* снизу) + правый сосед (его левая грань: был loose-край env_b(42),
|
||||||
* теперь пусто). TRANSPARENT — 0xFF не забивает чёрный, пишет и в
|
* теперь пусто). TRANSPARENT — 0xFF не забивает чёрный, пишет и в
|
||||||
* ОЗУ-копию → heal сохранит. */
|
* ОЗУ-копию → heal сохранит. */
|
||||||
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
||||||
|
bake_rest = 1; /* фон = покой (см. bake_rest) */
|
||||||
draw_tile(row, col);
|
draw_tile(row, col);
|
||||||
if (col + 1 < 10)
|
if (col + 1 < 10)
|
||||||
draw_tile(row, col + 1);
|
draw_tile(row, col + 1);
|
||||||
|
bake_rest = 0;
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -787,14 +815,24 @@ void pop_loose_bake_empty(int row, int col)
|
|||||||
* кадр 0 loose (41/42/43) на текущей y. Гравитация: speed 0→+3/кадр
|
* кадр 0 loose (41/42/43) на текущей y. Гравитация: speed 0→+3/кадр
|
||||||
* (cap 29), y+=speed. Двоебуфер: коридор фиксирован → heal чистит любой
|
* (cap 29), y+=speed. Двоебуфер: коридор фиксирован → heal чистит любой
|
||||||
* прошлый кадр ЭТОЙ страницы. Ниже поля кусок прячет clip_borders. */
|
* прошлый кадр ЭТОЙ страницы. Ниже поля кусок прячет clip_borders. */
|
||||||
static uint8_t mob_active; /* 0 нет; 1 падает */
|
/* Падающие куски — ТАБЛИЦА (порт mobs[14]/mobs_count, seg007:965). Одного
|
||||||
static uint8_t mob_clean; /* кадров дочистки после конца полёта (2 = обе стр.) */
|
* куска не хватает: в комнате 7 плиты (0,5) и (0,6) соседние, Kid роняет обе
|
||||||
static uint8_t mob_defer; /* кусок ниже Kid → рисуем ПОСЛЕ него (y-порядок) */
|
* подряд, и второй спавн затирал состояние первого — его пиксели оставались
|
||||||
static int mob_x; /* левый край (COL_XH*8) */
|
* висеть в воздухе (на каждой странице на своей y → мерцание), а щебень
|
||||||
static int mob_y; /* = curmob.y оригинала (низ куска, dby), растёт вниз */
|
* появлялся только под одной плитой. 4 слота: больше одновременно падающих
|
||||||
static int mob_prev_y[2];/* последняя нарисованная y на КАЖДОЙ странице (heal) */
|
* плит в одной комнате практически не бывает (в оригинале 14). */
|
||||||
static int8_t mob_speed;
|
#define MOB_MAX 4
|
||||||
static int8_t mob_row, mob_col; /* тайл-позиция куска (для окклюзии соседа) */
|
typedef struct {
|
||||||
|
uint8_t active; /* 0 нет; 1 падает */
|
||||||
|
uint8_t clean; /* кадров дочистки после конца полёта (2 = обе стр.) */
|
||||||
|
uint8_t defer; /* кусок ниже Kid → рисуем ПОСЛЕ него (y-порядок) */
|
||||||
|
int x; /* левый край (COL_XH*8) */
|
||||||
|
int y; /* = curmob.y оригинала (низ куска, dby), растёт вниз */
|
||||||
|
int prev_y[2]; /* последняя нарисованная y на КАЖДОЙ странице (heal) */
|
||||||
|
int8_t speed;
|
||||||
|
int8_t row, col; /* тайл-позиция куска (для окклюзии соседа) */
|
||||||
|
} mob_t;
|
||||||
|
static mob_t mobs[MOB_MAX];
|
||||||
|
|
||||||
/* Кусок «приземлился» (порт loose_land): 0 = нет, иначе tilepos+1 тайла, на
|
/* Кусок «приземлился» (порт loose_land): 0 = нет, иначе tilepos+1 тайла, на
|
||||||
* который он лёг → приложение/pop_map ставит debris + do_knock. */
|
* который он лёг → приложение/pop_map ставит debris + do_knock. */
|
||||||
@@ -809,13 +847,22 @@ static const int16_t MOB_Y_BOUND[5] = {-1, 62, 125, 188, 25};
|
|||||||
|
|
||||||
void pop_loose_mob_spawn(int row, int col)
|
void pop_loose_mob_spawn(int row, int col)
|
||||||
{
|
{
|
||||||
mob_x = COL_XH[col] * 8;
|
uint8_t i;
|
||||||
mob_y = MOB_Y_LAND[row + 1]; /* y_loose_land: низ куска в момент отрыва */
|
mob_t *m = 0;
|
||||||
mob_row = (int8_t)row;
|
/* свободный слот = не летит И дочистка завершена (иначе затрём хвост,
|
||||||
mob_col = (int8_t)col;
|
* который ещё не стёрт со второй страницы) */
|
||||||
mob_speed = 0;
|
for (i = 0; i < MOB_MAX; i++)
|
||||||
mob_active = 1;
|
if (!mobs[i].active && !mobs[i].clean) { m = &mobs[i]; break; }
|
||||||
mob_clean = 0;
|
if (!m) return; /* таблица полна — кусок без спрайта (тайл всё равно пуст) */
|
||||||
|
m->x = COL_XH[col] * 8;
|
||||||
|
m->y = MOB_Y_LAND[row + 1]; /* y_loose_land: низ куска в момент отрыва */
|
||||||
|
m->row = (int8_t)row;
|
||||||
|
m->col = (int8_t)col;
|
||||||
|
m->speed = 0;
|
||||||
|
m->active = 1;
|
||||||
|
m->clean = 0;
|
||||||
|
m->defer = 0;
|
||||||
|
m->prev_y[0] = m->prev_y[1] = MOB_Y_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Габарит куска по X: left/bottom (41/43, w=32) с mob_x; right (42, w=26)
|
/* Габарит куска по X: left/bottom (41/43, w=32) с mob_x; right (42, w=26)
|
||||||
@@ -833,47 +880,53 @@ void pop_loose_mob_spawn(int row, int col)
|
|||||||
* читается other_overlay_tile (порядок «кто поверх кого»). */
|
* читается other_overlay_tile (порядок «кто поверх кого»). */
|
||||||
static int8_t obj_col, obj_row;
|
static int8_t obj_col, obj_row;
|
||||||
|
|
||||||
static void mob_render(uint8_t pg);
|
static void mob_render(mob_t *m, uint8_t pg);
|
||||||
|
|
||||||
void pop_loose_mob_reset(void)
|
void pop_loose_mob_reset(void)
|
||||||
{
|
{
|
||||||
mob_active = 0; mob_clean = 0; mob_defer = 0;
|
uint8_t i;
|
||||||
mob_prev_y[0] = mob_prev_y[1] = MOB_Y_NONE;
|
for (i = 0; i < MOB_MAX; i++) {
|
||||||
|
mobs[i].active = 0; mobs[i].clean = 0; mobs[i].defer = 0;
|
||||||
|
mobs[i].prev_y[0] = mobs[i].prev_y[1] = MOB_Y_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_loose_mob_tick(void)
|
static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||||
{
|
{
|
||||||
uint8_t pg = gfx_get_draw_page() & 1;
|
if (!m->active && !m->clean) return;
|
||||||
if (!mob_active && !mob_clean) return;
|
|
||||||
/* Стереть кусок, нарисованный на ЭТОЙ странице в прошлый раз (у каждой
|
/* Стереть кусок, нарисованный на ЭТОЙ странице в прошлый раз (у каждой
|
||||||
* страницы своя копия фона). Раньше коридор был фиксирован под ряд 2;
|
* страницы своя копия фона). Раньше коридор был фиксирован под ряд 2;
|
||||||
* плита-потолок падает через весь ряд 0, поэтому чистим по фактической
|
* плита-потолок падает через весь ряд 0, поэтому чистим по фактической
|
||||||
* прошлой позиции. */
|
* прошлой позиции. */
|
||||||
if (mob_prev_y[pg] != MOB_Y_NONE) {
|
if (m->prev_y[pg] != MOB_Y_NONE) {
|
||||||
heal_off(MOB_X0(mob_x), mob_prev_y[pg] - 27, MOB_W, 32);
|
heal_off(MOB_X0(m->x), m->prev_y[pg] - 27, MOB_W, 32);
|
||||||
mob_prev_y[pg] = MOB_Y_NONE;
|
m->prev_y[pg] = MOB_Y_NONE;
|
||||||
}
|
}
|
||||||
if (!mob_active) { mob_clean--; return; }
|
if (!m->active) { m->clean--; return; }
|
||||||
/* гравитация (move_loose): ускорение до 29 */
|
/* гравитация (move_loose): ускорение до 29 */
|
||||||
if (mob_speed < 29) mob_speed += 3;
|
if (m->speed < 29) m->speed += 3;
|
||||||
mob_y += mob_speed;
|
m->y += m->speed;
|
||||||
/* move_loose (seg007:1126): низ куска пересёк границу своего ряда —
|
/* move_loose (seg007:1126): низ куска пересёк границу своего ряда —
|
||||||
* смотрим тайл этого ряда. Пусто/loose — валится дальше (порт
|
* смотрим тайл этого ряда. Пусто/loose — валится дальше (порт
|
||||||
* loose_fall «плита ломает плиту» не нужен: в ряду ниже её нет);
|
* loose_fall «плита ломает плиту» не нужен: в ряду ниже её нет);
|
||||||
* пол — приземление (loose_land: debris + do_knock). */
|
* пол — приземление (loose_land: debris + do_knock). */
|
||||||
if (mob_row < 3 && mob_y < 226 && MOB_Y_BOUND[mob_row + 1] <= mob_y) {
|
if (m->row < 3 && m->y < 226 && MOB_Y_BOUND[m->row + 1] <= m->y) {
|
||||||
uint8_t t = (uint8_t)(tile_code(mob_row, mob_col) & 0x1F);
|
uint8_t t = (uint8_t)(tile_code(m->row, m->col) & 0x1F);
|
||||||
if (t == 0 || t == 11) {
|
if (t == 0 || t == 11) {
|
||||||
mob_row++; /* mob_down_a_row */
|
m->row++; /* mob_down_a_row */
|
||||||
|
} else if (pop_loose_landed) {
|
||||||
|
/* сигнал прошлого приземления ещё не разобран (один за кадр) —
|
||||||
|
* подержим кусок на границе и приземлим следующим кадром */
|
||||||
|
m->y = MOB_Y_BOUND[m->row + 1];
|
||||||
} else {
|
} else {
|
||||||
mob_y = MOB_Y_BOUND[mob_row + 1];
|
m->y = MOB_Y_BOUND[m->row + 1];
|
||||||
pop_loose_landed = (uint8_t)(mob_row * 10 + mob_col + 1);
|
pop_loose_landed = (uint8_t)(m->row * 10 + m->col + 1);
|
||||||
mob_active = 0; mob_clean = 2; /* кусок исчез — на его месте debris */
|
m->active = 0; m->clean = 2; /* кусок исчез — на его месте debris */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mob_y - 27 >= POP_PLAYFIELD_H) { /* весь ниже поля (улетел из комнаты) */
|
if (m->y - 27 >= POP_PLAYFIELD_H) { /* весь ниже поля (улетел из комнаты) */
|
||||||
mob_active = 0; mob_clean = 2;
|
m->active = 0; m->clean = 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Порядок «плита vs Kid». В оригинале объекты рисуются при обходе СВОИХ
|
/* Порядок «плита vs Kid». В оригинале объекты рисуются при обходе СВОИХ
|
||||||
@@ -884,58 +937,66 @@ void pop_loose_mob_tick(void)
|
|||||||
* поверх Kid, если его тайл идёт в обходе ПОЗЖЕ тайла Kid, а при
|
* поверх Kid, если его тайл идёт в обходе ПОЗЖЕ тайла Kid, а при
|
||||||
* совпадении тайлов — если он ниже по y. */
|
* совпадении тайлов — если он ниже по y. */
|
||||||
{
|
{
|
||||||
int8_t mrow = (int8_t)(((mob_y + 60) / 63) % 4 - 1); /* y_to_row_mod4 */
|
int8_t mrow = (int8_t)(((m->y + 60) / 63) % 4 - 1); /* y_to_row_mod4 */
|
||||||
uint8_t over;
|
uint8_t over;
|
||||||
if (mrow != obj_row) over = (mrow < obj_row); /* ряды идут 2,1,0 */
|
if (mrow != obj_row) over = (mrow < obj_row); /* ряды идут 2,1,0 */
|
||||||
else if (mob_col != obj_col) over = (mob_col > obj_col);
|
else if (m->col != obj_col) over = (m->col > obj_col);
|
||||||
else over = (mob_y > kid_fp_obj_y());
|
else over = (m->y > kid_fp_obj_y());
|
||||||
if (over) { mob_defer = 1; return; }
|
if (over) { m->defer = 1; return; }
|
||||||
}
|
}
|
||||||
mob_render(pg);
|
mob_render(m, pg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mob_render(uint8_t pg)
|
void pop_loose_mob_tick(void)
|
||||||
|
{
|
||||||
|
uint8_t pg = gfx_get_draw_page() & 1, i;
|
||||||
|
for (i = 0; i < MOB_MAX; i++)
|
||||||
|
mob_tick_one(&mobs[i], pg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mob_render(mob_t *m, uint8_t pg)
|
||||||
{
|
{
|
||||||
/* Падающий кусок (SDLPoP draw_mobs/add_midtable, case 0x80): ТРИ куска —
|
/* Падающий кусок (SDLPoP draw_mobs/add_midtable, case 0x80): ТРИ куска —
|
||||||
* left(41) на obj_y-3, bottom(43) на obj_y, right(42) на obj_x+4 (=col+1,
|
* left(41) на obj_y-3, bottom(43) на obj_y, right(42) на obj_x+4 (=col+1,
|
||||||
* заходит в тайл СПРАВА) на obj_y-1. */
|
* заходит в тайл СПРАВА) на obj_y-1. */
|
||||||
gfx_set_bank(GFX_BANK_SPRITE);
|
gfx_set_bank(GFX_BANK_SPRITE);
|
||||||
env_b(43, mob_x, mob_y);
|
env_b(43, m->x, m->y);
|
||||||
env_b(41, mob_x, mob_y - 3);
|
env_b(41, m->x, m->y - 3);
|
||||||
env_b(42, mob_x + 32, mob_y - 1);
|
env_b(42, m->x + 32, m->y - 1);
|
||||||
mob_prev_y[pg] = mob_y;
|
m->prev_y[pg] = m->y;
|
||||||
/* Окклюзия правого куска соседним полом (SDLPoP redraw_at_cur_mob:
|
/* Окклюзия правого куска соседним полом (SDLPoP redraw_at_cur_mob:
|
||||||
* set_redraw_full(curr_tilepos+1) — сосед перерисовывается ПОВЕРХ mob).
|
* set_redraw_full(curr_tilepos+1) — сосед перерисовывается ПОВЕРХ mob).
|
||||||
* Правый кусок 42 целиком лежит в тайле col+1; пока плита у уровня пола,
|
* Правый кусок 42 целиком лежит в тайле col+1; пока плита у уровня пола,
|
||||||
* её правый край ПРЯЧЕТСЯ за передней гранью пола. Перерисовываем
|
* её правый край ПРЯЧЕТСЯ за передней гранью пола. Перерисовываем
|
||||||
* сосед-тайл В ТОМ ЖЕ КАДРЕ поверх куска (иначе край торчит на полу
|
* сосед-тайл В ТОМ ЖЕ КАДРЕ поверх куска (иначе край торчит на полу
|
||||||
* до heal'а следующего кадра — виден как хвост во время падения). */
|
* до heal'а следующего кадра — виден как хвост во время падения). */
|
||||||
if (mob_col + 1 < 10) {
|
if (m->col + 1 < 10) {
|
||||||
if (mob_row < 0) g_clip_top = POP_YOFF; /* полоса у потолка — только срез */
|
if (m->row < 0) g_clip_top = POP_YOFF; /* полоса у потолка — только срез */
|
||||||
draw_tile(mob_row, mob_col + 1);
|
draw_tile(m->row, m->col + 1);
|
||||||
g_clip_top = 0;
|
g_clip_top = 0;
|
||||||
}
|
}
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
/* клип СВОЕГО выхода за поле (верхний борт / статус-полоса) — по ВСЕЙ ширине */
|
/* клип СВОЕГО выхода за поле (верхний борт / статус-полоса) — по ВСЕЙ ширине */
|
||||||
pop_clip_sprite(MOB_X0(mob_x), MOB_W, mob_y - 26 + POP_YOFF, 30);
|
pop_clip_sprite(MOB_X0(m->x), MOB_W, m->y - 26 + POP_YOFF, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Отложенная отрисовка куска ПОВЕРХ Kid (он ниже Kid по obj_y). Звать
|
/* Отложенная отрисовка куска ПОВЕРХ Kid (он ниже Kid по obj_y). Звать
|
||||||
* после kid_draw, до fore-слоя. */
|
* после kid_draw, до fore-слоя. */
|
||||||
void pop_loose_mob_draw_over(void)
|
void pop_loose_mob_draw_over(void)
|
||||||
{
|
{
|
||||||
if (!mob_defer) return;
|
uint8_t pg = gfx_get_draw_page() & 1, i;
|
||||||
mob_defer = 0;
|
for (i = 0; i < MOB_MAX; i++)
|
||||||
mob_render(gfx_get_draw_page() & 1);
|
if (mobs[i].defer) { mobs[i].defer = 0; mob_render(&mobs[i], pg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Позиция падающего куска для check_loose_fall_on_kid (pop_map): колонка и
|
/* Позиция падающего куска для check_loose_fall_on_kid (pop_map): колонка и
|
||||||
* y (низ куска). 0 — куска нет. */
|
* y (низ куска). 0 — куска нет. */
|
||||||
uint8_t pop_loose_mob_pos(int *col, int *y)
|
uint8_t pop_loose_mob_pos(int *col, int *y)
|
||||||
{
|
{
|
||||||
if (!mob_active) return 0;
|
uint8_t i;
|
||||||
*col = mob_col; *y = mob_y;
|
for (i = 0; i < MOB_MAX; i++)
|
||||||
return 1;
|
if (mobs[i].active) { *col = mobs[i].col; *y = mobs[i].y; return 1; }
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Спрайт вышел за поле? → взвести флаг на 2 кадра (обе страницы дабл-
|
/* Спрайт вышел за поле? → взвести флаг на 2 кадра (обе страницы дабл-
|
||||||
@@ -976,6 +1037,7 @@ void pop_room_draw(uint8_t room_num,
|
|||||||
|
|
||||||
/* прозрачный блит: 0xFF не пишется (чёрный фон/нижние слои проступают) */
|
/* прозрачный блит: 0xFF не пишется (чёрный фон/нижние слои проступают) */
|
||||||
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
||||||
|
bake_rest = 1; /* фон = покой (см. bake_rest) */
|
||||||
for (row = 2; row >= 0; row--) /* снизу вверх (2,1,0) */
|
for (row = 2; row >= 0; row--) /* снизу вверх (2,1,0) */
|
||||||
for (col = 0; col < 10; col++)
|
for (col = 0; col < 10; col++)
|
||||||
draw_tile(row, col);
|
draw_tile(row, col);
|
||||||
@@ -987,6 +1049,7 @@ void pop_room_draw(uint8_t room_num,
|
|||||||
for (col = 0; col < 10; col++)
|
for (col = 0; col < 10; col++)
|
||||||
draw_tile(-1, col);
|
draw_tile(-1, col);
|
||||||
g_clip_top = 0;
|
g_clip_top = 0;
|
||||||
|
bake_rest = 0;
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1095,6 +1095,15 @@ void pop_loose_tick(void)
|
|||||||
}
|
}
|
||||||
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
||||||
check_loose_fall_on_kid(); /* seg007:1192 — плита падает Киду на голову */
|
check_loose_fall_on_kid(); /* seg007:1192 — плита падает Киду на голову */
|
||||||
|
/* Отложенная допечка ПРОШЛОГО приземления на вторую страницу — ПЕРЕД
|
||||||
|
* разбором нового: иначе при двух плитах, севших подряд, land_bake
|
||||||
|
* затирался новым и на одной странице оставался старый пол. */
|
||||||
|
if (land_bake && pop_loose_landed) {
|
||||||
|
uint8_t r = 0, c = land_bake_pos;
|
||||||
|
while (c >= 10) { c -= 10; r++; }
|
||||||
|
pop_floor_bake(r, c);
|
||||||
|
land_bake = 0;
|
||||||
|
}
|
||||||
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
|
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
|
||||||
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
|
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
|
||||||
uint8_t r = 0, c = pos;
|
uint8_t r = 0, c = pos;
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ __sfr __at (0xFE) io_border;
|
|||||||
/* Тест-старт для отладки пик (Фаза S): комната 6 = тестовая (пики в col3/col4
|
/* Тест-старт для отладки пик (Фаза S): комната 6 = тестовая (пики в col3/col4
|
||||||
* row2, шахта col3). Kid на полу row0 col1, идёт вправо → падает в шахту →
|
* row2, шахта col3). Kid на полу row0 col1, идёт вправо → падает в шахту →
|
||||||
* пики. TODO: вернуть на pop_level_start_room (комната 1) после отладки. */
|
* пики. TODO: вернуть на pop_level_start_room (комната 1) после отладки. */
|
||||||
#define START_ROOM 8 /* ОТЛАДКА clip_char: спуск с кнопки (0,6) */
|
#define START_ROOM 20 /* ОТЛАДКА: кнопка-closer (1,4) — отрисовка нажатой */
|
||||||
#define START_COL 8
|
#define START_COL 8
|
||||||
#define START_ROW 0
|
#define START_ROW 1
|
||||||
#define RESPAWN_DELAY 400 /* авто-респавн (фолбэк), если не нажали ↑ */
|
#define RESPAWN_DELAY 400 /* авто-респавн (фолбэк), если не нажали ↑ */
|
||||||
#define RESPAWN_SETTLE 20 /* тиков до приёма ↑ (труп успел лечь) */
|
#define RESPAWN_SETTLE 20 /* тиков до приёма ↑ (труп успел лечь) */
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,19 @@ SPIKE_ANIM_ENV_IDS = {128, 129, 130, 131, 132, # left
|
|||||||
# открытых состояний (54-59, 67) нужны анимации открытия — добавляем явно.
|
# открытых состояний (54-59, 67) нужны анимации открытия — добавляем явно.
|
||||||
GATE_ANIM_ENV_IDS = {50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 67}
|
GATE_ANIM_ENV_IDS = {50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 67}
|
||||||
|
|
||||||
|
# НАЖАТАЯ кнопка-closer (get_tile_to_draw seg008:2FE: при таймере связи >1
|
||||||
|
# tiles_6_closer рисуется как tiles_5_stuck). tile_table[5] = база 41 (уже
|
||||||
|
# есть), правая грань 35, нижняя 36 — оба id встречаются ТОЛЬКО в этом
|
||||||
|
# динамическом состоянии, статически тайла 5 в уровнях нет, значит в used
|
||||||
|
# render_room они не попадают. Без них у нажатой кнопки чёрный провал на
|
||||||
|
# месте нижней грани и потерянная правая грань.
|
||||||
|
STUCK_ENV_IDS = {35, 36}
|
||||||
|
|
||||||
|
# Левая половина кнопки-opener, когда СЛЕВА пусто (draw_tile_base seg008:0A8E:
|
||||||
|
# curr_tile==15 && tile_left==0 && level_type==0 → id 148 вместо базы 147).
|
||||||
|
# render_room этой ветки не знает, поэтому добавляем явно.
|
||||||
|
OPENER_NOFLOOR_ENV_IDS = {148}
|
||||||
|
|
||||||
# ---- chtab_1 (flame/sword/potion), база ресурса 150, папка PRINCE ----
|
# ---- chtab_1 (flame/sword/potion), база ресурса 150, папка PRINCE ----
|
||||||
# Зелье (seg008 draw_tile_fore/draw_tile_anim): склянка id 12 (малая) / 13
|
# Зелье (seg008 draw_tile_fore/draw_tile_anim): склянка id 12 (малая) / 13
|
||||||
# (большая, типы 2..4), кадры пузырька 16..22 (potion_fram_bubb) и его маска
|
# (большая, типы 2..4), кадры пузырька 16..22 (potion_fram_bubb) и его маска
|
||||||
@@ -337,7 +350,9 @@ def main():
|
|||||||
| LOOSE_ANIM_ENV_IDS # + дрожащие кадры loose
|
| LOOSE_ANIM_ENV_IDS # + дрожащие кадры loose
|
||||||
| SPIKE_ANIM_ENV_IDS # + кадры выдвижения пик
|
| SPIKE_ANIM_ENV_IDS # + кадры выдвижения пик
|
||||||
| GATE_ANIM_ENV_IDS # + кадры открытия ворот
|
| GATE_ANIM_ENV_IDS # + кадры открытия ворот
|
||||||
| TORCH_ENV_IDS) # + основание факела
|
| TORCH_ENV_IDS # + основание факела
|
||||||
|
| STUCK_ENV_IDS # + нажатая кнопка-closer
|
||||||
|
| OPENER_NOFLOOR_ENV_IDS) # + opener без пола слева
|
||||||
wall_ids = sorted(id for ch, id in used if ch == R.CHTAB_WALL)
|
wall_ids = sorted(id for ch, id in used if ch == R.CHTAB_WALL)
|
||||||
|
|
||||||
env_bg = [i for i in env_ids if i not in FORE_ENV_IDS]
|
env_bg = [i for i in env_ids if i not in FORE_ENV_IDS]
|
||||||
|
|||||||
Reference in New Issue
Block a user