Мышь уровня 8 + холодная половина главного цикла в банк 8
Спецсобытие уровня 8 (SDLPoP seg003:0545/0ABA, seg002:07EB): когда дверь уровня открыта, а Кид остаётся в комнате 16, через 150 кадров приходит мышь, пробегает справа налево по верхнему ряду, наступает на кнопку (0,7) — решётка (0,3) открывается — и убегает. Ассетов не потребовалось: кадры 186..188 идут по таблице Кида, их спрайты (images 130..132) уже лежат в kid16.atl, отрисовка подхватывает мышь сама. - guards.c: pop_check_mouse, autocontrol_mouse, ветки мыши в autocontrol_opponent / play_guard / check_can_guard_see_kid; - pop_leveldoor_open стал word, как в оригинале (в него же считается задержка — байт переполнился бы через 255 кадров); - leave_guard больше не записывает тень и мышь в данные уровня (seg002:02F5); - полосы HP у мыши нет (seg000:1159); - tests-host/t_mouse: 17 проверок, единственный набор с guards.c. Разгрузка резидента (куча в huge упала до 879 Б): pop_start_level, find_start_level_door, чит-навигация по комнатам и лейбл номера уехали в roomtest_cold.c (--bank 8, n_banks = 8). _CODE 25653 -> 24825, куча -> 1707 Б; кадровый путь не тронут. Проверено: tests-host 6/6, make size-check OK, живьём в MAME (мышь появилась, нажала кнопку, решётка поехала вверх, мышь ушла). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,103 @@
|
||||
|
||||
---
|
||||
|
||||
## Уровни: спецсобытия
|
||||
|
||||
<a id="l8-mouse"></a>
|
||||
### L8-MOUSE. Мышь уровня 8 — ЗАКРЫТА 2026-08-12
|
||||
|
||||
Спецсобытие комнаты 16: кнопка (0,7) открывает решётку (0,3), но с левой
|
||||
площадки верхнего ряда до кнопки не дойти — между ними провал в три колонки.
|
||||
Когда дверь уровня уже открыта, а Кид всё ещё в комнате 16, оригинал через
|
||||
150 кадров присылает мышь: она пробегает справа налево, наступает на кнопку и
|
||||
убегает. Порт по SDLPoP: `do_timers` seg003:0545, `do_mouse` seg003:0ABA,
|
||||
`autocontrol_mouse` seg002:07EB.
|
||||
|
||||
**Ассетов и отрисовки не потребовалось вовсе.** Кадры 186..188 лежат в
|
||||
таблице КИДА (`load_frame` seg006:0293 — общий case), их images 130..132 уже
|
||||
упакованы в `kid16.atl` (idx 2/3/4: 17×4, 19×4, 12×10) — `pop_pack_kid.py`
|
||||
берёт все `res(401+N).png`, что есть в `data/KID`. Отрисовка подхватывает
|
||||
мышь сама: `pop_frame_tbl_is_guard(24, …)` отдаёт 0, значит и таблица кадров,
|
||||
и набор атласов берутся кидовские, и палитра (0x70) тоже.
|
||||
|
||||
Что написано:
|
||||
|
||||
| где | что |
|
||||
|---|---|
|
||||
| `guards.c` | `pop_check_mouse` (условие + рождение), `autocontrol_mouse`, ветки мыши в `autocontrol_opponent` / `play_guard` / `pop_check_can_guard_see_kid` |
|
||||
| `pop_state.c/h` | `pop_leveldoor_open` стал **word**, как в оригинале (data.h:361): в него же считается задержка, байт переполнился бы через 255 кадров и обнулил признак «дверь открыта» |
|
||||
| `pop_guard.c` | `leave_guard` не записывает в данные уровня тень и мышь (seg002:02F5) — раньше эта проверка отсутствовала вовсе |
|
||||
| `pop_cdraw.c` | полосы HP у мыши нет (`draw_guard_hp`, seg000:1159) |
|
||||
| `pop_tune.h` | числа события (уровень/комната/задержка/пороги X) |
|
||||
|
||||
**Правило появления — мышь ОДНОРАЗОВАЯ (сверено с оригиналом).** Счётчик
|
||||
живёт в `leveldoor_open`: 0 на старте уровня (seg003:97), 1 — когда створка
|
||||
двери уровня доехала доверху (seg007:456, то есть Кид нажал кнопку в комнате
|
||||
3), дальше `++` каждый кадр, пока Кид в комнате 16, и вызов ровно при
|
||||
`== 150`. Отсюда три следствия:
|
||||
|
||||
- второго раза НЕТ: счётчик растёт дальше, а сравнение строгое. Не успел
|
||||
пройти решётку, пока она открыта — мышь больше не придёт;
|
||||
- выход из комнаты 16 счётчик не сбрасывает, а ЗАМОРАЖИВАЕТ: ушёл на сотом
|
||||
кадре, вернулся — ждать осталось пятьдесят;
|
||||
- обнуляет только `start_level`, то есть смерть/рестарт уровня — но он же
|
||||
возвращает тайлы и модификаторы, так что дверь придётся открывать заново.
|
||||
|
||||
Значения `0x4D` (музыка уровней 4 и 6) и `2` (победа над Джаффаром, уровень
|
||||
13) в ту же переменную к уровню 8 отношения не имеют — там счёт идёт
|
||||
монотонно 1 → 150.
|
||||
|
||||
**Чего в условии НЕТ (проверено грепом по всем упоминаниям `mouse_level` /
|
||||
`mouse_room` / `do_mouse` — единственная точка запуска это seg003:545):**
|
||||
оригинал не смотрит ни на состояние решётки (0,3), ни на то, с какой стороны
|
||||
провала стоит Кид, ни на то, прошёл ли он её уже. «Кид заперт за закрытой
|
||||
решёткой» получается САМО: находиться в комнате 16 двенадцать с половиной
|
||||
секунд можно только топчась там, а стоит уйти в комнату 4 — счётчик
|
||||
замирает. Обратная сторона той же простоты: вернувшись в комнату 16 с ЛЮБОЙ
|
||||
стороны, игрок доигрывает накопленное ожидание и может получить мышь, даже
|
||||
если решётка в этот момент открыта.
|
||||
|
||||
Тупика при этом нет: провал в колонках 4..6 ведёт на нижний ряд комнаты
|
||||
(`debris` между колоннами, а колонна — проходимый пол, seg006:0628), оттуда
|
||||
низом через комнату 4 с шипами есть путь к двери уровня в комнате 3. Цена —
|
||||
падение на два ряда, то есть −1 HP. Мышь экономит эту единицу, а не спасает
|
||||
от тупика.
|
||||
|
||||
**Тонкость, на которой легко сломать уход:** `seq_107` прыгает на метку
|
||||
`Mscurry1`, стоящую ПОСЛЕ опкода `act(actions_1_run_jump)` в `seq_105` — на
|
||||
обратном пути кадры бега проигрываются, а `action` остаётся стоечным. Именно
|
||||
этим оригинал отличает «бежит к кнопке» от «убегает»: условие исчезновения
|
||||
висит на `action == 0`.
|
||||
|
||||
**Проверено.** Хост-набор `t_mouse` (17 проверок, единственный, куда
|
||||
линкуется `guards.c`) — рождение по таймеру, замороженный счётчик вне комнаты,
|
||||
требование открытой двери, нажатие кнопки на пробеге, разворот и исчезновение,
|
||||
невидимость для Кида, необращение в «стража комнаты». Регресс проверен
|
||||
откатом: без ветки в `autocontrol_opponent` падают две проверки ухода.
|
||||
Живьём в MAME (комната 16 уровня 8, `leveldoor_open` взведён через мост):
|
||||
мышь появилась (`charid = 0x18`), добежала до колонки 7 (кадр 188, x = 164),
|
||||
решётка (0,3) поехала вверх, мышь ушла вправо и погасла (`direction = 0x56`).
|
||||
|
||||
<a id="mem-cold1"></a>
|
||||
### MEM-COLD1. Холодная половина главного цикла — в банк 8 (2026-08-12)
|
||||
|
||||
К уровню 8 куча в режиме huge упала до **879 Б**. Убирать из `roomtest.c`
|
||||
оказалось нечего — отладочное там всё живое (обход комнат, стоп-кадр, читы,
|
||||
профиль), — поэтому вынесли в банк то, что отрабатывает раз на уровень или
|
||||
только по клавише: `pop_start_level` + `find_start_level_door`, чит-навигацию
|
||||
по комнатам и лейбл номера комнаты (`roomtest_cold.c`, `--bank 8`, `n_banks`
|
||||
поднят до 8).
|
||||
|
||||
Результат: `_CODE` 25653 → 24825, **куча 879 → 1707 Б**, банк 8 занят на 5 %.
|
||||
Кадровый путь не тронут: за обычный кадр в банк 8 уходит ноль вызовов, при
|
||||
смене комнаты — один трамплин.
|
||||
|
||||
Что осталось в резиденте намеренно: `enter_room_side` и рабочие массивы
|
||||
комнаты (их читает и главный цикл, и холодная половина), `guard_over_kid` с
|
||||
хелперами (зовётся каждый кадр). Следующий шаг — [MEM-COLD2](TASKS_OPEN.md#mem-cold2).
|
||||
|
||||
---
|
||||
|
||||
## Приёмка уровней
|
||||
|
||||
<a id="pass-policy"></a>
|
||||
|
||||
Reference in New Issue
Block a user