TL;DR - Dumped a 17 year old debugging symbol file for a game called Carmageddon. Take a look at the symbols folder to see the output.
In the Carmageddon Splat Pack folder, there is a file called ‘DETHRSC.SYM’, last modified 13th November 1997.
It has sat there, un-noticed and un-loved for the last 17 years, ignored by the internet. Having made a remake of the Carmageddon engine, and being generally curious about random binary files, I tried to figure out the file format. Immediately by looking at it in a hex editor, it was obviously a debugging symbol file, the question was which type of symbol file? Of course, there are many symbol files with a .sym extension, and after some trial and error, it turned out to be a Watcom symbol file. I grabbed a copy of OpenWatcom and fired up the debugger, wd. It could read the symbols, but I never found any Carmageddon executable that matched up with it. It seems likely it was left there by mistake from a debug build.
Using wd to look at the symbols 1 by 1 in a little DOS window quickly becomes tiring, so then I wanted to dump the symbols out. For that, I needed the source code for the Watcom tools, and a working Open Watcom development environment.
(…Fast forward a while getting the environment up and finding where the code for handling symbol files lives…)
In the Watcom world, symbol file support is provided by various DIPs. To use a DIP dll requires the calling program to implement various client-side methods to allow the DIP to alloc memory etc, and then to provide callback functions for the DIP to call when walking the symbol list. It’s all pretty complex, but luckily there are a couple of utilities which illustrate generally how it should be done. I based jsonsymdump off dipdump (which is advertised as dumping symbol files to text format, but crashes on DETHRSRC.SYM). I did the minimal amount of work in C required to generate a valid json file, then wrote a node.js script to take that json file and generate some semi-valid-ish c files.
We now know all the methods and properties that were implemented in at least some build of the Carmageddon engine. It’s not going to allow anyone to reverse-engineer the engine without a matching executable, and we don’t know how any of the methods were actually implemented. But it is interesting to see how things were named and organized, and by reading the method names, one can make some good guesses at what is happening at a high level in the game engine.
Files underneath the DETHRACE directory are Carmageddon.
Files underneath the BRSRC13 directory are BRender, a 3d graphics engine which Carmageddon used.
Some of the symbol names are funny, some might offend people, and some make no sense unless you are one of the original developers! A few examples:
How to build and run yourself (if anyone ever wants to…)
Follow the README in jsonsymdump to build the C binary
I’ve just posted a new video showing the latest OpenNFS1 dev version. Compared to the original video I made years ago when I made v1.1, this version is much faster, with a better sense of speed and more faithful to the original.
It’s been at least 4 years since I did any work on my remake of the original need for speed game. Back then it got picked up by a few gamedev sites and I was contacted by EA Canada asking if I was interested in interviewing with them! (A completely different story to Square Enix and my Carmageddon remake!). Looking at my code after so long is pretty cringe-worthy - I cut a lot of corners before the release, the code is messy but it is still sort of fun to play. With the end of XNA, and being between projects, I decided to do a quick port to MonoGame and move the project to GitHub.
I figured it would be a few days of work and I’d be done with the port, as MonoGame implements almost all of XNA 4. Unfortunately, I had compiled against XNA 3, so first I had to update to XNA 4 and deal with all the breaking changes. Once that was done, it was running in MonoGame pretty quickly. As all developers love to do, I started ripping, replacing and refactoring. The problem now was when I wrote the code I had built up a really good mental model of the Need for Speed track structure and how it was represented in code and in the data files. It’s quite complex, with many parts, represented by classes with names like TrackNode, TerrainSegment, TerrainRow, TerrainStrip etc. The code didn’t do a good job of explaining how these objects fitted together. I used to just know that a TerrainSegment always had 4 TerrainRows, and each row had 10 TerrainStrips, but coming back to it took a quite a while to get back in the groove.
A few weeks of late nights later, a load of new features, bug fixing, and more digging around the original data files with a hex editor, OpenNFS1 is much cleaner and more faithful to the original. A couple of things that made the biggest look and feel difference was changing the field of view and aspect ratio to match screenshots of the original. The values I originally used were way off, and resulted in a lack of feeling of speed. I’ve added some simple AI to race against, here are a couple of screenshots with 100 racers! The original game used some really fun optimizations to have 8 cars simulated at once, which I am also using, and 100 cars is actually pretty computationally simple because of it.
I’m going to write a few posts about how the tracks and scenery and physics are organized in the original game (as far as I can guess from understanding the data files) because some of the ideas could work well for mobile games today. Also, if I don’t write it down this time, I’ll forget and hopefully it will be interesting for someone else too.