3D Monster Maze is of course the best game for the ZX81. I first played it on my first ZX81 back in 1982 and have loved it ever since. It is amazing what can be created with simple character block graphics.
I remember back in 2017, when I was drawing out the artwork for the PET replacement keyboard, it occurred to me that the PET character set included the same style graphics as the ZX81/TS1000.
Included on the PET are all the half and quarter block character on the ZX81*.
* spoiler: not all characters.
Around the same time, I came across Paul Farrow's reverse engineered source for the 3D Monster Maze. So, I got to thinking, I wonder if I could use that to make a PET version?
http://www.fruitcake.plus.com/Sinclair/ZX81/Disassemblies/MonsterMaze.htm
Now, first off, the ZX81 is 32x24 characters, and the code was a combination of Z80 assembly and ZX81 BASIC. How hard can it be to convert that to 40x25 characters in 6502 assembly? Well, maybe a bit too hard, so I wrote it in C instead to make my life a little easier.
I started with the first screen. Should be fairly simple, some block graphics and text. (The black and white pictures in this post show the ZX81 / TS1000 version, mainly screenshots from the Eighty One emulator. The black and green pictures are output from my new PET version from the Vice emulator)
Then I hit the first problem. It turns out that I didn't have all of the characters on the PET. The one highlighted in red was missing.
It's a character where the top half is 50% grey and the bottom is solid black. The ZX81 and the PET double the number of characters the have in ROM by inverted versions of each of those characters using additional hardware. So the one missing characters is actually two, one with bit 7 clear ($0A), and an inverted version which has bit 7 set ($8A).
It seems the PET has one where the bottom is 50% grey, but not the other way around. I found matches for all the other characters, but not that one. Ah well, it's only one character.
I just swapped that for a full 50% grey square, and moved his hand (it is a hand?) down a bit.
There, you would hardly notice it. I kept Malcolm Evans credit, and added my own. I also replaced the capital i and - characters with solid lines. If I hadn't told you about those changes, you probably wouldn't have noticed.
So far, so good. Is this going to work?
Guess what I found on the next screen? Yes, that one missing character is back again
I guess this is the Ringmaster's nose?
For the PET version, I just gave him a bigger nose.
Again, nothing you would notice. Looks like I am getting away with this. I wrote the text scrolling and screen update routines, and it was sort of coming together.
Then I moved onto the difficult bit. The main point of the game the 3D maze.
The wall in the far distance there, two black squares and one full 50% grey square isn't it?
No, it turns out the furthest wall is made up of six characters, and yes, it needs the one I don't have. In this case, the non-inverted version, 50% on the top, white on the bottom half.
At that point, I must have received a load of orders, or found something new to design. Either way, I put the code to one side with a plan to come back at some point.
...... insert some tumbleweeds here .....
Move forward to 2021, and in the lull between finishing packing all the Mini PET 40/80 kits and waiting for TFW8b to sort out the final packaging and flourishes, I thought it would be good to revisit it and see if I could finish the PET remake of 3D Monster Maze.
I decided the best option was to adjust the geometry. Rather than 6 squares making up the central square, I went for 1. You can see it best on the exit screen. This shows a pattern of random characters which start in the central six characters, and move outwards towards the edge.
For the new PET version, I went for a single central square, and that seemed to work quite well.
In the actual maze, the vanishing point looks fine.
However, I will take the opportunity to make a small improvement.
The PET has some diagonal half squares, and they work very nicely as maze walls.
I have left the ZX81 style crinkly walls as a hidden option.
On the ZX81 version, the score was always blank until you scored anything.
I decided to show the score from 0,
The ZX81 screen is 32 characters wide. The PET is 40. I have centred the screen and added 4 blank characters each side. I also updated my credit and rolled the date to 2021. Happy 40th Birthday 3DMM.
The ZX81 version works by drawing full walls on each side, then drawing in passage ways as required. You can sometimes see this when the screen is being drawn.
For the PET version, I use a double buffering technique, which helps to avoid this. I draw the screen to a 32x24 array, and then once everything is drawn, I copy the whole buffer to the PET screen. That makes it easier to offset it 4 characters from the left to centre things on the 40 column screen, and avoids tearing as much as possible.
Unfortunately that means it is not suitable for original 2001 PETs, as the screen updates will create "snow", caused by the video RAM being written at the same time as it is being drawn.
Something like the classic Space Invaders for the PET only moves one row of aliens at a time, and that fits in the gap between redraws. (the blue blocks show video RAM updates which fit in the gaps between the yellow sections where the screen is being drawn).
I did look at trying to do the screen copy in the VSync gaps, but it takes too long. There are 24 blocks, one for each line. The gap between them is the overhead of the loop and the call to memcpy. The two larger gaps are the PETs interrupt handler where it does it's keyboard scan etc.
Even if I disabled the PET interrupt handler, and wrote the whole copy routine in tight assembler, I'm not sure it would be enough. That the would reduce the gaps, but when it's actually running, I expect memcpy will be fairly well optimised, so the total is unlikely to be less that all of the blue blocks squashed together, and that is still too much to fit in the gap. If I split it into two or three updates, you will get tearing. I could rewrite the whole draw routine to only draw the bits of wall the need to change, but that's a lot of work and may not even be enough as there will always be times when the player turns to face a wall or Rex appears, so there will be snow on the 2001 whatever.
So it is fine on the 4032, and also any 2001N / 2032 / 3032 that have the requisite BASIC 4 and 32K RAM, just not 2001.
One of the concepts I remember from 3D Monster Maze is the "Mists of Time".
What happens here is the ZX81 is switched to "FAST" mode. This is where it stops drawing the screen to it can run code all the time (instead of just in the gaps at the and bottom of the screen), and it does so for about 30 seconds whilst it is generating the random maze. This bit of the code is written in BASIC, and so is quite slow.
For the PET version, I wrote the whole thing in C. I was initially worried that the 1MHz 6502 might be slower than the 3.25MHz Z80, and I might have to hand turn some 6502 code to speed this bit up, but to my surprise it took less that half a second in C.
I update the instructions to reflect that. To emulate the mists (i.e. the ZX81 not producing a picture so you old TV would show snow), I randomly cleared the screen a block at a time, and then revealed the maze a block at a time. That whole process takes several times longer than generating the maze!
The last thing to do was draw Rex.
From the first view to the second last frame of Rex animation, it's all black and white quarter squares, so translates 1:1 from the ZX81 version.
The last frame adds some details, and it is terrifying.
Even more so when you see just how many of the missing character Rex is drawn from.
A bit of artistic license here, moving his right arm up a bit to use whole squares, opening his mouth wider and adding a couple of extra teeth.
Either way. I expect the player is not going to be analysing the detail of the animation at this point.
Hopefully, you will find the exit, rather than Rex finding you. When you go through the exit, the ZX81 version takes you back to the Ringmaster and 30 seconds of the Mists of Time whilst it generates a new maze. Since that isn't required for the PET, I added an effect to have black characters create a tunnel effect for the exit which eventually fills the screen, and then the white square snow effect to the start of your new maze.
There are a few other extra bits I added, but I'll let you find those yourself.
There isn't any sound. I did try to add clumping footsteps for Rex. I also tried a Jaws type theme as Rex was approaching. In both cases, they sounded comically awful on the tiny piezo speaker on the PET, so I deleted the sound code never to be heard from again.
One extra I will tell you about is 80 column mode.
This is split, on the left is the same as the 40 column version. However, on the right there is a Pterodactyl's eye view of the maze. You can see it being initially generated, and then once it is complete, you can see yourself (the arrow showing the direction you are facing), Rex (R) and the Exit (X).
You can also follow Rex's progress as he leaves 'footprints' where he has been. The footprints are in the original code, the maze squares are changed once Rex has been there, although isn't used for anything. I wonder if there was a plan to draw these on the maze screen so you know that you are getting close to Rex?
You can also see that 'Rex Lies In Wait' actually means 'Rex is stuck'. The logic it uses is to move towards the player, along and down, even if that means walking down a dead end. As soon as you move past rex, he can follow you again.
There is also a small view of the maze ahead of the player, so you can see how that translates to the 3D view.
These were both added to help me during development, but I thought I would leave them in, they are useful as a trainer, and also to see how things work under the hood.
3D Monster Maze for PET and Mini PET is available on a cassette tape from The Future Was 8 bit. There is a video on the listing, but no matter what Rod says, there isn't any treasure in the maze. There never was any treasure in the maze. There never will be any treasure in the maze.
https://www.thefuturewas8bit.com/cas022.html
Here it is on cassette with the two original releases of 3D Monster Maze (J.K.Greye software was split into two and 3D Monster Maze ended up with New Generation Software).
There is also a digital download available from itch.io.
https://tynemouth.itch.io/pet-3d-monster-maze
It needs a 32K PET with BASIC 4. Ideally a 40 column screen, or a Mini PET 40/80 so you can run it in 80 column trainer mode as well.
See also a port by George Beckett to the Jupiter Ace / Minstrel 4th
https://github.com/markgbeckett/jupiter_ace/tree/master/3d_monster_maze
Rex lies in wait........