MOOB - A fast 3d maze crawler for the C128 on the 40-Column VIC or the 80-Column VDC

Copyright (C) Robert Willie, 2012 <hydradix@yahoo.com>

You are an electron inside the BASIC ROM of the Commodore 128 Computer.  Navigate through the code in the silicon to find an exit door (an RTS opcode), without getting confused by the various branches and loops.  When you pass through an exit, you make a quantum leap to a higher level in the code (you can not return to a lower level).  The area (code size) grows with each new level, making your job more difficult as you progress.

A BONUS timer is initialized at the start of each code area, and it steadily decreases with time until it reaches zero.  The BONUS is added to your SCORE when you pass through an exit, so find the exit as quickly as possible.  Because the higher levels are generally more difficult than the lower levels, the initial BONUS also grows with each higher level.

If you are in a hurry, that is probably all you need to know for now, as you can probably figure out starting and playing the game yourself.  If you have any problems or just enjoy reading, then continue...


STARTING THE GAME
If you have the game on floppy disk, the game will auto-boot if inserted into disk unit 8 when you turn on the C128.  For other disk units, you can issue the command:

BOOT Un

where n is the disk unit with the floppy disk.

If you have the game on a mass-storage device, start the game by issuing the BASIC command:

BOOT"MOOB.BIN",Un

where n is the disk unit where the program is stored.  The ",Un" is optional if using unit 8.

*NOTE* The original Commodore ROMs (with a 1985 copyright date on start-up) have a bug which appears with slow-serial devices (1541 etc.).  So if the computer crashes when you try to run the game, issue this command instead:

BOOT"MOOB.BIN",P12288,Un

The "P12288" tells the defective KERNAL the correct start address ($3000).


PLAYING THE GAME
Use the keyboard or a joystick in port 2 to play the game.  On the start-up screen, press any key or move the joystick to start the game.  A new AREA message will appear (telling you the code size you will navigate) and after about a second, the play field will appear (and the BONUS will start counting down).

The ROM bytes appear as a series of hallways from the perspective of your electron.  Move forward through the code by pressing joystick/cursor UP.  Move backward by pressing joystick/cursor DOWN.  A branch in the code will appear as an intersection of two hallways.  Turn your electron in the direction you wish to travel by pressing joystick/cursor LEFT or RIGHT.

Although not really neccessary, you can also step sideways without turning or moving forward (only possible if there is no wall by your side).  To do this, press < or > on the keyboard (you don't need to press SHIFT).  With a joystick, hold down FIRE and press the stick LEFT or RIGHT.

Navigate through the ROM until you find an RTS opcode to exit the area.  The exit looks like an open door where a wall would otherwise appear.  As you try to move through the exit, your electron will make a quantum leap to a higher level and your remaining BONUS is added to your SCORE.

HELPFULL HINTS
Beginners should try to turn the electron so it is facing straight down a hallway before moving forwards.  This is because when you reach an intersection, your electron will turn the corner if it is turned at an angle.  This is confusing if you are not expecting to turn the corner!  Advanced players should use this fact to their advantage, as you can round corners more quickly.

The keyboard and joystick input methods have different advantages, but you can get a good score with either method if you act accordingly:

- Beginners may want to use the keyboard as it easier to make precise movements.

- Repeatitive movement (continous UP/DOWN or LEFT/RIGHT) is faster with the keyboard than with a joystick.  The KERNAL is used for keyboard processing, so their is a slight speed increase for NTSC users (because it doesn't check system frequency).

- Changing movement (from LEFT to UP for example) is a bit faster when using the joystick and also allows diagonal movement (LEFT and UP to move forward and turn at the same time).  The joystick speed is the same on both NTSC and PAL (as my code does check system frequency).

Moving backwards may be confusing, but it is faster to back out of a dead end than to make a U-turn and move forward.

Try to keep moving at all times!  The game levels and BONUS are designed such that if you don't waste time, you will get a BONUS on every level even if you are unlucky or have never played before.  Wasting time obviously means not moving, but also means going down a path you have already traveled before.

That being said, don't get in such a hurry that you miss an intersection or needlessly go down the wrong path again.  In other words, you can stop a few times for a second without wasting your entire bonus.

If you can't find the exit, it is likely that you are stuck in a loop.  Small loops should be easy to recognize and escape from.  Large loops are more difficult to detect and even tougher to escape (lucky for you, they only occur sometimes in the higher levels).  You will have to think about where you have been before and deduce where you have not gone yet.  On the final levels (area 100+), you may need to draw a map... don't be a quiter!


*** SPOILER ALERT ***
Skip this section if you want to try your own skill without relying on the following info.

An easy way to help navigate any maze is to use a side-wall rule.  Choose left or right at the beginning and always follow that side of the wall.  So for example, choose right and follow the right wall.  If you come to an intersection, turn right if you can or otherwise continue straight.  When you come to a dead end, turn around and continue following the right wall (since you turned around you will be following the opposite wall, although it is now on your right).  Using this method you will always (eventually) get back to your starting position no matter how big and complex the maze.  Usually you will find the exit along the way.

The game levels have been designed so there is no advantage to choosing the left side over the right side, overall.  Of course you will get to the exit sooner if you are lucky and choose the good side.  The good side could be either left or right, depending on the level.  On a few levels, it makes no difference!

The side-wall method will NOT always find the exit.  Basically it will take you along the perimeter of the area, but if the exit is somewhere in the interior you will not find it.  So it is important you realize if you have made a complete loop of the perimeter and then start looking for an intersection that will allow access to the interior of the area.  There is no simple method to do this, aside from creating a map (either in your head or on paper).

Your electron always starts on the perimeter of an area.  The exit is usually on the far side of the area.  Sometimes the exit is really close, but you can not quickly get to it.

The exit is often located on or near the perimeter.  Sometimes the exit is deep in the interior and these are the hardest levels in my opinion (not neccessarily the highest levels).

There are 53 levels and the last is AREA 198.

*** END SPOILER ***


OTHER INFO
Here is some information that may be interesting but not really usefull...

Don't think you can cheat by viewing the source code to find a map if you get stuck.  All you will find is a reference to BASIC ROM.  If you can somehow convert the ROM into a map in your head, then I don't how you got stuck in the first place!

The game plays at the same speed regardless of display chip used.  However, you should see a difference in frame rate (besides overall appearance) between the two display chips.  The VIC can display about 10 to 19 frames per second, while the the VDC can display about 14 to 23 fps.

The input routines generally limit the display to 12 fps when using the joystick, 15 fps using an NTSC keyboard, or 12.5 fps using a PAL keyboard.

More work is done by the CPU for 3D calculations (etc.) than writing to display memory so although writing the VDC is slower, its display is faster because the CPU runs at 2MHz.


MISSING FEATURES
This game was designed for a 4 kiByte competition, so it is missing a lot of features you might expect in a real game.  These include:

- Can not PAUSE, RESTART, SAVE or LOAD
- Can not skip levels (that is more of cheat... but it could be an unlockable reward)
- No high score
- No introduction or level complete animation
- Extremely lame end game animation
- No sound except for lame effects on level complete or bump into wall
- No rewards except for scoring bonus (examples would be a compass or mini-map)
- Single player only
- No enemies (examples could be monsters or a second player)
- No items to be found (examples could be weapons, ammo, magic spells, etc.)
- No obsticles (examples could be locks needing a key or a rock pile needing a bomb)
- Extremely limited graphics (better looking chars and multiple colors would be nice)

The code is open source, so feel free to expand on the game by adding some of these features.  If you do, please share!


DEVELOPEMENT INFO
Before writing any game code in assembly, a BASIC test program was used.  This is included as "SIMP3D.BAS" just RUN it from C128 BASIC.  It uses VIC hi-res graphics and is quite slow.

MOOB was written in 8502 (6502) assembly langauage and was compiled with the publicly available cross assembler "xa" v2.1.4h (c) 1989-98 by A.Fachat on a Windows machine (in a DOS box) using the included (one line) batch file "MAKEmoob.bat"

The goal was a 4K version, and the executible ended up being about 6K.  I tried removing multiple features and compressing, but could not get it under 4879 bytes...  So instead of releasing the crippled version, you get the 'complete' 6K version.  Big time looser!

The rendering speed can be increased by either using fast multiply and divide routines (requiring 1024 and 512 byte tables respectively) or by including pre-rendered data as tables instead of doing any serious calculations at runtime.

The graphics engine was designed to handle a map size of about 60 tiles in each dimension, with a practical limit intended to be 40x21 tiles (area 840) which could be displayed as a map using 40-column char mode or a pair of sprites.  Neither of these limits have been tested because after reaching an area size of about 150, the chances that a section of ROM will produce a 'good' map becomes increasingly lower with bigger sizes.  Because of this, area 198 is the last one in the game (and it took quite a while to find it).

The graphics engine was conceived to have 4 sub-tile co-ordinates per map tile.  Note 64 tiles * 4 sub-tiles = 256 so the tile limit must be slighly less than 64 (as stated above) to avoid single byte overflow.  The engine was first developed with only 1 sub-tile per map tile... in other words the player was always in the center of a tile.  This meant a player could be standing in the middle of an intersection, or farther back in a hallway looking at an intersection, but could not get 'close' to the intersection to peek around a corner.

Expanding the graphic engine to handle 2 sub-tile co-ordinates was not much work for the low-level routines.  A few small tables (3 of them, 10 bytes each as I recall) was all that was needed.  But the higher-level code got totally bloated (and is the main reason it failed to reach 4K size).  The reason is because with 2 sub-tile cordinates, the player is either in the center of a tile (as before) or on the border of two tiles (to peek around corners).

However, if the player is on the border of two tiles, which tile is he 'really' on?  This is an important question because if the graphics engine chooses the wrong tile, it will draw a solid wall instead of an open wall (view down a hallway)!  The same problem occurs when the player tries to move.  If the game does not know the 'real' tile to move from, it can not know the correct tile to move to... which means you could walk through walls or not walk down halls!

The solution is to incorporate knowledge of both the current position (border of two tiles) and the direction the player is facing.  That's the simple answer, but looking at the code, it got pretty messy.  Could use a complete re-write...

Incorporating 4 sub-tile co-ordinates should not require much more work.  Again a few small tables would need to be added (not done) and some extra chars and patterns would be needed (already done but commented out... see 'font.src').  The high-level code should not need much (if any) changes because the new coordinates would be fully inside a tile (no border problems).  The lower level code may need some patching, as the new char patterns have angles greater than 45 degrees.

The graphics engine was developed with debug code (naturally) using the VIC video chip, and there was no delay in the input routines.  This worked at a confortable (although not amazing) 9~15 frames per second.  When testing the VDC routines, I was amazed at the speed.  And when I compiled it for non-debug mode, I thought there was a serious problem with the VDC emulation in VICE.  The game was too fast.  A rare thing for 3D games on an 8-bit computer, and especially so for the notorious VDC chip.  I tried it out on my real NTSC machine, and yes it was WAY too fast!!  Also the VIC version ran noticebly faster in the non-debug build as you might imagine.  Long story short, I had to add slow-down code in the form of input time limiting.

Almost forgot... if you change the line near the top of MOOB.SRC to read 'DEBUG = 1' and recompile, then you get a few neat options.  If you run the game in 40 column mode, then it will display a map of the current level on the 80-column screen (real handy for testing).  You can press SPACE to skip to the next level or X to go back to the previous level.  Pressing a number on the keypad will teleport you to a tile on the map border (for example, 8 will put you on the north border half-way between east and west borders).  The 40-column screen will show the current (untranslated) coordinate at the bottom left and translated coordinates twice near the center (top for horizontal trace, bottom for vertical trace).  These will 'flicker' as they are drawn to only 1 of the 2 graphic buffers.

Further, if you change the line near the top of MOOB.SRC to read 'LV_DEVELOP = 1' and recompile, then you get more options.  You should run the game in 40 columns so you see the map in 80 columns.  The map will show the base ROM address.  Press + or - to increase/decrease the width and press @ or * to increase/decrease the map height (these options reset the ROM pointer).  When happy with the size, press SPACE to scroll through ROM by one row (x-size bytes) or press X to scroll through ROM by one column (1 byte).  When you find a map you like, press a number on the keypad to teleport to a tile (see above) then you can test it on the 40 column screen.

Of course you could hand-make your game level (there is an example commented-out in 'MAP.SRC') instead of calling 'GenMap2' which builds one from ROM.

Stop reading and play!
