' ------------------------------------------------
' ATARI XE/XL TETRIS - OPTIMIZED EDITION
' ------------------------------------------------
DIM BOARD(264) BYTE, PIECE_X(4) BYTE, PIECE_Y(4) BYTE

' --- OPTIMIZED SHAPE DATA (using DATA statement) ---
DATA SH() BYTE = 1,0,1,1,1,2,1,3, 0,1,1,1,2,1,3,1,
DATA BYTE = 1,0,1,1,1,2,1,3, 0,1,1,1,2,1,3,1,
DATA BYTE = 1,1,2,1,1,2,2,2, 1,1,2,1,1,2,2,2,
DATA BYTE = 1,1,2,1,1,2,2,2, 1,1,2,1,1,2,2,2,
DATA BYTE = 1,1,0,1,2,1,1,0, 1,1,1,0,1,2,2,1,
DATA BYTE = 1,1,0,1,2,1,1,2, 1,1,1,0,1,2,0,1,
DATA BYTE = 1,1,1,0,1,2,2,2, 1,1,0,1,2,1,2,2,
DATA BYTE = 1,1,1,0,1,2,0,0, 1,1,0,1,2,1,0,0,
DATA BYTE = 1,1,0,1,2,1,0,0, 1,1,1,0,1,2,0,2,
DATA BYTE = 1,1,0,1,2,1,2,2, 1,1,1,0,1,2,2,0,
DATA BYTE = 1,1,2,1,1,2,0,2, 1,1,1,0,2,1,2,2,
DATA BYTE = 1,1,2,1,1,2,0,2, 1,1,1,0,2,1,2,2,
DATA BYTE = 1,1,0,1,1,2,2,2, 1,1,1,0,0,1,0,2,
DATA BYTE = 1,1,0,1,1,2,2,2, 1,1,1,0,0,1,0,2

' --- MAIN LOOP ---
WHILE 1
  HIT=0:GAMEOVER=0:SCORE=0:DELAY=10
  GRAPHICS 0:POKE 752,1:POKE 710,0:POKE 712,0:POKE 709,15
  
  POSITION 15,7:?"GEMINI-3 TETRIS"
  POSITION 9,18:?"PRESS FIRE TO START"
  WHILE STRIG(0):WEND
  
  CLS:@INIT_BOARD:@DRAW_ARENA
  CURP=PEEK(53770) M. 7:NEXTP=PEEK(53770) M. 7
  POSITION 25,2:?"SCORE:":POSITION 25,3:?SCORE;
  
  WHILE GAMEOVER=0
    PX=4:PY=0:ROT=0
    @DRAW_NEXT:@CHECK_COLLISION
    IF HIT:GAMEOVER=1:ENDIF
    
    LOCKED=0
    WHILE LOCKED=0 A. GAMEOVER=0
      @DRAW_PIECE
      FOR W=1 TO DELAY
        S=STICK(0):B=STRIG(0)
        IF S=11:DX=-1:@TRY_MOVE:WHILE STICK(0)=11:PAUSE 1:WEND:ENDIF
        IF S=7:DX=1:@TRY_MOVE:WHILE STICK(0)=7:PAUSE 1:WEND:ENDIF
        IF S=14:@HARD_DROP:LOCKED=1:W=DELAY:ENDIF
        IF B=0:@TRY_ROTATE:WHILE STRIG(0)=0:PAUSE 1:WEND:ENDIF
        IF S=13:W=DELAY:ENDIF
        PAUSE 1
      NEXT W
      
      IF LOCKED=0
        @ERASE_PIECE:PY=PY+1:@CHECK_COLLISION
        IF HIT:PY=PY-1:@DRAW_PIECE:@LOCK_PIECE:LOCKED=1:ENDIF
      ENDIF
    WEND
    
    @CHECK_LINES
    CURP=NEXTP:NEXTP=PEEK(53770) M. 7:@DRAW_NEXT
  WEND
  
  PAUSE 40:POKE 710,34:POKE 712,34:CLS
  POSITION 14,8:?"GAME OVER"
  POSITION 12,10:?"TOTAL SCORE:";SCORE
  POSITION 10,14:?"PLAY AGAIN? (Y/N)"
  L_IN=1
  WHILE L_IN
    K=PEEK(764)
    IF K=43:L_IN=0:ENDIF
    IF K=35:GRAPHICS 0:END:ENDIF
  WEND
  POKE 764,255
WEND

' --- PROCEDURES ---
PROC DRAW_NEXT
  FOR I=5 TO 10:POSITION 24,I:?"      ":NEXT I
  POSITION 25,5:?"NEXT:"
  A=NEXTP*32
  FOR I=0 TO 3
    NX=26+SH(A+I*2):NY=7+SH(A+I*2+1)
    POSITION NX,NY:?CHR$(160);
  NEXT I
ENDPROC

PROC HARD_DROP
  @ERASE_PIECE:STILL_FALL=1
  WHILE STILL_FALL
    PY=PY+1:@CHECK_COLLISION
    IF HIT:PY=PY-1:STILL_FALL=0:ENDIF
  WEND
  @DRAW_PIECE:@LOCK_PIECE
  SOUND 0,50,8,10:PAUSE 2:SOUND 0
ENDPROC

PROC CHECK_LINES
  FOR Y=19 TO 0 STEP -1
    L_C=0:FOR X=1 TO 10:IF BOARD(Y*12+X):INC L_C:ENDIF:NEXT X
    IF L_C=10
      SETCOLOR 2,0,14:PAUSE 2:SETCOLOR 2,0,0
      POSITION 11,Y:?"          "
      FOR F=50 TO 30 STEP -10:SOUND 0,F,10,14:PAUSE 2:NEXT F:SOUND 0
      FOR YY=Y TO 1 STEP -1:MSET ADR(BOARD)+YY*12+1,10,0:MOVE ADR(BOARD)+(YY-1)*12+1,ADR(BOARD)+YY*12+1,10:NEXT YY
      MSET ADR(BOARD)+1,10,0
      FOR RY=0 TO 19:POSITION 11,RY:FOR RX=1 TO 10
        IF BOARD(RY*12+RX):?CHR$(160);:ELSE:?" ";:ENDIF
      NEXT RX:NEXT RY
      SCORE=SCORE+100:POSITION 25,3:?SCORE;"   ":Y=Y+1
      IF DELAY>2:DEC DELAY:ENDIF
    ENDIF
  NEXT Y
ENDPROC

PROC TRY_ROTATE
  @ERASE_PIECE:OR=ROT:ROT=(ROT+1) M. 4:@CHECK_COLLISION
  IF HIT:ROT=OR:ELSE:SOUND 1,150,12,6:PAUSE 1:SOUND 1,120,12,6:PAUSE 1:SOUND 1:ENDIF
  @DRAW_PIECE
ENDPROC

PROC TRY_MOVE
  @ERASE_PIECE:OX=PX:PX=PX+DX:@CHECK_COLLISION
  IF HIT:PX=OX:ELSE:SOUND 0,100,10,2:PAUSE 1:SOUND 0:ENDIF
  @DRAW_PIECE
ENDPROC

PROC DRAW_ARENA
  FOR Y=0 TO 20:POSITION 10,Y:?"|";:POSITION 21,Y:?"|";:NEXT Y
  POSITION 11,20:?"----------";
ENDPROC

PROC DRAW_PIECE
  @GET_COORDS
  FOR I=0 TO 3:IF PIECE_Y(I)>=0:POSITION PIECE_X(I)+10,PIECE_Y(I):?CHR$(160);:ENDIF:NEXT I
ENDPROC

PROC ERASE_PIECE
  @GET_COORDS
  FOR I=0 TO 3:IF PIECE_Y(I)>=0:POSITION PIECE_X(I)+10,PIECE_Y(I):?" ";:ENDIF:NEXT I
ENDPROC

PROC INIT_BOARD
  MSET ADR(BOARD),264,0
  FOR Y=0 TO 21:BOARD(Y*12)=1:BOARD(Y*12+11)=1:NEXT Y
  FOR X=0 TO 11:BOARD(20*12+X)=1:NEXT X
ENDPROC

PROC GET_COORDS
  A=(CURP*32)+(ROT*8)
  FOR I=0 TO 3:PIECE_X(I)=PX+SH(A+I*2):PIECE_Y(I)=PY+SH(A+I*2+1):NEXT I
ENDPROC

PROC CHECK_COLLISION
  @GET_COORDS:HIT=0
  FOR I=0 TO 3
    CX=PIECE_X(I):CY=PIECE_Y(I)
    IF CX<1 O. CX>10 O. CY>19
      HIT=1
    ELSE
      IF CY>=0:IF BOARD(CY*12+CX):HIT=1:ENDIF:ENDIF
    ENDIF
  NEXT I
ENDPROC

PROC LOCK_PIECE
  @GET_COORDS
  FOR I=0 TO 3
    LY=PIECE_Y(I):LX=PIECE_X(I)
    IF LY>=0 A. LY<=19:BOARD(LY*12+LX)=1:ENDIF
  NEXT I
  SOUND 0,240,10,10:PAUSE 3:SOUND 0
ENDPROC