Уровни 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:
2026-08-13 18:21:52 +03:00
parent 716f6f9273
commit 67d62e3e8b
37 changed files with 3169 additions and 79 deletions
+28 -1
View File
@@ -109,7 +109,15 @@ void pop_start_level(void) __banked
pop_level_reset_tiles();
pop_level_reset_guards();
pop_guard_reset(); /* start_level: Guard.direction = none */
/* united_with_shadow = 0 (seg003:95) — состояние ПЕРСОНАЖА уровня, а не
* комнаты: pop_guard_reset зовётся и при каждом входе в комнату (из
* pop_guard_enter), поэтому гасить слияние надо здесь. */
pop_united_shadow = 0;
pop_shadow_init = 0;
pop_guard_notice_timer = 0; /* фора Джафара — не переживает рестарт */
pop_nav_hold = 0; /* старт уровня снимает и держатель чита */
pop_loose_mob_reset(); /* start_level: mobs_count = 0 (seg003:88) */
pop_loose_forget(); /* ...и фазы плит — уровень восстановлен целиком */
/* «Особое событие: убрать loose-плиту» (do_startpos): без этого путь в
* комнату-чекпойнт после респавна остался бы непройденным. */
if (chkp)
@@ -155,7 +163,11 @@ void pop_start_level(void) __banked
/* play_level (seg003:106): have_sword = level >= have_sword_from_level
* (=2) — начиная со второго уровня меч у Кида уже есть. */
pop_have_sword = (uint8_t)(pop_current_level >= 2);
pop_kid_hp_reset();
/* seamless (seg003:158): пришли БЕЗ двери уровня, прямо на бегу — HP не
* трогаем, оно переезжает как есть. Флаг одноразовый: у оригинала его
* гасит заставка «LEVEL N», которую этот же переход и пропускает. */
if (pop_seamless) { pop_seamless = 0; pop_kid_hp_carry(); }
else pop_kid_hp_reset();
}
/* ---- ОТЛАДКА: обход комнат по номеру -------------------------------- *
@@ -234,6 +246,16 @@ uint8_t pop_dbg_roomnav(uint8_t dir) __banked
holding_sword = 0;
offguard = 0;
guard_refrac = 0;
/* ПРОВАЛ НА СЛЕДУЮЩИЙ УРОВЕНЬ ПО ЧИТУ (та же болезнь, что выше).
* Уровень 12 кончается ФАКТОМ попадания в комнату 23 — двери у него нет
* (pop_seamless, seg000:0900). А навигация перебирает комнаты ПО
* НОМЕРУ, то есть любой обход рано или поздно наступает на 23-ю, и
* уровень молча меняется на 13-й: комнату 23 двенадцатого уровня читом
* не посмотреть в принципе, а прогон «съезжает» на соседний уровень
* незаметно для проверяющего (поймано 2026-08-13 на первом же прогоне).
* Держим триггер, пока Кид не сменит комнату НОГАМИ. */
pop_nav_hold = 1;
return 1;
}
@@ -276,6 +298,10 @@ void enter_room_side(uint8_t room, uint8_t side) __banked
* enter звать нельзя: он уже перенесён и живёт дальше как есть. */
uint8_t follow = (uint8_t)(side <= 3 ? pop_guard_follow(room, side) : 0);
if (!follow) pop_guard_leave(); /* запомнить стража уходящей комнаты */
/* ...и так же запомнить НЕДОСЧИТАННЫЕ loose: пока карта ещё описывает
* СТАРУЮ комнату, фаза уезжает в персистентный room_modif + trob, и
* плита доваливается заочно (см. pop_loose_leave_room / animate_loose). */
pop_loose_leave_room();
uint8_t *room_mod;
pop_room_load(room, room_fg, room_bg, lcol_fg, lcol_bg, rcol_fg, rcol_bg, below_fg);
pop_map_set(room_fg);
@@ -317,6 +343,7 @@ void enter_room_side(uint8_t room, uint8_t side) __banked
pop_trob_room_changed(); /* отложенные перерисовки пик — не из старой комнаты */
pop_trob_anim_room(room); /* факелы/зелья: стартовая фаза + trob */
pop_start_chompers(room, Kid.curr_row); /* seg000:1288: чомперы РЯДА Кида */
pop_check_fall_flo(); /* спецсобытие ур.13: гряда плит сверху */
/* check_shadow (seg002:0064) стоит ПЕРЕД enter_guard и на «шадоу»-
* уровнях забирает слот соперника себе: вернула 1 — стража поднимать
* НЕЛЬЗЯ (в комнате 24 уровня 5 он есть в данных, но оригинал его туда