#!/usr/bin/env python3 """ extract_room.py — вырезает ОДНУ комнату (foretable+backtable, 30+30 байт) + стартовую позицию уровня (start_room/start_pos/start_dir, 3 байта) из level-ресурса формата "res20NN.bin" (SDLPoP data/LEVELS/). Layout подтверждён структурным разбором: файл начинается СРАЗУ с foretable[720] (24 комнаты * 30 тайлов), затем backtable[720] — без заголовка (applications/PoP/docs/POP-DAT-FormatSpecifications.pdf §3.4 + декод байт 2026-07-15). Тайл tileOffset 0-9 = верхний ряд, 10-19 = средний, 20-29 = нижний (см. level.h level_tile()). Смещение start_room/start_pos/start_dir НЕ сразу после links (как предполагалось изначально) — сверено со структурой level_type в applications/PoP/SDLPoP/src/types.h (маленький структурный факт, порядок полей, не объём кода): fg[720]+bg[720]+doorlinks1[256]+ doorlinks2[256]+roomlinks[96]+used_rooms[1]+roomxs[24]+roomys[24]+ fill_1[15] = 2112 -> start_room(u8), start_pos(u8), start_dir(s8) (2026-07-16, подтверждено на res2001.bin: start_room=1, start_pos=0, start_dir=-1 — согласуется с links[room1] и решулось эмпирически через таблицу room-links, которая идеально легла на смещение 1952). Использование: extract_room.py LEVEL.bin ROOM OUT.dat Выход: OUT.dat — 63 байта (fore[30]+back[30]+start_room+start_pos+ start_dir), формат level_load_room() (room.c). ROOM — 1-based (как в файле/level.h); start_* — общеуровневые (не зависят от ROOM). """ import sys FORETABLE_OFF = 0 BACKTABLE_OFF = 720 ROOM_TILES = 30 START_OFF = 720 + 720 + 256 + 256 + 96 + 1 + 24 + 24 + 15 # 2112 def main(): if len(sys.argv) != 4: sys.exit(__doc__.strip()) src, room_s, out = sys.argv[1], sys.argv[2], sys.argv[3] room = int(room_s) data = open(src, "rb").read() if len(data) < START_OFF + 3: sys.exit(f"extract_room: {src}: {len(data)} Б — меньше ожидаемых " f"{START_OFF + 3} (foretable+backtable+...+start_position)") base = (room - 1) * ROOM_TILES fore = data[FORETABLE_OFF + base:FORETABLE_OFF + base + ROOM_TILES] back = data[BACKTABLE_OFF + base:BACKTABLE_OFF + base + ROOM_TILES] start = data[START_OFF:START_OFF + 3] open(out, "wb").write(fore + back + start) print(f"extract_room: комната {room} из {src} -> {out} " f"({len(fore)}+{len(back)}+{len(start)} Б); " f"start_room={start[0]} start_pos={start[1]} " f"start_dir={start[2] if start[2] < 128 else start[2] - 256}") if __name__ == "__main__": main()