kipley.com > Super Quest > How I created the map

Super Quest - How I created the map

Mapping Super Quest is tricky, because there's no way to pause the game, and random roving monsters may come along and kill you whenever you look away from the screen. Despite this I was able to create a rudimentary map as I went along, by quickly recording only the most basic information about each room (the exits, the monsters, and whether the room contained a valuable treasure, for purposes of determining good routes to grind).

While the resulting map is functional, it's not very pretty, or even completely accurate. Plus, while playing through the game it's very difficult to determine which rooms have "random exits" (that change each time you save the game), short of reloading the game multiple times and crawling through the entire dungeon over and over. And even if you explored the map completely many times you still could never be positive that you'd identified all the random rooms.

I was intrigued by the challenge of creating a perfectly accurate map of the game. I decided to try and analyze the original game files and see if I could reverse-engineer the data to figure out how the game stored the map.

The first step was easy... the Virtual Apple ][ website was nice enough to provide a handy download link for "Super Quest Disk 1", which is a zip archive containing a file called Super Quest (V5.51).dsk

Next I had to figure out how to access the .dsk file. I searched around on the web and found a program called FID that would display the directory listing and extract the files from Apple II .dsk files. Here's the resulting directory, along with links to each of the files:

Some of these files are text files, which show parts of the game code in Basic. This was fun to analyze, especially the parts in SQX.5 that contain a lot of the core game code. But none of the logic in there seemed to be about the part that I was most interested in, that is, the code that accessed the map data and created the visual representations of each room. That part of the code was likely written in assembly language, and I didn't have a good method to reverse-engineer that.

But I figured that even if I couldn't find/understand the code that drew the rooms, perhaps I could analyze the binary data itself and deduce how the rooms were stored. Since this was an old game that had to fit on a 5.25" floppy disk, at least all the files were small, which meant that it wouldn't take too long to study them.

So I opened up the binary files in UltraEdit and used the Hex Edit mode to analyze the data. It seemed most likely that the room data would be stored in "SQX.5 BIN ($5800/1800)", so I focused my efforts there.

When you look at binary data with the naked eye, at first it appears to be nothing but gibberish. The goal is to analyze the gibberish and see if you can detect patterns. Fortunately I already knew a bit about what kind of pattern I was looking for... since the Super Quest dungeon contains 1024 rooms, I figured it was likely that parts of the dungeon data would be 1024 bytes long, or some multiple of that.

Soon enough I found a section of data (from 4100 to 5123) that was 1024 bytes long that stood out from the surrounding data in the binary file, as each byte in that section had very small values. My first guess was that this data represented the exits to each room, as each exit for the room (north, south, east, west) could be stored as a single bit, making the values range from 0-15. However, I couldn't match up that (presumed) exit data to the map I'd manually created, no matter what various encoding methods I tried.

Then I realized that this data wasn't the exit data, instead it was the data for the treasure contained in each room. While I hadn't mapped every single treasure when creating my original map, I'd mapped enough of the high-value treasures to give me enough data points to confirm that the values matched up with the data in this section of the binary file. Yeehaw! Progress had been made!

Now it was time to write a simple program in Java that would read in the binary data file, and turn it into a visual display of the data for each room, as decoding 1024 rooms worth of data was not something I wanted to do by hand! My code drew a grid of all the rooms and displayed the data for the treasure in each room, and I turned the treasure indexes into "gold denar" values which I determined through the Basic code contained in SQX.5 (and from my knowledge gained by playing the game). One index of note that was slightly tricky to decode was that a lot of the rooms with small-value treasures actually contained a randomly valued treasure (worth from 0 to 16 gold denars) that changed each time you reloaded your character. Just another twist the game throws at you to frustrate efforts to create accurate maps. However, by accessing the binary data it became easy for me to spot the pattern and declare that any room with a treasure index value of "1" was one of those "random small treasure" rooms.

I scanned the binary file some more to see if I could find another section that corresponded to room data. Knowing where the start and finish points for the treasure section helped, as I figured the data for other sections might start or finish right before or after the treasure section. Sure enough, the next section I decoded was from 3076 to 4099, which was the data for the monsters. It turns out that for each byte in this section, the first 4 bits corresponded to the number of monsters in the room (0-15 monsters), and the last 4 bits corresponded to the type of monster. It's odd that the game features only 13 types of monsters, as they had enough room to store data for 3 more types without increasing the size of the binary file.

I updated my Java program to display the monsters in the rooms along with the treasures, and everything still looked right. Time to find the data for the room exits! I was on a roll now, and I soon found it at 2052 to 3075. After some analysis, I determined that the first 4 bits of each byte in this section represented the "shape" of the room (hallway, rectangular, octagonal, open, etc.) and whether it had random exits or not, while the last 4 bits indicated the exits (in order, a bit value of "1" indicated that the room had an exit to the north, south, east, or west).

I initially ignored the shapes data and wrote a quick routine that displayed all the rooms as hallways, with the proper exits. I crossed my fingers and ran the program, and there it was... the entire map of Super Quest, just as I'd come to know it. Success!

Of course there was still more tweaking to do to get everything perfect. First I had to figure out which codes corresponded to which room shapes, which didn't take too long. Then I had to write drawing routines for each different room shape. I mostly used Java's Graphics routines (drawLine(), drawString(), etc.) to draw the rooms, and I made my drawing code scalable so that I could adjust the sizes of the rooms later. One exception was for the "open" style rooms, that had a lot of angled interior walls. To accurately recreate the interior walls, I created two images for the different base interior wall configurations:

type8.gif:
type9.gif:

Along with four other transparent images that represented the additional interior walls that appeared if there was an exit from the open room to a non-open room in a given direction:

type9n.gif:
type9s.gif:
type9e.gif:
type9w.gif:

And then I used drawImage() to display the appropiate wall sections in the middle of each room.

Also I figured it would be nice to display the "rooms of interest" more prominently. These rooms included the bazaar, hospices, Puzzle Room locations, the room with the trap, the multi-treasure room, and the crown room. Interestingly, only the crown room location is stored within the dungeon's binary data... the rest of the special rooms are made to work through routines within the Basic code. I knew the locations of most of the special rooms already, but actually used the Basic code to figure out where all the Puzzle Room locations were (it appears randomly in one of three different locations, and while I'd visited all the rooms in the dungeon when I played through the game, I hadn't revisited the locations enough to see the Puzzle Room appear at all three).

Here's the section of code (in file SQX.5) that randomly picks the Puzzle Room to show up as room 104, 226, or 29:

4305 PZ = 104:P7 = RND (1): IF P7 > .44 THEN PZ = 226
4310 IF P7 > .75 THEN PZ = 29

So I had my code highlight the special rooms with a yellow background, and draw text on them to label what they were all about. Then I tweaked the default room size so that they were just big enough display all the necessary information without any text running over the walls. Once I was happy with how everything looked, I used Paint Shop Pro to take screen shots of the map from my Java program, and turn them into images for the web.

Here's the Java code I wrote to create and display the map:

  • SuperQuest.java
  • MapPanel.java
  • sq4 (the binary file from the original .dsk that contains the map data)
  • type8.gif
  • type9.gif
  • type9n.gif
  • type9s.gif
  • type9e.gif
  • type9w.gif

    Well, if you read through all of that, I'm impressed, because there's probably only about ten other people in the world (at most!) that would find it interesting. Thanks for listening to me ramble on!