Anyone remember GUEmap? It was crippleware (and I mean seriously crippled crippleware) mapping software, written by Christopher J. Madsen, that was pretty much the only game in town if you wanted a piece of software to make maps of your forays into the realms of Interactive Fiction. And so, having added hard drive support to Apple2 in order to be able to play 4am’s Pitch Dark (and finally get around to finishing up Planetfall), I cast about for some mapping software—and found that the only thing available was… GUEmap.
So a quick visit to the GUEmap homepage showed that it hadn’t been developed for well over twelve years. And before the Peanut Gallery pipes up with witty aphorisms about people living in glass houses throwing stones and such, let me just say that I understand perfectly just how difficult it is to keep your motivation going on long lived projects like these. So there.
So, feeling a pang of mild discouragement, I downloaded v2 of GUEmap and gave it a whirl; and it was just as bad as I remembered it. It was unintuitive, difficult to use and klunky. To me this was sad, as it could have been much better with just a few changes here and there, but, alas, this was not to be.
Or was it? I noticed, with a rasied eyebrow, that there was a source code archive available, and it had been released under the GPL! This was, in a word, interesting. And so, my curiosity having been piqued, I downloaded the source and took a look and oh, my…
Now before I ever saw the source, GUEmap had a few things going for it (like being the only real mapping software available) and a few things going against it (like being written for Windows only, and being crippleware). A quick look at the source showed it had yet another thing going against it: it was written in Microsoft Foundation Classes (or MFC for short).
When future historians look back on the history of software development they will find that we were living and coding in a Dark Age, and that one of the worst implements of torture devised to torment programmers of that era will be found to have been MFC. Scoff all you want, I lived through those times and recall them with horror; even the mere mention of MFC still causes me to shudder to this day.
So, in weighing my options, I briefly considered porting it to WxWidgets, but, having inhabited that Circle of Hell for a season, I decided against it. Yes, it probably would have been far easier to get it working that way, but at what cost? Especially since WxWidgets is basically an open source version of MFC. So that was right out. Also out was keeping it as a Windows only program, as I long ago learned that writing cross-platform code is the only way to keep one’s hard-earned code from the evils of bit-rot and platform lock-in. So that left pretty much Qt as the only viable option.
Now I know that quite a few people seem to have this irrational hatred of Qt, which I absolutely cannot fathom. But it’s just that, irrational. Qt provides a first-class framework for application development that pretty much gives you cross-platform executables for free. It truly is a remarkable piece of middleware and I will miss it when it’s gone.
And so I dug into the code, converting it to Qt as best as I could. It became apparent early on that this would be nigh on impossble to do all in one fell swoop, so I decided to see if I could get something minimal working in order to assess how much work it would be and whether or not it would be worth doing. And so I found a copy of an old GUEmap file of Zork I that I had kicking around after all these years and set about hardcoding it to load. Once I had that, I dug into the document code and the view code (mapdoc and mapview respectively). If I could get that to properly display the map on my Qt application window I knew I could get the rest working fairly easily.
Converting code like this is usually a tedious slog, and this was no exception. I was able to figure out the endianness of the file format (as it used MFC’s serialization code for saving and loading) and remove all the C++isms from the loading code. It seemed like it was successfully loading and parsing my Zork I file (and some well placed logging seemed to confirm this), so I pressed on with getting the view code compiling.
To accomplish this, I pretty much commented out all the code except for the drawing code and whatever functions it called. Eventually I was able to get the compiler if not happy with, at least tolerant of the code at that point. So I turned my attention to the document code and slogged my way through that as well. I could see that I was going to have to make decision here whether or not to cut out all the undo code, and, following the Programmer’s Prime Dictum (that being to do as little as possible), decided it would be less work to keep it in than to excise it and add it in later.
So eventually, after much adjustment and porting, I was able to get the compiler to grudgingly compile a minimal set of code that would load a file (hardcoded to load a specific file) and display it on the screen. I fired it up, and saw… Nothing.
Now a trap that some programmers fall into when coding up an application like this is to get hung up on the fact that while the X-axis conforms to the expected Cartesian ideal, the Y-axis is inverted with respect to said ideal. And indeed, it looked like Mr. Madsen had fallen into this particular trap. But really, for a simple application like GUEmap, this was completely unnecessary and an unwanted complication that added nothing. So, having determined this, I quickly coded up a transformation in Qt’s rendering code to mimic what he had done in MFC and lo and behold! It drew something!
What it drew was basically the "edges" (the lines connecting rooms to each other) of the map and nothing else. But this was progress, at least. But I knew this would only be a stop-gap measure at best, because I had run into this kind of thing in coding up Architektonas.
One major difference between the way Windows renders things using a coordinate transform to invert the Y-axis and the way Qt does it, is that Qt renders its text paths through the transformation while Windows does not. Which means that if you really need to have an non-inverted Y-axis (i.e., Cartesian), using a simple approach of using a transformation matrix to invert the Y-axis will give you inverted text; this is a consequence of Qt’s rendering being a left-handed system and, as such, it cannot be made into a right-handed system no matter what you do—it’s a mathematical impossibility.
And so, once I had the rooms and text labels displaying properly, the text was inverted as I knew it would be. So then I had to make yet another decision, and it seemed clear to me that the right way forward was to remove the trap from the code and keep the Y-axis inverted (from the Cartesian POV). Fortunately for me, it was fairly easy to do so and the major problem that I foresaw, that being the un-inverted Y-axis being baked into the file format, turned out to be mostly a non-issue as Mr. Madsen was inverting the Y-coordinates as he read the file from disk. It wasn’t fully a non-issue, as there were some side-effects that sprang from the un-inverted Y-axis assumption, such as the bottom of rooms being treated as the top (hello, unnecessary complication!). Once I addressed all these problems, I had the map drawing as it should. Progress!
So then, the next tentative thing to tackle was to see if I could translate the mouse loops without too much difficulty. I decided to convert the mouse down logic first, and took a similar approach to the rendering code in that I commented out the body of the function and added back in things little by little. Once I had the mouse down logic compiling, I decided to see if I could make it select and deselect rooms on the map; after finding and fixing all the places where it was checking for an inverted Y-axis, I was successful.
And so it went with the mouse move and mouse up functions; eventually I was able to pretty much restore all the missing functionality that made it able to create and edit maps. So, after a few days of hacking on the conversion, I could see it starting to pay dividends and that finishing it up would likely be worth the effort.
And so, I am proud to present GUEmap v3! It will load v1 and v2 maps, but only save in v3 format. Thanks to Christopher J. Madsen for opening up the source and, in keeping with the license for GUEmap v2, GUEmap v3 (and its successors) is also licensed under the GPL v2 or later.
Binary downloads will be coming soon.
If you don’t mind working with semi-broken code, you can check out and compile it on your own. The GIT repository is located at:
https://shamusworld.gotdns.org/git/guemap
If you choose to go this route, you’re on your own for now until I can set up a reliable line of communication. Good Luck!