Dungeon Crawling

So… In the last post I mentioned working on some TI-99/4a side projects. Well, I have finished one! 🙂

It is a 3D dungeon game called “Wizard’s Doom”, a spiritual sequel to the “Wizard’s Lair” and “Wizard’s Revenge” games developed by Rainbow software in the mid 1980’s.


“Wizard’s Lair” was the first TI game I personally bought with my own money, ordering it from the Triton catalog. It was one of those things I would anxiously check the mail for every single day. I let out a literal whoop of excitement the day it arrived. 🙂

And what about the game itself? For a game designed to run in TI Extended BASIC with no disk system or memory expansion, which means it had about 13k at most to work with, it’s pretty good. The game runs at a decent speed and has greater depth and nuance than most games produced for the TI-99/4a at the time. It was definitely worth money! The sequel is essentially the same game but with better graphics and some new twists.

The manual is very professional; the cover artwork is amazing and as far as I can tell, original. I can’t read the signature in the corner to determine the artist, but I’ve never seen it reproduced elsewhere. The manual was also not a cheap photocopy job; you can tell this because the cover has ink all the way to the edge, which is only possible if you printed it on a printer at 9×12 size and cut it down. And the cassettes and diskettes for the game had a shiny embossed label in two colors.

The games are a derivation of “Dungeons of Daggorath”; they share the same plot and basic game play. However, in comparison to that classic game, they are laughably simple… Granted, Dungeons of Daggorath is written in 100% assembly, so it has an advantage.

After 30 years, I thought “Why not write a sequel to Wizard’s Lair and Revenge? One that actually plays more like Dungeons of Daggorath in terms of depth and challenge? And uses a disk system and 32k RAM for maximum play-ability?”

And that’s how the project started…

Initial Design and Prototyping

The first step was to write my own maze generation algorithm. I’ve done some of this previously with experimenting doing a Rogue-style game, and in a Java project I did back in college over a decade ago.

The basic algorithm is: Create a 2-dimensional grid of empty squares. Pick a square, random or determined, mark that square “open”. Try and move in a random direction, and if you can, open the new square and make a connection between it and the prior square. You can either always look for empties, and back-track if you can’t find any, or just go through occupied squares. You can stop either when it runs out of chambers or have it track how many it’s created and stop arbitrarily. You can generate a lot of different styles of mazes with just a few simple changes to the algorithm in places, and it’s easy to seed with a fixed random value to generate the same maze time after time.

Studying Wizard’s Lair, I was amazed at how slow the algorithm was. It takes it several minutes to generate a maze, more than ten at some points, and other times it’s oddly fast. Part of the reason is the code infrastructure is sloppy with a lot of GOSUB and GOTO’s involved, rather than a clean linear approach. The other issue is that it doesn’t handle dead-ends well; if the maze is plotted without running into any other chambers it goes pretty quick, but once it has to deal with dead-ends it slows way down.

I wanted a fast generator, because I wanted each level to get progressively larger as you descended. I also wanted to use bit-wise operations to store directions in each chamber, which is much more efficient. (So the 1 bit becomes “north”, the 2 bit is “east”, and so forth.) I also added tracking for all open chambers by putting their row and column values into two strings. That gave me a record of chamber locations for backtracking, as well as placement of random monsters and items.

For dead-ends, I had to figure out how to handle them in a quick and efficient way. I wanted to keep the mazes from becoming too “single path” oriented, where one way just leads to a dead-end, I wanted 4-way crossings to be more common. So I put in a random check to determine if it backtracked to a prior chamber to look for new empties (using the chamber location strings) or if it just forged through an already open chamber. It also only tries once to backtrack; if it fails to find empties a second time it automatically plots through an open chamber. Playing with the randomness, I narrowed it down to a value that seemed to work and generate decent mazes that had the aesthetic I wanted.

After creating the maze, I wrote up the code to generate the 3D view. I wanted it to be faster than the original games were (which were okay but not great), but I quickly ran into problems…

The truth is, TI Extended BASIC is not very fast with video operations. At all. Drawing characters on the screen with HCHAR and VCHAR is decent in a single statement, but the overhead of calling multiple statements is much slower, creating visible drawing artifacts. I tested using static DATA statements to store positions for drawing, but it was no faster. In fact, the probable fastest method is to do direct stacked lists of call commands that use no variables, only static values.

I had some more complications as well… While doing some graphics design, I decided I wanted to use brick patterns for the dungeon walls. For the far off and middle-range bricks, I only needed two repeatable patterns. But for the close-up view, I wanted to do 2×1 size bricks, which meant I had to alternate the pattern every other row. I tested using DISPLAY AT for this and it worked, but was so slow… Taking tens of seconds to draw your view was just not acceptable.

So this got my mind going another direction… why not use assembly language for the drawing routines? And maybe more…

Assembly and BASIC

Let me give you a bit of background on this subject…

TI Extended BASIC has always had the ability to support assembly language routines. 25% of your memory expansion is actually inaccessible to Extended BASIC except via assembly routines; the 8K lower RAM area. A command was supplied (LOAD, which also doubled as the POKE command) to load assembly files directly into the 8K RAM, where you could then call them using the LINK command, passing values back and forth to assembly language routines.

However, the documentation on setting up assembly language subroutines for BASIC and Extended BASIC is, well, absolutely awful. All the information is actually in the Editor/Assembler manual but it’s so hidden that you’d never find it unless you knew what you were looking for. Also, TI Extended BASIC and TI BASIC are two separate environments (three, if you included TI Extended BASIC with and without memory expansion), and the documentation is hazy at times about the differences.

The first big issue is figuring out how to pass data into an assembly routine. This is where things get messy because you have to be familiar with how Extended BASIC stores data on the stack and how to determine if the value is a static, numeric, or string. The original documentation recommends using a library package TI provided for all your access needs. But it’s an enormous waste of generic code designed to handle every potential combination, eating up a good chunk of that 8k. Plus, TI didn’t provide source code, only binaries.

The second issue is dealing with the character set bias. TI BASIC and Extended BASIC relocate the ASCII table upwards by 96 characters because they had to make room for other things in video memory in the lower character values. As a result, any characters you want drawn you have to add 96 to in assembly.

It took a lot of reading of documentation, and even experimenting in the emulator with the debugger screen to look at memory addresses during execution, but I finally figured out how to write my own routines to extract static and variable values from a passed LINK call. It helped that I only needed numbers and not strings. I then wrote up my own video plotting routines to draw the maze sections, using a passed numeral value to indicate which section and if it was a wall or corridor, so it could branch to the appropriate routines. And it worked beautifully!

My first design used an internal buffer approach. It would draw in the buffer and not on the screen, and then output the buffer to the screen after it was completed. To my surprise, this didn’t work well. While navigating the maze, you’d push a direction button and after a notable pause, the view changed without any warning. I realized that the lack of a “feeling” of movement was the problem.

So I altered the design so that the BASIC code just calls LINKS for each section, essentially replicating what the original games did, just replacing the HCHAR and VCHAR calls with a single LINK. Testing showed that the movement issue was solved; you saw the corridor being drawn but it was acceptably fast and you had a definite sense of responsiveness.

The last issue with assembly routines in BASIC is loading them. The manuals advise you to use the LOAD command, which does work… but it’s incredibly slow. I only have around 2-3k of assembly code and it took several minutes to load in this fashion. It only needs to be done once at the game start, but having to wait 4-5 minutes for the game to finish loading isn’t cool…

Fortunately, another 99’er solved this issue years ago. Barry Boone wrote the Systex loader, which lets you take your assembly routine and merge it into an Extended BASIC program. The typical approach with Systex is to write a “loader” program which just runs your main program. You embed your assembly routines in that loader, and you’re good to go! It also has the advantage of obscuring your assembly binaries from casual viewing.


The other advantage of going to assembly routines was I could do something else I truly wanted… monsters bigger than the original single sprite that was in the first two games.

Wizard’s Lair and Revenge used a single 16×16 size sprite for monsters; the first game even used the same monster graphic (an impish creature) for every monster in the game. This works all right, but the monsters appear very small against the larger large 3D dungeon window (which takes up more than 2/3 of the screen.)

I had already been considering using more sprites for monsters, but moving to assembly was necessary to make it a viable option.

Why? Well, TI Extended BASIC can handle sprites, but typically only when you’re just doing one at a time. The manual specifies you can control multiple sprites in a single command. But in implementation they are NOT in sync with each other. For example, telling two sprites to move at once, you can see that the second starts moving after the first one starts.

The problem is that the subroutines provided actually process sprites one at a time, doing a full video read and/or write, then looping for the next one. This makes multi-sprite operations where you either want them to be alongside each other or over-lapping very difficult to manage. In assembly, things can be done quickly and in blocks, which makes sprites move instantly, change color instantly as a group, and so forth.

I had one other issue to solve though… TI Extended BASIC has a very limited character set, and that limit still applied even in assembly. I decided to do pattern swapping when a monster was on screen so I could have the best number of 16×16 patterns (eight) available. This meant that items and other sprites that appear in dungeon corridors wouldn’t be available when a monster was present. I decided it was worth it for the better graphics. I also used the same technique when drawing the map of the dungeon; swapping out character sets so I could show a more better detailed map than the original games.

The monster graphics themselves turned out to be a bigger job than I’d imagined! I didn’t want to copy any existing game’s graphics, so I decided to draw them myself.

I started with the wizard on the cover of the manual. I drew some boxes on him and tried to approximate the pixel locations. Funny enough, as I worked, either my natural artistic ability came out or I just got lucky but he slowly changed to be slightly angled in profile.

The end result was very nice, so I decided to extend it to every other monster; find a picture online (thank you Google images!) and draw boxes on it and plot them out. Nearly every monster ended up looking radically different from their original artwork. So I didn’t feel like I was “stealing” anyone’s work, more that I was inspired by it.

Abandoned Ideas

With any project, you occasionally have an idea that doesn’t make it in… mine in the case of this project was the Speech Synthesizer.

I wanted the wizard to give an evil laugh when the player reached level 6, just to freak them out. When you actually found the Evil Wizard, he would say “Die fool!” when either you or he initiated combat. Possibly a scream of “Noo!” when you defeat him. And finally, anytime the player died you would hear the wizard say “And yet another does not return…” My own little homage to Dungeons of Daggorath. 🙂

Unfortunately, creating speech on the TI-99/4a is incredibly difficult.

The first obstacle is finding software that will record audio in mono. (The TI’s sound chip is not stereo…) The second obstacle is to find software that will convert the audio file into LPC encoding that the synthesizer understands.

Fortunately, the engineers at TI who worked on the synthesizer went on to found their own company years later. And they wrote software in DOS to create the speech encoding for a variety of chipsets. The only hitch is it was packaged with a blueprint for a slightly later model of the speech core. This creates some slight misalignment but it’s surprisingly close. It also only available as 16-bit binaries, which means can’t be run on a 64-bit PC. (32-bit will go back to 16-bit, though.)

I did get test speech working, both in emulation and on the actual hardware. But a host of issues cropped up with it…

The first problem was it was very quiet on the actual hardware, as opposed to the emulator. After puzzling for awhile, I realized I’d recorded my voice using a crappy laptop microphone in an open room. So I had to re-record, keeping my mouth close to the mike. This worked, but the software I had to convert it to a mono audio file kept messing up from the volume of the recording, creating a static sound. It took a lot of tries to get a clean audio file.

The second problem was the LPC encoding. It generated a text file containing all the bytes, but it was HUGE. An evil laugh took over 600 bytes alone. My intend was to embed the code into the 8K RAM rather than load on the fly, but I was concerned at running out of memory to even store the four phrases I wanted.

Final problem… I hated how my voice sounded. I don’t have a naturally deep voice, so it was very difficult to get something that sounded like an evil wizard, and was scary. Part of that may be my bias against my voice, but still… it just sounded lame.

After all of that, I decided I would just forgo speech in the game.

Original Game Mechanics

When designing game-play, my first step was to investigate the original games and how they worked. Both Wizard’s Lair and Revenge have nearly identical design.

Wizard’s Lair has a fixed number of chambers per level, the maximum on level 4 is 45. The actual mazes can be up to 8×8 in size. Wizard’s Revenge, possibly to save memory, only has mazes that go up to a maximum of 6×6 in size. That also means there are less monsters and items in the second game.

There’s no hit mechanic in either game; you just deal damage when attacking and take it in return from monsters. Your attributes also take damage with every attack, but at a much smaller scale. (Which is why the manual notes that you may observe your attributes drop in value against “stronger” monsters…)

Monsters only have two attributes of note, their name and their power level, which is both their health and their amount of damage. The Evil Wizard has the highest power level, plus any spell that would kill a monster outright doesn’t work on him.

Items and monsters are populated off of static data lists. Each item or monster has a specified count and a minimum and maximum dungeon level they are on. Because the games were written for a 13k cassette environment, they don’t try and optimize by loading the data into arrays; instead they just read the data statements as needed. This creates the interesting effect that when moving into a new chamber, it takes notably longer for certain items to appear on the screen than others. (As it has to read/search all the data until it finds the one it wants.) Traps on items have a small percentage change of being generated.

In both games, treasure is used solely to increase “treasure points” which is used to calculate your final rating. You can essentially skip every treasure chest in Wizard’s Lair if all you care about is defeating the Wizard. In Wizard’s Revenge, chests also store food on the last few levels, which restores health. Experience points have no effect on your character at all in either game, they’re only used for ratings calculations.

Wizard’s Lair doesn’t have exits to the next level. Instead, you move on to the next level anytime you want with a command or you automatically descend after a certain amount of time has expired. If you are on the last level when this happens, you lose the game. Wizard’s Revenge got rid of the time factor and added exit chambers, a change I agree with.

Both games have some interesting fun things…

Wizard’s Lair has three separate spells that get rid of monsters immediately; VANISH, DEATH, and GRAVITY. The latter actually levitates the monster off the screen! None of them work on the Evil Wizard.

Wizard’s Revenge has very interesting traps beyond just impacting your attributes and health. One creates leeches in your backpack, filling every available space, forcing you to waste time dropping them. Another teleports you to a random position in the dungeon. And one creates walls blocking you in your current chamber; you have to attack the walls and break them down to escape!

Wizard’s Revenge also has a new instant death spell, MEDUSA, which literally turns the monster to stone. You can even leave and return to the chamber and find their statue there. (Obviously, that one doesn’t work on the Evil Wizard.) There is also a CARPET which will whisk you to the next level immediately when used. (If used on the last level you lose the game though.)

I’ve played and won both Wizard’s Lair and Wizard’s Revenge of course. A typical game takes an hour or two. The games are pretty challenging due to the randomness. The first game in particular has a pretty steep curve of power for monsters; you’re feeling cocky finishing level 1 with a club and leather shield and suddenly on level 2 you’re facing an ogre or mummy and getting pounded into oblivion. The Evil Wizard himself IS a challenge but not overly so; I found that so long as you had a magic shield (using a spell) you could beat him fairly easily.

So now on to what I want to do…

Game Goals

Early on, I wrote up a list of things I wanted in my game:

  • Character classes, so you could play the game in different ways
  • Six levels, each one progressively larger than the prior one
  • A much more useful map that shows the exact layout of the dungeon
  • A hit mechanic to go with the damage mechanic, to make combat more complex and nuanced
  • A separate spell system by which you can use magic points to cast spells. Spells now become scrolls that can be written into your spellbook or used to cast the spell
  • A greater variety of items and individual items to use
  • A greater variety of monsters, with unique abilities and graphics
  • State tracking for spell and trap effects, both positive and negative
  • A truly powerful Evil Wizard, who can actually cast spells and has a few tricks up his sleeve…

I’m happy to say I was able to implement everything I wanted and I still ended up with around 3K of memory left in Extended BASIC! 🙂 The only additional feature I added was a save/load game option. This came about due to feedback from a good friend play-testing the game, who noted it was taking several hours to complete and that a save game feature would be handy.


This was probably the most challenging part of the design. After the game was finished, I had to fine-tune the mechanics and make sure the game was winnable.

I was impacted by an earlier game of mine, which I discovered LONG after the fact was not winnable. The final level was relying on some game physics I’d changed without realizing it would impact it. I promised myself in my future games that I would make certain they could be won before releasing them.

It took a great deal of time to get the game to a playable state. I discovered early on that it was pretty easy to make the game TOO difficult. Part of the problem was that as the designer, I am fully aware of the mechanics and of how things work, how to use items, and so forth. As a result, what seems a challenge to me is flat out impossible to anyone else! I had to scale the game back to the point that I felt slightly bored with it to get it just right.


Since I was writing a spiritual sequel, I also wanted to create a manual for the game, modeled to look exactly like the first two game’s manuals. I intended to have a PDF copy of the manual AND to print a few copies, one for myself at least. 🙂

First, I scanned the original Wizard artwork as well as the graphics for the logos and other things. I then constructed the layout in Microsoft Publisher, and wrote up the text. Since my game was considerably more complex, I ended up with several more pages.

The main font used for the text was easy to discern; Helvetica, although I had to download it for Windows from a 3rd party site. Figuring out the font used for the title was harder; I eventually hunted it down as Parsons. Publisher has an option to publish documents at PDF files, which I took advantage of to create the final templates for printing.

Because the outer cover has ink all the way to the edge, I had to find a local print shop to print the covers. Fortunately I found a decent place right in town, the only tricky bit was getting my proofs and finished materials before they closed. (No weekend hours and closes at 5, usually when I’m on the bus home…) I considered the process to be a nice trial run for when I get manuals created for my CRPG.

I had 20 copies of the cover printed. In retrospect, I was probably optimistic on the count; I offered anyone who wanted a manual one for the cost of postage, and ended up selling maybe half-a-dozen. Oh well, I still have some if anyone wants one…

Final Thoughts

I quite enjoyed the experience of writing the game. It really came together exactly as I pictured it would! And expanding my knowledge of the TI’s capabilities with assembly routines and BASIC was very awesome as well.

I’m waiting now to hear if someone else has won the game. Regrettably, I’ve gotten little feedback, positive or negative… I suppose when you write a vintage game you should be happy for what you can get though.

I also discovered recently that another game already had the title I’d chosen… Wizard’s Doom is also the name of a Commodore 64 action/strategy title game. There was a lot of overlap in game titles back in the 80’s, so I’m not too worried about someone surfacing and filing a lawsuit over the name. 🙂

And my final challenge to anyone who has read this to the end…

Dare ye enter… and deliver unto the Evil Wizard his final doom?

Download: TI Game Shelf

Link: AtariAge thread on Wizard’s Doom

Link: CRPG Addict’s Review of Wizard’s Lair/Revenge/Doom

This entry was posted in Coding, CRPG, Design, Screenshots, TI-99/4a. Bookmark the permalink.

14 Responses to Dungeon Crawling

  1. Jose says:

    Thanks for your nice game. I’m really enjoying it so far.

  2. Alessandro says:

    Very nice!!

  3. Atantuo says:

    The CRPG Addict brought me here, and I’m glad he did. Just for fun, I taught myself Basic in school (~15 years ago) and dabbled in programming here and there since, never getting far past the very, well, basics. Needless to say anything you described in this post is lightyears out of my league, but I think I understand the underlying principles enough to appreciate your work. It certainly helps that I’m also a (C)RPG enthusiast with a particular soft spot for fan-made games. In short, this was a fascinating read, thank you!

    I’ll also make sure to actually try the game once I find time, as I’m completely unfamiliar with the system/emulator.

  4. This looks pretty rad and amazing you basically made a game that could have been made at the time! But did it better.

  5. Bob Pellegrino says:

    Hi – I’m Bob, owner / operator of Rainbow Software. I’m flattered that you liked my games as much as you did! I was just talking to a friend of mine, telling him about the games I wrote years ago and showing him the Triton catalogs I have from the mid 80’s, and he happened to look it up online and found your link and sent it to me. I was pretty shocked to see this LOL. I sold quite a lot of these games back then. It was a joy writing them, especially the satisfaction you get when it is all done and you play test it and it all works! I still have all my TI99 stuff in my basement, including lots of unsold games that were left over when the TI market crashed. By 1989 I had around 6-7 different games selling in the Triton catalog. I wrote a “Spritemaker” utility for the TI as well to simplify designing the graphics. I also wrote a lot of Commodore 64 games and utilities which I sold as shareware online through QuantumLink (Q-Link) using my own “share-lok” system (which was written up in RUN magazine!), and also which I sold through a company called Loadstar, a subscription disk company with a pretty large customer base nationwide. I still have my Commodore 128 and disk drive as well, along with all the games and programs. Unfortunately I only have the ability to load programs into my TI on cassette as I never purchased a disk drive back then. I actually sent my master cassettes to another company who mass produced the floppy disks for me. But I’d love to try your game sometime if possible! The Wizard’s graphic on the cover was original artwork done by a friend of mine who was a graphic artist, who also did my logo. I created the instruction books on my friend’s Apple Macintosh word processor. Yes it was Helveitca, can’t remember the other font but you may have it corrrect. As you know, it was not easy writing for a 16k machine – I had to keep renaming my variables down to one letter names to save bytes and the games ran with only a couple of bytes available without crashing. For some of my Commodore stuff I used a compiler to make thing run faster and smoother. Nice to touch base with you!

    • Adamantyr says:

      Hi Bob!

      It’s good to see you! I’m glad you’re flattered and not upset at my homage. 🙂

      The easiest way to play the game would be to use an emulator. Classic99 is the one I wrote the game in, and it works very well.

      I’m glad you find out more about Rainbow software and the creator. Thank you for writing it all those years ago!

  6. Opry99er says:

    Great game Adamantyr. 🙂

    And it is very cool to have the original author of the series comment on your tribute game.

    I second Classic99, Bob… no fuss… just download it and go.

  7. Ethan Roberts says:

    I know I am commenting on a really old post, but I need help.
    I have never used any computer older than a 386, but I would really like to try this game.

    How do I make Classic99 do that? Following internet instructions, I got it to play “Tunnels of Doom”, but I can’t get WizDoom.dsk to work.

    Where do I put the file? How do I make the emulator think it is a disk? Once that is sorted, how do I run it? What else does a firdt-timer need to know?

  8. Ethan Roberts says:

    I wanted to post an update. The kind folks at TIGameShelf helped me get it running. (Walid is the MAN!)

    Here is what I needed to do in case anyone else stumbles across this like I did, and needs help with Classic99:
    1. It does not matter where you put WizDoom.dsk
    2. In the menu, go to Cartridge-> Apps -> Extended BASIC.
    3. In the menu, go to Disk -> Dsk1 -> .\Dsk1\
    4. Change the Disk Type to Image (DSK)
    5. Hit the Path button and select WizDoom.dsk
    6. Hit ok.
    7. Hit any key, then choose “2. Extended BASIC”.
    8. If like me, you are not used to this vintage of games, wait. It will take longer than you are used to. It is worth it.

    There are other things I found that you can play around with, like volume of the beeps, CPU speed, stretching the play window, etc…

    Adamantyr: I am really liking this game and I look forward to your CRPG when it is finished!

    • adamantyr says:

      Excellent, I’m glad you got it working!

      One warning, classic99 won’t allow you to save games to a disk image. If you want to be able to save your game, search for TI99Dir (a directory tool) and you can use that to extract all the game files directly into the DSK1 folder.

  9. Ethan Roberts says:

    I made it to level 4!
    But then I got pinned down by a flying sword that was immune to all my attacks. I guess I should have gone with a spell-slinger! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *