Category Archives: BASIC

Commander X16 BASIC Tiles

I continue to learn more about the Commander X16 retro platform and programming in BASIC. I want to make games for the platform, so I needed to come to grips with how VERA handles tiles.

Currently, I’m using VMWare Fusion on my Mac with a Windows 10 VM for doing my retro development. I’m using X16 emulator R38 ,NotePad++ ,Tiled ,HxD ,TexturePacker ,MOSpeed and Vera Graphics Converter.

I started with a few false starts, and then I found a tile tutorial on 8-bit coding, which started me off. However, I needed something more. I was struggling with several different things, workflow and debugging how to get the tile graphics into the system and look ok, how to edit tilemaps and get that data into the X16. What is happening in VERA memory? Argg, their program works why doesn’t mine. So, now I have worked some things out I decided I should share what I learnt. 

I started by finding a nice 256 colour tileset, and I created what I thought was a basic 64 x 64 tilemap in Tiled. I then spent time learning how to export data out of Tiled as BASIC DATA statements. At this point I realised maybe I had made a mistake, just the data statements for the graphics and map were almost 30k. Also, I wasn’t having much luck with displaying anything. I was getting graphic snow/static. I just couldn’t see into VERA to work out what was happening. I spent time looking at the emulator debugger documentation, and I just couldn’t see what I needed. I had a look at the debugger.c code out of curiosity and found CMD_DUMP_VERA='v'
This was it! This lets me view VERA memory. Start the X16 emulator with the -debug switch.
C:\x16emu_win-r38>x16emu.exe -bas TUTORIAL-TILES.BAS -debug
Then activate the debugger by pressing F12. Once in the debugger press v and type the memory address in VERA to view. Awesome. 

X16 Emulator started with -debug and viewing VERA memory at $4000.

I still wasn’t having much luck. I stumbled upon a forum post which reminded me about the VLOAD command. I hadn’t looked at it before since at the time the documentation just listed TODO. A good reminder that the X16 team were working faster on the code then the documentation. I had some problems using VLOAD with data that crossed from Bank 0 to Bank 1. So I just made sure my data fit in either Bank 0 or Bank 1. 

For this tutorial, I am trying something more significant than my initial successful program. In Tiled I created a 256 x 32 tiled map of 16×16 tiles. Giving a scroll area of 4096 x 512, suitable for a side scroller like Mario. With the X16 in 320×240 mode, this would provide close to 26 screens worth of map for a level. I created an elementary map. I then used Johan K√•rlin tool for tiled, which let me export the map data. The map data takes up just over 16k. I used a subset of a graphic tileset from Open Game Art. I used what I thought was a small sample, which ended up being 416 tiles. I then used VERA Graphics Converter to turn the png file into 16×16 tiles at 4 bit per pixel and exported the binary data file, which was 53kb! Clearly, when I do create a game, I will have to make sure I only included used tiles.

Tiled – Clearly, I need to develop my level creation skills.

Looking at VERA and its registers and memory, we can see that VERA can handle two layers. By default, it uses layer 1 for text. I was thinking of using layer 1 for a HUD/score/user information etc. So we will enable layer 0 and put the tiles there. But how to handle that? VERA has 128kb of memory, and my tile graphics were going to take 52kb, and the map was going to take 16kb. 

AddressNameBit 7 – BIT 6 – bit 5 – Bit 4 – Bit 3 – Bit 2 – Bit 1 – Bit 0
$9F29DC_VIDEO (DCSEL=0)Current Field (Bit 7) Sprites Enable (Bit 6) Layer1 Enable (Bit 5) Layer0 Enable (Bit 4) Unused (Bit 3) Chroma Disable (Bit 2) Output Mode (Bit 1-0)
$9F2DL0_CONFIGMap Height (Bit 7-6) Map Width (Bit 5-4) T256C (Bit 3) Bitmap Mode (Bit 2) Color Depth (Bit 1-0)
$9F2EL0_MAPBASEMap Base Address Bits 16-9 (Bit 7-0)
$9F2FL0_TILEBASETile Base Address Bit 16-11 (Bit 7-2) Tile Height (Bit 1) Tile Width (Bit 0)
$9F30L0_HSCROLL_LH-Scroll Bits 7-0 (Bit 7-0)
$9F31L0_HSCROLL_HUnused (Bit 7-4) H-Scroll Bits 11-8 (Bit 3-0)
$9F32L0_VSCROLL_LV-Scroll Bits 7-0 (Bit 7-0)
$9F33L0_VSCROLL_HUnused (Bit 7-4) V-Scroll Bits 11-8 (Bit 3-0)
$9F34L1_CONFIGMap Height (Bit 7-6) Map Width (Bit 5-4) T256C (Bit 3) Bitmap Mode (Bit 2) Color Depth (Bit 1-0)
$9F35L1_MAPBASEMap Base Address Bits 16-9 (Bit 7-0)
$9F36L1_TILEBASETile Base Address Bit 16-11 (Bit 7-2) Tile Height (Bit 1) Tile Width (Bit 0)
$9F37L1_HSCROLL_LH-Scroll Bits 7-0 (Bit 7-0)
$9F38L1_HSCROLL_HUnused (Bit 7-4) H-Scroll Bits 11-8 (Bit 3-0)
$9F39L1_VSCROLL_LV-Scroll Bits 7-0 (Bit 7-0)
$9F3AL1_VSCROLL_HUnused (Bit 7-4) V-Scroll Bits 11-8 (Bit 3-0)
Subset of VERA Registers for Layer 0 and 1

I will start the structure of this program with a simple main program and a number of subroutines which perform tasks. The first task is setting up the SCREEN in 320×240 mode.

Now we will need to enable layer 0. Doing so is relatively straight forward. We simply poke the right bit of memory. Looking at the table above we can see to enable layer 0 we just need to set bit 4 of $9F29 to be 1. I like to use binary when POKEing value so I set exactly the right bits. I want both layer 0 and 1 and enabled and the default output mode. For this, I will POKE $9F29, %00110001.

Now we have to do several pokes to configure Layer 0 in VERA. $9F2D is fairly straight forward. We will ignore T256C and Bitmap mode. We only have two bits for height and two bits for width. A binary value needs to be set.

decimalBinaryHeight / Width
00032 tiles
10164 tiles
210128 tiles
311256 tiles
VERA Layer Height and Width options

The last two bits in $9F2D are color depth. This value changes how VERA expects the colour data to be encoded. 8-Bit Coding has a tutorial which goes into more depth.

Color Depth valueDescription
01 bpp
12 bpp
24 bpp
38 bpp
VERA Layer Color Depth options

The next register took a little bit for me to understand. $9F2E. Initial I had thought it just took a 16-bit address for VERA memory and remove the eight least significate bits. But that didn’t work. It wasn’t until I started to think a bit more. 16-bit address only allows 64k. VERA has 128k of memory. To cover all 128k of memory the binary range is 0 0000 0000 0000 0000 – 1 1111 1111 1111 1111. The 17-bit is selecting which 64k bank is being used, bank 0 or bank 1. So this register actually needs the high 8-bits from a 17bit address. I found the Windows Calculator very handy for this. The example here is setting the tilemap base at $4000 in VERA. $4000 in binary is 0100 0000 0000 0000. If I poke 0100 0000 into the VERA register, it will not work correctly. If I change it so it is a 17bit address 0 0100 0000 0000 0000 and then I take the high 8-bits, I poke in 0010 0000 VERA should work correctly.

Windows Calculator in Programmer mode.

Once I understood the addressing issue, I found working with $9F2F easier. Instead of having the high 8-bits of the tile graphic location, it takes the high 6-bits. The last two bits set the height and width of the tiles. The height and width can be 8 or 16 pixels. Giving us a total of four different tile sizes; 8×8, 8×16, 16×8, 16×16. The example here is setting the tile graphics base at $10000 in VERA with 16×16 tiles. The 17-bit address is 1 0000 0000 0000 0000. I take the high 6-bits from the address. The tiles will be 16 x 16, so the height and width bits will be both be 1. So I poke in the binary value 1000 00 11.

Binary valueTile height / width
08 pixels
116 pixels
VERA Tile dimensions

If we started the program with what we have done at the moment, we would not see anything. Only the default blue background, the white text of layer 1 will be visible. VERA handles color 0 as transparent. Color 0 is normally black. We will use the COLOR command to set the foreground color to white (1) and background color to black (0). Then we will clear the screen using CLS and PRINT some instructions. That will be the end of the first subroutine, so we can then RETURN to the main program.

So far the code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 END
10000 REM SETUP DISPLAY
10010 SCREEN $00: REM SETUP SCREEN MODE 320X240
10020 REM CONFIGURE LAYER 0 AND DISPLAY TILES
10030 POKE $9F29, %00110001: REM TURN ON LAYER 0,1 AND VGA OUTPUT
10040 POKE $9F2D, %00110010: REM MAP 32 X 256, T256C, BITMAP MODE, COLOR DEPTH
10050 POKE $9F2E, %00100000: REM MAP BASE AT $4000
10060 POKE $9F2F, %10000011: REM SET TILE BASE AT $10000 AND H=16 W=16
10070 REM CONFIGURE LAYER 1 AND DISPLAY INSTRUCTIONS
10080 COLOR 1,0
10090 CLS
10100 PRINT "MOVE VIEW USING WASD. Q TO QUIT"
10110 RETURN

Now I need to load the tilemap data and tile graphic data straight into VERAs memory. We will use the VLOAD command. Now currently there isn’t any documentation for this, and I think there might be a bug in it as well. The data loaded should either fit entirely in bank 0 or bank 1 of VERA. If I try and load a large block of data starting in bank 0 and expecting it to continue into bank 1, I have a problem. I will investigate further, but I think VLOAD works with this syntax;
VLOAD "filename",device,<VERA memory bank>, <VERA memory address>
For this example, I have two files. TILEMAP-256X32.BIN and TILE-GFX.BIN. I then use sub-routines to load each of the files into VERA. The tilemap base is at $4000 in bank 0, so the command should look like VLOAD "TILEMAP-256X32.BIN",0,$4000. The tile graphic data is at $10000, so address $0000 in bank 1. The command will look like VLOAD "TILE-GFX.BIN",1,$0000

So far the code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 GOSUB 20000: REM SETUP TILE MAP
120 GOSUB 30000: REM SETUP TILE GRAPHICS
130 END

10000 REM SETUP DISPLAY
10010 SCREEN $00: REM SETUP SCREEN MODE 320X240
10020 REM CONFIGURE LAYER 0 AND DISPLAY TILES
10030 POKE $9F29, %00110001: REM TURN ON LAYER 0,1 AND VGA OUTPUT
10040 POKE $9F2D, %00110010: REM MAP 32 X 256, T256C, BITMAP MODE, COLOR DEPTH
10050 POKE $9F2E, %00100000: REM MAP BASE AT $4000
10060 POKE $9F2F, %10000011: REM SET TILE BASE AT $10000 AND H=16 W=16
10070 REM CONFIGURE LAYER 1 AND DISPLAY INSTRUCTIONS
10080 COLOR 1,0
10090 CLS
10100 PRINT "MOVE VIEW USING WASD. Q TO QUIT"
10110 RETURN

20000 REM SETUP TILE MAP
20010 VLOAD "TILEMAP-256X32.BIN",8,0,$4000
20020 RETURN

30000 REM SETUP TILE GRAPHICS
30020 VLOAD "TILE-GFX.BIN",8,1,$0000
30030 RETURN

To see how it is going I copied the two data files and the BASIC file into the X16 emulator directory and ran;
C:\x16emu_win-r38>x16emu.exe -bas TUTORIAL-TILES.BAS -debug
To see how it appeared…. and success!

Success – Tilemap and graphic data loaded and displayed.

Now I want the program to take keyboard input and move the view around so we can explore the entire map. The maximum layer area that VERA can handle is 4096 pixels, starting at 0 and going to 4095. However, we can only poke up to a value of 255! 0 to 4095 is a 12-bit address, 0000 0000 0000 to 1111 1111 1111. When we look at the VERA registers, we see that the horizontal scroll is $9F30 for the low 8-bits and $9F31 for the high 4-bits. Unlike assembly, you just can’t grab the high, or low 8-bits using < or > and manipulate data as easily. (I would like to be wrong here so if you know otherwise please leave a comment). So we need to create a few variables to handle data. I’m going to make two variables to keep track of the tile horizontal and vertical location, TH and TV. Then to convert those numbers into values, these we can poke into VERA. I will create HL and HH for the horizontal low and high values. As well as a VL and VH variable for vertical low and high values. I will also create a variable to store the movement speed, MV.

I will create another subroutine to handle moving the screen view around the layer. Then I will GET the keyboard input and store it in variable K$. Inside the loop, it will check which key was pressed and call a subroutine to move the view either left/right/up/down. Then it will loop back to GET the keyboard input again.

So far the code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 GOSUB 20000: REM SETUP TILE MAP
120 GOSUB 30000: REM SETUP TILE GRAPHICS
130 GOSUB 1000: REM THE MAIN LOOP
140 END

1000 REM MAIN LOOP
1010 LET TH=0: TV=0: REM TILE HORIZONTAL AND VERTICAL LOCATION 0-4095
1020 LET HH=0: HL=0: VH=0: VL=0: REM HIGH AND LOW VALUES FOR HOR AND VER
1030 LET MV=2: REM SET DEFAULT MOVEMENT SPEED
1040 GET K$: REM READ IN KEYPRESSES
1050 IF K$="A" THEN GOSUB 1100: REM MOVE LEFT
1060 IF K$="D" THEN GOSUB 1200: REM MOVE RIGHT
1070 IF K$="W" THEN GOSUB 1300: REM MOVE UP
1080 IF K$="S" THEN GOSUB 1400: REM MOVE DOWN
1090 IF K$="Q" THEN RETURN: REM EXIT SUBROUTINE
1095 GOTO 1040: REM LOOP BACK TO GET KEYBOARD INPUT

We create a subroutine for each of the movements. The program will also check bounds. When moving left, we should not have a value of less than 0. When moving to the right, we have to adjust a little. The screen view is 320 pixels wide. We don’t want to move the screen view all the way to 4095; otherwise, the layer will wrap around, and we will be looking at layer pixels 0-319. So we limit the movement to 3776, which is layer width (4096) – screen view width (320). When moving up, we should not have a value of less than 0. When moving down, we have to adjust a little again. The screen view is 240 pixels high. We have a layer vertical size of 512, so we will limit movement to 272, which is layer height (512) – screen view height (240). We then call the subroutine for calculating the values which will be POKEd into VERA. Then call the subroutine for updating VERA.

1100 REM MOVE VIEW LEFT
1110 IF TH = 0 THEN RETURN
1120 TH=TH-MV
1130 GOSUB 1700: REM CALCULATE 8BIT
1140 GOSUB 1900: REM UPDATE SCROLL
1150 RETURN

1200 REM MOVE VIEW RIGHT
1210 IF TH = 3776 THEN RETURN: REM LAYER WIDTH - SCREEN VIEW WIDTH
1220 TH=TH+MV
1230 GOSUB 1700: REM CALCULATE 8BIT
1240 GOSUB 1900: REM UPDATE SCROLL
1250 RETURN

1300 REM MOVE UP
1310 IF TV = 0 THEN RETURN
1320 TV=TV-MV
1330 GOSUB 1800: REM CALCULATE 8BIT
1340 GOSUB 1900: REM UPDATE SCROLL
1350 RETURN

1400 REM MOVE DOWN
1410 IF TV = 272 THEN RETURN: REM 512-240
1420 TV=TV+MV
1430 GOSUB 1800: REM CALCULATE 8BIT
1440 GOSUB 1900: REM UPDATE SCROLL
1450 RETURN

Now we need to calculate the 8-bit values which will get POKEd into VERA. The X16 handles numbers in 8-bit chunks, 0-255. VERA allows scroll values from 0 to 4095, 0000 0000 0000 – 1111 1111 1111. VERA has $9F30 for the low 8 bits and $9F31 for the hight 4-bits. We think of this process as some basic division maths. The 4-bit high value is the horizontal location divided by 255, and the 8-bit low value is the remainder of that division. We have to so a few steps. I use the HH variable to store the horizontal high value, which is the INTeger result of TH (Tile Horizontal location) divided by 255. By using the INT function, we only get the quotient and no remainder (float value, decimal numbers) The HL variable stores the result of the TH – number of times 255 went into it, giving me an integer less than 255. We do the process again for the vertical. Once each of these sub-routines has completed return to the code which called them.

1700 REM CALCULATE HORITZONAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1710 HH = INT(TH / 255)
1720 HL = TH - (HH * 255)
1730 RETURN

1800 REM CALCULATE VERTICAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1810 VH = INT(TV / 255)
1820 VL = TV - (VH * 255)
1830 RETURN

Finally the subroutine for updating VERA. We just POKE the horizontal and vertical values into the VERA scroll registers for layer 0.

1900 REM UPDATE VERA FOR NEW LAYER SCROLL
1910 POKE $9F30,HL
1920 POKE $9F31,HH
1930 POKE $9F32,VL
1940 POKE $9F33,VH
1950 RETURN

With my BASIC code, I’ve tried to use as many comments as possible. I’m also using empty lines to help break up my code. I’m sure my code is not efficient or as fast as it could be. All the code, Tiled map file, binary and graphics are available from the Github repo.

So now the completed code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 GOSUB 20000: REM SETUP TILE MAP
120 GOSUB 30000: REM SETUP TILE GRAPHICS
130 GOSUB 1000: REM THE MAIN LOOP
140 END

1000 REM MAIN LOOP
1010 LET TH=0: TV=0: REM TILE HORIZONTAL AND VERTICAL LOCATION 0-4095
1020 LET HH=0: HL=0: VH=0: VL=0: REM HIGH AND LOW VALUES FOR HOR AND VER
1030 LET MV=2: REM SET DEFAULT MOVEMENT SPEED
1040 GET K$: REM READ IN KEYPRESSES
1050 IF K$="A" THEN GOSUB 1100: REM MOVE LEFT
1060 IF K$="D" THEN GOSUB 1200: REM MOVE RIGHT
1070 IF K$="W" THEN GOSUB 1300: REM MOVE UP
1080 IF K$="S" THEN GOSUB 1400: REM MOVE DOWN
1090 IF K$="Q" THEN RETURN: REM EXIT SUBROUTINE
1095 GOTO 1040: REM LOOP BACK TO GET KEYBOARD INPUT

1100 REM MOVE VIEW LEFT
1110 IF TH = 0 THEN RETURN
1120 TH=TH-MV
1130 GOSUB 1700: REM CALCULATE 8BIT
1140 GOSUB 1900: REM UPDATE SCROLL
1150 RETURN

1200 REM MOVE VIEW RIGHT
1210 IF TH = 3776 THEN RETURN: REM LAYER WIDTH - SCREEN VIEW WIDTH
1220 TH=TH+MV
1230 GOSUB 1700: REM CALCULATE 8BIT
1240 GOSUB 1900: REM UPDATE SCROLL
1250 RETURN

1300 REM MOVE UP
1310 IF TV = 0 THEN RETURN
1320 TV=TV-MV
1330 GOSUB 1800: REM CALCULATE 8BIT
1340 GOSUB 1900: REM UPDATE SCROLL
1350 RETURN

1400 REM MOVE DOWN
1410 IF TV = 272 THEN RETURN: REM 512-240
1420 TV=TV+MV
1430 GOSUB 1800: REM CALCULATE 8BIT
1440 GOSUB 1900: REM UPDATE SCROLL
1450 RETURN

1700 REM CALCULATE HORITZONAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1710 HH = INT(TH / 255)
1720 HL = TH - (HH * 255)
1730 RETURN

1800 REM CALCULATE VERTICAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1810 VH = INT(TV / 255)
1820 VL = TV - (VH * 255)
1830 RETURN

1900 REM UPDATE VERA FOR NEW LAYER SCROLL
1910 POKE $9F30,HL
1920 POKE $9F31,HH
1930 POKE $9F32,VL
1940 POKE $9F33,VH
1950 RETURN

10000 REM SETUP DISPLAY
10010 SCREEN $00: REM SETUP SCREEN MODE 320X240
10020 REM CONFIGURE LAYER 0 AND DISPLAY TILES
10030 POKE $9F29, %00110001: REM TURN ON LAYER 0,1 AND VGA OUTPUT
10040 POKE $9F2D, %00110010: REM MAP 32 X 256, T256C, BITMAP MODE, COLOR DEPTH
10050 POKE $9F2E, %00100000: REM MAP BASE AT $4000
10060 POKE $9F2F, %10000011: REM SET TILE BASE AT $10000 AND H=16 W=16
10070 REM CONFIGURE LAYER 1 AND DISPLAY INSTRUCTIONS
10080 COLOR 1,0
10090 CLS
10100 PRINT "MOVE VIEW USING WASD. Q TO QUIT"
10110 RETURN

20000 REM SETUP TILE MAP
20010 VLOAD "TILEMAP-256X32.BIN",8,0,$4000
20020 RETURN

30000 REM SETUP TILE GRAPHICS
30020 VLOAD "TILE-GFX.BIN",8,1,$0000
30030 RETURN

Combined with the data files, we get a nice little demo of X16 tiles and BASIC.

X16 – Tile demo in BASIC

Commander X16 BASIC from old Compute book code.

As a bit of challenge for myself, I am re-reading a few old Compute programming books for the Commodore 64 and converting them to run on the Commander X16. The book I’m currently working on is “Compute’s First Book of 64 Games” from 1983. Which is available on archive.org

Investment Simulation

5 PRINT"{CLR}"
10 CASH=100000:PGLD=499
15 POKE 53272,23:REM SHIFT TO LOWER CASE
20 PB=80
31 PRINT: PRINT"BUNDTFUND IS $"PB" PER SHARE.YOU HAVE "B"{4 SPACES}SHARES. -- $"PB*B
33 PRINT" GOLD IS{4 SPACES}$"GLS" OUNCES. -- $"GLD*PGLD
34 T=PB*B+GLD*PGLD
35 PRINT:PRINT" TOTAL INVESTMENTS -- $"T
36 PRINT:PRINT" YOU HAVE $"CASH" TO SPEND."
40 PRINT:PRINT" GRAND TOTAL":PRINT"(INVESTMENTS + CASH){4 SPACES}$"T+CASH
45 IFCK=1THEN500
50 PRINT:PRINT"1.BUY{2 SPACES}2.SELL{2 SPACES}3.DONE"
60 INPUTA:IFA=3THENCK=1:GOTO31
100 PRINT"WHICH?{3 SPACES}1.GOLD{4 SPACES}OR{4 SPACES}2.STOCK"
110 INPUTF
120 PRINT"HOW MANY (SHARES{3 SPACES} OR {3 SPACES} OUNCES)?"
130 INPUTN
140 IFF=1THEN160
150 PRINCE=PB*N:IFA=1THENCASH=CASH-PRICE:B=B+N:GOTO400
155 CASH=CASH+PRICE:GLD=GLD-N
160 PRICE=PGLD*N:IFA=1THENCASH=CASH-PRICE:GLD=GLD+N:GOTO400
170 CASH=CASH+PRICE:GLD=GLD-N
400 GOTO50
500 PRINT"PRESS ANY KEY TO CONT";
503 GET C$:IF C$=""THEN503
505 CK=0:PRINT:PRINT"{CLR}ONE MONTH LATER ...":FOR T=1TO700:NEXTT:PRINT
510 X=INT((RND(1)*100/10):Y=INT((RND(1)*200/10):Z=RND(1)
520 CH=CH+1:IFCH>4ANDCH<XTHENCH=0:GOTO600
525 IFCH=2GOTO600
530 IF Z>.5 THENPB=PB+X:PGLD=PGLD-Y:GOTO31
540 PB=PB-X:PGLD=PGLD+Y:GOTO31
600 PRINT"INTERNATIONAL UNREST...":PGLD=PGLD+2*Y:PB=PB-2*X:GOTO31
700 PRINT"MARKET RALLY ...{2 SPACES}":PGLD=PGLD-2*Y:PB=PB+3*X:GOTO31

While typing it all out I noticed bugs. Originally I thought I must be mistaken, but no. BuWhile typing it all out, I noticed bugs. Initially, I thought I must be mistaken, but no. Bugs like on line 33 with a variable called “GLS” instead of “GLD”. Then on line 150 with variables called “PRINCE” instead of “PRICE”. It also struck me that the formatting of the code could be more helpful. Finally, the number of GOTO creating a little pile of spaghetti code, which is one of the problems with BASIC.

So when I re-worked the code, I tried to create blocks of subroutines. Tried to remove all of the GOTOs. I also created little checks to make sure the player has enough money/gold/stock to do the function they want. I don’t think my code is more efficient than the original. I do, however, think it is easier to read and follows a more modern design. My code is available on Github.

1 REM COMPUTES FIRST BOOK OF 64 GAMES 
2 REM INVESTMENT SIMULATION
3 REM ORIGINAL BY RICHARD MANSFIELD
4 REM UPDATED BY JUSTIN BALDOCK
6 REM CASH = PLAYERS CASH : 
7 REM PB = PRICE OF 8BIT FUND : REM PGLD = PRICE OF GOLD
8 REM B = NUMBER OF 8BIT SHARES PLAYER HAS : REM GLD = NUMBER OF GOLD OUNCES PLAYER HAS
9 REM T = TOTAL VALUE OF PLAYER : REM CP = CAN PURCHASE
10 CASH=100000:PGLD=400
20 PB=80
29 PRINT CHR$(147) : REM CLEAR SCREEN
30 PRINT : REM SPACING
31 PRINT " 8-BIT FUND IS $"PB" PER SHARE. YOU HAVE "B" SHARES. -- $"PB*B
33 PRINT " GOLD IS $"PGLD" PER OUNCE. YOU HAVE "GLD" OUNCES. -- $"GLD*PGLD
34 T=(PB*B)+(GLD*PGLD)
35 PRINT:PRINT" TOTAL INVESTMENTS -- $"T
36 PRINT:PRINT" YOU HAVE $"CASH" TO SPEND."
40 PRINT:PRINT" GRAND TOTAL":PRINT"(INVESTMENTS + CASH)    $"T+CASH
50 PRINT:PRINT"1.BUY   2.SELL  3.DONE  4.QUIT"
60 INPUT A:IF A=3 THEN GOTO 4000 : REM GOTO THE MARKET SIMULATOR
70 IF A=4 THEN END
100 PRINT "WHICH?   1.GOLD    OR    2.STOCK"
110 INPUT F
120 PRINT "HOW MANY (SHARES   OR   OUNCES)?"
130 INPUT N
140 IF A=1 THEN IF F=1 THEN GOSUB 5600
145 IF A=1 THEN IF F=2 THEN GOSUB 5400
150 IF A=2 THEN IF F=1 THEN GOSUB 5200
155 IF A=2 THEN IF F=2 THEN GOSUB 5000
160 PRINT" PRESS ANY KEY TO CONTINUE."
170 GET C$: IF C$="" THEN GOTO 170 : REM WAIT FOR THE USER TO PRESS ANY KEY
180 GOTO 29 : REM RESTART THE MAIN LOOP
4000 REM
4001 REM THE MARKET SIMULATION
4010 PRINT:PRINT" ONE MONTH LATER...  "
4020 PRINT"                    ..."
4030 X=INT((RND(1)*100)/10):Y=INT((RND(1)*200)/10):Z=RND(1)
4040 CH=CH+1:IF CH>4 AND CH<X THEN CH=0: GOSUB 4400
4050 IF CH=2 THEN GOSUB 4500
4060 IF Z> .5 THEN GOSUB 4700
4070 IF Z<=.5 THEN GOSUB 4600
4080 PRINT:PRINT " THE MARKET MOVES..."
4090 PRINT:PRINT "                    ... PRESS ANY KEY TO CONTINUE."
4100 GET C$: IF C$="" GOTO 4100
4110 GOTO 29 : REM RETURN TO OUR MAIN LOOP
4120 END : REM THIS CODE SHOULD NEVER RUN
4400 REM
4401 REM METHOD INTERNATIONAL UNREST
4410 PRINT:PRINT" INTERNATIONAL UNREST...  "
4420 PGLD=PGLD+2*Y:PB=PB-2*X
4430 RETURN
4500 REM
4501 REM METHOD MARKET RALLY
4510 PRINT:PRINT" MARKET RALLIES ...  "
4520 PGLD=PGLD-2*Y:PB=PB+3*X
4530 RETURN
4600 REM
4601 REM METHOD GOLD UP, STOCK DOWN
4610 PB=PB-X:PGLD=PGLD+Y
4620 RETURN
4700 REM
4701 REM METHOD GOLD DOWN, STOCK UP
4710 PB=PB+X:PGLD=PGLD-Y
4720 RETURN
5000 REM
5001 REM SELL SHARES, PASS (N)UMBER OF SHARES TO SELL
5010 GOSUB 6000
5020 IF CP = 0 THEN PRINT" NOT ENOUGH SHARES TO SELL.":RETURN
5030 PRICE = PB*N : REM CAL PRICE
5040 CASH = CASH+PRICE : REM UPDATE CASH
5050 B = B-N : REM UPDATE STOCK OWNED
5060 PRINT " STOCK SOLD."
5070 RETURN
5200 REM
5201 REM METHOD SELL GOLD, PASS (N)UMBER OF GOLD TO SELL
5210 GOSUB 6100
5220 IF CP = 0 THEN PRINT" NOT ENOUGH GOLD TO SELL.":RETURN
5230 PRICE = PGLD*N : REM CAL PRICE
5240 CASH = CASH+PRICE : REM UDPATE CASH
5250 GLD = GLD-N :  REM UPDATE GOLD OWNED
5260 PRINT " GOLD SOLD."
5270 RETURN
5400 REM
5401 REM METHOD BUY SHARES, PASS (N)UMBER OF SHARES TO BUY
5410 PRICE = PB*N : REM CAL PRICE
5420 GOSUB 5800 : REM CHECK TO SEE IF PLAYER HAS ENOUGH MONEY
5430 IF CP = 0 THEN PRINT" NOT ENOUGH CASH TO PURCHASE SHARES":RETURN
5440 CASH = CASH-PRICE : REM UPDATE CASH
5450 B = B+N : REM UPDATE STOCK OWNED
5460 PRINT " STOCK PURCHASED."
5470 RETURN
5600 REM
5601 REM METHOD BUY GOLD, PASS (N)UMBER OF GOLD TO BUY
5610 PRICE = PGLD*N : REM CAL PRICE
5620 GOSUB 5800 : REM CHECK TO SEE IF PLAYER HAS ENOUGH MONEY
5630 IF CP = 0 THEN PRINT" NOT ENOUGH CASH TO PURCHASE GOLD":RETURN
5640 CASH = CASH-PRICE : REM UPDATE CASH
5650 GLD = GLD+N : REM UPDATE GOLD OWNED
5660 PRINT " GOLD PURCHASED."
5670 RETURN
5800 REM
5801 REM METHOD CHECK IF PLAYER HAS ENOUGH CASH
5810 IF CASH>=PRICE THEN CP=1
5820 IF CASH<PRICE THEN CP=0
5830 RETURN
6000 REM
6001 REM METHOD CHECK IF PLAYER HAS ENOUGH STOCK, PASS (N)UMBER OF STOCK TO SELL
6010 IF B>=N THEN CP=1
6020 IF B<N THEN CP=0
6030 RETURN
6100 REM
6101 REM METHOD CHECK IF PLAYER HAS ENOUGH GOLD, PASS (N)UMBER OF GOLD TO SELL
6110 IF GLD>=N THEN CP=1
6120 IF GLD<N THEN CP=0
6130 RETURN

I’ve started to update the next BASIC game, Ping-Pong. I’ve included the original C64 code listing again. At a first glance the code appears fairly good.

100 SCR=1024:COL=55296:POKE 53281,0
110 WALL=160:REM WALL CHARACTER, SOLID SQUARE.TRY {SPACE}OTHER CHARACTERS.
120 LN=40
130 GOSUB 260:REM DRAW BORDER
140 LOC=SCR+LN*10+LN/2:CLOC=COL+LN*10/2:REM SCREEN AND COLOR LOCATION
150 VECTR=LN:REM ALSO TRY -1,+1,LN-1,LN+1,ETC
160 BLANK=32
170 FIGURE=81:REM "BALL"CHARACTER.
180 IF PEEK(LOC+VECTR)<>WALL THEN 200
190 VECTR=-VECTR:REM REVERSE DIRECTION
200 POKE LOC,BLANK:REM ERASE OLD BALL
210 LOC=LOC+VECTR:CLOC=CLOC+VECTR:REM CALCULATE NEW POSITION
220 POKELOC+54272,1:POKELOC,81:REM PLACE BALL
230 GOTO180
240 END
250 REM BORDER SUBROUTINE
260 PRINT CHR$(147) : REM CLEAR SCREEN
270 FOR I=0 TO LN-1:POKE SCR+I,WALL:POKE COL+I,2:NEXTI:REM TOP
280 FOR I=0 TO LN-1:POKE SCR+LN*24+I,WALL:POKECOL+LN*24+I,2:NEXT I:REM BOTTOM
290 FOR I=0 TO 24: POKESCR+I*LN,WALL:POKECOL+I*LN,2:NEXT I:REM LEFT
300 FOR I=0 TO 24:POKE SCR+LN-1+I*LN,WALL:POKECOL+LN-1+I*LN,2:NEXTI:REM RIGHT
310 RETURN

Commander X16 Adventures in BASIC

Going over some old Commodore 64 books and re-typing up the old programs and adjusting them for the X16.

Bouncing Ball
Its good to experiment. To change the speed that the ball moves at change the value 50 on line 50 and line 100 to another value. The lower the value tm the faster the ball will move.

10 rem bouncing ball
20 print "{clr/home}"
25 for x = 1 to 10 : print "{crsr/down}:next
30 for bl = 0 to 78
40 print " {shift q}{crsr/left}";
50 for tm = 1 to 50
60 next tm
70 next bl
75 rem move ball right to left
80 for bl = 78 to 0 step -1
90 print " {crsr/left}{crsr/left}{shift q}{crsr/left}";
100 for tm = 1 to 50
110 next tm
120 next bl
130 goto 20

Classic maze
The maze program which can be converted in to the classic one liner which gives the unique maze on the Commodore 64. It runs and look pretty much identical on the X16.

10 print "{clr/home}"
20 print chr$(205.5+rnd(1));
30 goto
10 print chr$(205.5+rnd(1));:goto10

Lets make the maze a little bit more colourful. We are creating a random number between 0 and 1. We then use chr$ to send a control sequence to change the colour either yellow or cyan and then print use chr$ to print either a / or \.

10 let rn = int(0.5+rnd(1))
20 print chr$(158+rn);chr$(205+rn);
30 goto 10