As a kid, I always loved playing adventure games on my PCs. From the first time I played Space Quest, I was totally hooked. Although there are a ton of great games to choose from, Dark Seed has always been one of my favourties. Published by Cyberdreams around 1992, Dark Seed is a psychological-horror adventure featuring the artwork of H.R. Giger. If you haven't played it, I definitely recommend grabbing a copy and throwing it into dosbox.

Recently, poking around at the internals of this game (as one does) trying to understand how it works and how game asserts are stored. The graphics are particularly unusual for the era. In order to satisfy Giger's demand for quality, high-resolution graphics, Cyberdreams was forced to use EGA screen mode 9. This allows them to have 640x350 resolution (which was massive for the era) but at the cost of colour depth. This meant they would only have 16 assignable colors from a total palette of 64, instead of VGA's 256 assignable colours from a palette of 262,144. Images for this game need two parts to render correctly, the image file (either .IMG or .PIC) which holds the actual pixel placements, and a separate palette file which defines the colour assignments for each EGA attribute index. While looking at the palette files, something bizarre stuck out to me: the .PAL file seems to be 48 bytes, made of 16 3-byte sequences. In EGA, we only have 2 bits per channel (RGB) for a total of 6 bits to define a colour. You can absolutely do this in a single byte. But this game was defining values with 6 bits per channel, for a total of 18 bits. This sounds an awful lot like VGA... but the game is in EGA. What's more, 2 bit per channel leaves only 4 possible values for each channel, but the palettes are defining values outside of these ranges... and they're rending correctly! How is this even possible? EGA should be limited to a total palette of 64 colours.

I did a massive amount of digging on this one. Opening old MZ binary files is kind of awkward these days, but I found radare2 and IDA free v5 seem to have the best disassemblies for my analysis. I also ended up compiling dosbox-staging with the heavy debugger turned on. It wasn't a great experience, but it definitely worked.

After poking around for a moment, it's easy to identify two important calls. The first is here:

mov     bx, 10h
mov     cx, 10h
mov     ax, 1012h
int     10h

Each register is 2 bytes wide, so we are simultaneously setting 2 options at once (high and low.) We can see a bunch of things going on here:

  • ax sets a block of DAC color registers.
  • bx is our first color register to set.
  • cx specifies we are setting 16 registers.

But the next call is fascinating.

mov     bx, 101h
mov     ax, 1013h
int     10h

This call selects the video DAC colour page, but it's only available in the VGA spec. We obviously have a mix of both EGA and VGA interrupts being called.

After a bit of digging on Google, I found this awesome video about VGA palettes in EGA mode. Essentially, if you have a VGA card (which is backwards compatible with EGA) and a VGA monitor, you can actually manipulate the VGA DAC directly to assign the first 16 colour slots. Since the EGA backwards compatibility uses this same region for EGA slots, you essentially unlock the ability to use any of the 262,144 colours of the VGA palette in your assignable EGA slots. It's a pretty marvelous piece of engineering for the era, honestly, especially in an age before the modern Internet. 🙂

Dark Seed managed to be a great game on multiple levels, and this little gem just made it all that more interesting.