Files
Sprinter-SDCC/applications/PoP/roomtest/pop_tune.h
T
snark13 67d62e3e8b Уровни 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>
2026-08-13 18:21:52 +03:00

155 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_tune.h — НАСТРАИВАЕМЫЕ КОНСТАНТЫ движка (аналог custom_options
* SDLPoP) в одном месте.
*
* Зачем отдельный заголовок. У оригинала «особые события» уровней зашиты
* магическими числами прямо в код (`current_level == 3 && Char.room == 7`),
* и SDLPoP вынес их в структуру `custom_options_type` (types.h) с
* загрузкой из SDLPoP.ini и правкой через меню Settings/Mods. Нам нужно
* то же самое по двум причинам:
*
* 1. ОТЛАДКА. Некоторые сцены руками почти не проверить (успеть в
* закрывающуюся решётку), и единственный вменяемый способ — временно
* растянуть тайминг. Такие крутилки обязаны жить в одном месте, а не
* прятаться числами по трём модулям.
* 2. МОДЫ. Тот, кто захочет свой набор уровней, меняет ровно эти числа.
*
* Пока это только `#define` — ни INI, ни меню нет (см. TASKS_OPEN.md, запись
* TUNE-1). Но правило уже действует: НОВОЕ «особое событие» или тайминг
* заводится ЗДЕСЬ, а не константой по месту. Имена — как у SDLPoP
* (custom->имя), чтобы сверка с оригиналом оставалась механической.
*/
#ifndef POP_TUNE_H
#define POP_TUNE_H
/* ---- Чекпойнт уровня 3 (SDLPoP: checkpoint_*) ----------------------- *
* Оригинал: level3_set_chkp (seg002:0665) взводит флаг, когда Кид уходит
* ВЛЕВО ИЗ комнаты 7 (вызов стоит до goto_other_room, поэтому Char.room там
* ещё старая); do_startpos (seg003:0141) подменяет по
* нему стартовую позицию и убирает loose-плиту, через которую туда
* попадают (иначе после респавна дорога назад была бы уже провалена). */
#define POP_CHKP_LEVEL 3 /* checkpoint_level */
#define POP_CHKP_ROOM 7 /* комната, ИЗ КОТОРОЙ уходят влево (у
* SDLPoP хардкод; это НЕ комната
* назначения — см. roomtest.c) */
#define POP_CHKP_RESPAWN_ROOM 2 /* checkpoint_respawn_room */
#define POP_CHKP_RESPAWN_TILEPOS 6 /* checkpoint_respawn_tilepos */
#define POP_CHKP_RESPAWN_DIR (-1) /* checkpoint_respawn_dir: влево */
#define POP_CHKP_CLEAR_ROOM 7 /* checkpoint_clear_tile_room */
#define POP_CHKP_CLEAR_COL 4 /* checkpoint_clear_tile_col */
#define POP_CHKP_CLEAR_ROW 0 /* checkpoint_clear_tile_row */
/* ---- Отладочные крутилки (в оригинале и в SDLPoP их НЕТ) ------------ *
* POP_DBG_GATE_HOLD — сколько кадров решётка держится поднятой после
* нажатия кнопки, ПРЕЖДЕ чем пойдёт вниз. В оригинале это таймер связи
* дверей: trigger_button ставит 5, animate_button вычитает по единице, и
* решётка стоит, пока таймер > 1 (то есть ~4 кадра после того, как Кид
* сошёл с кнопки). Проверять руками проход в закрывающуюся решётку при
* таком окне почти невозможно, поэтому значение вынесено сюда: поставь
* 30 — и успеешь дойти спокойно. ОБЯЗАН быть 5 в игровой сборке.
*
* ПОТОЛОК 30. Таймер связи — пять бит модификатора кнопки (маска 0x1F), а
* значение 31 у оригинала означает «событие заклинено» (`link_timer != 0x1F`
* в trigger_button). Больше 30 ставить нельзя — кнопка перестанет
* срабатывать вовсе. */
#define POP_DBG_GATE_HOLD 5
/* ---- Улучшения SDLPoP (в ОРИГИНАЛЕ их нет) -------------------------- *
* POP_ENABLE_JUMP_GRAB — зацепиться за кромку можно ПРЯМО В ПРЫЖКЕ, если
* Shift зажат заранее (SDLPoP `enable_jump_grab`, seg006:1228). Ваниль
* разрешает зацеп только в начале падения (`check_grab`, кадры 102..105),
* то есть Shift приходится нажимать уже в полёте — это и раздражало на
* приёмке. 0 — как в оригинале, 1 — как в SDLPoP с включёнными
* enhancements. */
#define POP_ENABLE_JUMP_GRAB 1
/* ---- Чомперы (SDLPoP: custom->chomper_speed) ------------------------ *
* Период смыкания челюстей в кадрах: фаза крутится 1..N и сбрасывается в 1.
* В оригинале 15; SDLPoP выносит это в настройку, потому что на разных
* уровнях моды любят делать чомперы быстрее. Меньше — злее. */
#define POP_CHOMPER_SPEED 15
/* ---- Отладка сцены «тень крадёт зелье» (уровень 5) ------------------ *
* Тень появляется в комнате 24 сразу при входе, но СТОИТ, пока не откроют
* ворота (кол 1, ряд 0, openness >= 80) — так в оригинале
* (autocontrol_shadow_level5, seg002:1157). Чтобы посмотреть саму сцену
* (подход, питьё, уход), не проходя уровень до кнопки, поставь 1: тень
* стартует запись ходов сразу. ОБЯЗАН быть 0 в игровой сборке. */
#ifndef POP_DBG_SHADOW_NOWAIT
#define POP_DBG_SHADOW_NOWAIT 0
#endif
/* ---- Зелье МЕДЛЕННОГО ПАДЕНИЯ (SDLPoP: FEATHER_FALL_LENGTH) ---------- *
* В оригинале длительность эффекта задана НЕ таймером, а звуком: эффект
* держится, пока играет sound_39_low_weight, и снимается принудительно на
* 225-м тике (do_timers, seg003:0517). Звука у нас нет, поэтому берём тот
* же порог напрямую — 225 ИГРОВЫХ КАДРОВ (у оригинала тик do_timers = кадр
* игрового цикла; 225 кадров при его 12 fps и есть FEATHER_FALL_LENGTH =
* 18,75 с из фикса SDLPoP). По ВРЕМЕНИ у нас выйдет короче ровно настолько,
* насколько наша игра быстрее оригинала — это общий вопрос темпа
* (TASKS_OPEN.md, L1-SPEED), а не свойство зелья. */
#define POP_FEATHER_FRAMES 225
/* ---- Спецсобытие «МЫШЬ» (уровень 8, комната 16) ---------------------- *
* Кнопка (0,7) комнаты 16 открывает решётку (0,3) — ту, за которой лежит
* путь через комнату 4 (два чомпера) к кнопке выхода в комнате 3. Сам Кид
* до кнопки с левой площадки не дотягивается (провал в колонках 4..6),
* поэтому, когда дверь уровня уже открыта, а он всё ещё в комнате 16,
* оригинал через 150 тиков присылает мышь: она пробегает справа налево по
* верхнему ряду, наступает на кнопку и убегает обратно (do_timers
* seg003:0545, do_mouse seg003:0ABA, autocontrol_mouse seg002:07EB).
*
* Числа — custom-константы SDLPoP (data.h:821): уровень/комната/задержка/
* стартовая X. Пороги разворота (166) и исчезновения (200) — литералы
* autocontrol_mouse. Задержка в ИГРОВЫХ КАДРАХ, как POP_FEATHER_FRAMES. */
#define POP_MOUSE_LEVEL 8
#define POP_MOUSE_ROOM 16
#define POP_MOUSE_DELAY 150
#define POP_MOUSE_START_X 200
#define POP_MOUSE_TURN_X 166 /* x < этого — развернуться и уйти */
#define POP_MOUSE_LEAVE_X 200 /* x >= этого в стойке — исчезнуть */
/* ---- Уровень зелий (SDLPoP: «potions level», seg006:1894) ------------ *
* На нём синие склянки «вреда» забирают ПОЛОВИНУ запаса HP, а не единицу.
* В оригинале это условие `current_level == 15` прямо в proc_get_object. */
#define POP_POTIONS_LEVEL 15
/* С какого уровня начинается игра (-DFIRST_LEVEL=N при сборке). Живёт
* здесь, а не в roomtest.c: старт уровня уехал в холодную половину цикла
* (roomtest_cold.c, банк 8), и константа нужна обеим. */
#ifndef FIRST_LEVEL
#define FIRST_LEVEL 1
#endif
/* Уровень с зельем инверсии (переворот экрана). По нему делается
* ПРЕДзагрузка зеркального набора спрайтов персонажей — чтобы пауза на
* чтение 34 страниц пришлась на загрузку уровня, а не на глоток зелья. */
#define POP_UPSIDE_LEVEL 9
/* Уровень ПАДАЮЩИХ ПЛИТ (custom->loose_tiles_*, seg000:1317 check_fall_flo).
* При входе в комнату 23 или 16 тринадцатого уровня вся гряда loose ряда 2
* комнаты СВЕРХУ получает ОТРИЦАТЕЛЬНУЮ фазу — отложенный старт, — и плиты
* сыплются на Кида вразнобой. Комнаты сверху — 17 и 1 соответственно, и в
* них ряд 2 колонок 2..7 действительно loose (сверено по res2013.bin,
* ../docs/levels_12_15_plan.md §7.1). Диапазон 22..27 — надмножество: в
* комнате 1 тайл 24 пустой, и он молча пропускается.
*
* Комната 23 у этого уровня ещё и СТАРТОВАЯ, то есть плиты сыплются с
* первого кадра уровня — это его открывающая сцена, а не событие в
* середине. */
#define POP_LOOSE_TILES_LEVEL 13
#define POP_LOOSE_TILES_ROOM1 23
#define POP_LOOSE_TILES_ROOM2 16
#define POP_LOOSE_TILES_FIRST 22 /* ряд 2, колонка 2 */
#define POP_LOOSE_TILES_LAST 27 /* ряд 2, колонка 7 */
/* Бесшовный выход уровня (tbl_seamless_exit, play_level_2 seg000:900). У
* оригинала это таблица по уровням, но заполнена она ровно одной парой:
* уровень 12 кончается, как только Кид попал в комнату 23 — двери уровня у
* него нет. Комната 23 у 13-го уровня СТАРТОВАЯ и совпадает геометрией
* ряда, поэтому шва не видно (../docs/levels_12_15_plan.md §1.7). */
#define POP_SEAMLESS_LEVEL 12
#define POP_SEAMLESS_ROOM 23
#endif /* POP_TUNE_H */