Доска: анализ уровней 9-11, задача L9-INVERT (зелье переворота)

Уровни 10 и 11 не приносят ни новых тайлов, ни спецсобытий (зелья только
heal / +max HP).  Уровень 9 — зелья типа 4 (переворот) в комнатах 7 и 10.
Записан разбор механики оригинала и разбор цены переворота для наших двух
раскладок спрайтов (row-major бесплатно, column-major требует копий).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 15:35:29 +03:00
parent 361c9d9f78
commit 6a392f5403
+49
View File
@@ -47,6 +47,55 @@
чомпера комнаты 4, а стражи там сильнее прежних (комната 5 — skill **7**, чомпера комнаты 4, а стражи там сильнее прежних (комната 5 — skill **7**,
это максимум из встречавшихся; 12/22/24 — skill 2/3/3). это максимум из встречавшихся; 12/22/24 — skill 2/3/3).
<a id="l9-invert"></a>
### L9-INVERT. Зелье ПЕРЕВОРОТА (уровень 9, комнаты 7 и 10)
Единственное новое на уровнях 9-11: зелья типа 4 на `(1,7)` комнаты 7 и
`(0,4)` комнаты 10 (сверено по `res2009.bin`). Уровни 10 и 11 не приносят ни
тайлов, ни спецсобытий — только дворцовый тайлсет (есть) и стражи skill 3-4.
Механика оригинала (seg000:15E9 `toggle_upside`, seg006:1886):
`upside_down = ~upside_down`, снимается смертью Кида (seg000:1224, при
`alive >= 0`) и стартом уровня (seg003:38/188); второе зелье переворачивает
обратно. Управление НЕ инвертируется. Переворот у оригинала — чисто вывод:
`flip_screen(offscreen)` перед копированием прямоугольников на экран и обратно
после (seg000:939/946); полоса HP рисуется прямо на экран (y = 194) и НЕ
переворачивается.
**Приём оригинала нам не подходит:** мы рисуем инкрементально прямо в
видеостраницу (heal + спрайты), готового offscreen-кадра нет, и «перевернуть
буфер на вывод» означало бы полный кадровый блит 61 440 Б. Значит
переворачиваем НА ОТРИСОВКЕ: `y' = POP_YOFF + POP_PLAYFIELD_H - (y - POP_YOFF) - h`
плюс вертикальное зеркало самого спрайта.
Зеркало по вертикали стоит по-разному в зависимости от раскладки спрайта:
- **row-major** (весь слой фона: тайлы, кладка, факелы, зелья, обломки,
двери) — бесплатно: внешний цикл идёт по строкам источника снизу вверх, сама
строка копируется вперёд. В libbgi такого варианта СЕЙЧАС НЕТ (флип есть
только у `gfx_blit_cols*`, и он горизонтальный) — нужна пара
`gfx_blit*_vflip`;
- **column-major** (Кид, стражи, мышь, меч — 34 атласа, 228 563 Б) — реверс
ВНУТРИ колонки, а accel копирует блок только вперёд. Нужны перевёрнутые
копии в отдельных EMM-страницах (реверс через стек `pop`/`push`, ~10 тактов
на байт).
**Когда делать копии — решать при реализации,** варианты в порядке
предпочтения:
1. **ленивый постраничный кэш**: страница атласа (8 кадров, 3-10 КБ)
переворачивается при первом обращении в перевёрнутом режиме — ~0.2-0.4
растрового кадра на страницу, размазано по времени; реально нужны 5-10
страниц из 34, и если зелье не выпито, не тратится ничего;
2. на входе в уровень, где в данных есть зелье типа 4 (скан `bg` уровня) —
вся пачка разом, ~5-6 млн тактов ≈ 0.3 с, пауза прячется в загрузку;
3. офлайн в `pop_pack_kid.py`/`pop_pack_guard.py` — рантайм ноль, но +228 КБ
на диске и +34 страницы всегда, а на дискете это заметная загрузка.
Не забыть при реализации: зеркалить надо и heal-прямоугольники, и футпринт
fore-слоя, и клип (`clip_char`), и брызги; полоса HP и лейбл комнаты остаются
как есть (они вне поля 192).
<a id="mem-cold2"></a> <a id="mem-cold2"></a>
### MEM-COLD2. Второй шаг разгрузки резидента ### MEM-COLD2. Второй шаг разгрузки резидента