Trick Shot TEN by Jim Happel
About
BASIC 10 Liner entry
Game Name:
Trick Shoot-TEN
Category:
PUR-80
Computer/BASIC:
Commodore PET 2001 BASIC 1 (Original buggy ROMS)
Game Description:
Trick shooting contest! Raise the ball to the right height, drop it on the ramp, and bounce it into the basket. As you make more and more shots, the baskets get smaller appear at more random locations. How many trick shots you can make in a row?
Game Instructions:
Hold the space bar down until the desired ball height is reached – then let go! Watch as the ball drops onto the ramp and bounces toward the basket. After scoring, tap the space bar to start the next round. Your current score is shown at the top center of the screen while the high score is displayed at the top left. To start a new game, press the space bar.
Game Features:
- Displays both the current score and the high score
- Increasing difficulty - the basket gets smaller and the placement becomes more random
- True parabolic calculations
- Beautiful PETSCII graphics
- Unique game sounds for ball movement, scores, and end of game
Video of the game playing on an actual PET 2001 (1977 design):
The code:
No lines are greater than 80 characters when entered using standard commodore screen codes and abbreviated commands.
- In VICE:
PET 2001 program lisiting screen.png
- In ASCII with screen code descriptions
0 POKE59466,15:POKE59467,16:L=(-10+S)*(10-S>0)+3:X=0:Y=12:T=24:IFB<STHENB=S 1 PRINT"{clear}";B;TAB(17);S:C=223:GOSUB8:C=102:O=(9+((RND(1)*S)AND15)):Y=INT(14+(RND(1)*SAND7)) 2 FORJ=1TO2:FORX=OTOL+O:T=24:GOSUB8:NEXTX:Y=Y+1:NEXTJ:X=0:Y=11:T=24:C=81:GOSUB8:WAIT515,8,8 3 Y=ABS(Y-1):GOSUB8:IFPEEK(515)=6THEN3 4 H=(12-Y):K=Y+1:FORI=1TO11-Y:Y=Y+1:GOSUB8:NEXT 5 X=X+1:Y=INT(.1*(X-H)^2+K):ONSGN(22-Y)+2GOTO7:GOSUB8:ONABS(PEEK(P+40)-101)GOTO6:GOTO5 6 PRINT"{home}{down*2} {reverse on}score!{reverse off}":S=S+1:Y=2:FORJ=1TO4:GOSUB9:Y=Y-.5:NEXT:WAIT515,8,8:GOTO0 7 PRINT"{home}{down*2} {reverse on}game over{reverse off}":Y=12:FORJ=1TO12:GOSUB9:Y=Y+.5:NEXT:WAIT515,8,8:S=0:GOTO0 8 P=32768+Y*40+X:POKEP,C:POKE32768+Z+T*40,32:Z=X:T=Y 9 POKE59464,48+Y*5:POKE59464,0:RETURN- In ASCII with abbreviated commands and screen code descriptions
0pO59466,15:pO59467,16:L=(-10+S)*(10-S>0)+3:X=0:Y=12:T=24:IFB<StHB=S 1?"{clear}";B;tA17);S:C=223:goS8:C=102:O=(9+((rN(1)*S)aN15)):Y=INT(14+(rN(1)*SaN7)) 2fOJ=1TO2:fOX=OTOL+O:T=24:goS8:nEX:Y=Y+1:nEJ:X=0:Y=11:T=24:C=81:goS8:wA515,8,8 3Y=aB(Y-1):goS8:IFpE(515)=6tH3 4H=(12-Y):K=Y+1:fOI=1TO11-Y:Y=Y+1:goS8:nE 5X=X+1:Y=INT(.1*(X-H)^2+K):ONsG(22-Y)+2gO7:goS8:ONaB(pE(P+40)-101)gO6:gO5 6?"{home}{down*2} {reverse on}score!{reverse off}":S=S+1:Y=2:fOJ=1TO4:goS9:Y=Y-.5:nE:wA515,8,8:gO0 7?"{home}{down*2} {reverse on}game over{reverse off}":Y=12:fOJ=1TO12:goS9:Y=Y+.5:nE:wA515,8,8:S=0:gO0 8P=32768+Y*40+X:pOP,C:pO32768+Z+T*40,32:Z=X:T=Y 9pO59464,48+Y*5:pO59464,0:reTVariables:
Variable, Name, Description
B, Best, High score
C, Char, Screen code of character to print to screen
H, H, Parabola formula value
I, I temp, Temporary loop variable
J, J temp, Temporary loop variable
K, K, Parabola formula value
L, Length, Length of basket
O, Offset, Offset of the basket from left
P, Position, Current ball position in screen memory
S, Score, Score of current game
T, T Pos, Last Y location drawn
X, X Pos, X location to draw character
Y, Y Pos, Y location to draw character
Z, Z Pos, Last X location drawn
How it works:
The code relies heavily on the subroutine at lines 8 and 9, so I’ll start there (by line #):
8: Draws the specified character (screen code), C, on the screen at the X,Y location. It also blanks (space=32) the last location drawn to (Z,T) so that the ball animation doesn’t leave a trail. A GOSUB to line 8 doesn’t return, but falls through to line 9 before RETURNing.
9: Plays a short tone based on the Y location last drawn to. This uses the CB2 sound modification that was a common user hack to the PET 2001 – commodore adopted this convention in later PETs. A character higher on the screen (lower Y) gets a higher pitch so that the ball arch makes a pleasing rising and falling sound with the ball position. Line 9 is also called directly when wanting to play a sound without drawing to the screen (e.g. the scoring and game over sounds)
0: Sets up the CB2 sound, calculates the length (L) for the next basket (target), sets X,Y to 0,12 and character to 223 (ramp), and checks the if the high score (B) needs to be updated. The length (L) should reduce one every round until 3 and then hold at that. Since commodore BASIC 1 doesn’t support ELSE in IF THEN statements (no L=L-1:IF L<3 THEN L=3 ELSE), innovative means are needed. The equation (10-S>0) is used to stop decrementing at zero. It evaluates as TRUE (-1) or FALSE (0). Therefore, if the score is 9 or less, (10-S>0)=-1; but if the score is 10 or more, (10-S>0)=0. (-10+S) will start at -10 and count down (actually up since it is negative) as the score (S) increases. Examples: If S=0; (-10+S)*(10-S>0)=(-10)*(-1)=10. If S=8; (-10+S)*(10-S>0)=(-2)*(-1)=2. If S=11; (-10+S)*(10-S>0)=(1)*(0)=0. A constant of 3 is added so that the basket is never less than three characters wide. So the width starts at 13 and goes down to 3.
1: Clears the screen and prints the high score (B) and current score (S), sets least Y position (T) to a harmless value for the erasing in line 8, calls routine at 8 to draw ramp character, sets C to 102 (the checkerboard pattern), calculates the offset (O) of the basket (target) from the left edge of the screen, and calculates the Y value of the basket (target). For the offset, RND(0)*S makes a random value up to the current value of S and therefore the random placement grows as your score grows. ANDing with 15 caps the value at 15. A constant 9 is added so that offsets can vary from 9 to 24. For the Y value, RND(0)*S makes a random value up to the current value of S and therefore the random placement grows as your score grows. ANDing with 7 caps the value at 7. A constant 14 is added so that the Y value of the basket can vary from 14 to 21.
2: FOR J loops through drawing the two lines of the basket (target), FOR X draws from the offset (O) to the offset plus the length (O+L), last Y is set to harmless location (T=24), draw routine and loop increasing the Y (next line) between the two J loops. Sets X,Y = 0,12, T=24 (harmless last Y) and C=81 and calls the draw routine to draw the ball on the ramp. Waits for the spacebar.
3: Moves the ball up (Y-1) as long as the space bar is held down (PEEK(515)=6). The ABS stops the ball Y value from becoming a negative number and creates a fun bouncing at the top of the screen. Line three is short but loops back onto itself. Once the space bar is released, the code falls to line 4.
4: The constants for the parabola equation (H.K) are calculated based on the Y value when the space bar was released. The FOR NEXT loop moves the ball back down to the ramp. The parabola equation was derived from: https://www.radfordmathematics.com/functions/quadratic-functions-parabola/vertex...
5: Now the ball moves through its parabolic arc. X is incremented by one and the Y value is calculated by the equation. ONSGN(22-Y)+2GOTO7 branches to line 7 (game over) if the ball’s Y value is greater than 22. Since commodore BASIC 1 doesn’t support ELSE in IF THEN statements (no IF Y>22 THEN 7 ELSE), innovative means are needed. SGN(22-Y) checks the sign of 22-Y. When it’s negative (22>Y), then it produces a value of -1. ON branches with a value of 1. So SGN(22>Y)+2 = -1+2 = 1 when Y>22. ONABS(PEEK(P+40)-101)GOTO6 branches to line 6 when the character under the ball is the checkerboard pattern. PEEK(P+40) gets the screen code of the character below the ball. We are looking for 102, the checkerboard character. ON branches with a value of 1. So PEEK(P+40)-101=102-101=1 if the character below the ball is the checkerboard pattern. The ON command errors on negative values so the ABS is used to protect against that (e.g. space=32, so PEEK(P+40)-101=32-101=-69 without the ABS).
6. This is the score routine. This line prints a nice message, adds one to the score, sets the Y value to something low (2), executes a FOR J loop that calls the sound routine 4 times reducing Y between loops making a nice chirping sound signaling the score, waits for the space bar to be pushed, and then GOTOs 0.
7. This is the game over routine. This line prints the game over message, sets the Y value to something high (14), executes a FOR J loop that calls the sound routine 12 times increasing Y between loops making a decreasing low sound signaling the end of the game, waits for the space bar to be pushed, set the score to 0, and then GOTOs 0.