mrxstudios

Dust Remastered

Reverse Engineering Dust: Game Locations and Map Layout

Dust: A Tale of the Wired West” is a game produced by Cyberflix in 1995. It is a game where the player has lots of conversations with colorful characters, collects inventory items and solves puzzles.

My goals is to better understand the intricacies of how games were made back in the day and diving into the nostalgia of one my favorite games.

In this blog I’d like to explore how these maps work, how the player navigates them, and how this information is stored in the game files.

Dust Game Files

First, here’s a recap of the types of game files Dust contains.
The Windows installation of Dust contains several executable files and game files of interest:

TypeDescription
ExecutablesDust.exe
DF.exe
MoviePlay.exe
CSTCast files containing the sprites of the characters and some game logic
FLTFlat files containing puzzle logic
MOVMovie files contain screen animations and still renders
PRPProp files contain sprites of props that are placed throughout the game
PUPPuppet files contain characters dialogue, game logic and sprites of the characters
SETSet files contain game locations and game logic.
Types of Game Files

Today we’re going to focus on the SET files, which are used to store all kinds of information about the game’s locations.

A SET file is built up out of several types of blocks:

TypeDescription
HEADERThe header block contains the Color Lookup Table, the map grid, and the locations of the blocks below. It does not contain the locations of the frame blocks.
SCRIPTEach set file contains a boot script-block and a script-block for each place you can stand in this map.
WAYPOINTSThe waypoints block contains a list of waypoints that are used to place items and characters in the game. They can also be used to as a destination for a character to walk towards.
FRAMELISTThe framelist block contains the locations of the frame blocks and information about which frames are part of which walking animation while traversing the map.
FRAMEA frame block contains image-compressed data that can be rendered to the screen.
Relevant block types in a SET file

Map Layout

The layout of the map is stored at the bottom of the Header block.
All blocks in the Dust game files start with 4 bytes of block information: The block-ID and its size. Since we’re looking at the Windows version of the game files, all the data is stored in Little-Endian byte-order.

Below is an example of the data from APOTH.SET:


0000 0000 0000 0000 0100 0C00 085363656E65204131 00000000000000 22000000 |_____________Scene A1_______”___|
0100 0000 0100 0000 0000 0000 085363656E65204132 00000000000000 23000000 |_____________Scene A2_______#___|
0200 0000 0000 0000 0100 0C00 085363656E65204133 00000000000000 24000000 |_____________Scene A3_______$___|
0000 0100 0000 0000 0100 0C00 085363656E65204231 00000000000000 25000000 |_____________Scene B1_______%___|
0100 0100 0100 0000 0000 0000 085363656E65204232 00000000000000 26000000 |_____________Scene B2_______&___|
0200 0100 0000 0000 0100 0C00 085363656E65204233 00000000000000 27000000 |_____________Scene B3_______’___|
0000 0200 0000 0000 0100 0C00 085363656E65204331 00000000000000 28000000 |_____________Scene C1_______(___|
0100 0200 0100 0000 0000 0100 085363656E65204332 00000000000000 29000000 |_____________Scene C2_______)___|
0200 0200 0000 0000 0100 0C00 085363656E65204333 00000000000000 2A000000 |_____________Scene C3_______*___|
_________ ____ ____ ____ ____ __________________ ______________ ________                                   
    A      B    C    D    E           F                 G           H                                      

ColumnDescription
AThe X and Y coordinates of the scene (tile in the grid).
BBoolean (1 or 0) which determines whether there is something to interact with in this scene. For example a door you can enter/exit, or something you can click on.
CUnknown Boolean (1 or 0). I haven’t found any correlation between the grid tiles and this value.
DBoolean (1 or 0) which determines whether this block is inaccessible. If the value is one, the player can’t access that tile in the grid.
EUnknown value. This only seems to be filled when the block is inaccessible, but I haven’t found a correlation with anything.
FThe name of the scene. The first byte (08) tells us how long the string is. “Scene A1” is 8 characters long.
GThis is extra space for the name string to occupy if necessary.
HScript block ID. Each scene in the map can have a script attached to it. These scripts hold game logic which allow players to interact with the map, such as: walking through doors, interacting with objects and moving to other scenes.

With all this information, we can draw a diagram of the map where:

  • Inaccessible blocks are white
  • Accessible blocks are green
  • Interactable and accessible blocks are blue

Below is the diagram of the the Yunni area underneath the mission, also known in the gamefiles as the Hub.

Diagram of Scenes in HUB.SET

Plotting the Waypoints

The Waypoints block is quite straight forward. The number of waypoints is stored at offset 24 (offset 32 when including block ID and block size).

It is then followed by chunks of 50 bytes, that can contain 1 or 2 waypoints. They are divided quite strangely, because the first half is 26 bytes and the second half is 24 bytes. The second half only seems to be filled in larger maps.

OffsetSizeOptionalDescription
2UINT16NoX coordinate of Waypoint 1
4UINT16NoY coordinate of Waypoint 1
8UINT8NoLength of name string of Waypoint 1
9-25NoName of Waypoint 1
26UINT16YesX coordinate of Waypoint 2
28UINT16YesY coordinate of Waypoint 2
32UINT8YesLength of name string of Waypoint 2
33-49YesName of Waypoint 2
Waypoint chunk format

As it turns out, in order to line up these coordinates with the grid we drew above, each tile needs to be 255×255 in coordinate space.

Anyone who has played Dust will quickly recognize which map they’re looking at below:

blue=accessible and interactable
green=accessible

Unraveling the Framelist Block

The Framelist Block consists of chunks of 28 bytes. To know how many of these chunks there are, we need to get that information from the file’s Header block at offset 16 (offset 20 if you take the block-id and blocksize into account).

So, what does a chunk look like and what information does it hold? Let’s have a look at the Apothecary set file:

00000000: 0000 0100 0100 0000 0100 0300 0000 0100 0100 0000 0100 0300 2D000000 |_________________________-__|
00000028: 0000 0100 0300 0000 0100 0200 0000 0100 0300 0000 0100 0200 33000000 |_________________________3__|
00000056: 0000 0100 0200 0000 0100 0400 0000 0100 0200 0000 0100 0400 39000000 |_________________________9__|

00000112: 0000 0100 0300 0100 0100 0300 0000 0100 0300 0100 0100 0300 45000000 |_________________________E__|

          _____________________________ _____________________________ ________                                                        A                             B                   C                                  

This Framelist block contains a total of 28 chunks of 28 bytes.

Block IDs (C)

In column C we see an incrementing list of block ID’s. In the example above 2D000000 converts to a decimal value of 45 and 33000000 converts to a value of 51. Each of these block ID’s is 6 apart.

In analyzing block 45 and block 51, we can quickly recognize that these are Frame blocks, because they start with 8 bytes of image dimensions that are familiar to us (264 and 512). Also the blocks in between are Frame blocks.
After some checking in different SET files we can assume that each each of these chunks of a Framelist block gives information about 6 frame blocks.

Analyzing the Frame Blocks

0000 0100 0100 0000 0100 0300

If we analyze column A, we see 6 numbers. The third and sixth numbers (marked in red) contain a value between 1 and 4. The other columns (marked in blue) contain values between 0 and another low number.

In order to make sense of what these numbers mean, we have to look at the six frames that correspond to this chunk. The six frames always contain:

  • 5 animation frames, followed by
  • 1 still frame of higher quality
Blocks 45-50 of APOTH.SET
Unfortunately I can not show you how the image compression of these frames works, because it's still owned by Cyberflix. All I can say about this topic is that it's quite complex and that it was developed in-house using huffman compression.

Location and Orientation (A)

0000 0100 0100 0000 0100 0300

In the case of the chunk above (block 45), the player is standing in the West-most accessible scene with coordinates (0,1).

Block 45 of APOTH.SET
APOTH.SET map layout

So it’s clear that the first two numbers (in blue) mark the scene location of the six frames.
The fourth and fifth numbers (also marked in blue) mark the scene location after the animation has finished. In this case, since we’re not moving to another scene (square), both are (0,1).

The third and sixth numbers (marked in red) determine the orientation of the player. These numbers can only hold a value of 1-4:

  1. North
  2. South
  3. East
  4. West

In case the player doesn’t rotate, but moves from one scene to another, the chunk can look something like this:

00000112: 0000 0100 0300 0100 0100 0300 0000 0100 0300 0100 0100 0300 45000000 |_________________________E__|

Duplicate values (B)

00000112: 0000 0100 0300 0100 0100 0300 0000 0100 0300 0100 0100 0300 45000000 |_________________________E__|
          _____________________________ _____________________________ ________                                                        A                             B                   C                                  

For some reason, the values in column B (grey) are always an exact copy of the values in column A. The only exception I found was in HUB.SET, which might be reusing animations, or because it teleports the player to the opposite side as part of a maze puzzle.

For now it’s a mystery.

Here is a screenshot of my script which parses all of this data and presents it in a more human readable way:

APOTH.SET Block 44

Interesting Finds

I was hoping to discover some areas in the game that were rendered out but unreachable through the game’s logic. I managed to find some chunks where the camera moves forward into the bookcases of the Chinese Curiosity Shop and seeing an empty Saloon is also quite strange. It’s not much, but hey, it’s something we weren’t able to see before.

Final Thoughts

I managed to draw the map and the waypoints about a year before I figured out how the Framelist blocks worked. I was not able to crack this part of the puzzle until I could decode and render the Frame blocks.

The way that the DreamFactory engine works really becomes a lot more clear once you see that they rendered out all these frames one by one, followed by the characters and props being drawn on top of them.

It was another fun puzzle and I was treated with the gift of being slammed through a book case and some ancient vases. All in all; not a bad day for Reverse Engineering.

Published by

2 responses to “Reverse Engineering Dust: Game Locations and Map Layout”

  1. This is super impressive stuff, very keen to see the full game re-imagined in higher res! There’s definitely some folks out there who’re big fans (Brutalmoose on Twitch & Youtube, for one).

    Like

    1. Thank you so much!! If you want to join us on Discord, we’d love to have you:
      https://discord.gg/QrC7w4RTwq

      Like

Leave a comment

Design a site like this with WordPress.com
Get started