f63751edce
Падающий кусок теперь привязан к своей комнате и долетает после ухода Кида; подтверждено живым прогоном. Автоматикой гонка не воспроизводилась — мост MAME шлёт нажатия рывками, и «уйти раньше, чем долетит плита» через него не набиралось; это отмечено в записи вместе с указанием, что кейс стоит первым в плане host-тестов. Вторая волна прогона уровня 1 закрыта целиком: BUG-KBD-4, BUG-RESPAWN-2, BUG-DRAWORDER-1, BUG-LOOSE-2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
236 lines
19 KiB
Markdown
236 lines
19 KiB
Markdown
# roomtest — ОТКРЫТЫЕ баги и незакрытые оптимизации
|
||
|
||
Только то, что **не закрыто**. Всё закрытое (и, что важнее, разбор корней)
|
||
переехало в [`bug_closed.md`](bug_closed.md): прежде чем заводить новый баг,
|
||
грепни там по симптому.
|
||
|
||
Приоритеты работ — в [`TASKS.md`](TASKS.md), а не здесь. Правило проекта:
|
||
механику сверять с `../SDLPoP/src/` ДО кодинга.
|
||
|
||
Ревизия списка: **2026-08-03** (прогон всех комнат уровня 1). Одиннадцать
|
||
наблюдений с прогона свелись к шести корням; **все шесть закрыты и проверены
|
||
в MAME** — разбор в [`bug_closed.md`](bug_closed.md): BUG-LVLSTATE-1 (уровень
|
||
стал мутабельным), BUG-RESPAWN-1 (респавн перезагружает уровень),
|
||
BUG-DEATH-1 (смерть от меча), BUG-GATE-ANIM-1 (анимация ворот), BUG-COLL-1
|
||
(полный порт `check_collisions`), BUG-STANDUP-1 (лишний guard в
|
||
`bumped_floor`). Клавиатурный BUG-KBD-3 доведён до конца во второй волне
|
||
(см. ниже); из первой волны открытым остался косметический BUG-SEAM-DRAW-1.
|
||
|
||
Ревизия **2026-08-03, вечер** (вторая волна с прогона): все четыре наблюдения
|
||
закрыты — BUG-KBD-4 (фантомный отжим Shift), BUG-RESPAWN-2 (стражи не оживают),
|
||
BUG-DRAWORDER-1 (Кид поверх тела стража) и BUG-LOOSE-2 (осколки только от одной
|
||
из двух плит). У BUG-DRAWORDER-1 остался артефакт «ноги поверх головы»,
|
||
сверенный с SDLPoP и записанный в «НЕ БАГИ».
|
||
|
||
| ID | что | тип | статус |
|
||
|----|-----|-----|--------|
|
||
| [BUG-SEAM-DRAW-1](#bug-seam-draw-1) | у решётки на шве экран переключается, а Кид в шве НЕ рисуется | Minor | открыт |
|
||
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт |
|
||
| [T-2](#t-2) | Кид перерисовывается в покое | оптимизация | открыт |
|
||
| [обход 24 комнат](#обход-всех-24-комнат-уровня-1) | таблица заполнена на 5 строк из 24 | ревизия | открыт |
|
||
|
||
---
|
||
|
||
<a id="ручная-перепроверка-2026-08-03"></a>
|
||
# Ручная перепроверка фиксов (2026-08-03)
|
||
|
||
Шесть корней закрыты автоматической проверкой в MAME (мост `mame-z80`:
|
||
чтение `_Kid`, потиковые трассы, скриншоты) — этого достаточно, чтобы
|
||
показать, что конкретный сценарий больше не воспроизводится, но НЕ
|
||
достаточно, чтобы поймать регрессии в соседней механике. Ниже — сценарии
|
||
ровно в тех формулировках, в которых баги были заведены.
|
||
|
||
Собрано и лежит в образе (`make` + `make hdd` уже прогнаны; libc пересобран,
|
||
`make size-check` без роста).
|
||
|
||
| # | что проверить | ожидаемо |
|
||
|---|---------------|----------|
|
||
| 1 | комната 22: выпить зелье (0,6), выйти в 16/23 и вернуться | кувшина нет, пузырька над пустым местом нет |
|
||
| 2 | то же для комнат 14 (0,5) и 17 (2,3) | так же |
|
||
| 3 | комната 15: подобрать меч (2,2), выйти и вернуться | меча нет; кладка на дальней стене НЕ мигает |
|
||
| 4 | комната 12: разбить плиты (0,1)/(0,2) и потолок в 16, выйти-вернуться | остаются разбитыми, проём не закрывается |
|
||
| 5 | комната 17 из 23: разбить (1,5)/(1,6), выпить зелье (2,3), вернуться | всё остаётся |
|
||
| 6 | **после смерти** зайти в те же комнаты | ВСЁ восстановлено (в оригинале смерть = `load_level`) |
|
||
| 7 | комната 12: разбег в закрытую решётку (0,9) с полушага | не проходит насквозь; экран может перелистнуться — это [BUG-SEAM-DRAW-1](#bug-seam-draw-1) |
|
||
| 8 | комната 6: бег справа налево от (0,9), длинный прыжок (0,6)→(0,7) | не влетает внутрь стены |
|
||
| 9 | комната 5: с кнопки (0,6) падение на (2,7), присед, вставание | остаётся в комнате 5 (проверено трассой: `fr=111 x=177` → `seq_47` → `fr=15 x=173`) |
|
||
| 10 | комната 5: нажать кнопку (0,4) | поднимаются ОБЕ решётки — (0,5) видно на экране, (0,9) проверять из комнаты 1 |
|
||
| 11 | страж (комнаты 3, 21) убивает Кида | смерть доигрывается, респавн в стартовой позиции уровня; цикла «убил-воскрес» нет |
|
||
| 12 | клавиатура: долгая игра с Shift+стрелка | ↑ и Shift не залипают; осторожный шаг не превращается в бег (доработано во второй волне — п.17) |
|
||
|
||
## Вторая волна (2026-08-03, вечер)
|
||
|
||
| # | что проверить | ожидаемо |
|
||
|---|---------------|----------|
|
||
| 17 | **[BUG-KBD-4]** долго играть Shift+стрелка, много тапов подряд | Shift не «отваливается»; если однажды залипнет — снимается первым же нажатием стрелки |
|
||
| 18 | **[BUG-RESPAWN-2]** убить стража (комнаты 3/21), умереть, вернуться в ту же комнату | страж снова жив, стоит на исходном тайле, HP полные |
|
||
|
||
Отдельно стоит посмотреть **на регрессии от порта `check_collisions`** — он
|
||
трогает всю горизонтальную коллизию: бамп в стену на бегу и в прыжке,
|
||
осторожный шаг у стены, проход через ОТКРЫТЫЕ ворота, разворот в проёме
|
||
решётки, переходы через швы (старый BUG-SEAM-PINGPONG).
|
||
|
||
---
|
||
|
||
# Открытые баги уровня 1
|
||
|
||
<a id="bug-seam-draw-1"></a>
|
||
## BUG-SEAM-DRAW-1. Кид, упершийся в решётку на шве, не рисуется
|
||
|
||
**Симптом.** Комната 5: Кид добегает до закрытой решётки (0,9), решётка его
|
||
ДЕРЖИТ (проверено: x встаёт на 60 и дальше не растёт), но экран
|
||
переключается на комнату 1, и в ней Кид не виден — он стоит на `x = 57..60`,
|
||
левее кромки комнаты (col 0 начинается с 58).
|
||
|
||
**Разбор.** Переключение экрана само по себе штатное: `leave_room`
|
||
(seg002:423) уводит вправо при `char_x_right >= 201`, а левая грань решётки
|
||
как раз 201 — то есть в оригинале экран тоже перелистнётся, если персонаж
|
||
встанет ровно на грань. Не штатно то, что персонажа в шве **не рисуют**:
|
||
`update_kid_render_dx` даёт смещение только когда `kid_room != cur_room`, а
|
||
`enter_room` сразу выравнивает `kid_room = cur_room`. Это остаток
|
||
непортированной модели straddle (S3 в `pop_kid_plan`).
|
||
|
||
**Что делать.** Довести S3: держать `Kid.room` отдельно от `drawn_room` и
|
||
рисовать персонажа со смещением ±140, как `xpos_in_drawn_room` (seg004:0405).
|
||
|
||
|
||
|
||
|
||
|
||
# Оптимизация отрисовки (записано 2026-07-29)
|
||
|
||
Не баги — план работ. Оба пункта про одно: у оригинала пометка тайла к
|
||
перерисовке стоит копейки (бит в таблице, которая всё равно чистится каждый
|
||
кадр), а у нас каждая такая пометка превращается в реальный heal (копию из
|
||
ОЗУ-копии акселератора) плюс блиты. Поэтому буквальный порт «перерисовываем
|
||
безусловно» корректен, но дорог.
|
||
|
||
<a id="t-1"></a>
|
||
## T-1. Пики: перерисовывать по причине, а не безусловно
|
||
|
||
**Сейчас:** `pop_process_trobs` зовёт `pop_spike_redraw` каждый кадр для
|
||
каждой живой пики в комнате (порт `redraw_21h`, который `animate_spike`
|
||
вызывает вне всяких `if`). Это корректно, но лишнее для пик, до которых
|
||
Киду дела нет.
|
||
|
||
**Надо:** перерисовывать тайл пики, только если
|
||
1. **сменился её видимый кадр** (шаг выдвижения/уборки), ЛИБО
|
||
2. **её кто-то стёр** — а стереть у нас может только heal, то есть тайл
|
||
попал в прямоугольник `kid_heal` этого кадра.
|
||
|
||
Это и есть модель оригинала, просто выраженная флагами: `redraw_at_char`
|
||
(seg003:0576) каждый кадр помечает `set_redraw_fore` тайлы персонажа, причём
|
||
**объединение текущего и предыдущего** прямоугольника
|
||
(`MIN(char_top_row, prev_char_top_row)` и т.д.), а `animate_spike` помечает
|
||
свой тайл. Итог = {тайл сменил кадр} ∪ {тайлы Кида}.
|
||
|
||
**Как:** слой Кида и так считает `cL..cR`/`rT..rB` в `pop_fore_over_kid` —
|
||
пусть публикует их (плюс предыдущие, как в оригинале), а цикл trob'ов
|
||
сравнивает `tilepos` с диапазоном целочисленно. Никаких пересечений
|
||
прямоугольников (см. память `manual_hints_over_auto_detect`).
|
||
|
||
**Приоритет:** отдаётся почти бесплатно ПОСЛЕ T-2, отдельно не окупается.
|
||
|
||
<a id="t-2"></a>
|
||
## T-2. Idle-skip: не перерисовывать Кида, когда ничего не происходит
|
||
|
||
**Сейчас:** `kid_heal` → `kid_draw` → `pop_fore_over_kid` идут каждый кадр,
|
||
даже когда Kid стоит и в его тайлах ничего не меняется. Это ровно поведение
|
||
оригинала (`draw_game_frame`, seg000:917 — `draw_moving()` + `draw_tables()`
|
||
безусловно), но у него это дёшево, а у нас нет.
|
||
|
||
**Надо:** пропускать heal+draw Кида, когда кадр/поза/координаты не менялись
|
||
и в его тайлах нет активной анимации.
|
||
|
||
**Осторожно (дабл-буфер):** пропускать можно **не раньше второго подряд**
|
||
неизменного кадра — иначе одна из двух страниц останется со старым
|
||
содержимым. Условие «обе страницы уже получили это состояние».
|
||
|
||
**Связь с T-1:** после T-2 пики отпадают сами — раз Кида не перерисовываем,
|
||
heal'а нет, стирать пики нечем, редрой не нужен.
|
||
|
||
**Связь с KBD-1:** это ещё и минус DI-окна в самых спокойных кадрах — ровно
|
||
там, где тапают Shift+стрелку (см. остаток KBD-1 в [`TASKS.md`](TASKS.md)).
|
||
|
||
---
|
||
|
||
# Обход всех 24 комнат уровня 1 — поиск багов отрисовки
|
||
|
||
Инструмент: `#define ROOMNAV` в `roomtest.c` — `+`/`-` (цифровой блок либо
|
||
`=`/`-` основного ряда) переключают комнату по номеру (1..24, с обёрткой),
|
||
Kid ставится на первый пол, `pop_trob_reset()` возвращает пики/ворота в
|
||
исходное. Номер комнаты — полосками в верхнем борте: слева десятки, справа
|
||
единицы (`||` `||||` = 24). Убирается закомментированием одной строки.
|
||
|
||
Комнаты **13, 18, 24 недостижимы** в обычной игре — это свойство данных
|
||
уровня, разбор в [`bug_closed.md`](bug_closed.md) («НЕ БАГИ»). Приоритет
|
||
багов в них низкий.
|
||
|
||
Таблица заполнена на 5 строк из 24 — доделать в рамках L1-TRIAGE
|
||
([`TASKS.md`](TASKS.md)).
|
||
|
||
| комната | статус | что не так |
|
||
|---------|--------|------------|
|
||
| 1 | пофикшено | падающая плита (2,6): правая грань видна через пол (2,7) и перекрывает его переднюю грань — `mob_render` брал ряд соседа из `m->row` (счётчик, уже ушедший на ряд вперёд), а не из координаты |
|
||
| 2 | | |
|
||
| 3 | | |
|
||
| 4 | | |
|
||
| 5 | пофикшено | прыжок в решётку: Kid оставался стоять на 6 px ВЫШЕ пола и без приземления-приседания — от `bumped()` (seg004) был портирован только хвост (`seq_47`), не хватало `bumped_floor` (прижатие Y к полу + `seq_46_hardbump` на кадрах прыжка 24/25/40..42/102..106) и `bumped_fall` |
|
||
| 6 | | |
|
||
| 7 | | |
|
||
| 8 | | |
|
||
| 9 | сделано | дверь уровня (1,3)-(1,4) рисовалась чёрным проёмом: не был портирован `draw_leveldoor` (seg008:1D29) — створка (слайсы 33 + верх 34), лестница за ней (99/144) и анимация подъёма по кнопке (`animate_leveldoor`, seg007:05F1, modif 0→43). Спрайты 33/34/99/144 добавлены в атлас явным набором (render_room.py дверь не рисует) |
|
||
| 10 | | |
|
||
| 11 | | |
|
||
| 12 | пофикшено | вис/подтягивание на кромке loose-плиты: плита рисовалась ПОД Кидом. Не хватало двух кусков `draw_tile`: (а) `draw_loose` кладёт нижнюю грань плиты И в foretable (поверх персонажа), (б) `draw_tile_base` подставляет верх плиты из `loose_fram_left`, а в нашем midtable-оверлее стоял голый `base_id` (у loose он 0). Голова Кида поверх падающей на него плиты — см. «НЕ БАГИ» в `bug_closed.md` |
|
||
| 13 | недостижима в игре | |
|
||
| 14 | | |
|
||
| 15 | сделано | меч (2,2) не рисовался: тайл 22 в draw_tile_anim не был портирован. Добавлены отрисовка предмета (chtab_1 id 10/11 на draw_main_y−3), подъём по Shift (check_get_item/get_item/do_pickup: присед → seq_91 pickupsword → меч исчезает с пола) и статус `pop_have_sword` |
|
||
| 16 | | |
|
||
| 17 | | |
|
||
| 18 | недостижима в игре | |
|
||
| 19 | | |
|
||
| 20 | | |
|
||
| 21 | | |
|
||
| 22 | | |
|
||
| 23 | | |
|
||
| 24 | недостижима в игре | |
|
||
|
||
---
|
||
|
||
## Заметки (отладка)
|
||
|
||
- Тестовые клавиши осторожного шага: **J** = шаг влево, **L** = шаг вправо
|
||
(эмуляция Shift+стрелка), см. `pop_ctrl.c` `KBD_DBG_STEP*`. Первый шаг в
|
||
сторону = разворот (как в оригинале safe_step), движение со второго.
|
||
- Читы (`pop_cheat.h`): **K** — убить стража, **I** — бессмертие (toggle),
|
||
**S** — выдать меч.
|
||
- Респавн после смерти — по **↑** (или авто через `RESPAWN_DELAY`); ставит
|
||
Kid в стартовую позицию УРОВНЯ (`pop_start_level`, порт do_startpos).
|
||
- **ROOMNAV (`=`/`-`) — тоже наш чит**, которого в оригинале не было, как и
|
||
`S`. Все они со временем съедутся в общий блок читов, разрешаемый в
|
||
настройках; пока просто включены (`pop_cheats = 1` в `roomtest.c`).
|
||
|
||
|
||
---
|
||
|
||
<a id="сырые-наблюдения-прогон-2026-08-03"></a>
|
||
## Сырые наблюдения (прогон 2026-08-03) → корень
|
||
|
||
Формулировки с прогона, как записаны. Закрытые корни — в
|
||
[`bug_closed.md`](bug_closed.md).
|
||
|
||
| # | наблюдение (кратко) | корень | статус |
|
||
|---|---------------------|--------|--------|
|
||
| 1 | кувшин выпит, а пузырёк рисуется / кувшин возвращается (14, 22, 17) | BUG-LVLSTATE-1 | закрыт |
|
||
| 2 | меч возвращается в 15 / мигает контур кладки | BUG-LVLSTATE-1 | закрыт |
|
||
| 3 | комната 12: пробегает сквозь закрытую решётку (0,9) | BUG-COLL-1 | закрыт |
|
||
| 4 | после respawn плиты остаются разбитыми, зелья выпитыми | BUG-RESPAWN-1 | закрыт |
|
||
| 5 | плита/зелье возвращаются и БЕЗ respawn (12→16, 17, 22) | BUG-LVLSTATE-1 | закрыт |
|
||
| 6 | комната 6: длинный прыжок (0,6)→(0,7) — влёт в стену, респавн | BUG-COLL-1 | закрыт |
|
||
| 7 | залипает ↑ | BUG-KBD-3 | закрыт (см. `bug_closed.md`) |
|
||
| 8 | залипает Shift | BUG-KBD-3 / BUG-KBD-4 | закрыт (см. `bug_closed.md`) |
|
||
| 9 | комната 5: кнопка (0,4) не открывает решётку (0,5) | BUG-GATE-ANIM-1 | закрыт |
|
||
| 10 | комната 5: с кнопки (0,6) на (2,7), присед — провал в комнату 6 | BUG-STANDUP-1 | закрыт |
|
||
| 11 | страж убил Кида → Кид воскресает на месте и его убивают снова | BUG-DEATH-1 | закрыт |
|