Wednesday, 30 July 2014

Summer Retrochallenge 3: Techniques for "Shoehorning" Classic IF into the MC-10

One of the things I’ve enjoyed doing with the MC-10 is converting a bunch of classic interactive fiction (IF) games to run on it. I’ve described elsewhere the speedy 4 line word wrap routine I developed to facilitate this process. It completely frees one from one of the most tedious aspects of converting text message intensive programs, such as IF games, which is formatting text string output. It can also save memory by eliminating redundant white spaces often used to accomplish this task. However, one of the other hurdles of converting IF programs is how to accommodate the large amounts of data, such as text strings, and also numeric data, that such programs typically include. I want to share two techniques I have developed that have allowed me to port some classic IF programs, which were developed on machines with more than 16K, such as memory enhanced versions of the TRS-80 Model 1, 48K Atari, or the C64. Using these techniques I have been able to squeeze these games into the more constricted 20K memory space of the MC-10

Lots of DATA
The first technique is to remove the largest sequence of DATA statements that are read into a numeric array and replace this with reading a file from cassette directly into the array. This technique uses a command that as far as I am aware is completely unique to MC-10/Alice Basic: CLOAD*VARNAM, “FILENAME”.  This command can be used to easily read any numeric array from tape (or disk file when using the VMC-10 emulator).  This technique can save large amounts of memory because it eliminates all the redundant DATA statements, which play no role in a program once their information has been transferred into an array using the READ command.  In other words, it prevents the numeric data from having to be held in two places in memory at once--array variable memory space and as DATA statements in the program listing itself.  Since this special command can only be used with numeric arrays and not string arrays it can only be used to help remove redundant numeric data.  However, I have found that many IF programs, especially those of the classic IF author Scott Adams, typically use large amounts of numeric data to encode the complex movements between locations, so this technique can still be very helpful.

Dr. Who
In some cases, such as in my recent port of “Dr. Who,” I was able to combine various different arrays into one, and then use offsets for the added arrays.  For example I could take arrays A(10), B(10), C(10) and turn them into the single array A(N), A(10+N), A(20+N).  Such a process is not as tedious or time consuming as you might think, as you can simply use the Search and Replace function of your text editor to change the names of the added arrays and add the necessary offset number.  For instance, in the above all, I would have to do is search for all instances of “B(“ and replace these with “A(10+”.  By doing such combining, you can keep the extra file load to one instance at the start of the program.  One of my large IF games will therefore typically have two files such as PIRATE1 and PIRATE2 (Scott Adams' second adventure). You can see below that after running the program file PIRATE1 the user is prompted to load “the second part” consisting of the file “PIRTATE2”.

PIRATE1 and PIRATE2
The second technique I have developed allows me to deal with the redundancy of reading a large number of text strings from DATA statements into text arrays.  Again this leads to the information being stored in two places in memory at once (the DATA statements and the space reserved for the text array variable).  What I do is to change a specific long sequence of such strings to a “read on demand” sequence of DATA statements.  When any specific string is needed, you simply call a subroutine that uses the RESTORE command to reset the READ command to start from the beginning of the DATA statements and then READ into a single variable as many times necessary to get to the desired text string. This sometimes requires rearranging the DATA statements so that the sequence of strings is at the front of the list of all DATA statements. This is necessary because Micro Color Basic's RESTORE command doesn’t allow you to select the program line you want to the data pointer to be set to. There is a little sacrifice of display speed using this method, but this is partly offset by the fact that the MC-10’s Basic is a little speedier than many other Basics. Also, you can use the other speed techniques I have discussed elsewhere, such as using single character variable names that are declared first in the list of variables for doing the work of such a subroutine.  Also, you must remember to do a “dummy run” for the entire list of strings at program startup so that any additional  DATA statements can be read and stored as usual.

Using these techniques I have been able to shoehorn a number of classic programs into the 20K of my favourite little 8-bit machine:
Scott Adams
David Malmberg
Tim Hartnell
James Smith
The following is an MSWord VisualBasic macro that I use to search for PRINT statements and replace them with the assignment of the string to the variable M$ followed by a call to my Word Wrap routine (GOSUB1):

Sub Macro3()
'
' Macro3 Macro
'
'
    Selection.Find.ClearFormatting
    With Selection.Find
        .Text = "print"""
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
    Selection.TypeText Text:="M$="""
    Selection.Find.ClearFormatting
    With Selection.Find
        .Text = """"
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
    Selection.MoveRight Unit:=wdCharacter, Count:=1
    Selection.TypeText Text:=":GOSUB1"
End Sub

Monday, 28 July 2014

Summer Retrochallenge 2: "Big Red" A Micro Color Basic 3D Monster Maze

I have always been fascinated by the ZX-81 computer because it was the template upon which the MC-10 was based. The MC-10 was obviously meant to appeal to the same kind of extreme low budget home computer market of the early 80s.  By 1984 that market had dissipated.  Yet MC-10 users like myself looked back to that brief period of budget computing as a sort of "golden age."  Budget machines like the ZX required monumental levels of ingenuity to overcome their intrinsic hardware deficiencies. One of the greatest examples of such ingenuity was 3D Monster Maze:
I have wanted to create a version of this program for the MC-10 since learning about it through magazines in the mid 80s. However, not knowing machine language, it seemed unlikely that I would ever be able to make anything even remotely like it. Still, I always kept my eyes pealed for Basic 3D maze programs with the thought of possibly tweaking one to create an environment for some kind of denizen like the terrifying T-Rex of 3D Monster maze. Such searching lead me to port several 3D maze programs:
Rat Maze by Ben Brunotte
3D Labyrinth by Dieter Fryer
Both of these programs had specific problems. Rat maze was converted from a hires Coco program and so I used the special lowres 64 X 48 mode of the MC-10 to more easily convert the hires 256 X 192 graphics (each axis only had to be divided by 4). However, this special mode only had two colors and additional difficulties (it required complex pokes to use) that would make it difficult to create a fast animated arcade game. Also, the code was very difficult to understand. 3D Labyrinth by Dieter Fryer was a conversion of a VZ-200 program that also used a higher resolution graphics mode. I was able to convert it to lowres 64 X 32 graphics, but like Ratmaze, these on the fly conversions sapped the speed of the wall rendering. The wall "texturing" (which looks more like that of 3D Monster Maze) also added complexity to the code. For both programs the complexity and conversion issues seemed likely to leave little room for adding an additional layer of a real-time arcade quality action to the program.

Finally I discovered a very simple 3D maze engine for one of the late 70s text only hobby computers programmed by Don Scales in 1980. It was also called "Labyrinth" and was made for a machine with a limited resolution that converted easily to the 32 X 16 text screen of the MC-10. I was able to get it running after dealing with some issues regarding integer division. Part of the rendering took advantage of the fact that the numeric variables of the Basic of its native machine (I can't recall which now) were integer only and that concatenation automatically occurred whenever division occurred. After realizing this I was able to put in some INT commands where they were needed in order to get it to render 4 levels of depth:
Labyrinth by Don Scales
Because it was a very spartan and simple wall rendering engine it was an easy process to shift the wall graphics from text to the lowres color block elements of the MC-10 and there was enough speed in the rendering of the walls to allow for speedier arcade quality movement and the addition of the code needed for a simple AI and animation of an enemy. I chose a "killer tomato" because drawing such a figure would be much easier than the complex artwork of "Rex" from the original 3D Monster Maze. Here's what I ended up with:
It may not quite be up to the shock horror level of 3D Monster Maze, but for a Basic program I think it's pretty good. I added a complex high score screen which reports the progressive success percentages of different players so my son and I could play alternately for the highest success rate at avoiding "Big Red" (as we came to call the tomato).

Unlike the original, this program draws a true maze (there is only one way out) so its possible that you can find yourself stuck with having to get past Big Red. We left it this way after some consideration because Red was still too slow to make the game an exercise in sprinting away from him until one could find the exit. Instead, one must carefully search for the way out, while avoiding being eaten by Big Red. Then, if the player determines that Big Red is camped out on the way to the exit, we made it possible for you to "lure" Big Red into following you (if you can keep ahead of him). If Big Red "sees" you (i.e. if you see him) then he will turn and come in your direction. However, when you can't see him he generally (but not always) travels in straight lines until he hits a wall, at which point he chooses a new random direction.

Since the MC-10 has sound, you get a sequence of progressively higher pitched beeps once he comes within 4 squares distance of you (any direction). This is in the place of the classic messages of the original such as "you hear footsteps" and "Rex sees you", etc.  I think of the beeps as the sound that Big Red makes as he bounces along the hallways...

Anyway, the following video will give you a sense of the game play:
And greetings to all the other folks doing Mark Wickens' Summer Retrochallenge! Check out his site to find out more about their projects and about the growing on-line retrocomputing community.

Sunday, 27 July 2014

Summer Retrochallenge 1: "Temple of Apshai" for the MC-10

Richard V. from the Netherlands suggested on the Yahoo MC10 group that the classic 8-Bit Basic game "The Temple of Apshai" might be a good prospect for porting to the MC-10. He posted some of the source code. The game, made for the TRS-80 Model 1/3, did look like a good prospect. It only used what seemed like simple SET/RESET graphics.
I've described in another of my posts (TRS-80 Model 1 Homage) how converting such graphics usually only involves halving the X coordinate and reducing the Y coordinate by a 3rd since the Model 1 has a 128 X 48 low res screen to the MC-10's 64 by 32 screen. One loses a little detail, but then again one has available the MC-10's 8 colors for each of the blocks, which can sometimes be used to recoup some of the detail that might be otherwise lost. Also, Model 1 games often only use 16K, an early baseline standard, which gives the MC-10 programmer 4K extra to fiddle around with.

And I needed that extra memory because Apshai is a very cleverly programmed game that used all the memory resources of a 16K Model 1 to the max, and then some. It is a game with 4 separate levels of some very complicated room maps, each filled with specific monsters, traps, secret doors and treasures.
It takes a lot of data to store all that detail.  Each level therefore was saved as a file of bytes, which could be loaded separately. I had to use a Windows utility for loading and editing Model 1 files to get at this info.  I was able to copy it into a text editor, where I massaged it into DATA statements that could then be used to create files loadable by the MC-10. I also had to create a special utility to translate hexadecimal digits, since this is the way that the PC utility presented the info.  The MC-10 doesn't have a way of dealing with hex, unlike Coco Extended Basic with its "&H" prefix.

In order to make such a large and complex program fit in memory the programmers split Apshai into two. The first half called "INN," for "the Innkeeper, is used to create a typical D&D like character with different random attributes (numbered from 1 to 18) and to equip that character with the basic items needed, which can be purchased using a randomly generated amount of starting silver. In the Model 1 version the INN program would also then load a selected level with all its wall detail (as in the illustration above) and other items and poke this information byte by byte into an area of high memory. Then the INN program would delete itself and run the DM or "DunjonMaster" program (while leaving the area of high memory with all its info intact). This is a clever way to save memory, because DM doesn't have to include all the ponderous code need to generate a character and load data from tape or disk.  Also, the information is stored in byte form in memory rather than data statements and variables. DM just has to have code for rendering the level info and running combat and moving the character.

Model 1 Basic allows programs to "chain" run other programs (i.e. to load and run another program) but the MC-10 does not. As soon as any program is CLOADED and RUN in an MC-10 all variable memory is cleared, which the Model 1 either does not do, or was made not to do by some of the more mysterious POKES in the code which I could not decipher. I had to find a way to achieve the same effect. Luckily the MC-10 obliges nicely. It has a quirky command CSAVE*arrayname,"filename" that saves any numeric array to tape. It also has a VARPTR command which allows you to find out where any variables or arrays are actually storing their data in memory. Using these commands I was able to modify all the places in the code where data was being peeked from the high memory space of the Model 1 to instances where data was peeked or poked to the memory space of a specific array. I could then use the CSAVE* command (and its opposite CLOAD*) to pass this info between INN and DM. The MC-10 only supports floating point numeric variables and arrays with each number taking 5 bytes to encode. I just had to find out the lowest value ever PEEKED and the HIGHEST and then divide this number by 5 and declare an array of that size and then, using VARPTR, I could do the same thing as the pokes to high memory were doing in the Model 1 version.

There was one catch.  Whenever Basic encounters a new variable while running a line by line interpreted program, it re-arranges memory space and tucks the new variable into an appropriate spot. This means that if you have variables that have not been used yet in a program and then get called, you have to do another VARPTR call to find out where your array has now been shunted in memory. The only way around having to do such continuous checking (with all the extra VARPTR commands this would require) is to formally declare all your variables and arrays at the start of the program. I've described elsewhere in this blog (Getting Speed Out of MC-10 Microsoft Basic) how carefully declaring all variables and putting the one's used most often first in such a declaration, is a way to speed up Basic program execution. The simplest way to declare a variable in Micro Color Basic is to include it in a DIM statement (which isn't limited to being used with arrays). So I had to carefully examine the code and then test and re-test until I had discovered all the variables that were used (in both INN and DM) and include them in DIM statements at the start of each program.  It was a tedious but necessary part of the project.

After doing all this I had a basically functional port. It was then just a question of cleaning up the code using the speed techniques outlined in the post mentioned above and adding a few bells and whistles, such as color and a few different shapes for the main monster types (creepy crawlers, undead, bugs, blobs, etc.). As usually I had to do some creative shortening of messages, as you end up with half the text width to describe anything (32 versus 64). This was made easier by the fact that the authors had clearly envisioned porting their program to other 40 character per line screen machines and thus kept everything fairly brief. As I have found with other Model 1 programs, the MC-10 just seems to run Basic code faster, so combined with the speedup techniques, the game is a little more speedy than the original.  Here are some comparison screenshots of some different versions:
Apple II
TRS-80
MC-10 Version
I had the make the character a little simple (the little chevron above).  But I was able to offset some of the drab red uniformity by adding some color to the monsters, which you can see here (a blue Ant Man):
I still have a bit of work to do on how doors are rendered, but otherwise I'm pretty pleased with the conversion, and haven't encountered any major errors since working out the basic graphic conversion kinks. In my version, its up to you to load and save the levels (array) each time you use INN and DM, but this is not very different from the original, and is even easier in the VMC10 emulator, where you simply can click on desired virtual cassette files (.C10). The extra 4K of memory allowed me to add DATA statements to DM with the values of the treasures for each level, so at least you no longer have to look them up in the manual and do a bunch of pencil-and-paper calculations to figure out the total of what you earned (it's calculated for you when you reload a level into DM). If you wish to try the program it can be found in the JimG subdirectory of the Cassette directory of the emulator (along with all my other Basic programs), which can be downloaded at: https://github.com/jggames

There is also a YouTube video which will give you a bit of an idea of how the program runs:

I have written a brief review of the program posted on the Interactive Fiction Database in which I explain why the game should be seen as more than a mere arcade RPG kill fest. A true appreciation of it really requires some engagement with the clever narrative elements laid out in its elaborate manual. There really is a mystery behind the "curse of Apshai," which the player can seek to unravel and defeat. Enjoy!

Tuesday, 29 April 2014

Tim Hartnell's "Chateau Gaillard"


I found the source code for this on an Atari site that has archived a whole bunch of published materials for early 8-bit computers. There seems to be something about the Atari crowd that inclines them to programming activities. Their collective efforts to support this inclination are also helpful for the rest of us 8-biters. One interesting book they have maintained in digital form is Tim Hartnell's classic Creating Adventure Games on Your Computer. In the course of porting "Chateau Gaillard" to the TRS-80 MC-10, I found a few errors in the original listing. For example, the way the code originally worked the weapon you chose seemed to have no effect on combat. There were elaborate routines for reporting and selecting which weapon you would use, but when it came right down to it, the value entered was not used in the combat routine. There were also some other bugs, such as the interaction with the Dwarf (misreported the objects he was willing to accept during negotiations) and the fact that you could simply "go up" back to the surface from the initial room you fall into, contrary to the message that "there is now no way back." On the whole, the combat routine just seemed overly punishing and I found the game difficult to complete, so I adjusted it. Also, when you moved an excessive number of points were randomly subtracted from your statistics. I changed it so that only your strength is randomly diminished as you explore, and at a much lower rate. Now you at least have a chance of finding the healing potion and replenishing your strength. I also added a routine to allow you to re-roll your character stats at the beginning of the game until you get a reasonably fair dispersal. As with most Basic two-word parsers there are some quirks. There is no shorthand N, S, E, or W for moving. The closest you can get is GO N, GO S, etc. Otherwise, three letters is all you need for either word to register. However, I added a single word "INVENTORY" command, because I didn’t like seeing an inventory automatically with every new screen. There are lots of arbitrary deaths in this game from traps, so you’ll just have to play it multiple times and map it enough to learn where not to go. That being said, some meager clues are given to help you avoid some of these deaths. The basic object of the game is to find the two keys, which are needed to allow you to escape two rooms that otherwise lock you in. Once you get the right keys for the right rooms, you can use them to unlock all the doors in those rooms, which will allow you to find a stairwell back to the surface. On the whole, it is a fun little 8-bit Basic dungeon romp. The combat routine is quite unique in the way it allows you to choose which vital statistics you will draw on in your combat against the different creatures (which have some very creative names) and their distinctive vital stats. In brief you should try to select your highest stats while selecting the lowest equivalent stats of your opponent. Various clues about how to overcome dangers are also sprinkled throughout the maze, which is a nice touch. If you get stuck there is a map below to give you a hand. The coordinated colors indicate various rooms with ways to move up or down between the levels.

** SPOILER ALERT **

Above Ground 



Chateau Forest
(Start)
Escape


Level 2







Smokey Room
Cursed Mirror
Marble Room








Cramped Room
(Start)
Mirrored Hall






Draped Hall
Dwarf’s
Room
Long Corridor





Spider
Alcove

Despair
Room
Game Room



Silver Key



Stone Cavern

Dried Fountain
Dried Flowers

Battle- ments
Eerie Room
Mattress Room
Paneled Room
Stone Trap


Potting Shed



Trap
Kitchen
Black Dragon





Flaming
Pit
L Shaped
Room
Arch


Landing







Fresh Air









Level 3

Slippery Room
Torture Chamber
Dungeon
Gargoyle

Dingy Pit
Dance Hall
Gloomy Passage





Common Hovel
Trophy Room
Rear Turret
Gold Key


Cobweb Room
Secret Room



ADDENDUM (January 2024)
I updated this program so that it now loads all in single file.  Fixed a few more awkward and wordy phrases.


Tuesday, 22 April 2014

Citadelle: The Shield of Oran

In the first installment of Loriciels' Citadelle series, which I ported from source code from the Sanyo PHC-25, and translated to English, you will come up against a range of monsters. There are Lich’s, Bugbears, Orcs, Assassins, Warriors, Shades and Gnolls. The game feels like an RPG, but it actually combines elements of that genre with a simple two-word parser text adventure and treasure hunt. There are puzzles to be solved too.

In the version I ported the stats of the monsters are randomly generated in terms of the hit points, armour class and strength at the beginning of each combat, so retreating might not be a good idea. Retreating takes you back to the previous room you were in. When you re-enter the room all the conditions for the monster will be reset. This might be a good thing if the monster is really strong and you’re getting pasted. Going and coming back in might make for a weaker monster. However, it might be worse!

Choosing Defence rather than attack just reduces your chances of being hit while also decreasing your chances of hitting the monster. Spells are powerful but fickle. The monsters are deployed in fixed locations as indicated in the map below.  However, if they don’t “disappear” at the end of combat random monsters will be spawned at random in one of the rooms. If you have the sword and the armour, the monsters are pretty easy to defeat. You won’t be let through the portcullis if you get pasted by the Gnoll and you don’t have at least one of these two items. A map and instructions follow:

** SPOILER ALERT ** Walkthrough Map below!



Exit




            N
     W    +    E
            S
      

Tomb

SAY AROG
GIVE EYE
warrior

Arms of Oran

(must have
Lighted lamp)
EXAMINE OBJECT
TAKE SHIELD
EXAMINE SHIELD
harpy
Well Room

SEARCH WELL
TAKE KEY
EXAMINE STONES
OPEN STONE
(requires hammer
 and chisel)
SEARCH NOOK
TAKE EYE
Assassin
Armoury

EXAMINE MOSAICS
EXAMINE STARS
OPEN STAR
(requires hammer
 and chisel)
TAKE ROD
Lich
Tiled Entry Hall

TAKE LAMP
LIGHT LAMP
OPEN DOOR
(requires key)

Dark Hall

EXAMINE FLOOR
SEARCH DUST
EXAMINE WALLS
SEARCH WALLS
USE MECHANISM
Store Room

OPEN CRATES
EMPTY CRATES
(you'll discover
the name Arog)
OPEN BARREL
EMPTY BARRELS
SEARCH SACKS
TAKE CUBE
INSERT CUBE
(requires mech
from dark hall
to have been
touched)

Stables

CLIMB LADDER
SEARCH ROOM
MOVE BOARDS

Inside Cave

SEARCH SKELETON
TAKE CHISEL

Guard Room

USE MECHANISM
Bugbear


Hay Loft

SEARCH SACKS
TAKE HAMMER
SEARCH HAY
DESCEND LADDER
Shadow
In front of Cave

EXAMINE GROUND
TAKE FLINT
TOUCH PORTCULLIS
Gnoll




Forest

MOVE ROCK
TAKE SWORD
SEARCH TREE
TAKE ARMOUR