/* * 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 /* Загрузить уровень из файла в 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); /* ---- Номер уровня и потабличные различия (levels_plan.md §1) -------- */ /* Порт current_level (seg000 load_lev_spr: current_level = next_level = * level). Уровень 1..15; 0 — демо-уровень, в скоуп не входит. Читают * потабличные функции ниже, стражи (HP/тип) и стартовая логика. */ extern uint8_t pop_current_level; /* Загрузить уровень НОМЕРОМ: освободить страницу прошлого, взять * `LEVELS\res20NN.bin` (fallback `a:\res20NN.bin`) и выставить * pop_current_level. 0 — OK, -1 — файла нет / не влез (тогда * pop_current_level и страница НЕ тронуты — играем дальше на старом). * Порт связки load_lev_spr + load_level (seg000:1098/1169). */ int pop_level_load_num(uint8_t n); /* tbl_entry_pose (data.h:848): 1 — падение внутрь (ур. 1), 2 — вбегание * (ур. 13), 0 — разворот на месте. Индекс — номер уровня. */ uint8_t pop_level_entry_pose(uint8_t n); /* tbl_guard_hp (data.h:846) — база HP стража на уровне (get_guard_hp, * seg002:0044: extrastrength[skill] + tbl_guard_hp[level]). */ uint8_t pop_level_guard_hp(uint8_t n); /* tbl_guard_type (data.h:844): 0 обычный, 1 толстый, 2 скелет, 3 визирь, * 4 тень, −1 — стражей на уровне НЕТ (уровни 14/15). */ int8_t pop_level_guard_type(uint8_t n); /* tbl_level_type (data.h:840): 0 = dungeon, 1 = palace. Пока читается * только для контроля — второй тайлсет это levels_plan.md §3. */ uint8_t pop_level_tileset(uint8_t n); /* Извлечь комнату 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[11] — [0..9] верхний ряд (row0) комнаты СНИЗУ, * [10] тайл (0,9) комнаты СНИЗУ-СЛЕВА («стена * вниз»); нет комнаты → стена. * 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); /* Записать тайл в ЖИВУЮ foretable уровня (порт curr_room_tiles[tp] = tile: * do_pickup / remove_loose / loose_land). Изменение персистентно — уровень * лежит в ОЗУ-странице, а не в ПЗУ, — то есть переживает выход из комнаты, * как в оригинале. Отменяется только pop_level_reset_tiles. */ void pop_level_set_tile(uint8_t room, uint8_t tilepos, uint8_t tile); /* Рестарт уровня: вернуть ВСЕ тайлы в исходное (порт load_level, который * play_level зовёт на каждой итерации — в т.ч. после смерти Кида). */ void pop_level_reset_tiles(void); /* Рестарт уровня: вернуть ВСЕХ стражей (тот же load_level + pos_guards). * Убитый страж после respawn снова жив — как в оригинале. */ void pop_level_reset_guards(void); /* Батч-доступ к странице уровня (один 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