b22cee3456
Смерть стража теперь персистентна между входами в комнату — по механизму оригинала, а не отдельной таблицей «убит/не убит». В 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>
98 lines
6.3 KiB
C
98 lines
6.3 KiB
C
/*
|
||
* 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
|