How to Build a ZX81 Ultima Game Part 2: Gem Quest
Three years later, I attempted to build Gem Quest again, but didn’t progress much further.
After sharing Tiles, I started to dig into my previous attempts at building an adventure game. Digging through my past research, I thought about encoding the world differently. Sadly, my experiments using MCODER failed. This spurred me to try assembler again and, to my surprise, build a good start to my game. But first, a trip down memory lane and review my first attempt at building Gem Quest.
Early fits and starts.
After finishing Tiles in 2013, I started research on what the game would be about. Liking the idea of stones or gems, I researched different gemology sites and legends. I found the legends about the Bali and Vala most intriguing. In those legends, the demon’s body becomes the gems populating our world. Combing different ideas, it became the starting idea for my game called Gem Quest.
But, I was stuck on the game itself. Although the game engine was working well, I was already running low on memory. It spurred me to learn z80 assembly. The idea was that I could write the game as machine code. Doing so would give me both speed and memory. I had the title screen working in no time, but I didn’t get much further.
Soon afterwards, I decided to replace my aging Toshiba laptop with a MacBook Pro. The problem is that the development environment I was using, FASMW-ZX, was for Windows. Given the Mac was Intel based, I was able to get EightyOne, the emulator I was using, working in WINE. Yet, I never got around to wrapping FASMW-ZX. As such, my foray into assembler was short lived.
Time moves on.
Three years after my first attempt to build an Ultima style game for the ZX81, I tried to get Gem Quest working again. By 2016, I had a lot of time to dream up new ideas. One thought was about reducing memory by storing the tiles in REM statements. This would make them static memory, which wasn’t compiled. This negating the need for an array and allowed me to leave the BASIC alone. The technique worked well enough, saving me much needed memory.
Contrary to my plans, things after that didn’t go well. I started coding more complex routines. I was able to get some stats working, including a food and health routine. As the food diminished, your health would drop as well. The mechanic worked well enough and the world screen looked better. I even made it possible to buy food and health at the castles.
Even with the memory saving ideas I knew I was going to be hitting the ZX81’s limit. Using MCODER meant I had three programs in memory. The BASIC code for the game, the machine code, and the complier. Although Gem Quest works well as a tech demo, there isn’t much memory left for a real game. Knowing that, I decided I needed to refactor things a bit.
Although I hoped to find some wasted memory, it didn’t seem to help. In fact, the game stopped working altogether. I tried several different rewrites, even using side by side listings. Nothing worked. I even tried adding more memory, using a 48K system. I’m pretty sure that I was executing code outside of the allowed limits. MCODER didn’t offer me much in debugging though.
At this point, Gem Quest fell to the wayside again. But it always was there too. I had loaded Tiles on my site as a tech demo. Yet, being incomplete, I hadn’t done anything with it. I kept thinking about new ways to reduce memory further, but didn’t act on that. Until last month. Working to share what I’d down with the original demo, I thought it time to actually get to work on it again.
Bringing us to the present.
After writing my article on Tiles, I started to think about different ways to encode the world. I knew that I could do stacked compiles with MCODER. I wondered if I could build my game in layers, removing the BASIC code after I compiled it. The hope was this would save enough memory to build a small game. Before getting to that, though, I had another idea to try out.
I was thinking about Ultima and how the world map might have worked. Thinking about ways to reuse space, I wondered if I could place objets using the extra bytes in tiles. The goal was to compress the world array and save more space. Instead of working on the game though, I decided to test that theory by writing a test program. That was where I went wrong, or in the end, right.
My attempt at building a BASIC version of the routine was successful. Using simple math, I was able to save two tiles in one location. It might not be enough for the real game, but it was a start. I then loaded up MCODER to assemble it into machine code. Like before, trouble brewed. The program didn’t work. It complied fine and parts of it did work, but the numbers weren’t matching the BASIC results
Stumped, and frustrated, I decided to give up on MCODER. Instead, I went back to my first idea from 2013, write Gem Quest in Assembler. In a way, my failure set me up for success. I spent the rest of the month working on getting the game engine working. To my surprise, I got much further. In fact, I have almost everything working from Gem Quest, and much more. That, however, is a story for for the next chapter.