Metamorphism Quake - Part 2

By Kevin , February 13th, 2021

In the first post of this series, I spoke about reviving a Quake mod from a quarter century ago to see if it can still be played in 2021. Here I discuss some of the bugs and UI tweaks I fixed in my quest to get the game running.

Bugfixing

Code that is a quarter century old doesn't come without some rough edges. If the code was an old house then I would be my own Bob Vila, welcome to "This Old Project". The foundation and framing were still good, but there were areas that needed attention. Cracking wood; busted windows. Chipped paint.

First, I had to get an assessment. Going from point A to point B was going to be tough. Studying the commit log, those 34 commits came from an 8 week period in 2011 where someone made updates and posted it to SourceForge. None of the changes were tracked from the inception to release 5.0 - so I have no context or history over any of the why things are what they are.

This mod was written in 1997. All of the development was done on (I assume) a Windows machine. Mac and Linux were not big in those days (despite id making their games mostly cross compatible). To make it more complicated, the version of Quake with Steam is Windows with Windows based file formats. Steam on Linux comes with an add on called Proton to run games in - essentially, it is Wine packaged for Steam (virtualization layer). That means I cannot just run or debug any of those files, or consider much of the documentation for compiling them as I am running on Linux.

Despite that, I downloaded CLion from Jetbrains and dove in.

Weekend 1

I didn't plan on doing a whole lot - I don't write lots of C and generally assumed the game was stable. While I could get the mod running as the download from SourceForge, I noticed numerous typos in some of the text in the game. I figured I could at least fix that.

The first weekend I dedicated to this was spent getting the Makefile to build the project, to correct some typos and code formatting errors, and update some of the game text to be more clear. I was running into a whole host of issues on that first weekend:

  • Certain UTF-8 characters were being used in the game text, but rendering as gibberish in game (On Steam Linux, anyway).
  • Certain maps were crashing the client, in the same exact spots.
  • Capture the Flag mode would not load.
  • The commit history only contains a short period of commits in 2011.
  • Portions of the codebase were generally undocumented.
  • Building qwprogs.dat (for running QuakeWorld servers) did not build at all.
  • The code contains no general README on how to play, how to install, what the commands are in-game, or what Meta is itself - or how to build the source.
  • The included qcc compiler did not appear to work, but the qccx compiler did.

Fixing the characters was first on my list because it was the first thing you'd see upon entering the game. The file types were showing as 'unknown/8bit' character encoding, and the original codebase appeared to have either the Euro symbol or the "?" diamond mark, signifying an unknown character. The odd thing is, the game does not show these characters with the 6.0.0 release download (unmodified from SourceForge). So, visually, I knew what the symbols were supposed to be, anyway. To complicate the matter, the IDE was auto-assigning UTF-8 format to any file it opened, and would complain about these characters.

I don't know a ton about character encodings - but it appeared that the intent was using windows-1252 encoding. Setting a few files to this format did fix some of the in-game text, but not all of it. This likely worked fine back in the day as pretty much every player was running a Windows box. 

It took a couple of hours of research but I managed to dig up a site on the internet that had some critical information I would need. Within it is a section on escape sequences that would represent certain glpyhs (symbols) on the in-game text - and this is exactly what I needed. After replacing all known instances, compiling and loading the game showed the familiar symbols that I expected to see. My first big fix! I proceeded to then go through and fix or convert odd symbols to their glyph counterpart. How that wound up in the code base, I am not sure. But it seems from the documentation, the escape codes should have been used all along.

I committed these fixes, and started working on a README in the repo, documenting what I knew to date. After that, I set out to fix the map crashing issue.

Fixing the map loading error

The next thing I wanted to tackle was why certain maps were crashing immediately when joining or when visiting certain areas of the map. I knew that this effort would be virtually useless if this was not resolved since the game is not playable like that.

At first I wasn't sure if I would be able to remedy this. I didn't know if this was an issue with the core Quake code running on Steam in Proton and trying to use a mod, or if this was somewhere in the mod code itself.

I was able to reproduce the issue in exactly the same spot in each map, so that was a starting point. I also got a vague console error in the Quake console, but it at least gave me an error string that I could track down: "train_next: no next target".

That brought me to this function below. objerror will cause a fatal crash with the reason. I commented that out and left a note as to why it is commented:

void() train_next =
{
	local entity	targ;

	targ = find (world, targetname, self.target);
	self.target = targ.target;
	if (!self.target) {
	    // @todo: Don't crash the game, just do nothing for now until we can debug the cause.
	    // To test, load e1m3 and go to a room with a lift. The game will crash.
	    // Try to load e1m5, it will crash immediately.
	    // Root cause still unknown. Regular Quake (without meta) works fine.
            //objerror ("train_next: no next target");
	} else {
        if (targ.wait) {
            self.wait = targ.wait;
        } else {
            self.wait = 0;
        }

        sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
        SUB_CalcMove(targ.origin - self.mins, self.speed, train_wait);
    }
};

This appears to fix the issue, in the sense that the maps no longer crashed when playing. I reviewed other Quake 1 mods that have this file (plats.c or plats.cpp) and they have the same exact code. So for now I removed it so the game client stays up until I can find what is actually triggering this. Perhaps its because I am running on Proton (Wine) in Steam, or that there was additions to the mod code in version 6.0 that created a regression. Hard to say. But I see no residual effects from this change yet, so perhaps this is okay. I am still trying to figure out how to log the state so I can review it, like seeing what "self" is, which may yield more clues.

Quake map e1m3
Map e1m3 no longer crashes the game client when entering this room, among others.

I did note that running the game normally without the mod files loaded did work correctly. That is another clue that perhaps the bug is in the Meta codebase - I just need an effective way to track down what is triggering it and fix that.

In either case - this made the game stable enough to run around any of the original Quake 1 maps and try classes and fool around with the grappling hook, a good step forward. I could run a local LAN game and have no issues at all. It is starting to look and feel exactly how I remembered it all those years ago. 

Next, I needed to run this on an actual game server and connect to it using the QuakeWorld game client. There were a lot of unknowns here to tackle as well and I will cover that in the next installment.