Maya Grab [Day 12] – Drawing PETSCII

Yesterday and today I’ve wanted to setup a couple of rooms, to get the game started and to see how long does it take to draw everything manually. I’ve managed to do the title and rip screens, and the first three rooms with all their states. I’ve thought I’ll be bored after just two or three screens, but it’s actually fun. Again, before I get to the main topic, let’s see some changes in the code:

1540 L$=CHR$(127): R$=CHR$(169)

This is really funny. Two new variables with special C64 characters that I couldn’t find on my keyboard. They are often used, and if I ever find the right key combination to display them, this line will be removed.

10500 :
10505 REM – INIT SCREEN —————
10510 :
10515 PRINT CHR$(147)
10520 POKE 53280,0: POKE 53281,0
10525 RETURN
10530 :
10600 PRINT CHR$(147)
10605 POKE 53280,CB: POKE 53281,CF
10610 RETURN

The init screen subroutine now sets the border to black (needed for the title screen), and there is another one beginning at line 10600 which sets the colors for the game. Lot’s of similar code, I know.

30000 :
30005 REM *****************************
30010 REM * ROOM DRAWING              *
30015 REM *****************************
30020 :
30025 IF PR=0 THEN 30500
30030 IF PR=1 THEN 31000
30035 IF PR=2 THEN 32000
30040 IF PR=3 THEN 33000
30045 IF PR=4 THEN 34000

Another part that will be optimized later. Depending on the room the player is in, the correct drawing subroutine is called.

There’s no point showing the code for drawing the screens, it’s just a bunch of PRINT commands. Also it would take ages to “convert” the code into normal ASCII and display it in HTML with the correct C64 font. So, if you look at the source code and the room drawing subroutines, you’ll find just an RETURN command, which means that this room is finished and already in the game.

The thing that’s bothering me is free memory. Not so many bytes left, and I did only one third of the rooms; still have to do the sprites and write the complete interpreter. I’ll focus on the rooms in the next couple of days and keep an eye on those bytes.

Program size: 21688 bytes, on disk 19050 bytes or 75 blocks
Free BASIC memory: 17223 bytes
Used BASIC commands: –

Source code

* * * * *

Maya Grab [Day 11] – Main game loop

Yesterday I’ve made a one day break before I move on to the next thing what I had in mind. It’s the main game loop. It’s very simple and it controls all states of the game. I’ve commented it very well because it consists mostly of calling subroutines. To test if everything is working correctly I’ve had to make also a dummy interpreter and room drawing routine. Let’s see the code:

4015 DIM PI$(IS): DIM RF(RS)
4020 PR=0: PT=0: PC=0: PP=0

Last time I’ve said, that the game can be restarted by jumping to line 4000; well, it caused an error, because arrays can’t be defined more than once in a program. The solution is a little bit dirty, I’ve swapped these two lines and I’m restarting the game now by jumping to line 4020.

18500 :
18505 REM – WAIT ———————- 
18510 :
18515 FOR I=0 TO 2000: NEXT
18520 RETURN

Simple routine which causes a short delay; will be used only when the title screen is shown.

19000 :
19005 REM – WAIT FOR KEY ————–
19010 :
19015 GET X$: IF X$=“” THEN 19015
19020 RETURN

Another simple routine which waits for a keypress; will be used only when the RIP screen is shown.

30000 :
30005 REM *****************************
30010 REM * ROOM DRAWING              *
30015 REM *****************************
30020 :
30025 PRINT CHR$(19);
30030 PRINT “[CRD][CRL]”;
30035 PRINT “ROOM:”;PR;” FLAGS:”;RF(PR)
30040 RETURN
30500 :
30505 REM – ROOM 00 ——————-
30510 :
30515 PRINT CHR$(19);
30520 PRINT “[CRD][CRL]”;
30525 PRINT “TITLE”
30530 RETURN
31000 :
31005 REM – ROOM 01 ——————-
31010 :
31015 PRINT CHR$(19);
31020 PRINT “[CRD][CRL]”;
31025 PRINT “RIP”
31030 RETURN

A dummy room drawing routine which draws for the title and rip game states appropriate strings, and for all other rooms in the game it’s number and flags. That’s all the info I need for now.

20000 :
20005 REM *****************************
20010 REM * INTERPRETER               *
20015 REM *****************************
20020 :
20025 REM * MODIFIES:
20030 REM * PR  – PLAYER ROOM
20035 REM * PC  – PLAYER COMMANDS
20040 REM * PP  – PLAYER POINTS
20045 REM * PI$ – PLAYER INVENTORY
20050 REM * RF  – ROOM FLAGS
20055 :
20060 REM * PARAMETERS:
20065 REM * A$ – USER COMMAND
20070 :
20075 REM * RETURNS:
20080 REM * A$ – MESSAGE TO SHOW
20085 REM * A  – INTERPRETER RESPONSE:
20090 REM *    – 1) REDRAW ROOM
20095 REM *    – 2) CHANGE ROOM
20100 REM *    – 3) PLAYER DIED
20105 REM *    – 4) SHOW MESSAGE
20110 REM *    – 5) SHOW INVENTORY
20115 :
20120 PR=PR+1: A$=IM$(4): A=2
20125 RETURN

A dummy interpreter which simply moves the player to the next room every time the player types something. This routine will be the only one which can modify the game parameters. It receives the command in A$, and returns a message in A$ and in A what should the game loop do or redraw next.

5000 :
5005 REM ******************************
5010 REM * MAIN GAME LOOP             *
5015 REM ******************************
5020 :
5025 IF PR=0 THEN 5100: REM TITLE
5030 IF PR=1 THEN 5200: REM RIP
5035 GOTO 5300        : REM ROOMS
5100 :
5105 REM – TITLE SCREEN —————
5110 :
5115 GOSUB 10500: REM INIT SCREEN
5120 GOSUB 30500: REM DRAW TITLE
5125 GOSUB 18500: REM WAIT
5130 PR=2       : REM SET ROOM TO 2
5135 GOSUB 10500: REM INIT SCREEN
5140 GOSUB 11500: REM DRAW FRAME
5145 GOTO 5300  : REM ROOMS
5200 :
5205 REM – RIP SCREEN —————–
5210 :
5215 GOSUB 31000: REM DRAW RIP
5220 GOSUB 12500: REM DRAW ITEMS
5225 GOSUB 13500: REM DRAW DIRECTIONS
5230 GOSUB 14000: REM CLEAR INPUT
5235 GOSUB 16000: REM DRAW RIP MESSAGE
5240 GOSUB 15000: REM CLEAR MESSAGE
5245 GOSUB 16500: REM DRAW STATS
5250 GOSUB 19000: REM WAIT FOR KEY
5255 GOTO 4020  : REM RESTART GAME
5300 :
5305 REM – ROOMS ———————-
5310 :
5315 GOSUB 30000: REM DRAW ROOM
5320 GOSUB 12500: REM DRAW ITEMS
5325 GOSUB 13500: REM DRAW DIRECTIONS
5330 GOSUB 15000: REM CLEAR MESSAGE
5335 GOSUB 15500: REM DRAW MESSAGE
5340 GOSUB 14000: REM CLEAR INPUT
5345 GOSUB 14500: REM WAIT FOR INPUT
5350 GOSUB 20000: REM INTERPRETER
5355 ON A GOTO 5415,5420,5425,5430,5435
5400 :
5405 REM – PARSE INTERPRETER RESPONSE –
5410 :
5415 GOSUB 30000: GOTO 5330: REM ROOM 1
5420 GOTO 5300             : REM ALL  2
5425 GOTO 5200             : REM ALL  3
5430 GOTO 5330             : REM MSG  4
5435 GOSUB 17000: GOTO 5330: REM INV  5

Nothing much to say about this one; everything is in the comments. There are only three states in the game: title, rip and rooms. The 5025-5035 lines are also too much, the loop can handle everything, but I’ve left it for security reasons if I call the line 5000 again by accident. All three states are handled separately (event if rip and rooms states have many things in common), and after the interpreter finishes interpreting the command, the results are handled. What’s missing here is one more result when the player completes the game. It will be implemented later.

Program size: 14226 bytes, on disk 14478 bytes or 57 blocks
Free BASIC memory: 24685 bytes
Used BASIC commands: ON

Source code

* * * * *

Maya Grab [Day 10] – UI subroutines

Today I’ve wrote some simple routines for building up the game UI. I’m simply amazed how printing to screen is slow in BASIC. But first let’s take a look at some other modifications I’ve also done.

1500 :
1505 REM – DEFINES ——————–
1510 :
1515 V=53248: S=54272: C=646
1520 MA=780: MX=781: MY=782 MS=783
1525 CB=12: CF=0: FW=27: FC=2: FH=19
1530 PI=1: PD=11: PE=20: PM=22
1535 SL=100: SH=180

Here I’ve stored the address for changing the text color 646 ($0286). Then I needed to access another register in machine code for a routine that I’ve found for placing the cursor at specific position (783). But, the routine was buggy, crashed my emulator, so I’ve replaced it with another one, and this variable will be probably removed at the end. The color of the frame (in which the rooms are drawn into) is stored in FC. And I’ve renamed PO to PI (items Y position) and PI to PE (user input Y position).

4000 :
4005 REM – GAME VARIABLES ————-
4010 :
4015 PR=0: PT=0: PC=0: PP=0
4020 DIM PI$(IS): DIM RF(RS)
4025 :
4030 FOR I=0 TO IS1: PI$(I)=“”: NEXT
4035 FOR I=0 TO RS1: RF(I)=0: NEXT

Last two lines are new; two loops for reseting players inventory and room states if the game should be restarted. The initial plan was to write a routine for this, but after these definitions, the common variables are initialized (line 4500) and the program enters the main loop (line 5000); meaning the whole game can be reseted by just jumping to line 4000, without subroutines.

11000 :
11005 REM – POSITION CURSOR ———–
11010 :
11015 POKE 211,X :POKE 214,Y
11020 SYS 58640
11025 RETURN

This routine places the cursor at position given by X and Y variables. The parameters must be written to addresses 211 ($00D3) and 214 ($00D6) before calling a system machine code routine at address 58640 ($E510).

11500 :
11505 REM – DRAW FRAME —————-
11510 :
11515 X=0: Y=0: GOSUB 11000
11520 POKE C,FC
11525 :
11530 PRINT“[RVS][SPCx12]”;
11535 PRINT“[SPCx17]”
11540 FOR I=0 TO FH2
11545 PRINT“[RVS] “ SPC(FW2) ” “
11550 NEXT
11555 PRINT“[RVS][SPCx12]”;
11560 PRINT“[SPCx17]”
11565 RETURN

This routine draws the frame around a room. The cursor is positioned, the color is set and first the upper bar is drawn, then the side bars in a loop, and at the end the bottom bar. It’s very slow, even if the content of the frame in the middle isn’t cleared.

12500 :
12505 REM – PRINT ITEMS —————
12510 :
12515 X=FW+1: Y=PI: GOSUB 11000
12520 POKE C,14
12525 PRINT IM$(0)
12530 :
12535 POKE C,1
12540 FOR I=0 TO 4
12545 PRINT “[CRDx2][CRLx12]”;
12550 PRINT RO$(PR,I)
12555 NEXT
12560 RETURN

This routine prints items for the current room. Again, the cursor is positioned and the color is set for the label which is printed first. Then, in a loop, the items are printed underneath the label. I’ve tried first to position every item with the subroutine I’ve made, but that was very slow. The fastest way was to do a line feed after every item, and then roll back the cursor to the next item. Tricky but much faster.

13500 :
13505 REM – PRINT DIRECTIONS ———-
13510 :
13515 X=FW+1: Y=PD: GOSUB 11000
13520 POKE C,14
13525 PRINT IM$(1)
13530 :
13535 POKE C,1
13540 FOR I=0 TO 4
13545 PRINT “[CRDx2][CRLx12]”;
13550 PRINT RD$(PR,I)
13555 NEXT
13560 RETURN

Same stuff here for directions for the current room, and of course everything is printed at a different position, underneath the items.

14000 :
14005 REM – CLEAR INPUT —————
14010 :
14015 X=0: Y=PM: GOSUB 11000
14020 PRINT“[SPCx19]”;
14025 PRINT“[SPCx20]”
14030 RETURN

This routine clears the whole line where the player is entering commands.

14500 :
14505 REM – WAIT FOR INPUT ————
14510 :
14515 A$=“”: X$=“”: Y$=” “
14520 A=402LEN(IM$(2))
14525 :
14530 X=0: Y=PE: GOSUB 11000
14535 POKE C,7
14540 PRINT IM$(2);
14545 POKE 204,0
14550 :

I’ve updated the input subroutine to appear at the correct position and to show the correct label with appropriate color.

15000 :
15005 REM – CLEAR MESSAGE ————-
15010 :
15015 X=0: Y=PM: GOSUB 11000
15020 PRINT“[SPCx19]”;
15025 PRINT“[SPCx20]”
15030 RETURN

This routine clears the whole line where the interpreter is writing messages to the user.

15500 :
15505 REM – PRINT MESSAGE ————-
15510 :
15515 X=0: Y=PM: GOSUB 11000
15520 PRINT A$
15525 RETURN

This routine prints a message stored in A$. The colors will be also set in the message itself since multicolor support is needed.

Program size: 14979 bytes, on disk 12446 bytes or 49 blocks
Free BASIC memory: 23932 bytes
Used BASIC commands: SYS, FOR, TO, NEXT, SPC

Source code

* * * * *

Maya Grab [Day 9] – More data initialization

Nothing interesting about the work for today. I’ve entered all the strings for room objects and directions and for the interpreter commands and messages. It was about 400 lines of code; very interesting typing all this manually, without copy/paste on a real C64. Regarding strings and localization, whats missing now is only the room messages, since I have to actually play the game and try out various things to see what specific messages are showing up in each room.

I’ve checked the free memory a couple of times while typing all the data; the interpreter strings took about 3kb, and the room strings another 2kb of memory. I’ve reduced the room objects and directions arrays from 6 to 4 per room, because there’s simply not enough space on screen to show 6 strings. Also I’m not sure if I’ll need 16 strings per room for messages, so I guess that could be also reduced to maybe 12 or even 8.

Next I wanted to check the execution time, and before entering any data it was about 1 second until the user input showed up; with data entered it’s 2 seconds, which is also pretty ok I guess. I don’t know if this depends on how I assigned strings to the arrays. Normally you would store a large amount of data with the DATA command, and then read it in a FOR NEXT loop with the READ command. The problem is, you only have one data pointer and you can’t control it, so all data must be read from start to the end (like a sequential file) and stored in appropriate variable types. You can’t read something from the end, then something from the start, and afterwards something from the middle of the whole data block. Only thing you can do is reset the pointer with the RESTORE command and read again everything from beginning. I could use this method because the data I want to initialize never changes, but it makes, for me at least, the code totally unreadable, and you have to be careful while changing the array sizes. So I’m initializing all arrays the dumb way, but fully optimized for maximum code beauty:


3600 IM$( 0)=“ICH SEHE  :”
3601 IM$( 1)=“WEGE NACH :”
3602 IM$( 2)=“WAS NUN ?”
3603 IM$( 3)=“WIE ???”
3604 IM$( 4)=“OK.”
3605 IM$( 5)=“KENNE ICH NICHT”
3606 IM$( 6)=“DAS GEHT JETZT NICHT !”
3607 IM$( 7)=“KANN ICH JETZT NICHT”
3608 IM$( 8)=“NEHMEN !”
3609 IM$( 9)=“HINGEHEN !”
3610 IM$(10)=“ANSEHEN !”
3611 IM$(11)=“OEFFNEN !”

Program size: 14101 bytes, on disk 11684 bytes or 46 blocks
Free BASIC memory: 24810 bytes
Used BASIC commands: –

Source code

* * * * *

Maya Grab [Day 8] – Playing sound

Wrapping up the text input routine by adding sound while typing. This is also the only place where sound effects are used. Some basic instructions how the SID sound chip can be programmed can be found here. Of course, it’s impossible to replicate 100% the same sound that’s used in the original game just by hearing it playing. Nevertheless, Thomas Langenkamp, the author of Maya-Grab, has programmed another game called Ratefix which is released in the same Input-64 issue and which uses exactly the same sound as Maya-Grab. The listing of Ratefix isn’t protected, so it’s very easy to find out all necessary parameters. Let’s take a look at the code:

51000 :
51005 REM – PLAY SOUND —————-
51010 :
51015 POKE S+1,SH
51020 POKE S+4,21
51025 POKE S+5,9
51030 POKE S+15,30
51035 :
51040 POKE S+24,15
51045 :
51050 POKE S+4,20
51055 RETURN

Sounds on the C64 can be produced by writing values to the first 24 registers beginning at address 54272 ($D400); there are 4 additional registers but they are used for something else. First three pokes are setting the sound for channel 1: frequency (S+1), waveform (S+4) and decay (S+5). The next one is setting the frequency for voice 3; I’m not really understand the logic behind it and why Thomas did it, but it fixed a waveform issue which appears from time to time when playing the sound multiple times. Next poke sets the master volume (S+24), and after that, the waveform is changed again immediately to make the sound short.

Program size: 8505 bytes, on disk 5842 bytes or 23 blocks
Free BASIC memory: 30406 bytes
Used BASIC commands: GOSUB

Source code

* * * * *

Maya Grab [Day 7] – Custom input routine

Before doing anything today I wanted to write couple of commands to setup the screen and print available basic memory. And there I’ve encountered the first problem – my already defined variable names. If names are longer then 2 characters, conflicts can happen like described here.

10 GCB=12: GCF=0
20 PRINT GCB: PRINT GCF

Like shown on the first screenshot, this program will output for both variables 0, even if GCB is defined as 12. It took me quite some time to figure out that this is caused how the C64 is storing variable names. To be sure that every value is stored ok, I’ve redefined all variable names to max. two characters and added one more, that I’ve forgot, for counting player progress in the game.

10500 :
10505 REM – INIT SCREEN —————
10510 :
10515 PRINT CHR$(147)
10520 POKE 53280,CB: POKE 53281,CF
10525 RETURN

This is the routine for setting up the screen. I’m first printing a character with the ASCII code 147 which is for clearing the screen. Then I’m writing our predefined border color to address 53280 and foreground color to address 53281. Since I’m going to change the colors only once, I’m not going to keep those addresses in separate variables.

19500 :
19505 REM – PRINT FREE MEMORY ———
19510 :
19515 PRINT FRE(0)65536*(FRE(0)<0)
19520 END

Not sure how this work, I’ve found it on the internet. The FRE command outputs free bytes and the rest is just for normalizing negative numbers.

Now finally we’re going to checkout the routine how user input is read. On the C64 that could be easily achieved by simply typing this:

INPUT A$

The code waits for the user to type something and press the RETURN key. After that the string (in this case) is stored into variable A$. The problem with this command is that we don’t know which keys the user is pressing before pressing the RETURN key. Meaning, the user can press anything, for example characters that we want to filter out or keys for moving the cursor; therefore he can alter the screen contents and make a complete mess.

Solution for this is to make a custom input routine with the command GET, which waits for only one key to be pressed. Then we can check if we’re going to accept this key or just ignore it and wait for the next one until RETURN is pressed. Here’s the code:

14500 :
14505 REM – WAIT FOR INPUT ————
14510 :
14515 A$=“”: X$=“”: Y$=” “
14520 A=402LEN(“? “)
14525 PRINT “? “;
14530 POKE 204,0
14535 :
14600 GET X$: IF X$=“” THEN 14600
14605 X=ASC(X$)
14610 IF X=13 THEN 14900
14615 IF X=20 AND LEN(A$)>0 THEN 14700
14620 IF X=32 AND ASC(Y$)<>32 THEN 14800
14625 IF X>=65 AND X<=90 THEN 14800
14630 GOTO 14600
14635 :
14700 A$=LEFT$(A$,LEN(A$)-1)
14705 Y$=X$
14710 PRINT X$;
14715 GOTO 14600
14720 :
14800 IF LEN(A$)=A THEN 14600
14805 A$=A$+X$
14810 Y$=X$
14815 PRINT X$;
14820 GOTO 14600
14825 :
14900 PRINT ” “
14905 POKE 204,255
14910 RETURN

First some common variables are initialized; A$ for holding the result string, X$ for current char, Y$ for last char and Y for total string length allowed for typing. Currently only “? ” is printed, but I’ll replace this later with a localized string. Since the cursor is only shown when using the INPUT command, we have to show it manually by writing 0 to address 204. Everything is setup now for the loop which waits for a key press and that’s happening in line 14600. Then we take the ASCII value of the pressed key and check if it is RETURN (code 13), DELETE (code 20), SPACE (code 32) or a letter (codes from 65 to 90). Additional checks are made that we can’t delete a character if string length is 0 and that we can’t type two spaces in a row or begin input with a space. If none of these allowed characters match we jump back to the wait for key loop. Deleting a character is handled from line 14700; with the left command we’re taking the whole string with the last character removed. Of course we have to store last char to Y$ and print it out on screen. Other allowed characters are added to the string (if the length is in defined range) at line 14800. Last but not least, the RETURN key is handled from line 14900. Since we have enabled the cursor we have to print a additional space to clear it at the end of the output and disable it again by writing 255 again to address 204.

Program size: 5494 bytes, on disk 5080 bytes or 22 blocks
Free BASIC memory: 33417 bytes
Used BASIC commands: FRE, GET, IF, THEN, ASC, CHR$, AND, LEN, LEFT$, GOTO, PRINT, POKE, RETURN

Source code

* * * * *

Maya Grab [Day 6] – Defines and data initialization

Well, it was about time to write some useful code which actually does something. Today’s task was to write all variables for constants and some of the game data into the code. Variables on the C64 take up 7 bytes of memory and, of course, you can’t have dozens of them in your program. I remember once, I wanted to do a strategy game and didn’t have a clue that arrays exist (yes, I was 9 years old), so I’ve stored lists like separate variables. Epic fail; I’ve got the “out of memory” error really really fast.

Anyways, constants must be defined for addresses which are going to be read (PEEK-ed) or written (POKE-ed) very often; it makes the code much faster. Also, I’m going to use constants for some colors and screen positions for drawing things. There are also game constants (room data, interpreter data… etc) which aren’t going to change during gameplay and should be initialized only once. And last but not least there are variables which are going to change often. Unfortunately, you can’t give a variable name something like “MYAWESOMEVARIABLE”; well you can, just tried it out, but that’s going to eat up your whole screen space, and we said max. 39 characters (including the line number) for optimal code beauty. Therefore I cut down all variable names to a max of 3 characters. Let’s take a look what I have written down so far:

V=53248: S=54272

The first one is the address of the VIC2 graphics chip which handles, among other things, sprites. The second one is the address of the SID sound chip.

MLA=780: MLX=781: MLY=782

At those addresses the last state of the three CPU registers (accumulator, x and y) is stored. This is useful for passing data to the machine language code or vice versa.

GCB=12: GCF=0: GFW=27: GFH=19

The first two are colors of the border and the foreground and the last two are dimensions of the frame in which the current room is drawn.

GPO=1: GPD=11: GPI=20: GPM=22

Y positions on screen where objects (GPO), directions (GPD), user input (GPI) and messages (GPM) are drawn.

SFL=100: SFH=200

Frequencies for playing sound for typing (SFL) and confirming (SFH) a command.

PIS=16: RMN=20

Max number of items in players inventory (PIS) and total number of rooms (RMN) in game (including title and RIP screens – like Ron Gilbert did in Maniac Mansion).

DIM ROA$(RMN,6): DIM RDA$(RMN,6)
DIM RMA$(RMN,16)

Two dimensional arrays where objects (ROA), directions (RDA) and messages (RMA) are kept for every room.

DIM IMA$(16): DIM IVA$(35)
DIM IAA$(40): DIM INA$(66)

One dimensional arrays where messages (IMA), verbs (IVA), adverbs (IAA) and nouns (INA) are kept for the interpreter.

PRN=0: PGT=0: PIC=0

Player variables for holding current room number (PRN), game time (PGT) and number of issued commands (PIC).

DIM PIA$(PIS): DIM RSA(RMN)

One dimensional arrays for holding players inventory (PIA) and room states (RSA).

A%=0: X%=0: Y%=0
A$=“”: X$=“”: Y$=“”

Here I wanted to define couple of helper variables for passing parameters to and returning from subroutines, and since the CPU has three registers, I defined three integer and three string variables and gave them same names just for fun.

Program size: 7759 bytes, on disk 5080 bytes or 20 blocks
Free BASIC memory: 31152 bytes
Used BASIC commands: VARIABLE, DIM

Source code

* * * * *

Maya Grab [Day 5] – First lines of code

After all preparations I’ve finally wrote some code. It’s just bunch of remarks (comments) and code organization things like I described three days ago. I’ve put all code segments together and at previously specified line numbers. For every code segment (data initialization, main game loop, subroutines, interpreter… etc) I took some time to think about the steps between two lines of code; remember, it’s not easy to shift code up and down in BASIC. I hope I’ve left enough space between lines for adding or modifying the code later.

I’m very satisfied how I’ve organized everything, I’m a huge fan of clean code (who isn’t). But what’s bothering me now is this article I’ve found here. It’s about optimizations in BASIC how to save memory and gain speed; clean but fast code can’t be easily achieved. I have to avoid jumping to code and subroutines at higher lines; failed, I’m already planning to use everything until line 63999. I have to put as many commands in one line as possible; failed, I plan to use max. 39 characters per line for easy code reading (the C64 supports 80 characters which is two lines, with some tricks you can pack even more). I have to remove spaces between commands; failed, I find such code hard to read. I have to remove the comments; failed, I’ve already have more than 300 lines of comments only, and the program still doesn’t do a single thing. I guess I’ll have to see during development how the game is performing and then try to do little optimizations which hopefully won’t hurt much.

Now comes the interesting part… I’ve decided, at the end of each coding day, to include the current source code and some statistics. It’s going to be very interesting to see how the game is making progress. And now the big surprise; the game is already over 4kb and I haven’t done a thing. In machine code only the last “END” command would be compiled, and the game would be probably 10 bytes long. Cool to know, what’s going to be removed first if I run out of memory.

Program size: 4672 bytes, on disk 4826 bytes or 19 blocks
Free BASIC memory: 34239 bytes
Used BASIC commands: REM, END

Source code

* * * * *

Maya Grab [Day 4] – Tools & Floppies

Last couple of weeks I’m totally into writing tools in PHP; already made a few for my Laser Squad remake. Remember how I said that I will try to include as much code snippets as possible in the journal and therefore I’ve made some extra CSS? Well I’ve made a tool were you can paste your C64 BASIC code into and it returns a styled HTML with all the code syntax highlighted. It’s about 90% accurate, what’s missing is detecting variable assignments, but that can be easily resolved manually or with other CSS tricks. I didn’t want to invest more than one hour into this. The final listing will be also published styled as a HTML page for easy reading; still not sure though if I’m going to publish also all the steps while I’m making the game.

Having this done there is only one thing to do before I can write my first lines of code – setting up the floppy disk where I’m going to save my game. It’s very easy to create a empty formatted disk from the emulator, but I wanted to format it again from the C64. Just for info, one side of a C64 disk has a total of 170kb, but a little bit more then 5kb is reserved for the file allocation information (so called BAM – block availability map) and for keeping pointers to the next physical track. Meaning we have 664 blocks free for user data, and each block is 254 bytes long (a total of 168,656 bytes which is almost 165kb).

Here are some basic commands I’m using for operating the disk drive:

OPEN 1,8,15,“N:MAYA-GRAB 2016,01”: CLOSE 1
        format disk in drive 8 with name MAYA-GRAB 2016 and ID 01
LOAD “$”,8
        load the file directory from the disk in drive 8
LIST
        list the previously loaded file directory
LOAD “*”,8
        load the first file on disk from the disk in drive 8 at $0801
LOAD “MAYA-GRAB”,8
        load the file with given name from the disk in drive 8 at $0801
SAVE “MAYA-GRAB”,8
        save the file with given name to the disk in drive 8 at $0801

* * * * *

Maya Grab [Day 3] – Peeking into memory

Today I was busy taking screenshots of all the rooms and their states in the game. The complete solution for the game can be found here. Oh, did I say that the game is in german only? But no worries, I’ll make an english version too. Anyways, 46 screenshots of rooms and states are waiting for conversion back to C64 character graphics. It has to be done manually, or with a image to PETSCII tool, since the program is protected and can’t be listed. But that’s ok, I want to do it manually so I can practice a little bit creating graphics like this.

Having a solution for the game is fine, but there are surely more possibilities for writing commands to the interpreter and since, like mentioned before, the program is protected, there is only one thing left to try out – make a memory dump of the C64 and hope that the commands aren’t crunched or somehow hidden or crypted. Almost every emulator (I’m using VICE) has a built in Monitor, a powerful tool which you can use to write machine code or look into and alter specific memory addresses. So I’ve started the game, did a soft reset and started the tool. With the command “I” you can output a memory part, for example “I 0000 FFFF” will output all 64kb. I’ve mentioned before that the BASIC program is starting at address $0801 and there is also a 4kb upper RAM at $C000 which in this case was empty. What I’ve found out is that all the commands are stored from $2080 to $23A0. There are 35 verbs, 40 adverbs and 66 nouns for use. By looking further from $5000 to $7AA8, there were more strings which show up in the game, mixed with some other data or code probably for interpreting the commands.

Since I know now all the words that can be used I can, more or less, guess how the interpreter works. If you look at the solution you’ll notice that all the commands are build up verb + noun. Obviously, the adverbs, that come usually between those two words, are completely optional or just ignored. One more interesting thing is that the words are shortened to 5 or 6 characters. The word “schluessel” (“key” on german) is shortened to “schlu”. Basically you can write: “nimm schlu” to take the key. It’s valid and the interpreter understands it… like this also: “nimm schluabcdefghijklmn”. I assume that this is done for speeding up the interpreter, since there is enough memory to store whole words. You can also take an item more then once, the interpreter will say every time “OK”.

* * * * *