PoP roomtest: отладочный обход комнат (+/-) + TODO по редрою пик и idle-skip
ROOMNAV (одна строка #define в roomtest.c): '+'/'-' — следующая/предыдущая комната уровня ПО НОМЕРУ (1..24, с обёрткой), Kid ставится на первый пол, pop_trob_reset() возвращает пики/ворота в исходное. Нужен для обхода всех 24 комнат в поиске багов отрисовки, включая недостижимые обычным путём. Цена — 505 Б кода W1 (22816 -> 23321), они же вычитаются из кучи (4178 -> 3673 Б); W3 не тронут. Переводить приложение в huge ради этого не стали: смена модели памяти (банкованный W1 + трамплины) ради полукилобайта — плохой размен прямо перед прогоном комнат. Номер комнаты — ПОЛОСКАМИ в верхнем борте (слева десятки, справа единицы), а не outtextxy: текст тянет системный знакогенератор (_gfx_font_buf, 2 КБ статики) и сажает кучу до 576 Б. Цвет полосок 0x57, а не WHITE: палитра игровая, запись 15 в ней ЧЁРНАЯ (kid.pal 0x0F = 0,0,0) — из-за этого закомментированный ранее лейбл был бы невидим в любом случае. bug_list.md: раздел TODO (T-1 редрой пик по причине, T-2 idle-skip) + пустая таблица на 24 комнаты под результаты обхода. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -344,3 +344,91 @@ roomtest.c (enter_room/drawn_room/главный цикл), pop_kid.c (кадр
|
|||||||
Реализовано на 2026-07-22: S1 (kid_room + render_dx) + pop_leave_timer.
|
Реализовано на 2026-07-22: S1 (kid_room + render_dx) + pop_leave_timer.
|
||||||
S2/S3 отложены — баг закрыт odd-pixel поправкой (см. КОРЕНЬ выше).
|
S2/S3 отложены — баг закрыт odd-pixel поправкой (см. КОРЕНЬ выше).
|
||||||
Память: [[pop_seam_room_model]], [[sdlpop_odd_pixel_char_x]].
|
Память: [[pop_seam_room_model]], [[sdlpop_odd_pixel_char_x]].
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# TODO: оптимизация отрисовки (записано 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. 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-1 idle-skip не требует ничего дополнительного для
|
||||||
|
пик: раз Кида не перерисовываем — heal'а нет — стирать пики нечем — редрой
|
||||||
|
не нужен, он отпадает сам.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Обход всех 24 комнат уровня 1 — поиск багов отрисовки
|
||||||
|
|
||||||
|
Инструмент: `#define ROOMNAV` в `roomtest.c` — `+`/`-` (цифровой блок либо
|
||||||
|
`=`/`-` основного ряда) переключают комнату по номеру (1..24, с обёрткой),
|
||||||
|
Kid ставится на первый пол, `pop_trob_reset()` возвращает пики/ворота в
|
||||||
|
исходное. Номер комнаты — полосками в верхнем борте: слева десятки, справа
|
||||||
|
единицы (`||` `||||` = 24). Убирается закомментированием одной строки.
|
||||||
|
|
||||||
|
| комната | статус | что не так |
|
||||||
|
|---------|--------|------------|
|
||||||
|
| 1 | | |
|
||||||
|
| 2 | | |
|
||||||
|
| 3 | | |
|
||||||
|
| 4 | | |
|
||||||
|
| 5 | | |
|
||||||
|
| 6 | | |
|
||||||
|
| 7 | | |
|
||||||
|
| 8 | | |
|
||||||
|
| 9 | | |
|
||||||
|
| 10 | | |
|
||||||
|
| 11 | | |
|
||||||
|
| 12 | | |
|
||||||
|
| 13 | | |
|
||||||
|
| 14 | | |
|
||||||
|
| 15 | | |
|
||||||
|
| 16 | | |
|
||||||
|
| 17 | | |
|
||||||
|
| 18 | | |
|
||||||
|
| 19 | | |
|
||||||
|
| 20 | | |
|
||||||
|
| 21 | | |
|
||||||
|
| 22 | | |
|
||||||
|
| 23 | | |
|
||||||
|
| 24 | | |
|
||||||
|
|||||||
@@ -26,12 +26,19 @@ __sfr __at (0xFE) io_border;
|
|||||||
/* Тест-старт для отладки пик (Фаза S): комната 6 = тестовая (пики в col3/col4
|
/* Тест-старт для отладки пик (Фаза S): комната 6 = тестовая (пики в col3/col4
|
||||||
* row2, шахта col3). Kid на полу row0 col1, идёт вправо → падает в шахту →
|
* row2, шахта col3). Kid на полу row0 col1, идёт вправо → падает в шахту →
|
||||||
* пики. TODO: вернуть на pop_level_start_room (комната 1) после отладки. */
|
* пики. TODO: вернуть на pop_level_start_room (комната 1) после отладки. */
|
||||||
#define START_ROOM 14 /* ОТЛАДКА: пики (2,7)/(2,8) — редрой каждый кадр */
|
#define START_ROOM 1 /* обход комнат: старт с 1-й, дальше +/- (ROOMNAV) */
|
||||||
#define START_COL 9
|
#define START_COL 3
|
||||||
#define START_ROW 2
|
#define START_ROW 0
|
||||||
#define RESPAWN_DELAY 400 /* авто-респавн (фолбэк), если не нажали ↑ */
|
#define RESPAWN_DELAY 400 /* авто-респавн (фолбэк), если не нажали ↑ */
|
||||||
#define RESPAWN_SETTLE 20 /* тиков до приёма ↑ (труп успел лечь) */
|
#define RESPAWN_SETTLE 20 /* тиков до приёма ↑ (труп успел лечь) */
|
||||||
|
|
||||||
|
/* ОТЛАДОЧНЫЙ ОБХОД КОМНАТ: '+'/'-' (цифровой блок либо '='/'-' основного
|
||||||
|
* ряда) — следующая/предыдущая комната уровня ПО НОМЕРУ (1..24, с обёрткой),
|
||||||
|
* Kid ставится на первый попавшийся пол. Нужен, чтобы пройти все комнаты и
|
||||||
|
* собрать список багов отрисовки, включая недостижимые обычным путём.
|
||||||
|
* Убирается закомментированием ОДНОЙ строки ниже. */
|
||||||
|
#define ROOMNAV 1
|
||||||
|
|
||||||
/* Рабочая копия ТЕКУЩЕЙ комнаты (W2, мутабельная: loose→empty) + срезы
|
/* Рабочая копия ТЕКУЩЕЙ комнаты (W2, мутабельная: loose→empty) + срезы
|
||||||
* соседей для кромок. Заполняются pop_room_load из уровня. File-scope,
|
* соседей для кромок. Заполняются pop_room_load из уровня. File-scope,
|
||||||
* чтобы enter_room переключал комнату без длинного списка параметров. */
|
* чтобы enter_room переключал комнату без длинного списка параметров. */
|
||||||
@@ -172,6 +179,9 @@ int main(void)
|
|||||||
* отладки багов рисования (edge по sp_prev, чтоб не дёргать). */
|
* отладки багов рисования (edge по sp_prev, чтоб не дёргать). */
|
||||||
uint8_t front = 0, back, dbuf = 1, sp_prev = 0, frozen = 0;
|
uint8_t front = 0, back, dbuf = 1, sp_prev = 0, frozen = 0;
|
||||||
uint16_t dead_frames = 0;
|
uint16_t dead_frames = 0;
|
||||||
|
#ifdef ROOMNAV
|
||||||
|
uint8_t nav_prev = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (pop_bg_load() != 0) { /* атласы — ДО initgraph (снимает DSS-страницу W0) */
|
if (pop_bg_load() != 0) { /* атласы — ДО initgraph (снимает DSS-страницу W0) */
|
||||||
puts("pop_bg_load failed");
|
puts("pop_bg_load failed");
|
||||||
@@ -246,6 +256,37 @@ int main(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ROOMNAV
|
||||||
|
/* Обход комнат по номеру: '+' (0x79 numpad / 0x55 '=') — вперёд,
|
||||||
|
* '-' (0x7B / 0x4E) — назад. Edge по nav_prev: одно нажатие = одна
|
||||||
|
* комната. pop_trob_reset ДО enter_room — каждая комната смотрится в
|
||||||
|
* исходном состоянии (пики убраны, ворота закрыты). */
|
||||||
|
{
|
||||||
|
uint8_t nav = (uint8_t)((kbd_raw_down(0x79) || kbd_raw_down(0x55)) |
|
||||||
|
((kbd_raw_down(0x7B) || kbd_raw_down(0x4E)) << 1));
|
||||||
|
if (nav && !nav_prev) {
|
||||||
|
uint8_t r = cur_room, i, c, pos = 20, any = 0xFF;
|
||||||
|
r = (nav & 1) ? (uint8_t)(r == 24 ? 1 : r + 1)
|
||||||
|
: (uint8_t)(r == 1 ? 24 : r - 1);
|
||||||
|
pop_trob_reset();
|
||||||
|
enter_room(r);
|
||||||
|
/* Предпочитаем обычный пол; иначе — любой tile_is_floor
|
||||||
|
* (seg001): всё, кроме пустоты/стены/верхов колонны и двери. */
|
||||||
|
for (i = 0; i < 30; i++) {
|
||||||
|
c = (uint8_t)(room_fg[i] & 0x1F);
|
||||||
|
if (c == 1) { any = i; break; }
|
||||||
|
if (any == 0xFF && c && c != 9 && c != 12 && c != 20 &&
|
||||||
|
!(c >= 26 && c <= 29)) any = i;
|
||||||
|
}
|
||||||
|
if (any != 0xFF) pos = any;
|
||||||
|
kid_init(SEQ_STAND, (int8_t)(pos % 10), (int8_t)(pos / 10), 0);
|
||||||
|
pop_kid_hp_reset();
|
||||||
|
dead_frames = 0;
|
||||||
|
}
|
||||||
|
nav_prev = nav;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Рисуем в СКРЫТУЮ страницу (при dbuf); в однобуфере — в 0. */
|
/* Рисуем в СКРЫТУЮ страницу (при dbuf); в однобуфере — в 0. */
|
||||||
back = dbuf ? (uint8_t)(front ^ 1) : 0;
|
back = dbuf ? (uint8_t)(front ^ 1) : 0;
|
||||||
gfx_set_draw_page(back);
|
gfx_set_draw_page(back);
|
||||||
@@ -360,18 +401,28 @@ int main(void)
|
|||||||
/* Отладка: номер отрисованной комнаты в верхнем борте — рисуем ТОЛЬКО
|
/* Отладка: номер отрисованной комнаты в верхнем борте — рисуем ТОЛЬКО
|
||||||
* при её смене (change-driven, счётчик 2 = обе страницы дабл-буфера),
|
* при её смене (change-driven, счётчик 2 = обе страницы дабл-буфера),
|
||||||
* а не каждый кадр (обход sdcc_z80_cmp_store_a_bug: сначала сохранить). */
|
* а не каждый кадр (обход sdcc_z80_cmp_store_a_bug: сначала сохранить). */
|
||||||
|
#ifdef ROOMNAV
|
||||||
{
|
{
|
||||||
uint8_t r = cur_room;
|
uint8_t r = cur_room, prev = room_label_sig;
|
||||||
// if (r != room_label_sig) { room_label_sig = r; room_label_redraw = 2; }
|
room_label_sig = r; /* СНАЧАЛА сохранить (sdcc_z80_cmp_store_a_bug) */
|
||||||
// if (room_label_redraw) {
|
if (r != prev) room_label_redraw = 2;
|
||||||
// char roomLabel[] = "Room ##";
|
if (room_label_redraw) {
|
||||||
// roomLabel[5] = (char)(r / 10 + '0');
|
/* Номер ПАЛОЧКАМИ, а не outtextxy: текст тянет системный
|
||||||
// roomLabel[6] = (char)(r % 10 + '0');
|
* знакогенератор (_gfx_font_buf, 2 КБ статики в W2) и сажает
|
||||||
// setcolor(WHITE);
|
* кучу с 3867 до 576 Б. Слева десятки, справа единицы:
|
||||||
// outtextxy(100, 0, roomLabel);
|
* || |||| = 24. bar/setfillstyle уже используются. */
|
||||||
// room_label_redraw--;
|
uint8_t i;
|
||||||
// }
|
setfillstyle(SOLID_FILL, BLACK);
|
||||||
|
bar(100, 0, 175, 5);
|
||||||
|
/* 0x57, а НЕ WHITE: палитра игровая, запись 15 в ней чёрная
|
||||||
|
* (kid.pal: 0x0F = 0,0,0; чистый белый = 0x57). */
|
||||||
|
setfillstyle(SOLID_FILL, 0x57);
|
||||||
|
for (i = 0; i < (uint8_t)(r / 10); i++) bar(100 + i * 5, 0, 101 + i * 5, 5);
|
||||||
|
for (i = 0; i < (uint8_t)(r % 10); i++) bar(130 + i * 5, 0, 131 + i * 5, 5);
|
||||||
|
room_label_redraw--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
gfx_wait_vsync();
|
gfx_wait_vsync();
|
||||||
gfx_wait_vsync();
|
gfx_wait_vsync();
|
||||||
|
|||||||
Reference in New Issue
Block a user