Tuesday 11 November 2014

Space Trek by Jake Commander


Here are a few comments about the code I modified for the MC-10 (on Github) of Jake Commander's "SPACE TREK" originally published in Color Computer Magazine (May 1983). Each comment refers to the code snippet just above it. My MC-10 version has removed all ELSE commands and changed all PLAY commands to simpler SOUND commands. Also, all string assignments using the special poke routine at the beginning of the program and all uses of the STRING$ command have been replaced by literal strings, since graphic characters can be input directly from the MC-10's keyboard. All PRINT USING commands have been replaced by combinations of INT, STR$ and MID$, RIGHT$ or LEFT$ commands to format numeric output.

1 C1=1:C2=32
2 IFMID$(M$,C2,1)<>""ANDMID$(M$,C2,1)<>" "THENC2=C2-1:GOTO2
3 PRINTMID$(M$,C1,C2-C1):C1=C2+1:C2=C1+31:IFC1<=LEN(M$)THEN2
4 RETURN

The above is my 32 character word-wrap routine. I use it for all printed messages instead of inserting spaces in them. It's also more flexible when it comes to messages that change length, such as when you have STR$(numvar) numeric data being concatenated with a string.

420 GOSUB1650:H=H+1:IFH<150THEN390 

If others want to port this code they will need adjust the speed of the game because of differences in their machines from the original Coco version.  Change the 150 value above to something higher if your machine is slower or something lower if your machine is faster. This is the countdown for the "pings" of the view screen, as in the original Star Trek show.

580 GOSUB650:FORH=1TON:GOSUB660:ONZGOTO590,595,594 
590 NEXTH:IFF=0THEN640
591 H=H-1:GOTO620
594 TM=H:H=N:NEXTH:H=TM:GOTO680
595 TM=H:H=N:NEXTH:H=TM

The ON/GOTO in line 580 is in the middle of a FOR/NEXT loop.  As far as I can tell, the jumps to 595 and 594 originally simply jumped out of the FOR/NEXT loop never to return. I just hate not closing NEXT loops on principle, and they can occasionally cause problems if they occur too often, so I added a temp (TM) variable and lines 595 and 594 to gracefully exit the loop before proceeding on to the original GOTO lines.  I use the TM variable to re-assign the value of the NEXT loop to the variable after completing it properly, just in case the program relies on knowledge of what the value of the loop was.

920 FORI=1TO3:IFC=K(I,1)ANDD=K(I,2)THENK(I,3)=-1:X=C:Y=D:R=320:GOSUB1560:I=3
930 NEXT:GOTO970

There was a rare problem where a photon torpedo hit would seem to register twice (two explosions in a row).  I think this may have been a result of not gracefully exiting the for next loop as soon as the "hit" Klingon is found (why keep searching for hits on the other Klingons?).  So I added I=3 after the torpedo is found to have hit one of the 3 Klingons that can be in any Quadrant.

950 GOSUB1580:PRINT@320,;:M$="WELL DONE! STARBASE DESTROYED!":GOSUB1:B=B-1:BT=BT-1:M2=4:X=C:Y=D:GOSUB1550
951 PRINT@352,;:M$="THE EXPLOSION HAS THROWN YOU OFF COURSE":GOSUB1:GOSUB1350:PRINT@320,;:C=RND(...

I changed the word "DAMAGE" to "EXPLOSION."  It seemed to make more sense. Also, I added a pause (GOSUB1350) and a PRINT@ statement after the message, since occasionally more messages might follow that fill the screen beyond the 16 line limit of the MC-10.

1090 PRINT@320,"LAST BATTLE-CRUISER DESTROYED!":GOSUB1700:PRINT"THE ";U$;" IS SAVED!!":GOSUB1700:SOUND75,5:SOUND80,5
1091 PRINT"YOUR EFFICIENCY RATING ="INT(K7/(T-T0)*1000):END

I added a call to line 1700 for a little noise/music when you win.  It seemed anti-climatic otherwise. Line 1700 in the original listing seemed to be an orphan anyway, so I tweaked it for a more congratulatory sound.

1100 CD=0:AF=0
1110 A=0:GOSUB380:PRINT@217,"OPT?  ";
1120 GOSUB390:IFA>6THEN1120
1130 IFA$=CHR$(13)THENONA+1GOTO330,1290,1150,1160,1170,1280,1140:GOTO1120
1131 PRINT@249,B$(A*2+17);:PRINT@281,B$(A*2+18);:GOTO1120
1140 A=0:AF=0:FORJ=1TO8:FORI=1TO8:CC=INT(Z(I,J)/100)...
1141 POKE16424+A+(I-1)*2,CC+112:POKE16425+A+(I-1)*2,Z(I,J)-CC*100-O*10+112-64*O:NEXT:A=A+32:NEXT:O=0:GOTO1110
1150 O=0:AF=0:FORA=40TO266STEP32:PRINT@A,Y$;:NEXT:PRINT@41,"STATUS REPORT:";:PRINT@106,"KLINGONS ="KT;
1151 PRINT@138,"STARDATES="INT(T0+TT-T);:PRINT@170,"STARBASES="BT;:GOTO1110
1160 IFK=0THENGOSUB1620:GOTO1110
1161 AF=1:CC=U:A=V:FORF=1TO3:IFK(F,3)<0THEN1270
1162 TM=F:F=3:NEXT:F=TM:W=K(F,1)...
1170 AF=0:PRINT@384,"ENTER START AND END CO-ORDINATES":PRINT@320,;:INPUT"(X,Y,X,Y)";CC,A,W,X

When in the computer OPT mode, if you select TORPEDO DATA and then select any other options besides GUIDED TORPEDO, you garble the variables used to store your TORPEDO DATA. So I added the AF (auto fire) variable switch to all the Computer options to turn off the GUIDED TORPEDO fire option if you don't select it right after selecting the TORPEDO DATA option. Now GUIDED TORPEDO will only work if you select it after selecting the TORPEDO DATA opt.

1281 IFAF=0THEN1300

This line is the one added to the TORPEDO subroutine to prevent firing (and possible infinite loop) unless the AF variable is set to 1.

1360 FORZZ=H*.25+1TO1STEP-1:POKE49151,64:SOUND255,1:NEXT:RETURN 

The above poke just switches the screen of the MC-10 to orange from regular green to give a flickering screen effect when you are hit.

1520 T=T+.5:PRINT@64,INT(T);:GOSUB1500:IFT>T0+TTTHEN1060

This is the stardate countdown. It used to read T=T+1, but since the Coco is slower than an MC-10, I had to have it count more slowly (by .5s) or the game expected you to play at too high a speed to be fair.

1550 GOSUB1580:S(X,Y)=0:G(L,M)=K*100+B*10+S:RETURN
1560 K=K-1:IFK<0THENK=0:SOUND100,20
1561 GOSUB1550:GOSUB1420:PRINT@R,"KLINGON AT"STR$(INT(X))","RIGHT$(STR$(INT(Y)),2)" DESTROYED";

I added the check in 1560 above to prevent the problem mentioned above of double explosions from torpedo hits on some Klingons.  If the hit registered twice the K variable could go to a negative number which really messed up the modification of the 3 digit number (i.e. 100s, 10s, 1s) calculated in 1550 used to store each Quadrant's info G(Klingons, Starbases, Stars).

1640 ZZ=PEEK(17025):PRINTLEFT$(BL$,16895-(PEEK(17024)*256+PEEK(17025)));:POKE17025,ZZ:RETURN

The peeks in this routine above 17024 and 17025 are simply the way for the MC-10 to determine the screen location of the current cursor location (0-511). It is used to print blanks of a particular length from that location to the second last position of the screen (i.e. to clear the message area but not print in the bottom right corner so as to cause a linefeed moving the entire screen up).

1700 FORX=50TO70STEP5:SOUNDX,1:NEXT:RETURN

This line was an orphan in my listing of the program. So I modified it and use it in the win routine to provide a little sound.

And there are always tweaks and modifications that cry out for implementation...

1285 C=CC:IFRND(10)>9THENC=C+.5:IFC>=9THENC=1

For example, I changed the GUIDED TORPEDO routine to misfire on a 1 in 10 chance, just to moderate this lazy option. There has to be some disadvantages for relying on computers for everything!

Saturday 4 October 2014

Converting from MC-10 to Coco and Dragon

=====>

Part of the difficulty I have in porting programs from the MC-10 to Coco and Dragon is that Coco and Dragon Basic needs spaces in certain places that the slightly later rendition of Microsoft Basic used on the MC-10 does not require. Specifically:
ONNGOTO100 must become ONN__GOTO100
FORA=BTOCSTEPD must become FORC=A__TOB__STEPC
IFA=BTHEN must become IFA=B__THEN
IFA=BANDC=D must become IFA=B__ANDC=D
IFA=BORC=D must become IFA=B__ORC=D
PRINTATAB(10)B must become PRINTA__TAB(10)

An important programming technique for getting speed in my games for the MC-10 is to remove ALL spaces and to stick to single letter variables.This is fine on the MC-10.It requires absolutely no spaces anywhere. Every space just wastes tiny increments of time. I have some macros in MSWord now that help me with some of these replacements, but not all.I also have macros for changing the directly entered graphic strings to CHR$ equivalents, but there is always cleanup and unforeseen complications...

In terms of the key polling routine I have to change this for the MC-10:
20 ONK(PEEK(2)ANDPEEK(17023))GOSUB2,3,4,7

to this for the COCO:
14 ONK(PEEK(135))GOSUB2,3,4,7:RETURN
20 POKE345,255:POKE344,255:POKE343,255:POKE342,255:POKE341,255:POKE340,255:IF(PEEK(345)ANDPEEK(344)ANDPEEK(343)ANDPEEK(342)ANDPEEK(341)ANDPEEK(340))<>255THENGOSUB14

and this for the DRAGON:
14 ONK(PEEK(135))GOSUB2,3,4,7:RETURN
20 IF(PEEK(345)ANDPEEK(344)ANDPEEK(343)ANDPEEK(342)ANDPEEK(341)ANDPEEK(340))<>255THENGOSUB14

The multiple pokes in the Coco routine are for the benefit of CocoBs, which have a slightly different way of handling the rollover table that does not reset it. The Coco1 and Coco3 don't need such pokes, but it is too difficult to be bothered having multiple versions and they're not bothered by the pokes. The Dragon, however, is bothered, so I have to take all the pokes out for it. I also have to change the values of the K array to those of the arrow keys on the COCO/DRAGON rather than the codes for ASWZ.

MC-10 "Arrow" DiamondCoco Arrow Keys ASCII ValuesCoco Rollover Table peek
A=65
 LeftArrow=8
 343
W=87
 Up Arrow=94
 341
S=83
 Right Arrow=9
 344
Z=90
 Down Arrow=10
 342
SPACE=32
 Space=32
 345

Any special peeks or pokes must also be converted. Such as those which provide the current cursor location of the MC-10 17024 and 17025 (136 and 137 for the Coco), which I use quite a bit.

POKE49151,64 (MC-10) must be switched for SCREEN0,1 (Coco). The MC-10 uses a special CLOAD*A,"FILENAME" command to store numeric arrays to tape (in this case array A). This has to be replaced with the following code for a Coco with a disk drive:
6800 GOSUB10003:PRINT"SAVING":OPEN "O", #1,"DATA/DAT":FORC1=0TO150:WRITE #1,A(C1):NEXT:CLOSE#1:GOSUB10001
6840 GOSUB10003:PRINT"LOADING":OPEN "I", #1, "DATA/DAT":FORC1=0TO150:INPUT#1,A(C1):NEXT:CLOSE#1:GOSUB10001

or this code for a DRAGON using tape:
6800 GOSUB10003:PRINT"SAVING":OPEN "O", #-1,"DATA":FORC1=0TO150:PRINT #-1,A(C1):NEXT:CLOSE#-1:GOSUB10001
6840 GOSUB10003:PRINT"LOADING":OPEN "I", #-1, "DATA":FORC1=0TO150:INPUT #-1,A(C1):NEXT:CLOSE#-1:GOSUB10001

Finally, I usually include Zephr's nifty speedkey and speedup poke sensing subroutine for the Dragon and Coco
10000 IF PEEK(65535)=27 THEN DS$="Y":GOTO10001 ELSE CLS:INPUT"CAN YOUR COMPUTER HANDLE DOUBLE SPEED (Y/N)";DS$:IFLEFT$(DS$,1)<>"N"ANDLEFT$(DS$,1)<>"Y"THEN10000
10001 IF LEFT$(DS$,1)="Y" THEN IFPEEK(65535)=27 THEN POKE65497,0 ELSE POKE65495,0 
10002 RETURN
10003 IF PEEK(65535)=27 THEN POKE65496,0 ELSE POKE65494,0
10004 RETURN
10005 ' ENABLE DRAGON SPEEDKEY
10006 IF PEEK(65535)<>180 THEN 10008
10007 IF PEEK(269)+PEEK(270)<>1 THEN POKE65283,52:POKE256,116:POKE257,1:POKE258,81:POKE259,126:POKE260,PEEK(269):POKE 261,PEEK(270):POKE269,1:POKE270,0:POKE65283,53
10008 RETURN
10009 ' DISABLE DRAGON SPEEDKEY
10010 IF PEEK(65535)<>180 THEN 10012
10011 IF PEEK(269)+PEEK(270)=1 THEN POKE65283,52:POKE269,PEEK(260):POKE270,PEEK(261):POKE65283,53
10012 RETURN

I also change the typical Coco RANDOMIZE function:
R=RND(-TIMER)
to the following on the MC-10
R=RND(-(PEEK(9)*256+PEEK(10)))

Anyway, I am currently working on porting a dozen or so of my latest MC-10 programs to Coco and Dragon, but it is a lot of fiddly tiring work (not as fun as the original programming challenges), so my progress is slow. I've done BIGRED, SWELFOOP, and DICEWARS for the Coco. I'm currently working on Temple of Apshai. Here's what I plan to do:

JGGAMES10.DSK:
BIGRED
SWELFOOP
DICEWARS
SEAWAR
FLAPPY
DIGGER
CRAZY8S
SHUFFLE
GOFISH
HEXAGON
DOTS

JGGAMES11.DSK:
APSHAI

JGGAMES12.DSK:
PIRATE1
CASTADV1
JOURNEY
MORLOCKS
SORCERY
ORIENT
ADVENT1
DRWHO1
PTREAS
ORAN
CHATEAU1
NINJA
PIRATE1
MANTICOR

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