Skip to main content

Dungeon Master Tools — extract data from Dungeon Master / Chaos Strikes Back files (GRAPHICS.DAT, DUNGEON.DAT)

Project description

Dungeon Master Tools

Dungeon Master Tools is a collection of Tools in Python for the Amiga/PC/Atari ST Game, packaged as the importable dmcsb package (published on PyPI as dmcsbpip install dmcsb):

  • dmcsb.dungeon (DungeonFile) - loads and extracts the data in DUNGEON.DAT (Big Endian only for now)
  • dmcsb.graphics (GraphicsFile) - library for GRAPHICS.DAT handling

Installation

pip install dmcsb              # optional: "dmcsb[pil]" enables GraphicsFile.to_pil()

or, from a source checkout, pip install -e . (or just run from the repo root — the package is importable without installing).

Command line

Installing puts a dmcsb command on your PATH (equivalently python3 -m dmcsb):

dmcsb dump GRAPHICS.DAT [out_dir]      # -> PNG/WAV/TXT/.bin + an HTML contact sheet
dmcsb dungeon DUNGEON.DAT --level 1    # print one dungeon level (map, things, champions)
dmcsb uncompress DUNGEON.DAT [out.dat] # write a decompressed copy (no parsing)

dmcsb dump also takes --map / --palettes / --zones to override the bundled tables. The same three operations are available as standalone scripts in examples/ (thin wrappers over the library, runnable from a source checkout).

After loading a DungeonFile you can access all data from the object:

  • hdr -> header dict
  • maps[] / mapsinfo[str(level)] -> map descriptors (in file order / keyed by Level)
  • thinglist[] -> 16 entries in storage order (None for unused types)
  • things[name] -> decoded list by type: "Door", "Creature", "Weapon", "Sensor", ... (whole dungeon)
  • things_on_level(level) -> things located on one level, grouped by type
  • located_things(level) -> things on a level with their map (x, y) + sub-square cell (dir N/E/S/W)
  • item_name(category, type) -> human item name (Weapon/Armour/Potion/Junk/Container/Scroll)
  • text(textstring) / texts() -> decoded message strings (signs, ...)
  • scroll_text(scroll) -> the text a scroll points at (via its TextStringThingIndex)
  • champions() -> all champion sheets in the dungeon (name, title, gender, stats, skills); champions_on_level(level) -> only those whose sheet sits on that level (e.g. the Hall of Champions), with x,y; champion(offset) decodes one
  • tile_data -> raw tile bytes; tile_grid(level) -> 2-D tile array
  • text_data -> raw encoded dungeon text
  • chksum -> trailing checksum word, or None if the file has none

for more info see: http://dmweb.free.fr/?q=node/217

The library is silent (no prints); load from a path, bytes, or an open file. Little-endian (PC) files are not supported yet and raise NotImplementedError.

from dmcsb import open_dungeon

d = open_dungeon("DUNGEON.DAT")          # or open_dungeon(data=raw_bytes)
print(d.hdr['OrnamentRandomSeed'])
print(d.mapsinfo['1']['Difficulty'])
for door in d.things['Door']:                 # every door in the dungeon
    print(door['Type'], door['OrnamentOrdinal'])

for name, items in d.things_on_level(1).items():   # only level 1, grouped by type
    print(name, len(items))

for i, visible, msg in d.texts():             # decoded scroll/sign messages
    print(i, repr(msg))
for c in d.champions():                       # initial party champions
    print(c['name'], c['title'], c['Health'], c['Strength'])

Text uses DM's 5-bit packing (3 codes per 16-bit word). The decoder handles letters, spaces, ., line breaks and the standard DM/CSB escape tables (so e.g. THE / YOU expand inside titles and messages); pass an escape= callback to override them. It targets the normal/"new font" text used by the Amiga versions. Champion statistics/skills are stored as hex nibbles and decoded to integers (Stamina is kept as the raw value, i.e. 10x the number shown in-game).


When you run the demo, it prints one dungeon level:

python3 examples/demo_dungeon.py [level] [DUNGEON.DAT]

level defaults to 1; the optional second argument is the path to the file (defaults to DUNGEON.DAT). For example python3 examples/demo_dungeon.py 5 shows Level 5. With no arguments, Level 1 is shown:

Map at Level 1 ----------------
  RawMapDataByteOffset: 376
  OffsetMapX: 0, OffsetMapY: 14
  Width: 31, Height: 31, Level: 1
  RandomFloorOrnamentCount: 2
  FloorOrnamentCount: 3
  RandomWallOrnamentCount: 3
  WallOrnamentCount: 12
  Difficulty: 1
  CreatureTypeCount: 2
  DoorOrnamentCount: 3
  DoorSet1: 1, DoorSet0: 0
  WallSet: 0, FloorSet: 0

Creatures/Wall/Floor/Doors used ----------------
Creature: 6, 10, 
WallOrnate: 33, 4, 35, 51, 15, 1, 49, 38, 46, 45, 44, 5, 
FloorOrnate: 2, 8, 1, 
DoorDeco: 4, 8, 3, 

MapData ----------------

  1 4 1 1 1 1 1 1   1 1 4 1 1   1 1 1         1     1 1 4 1   1 1 
  1     3     4     1       1 1 1 1 1 4 4 1   1 1 1 1     1   1 5 
  1 1         1   1 1 1 1       1 1 1     1   1 1       1 1 1     
    4         1   1 1   1   1 1           1   1   1 1 1     1 5   
    1                   1   1 1 1 1 1 1 1 5   4   1   1 4 1 1     
  1 1   1 4 1 4 1 1   1 1   1   1 1 1 1     1 1   2               
  1     1             1           1       1 1     1 1           1 
  1 1 1 1   1 1 1     1   1 1 1   1 1 1 1 1 1       1   1 1 1 1 1 
  1     1   1   2     1   1 1 1               1 1 1 1   1   1   4 
    1 1 1   4   1   1 1   1         1 1 1 1 1 1         1   1   1 
    1       1       1   1 1   1 1   1         1 1 1 1 1 1   1   1 
  1 1 1 1 1 1   1   1   1 1 1 1 1   1   1   1       4       1     
  1             1 1 1   4               1   1 1 1   1 1 1   1 1   
  1 1 1 4 1 1 4 1       1         1 1 1 1 1 1   1 1     1         
    1                 1 1   1 1   1 1 1 1 1       1 1   1 1 1 1 1 
    1 1 1 1 4 1 1 1 1 1     2     1 1 1 1 1   1     1       1   1 
      1 1 1               1 5     1 1 1 1 1   1 1 1 1 1 1 1 1   1 
              1 1 1 1     1       1 1 1 1 1         1 1 1 1 1   1 
  1 1 1 1 1 1 1     1     1   1       4       1                   
  1 1 1 1 1 1 1   1 1     1   1 1 1 1 1 1 1 1 1         1 1 1 1   
  1   1 1 1 1 1   1   1 1 1           4           1 1 1 1 1 1 1 5 
  1 1 1         1 1   1 1 1   1 1 1   5 1 1 1 4 1 1 1 1 1 1     1 
    1           4     1       1   1 1 1   1                     1 
    1 1 1   1 1 1 1   1 1 1 1 1                     1   1 1 1 1 1 
        1   1 1 1 1                     1 1 1   1 1 1   1   1     
        1       1 1 1 1 1   1 1 1       1   1   1   1 1 1   1 1   
        1     3   1 1   1 1 1   1 1 4 1 1   1   1                 
        1     1     1 1   1       4         1   1 1 1 1 1 1 4 1   
        1     1     1 1   1 1 1   1       1 1 1     1         1   
        1     1 1 1       1 1 6           1 1 1 1 1 1 5 1 1 1 1   
      1 1 1 1     1       1   1 1         1 1 1                   
      1 1   1 1 1 1           1 1                   

The demo also prints every Thing on the level (grouped by type) after the map.

To just decompress a compressed dungeon to a raw file (no parsing):

python3 examples/uncompress_dungeon.py DUNGEON.DAT [output.dat]

The output defaults to <input>.uncompressed.

dmcsb package — GRAPHICS.DAT library

The graphics handling lives in the installable dmcsb package. It loads the Amiga 3.x GRAPHICS.DAT into memory and decodes IMG1 images, the FNT1 font, SND2 sounds, TXT2 text and the LAY1 screen layout. The data tables (image map, palettes, zone names) are bundled inside the package and applied automatically — you can override them by passing your own paths.

Use it in your own project (after pip install dmcsb — see Installation):

from dmcsb import open_graphics

g = open_graphics("GRAPHICS.DAT")   # bundled map + palettes auto-applied
# overrides: open_graphics("GRAPHICS.DAT", map="my_map.txt", palettes="my_pal.txt")
# from memory: open_graphics(data=open("GRAPHICS.DAT","rb").read())

len(g)                  # number of items
list(g)                 # [(index, type_name), ...]
g.info(i)               # {type, name, palette, sizes, compressed}

g.image(i)              # IMG1/FNT1 -> (w, h, rgb_bytes)
g.image_indexed(i)      # -> (w, h, palette_indices) for your own coloring
g.to_pil(i)             # -> PIL.Image (needs Pillow)
g.font()                # finds FNT1 -> (w, h, rgb_bytes)
g.sound(i)              # SND2 -> signed 8-bit PCM
g.text(i)               # TXT2 -> [str]
g.layout()              # LAY1 -> {'signature','ranges','records'} (relative coords)
g.first_of_type("LAY1") /  g.indices_of_type("SND")

To dump everything into a folder of PNG/WAV/TXT plus an HTML contact sheet, see the example app (it consumes the library):

python3 examples/dump_graphics.py GRAPHICS.DAT gfx/
# optional overrides: ... gfx/ graphics_map.txt palettes.txt zones.txt

Many Thanks to ChristopheF & Sphenx

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dmcsb-0.1.0.tar.gz (55.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dmcsb-0.1.0-py3-none-any.whl (47.3 kB view details)

Uploaded Python 3

File details

Details for the file dmcsb-0.1.0.tar.gz.

File metadata

  • Download URL: dmcsb-0.1.0.tar.gz
  • Upload date:
  • Size: 55.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for dmcsb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f5c2836023955888808fef9249d7a877d20b3dda360be6297030057813a56bc3
MD5 23008cf964a1f58bcacbaf834ea61a1f
BLAKE2b-256 443addbc325017d1ad1f2a6e807b6cc966c332376b6a3925716a068fd17730a0

See more details on using hashes here.

File details

Details for the file dmcsb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dmcsb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 47.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for dmcsb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 323a4858b27895800565b4a3ceeef520ab2c793f371b6aa1c094909d10e15e39
MD5 44011162b4745dc52995eea0f9d45b2e
BLAKE2b-256 97ce73b304b3b6b576ec0b2497b9ecc8cd26464614c540aaf1dee2c75e26f75f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page