Уровни 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:
@@ -355,6 +355,8 @@ int main(void)
|
||||
}
|
||||
pop_check_skel(); /* спецсобытие ур.3: скелет встаёт */
|
||||
pop_check_mouse(); /* спецсобытие ур.8: мышь жмёт кнопку */
|
||||
pop_check_killed_shadow(); /* спецсобытие ур.12: смерть тени = смерть Кида */
|
||||
pop_frame_timers(); /* timers (seg003:0735): вспышка слияния */
|
||||
pop_check_can_guard_see_kid(); /* луч видимости — ДО логики персонажей */
|
||||
pop_ctrl_tick(); /* ввод -> control(): смена seq */
|
||||
/* Кто в этом кадре не изменился с прошлой отрисовки ЭТОЙ страницы —
|
||||
@@ -396,6 +398,7 @@ int main(void)
|
||||
pop_next_level = (uint8_t)(pop_current_level + 1);
|
||||
}
|
||||
else if (down) { /* L2: переход в комнату снизу — продолжает падать */
|
||||
pop_nav_hold = 0; /* сменил комнату НОГАМИ — чит забыт */
|
||||
enter_room(down); /* координаты Kid уже репроецированы pop_map */
|
||||
gfx_set_draw_page(back); /* вернуть текущую back для отрисовки */
|
||||
} else { /* выпал из уровня (нет комнаты снизу) — рестарт */
|
||||
@@ -424,9 +427,20 @@ int main(void)
|
||||
pop_checkpoint = 1;
|
||||
hitp_beg_lev = hitp_max;
|
||||
}
|
||||
/* Соседи чекпойнта по leave_room (seg002:0490): в ветке ухода
|
||||
* ВПРАВО (pop_leave_dir == 2) — sword_disappears + meet_Jaffar,
|
||||
* в ветке ВЛЕВО — Jaffar_exit. Комната во всех трёх ещё СТАРАЯ,
|
||||
* как и в оригинале (goto_other_room идёт после). */
|
||||
if (pop_leave_dir_prev == 2) {
|
||||
pop_sword_disappears();
|
||||
pop_meet_jaffar();
|
||||
} else if (left) {
|
||||
pop_jaffar_exit();
|
||||
}
|
||||
if (nb) {
|
||||
/* side для pop_guard_follow — то же направление, по которому
|
||||
* ищем соседа (roomleave_result оригинала). */
|
||||
pop_nav_hold = 0; /* сменил комнату НОГАМИ — чит забыт */
|
||||
enter_room_side(nb, (uint8_t)(pop_leave_dir_prev - 1));
|
||||
gfx_set_draw_page(back);
|
||||
}
|
||||
@@ -438,6 +452,30 @@ int main(void)
|
||||
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
||||
pop_process_trobs(cur_room); /* пики/ворота/дверь: продвинуть СОСТОЯНИЕ (порт */
|
||||
/* process_trobs — рисования внутри нет) */
|
||||
if (pop_neigh_dirty) {
|
||||
/* Тайл СОСЕДА изменился заочно (провалилась брошенная плита —
|
||||
* animate_loose). Обе кромочные копии — снимки на момент входа
|
||||
* в комнату, обновляем обе: g_lcol/g_rcol (коллизия у шва) и
|
||||
* lcol_fg (отрисовка: колонка 9 левого соседа видна в col0
|
||||
* через draw_tile_anim_right, pop_room.c). Без второй шов
|
||||
* продолжал рисовать плиту, которой уже нет — LOOSE-ROOM-CHANGE.
|
||||
* Событие редкое, поэтому по сигналу, а не опросом каждый кадр. */
|
||||
uint8_t lft = pop_room_link(cur_room, 0);
|
||||
pop_neigh_dirty = 0;
|
||||
pop_map_refresh_edges();
|
||||
if (lft) {
|
||||
uint8_t i;
|
||||
pop_level_access_begin();
|
||||
for (i = 0; i < 3; i++) {
|
||||
uint8_t c = pop_level_tile_raw(lft, (uint8_t)(9 + i * 10));
|
||||
if (c == (uint8_t)(lcol_fg[i] & 0x1F)) continue;
|
||||
lcol_fg[i] = c;
|
||||
seam_rows |= (uint8_t)(1 << i);
|
||||
seam_redraw = 2; /* обе страницы дабл-буфера */
|
||||
}
|
||||
pop_level_access_end();
|
||||
}
|
||||
}
|
||||
pop_redraw_needed(); /* и разобрать пометки перерисовки тайлов (порт */
|
||||
/* redraw_needed, seg008:0178) — СЛОЙ ФОНА, до Kid */
|
||||
{ /* ворота соседа слева (room8) видны в col0 — */
|
||||
@@ -471,6 +509,18 @@ int main(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Бесшовный выход уровня 12 (play_level_2, seg000:900): двери уровня
|
||||
* у него нет — уровень кончается ФАКТОМ попадания в комнату 23.
|
||||
* Условие «уровень ещё не сменён» обязательно: комната 23 есть и у
|
||||
* 13-го, причём она там СТАРТОВАЯ, и без гарда переход зациклился бы
|
||||
* (12 → 13 → 14 в первом же кадре нового уровня). */
|
||||
if (pop_current_level == POP_SEAMLESS_LEVEL &&
|
||||
pop_next_level == pop_current_level &&
|
||||
!pop_nav_hold && /* не по чит-телепорту, см. pop_state.c */
|
||||
kid_room == POP_SEAMLESS_ROOM) {
|
||||
pop_next_level = (uint8_t)(pop_current_level + 1);
|
||||
pop_seamless = 1;
|
||||
}
|
||||
if (pop_next_level != pop_current_level) {
|
||||
/* Смена уровня целиком — в банке (pop_level_switch): грузится
|
||||
* файл, спрайты соперника и тайлсет. Раз на уровень. */
|
||||
@@ -550,6 +600,7 @@ int main(void)
|
||||
* HP — красный, перо (медленное падение) — зелёный. */
|
||||
if (pop_flash_color == POP_FLASH_RED) flash_bg(255, 0, 0);
|
||||
else if (pop_flash_color == POP_FLASH_GREEN) flash_bg(85, 255, 85);
|
||||
else if (pop_flash_color == POP_FLASH_WHITE) flash_bg(255, 255, 255);
|
||||
else flash_bg(255, 255, 85);
|
||||
pop_flash_time--;
|
||||
if (!pop_flash_time) pop_flash_color = POP_FLASH_YELLOW;
|
||||
@@ -567,6 +618,11 @@ int main(void)
|
||||
* пролетел сквозь зеркало, тень должна родиться ДО того, как слот
|
||||
* соперника пойдёт рисоваться, иначе кадр её проглотит. */
|
||||
pop_check_mirror();
|
||||
/* Падающие плиты, идущие ПОД Kid. Здесь, а не внутри pop_loose_tick:
|
||||
* фон кадра (перепечатки тайлов, шов) обязан быть готов ДО любого
|
||||
* спрайта, иначе перепечатка ложится поверх уже нарисованного куска —
|
||||
* так окно задней стены и передняя грань пола оказывались на плите. */
|
||||
pop_loose_mob_draw();
|
||||
{ /* Кто позже — тот поверх; порядок задаёт обход тайлов, а не роль
|
||||
* персонажа (см. guard_over_kid). Отрисовка одна на всех Char
|
||||
* (pop_cdraw.c), различает их только слот. */
|
||||
|
||||
Reference in New Issue
Block a user