/*
 * 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);

/* ---- Номер уровня и потабличные различия (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[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);

/* Записать тайл в ЖИВУЮ 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
