d552cbaca9
Три Critical'а (BUG-1 провал на row 1 при боковом переходе, BUG-2 ping-pong при возврате, BUG-3 окклюзия climb-up на кнопке) висели непроверенными с 2026-07-21. Прогнал в MAME: - BUG-1 не воспроизводится: room6 → кнопка (0,2) → открытая решётка → переход влево даёт room8, y=55, curr_row=0. Заодно снят и сам диагноз записи — репроекция Y при БОКОВОМ переходе не нужна: goto_other_room (seg002.c:390) меняет только x, наш check_leave делает то же. - BUG-2 не воспроизводится: шов room2↔room3, четыре пересечения с разворотом сразу после входа — комната меняется ровно раз на пересечение. - BUG-3 закрыт фиксом tile_code_drawn от 2026-07-28 (это дубль уже записанного «спуск с кнопки»); оговорка про непереснятый подъём — в bug_closed.md. bug_list.md теперь только открытое (BUG-CEIL-1/2/3, BUG-OCCL-1, T-1, T-2, таблица обхода 24 комнат) + индекс с якорями. bug_closed.md — закрытое вместе с разбором корней (odd-pixel char_x, подстановка тайла кнопки, баг кодогенератора SDCC), он и есть главная ценность архива. TASKS.md: кросслинки на открытые баги в шапке, в L1-TRIAGE, L1-PASS и «Отложено». Указатели в CLAUDE.md/README/room_model_plan/layout_plan_v2 переведены на нужный из двух файлов. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
193 lines
14 KiB
Markdown
193 lines
14 KiB
Markdown
# roomtest — ОТКРЫТЫЕ баги и незакрытые оптимизации
|
||
|
||
Только то, что **не закрыто**. Всё закрытое (и, что важнее, разбор корней —
|
||
odd-pixel арифметика `char_x`, подстановка тайла нажатой кнопки, баг
|
||
кодогенератора SDCC) переехало в [`bug_closed.md`](bug_closed.md): прежде чем
|
||
заводить новый баг, грепни там по симптому.
|
||
|
||
Приоритеты работ — в [`TASKS.md`](TASKS.md), а не здесь. Правило проекта:
|
||
механику сверять с `../SDLPoP/src/` ДО кодинга.
|
||
|
||
Ревизия списка: **2026-08-01** (задача L1-TRIAGE). BUG-1, BUG-2 и BUG-3
|
||
стояли как Critical с 2026-07-21 — все три прогнаны в MAME и закрыты,
|
||
протокол в [`bug_closed.md`](bug_closed.md). Critical'ов сейчас нет.
|
||
|
||
| ID | что | тяжесть |
|
||
|----|-----|---------|
|
||
| [BUG-CEIL-1](#bug-ceil-1) | прыжок вверх: руки Kid поверх потолка | Medium |
|
||
| [BUG-CEIL-3](#bug-ceil-3) | анимация ворот стирает потолок над ними | Medium |
|
||
| [BUG-OCCL-1](#bug-occl-1) | тень дальней колонны перекрывает Kid | Medium |
|
||
| [BUG-CEIL-2](#bug-ceil-2) | loose-плита в потолке не трясётся | Medium, отложен |
|
||
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация |
|
||
| [T-2](#t-2) | Кид перерисовывается в покое | оптимизация |
|
||
| [обход 24 комнат](#обход-всех-24-комнат-уровня-1) | таблица заполнена на 5 строк из 24 | ревизия |
|
||
|
||
---
|
||
|
||
<a id="bug-ceil-1"></a>
|
||
## BUG-CEIL-1. Прыжок вверх: руки Kid рисуются ПОВЕРХ потолка — **Medium**
|
||
|
||
**Симптом (2026-07-22):** при прыжке вверх (SEQ up, кадры 67..79) руки/голова
|
||
Kid заходят в полосу кладки у потолка (row -1) и рисуются ПОВЕРХ неё — потолок
|
||
должен окклюдить руки (как передняя грань).
|
||
|
||
**Где:** `pop_bg.c` — полоса потолка (`draw_tile(-1)`) сейчас только фон
|
||
(запечена в pop_room_draw), не окклюдер поверх Kid. Нужен ceiling-overlay в
|
||
`pop_fore_over_kid` (перерисовать срез полосы над Kid поверх спрайта), по
|
||
аналогии с fore-тайлами. Инфраструктура `g_clip_top`/`gfx_blit_part` уже есть.
|
||
|
||
<a id="bug-ceil-3"></a>
|
||
## BUG-CEIL-3. Анимация ворот стирает потолок над ними — **Medium**
|
||
|
||
**Симптом (2026-07-22):** при опускании/поднятии решётки шва (анимация openness)
|
||
полоса кладки у потолка НАД воротами пропадает (см. потолок над левым швом).
|
||
|
||
**Где:** `pop_bg.c` `pop_room_redraw_seam_left` (и `pop_button_redraw`/
|
||
`pop_spike_redraw` — общий класс): чёрный `bar` по col0 row0 стирает потолочную
|
||
полосу (row-1), а redraw рисует только сам гейт, не восстанавливая полосу.
|
||
Нужно: при перерисовке шва/тайла у потолка перерисовать и срез потолочной полосы
|
||
(draw_tile(-1,col) с g_clip_top) над затронутыми колонками.
|
||
|
||
<a id="bug-occl-1"></a>
|
||
## BUG-OCCL-1. Тень дальней колонны перекрывает Kid в (0,4)-(0,5) — **Medium**
|
||
|
||
**Симптом (2026-07-22):** Kid, стоя/прыгая у (0,4)-(0,5), частично перекрыт
|
||
тёмной штриховкой — это ТЕНЬ/боковая грань ДАЛЬНЕЙ колонны (сзади по глубине),
|
||
которая НЕ должна окклюдить персонажа. Over-occlusion fore-слоя.
|
||
|
||
**Где:** `pop_bg.c` `pop_fore_over_kid`/`fore_tile` — рисует fore футпринт-тайлов
|
||
без учёта глубины (какая грань РЕАЛЬНО перед Kid). Порт seg003 redraw_at_char
|
||
окклюдит только передние грани; дальняя колонна (за Kid) не должна. Сверить с
|
||
SDLPoP redraw_at_char (какие тайлы/грани идут в fore vs back по y-сортировке).
|
||
|
||
<a id="bug-ceil-2"></a>
|
||
## BUG-CEIL-2. Тряска/разбитие loose-плиты в потолке (row -1) не работает — **Medium, ОТЛОЖЕН**
|
||
|
||
**Симптом (2026-07-22):** loose-плита в ряду 2 верхнего соседа (room5 (2,5) →
|
||
потолок room6 над (0,5)) при прыжках Kid на (0,5) НЕ трясётся и не разбивается.
|
||
|
||
**Где:** верхний сосед не «живой» — `above_fg` берётся из статики уровня,
|
||
loose-состояние соседней комнаты не тянем (per-room loose/modif не персистятся).
|
||
check_press/knock работают только по текущей комнате. Нужно: (а) пробой
|
||
loose сверху через границу комнаты, (б) персистентное loose-состояние соседа +
|
||
его отрисовка в полосе. Пока полоса рисует loose статически (кадр покоя).
|
||
|
||
**Почему отложен:** требует персистентного per-room modifier соседей — это
|
||
фаза P0 из [`../docs/gates_spikes_plan.md`](../docs/gates_spikes_plan.md), а не
|
||
точечный фикс. См. «Отложено осознанно» в [`TASKS.md`](TASKS.md).
|
||
|
||
---
|
||
|
||
# Оптимизация отрисовки (записано 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 в `START_ROOM`.
|
||
- `START_ROOM=1 / COL 3 / ROW 0` — жёстко зашитый тестовый старт; перевести
|
||
на `pop_level_start_*` (задача L1-START в [`TASKS.md`](TASKS.md)).
|