PoP roomtest: дверь уровня — створка, лестница и анимация открытия
Комната 9: портал на уровень 2 рисовался чёрным проёмом — не был
портирован draw_leveldoor (seg008:1D29). Дверь рисуется при обработке
ПРАВОЙ половины (tile_left = 0x10), все куски со сдвигом +8 px:
99 низ лестницы (всегда),
144 марш лестницы за створкой (когда створка тронулась),
33 слайс створки — повторяется вниз с шагом 4 px до y = ybottom-modif
(modif 0 = закрыто на всю высоту, 43 = открыто, остаётся кромка),
34 верх коробки.
Анимация: animate_leveldoor (seg007:05F1) — type 0..2 открытие (modif++
до 43), type>=3 быстрое закрытие со скоростями {0,5,17,99}. Кнопка
заводит trob через trigger_1 (seg007:0999): дверь открывается ОДИН раз,
при modif != 0 кнопка уже ничего не делает.
Перерисовка створки — pop_leveldoor_redraw: draw_tile правой половины С
ЗАПЕЧКОЙ в ОЗУ-копию (банк TRANSPARENT), иначе kid_heal возвращал бы из
фона закрытую створку. Куски двери непрозрачные, wipe не нужен.
Спрайты 33/34/99/144 не попадали в атлас: сбор идёт прогоном
render_room.py, а он draw_leveldoor не реализует — добавлены явным
набором LEVELDOOR_ENV_IDS (как STUCK_ENV_IDS для нажатой кнопки).
Проверено в MAME (комната 9): закрытая дверь = решётка как в оригинале;
после нажатия кнопки (0,0) створка едет вверх, открывая лестницу.
Вход в дверь (кадры 217..228 + переход на уровень 2) НЕ делался.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -445,7 +445,7 @@ Kid ставится на первый пол, `pop_trob_reset()` возвращ
|
||||
| 6 | | |
|
||||
| 7 | | |
|
||||
| 8 | | |
|
||||
| 9 | | |
|
||||
| 9 | сделано | дверь уровня (1,3)-(1,4) рисовалась чёрным проёмом: не был портирован `draw_leveldoor` (seg008:1D29) — створка (слайсы 33 + верх 34), лестница за ней (99/144) и анимация подъёма по кнопке (`animate_leveldoor`, seg007:05F1, modif 0→43). Спрайты 33/34/99/144 добавлены в атлас явным набором (render_room.py дверь не рисует) |
|
||||
| 10 | | |
|
||||
| 11 | | |
|
||||
| 12 | пофикшено | вис/подтягивание на кромке loose-плиты: плита рисовалась ПОД Кидом. Не хватало двух кусков `draw_tile`: (а) `draw_loose` кладёт нижнюю грань плиты И в foretable (поверх персонажа), (б) `draw_tile_base` подставляет верх плиты из `loose_fram_left`, а в нашем midtable-оверлее стоял голый `base_id` (у loose он 0). Голова Кида поверх падающей на него плиты — см. «НЕ БАГИ» |
|
||||
|
||||
@@ -464,6 +464,32 @@ static uint8_t get_loose_frame(uint8_t m)
|
||||
return m;
|
||||
}
|
||||
|
||||
/* draw_leveldoor (seg008:1D29) — дверь уровня. Рисуется при обработке
|
||||
* ПРАВОЙ половины (tile_left = 0x10), все куски со сдвигом +8px (xh+1):
|
||||
* 99 низ лестницы (всегда),
|
||||
* 144 марш лестницы за створкой (когда створка приподнята, modif != 0),
|
||||
* 33 слайс створки — повторяется вниз с шагом 4px, пока не дойдёт до
|
||||
* y = ybottom − modif: modif 0 = закрыто (створка на всю высоту),
|
||||
* 43 = открыто (остаётся только верхняя кромка),
|
||||
* 34 верх коробки двери.
|
||||
* Куски непрозрачные (blitters_0_no_transp) — как в оригинале. */
|
||||
static void draw_leveldoor(uint8_t modif, int xh, int dmy)
|
||||
{
|
||||
int x = (xh + 1) * 8;
|
||||
int ybottom = dmy - 13;
|
||||
int ylo = ybottom - (int)(modif & 3) - 48; /* leveldoor_ybottom */
|
||||
int y = ybottom - (int)modif;
|
||||
env_b(99, x, ybottom);
|
||||
if (modif)
|
||||
env_b(144, x, ybottom - 4); /* лестница (комната ≠ стартовой) */
|
||||
for (;;) {
|
||||
env_b(33, x, ylo);
|
||||
if (y > ylo) ylo += 4;
|
||||
else break;
|
||||
}
|
||||
env_b(34, x, dmy - 64);
|
||||
}
|
||||
|
||||
/* ---- draw_tile (seg008.c:155) — одна клетка ------------------------ */
|
||||
static void draw_tile(int row, int col)
|
||||
{
|
||||
@@ -539,6 +565,8 @@ static void draw_tile(int row, int col)
|
||||
uint8_t sf = (lmod & 0x80) ? 5 : lmod;
|
||||
if (sf < 10 && SPIKES_FRAM_RIGHT[sf])
|
||||
env_b(SPIKES_FRAM_RIGHT[sf], x, dmy - 7);
|
||||
} else if (lcode == 16) { /* дверь уровня */
|
||||
draw_leveldoor(lmod, xh, dmy);
|
||||
}
|
||||
/* Пламя факела (seg008:560, chtab_1 id modifier+1) в фон НЕ запекаем:
|
||||
* оно анимируется каждый кадр, а heal вернул бы запечённый кадр из-под
|
||||
@@ -769,6 +797,17 @@ void pop_floor_bake(int row, int col)
|
||||
|
||||
void pop_button_redraw(int row, int col) { pop_floor_bake(row, col); }
|
||||
|
||||
/* Перерисовать ПРАВУЮ половину двери уровня (в её ячейке рисуется створка,
|
||||
* см. draw_leveldoor) на back-странице С ЗАПЕЧКОЙ в ОЗУ-копию: створка едет,
|
||||
* а heal обязан возвращать её ТЕКУЩЕЕ положение, а не запечённое закрытое.
|
||||
* Куски двери непрозрачные — wipe не нужен. */
|
||||
void pop_leveldoor_redraw(int row, int col)
|
||||
{
|
||||
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
||||
draw_tile(row, col);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
}
|
||||
|
||||
/* Запечь ПУСТОТУ на месте упавшего loose (текущая страница). Порт
|
||||
* redraw_at_cur_mob (seg007:132C): перерисовать сам тайл (теперь empty) И
|
||||
* тайл СПРАВА (его левая грань зависит от нашего кода: пока был loose —
|
||||
|
||||
@@ -102,6 +102,10 @@ void pop_room_redraw_seam_left(void);
|
||||
void pop_floor_bake(int row, int col);
|
||||
void pop_button_redraw(int row, int col); /* = pop_floor_bake (кнопка) */
|
||||
|
||||
/* Дверь уровня: перерисовать её ПРАВУЮ половину (row, col = правая) с
|
||||
* запечкой — створка анимируется (pop_trob animate_leveldoor). */
|
||||
void pop_leveldoor_redraw(int row, int col);
|
||||
|
||||
/* Падающий кусок loose (mob, seg007 move_loose): спавн при падении тайла
|
||||
* (row,col) и покадровое продвижение+отрисовка на back-странице. tick
|
||||
* зовётся каждый кадр (внутри pop_loose_tick); клип низа делает clip. */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define TILE_OPENER 0x0F
|
||||
#define TILE_POTION 0x0A
|
||||
#define TILE_SWORD 0x16 /* меч-предмет на полу */
|
||||
#define TILE_LEVELDOOR 0x10 /* левая половина двери уровня (на ней modif) */
|
||||
#define TILE_TORCH 0x13
|
||||
#define TILE_TORCH_DEBRIS 0x1E
|
||||
|
||||
@@ -240,6 +241,13 @@ static int8_t trigger_1(uint8_t target_type, uint8_t room, uint8_t tilepos, uint
|
||||
{
|
||||
if (target_type == TILE_GATE)
|
||||
return trigger_gate(room, tilepos, button_type);
|
||||
if (target_type == TILE_LEVELDOOR) {
|
||||
/* trigger_1 (seg007:0999): дверь уровня открывается ОДИН раз — если
|
||||
* створка уже тронулась (modif != 0), кнопка ничего не делает. */
|
||||
uint8_t *m = pop_trob_modif(room);
|
||||
if (m && m[tilepos] == 0) return 1;
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -282,6 +290,27 @@ static void animate_button(uint8_t idx, int8_t *type)
|
||||
}
|
||||
}
|
||||
|
||||
/* animate_leveldoor (seg007:05F1): створка двери уровня. type 0..2 —
|
||||
* открытие (modif 0 -> 43, по пикселю за кадр), type >= 3 — быстрое
|
||||
* закрытие со скоростями {0,5,17,99} (после выхода из уровня). Готово ->
|
||||
* type = -1. */
|
||||
static const uint8_t leveldoor_close_speeds[5] = {0, 5, 17, 99, 0};
|
||||
|
||||
static void animate_leveldoor(uint8_t *m, int8_t *type)
|
||||
{
|
||||
if (*type < 0) return;
|
||||
if (*type >= 3) {
|
||||
uint8_t sp;
|
||||
if (*type < 7) (*type)++;
|
||||
sp = leveldoor_close_speeds[*type - 3];
|
||||
if (sp >= *m) { *m = 0; *type = -1; }
|
||||
else *m = (uint8_t)(*m - sp);
|
||||
} else {
|
||||
if (*m < 43) (*m)++;
|
||||
if (*m >= 43) { *m = 43; *type = -1; }
|
||||
}
|
||||
}
|
||||
|
||||
/* animate_door (seg007:0522): openness по типу анимации. *m — modif ворот,
|
||||
* *type — 0 закрытие / 1 открытие / 2 насовсем / 3..8 быстрое закрытие. */
|
||||
static const uint8_t gate_close_speeds[9] = {0, 0, 0, 20, 40, 60, 80, 100, 120};
|
||||
@@ -384,6 +413,9 @@ void pop_process_trobs(uint8_t cur_room)
|
||||
case TILE_GATE:
|
||||
animate_door(&mod[tp], &type);
|
||||
break;
|
||||
case TILE_LEVELDOOR:
|
||||
animate_leveldoor(&mod[tp], &type);
|
||||
break;
|
||||
case TILE_TORCH:
|
||||
case TILE_TORCH_DEBRIS:
|
||||
/* animate_torch (seg007:03C1): кадр пламени; анимация вечная —
|
||||
@@ -439,6 +471,14 @@ void pop_process_trobs(uint8_t cur_room)
|
||||
* его уже никто не положит: ставим отложенный редрой. */
|
||||
if (type < 0) { spike_rest[tp] = 1; rest_pending++; }
|
||||
}
|
||||
if (room == cur_room && code == TILE_LEVELDOOR) {
|
||||
/* Створка едет каждый кадр — перерисовываем ПРАВУЮ половину (там
|
||||
* её рисует draw_tile_anim_right) С ЗАПЕЧКОЙ в ОЗУ-копию: иначе
|
||||
* kid_heal вернул бы из фона закрытую створку. Куски двери
|
||||
* непрозрачны, поэтому wipe не нужен. */
|
||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
||||
if (tcol + 1 < 10) pop_leveldoor_redraw(trow, tcol + 1);
|
||||
}
|
||||
if (room == cur_room && code == TILE_SWORD) {
|
||||
/* МЕЧ — редрой только на смене видимого кадра (блеск = modif==1):
|
||||
* спрайт запечён в фон (draw_tile), поэтому перерисовываем тайл
|
||||
|
||||
Reference in New Issue
Block a user