VIC-20: Sky-Ape-Er code dissection – part 3

See also: part 1, part 2, part 3, part 4 or part 5 (with more coming).

Its time for another VIC-20 Tuesday!

In this installment, I will walk through the code for my VIC-20 game Sky-Ape-Er. Thanks to a wonderful utility I mentioned in part one, I have this ASCII program listing. The utility replaces the special PETASCII control characters with {words} so they can be viewed on non-Commodore systems.

Sky-Ape-Er program listing

Initialization

1 POKE 808,100
  • That poke would “disable the RUN/STOP key, the RESTORE key, and the LIST command” to keep someone from being able to save a copy of it.
5 REM  ************          *SKY-APE-ER*        *******BY*******
6 REM*ALLEN HUFFMAN* ****************{$cc}
  • Comments, but with no dates. Thanks, me. One of my tapes had the game in various stages of completion, named “SKY-APE-ER 1”, “SKY-APE-ER 2” and “SKY-APE-ER 3”, but all my other tapes just called it SKY-APE-ER, and I’ve found at least two distinct versions of the game so far.
  • I am not sure what the {$cc} is at the end. From looking at the c64list.exe command I used to make this listing, it seems to be an unknown token. This might have been something I placed in that line to prevent listing, even after a LOAD without the POKE being executed. But, you can LIST 10- and still see it ;-)
10 S=1:POKE36879,26:POKE36878,15:S1=36875:POKE775,200:POKE36869,255
  • S is the screen (level) to display. Sky-Ape-Er contained three screens, and a “game won” screen.
  • 36879 is the border color, with 26 being red.
  • 36878 is something to do with the music chip.
  • S1 is being set to the sound note location 36875.
  • 775,200 disables LIST. Or maybe not. There was conflicting information in the magazine I looked that up in.
  • 36869 enables the custom font characters.

Set up game screen

15 PRINT"{clear}":L=8118:B=7772:M=15
  • L is the starting memory location for the player.
  • B is the starting memory location of the chimp (B for barrel, I suppose, as this was inspired by Donkey Kong).
  • M is the character to POKE to the screen for the player (man). 15 is the letter”O”.
20 FORA=38400TO38905:POKEA,0:NEXTA
  • This clears the color for each character on the screen. The characters for the screen are stored in one block of memory, and the color of each character is stored in a different block of memory.

Display ape

25 PRINT"{home}{down}{right}{black}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"
  • This clears the screen, then draws the letters that make up the ape character. The VIC-20 has no PRINT@ or LOCATE function, but you could embed cursor movement commands in the PRINT statements. Thus, it would “home” to the top fo the screen, move the cursor {down} one, then {right} one, set the color to {black}, print ABC, then go {down} one and {left} three times (cursor is now back under the A) and print DEF, and repeat for the other lines. The ape was 3×4 characters in size!

Display game screen

30 ONSGOTO35,45,55,500
  • This goes to the appropriate routine to display the current screen (level) based on the value of S. There were three screens. If S is 4, it goes to a “win” screen.

Screen 1

35 PRINT"{red}@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}";
40 PRINT"@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70

That would draw this:

Sky-Ape-Er screen 1.

Screen 2

45 PRINT"{blue}@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";
50 PRINT"@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70

That would draw this:

VIC-20 Sky-Ape Er, screen 2.

Screen 3

55 PRINT"{purple}@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{up:3}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";
60 PRINT"@@@{up:4}{left}@@@{down}{left}@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@{up}{left}@{up}{left}@"

That would draw this:

VIC-20 Sky-Ape-Er, screen 3.

Begin game

70 T=0
  • T is used for time. It starts at zero and increments, so the goal is to get to the top as fast as possible.

Main game loop

Display player and check to see if we made it to the top, or were hit by a chimp.

80 POKEL,M:POKEB,32:POKES1,0
83 IFL=7772ORL=7749THEN400
84 IFL=BTHEN250
  • Line 80 pokes the Man on the screen at its Location. The Barrel is poked to a space, so erased. The S1 sound is stopped. Nothing would be playing the first time this code is ran.
  • If the Location is 7772 or 7749, we go to 400.

Move the chimp

85 B=B+23:IFPEEK(B)=0THENB=B-22:POKEB,16
  • This controls the movement of the enemy (chimp). B is the location. The VIC-20 screen is 22 characters per line, so incrementing B by 23 would move the position down and to the right.
  • The new location of B is checked to see if it is 0 (the brick). If it is, it moves the location back 22 (up one). Thus, the chimp always tries to go down and to the right, and if it can’t it just goes right.
  • The POKE is what puts the chimp character on the screen at that position.
  • From looking at this, it seems the chimp is not displayed if it goes down and to the right successfully. I wonder why? Bug? It would get displayed the next time. Or inteitonal? I’ll look into this.

Handle player falling

87 IFPEEK(L+22)=32THENPOKEL,32:L=L+22:POKEL,M
  • This looks at the block under the player. If it is 32 (empty), it erases the player and moves it down, then displays it at the new location.
  • This code is what makes the player “fall” when it jumps or, on screen 3, when it falls off the edge. Cool.

Make “tick” sound

90 POKES1,240:POKES1,0
  • S1 is the address of one of the sound channels (the VIC-20 has three musical channels, plus noise). This turns one on and off, making the “tick” sound.
  • I did not even consider being able to do background music for a game back then. I bet I could today, memory permitting, even in BASIC.

Collision detection (player and chimp)

95 IFB=LTHEN250
  • This is the collision detection. If the chimps location (B) is the same as the players Location, we go to 250 (death).

Reset chimp back to top

100 IFB=8118THENPOKEB,32:B=7772:POKEB,12
  • This checks to see if the chimp is at the bottom right of the screen.
  • If it is, it gets erased, and the position is reset back to the top left starting position and it is displayed there.

Update and check timer

105 PRINT"{home}{blue}{rvrs on}{right}TIME:";T:T=T+1
110 IFT>200THEN300
  • This homes the cursor, changes the color to blue, turns on reverse video, then displays “TIME:” and the current time value. The reason it goes reverse is because we are using a special character set that replaces the lower alphabet characters. In this mode, there is some memory thing that happens that wraps around the inverse video characters to the standard characters. When using special characters, you have access to the basic letters by using reverse. Apparently.

Keyboard input

115 K=PEEK(197):IFK=64THEN80
  • Memory location 197 is the current key being pressed. If no key is pressed, 64 is returned and the program goes back to the top and continues. (Move the chimp, update the time, etc.)
120 POKEL,32:POKES1,230
  • If there was input, then this line will erase the player, and turn on the sound chip to start making a tone.

Move player or jump

125 IFK=17THENL=L-1:M=14
130 IFK=41THENL=L+1:M=13
135 IFK=39THEN180
140 IFPEEK(L)=0THEN150
145 GOTO80
  • K is the value of the key being pressed.
  • 17 is “A”, so if that is pressed, we move the player’s location to the left and change the player’s character to the “facing left” letter.
  • 41 is “S”, so if that is pressed, we move the player’s location to the right and change the player’s character to the “facing right” letter.
  • 39 is the F1 function key. If that is seen, we go to the jump routine at line 180.
  • If the player’s position (which may or may not have been updated) is 0, it is in a wall, so go to line 150 to fix that location.
  • If still here, we go back to line 80 and continue with the main loop.

Handle running into wall collision

150 IFK=17THENL=L+1
155 IFK=41THENL=L-1
160 M=15:GOTO80
  • This is kind of silly, but if we are here, we hit a wall, so we look at what the last key was pressed and reverse the direction that it did.
  • We set the player’s character to the “facing forward” character.

Jump routine

180 POKES1,235:IFM=14THENL=L-23
183 IFM=15THENL=L-22
185 IFM=13THENL=L-21
190 IFPEEK(L)=0THEN200
195 M=15:GOTO80
  • First we start to make a tone.
  • Then we check to see if the player’s character is 14 (facing left). If it is, we move the player’s position up and to the left (22 characters per row, so -23).
  • If the player’s character is 15 (facing forward), we move the location up,
  • If the player’s character is 13 (facing right), we move the location up and to the right.
  • If the new location is in a wall, we go to 200 to fix that.
  • We set the player’s character to 15 (facing forward) so the jump will land facing that way.
  • We go back to 80 to continue the main game loop.

Handle jumping into wall collision

200 IFM=13THENL=L+21
210 M=15:GOTO80
  • This code takes care of jumping into walls.
  • If the character is facing right, then we move the position down and to the left back where it came from.
  • Else, we know the only other place it can hit a wall is to the right (wow, I was clever here!) so we just make the character face forward and go back to the main loop.

Death screen

250 FORA=1TO11:READN,L:POKES1,N:FORP=1TOL:NEXTP:POKES1,0:NEXTA
255 PRINT"{clear}{black}{rvrs on}{down} GUESS WHAT! YOU HAVE {down}JUST BEEN STRUCK DOWN {down} BY A LUCKY CHIMP!"
260 PRINT"{rvrs on}{down}({blue}THAT MEANS {red}GAME OVER{black})"
265 GOTO450
  • The first line reads musical note and duration values from DATA statements, then makes each note sound for that amount of time.
  • The screen is then cleared, and a game over message is displays.
  • It then goes to 450 to see if the player wants to play again.
270 DATA202,250,202,250,202,150,202,350,210,250,208,150,208,200,202,200,202,250,200,200
275 DATA 202,400
  • Those DATA statements contain the note value and length of the tune that plays when you die (funeral march). I did not know anything about music at the time, so I figured it out by ear. The timing is awful.

Time exceeded

285 PRINT"{down:2}{rvrs on}PRESS ANY KEY TO START"
300 PRINT"{clear}{black}{rvrs on}{down:3}WELL WHAT DO YOU KNOW?"
305 PRINT"{rvrs on}{down:2}WHILE YOU WERE DOWN ONTHE GROUND JUMPING A- ROUND,YOUR TIME CLOCK"
310 PRINT"{rvrs on} JUST RAN OUT!"
315 PRINT"{rvrs on}{down:2} NEXT TIME {red}WATCH{black} THE CLOCK!"
320 GOTO450
  • This message is displayed when time runs out. It then goes to the “play again?” screen.

Screen completed

400 S=S+1:GOTO15
  • This increments the screen, and then goes back to display it.

Play again prompt

450 PRINT"{black}{rvrs on}{down:2}{right}WILL YOU TRY AGAIN?"
455 GETA$:IFA$=""THEN455
460 IFA$="N"THEN550
465 IFA$="Y"THEN480
470 GOTO455
  • This prompts the user to ask if they want to play again. It waits for a key press, then if it is “Y”es, it goes to 480 (start a new game). If it is “N”o, it goes to 550 (end the game).

Press any key to play again prompt

480 PRINT"{clear}{black}{rvrs on}{down:2}AT LAST! SOMEONE BRAVE ENOUGH TO {red}TRY{black} TO STOP  KING KING'S COUSIN!"
490 GETA$:IFA$=""THEN490
495 RUN

If the player chooses “Y”es to play again, this messages is displayed. It waits for any key to be pressed, then re-runs the program.

Game won – Falling ape animation

500 PRINT"{clear}{black}"
505 FORZ=0TO16:PRINT"{home}":FORR=0TOZ:PRINT:NEXTR
510 PRINT" {down}{left:3}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"
515 NEXTZ
  • This cleans the screen, draws the ape, and then makes it “fall” to the bottom of the screen. Remember how Donkey Kong would fall at the end of the rivets level? Kinda like that. Just not as good. I had forgotten about this!
525 POKE36874,128
530 FORX=15TO0STEP-.1:POKE36878,X:NEXTX:POKE36874,0
  • That plays a sound effect when the ape hits the bottom of the screen.

Game won message

535 PRINT"{clear}{black}{rvrs on}{down:3}CONGRATULATIONS!!!!!!!{down} YOU NOW KNOW WHAT IT  FEELS LIKE TO BE ON"
540 PRINT"{rvrs on}TOP!{$a0}YOU PLAYED WELL!"
545 PRINT"{rvrs on}{down:2}{blue}BET YOU DON'T WIN NEXT TIME!"
548 PRINT:GOTO450
  • This displays the “game won” message, then goes to 450 to ask the player if they wish to play again.

Quit game message

550 PRINT"{clear}{black}{rvrs on}I DIDN'T THINK YOU HAD ENOUGH COURAGE TO TRY   TO STOP A MAD APE!"
560 PRINT"{down}{rvrs on}{red}I HOPE YOU ENJOYED NOT SAVING THE BUILDING!"
565 FORG=1TO10000:NEXTG
570 SYS64802
  • This would display a message, wait, and then reboot the VIC-20.

Programmer’s thoughts

I actually expected this code to be far worse than it actually is. If I were writing it today, I see a number of things I could do to make it more efficient. I also have many ideas of ways I could use the VIC-20 features to make the game fancier (animated characters, better music and sounds).

But, overall, I am fairly pleased with how my junior high self programmed this. I was completely self-taught from reading the VIC-20 manual and articles in magazines.

But since I know I could do it better today, I think I might just give that a shot.

Here is the full listing of this version of the program. If you want to run it, I would do two things:

  • Delete line 1 entirely.
  • In line 10, remove the POKE772,200.
  • And I’d get rid of the same POKEs in the INSTRUCTIONS loader.

And if you don’t want to type it in, here is a virtual tape for the VICE Commodore emulator. It has the above changes made, but otherwise is exactly as I last touched it in 1983. Enjoy!

Until next time…

Full SKY-APE-ER listing:

1 POKE 808,100
5 REM  ************          *SKY-APE-ER*        *******BY*******
6 REM*ALLEN  HUFFMAN*      ****************L
10 S=1:POKE36879,26:POKE36878,15:S1=36875:POKE775,200:POKE36869,255
15 PRINT"{clear}":L=8118:B=7772:M=15
20 FORA=38400TO38905:POKEA,0:NEXTA
25 PRINT"{home}{down}{right}{black}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"
30 ONSGOTO35,45,55,500
35 PRINT"{red}@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}";
40 PRINT"@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70
45 PRINT"{blue}@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";
50 PRINT"@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70
55 PRINT"{purple}@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{up:3}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";
60 PRINT"@@@{up:4}{left}@@@{down}{left}@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@{up}{left}@{up}{left}@"
70 T=0
80 POKEL,M:POKEB,32:POKES1,0
83 IFL=7772ORL=7749THEN400
84 IFL=BTHEN250
85 B=B+23:IFPEEK(B)=0THENB=B-22:POKEB,16
87 IFPEEK(L+22)=32THENPOKEL,32:L=L+22:POKEL,M
90 POKES1,240:POKES1,0
95 IFB=LTHEN250
100 IFB=8118THENPOKEB,32:B=7772:POKEB,12
105 PRINT"{home}{blue}{rvrs on}{right}TIME:";T:T=T+1
110 IFT>200THEN300
115 K=PEEK(197):IFK=64THEN80
120 POKEL,32:POKES1,230
125 IFK=17THENL=L-1:M=14
130 IFK=41THENL=L+1:M=13
135 IFK=39THEN180
140 IFPEEK(L)=0THEN150
145 GOTO80
150 IFK=17THENL=L+1
155 IFK=41THENL=L-1
160 M=15:GOTO80
180 POKES1,235:IFM=14THENL=L-23
183 IFM=15THENL=L-22
185 IFM=13THENL=L-21
190 IFPEEK(L)=0THEN200
195 M=15:GOTO80
200 IFM=13THENL=L+21
210 M=15:GOTO80
250 FORA=1TO11:READN,L:POKES1,N:FORP=1TOL:NEXTP:POKES1,0:NEXTA
255 PRINT"{clear}{black}{rvrs on}{down} GUESS WHAT! YOU HAVE {down}JUST BEEN STRUCK DOWN {down}  BY A LUCKY CHIMP!"
260 PRINT"{rvrs on}{down}({blue}THAT MEANS {red}GAME OVER{black})"
265 GOTO450
270 DATA202,250,202,250,202,150,202,350,210,250,208,150,208,200,202,200,202,250,200,200
275 DATA202,400
285 PRINT"{down:2}{rvrs on}PRESS ANY KEY TO START"
300 PRINT"{clear}{black}{rvrs on}{down:3}WELL WHAT DO YOU KNOW?"
305 PRINT"{rvrs on}{down:2}WHILE YOU WERE DOWN ONTHE GROUND JUMPING A- ROUND,YOUR TIME CLOCK"
310 PRINT"{rvrs on}    JUST RAN OUT!"
315 PRINT"{rvrs on}{down:2}  NEXT TIME {red}WATCH{black} THE CLOCK!"
320 GOTO450
400 S=S+1:GOTO15
450 PRINT"{black}{rvrs on}{down:2}{right}WILL YOU TRY AGAIN?"
455 GETA$:IFA$=""THEN455
460 IFA$="N"THEN550
465 IFA$="Y"THEN480
470 GOTO455
480 PRINT"{clear}{black}{rvrs on}{down:2}AT LAST! SOMEONE BRAVE ENOUGH TO {red}TRY{black} TO STOP  KING KING'S COUSIN!"
490 GETA$:IFA$=""THEN490
495 RUN
500 PRINT"{clear}{black}"
505 FORZ=0TO16:PRINT"{home}":FORR=0TOZ:PRINT:NEXTR
510 PRINT"   {down}{left:3}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"
515 NEXTZ
525 POKE36874,128
530 FORX=15TO0STEP-.1:POKE36878,X:NEXTX:POKE36874,0
535 PRINT"{clear}{black}{rvrs on}{down:3}CONGRATULATIONS!!!!!!!{down} YOU NOW KNOW WHAT IT  FEELS LIKE TO BE ON"
540 PRINT"{rvrs on}TOP!{shft space}YOU PLAYED WELL!"
545 PRINT"{rvrs on}{down:2}{blue}BET YOU DON'T WIN NEXT       TIME!"
548 PRINT:GOTO450
550 PRINT"{clear}{black}{rvrs on}I DIDN'T THINK YOU HAD ENOUGH COURAGE TO TRY   TO STOP A MAD APE!"
560 PRINT"{down}{rvrs on}{red}I HOPE YOU ENJOYED NOT SAVING THE BUILDING!"
565 FORG=1TO10000:NEXTG
570 SYS64802

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.