Pirate Doom

Application icon for !Doom II
!Doom II

In the very dim past there were games that consumed us. The main one for me was Civilisation - and that's a different story. But Wolfenstein 3D started a serious wave of First Person Shooters. Wolf was something of a milestone, and when Eddie Edwards ported it there was a lot of interest. I was there with so many other people at the Acorn World show saying how cool it was, but that Doom would be so much cooler. Eddie, by that time, was a bit tired, but still in good spirits, saying that he was interested but hadn't got the backing.

Spin forward a few years and through sources I'm not divulging (mostly because I honestly don't remember), I obtained a copy of the Doom port that Eddie had done. I think the story I heard was that he'd been given sources to work with by id because they were impressed with his port of Wolf, but without more negotiation and money he couldn't do anything about it. There were stories that the game was stolen from his machine, and others that he released it himself to try to get some interest. I don't know which it was and whilst I tried to find out more about it, I never really got to the bottom of it.

Whilst I was working with it, some of the people on IRC and who I spoke to by email who had also obtained copies would pass around some little tools that they'd written and their findings. A few of these are dotted around my directory - in particular a Gamma correction for the palette files in the WADs because the game appeared just too dark (on the RiscPC, certainly, and to a lesser extent the A5000 version), and a couple of WAD management tools for launching the game. Each had a little !Help file of notes and musings, and were signed with pseudonyms - I have no idea who most of them came from now.

In any case, the version that was supplied was very much a development version. The 8bit version had no sound. The 16bit version had sound but only ran on the RiscPC (the 16bit support seemed to have been dropped by the time I saw the source). There was a 24bit version as well, which also had no sound (I think - I can't remember this far back very well).

I set about disassembling things to find out what exciting things were in there. It had all been built with the function signatures present, so that made things a lot more fun. There are a few things I can say, based on my notes about the various areas of the code that I made at the time:

  • Early on I had identified where the network flag was set and how it was being used.
  • The sound system was actually installed inside application space when present.
  • The music system was present and would try to play patches itself, rather than calling out to the MIDI system as the released version would.
  • The music system seemed to share some common code with parts of Wolf 3D.
  • I made specific note about the buffer fill:
    buffer fill code->
      offset uses fixed point arithmetic, point before b12
      I really like the sound generation code !
    

The initial changes I made were just to get the game to run on my A5000 - there are a selection of different patches in the directory I've got here. I produced the patch in Acorn !Patch format, which is pretty bizarre for me. Probably because it was easier to patch the binary directly in !Zap and then run my !MakePatch tool to compare the result to the original once I had a version I was happy with.

Once I had it working on my A5000 I wanted more. Needed more. It is Doom, after all <smile>. I looked at the Sound code and wrote up a module that would... oh, good gosh I've just read the code and remembered what it was that I did. Ok... there were two ways in which the sound could be played. Initially I needed a way to play the sounds on an 8bit sound system as there was no code present to do any of that and the functions that did were stubs. Fortunately with the 16bit version (which had sound) and the 8bit version (which had stubs) to compare, this became easier.

The easiest way to do this was to extract all the sound samples from the WAD file and make RISC OS voice modules. One per sound effect. I reckoned that these could be loaded on demand and replaced in a least-recently-used manner. We have to replace them because a) there's a lot of samples and not much memory, and b) the SoundChannels module only supports a limited number of voices at a time (16 or 32, I think). Pretty simple, but the A5000 doesn't have a lot of memory. Solution ? Play the sound on another machine. The initial version of the DoomSound module would use Econet to transmit sound requests to a second machine which would be running a little BASIC program that would load the sounds from disc and trigger the effect.

I think at the time I was doing this, I was using the family A5000 as the slave whilst mine played the game.

A little bit of fiddling around and I managed to get a sensible balance of sound on just one machine - the LRU voice loading being done inside that module. I believe that the way that I managed to get back sufficient memory was to disable all the internal sound loading in the application itself - although it wasn't playing any of the sounds, it was still loading them. And because they never completed playing they would eventually fill the zone (memory allocation area).

That might seem a little heavy handed, but it did the job and wasn't actually all that slow - given that we're running a quite unoptimised Doom on a 33MHz system, and having to hack in any functionality I wanted <smile>.

Anyhow, the next thing to try was to throw in some music handling. This was a little less successful - although I managed to get out the necessary parameters for the playback I never managed to find the correct parameters for the music files that it expected - and not through lack of trying. There's quite a few directories of files containing MIDI patch files and configuration files that map them according to what I think that the Doom16 was expecting. It never really worked though. Instead I ripped out the music playing code from the 8bit version (well patched the stubs to point to a module entry).

The DoomMusic module provided the 'music' for the game - I just used basic WaveSynth sound to try to get something useful out of it. It wasn't at all successful and I gave up quite quickly.

I began work on a networking the game. The IPX network driver source could be found on many of the online Doom resources (along with serial and some other 'DOS network' sources), and this explained the calling conventions and data structures. As a result it wasn't at all hard to hook a simple network module up to the entry points in the application. Again, this was Econet networking - and it wasn't too hard really. Fiddly to set up, but if you'd ever tried setting up network games with the original PC version you'd know this pain wasn't anything new.

Application icon for !DoomWADs
!DoomWADs
I'd also started writing a WAD manager of my own - !DoomWADs. Imaginative aren't I? This was intended to launch the A5000 Doom which used sound. It had a few options for starting the basic game or adding in options for disabling monsters or disabling the sound (apparently so that I could play at night and not disturb my brothers). It also had support for setting up the network itself, so you didn't have to do it from the command line - the module had a painful configuration.

It's one of the very few applications I've written which had 3 IconBar icons:

  • a resource icon which lets you open the WADs directory and select PWADs (using my Filer library I'd written previously), and allowing you to choose which level to play. It could also show you the text file that was alongside the PWAD.
  • a 'mode' icon which let you select between 'Standalone', 'Server' and 'Client' modes - together with little icons that showed the state. The menu gave you the option to configure the network settings for the game.
  • a main 'Play' icon which let you configure which game would be run, and other configuration. Clicking it would launch the main game application.

Having got a useful and interesting version that had sound and networking, I then put together patch to blow the others away. Changing the game from running single-tasking to running in the desktop, in a window. Tra-la-la... Replace the initialisation, make the system always single buffer to an area of my choosing - a sprite. Change the main poll loop to call a SWI Wimp_Poll, write my own sprite rendering in a window. Add an IconBar icon. Make it understand that it only runs when it has focus, not all the time. And... rest.

Doom - being attacked by Imps
My hacked Doom, running in the Desktop.

The picture above is actually captured from RPCEmu in a 16bit mode, so it's a little more colourful than it would have been on the A5000. I enabled the 'run on the IconBar' option as well, just to show that that worked - when that's disabled, it would just appear as a 'Doom II' logo. When you gave the application focus, the game would run - unless you selected 'Continuous', in which case it would run all the time, even if you closed the main window. That was the real silly use of the IconBar icon <smile> - you could play whilst doing other things. Albeit you had no memory for anything else and moving around would disrupt other things. <laugh>

If it looks a little squashed in the picture that's because the window's the wrong shape - the redraw would scale the sprite to fit the window, which meant that unless you matched the original aspect ratio you got a squashed image.

It also looks rather darker than it should (or at least, darker than I think it should) because the brightness controls didn't work on that version - normally there were 4 levels of brightness that you could move between, but they just didn't do anything.

I have an amusing email reply back from Pineapple allocations in my email archives:

Subject: Re: Request for filetype allocations...

On Sat 03 Jan, Justin Fletcher wrote:

> I hope you can honour this request... :-)

DoomWad &16C, DoomGame &16B.

I'm not going to ask what they're for...

Alan

According to the history on !DoomWads, Eddie wanted a look at what I'd done - I had finally found a contact address for him that was valid. According to my mailbox there was some discussion on comp.sys.acorn which then resulted in a few people contacting me asking about things. I think I sent Dave Walker a copy of the original+modified network capable version which resulted in a mail back from Kevin Lingley who was someone vaguely important at Acorn asking about how we could make it happen.

Looking through my email here brings back a lot of memories - it seems like there were a lot of people trying to get hold of copies of the game and the hacks that I'd done.

Application icon for !jDoom
!jDoom
I wrote network drivers for Serial and UDP in response to requests from people so that we could play the game in different ways. The networking was still a bit of a black art, but I defined a module API that allowed the network drivers to be called from the main application and provide responses, together with a setup application that could be used with any of the supplied modules. It looks like there's an ordering issue with the octets in the UDP driver, but it's not like that's a big deal. The network driver setup was built so that it could be invoked from !DoomWads - we'd start !jDoom which provided the network configuration and then it would launch the main Doom application.

There were some !StrongHelp manuals I created for the Doom Secrets and Doom technical documentation which came from the documents that were on the Internet at the time. I also created a helpful !StrongHelp manual documenting the network modules and how you wrote new ones.

When I've been trying it just now, it's still very fiddly to get a real game to run, although I'm not sure whether that's because the code is bad or because I assumed something that's no longer true in Select.

Through all this I felt pretty pleased that I'd managed to get so far through adding things to Doom without having any source code. Whilst a few people seemed pretty impressed with what I'd done, it still falls to Eddie to take all the credit for the port - without it, there would be nothing. I just tinkered at the edges. In a cute way, I think, but still just tinkering.

There were talks with a few people for bringing Doom to RISC OS properly, but the privilege fell to RComp to do that. They got in touch with Eddie and sorted out a deal with id Software to bring it to RISC OS. Eddie finished his version - which was beyond what we had seen - and brought it out as a full game. It was greeted rather well by people, even myself <smile>.

Doom

Application icon for !Doom
!Doom

Once the Doom was released properly, it was obvious what it would need some network drivers. Eddie had documented the driver interface that he was using - which differed from what I'd done before. It was far more sensible, but meant that the basic drivers I'd written weren't really suitable, and in any case they needed some proper application to control them as Doom was being done commercially now.

RComp asked me if I'd do some network drivers, as I'd done them before and passed me the details. Being in the middle of 3rd year and trying not to be too distracted by Mozilla at the time, I said I'd try to do some but that it would take me a while as I really needed to finish projects and things. Which I then ignored and played a lot with Mozilla. Eventually final year project needed to be done - an ARM Pascal decompiler (mostly based on what I'd learnt from disassembling Doom and playing with compiling things in other odd ways). The final project was actually completed over the course of about 5 days, pretty much without sleep and comprising a significantly larger amount of work than had gone before. It's all about the research before hand, guys... and if that research happens to involve hacking about at a game, so much the better!

Finally I got around to doing some network drivers - a serial and UDP version, which weren't great but the did the job. Being unfamiliar with writing modules much in C, I used what I'd learnt previously and the newly created AOF output in !JFPatch to create modules which were in C, but had a very thin custom assembler veneer. This also meant that there was some fun with workspace for the application, but after a few attempts I think I managed to work out all the bugs - some versions would just corrupt the RMA blocks following the module in memory because of the badly specified initialisers in my code.

The UDP network driver was pretty simple, based on the original Doom network driver for the PC version. The front end wasn't very easy to use - getting the combinations of players wrong could easily mean that you ended up with a failed game at the very beginning. I seem to remember that you were always 'player 1', regardless of how the game was configured, and the other players needed to be listed in the correct order. I don't exactly remember the way it worked. To make it easier to select players,

I reused the !SiteEdit tool that I'd written for the other network games so that I didn't have to rewrite any hotlist selection code. It wasn't that hard to have added as a library, really, so I could have done that if I'd wanted.

Network games themselves were really fun, once you'd got a combination that worked. It's a little disappointing that I didn't spend as much time on the Doom networking in the real version as the original !jDoom set up tool. !jDoom could broadcast packets to find other users who were waiting for a game, and associate them, automatically organising the players for you so that they would connect properly. The drivers were all dealt with equally, so the front end configuration could set up the serial or UDP (or Econet) driver in a similar way.

The final network drivers that I released were just the drivers and a simple tool that you could type the names into (or use the site selection hotlist from !SiteEdit). Ah well.

Gyrinus II

Application icon for !Gyrinus II
!Gyrinus II

Not long after I'd played with Doom, I was - for a number of reasons - rather fed up, and wanted to do something equally impressive. Nothing really sprang to mind, but I decided to reapply what I'd done with Doom to another game that I'd enjoyed - !Gyrinus2 (as an aside, I'd never seen !Gyrinus 1, and could never find a copy). Anyhow, the idea was simply to reapply the patch I'd done for Doom to run in the desktop to it. Not particularly hard, and the main support module is just a cut down version of the one that I'd written for Doom in the first place.

How do you get off the first level?
What you can't see is that it's actually quite smooth to play.

Doom Front End

Application icon for !Doom
!Doom

RComp released Doom and it was generally quite successful, I believe. Because of the work I'd done in the past on Doom, and Eddie's unavailability, I was asked if I'd like to make an enhanced version - what would become Doom+.

Before I got the source to the game itself, I was given the source to the front end launcher application. This was written in C, and was a very rushed affair, which Eddie apologised for in a note that came with it. He also gave some hints on how the code was structured and the layout of the icons, which was useful in initially familiarising myself with the code.

The source itself was quite well structured, and wasn't actually that hard to find my way around. The first thing I did was replace the Obey files that built it with an AMU makefile, and check the lot into RCS. At the time that I was doing this, I'd finished University and we'd used RCS there, so I continued with it. It was only later when we started RISCOS Ltd that I began to use CVS.

One of the first things that I added was an optional restriction on the modes that could be selected to just those modes that had been given names, and which were able to be double banked. The game required double banked modes in order to work reliably without tearing - and it could use triple banked modes to smooth out the processing if possible.

Later, when I had access to the back end source, I actually added an option to allow single banked modes, which required a fast system or an acceptance that tearing might happen. I favoured the latter for the huge modes - the main reason that I had added the option was to allow the use of the huge ViewFinder modes which could only be displayed single banked, just to show off the fact that the game supported such modes.

The front end had initially stored its configuration inside the application, which was common on pre-RiscPC systems, despite the fact that the game itself was RiscPC only. The original game that Eddie had created worked on an A5000 with slight modifications (as described above), but the released version made no pretence of working on earlier systems. I changed the configuration so that it used the Choices system if it was present, which meant that the game could be run from a Zip disc if it was intended to be run on a static system, or using the global configuration if not.

The Zip disc loading was actually a quite useful solution, as the parallel Zip drive interface was supported by the STB systems that Acorn had been producing. This gave the STB access to much more storage than their memory and network loading could support - a whole 100MB on a disc. This was one of the targets we wanted to work well, and as the STB didn't have a mouse that was of much use, the front end itself would be difficult to use.

It wasn't completely necessary to use the front end at all - you could load all the files and launch the game by directly running the correct binary. However, this then meant that you had to know all the parameters to pass, and it would be more difficult to do as the game developed and new options were added.

To make this easier, I created a smaller launcher that could launch the game by just reading a configuration file and running the right binary. The front end was updated to allow you to save the configuration as an application which included this launcher and the necessary configuration. All the STB had to do was to run the one application and the game would launch with all the configuration set up as required.

Initially the front end supported running IWAD files, together with a fixed number of PWADs that appeared as writable fields in the front end. This wasn't quite as neat as I wanted. Although you could double click the PWAD and the front end would select the relevant IWAD to use, it still wasn't as smooth as it could be. It was actually quite clever - it looked at what type of lumps were in the PWAD file and matched it to an appropriate IWAD. Eddie had done a neat job on making that work. The new pane that I added replaced the 3 input fields and allowed more PWADs to be added, and allowed you to remove them through a 'x' icon.

The checking was improved as well, so that if you tried loading an IWAD for Heretic or Hexen, or the very early betas of Doom, it would give you an error rather than trying to use them and failing badly.

Later there were a whole host of new options added to the front end to support the changes to the real game, but even the early versions of the front end had things like information displays for the PWAD files, and key and miscellaneous configuration windows for setting of other obscure options.