Perfect β Fallout Tactics then. π
In Fallout Tactics, .MIS files are mission/map files, basically containers for:
- Header info β version, map size, checksum.
- Tiles β terrain grid, elevation, blocking.
- Entities β units, items, containers, scenery, doors.
- Triggers β scripts/events, mission objectives.
- Strings β text (mission descriptions, dialogue references).
Theyβre usually stored in .bos archives (which are just renamed ZIP files), then extracted as .MIS. Inside the .MIS, many sections are zlib-compressed chunks.
-
Header
-
First few bytes give version + map dimensions.
-
Example structure:
struct MisHeader { uint32_t version; uint32_t width; uint32_t height; uint32_t unknown1; };
-
-
Chunked data
- Each chunk =
[chunkType: 4 bytes][length: 4 bytes][compressed: 1 byte][payload] - If
compressed == 1, decompress with zlib.
- Each chunk =
-
Chunk types (based on reverse-engineering docs and community tools like BosEdit)
TILEβ terrain & scenery placement.ENTYβ entity definitions (actors, items, etc.).TRIGβ triggers (mission scripts).STRGβ string tables.- Others like
PATH,ZONE, etc.
-
Entities/Triggers
- Binary blobs with references to prototypes (
.SPRsprites,.ENTentities). - Often require parsing nested structs (name, position, rotation, properties).
- Binary blobs with references to prototypes (
import struct, zlib
def parse_mis(path):
with open(path, "rb") as f:
data = f.read()
# Header: version, width, height, unknown
version, width, height, unk = struct.unpack("<IIII", data[:16])
pos = 16
chunks = []
while pos < len(data):
if pos + 9 > len(data): # safety
break
chunk_type = data[pos:pos+4].decode("ascii", errors="ignore")
length = struct.unpack("<I", data[pos+4:pos+8])[0]
compressed = data[pos+8]
pos += 9
raw_chunk = data[pos:pos+length]
pos += length
if compressed:
try:
raw_chunk = zlib.decompress(raw_chunk)
except Exception as e:
print(f"Failed to decompress {chunk_type}: {e}")
chunks.append({
"type": chunk_type,
"size": len(raw_chunk),
"data": raw_chunk
})
return {
"header": {"version": version, "mapSize": (width, height), "unknown": unk},
"chunks": chunks
}
mis = parse_mis("example.mis")
print(mis["header"])
for c in mis["chunks"]:
print(f"{c['type']} -> {c['size']} bytes")This will give you:
- A header with basic info.
- A list of chunks, each decompressed if necessary.
From there, you can go chunk-by-chunk and start defining binary layouts (struct.unpack) to fully parse things like entities or triggers.
π Do you want me to dig deeper and draft a full chunk format reference (so you can parse TILE, ENTY, TRIG properly), or should we keep it at a generic chunk dumper first so you can peek inside your .MIS files?