The author has recently expressed an interest in the listings for games from the recent 4K BASIC challenge on the Atari Age forums so here, for his edification and indeed yours dear reader, is your correspondent’s entry, detokenised and commented on at very little extra cost.
Stellar Caverns works in the same way as all of those “use PRINT to scroll the screen” games that many thirty- and forty-somethings will have typed in from books and magazines (as well as creating for themselves) during the 1980s, but sneakily rewrites the display list (which controls the layout of the Atari’s display) so that the first line of what BASIC considers to be the screen is at the bottom, the second line above it and so on until the next to last is reached; the last line of BASIC’s screen is skipped because scrolling using PRINT causes some flickering and hiding the line is a cheap and cheerful way to hide that. The Stellar Caverns logo is in a different mode and “hidden” away from the regular screen memory so it remains unaffected by anything else happening onscreen.
So onwards to the program itself with comments to follow:
10 LC=39808:FOR T=1 TO 3:POKE LC,112:LC=LC+1:NEXT T
15 POKE LC,70:POKE LC+1,0:POKE LC+2,6:LC=LC+3
20 SC=40920-40:FOR T=1 TO 23
30 POKE LC,66:POKE LC+1,SC-(INT(SC/256)*256):POKE LC+2,INT(SC/256):LC=LC+3
40 SC=SC-40:NEXT T
50 POKE LC,65:POKE LC+1,128:POKE LC+2,155
55 POKE 752,1:PRINT “[clear screen]”
60 POKE 560,128:POKE 561,155
To start with, lines 10 to 50 create a new display list in memory from location 39808 onwards and then line 60 enables it. There are no handy graphics commands from BASIC to do any of this so the POKE commands are necessary.
80 FOR T=0 TO 19:READ D:POKE 1536+T,D:NEXT T
90 SETCOLOR 1,0,0:SETCOLOR 2,0,0:SETCOLOR 0,15,10
Line 80 reads the data from lines 1000 to 1020 – the “Stellar Caverns” text for the top line of the screen – and writes them into a spare gap in memory at 1536; this area is pretty much free space for programmers to use and usually referred to as page 6 (a page is 256 bytes long) and yes, the Atari magazine was named after it! Line 90 is there to initalise some of the playfield colours.
100 POKE 53277,2:POKE 623,1:POKE 559,62
110 POKE 54279,128
120 FOR T=0 TO 255:POKE 33792+T,0:POKE 34048+T,255:POKE 34304+T,255:NEXT T
125 POKE 53249,48:POKE 53250,200
130 FOR T=0 TO 23:READ D:POKE 33968+T,D:NEXT T
These lines enable on the hardware sprites, initialise a few options and set up the sprite data. Line 120 clears the player’s sprite and fills two more used to mask off the sides of the playfield, whilst line 125 positions the masking sprites and line 130 copies some data from lines 1100 to 1120 to the player sprite to get it ready for use. Again, there’s nothing in the BASIC to do these jobs so they have to be handled with POKEs.
200 PRINT “[clear screen]”:POKE 53248,0
205 SETCOLOR 1,2,15:SETCOLOR 2,14,2
210 POSITION 2,16:PRINT ” S T E L L A R C A V E R N S ”
220 POSITION 9,10:PRINT “CODED BY JASON (T.M.R)”
230 POSITION 6,7:PRINT “CODED 18TH AUGUST 2012 FOR A”
235 POSITION 5,5:PRINT “BASIC COMPETITION AT ATARI AGE”
240 POSITION 9,2:PRINT ” PRESS FIRE TO START! “
Line 200 clears the screen and hides the player sprite out of visible range, then the title screen is initialised. (Lines 210 and 240 have inverted text that hasn’t been translated to ASCII).
280 SETCOLOR 0,LC,10
285 LC=LC+1:IF LC>15 THEN LC=1
290 IF STRIG(0)=1 THEN 280
295 SETCOLOR 0,15,10
This updates the colour of the Stellar Caverns logo at the top of the playfield whilst waiting for the fire button to be pressed, then resets it on the way out.
500 DIM LS$(80):HI=500
510 LS$=” < > ”
525 PRINT “[clear screen]”:FOR T=1 TO 24:PRINT :NEXT T:POKE 704,15
Set up the game’s variables. LS$ is a string containing the landscape (again, with some inverted characters which don’t translate, they stop at the first chevron and restart at the second) whilst LX is Landscape X (where in LS$ is displayed for each update) and PX is player X position. The rest of these variables are timers and counters being initialised; RD is Random Direction (so which way the landscape is moving, either left or right), RT is a timer used to decide when the next random direction change will happen, DT, DL and HT are all used to decide when random elements are introduced over the landscape. SC is the player’s score and HI (which is set on line 500 so not called each time the game is started) is the high score.
Finally, line 525 clears the screen and prints the initial tunnel before the game itself starts. Speaking of which…
530 PRINT LS$(LX,LX+35)
531 HT=HT-1:IF HT<1 THEN HT=DL*2:POKE 40884+(31*RND(0)),190+(30*RND(0))
535 POKE 53248,PX
540 IF RD=0 THEN LX=LX-1:IF LX<2 THEN LX=2:RD=1
545 IF RD=1 THEN LX=LX+1:IF LX>44 THEN LX=44:RD=0
550 RT=RT-1:IF RT=0 THEN RT=DL+INT(10*RND(0)):RD=INT(2*RND(0))
555 DT=DT-1:IF DT<1 THEN DT=200:DL=DL-1:IF DL<1 THEN DL=1
570 IF JOY=4 OR JOY=5 OR JOY=7 THEN PX=PX-5:IF PX<56 THEN PX=56
580 IF JOY=8 OR JOY=9 OR JOY=10 THEN PX=PX+5:IF PX>191 THEN PX=191
590 IF PEEK(53252)>0 THEN GOTO 700
600 SC=SC+5:GOTO 530
This is the game’s main loop. Line 530 PRINTs a new line of landscape which forces the screen to scroll whilst 531 will, as long as the timers say to do so, occasionally add random extra characters to liven things up. 535 positions the player’s sprite horizontally based. Lines 540 to 555 deal with randomly moving the landscape left or right and deciding when a new move starts.
The all-important joystick input is dealt with by lines 560 to 580 and there are three possible values being checked for each direction to discard accidental diagonals, sadly the lack of bitwise commands in Atari BASIC means this can’t be done as a faster single check. Line 590 PEEKs the hardware sprite collision register to see if the player has smashed into the landscape (again, there is no dedicated command from BASIC to do this) and makes a jump to 700 if so, otherwise the score is incremented by five points and the game loop restarts.
700 FOR T=16 TO 127 STEP 2:POKE 704,T:SOUND 1,255*RND(0),80,10:NEXT T
705 SOUND 0,0,0,0:SOUND 1,0,0,0
710 IF SC>HI THEN HI=SC
750 POSITION 10,10:PRINT ” SCORE”
755 POSITION 10,10:PRINT SC
760 POSITION 10,8:PRINT ” TOP SCORE”
765 POSITION 10,8:PRINT HI
770 POSITION 13,14:PRINT ” GAME OVER! ”
772 FOR T=1 TO 40:IF STRIG(0)=0 THEN 790
773 NEXT T
775 POSITION 13,14:PRINT ” GAME OVER! ”
777 FOR T=1 TO 40:IF STRIG(0)=0 THEN 790
778 NEXT T
780 IF STRIG(0)=1 THEN 770
790 GOTO 510
Finally there’s the game over routine which plays a “you died” sound before displaying the player’s score and best of the day and an “animated” game over message (line 775 has inverted text, again not translated). That’s the end of the program itself, so all that follows is data.
1000 DATA 0,0,51,52,37,44,44,33
1010 DATA 50,0,35,33,54,37,50,46
1020 DATA 51,1,0,0
This first block of DATA statements contains the text “Stellar Caverns” and some space characters to pad the line out to twenty characters. This is used for the top of the play area, copied into place by line 80.
1100 DATA 24,24,60,60,126,126,0,126
1110 DATA 102,66,66,126,24,90,90,219
1120 DATA 219,219,219,219,195,153,60,60
And finally, the sprite definition data for the player’s ship, which is copied to memory by line 130.