Уровни 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:
@@ -231,6 +231,151 @@ MEM-BANK2, MEM-BANK5, CLIP-1, KBD-1, DBG-CHEATS.
|
||||
|
||||
## P0 — делаем сейчас
|
||||
|
||||
### <a id="l12-shadow"></a>L12-SHADOW. Уровень 12: встреча с тенью, бой, слияние
|
||||
|
||||
> **Статус 2026-08-13: код написан, хост-тесты зелёные (45 проверок,
|
||||
> `tests-host/t_shadow.c`), ЖИВОЙ ПРОВЕРКИ В MAME ЕЩЁ НЕ БЫЛО.** Для неё
|
||||
> нужна сборка с `FIRST_LEVEL=12` и полный рестарт MAME после `make hdd`.
|
||||
|
||||
План и сверка констант с оригинальными данными —
|
||||
[`../docs/levels_12_15_plan.md`](../docs/levels_12_15_plan.md) §1 и §7.
|
||||
Сделано ровно по нему:
|
||||
|
||||
| кусок | где | порт |
|
||||
|---|---|---|
|
||||
| подъём тени в комнате 15 (условие «меч уже подобран») | `guards.c` `pop_check_shadow` | seg002:0070 |
|
||||
| `init_shad_12` + вход ПАДЕНИЕМ (`seq_7`) | `guards.c` | data:0EFA |
|
||||
| ИИ тени: ждать Кида / драться / сойтись / слиться | `guards.c` `autocontrol_shadow_level12` | seg002:1184 |
|
||||
| «ранил тень — ранил себя» | `pop_guard.c` `pop_do_delta_hp` | seg000:1518 |
|
||||
| «убил тень — убил себя» | `guards.c` `pop_check_killed_shadow` | seg006:2033 |
|
||||
| таймер вспышки слияния (0 → счётчик → −1) | `pop_guard.c` `pop_shadow_timer` | seg003:0735 |
|
||||
| меч исчезает при уходе вправо из комнаты 18 | `guards.c` `pop_sword_disappears` | seg002:0536 |
|
||||
| появление плит в комнатах 2/13 после слияния | `pop_map.c` `floors_appear` | seg006:1063 |
|
||||
| бесшовный переход 12 → 13 (комната 23, без двери) | `roomtest.c` + `pop_start_level` | seg000:0900 |
|
||||
|
||||
Осознанное расхождение: мигания Кида спрайтами тени во время вспышки нет —
|
||||
запись в [`../docs/impl_diff.md`](../docs/impl_diff.md).
|
||||
|
||||
<a id="bg-once"></a>
|
||||
### BG-ONCE. Задний фон рисуется ОДИН раз; вместо чёрных баров — heal
|
||||
|
||||
**Предложение пользователя 2026-08-13. Не делать сейчас — обязательно к
|
||||
проверке и реализации на этапе полиша/оптимизации.**
|
||||
|
||||
Суть: элементы САМОГО заднего фона — факелы без пламени, окна, узор кладки,
|
||||
решётчатая кладка и что ещё найдётся — впечатываются в фон один раз и больше
|
||||
не перерисовываются никогда. Ни один объект за ними оказаться не может, а
|
||||
значит и возвращать их поверх чего-либо не нужно. Если такой элемент оказался
|
||||
затёрт, это САМО ПО СЕБЕ сигнал об ошибке: либо бар/прямоугольник слишком
|
||||
велик, либо что-то рисуется не в своём слое.
|
||||
|
||||
Вторая половина предложения — и она про скорость: там, где мы гасим область
|
||||
чёрным баром перед выводом спрайта, звать вместо бара **heal по координатам
|
||||
бара**. Бар всё равно приходится потом закрывать фоном, то есть выходит две
|
||||
операции; heal делает то же одной и сразу правильным содержимым.
|
||||
|
||||
**Оценка: идея верная по направлению, но есть два известных препятствия.**
|
||||
|
||||
1. **Узкий heal уже пробовали — и откатили.** В `pop_room.c` (`pop_clip_sprite`)
|
||||
записано: per-спрайтовый heal не используется, потому что выравнивание
|
||||
блока акселератора оставляет 1-2 px слайверы правой грани, и на одной
|
||||
странице дабл-буфера это мерцает. Поэтому борта чистит полоса
|
||||
`pop_room_clip_borders` с гейтом по флагу. Прежде чем менять бары на heal,
|
||||
надо решить именно эту задачу — иначе получим мерцание вместо ускорения.
|
||||
2. **Полный запрет «не перерисовывать фон» противоречит foretable.**
|
||||
`draw_tile_fore` (seg008:715) кладёт в передний слой ГЛАВНУЮ ГРАНЬ стены
|
||||
вместе с её узором — она обязана перекрывать персонажа. То есть запрет
|
||||
должен различать «декор задней стены» и «передняя грань», а это ровно
|
||||
различие backtable/foretable оригинала. Фактически предложение сводится к
|
||||
«привести наши слои в соответствие с таблицами оригинала» — тот же вывод,
|
||||
к которому пришёл разбор `overlay_mid_tile` (см. ниже).
|
||||
|
||||
**Известное исключение**, которое надо не сломать: Кид, уходящий по лестнице
|
||||
в дверь уровня, действительно уезжает за передний план — но он и рисуется
|
||||
отдельно (`clip_char`, правая грань doortop; см. memory `pop_clip_char_todo`).
|
||||
|
||||
**Критерий приёмки этапа:** пройти уровни с падающими плитами (13) и с
|
||||
факелами/окнами (10-12) и убедиться, что ни один фоновый элемент не
|
||||
перерисовывается в кадре, где его тайл не менялся; замерить кадр до и после.
|
||||
|
||||
<a id="l12-shadow-spr"></a>
|
||||
### L12-SHADOW-SPR. Тень дерётся спрайтами СТРАЖА, а не своими
|
||||
|
||||
**Найдено прогоном 2026-08-13.** `tbl_guard_type[12] = 4` — это SHADOW.DAT,
|
||||
отдельный набор спрайтов (силуэт Кида), а `pop_guard_load` (`pop_cdraw.c`)
|
||||
разбирает только тип 2 (SKEL) и 3 (VIZIER); тип 4 сваливается в набор
|
||||
обычного стража. Ассеты есть: `SDLPoP/data/SHADOW` (32 кадра + `res750.pal`).
|
||||
|
||||
Правка по образцу VIZIER (набор в `pop_pack_guard.py`, каталог в Makefile,
|
||||
ветка в `pop_guard_load`), НО сначала проверить две вещи, иначе спрайты
|
||||
поедут: (1) какую таблицу кадров получает `CHARID_1_SHADOW` в
|
||||
`pop_frame_tbl_is_guard` — Кида или стража, и (2) сколько кадров в наборе
|
||||
(32 против 34 у стража) и не выходит ли индекс за его пределы.
|
||||
|
||||
Это НЕ полный «вид тени» (OR/XOR-блиттеры, [`../docs/shadow_render.md`]) —
|
||||
только правильный набор спрайтов вместо чужого.
|
||||
|
||||
<a id="l12-seam-polish"></a>
|
||||
### L12-SEAM-POLISH. Переход 12 -> 13 выглядит коряво
|
||||
|
||||
Механика работает (комната 23, без заставки и без сброса HP), но сама
|
||||
анимация прохода рваная — замечено пользователем 2026-08-13. Полишинг,
|
||||
берётся вместе с остальной шлифовкой переходов.
|
||||
|
||||
<a id="l13-jaffar"></a>
|
||||
### L13-JAFFAR. Уровень 13: Джафар, победа, выход, падающая гряда
|
||||
|
||||
> **Статус 2026-08-13: код написан, хост-тесты зелёные (44 проверки,
|
||||
> `tests-host/t_jaffar.c`), ЖИВОЙ ПРОВЕРКИ В MAME ЕЩЁ НЕ БЫЛО.**
|
||||
|
||||
Своего ИИ у Джафара нет — это обычный страж (seg002:085A), skill 9 и 6 HP уже
|
||||
лежат в `pop_level_cold.c`. Сделаны только события и данные:
|
||||
|
||||
| кусок | где | порт |
|
||||
|---|---|---|
|
||||
| фора после встречи (`guard_notice_timer`) | `guards.c` `pop_meet_jaffar` + `autocontrol_guard_inactive` | seg002:0544 / 0736 |
|
||||
| победа: белая вспышка + «выход разрешён» | `guards.c` `on_guard_killed` | seg006:1927 |
|
||||
| выход: кнопка комнаты 24 при уходе ВЛЕВО | `guards.c` `pop_jaffar_exit` | seg002:0517 |
|
||||
| гряда плит сверху при входе в комнаты 23/16 | `pop_map.c` `pop_check_fall_flo` | seg000:1317 |
|
||||
| фазу со старшим битом на 13-м НЕ гасить | `pop_map.c` `pop_loose_tick`, `pop_trob.c` `animate_loose` | seg007:823 |
|
||||
| сотрясение на 13-м плиты НЕ трясёт | `pop_map.c` `do_knock` | seg007:949 |
|
||||
| плита бьёт и В БЕГЕ | `pop_map.c` `fell_on_your_head` | seg007:1218 |
|
||||
| СПРАЙТЫ Джафара (VIZIER.DAT, своя палитра) | `pop_pack_guard.py`, `pop_cdraw.c`, `Makefile` | seg000:1092 |
|
||||
|
||||
По ходу нашлась и починена смежная ошибка: цвет стража из данных комнаты
|
||||
применялся к ЛЮБОМУ набору, хотя оригинал берёт его только у обычного стража
|
||||
(`curr_guard_color = 0` при `tbl_guard_type != 0`, seg002:183) — скелета это
|
||||
не задевало случайно, Джафара покрасило бы.
|
||||
|
||||
Осознанное расхождение (представление фазы отложенного старта) — запись в
|
||||
[`../docs/impl_diff.md`](../docs/impl_diff.md).
|
||||
|
||||
**Не портировано намеренно:** `is_show_time` в `on_guard_killed` — это показ
|
||||
ОСТАВШЕГОСЯ ВРЕМЕНИ, а часов на 60 минут у нас пока нет вовсе.
|
||||
|
||||
**Что проверять в MAME** (`make LEVEL=13`):
|
||||
|
||||
1. комната 23 (стартовая): плиты сверху сыплются ВРАЗНОБОЙ с первых кадров,
|
||||
и они бьют, даже если пробегать под ними;
|
||||
2. приземление Кида плиты НЕ трясёт (иначе гряда посыплется разом);
|
||||
3. уход вправо из комнаты 3: Джафар виден СВОИМИ спрайтами и своей палитрой,
|
||||
~2 секунды стоит, не доставая клинок;
|
||||
4. смерть Джафара — белая вспышка; уход ВЛЕВО открывает дверь уровня.
|
||||
|
||||
**Что проверять в MAME** (по порядку прохождения уровня):
|
||||
|
||||
1. комната 15: пока меч лежит — тени нет; подобрал меч, вышел и вернулся —
|
||||
тень СВАЛИВАЕТСЯ сверху, а не стоит готовая;
|
||||
2. бой: каждый удар по тени отнимает HP и у Кида; добить её нельзя — на её
|
||||
смерти умирает и Кид (белая вспышка);
|
||||
3. слияние: убрать меч (`Shift`+вниз), подойти — белая вспышка, тень исчезла,
|
||||
потолок HP вырос на единицу;
|
||||
4. после слияния в комнатах 2 и 13 (верхний ряд) под ногами появляются плиты;
|
||||
5. уход ВПРАВО из комнаты 18 убирает меч из комнаты 15 (вернуться и взять
|
||||
второй раз нельзя);
|
||||
6. комната 23 — уровень молча становится 13-м, HP НЕ сбрасывается.
|
||||
|
||||
|
||||
### <a id="l7-feather"></a>L7-FEATHER. Зелье МЕДЛЕННОГО ПАДЕНИЯ (уровень 7, комната 1)
|
||||
|
||||
> **Статус 2026-08-12: код написан, ждёт живой проверки в MAME.** Сделаны все
|
||||
|
||||
Reference in New Issue
Block a user