Pages

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!