Files
Sprinter-SDCC/applications/PoP/roomtest/pop_level.h
T
snark13 b22cee3456 PoP roomtest: убитый страж остаётся мёртвым; меч только по подбору или читу S
Смерть стража теперь персистентна между входами в комнату — по механизму
оригинала, а не отдельной таблицей «убит/не убит».  В SDLPoP массивы
level.guards_* лежат в ОЗУ и движок их ПЕРЕПИСЫВАЕТ: leave_guard (seg002:02F5)
кладёт туда позицию/направление/мастерство, а у МЁРТВОГО ещё и curr_seq;
enter_guard, увидев непустой seq_hi, поднимает стража прямо в этой
последовательности и по кадру смерти (185/177/178) ставит alive = 1.

У нас уровень лежит в EMM-странице только на чтение, поэтому в W2 добавлена
живая копия — 6 байт на комнату (tile/dir/x/skill/seq_lo/seq_hi):
- pop_guard_leave() в начале enter_room запоминает уходящего стража;
- pop_guard_enter поднимает труп сохранённой последовательностью И
  сохранённой X (pos_guards пересчитывает её из колонки только при загрузке
  уровня, дальше ею владеет leave_guard — иначе тело прыгает в центр тайла).

ГРАБЛИ: guards_seq_lo/hi в ФАЙЛЕ уровня не используются, там 0xFF во всех
комнатах (оригинал чистит их в reset_level_unused_fields).  Прочитав их как
есть, я скормил интерпретатору curr_seq = 0xFFFF, и приложение зависало —
бордюр оставался синим, цикл не доходил до vsync.  Живая копия стартует
нулями: 0 = «поднимать стандартной стойкой».

Меч Киду больше не выдаётся автоматически: DEBUG_SWORD_ROOM убран, вместо
него чит S (выдать меч).  Штатный путь — подобрать с пола.

Проверено в MAME: чит K убивает стража, уход из комнаты 3 и возврат —
тело на месте, страж не воскресает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 21:33:21 +03:00

98 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_level.h — данные уровня PoP из сырого файла res200N.bin (Фаза L1).
*
* Уровень загружается ОДИН раз в отдельную EMM-страницу (как атласы:
* данные с offset 0x100, ISR-стаб в первых байтах — страница безопасна
* для маппинга в W0). Файл — сырой blueprnt DAT 1.0 (2305 байт, БЕЗ
* checksum-байта; Table 6 спецификации POP-DAT):
* foretable(fg) @0 backtable(bg) @720 door I/II @1440/1696
* links @1952 (24×{L,R,U,D}) start @2112 ...
* Тайл-код = байт fg & 0x1F (верхние биты — модификатор, пока не нужны);
* bg передаётся как есть. См. applications/PoP/docs/POP-DAT-* .
*
* Рабочая копия ТЕКУЩЕЙ комнаты живёт в обычной памяти (W2) у приложения
* (мутабельная — loose→empty); pop_room_load извлекает её из страницы +
* тонкие срезы соседей для кромок (правый столбец left-комнаты, верхний
* ряд down-комнаты). Страница маппится в W0 только на время извлечения.
*/
#ifndef POP_LEVEL_H
#define POP_LEVEL_H
#include <stdint.h>
/* Загрузить уровень из файла в EMM-страницу. 0 — OK, -1 — ошибка
* (open/alloc/размер). Звать ПОСЛЕ первого atlas_load (pop_bg_load) —
* он снимает страницу ядра DSS для W0-unmap. */
int pop_level_load(const char *path);
void pop_level_free(void);
/* Извлечь комнату room (1..24) в массивы приложения (W2):
* fg[30], bg[30] — тайлы комнаты (fg маскирован &0x1F, bg raw);
* lcol_fg[6], lcol_bg[3] — [0..2] правый столбец (col9) комнаты СЛЕВА
* (кромка col0), [3..5] предпоследний (col8) —
* для коллизии на колонке −2 (Kid стоит В шве);
* rcol_fg[6] симметрично (col0 / col1);
* нет комнаты → стена/0;
* below_fg[10] — верхний ряд (row0) комнаты СНИЗУ («стена
* вниз»); нет комнаты → стена.
* 0 — OK, -1 — уровень не загружен / room вне диапазона. */
int pop_room_load(uint8_t room, uint8_t *fg, uint8_t *bg,
uint8_t *lcol_fg, uint8_t *lcol_bg,
uint8_t *rcol_fg, uint8_t *rcol_bg, uint8_t *below_fg);
/* Связь комнаты по стороне (0=L,1=R,2=U,3=D) → номер соседней (1..24) или
* 0, если стороны нет. Для переходов между комнатами (L2/L3). */
uint8_t pop_room_link(uint8_t room, uint8_t side);
/* Тайл-код (fg & 0x1F) по комнате (1..24) и позиции tilepos (0..29,
* row*10+col); вне диапазона → 0 (empty). Для trob-диспетчера (pop_trob):
* тип анимируемого тайла в ЛЮБОЙ комнате, не только текущей. */
uint8_t pop_level_tile(uint8_t room, uint8_t tilepos);
/* Батч-доступ к странице уровня (один map/unmap окна 0 на много чтений).
* Между begin/end — только pop_level_tile_raw, без рисования. */
void pop_level_access_begin(void);
void pop_level_access_end(void);
uint8_t pop_level_tile_raw(uint8_t room, uint8_t tilepos);
/* Скопировать backtable (модификаторы) комнаты room в out[30]. Исходное
* состояние per-room modifier (openness ворот, состояние пик и т.п.) для
* ленивой инициализации room_modif в pop_trob. Вне диапазона → нули. */
void pop_level_room_bg(uint8_t room, uint8_t *out30);
/* Таблицы связей дверей (LINKLOC@1440 / LINKMAP@1696, по 256 Б). Копируются
* в W2-RAM при загрузке (LINKMAP мутабельна — таймеры кнопок). i — индекс
* цепочки (модификатор кнопки). Декод — в pop_trob (get_doorlink_*). */
uint8_t pop_doorlink1(uint8_t i);
uint8_t pop_doorlink2(uint8_t i);
void pop_doorlink2_set(uint8_t i, uint8_t v);
/* Ряд приземления падающего loose-куска в колонке col комнаты room: первый
* НЕ-пустой тайл сверху вниз; возвращает его ряд, если это floor (→ debris),
* иначе -1 (пролетел/крушение о стену). */
int8_t pop_room_col_landing(uint8_t room, uint8_t col);
/* Стартовая позиция уровня (блок @2112): комната / поза / направление. */
/* Страж комнаты: 1 = есть (заполнит tile/dir/color/skill), 0 = нет.
* Порт enter_guard (seg002:0112). */
/* leave_guard (seg002:02F5): запомнить состояние стража комнаты в ЖИВОЙ
* копии массивов уровня. dead != 0 — сохранить и последовательность, тогда
* при возврате в комнату страж поднимется трупом там же, где лёг.
* tile == 30 (или больше) — «стража в комнате больше нет». */
void pop_guard_state_save(uint8_t room, uint8_t tile, int8_t dir, uint8_t x,
uint8_t skill, uint16_t seq, uint8_t dead);
/* Последовательность запомненного стража (0 — поднимать стандартной
* стойкой, как у живого). */
uint16_t pop_guard_state_seq(uint8_t room);
uint8_t pop_guard_state_x(uint8_t room);
uint8_t pop_level_guard(uint8_t room, uint8_t *tile, int8_t *dir,
uint8_t *color, uint8_t *skill);
uint8_t pop_level_start_room(void);
uint8_t pop_level_start_pos(void);
int8_t pop_level_start_dir(void);
#endif