PROCEDUREset_owner (numOwner) LOCAL ii FOR ii=1 TO tetris WITH ThisForm.d.arr [ THIS.dY+THIS.arrY[ii], THIS.dX+THIS.arrX[ii] ] .Owner = numOwner ENDWITH ENDFOR ENDPROC PROCEDUREconflict (dY,dX, allowedMode) LOCAL ii FOR ii=1 TO tetris IF Not (BETW(dY+THIS.dY+THIS.arrY[ii], 1, bucketHeight); AndBETW(dX+THIS.dX+THIS.arrX[ii], 1, bucketWidth)) RETURN .T. ENDIF
WITH ThisForm.d.arr [ dY+THIS.dY+THIS.arrY[ii], dX+THIS.dX+THIS.arrX[ii] ] IF Not (.Owner=0 Or .Owner=THIS.mode Or .Owner=allowedMode) RETURN .T. ENDIF ENDWITH ENDFOR RETURN .F. ENDPROC FUNCTIONmove_ (dY,dX) IF THIS.Conflict (dY,dX,0) RETURN .F. ELSE THIS.set_free THIS.dY = THIS.dY + dY THIS.dX = THIS.dX + dX THIS.set_visible RETURN .T. ENDIF ENDPROC PROCEDUREmove_down RETURN THIS.move_ (1,0) ENDPROC
PROCEDURERemoveSquees LOCAL lnY, lnX, lcName FOR lnY=1 TO bucketHeight FOR lnX=1 TO bucketWidth lcName = STRTRAN('arr'+STR(lnY,2) + '_' + STR(lnX,2), ' ','0') THIS.RemoveObject (lcName) ENDFOR ENDFOR ENDPROC FUNCTIONinit_figure THIS.current_mode = INT (RAND() * THIS.max_mode) + 1 IF NOT BETW(THIS.current_mode, 1,THIS.max_mode) THIS.current_mode = 1 ENDIF WITH THIS.ff [THIS.current_mode] .reset_figure IF .conflict (0,0,0) RETURN .F. ENDIF .set_visible ENDWITH RETURN .T. ENDFUNC FUNCTIONdebris_line (num)&& if there is at least one line of debris LOCAL ii FOR ii=1 TO bucketWidth IF THIS.arr [num, ii].Owner <> -1 RETURN .F. ENDIF ENDFOR RETURN .T. ENDFUNC FUNCTION find_debris_line LOCAL jj FOR jj=bucketHeight TO 1 STEP -1 IF THIS.debris_line (jj) RETURN jj ENDIF ENDFOR RETURN 0 ENDFUNC PROCEDUREshake_debris LOCAL num, jj, ii, savedColor num = THIS.find_debris_line() IF num = 0 RETURN ENDIF * release line FOR ii=1 TO bucketWidth THIS.arr[num, ii].Owner = 0 THIS.arr[num, ii].BackColor = THIS.BackColor ENDFOR * drop all other lines FOR jj=num-1 TO 1 STEP -1 FOR ii=1 TO bucketWidth IF THIS.arr[jj,ii].Owner = -1 savedColor = THIS.arr [jj, ii].BackColor THIS.arr [jj, ii].BackColor = THIS.BackColor THIS.arr [jj, ii].Owner = 0 THIS.arr [jj+1, ii].BackColor = savedColor THIS.arr [jj+1, ii].Owner = -1 ENDIF ENDFOR ENDFOR ENDPROC PROCEDURErotate_figure (newMode, dY,dX) LOCAL obj WITH THIS.ff [THIS.current_mode] obj = THIS.ff [.turned_clockwise] obj.dY = .dY + .turned_clockwise_dY obj.dX = .dX + .turned_clockwise_dX ENDWITH IF Not obj.Conflict (0,0,THIS.current_mode) THIS.ff [THIS.current_mode].set_free THIS.current_mode = obj.mode THIS.ff [THIS.current_mode].set_visible RETURN .T. ELSE RETURN .F. ENDIF ENDPROC
PROCEDURErotate WITH THIS.ff [THIS.current_mode] DO WHILE .T. IF THIS.rotate_figure (.turned_clockwise, .turned_clockwise_dY, .turned_clockwise_dX) EXIT ELSE IF Not .move_right() EXIT ENDIF ENDIF ENDDO ENDWITH ENDPROC
DEFINE CLASS frm As Form Caption= 'Tetris' MaxButton= .F. BorderStyle = 2 KeyPreview= .T. ADD OBJECT d As bucket ADD OBJECT t As Timer PROCEDUREInit WITH THIS.d STORE 0 TO .top, .left THIS.Width= .Width THIS.Height = .Height ENDWITH THIS.d.init_figure THIS.t.Interval = dropInterval && setting speed ENDPROC PROCEDUREDestroy THIS.d.RemoveSquees ENDPROC PROCEDUREKeyPress LPARAMETERS nKeyCode, nShiftAltCtrl DO CASE CASE nKeyCode=27 THIS.release CASE nKeyCode=keyLeft THIS.d.ff [THIS.d.current_mode].move_left CASE nKeyCode=keyRight THIS.d.ff [THIS.d.current_mode].move_right CASE nKeyCode=keyDrop DO WHILE THIS.d.ff [THIS.d.current_mode].move_down() ENDDO CASE nKeyCode=keyRotate THIS.d.rotate ENDCASE ENDPROC PROCEDUREt.Timer LOCAL obj WITH ThisForm.d obj = .ff [.current_mode] IF Not obj.move_down() obj.set_debris IF .init_figure() obj = .ff [.current_mode] ELSE ThisForm.release&& here you lost ENDIF ENDIF .shake_debris ENDWITH ENDPROC
ENDDEFINE