# 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-CEIL-1/2/3, BUG-OCCL-1 (была починена кодом ещё в июле, список просто отстал — чем именно закрыта каждая, расписано в [`bug_closed.md`](bug_closed.md)). **Открытых багов нет.** Осталось только незакрытое по оптимизации и незаконченная ревизия комнат: | ID | что | тип | |----|-----|-----| | [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | | [T-2](#t-2) | Кид перерисовывается в покое | оптимизация | | [обход 24 комнат](#обход-всех-24-комнат-уровня-1) | таблица заполнена на 5 строк из 24 | ревизия | --- # Оптимизация отрисовки (записано 2026-07-29) Не баги — план работ. Оба пункта про одно: у оригинала пометка тайла к перерисовке стоит копейки (бит в таблице, которая всё равно чистится каждый кадр), а у нас каждая такая пометка превращается в реальный heal (копию из ОЗУ-копии акселератора) плюс блиты. Поэтому буквальный порт «перерисовываем безусловно» корректен, но дорог. ## 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, отдельно не окупается. ## 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`).