REM KEYS


REM J/K/L: left/down/right
REM F/G or U/O: rotate left/right
REM I: quick drop
REM P: PAUSE
REM Q: quit 

REM GAME LOOP FROM 1 TO 740

0 GOTO 1000
1 IF W>LV THEN W=Z: GOTO 4
2 W=W+U: ON PEEK(L)-V GOTO 11,9,1,380,7,3,8,1,1,9,740,720,1,1,1,11: GOTO 1
3 POKE KC,Z

REM DOWN
4 Y=Y+U: J=J+O: R=U

REM erase_check_n_restore
5 INVERSE: HTAB M:VTAB N:PRINT Z$;: POKE FA,FI: IF SCRN(I+A,J+B)+ SCRN(I+C,J+D)+SCRN(I+E,J+F)+ SCRN(I+G,J+H) THEN Y=N: X=M: HTAB X: VTAB Y: PRINT A$; : ON R GOTO 400: I=X-U: GOTO 1

REM draw new position
6 M=X:N=Y: R=Z: HTAB X: VTAB Y: PRINT A$;: GOTO 1
 
REM LEFT
7 POKE KC,Z: X=I: I=X-U:GOTO 5

REM RIGHT
8 POKE KC,Z: I=X: X=X+U: GOTO 5


REM ROT_RIGHT
9 POKE KC,Z: SS=S: S=S-Q: TT=T: T=T-U: IF T<Z THEN T=P:S=S+S6: GOTO 260
10 GOTO 260

REM ROT LEFT
11 POKE KC,Z: SS=S: S=S+Q: TT=T: T=T+U: IF T=Q THEN T=Z:S=S-S6


REM CHECK IF ROT POSSIBLE, IF NOT RESTORE AND REDRAW
260 AA=A: BB=B:CC=C:DD=D:EE=E:FF=F:GG=G:HH=H: A= X(S+Z): B=Y(S+Z): C=X(S+U): D=Y(S+U): E=X(S+O): F=Y(S+O): G=X(S+P): H=Y(S+P)
270 INVERSE: HTAB X:VTAB Y:PRINT Z$;: POKE FA,FI: IF SCRN(I+A,J+B)+SCRN(I+C,J+D)+SCRN(I+E,J+F)+SCRN(I+G,J+H) THEN A=AA:B=BB:C=CC:D=DD:E=EE:F=FF:G=GG:H=HH: S=SS: T=TT: HTAB X: VTAB Y: PRINT A$; : GOTO 1

REM ROTATION IS POSSIBLE, SET NEW VALUES
280 SS=S: QS=NS*Q+T: A$=A$(QS): Z$=Z$(QS): HTAB X: VTAB Y: PRINT A$;: GOTO 1


REM QUICK DROP
380 POKE KC,Z: Y=Y+U: J=J+O: INVERSE: HTAB M:VTAB N:PRINT Z$;: POKE FA,FI: IF NOT SCRN(I+A,J+B) THEN IF NOT SCRN(I+C,J+D) THEN IF NOT SCRN(I+E,J+F) THEN IF NOT SCRN(I+G,J+H) THEN M=X:N=Y: R=R+U: HTAB X: VTAB Y: PRINT A$;: GOTO 380
390 SC=SC+N0*INT(R/N5): Y=N: X=M: HTAB X: VTAB Y: PRINT A$; : NORMAL: HTAB 1: VTAB T1: PRINT "SCORE: "SC;



REM check_lines
400 A=PEEK(SP): A=PEEK(SP): IF Y=1 THEN GOTO 700
410 J=J-O: IF LJ>J THEN LJ=J
420 R=Z: RN=-U: K= J+Q+Q: IF K>NY THEN K=NY
430 FOR JJ = J TO K STEP O: G=U: FOR I = MX TO NX: IF NOT SCRN(I,JJ) THEN I=NX+U: G=Z
440 NEXT
450 IF G THEN RN=RN+U: R(RN) = JJ
460 NEXT
470 IF RN<Z THEN 610
480 FOR C = Z TO 32: A=PEEK(SP): COLOR=C: FOR I=Z TO RN: HLIN MX,NX AT R(I): HLIN MX,NX AT R(I)+U: NEXT: NEXT
490 FOR K = Z TO RN: Y=R(K): FOR J = Y-U TO LJ-U STEP -O: FOR I=MX TO NX: COLOR=SCRN(I,J): PLOT I,J+O: COLOR=SCRN(I,J-U): PLOT I,J+U: NEXT: NEXT: LJ=LJ+O: NEXT

560 SC=SC+P(RN): LI=LI+RN+U: IF LI>=NL THEN  NL=NL+TL: LV=LV-U: IF LV<U THEN LV=U

600 NORMAL: HTAB U: VTAB T1: PRINT "SCORE: "SC: PRINT "LINES: "LI: PRINT "LEVEL: "ML-LV
610 INVERSE: HTAB E8: VTAB N0: PRINT Z$(PS*Q); : NS=PS: PS=INT(RND(U)*7): POKE FA, C(PS): HTAB E8: VTAB N0: PRINT A$(PS*Q);

620 S=NS*S6: QS=NS*Q: A$=A$(QS): Z$=Z$(QS): FI=C(NS): T=Z: X=T1: Y=U: N=Y: M=X: SS=S: A= X(S+Z): B=Y(S+Z): C=X(S+U): D=Y(S+U): E=X(S+O): F=Y(S+O): G=X(S+P): H=Y(S+P): POKE FA,FI: HTAB X: VTAB Y: ? A$; : I=X-U: J=Y-U: W=Z: GOTO 1



REM GAME OVER
700 POKE KC,Z:A=-868:G$=CHR$(7):PRINT G$G$G$:VTAB T1:HTAB 15:CALL A:VTAB T2:HTAB N0:CALL A:HTAB T0:INVERSE:PRINT ">>> GAME OVER <<<";:VTAB 23:HTAB N0:CALL A
705 VTAB T4:HTAB U:NORMAL:PRINT "PLAY AGAIN (Y/N) ? ";:CALL A:GET K$:IF K$<>"N" THEN 2020
710 TEXT: HOME: NORMAL: PRINT "THANKS FOR PLAYING ! ": IF DS THEN CALL 43089: REM RECONNECT DOS
715 END
720 POKE KC,Z: VTAB T4: HTAB U: INVERSE: ? "ARE YOU SURE (Y/N)?"; : GET K$ : IF K$ = "Y" THEN 710
730 HTAB U:  CALL - 868: GOSUB 2600: POKE FA,FI: GOTO 1

REM PAUSE
740 POKE KC,Z: VTAB T4: HTAB O: FLASH: PRINT ">>> PAUSED <<<";: GET K$: POKE KC,Z: VTAB T4: HTAB 1: CALL - 868: GOSUB 2600: POKE FA,FI: GOTO 1


REM VARIABLES
REM A$: STRING REPRESENTING THE SHAPE TO PRINT
REM A/B/C/D/E/F/G/H: X/Y OFFSETS TO CHECK
REM AA/BB/CC/DD/EE/FF/GG/HH PREVIOUS VALUES OF A/B/C/D/E/F/G/H
REM AA$: PREVIOUS VALUE OF A$
REM E8: CONSTANT 8
REM FA: CONSTANT 50
REM FI: INVERSE FLAG TO POKE
REM I/J: PIECE POSITION ON LORES SCREEN
REM K: MISC. COUNTER
REM KC: CLEAR KBD STROBE CONSTANT (49168)
REM L: CONSTANT 49152 (LAST KEY HIT ADDR.)
REM LV: LEVEL
REM M/N: PREVIOUS X/Y POSITION
REM MX/NX: PIT LEFT AND PIT RIGHT POSITIONS (15/24)
REM MY/NY: PIT TOP/BOTTOM POS
REM ML: MAX LEVEL
REM NS: SHAPE #
REM N0: CONSTANT 10
REM O: CONSTANT 2
REM P: CONSTANT 3
REM Q: CONSTANT 4
REM R: PIECE GOING DOWN FLAG (0/1)
REM S: SHAPE OFFSET NUMBER 0..27
REM SS: PREVIOUS SHAPE OFFSET 0..27
REM SP: CONSTANT 49200 (SPEAKER)
REM T: 0-3 COUNTER
REM TT: PREVIOUS VALUE OF T
REM T0, T1, T2, T4: CONSTANTS 20, 21, 22, 24
REM U: CONSTANT 1
REM V: CONSTANT 197 = MIN. KEY #
REM X/Y: PIECE POSITION ON TEXT SCREEN
REM Z: CONSTANT 0
REM Z$: STRING TO ERASE SHAPE
REM ZZ$: PREVIOUS VALUE OF Z$


REM DECLARE MOST USED VARIABLES FIRST !

1000 U=1:X=0:Y=0:Z=0:S=0:O=2:M=0:N=0:K=0:R=0:SS=0:A$="":Z$="":A=0:B=0:C=0:D=0:E=0:F=0:G=0:H=0:T=0:TT=0:P=3:Q=4:L=49152:V=197:CE=62248:FA=50:FI=0:KC=49168:S6=16:MX=15:NX=24:MY=4:NY=36:SP=49200:N5=5:N0=10:T1=21:T2=22:T4=24:T0=20:E8=8

1010 GOSUB 3000: TEXT: HOME: NORMAL: HTAB 5: PRINT "A TETRIS CLONE IN PURE APPLESOFT": HTAB 13: PRINT "BY FVL (C) 2022"
1020 VTAB 4: HTAB 17: PRINT "KEYS:"
1030 VTAB 6: PRINT " J/K/L      : MOVE LEFT/DOWN/RIGHT"
1040 PRINT " F/G OR U/O : ROTATE LEFT/RIGHT"
1050 PRINT " I          : QUICK DROP"
1060 PRINT " P          : PAUSE"
1070 PRINT " Q          : QUIT"
1080 VTAB 12: HTAB 15: PRINT "POINTS:"
1090 VTAB 14: PRINT " 1 LINE     :   40 POINTS" 
1100 PRINT " 2 LINES    :  100 POINTS" 
1110 PRINT " 3 LINES    :  300 POINTS" 
1120 PRINT " 4 LINES    : 1200 POINTS"
1130 PRINT " QUICK DROP : 0-30 POINTS": HTAB 15: PRINT "(HEIGHT DEPENDENT)"
1140 VTAB 21: HTAB 9: PRINT "NEW LEVEL EVERY 5 LINES": VTAB 22: HTAB 5: PRINT "SPEED INCREASES WITH EACH LEVEL"


1380 VTAB T4: HTAB 8: PRINT "PLEASE WAIT >>> .......";: TH= PEEK(36): TA = PEEK(40)+PEEK(41)*256+TH-7



1390 DIM X(111), Y(111), A$(27), Z$(27), C(6): FOR S=0 TO 6: POKE TA+S, PEEK(TA+S)-128 : FOR J=0 TO 3: FOR I=0 TO 3: READ X(S*S6 + J*Q + I), Y(S*S6 + J*Q + I): NEXT: NEXT: READ C(S): NEXT
1400 D$ = CHR$(10): L$=CHR$(8): Q$=CHR$(34): F$=CHR$(102)


REM SQUARE SHAPE
REM .xX.
REM .xx.

1410 A$(0) = L$+"QQ"+D$+L$+L$+"QQ": A$(1)=A$(0): A$(2)=A$(0): A$(3)=A$(0)
1420 Z$(0) = L$+"@@"+D$+L$+L$+"@@": Z$(1)=Z$(0): Z$(2)=Z$(0): Z$(3)=Z$(0): POKE TA, 160

REM BAR
REM ..O.
REM xxxx

1430 A$(4) = D$ + L$ + L$ + Q$+ Q$+ Q$+ Q$: Z$(4) = + L$ + L$ + D$ + "@@@@"

REM .xO.
REM .x..
REM .x..
REM .x..

1440 A$(5) = L$ + Q$  + D$+L$+Q$+ D$+L$+Q$+ D$+L$+Q$
1450 Z$(5) = L$ + "@" + D$+L$+"@"+ D$+L$+"@"+ D$+L$+"@"
1460 A$(6) = A$(4): A$(7)=A$(5): Z$(6) = Z$(4): Z$(7)=Z$(5): POKE TA+1, 160

REM T-SHAPE
REM .xO.
REM xxx.

1470 A$(8) = L$ + "L" + D$ + L$ + L$ + "LLL": Z$(8) = L$ + "@" + D$+L$ + L$ +"@@@"

REM .xO.
REM xx..
REM .x..

1480 A$(9) = L$ + "L" + D$+L$+L$+ "LL" + D$+L$+"L": Z$(9) = L$ + "@" + D$+L$+L$+ "@@" + D$+L$+"@"

REM ..O.
REM xxx.
REM .x..

1490 A$(10) = D$ + L$ + L$ + "LLL" + D$+L$+L$+"L": Z$(10) = D$ + L$ + L$ + "@@@" + D$+L$+L$+"@"

REM .xO.
REM .xx.
REM .x..

1500 A$(11) = L$ + "L" + D$ + L$+"LL" + D$+L$+L$+ "L": Z$(11) = L$ + "@" + D$ + L$+"@@" + D$+L$+L$+ "@": POKE TA+2, 160

REM L-SHAPE
REM ..O.
REM xxx.
REM x...

1510 A$(12) = D$ + L$ + L$ + "]]]" + D$ + L$+ L$+ L$+"]": Z$(12) = D$ + L$ + L$ + "@@@" + D$ + L$+ L$+ L$+"@"

REM .xO.
REM .x..
REM .xx.

1520 A$(13) = L$ + "]"+ D$ + L$ + "]"+ D$ + L$ + "]]": Z$(13) = L$ + "@"+ D$ + L$ + "@"+ D$ + L$ + "@@"

REM ..X.
REM xxx.

1530 A$(14) = "]" + D$ + L$+ L$+ L$+"]]]": Z$(14) = "@" + D$ + L$+ L$+ L$+"@@@"

REM xxO.
REM .x..
REM .x..

1540 A$(15) = L$+L$+"]]" + D$ + L$ + "]" + D$ + L$ + "]": Z$(15) = L$+L$+"@@" + D$ + L$ + "@" + D$ + L$ + "@": POKE TA+3, 160

REM L-SHAPE INVERTED
REM ..O.
REM xxx.
REM ..x.

1550 A$(16) = D$ + L$ + L$ + F$ + F$ + F$ + D$ + L$+ F$: Z$(16) = D$ + L$ + L$ + "@@@" + D$ + L$+ "@"

REM .xX.
REM .x..
REM .x..

1560 A$(17) = L$ + F$ + F$ + D$ + L$+L$ + F$+ D$ + L$ + F$: Z$(17) = L$ + "@@" + D$ + L$+L$ + "@"+ D$ + L$ + "@"

REM x.O.
REM xxx.

1570 A$(18) = L$ + L$ + F$ + D$ + L$ + F$ + F$ + F$: Z$(18) = L$ + L$ + "@" + D$ + L$ + "@@@"

REM .xO.
REM .x..
REM xx..

1580 A$(19) = L$ + F$ + D$+L$ + F$ + D$+L$ + L$ + F$ + F$: Z$(19) = L$ + "@" + D$+L$ + "@" + D$+L$+L$ + "@@": POKE TA+4, 160

REM Z-SHAPE

REM xxO.
REM .xx.

1590 A$(20) = L$ + L$ + "33" + D$ + L$ + "33":  Z$(20) = L$ + L$ + "@@" + D$ + L$ + "@@"

REM .xO.
REM xx..
REM x...

1600 A$(21) = L$ + "3" + D$ + L$ + L$ + "33" + D$ + L$ + L$ + "3": Z$(21) = L$ + "@" + D$ + L$ + L$ + "@@" + D$ + L$ + L$ + "@"
1610 A$(22) = A$(20): A$(23) = A$(21): Z$(22) = Z$(20): Z$(23) = Z$(21): POKE TA+5, 160

REM S-SHAPE
REM .xX.
REM xx..

1620 A$(24) = L$ + ";;" + D$ + L$ + L$ + L$ + ";;": Z$(24) = L$ + "@@" + D$ + L$ + L$ + L$ + "@@"

REM x.O.
REM xx..
REM .x..

1630 A$(25) = L$ + L$ + ";" + D$ + L$ + ";;" + D$ + L$ + ";": Z$(25) = L$ + L$ + "@" + D$ + L$ + "@@" + D$ + L$ + "@"
1640 A$(26) = A$(24): A$(27) = A$(25): Z$(26) = Z$(24): Z$(27) = Z$(25): POKE TA+6, 160

1700 VTAB 24: CALL - 868: HTAB 1: INVERSE: PRINT "       <<< ANY KEY TO CONTINUE >>>     "; : POKE TA-TH+39+7,32: WAIT 49152, 128


2000 P(0)=40: P(1)=100: P(2)=300:P(3)=1200: DS= PEEK(40672) = 162: IF DS THEN CALL 40672: REM DISCONNECT DOS FOR FASTER PRINT

2010 Q$ = CHR$(119) + CHR$(119) + CHR$(119) + CHR$(119) + CHR$(119): Q$=Q$+Q$+Q$+Q$+Q$+Q$+Q$+Q$: SL=1: OD=0: OL=5
2020 HOME: GR: FLASH: FOR I=1 TO 20: VTAB I: ? Q$;: NEXT: INVERSE: FOR I = 1 TO 19: HTAB 16: VTAB I: ? "@@@@@@@@@@";: NEXT: FOR I= 9 TO 13: VTAB I: HTAB 5: PRINT "@@@@@@";: NEXT

2080 NORMAL
2090 POKE KC, Z: VTAB 21: HTAB 7: PRINT "STARTING LEVEL: ";: INVERSE: PRINT SL;: NORMAL : PRINT SPC(SL<10)" (+/-) TO CHANGE";
2100 VTAB 22: HTAB 4: PRINT "OBSTACLES DENSITY: ";: INVERSE: PRINT OD;: NORMAL: PRINT "  (O/P) TO CHANGE";
2110 VTAB 23: HTAB 1: PRINT "OBSTACLES UP TO LINE: ";: INVERSE: PRINT OL;: NORMAL: PRINT SPC(OL<10)" (L/M) TO CHANGE";

2120 INVERSE: VTAB 24: HTAB 3: PRINT "<<< PRESS ANY OTHER KEY TO START >>>"; : GET K$: NORMAL
2130 IF K$<>"+" AND K$<>"-" THEN 2170
REM CHANGE LEVEL
2140 SL=SL+44-ASC(K$): IF SL<1 THEN SL=40: GOTO 2090
2150 IF SL>40 THEN SL=1
2160 GOTO 2090
2170 IF K$="L" OR K$="M" THEN 2250: REM CHANGE OBSTACLES LINE
2180 IF K$<>"O" AND K$<>"P" THEN 2300: REM START GAME
REM CHANGE OBSTACLES DENSITY
2190 OD=OD-2*ASC(K$)+159: IF OD>7 THEN OD=0
2200 IF OD<0 THEN OD=7
2210 GOTO 2090
REM CHANGE OBSTACLES FINAL LINE
2250 OL=OL-2*ASC(K$)+153: IF OL>15 THEN OL=5
2260 IF OL<5 THEN OL=15
2270 GOTO 2090

2300 HOME: SC=0: LJ=40: ML=41: LV=ML-SL: PS=INT(RND(U)*7): LI=0: TL=5: NL=TL: GOSUB 2600
2310 IF NOT OD THEN 2400
2320 FOR J=NY TO NY+2-OL*2 STEP -2: K=0: FOR I=0 TO 9
2330 IF K<9 AND RND(1)*10<=OD THEN CC=INT(RND(1)*16): CC=CC*(CC<>7): COLOR=CC: PLOT I+MX,J: PLOT I+MX,J+1: K=K+(CC>0)
2340 NEXT: NEXT

2400 GOTO 600

2600 NORMAL: VTAB 21: HTAB 19: PRINT "J/K/L: LEFT/DOWN/RIGHT";: HTAB 15: PRINT "F/G - U/O: ROTATE L/R": HTAB 23: PRINT "I: QUICK DROP": HTAB 21: PRINT "P/Q: PAUSE/QUIT";: HTAB 2: INVERSE: PRINT "=== TETRIS ===";: RETURN

REM =========== ONERR GOTO 
REM ALSO PREPARE AMPERSAND VECTOR TO JMP TO $F328 (RESET STACK POSITION WITHOUT RESUME)
REM ANYTHING AFTER ON ERR ON THE SAME LINE IS IGNORED BY APPLESOFT

3000 ON ERR GOTO 3100
3010 POKE 1013, 76: POKE 1014,40: POKE 1015,243: RETURN

REM === 3072 is next multiple of 256, so going to line 3100 in case of error will only skip line 3010 !
REM USE AMPERSAND TO DO A CALL 62248 (-3288) TO SPARE A FEW CYCLES.
3100 &: GOTO 1




REM ======================================= CHECKING POINTS

REM BECAUSE PRINT CAN ONLY MOVE THE CURSOR LEFT AND DOWN, WE HAVE TO ASSUME WE START IN POS (3,0)
REM X MARKS A PLOTTED STARTING POINT, O MARKS AN UNPLOTTED STARTING POINT

REM  0123 
REM 0..X.
REM 1....
REM 2....
REM 3....


REM SQUARE SHAPE
REM .xX.
REM .xx.

10010 DATA  0, 0,-1, 0, 0, 2,-1, 2
10020 DATA  0, 0,-1, 0, 0, 2,-1, 2
10030 DATA  0, 0,-1, 0, 0, 2,-1, 2
10040 DATA  0, 0,-1, 0, 0, 2,-1, 2,63 : REM []  COLOR=MAGENTA (Q INVERSED)

REM BAR
REM ..O.
REM xxxx

10050 DATA  0, 2,-1, 2,-2, 2, 1, 2

REM .xO.
REM .x..
REM .x..
REM .x..

10060 DATA -1, 0,-1, 2,-1, 4,-1, 6
10070 DATA  0, 2,-1, 2,-2, 2, 1, 2
10080 DATA -1, 0,-1, 2,-1, 4,-1, 6
10090 DATA 63: REM COLOR=DARK BLUE (" INVERSED)

REM T-SHAPE
REM .xO.
REM xxx.

10100 DATA -1, 0,-2, 2,-1, 2, 0, 2

REM .xO.
REM xx..
REM .x..

10110 DATA -1, 0,-2, 2,-1, 2, -1, 4

REM ..O.
REM xxx.
REM .x..

10120 DATA -2, 2,-1, 2, 0, 2, -1, 4

REM .xO.
REM .xx.
REM .x..

10130 DATA -1, 0,-1, 2, 0, 2,-1, 4

10140 DATA 255: REM COLOR=GREEN (L NORMAL)

REM L-SHAPE
REM ..O.
REM xxx.
REM x...

10150 DATA -2,2,-1,2,0,2,-2,4

REM .xO.
REM .x..
REM .xx.

10160 DATA -1,0,-1,2,-1,4,0,4

REM ..X.
REM xxx.

10170 DATA 0,0,-2,2,-1,2,0,2

REM xxO.
REM .x..
REM .x..

10180 DATA -2,0,-1,0,-1,2,-1,4

10190 DATA 255: REM COLOR=YELLOW (] NORMAL)

REM L-SHAPE INVERTED
REM ..O.
REM xxx.
REM ..x.

10200 DATA -2,2,-1,2,0,2,0,4

REM .xX.
REM .x..
REM .x..

10210 DATA 0,0,-1,0,-1,2,-1,4

REM x.O.
REM xxx.

10220 DATA -2,0,-2,2,-1,2,0,2

REM .xO.
REM .x..
REM xx..

10230 DATA -1,0,-1,2,-1,4,-2,4

10240 DATA 127: REM COLOR=MEDIUM BLUE (CHAR 102 AND FLAG 127)

REM Z-SHAPE

REM xxO.
REM .xx.

10250 DATA -2,0,-1,0,-1,2,0,2

REM .xO.
REM xx..
REM x...

10260 DATA -1,0,-1,2,-2,2,-2,4
10270 DATA -2,0,-1,0,-1,2,0,2
10280 DATA -1,0,-1,2,-2,2,-2,4

10290 DATA 63: REM COLOR=PURPLE (3 INVERSE)

REM S-SHAPE
REM .xX.
REM xx..

10300 DATA 0,0,-1,0,-1,2,-2,2

REM x.O.
REM xx..
REM .x..

10310 DATA -2,0,-2,2,-1,2,-1,4
10320 DATA 0,0,-1,0,-1,2,-2,2
10330 DATA -2,0,-2,2,-1,2,-1,4

10340 DATA 255: REM COLOR=PINK (; NORMAL)
