home *** CD-ROM | disk | FTP | other *** search
/ ftp.alaska-software.com / 2014.06.ftp.alaska-software.com.tar / ftp.alaska-software.com / acsn / XPPTRIS11E.ZIP / XPPTRIS.PRG < prev   
Text File  |  2007-10-25  |  46KB  |  1,277 lines

  1. ******************************************************************
  2. * Langage     : Clipper 5.0 VF
  3. * Fichier     : Cliptris.prg
  4. * Author      : Philippe BONNARDEL
  5. *              <<< This program is placed in the public domain >>>
  6. * Version     : 1.0
  7. * Date        : 08/04/95
  8. * Compil.     : /L/N/W
  9. * Link        : None
  10. * Description : Tetris Game
  11. * Information : Questions, Problems,...? My CIS-ID : 100604,1637
  12. *
  13. * modify for Xbase++ GUI by AUGE_OHR, Jimmy
  14. * Date        : 24.10.2007
  15. * Compile     : /W
  16. * Link        : /PM:PM
  17. * Note        : compile with /DXPPGUI or use #define XPPGUI .T.
  18. ******************************************************************
  19. #include "box.ch"
  20. #include "inkey.ch"
  21. #include "Common.ch"
  22.  
  23. *#define XPPGUI .T.
  24. #IFDEF XPPGUI                             // Xpp GUI
  25.  
  26.  #include "Appevent.ch"
  27.  #include "Gra.ch"
  28.  #include "Xbp.ch"
  29.  #include "Font.ch"
  30.  #include "DLL.ch"
  31.  #define  aPRES_PARAM { ;       // Presentation Parameter fuer den Browser
  32.          {XBP_PP_COL_DA_FGCLR          , XBPSYSCLR_WINDOWSTATICTEXT   }, ;
  33.          {XBP_PP_COL_DA_BGCLR          , XBPSYSCLR_WINDOW             }, ;
  34.          {XBP_PP_COL_DA_HILITE_FGCLR   , GRA_CLR_BLACK },;  // don∩t show
  35.          {XBP_PP_COL_DA_HILITE_BGCLR   , GRA_CLR_BLACK },;  // Cursor here
  36.          {XBP_PP_COL_DA_COMPOUNDNAME   , FONT_DEFPROP_SMALL           }, ;
  37.          {XBP_PP_COL_DA_ROWHEIGHT      , 18                           }, ;
  38.          {XBP_PP_COL_DA_ROWWIDTH       , 10                           }, ;
  39.          {XBP_PP_COL_DA_FRAMELAYOUT    , XBPFRAME_NONE                }, ;
  40.          {XBP_PP_COL_DA_CELLFRAMELAYOUT, XBPFRAME_BOX                 }, ;
  41.          {XBP_PP_COL_DA_CELLHEIGHT     , 32                           }, ;
  42.          {XBP_PP_COL_DA_CELLWIDTH      , 8                            }}
  43. #ENDIF
  44.  
  45. #define C_VERSION         "1.1"
  46. #define C_YEAR            "2007"
  47. #define WIN_UP            2
  48. #define WIN_LEFT          17
  49. #define BD_HEIGHT         18
  50. #define BD_WIDTH          20
  51. #define ST_WIDTH          23
  52. #define N_ROW_TEXT        WIN_UP + 2
  53. #define N_COL_TEXT        WIN_LEFT + BD_WIDTH + 3
  54. #define N_LEN_TEXT        12
  55. #define N_COL_SCORE       N_COL_TEXT + N_LEN_TEXT
  56. #define N_LEN_DISP        ST_WIDTH - N_LEN_TEXT - 1
  57. #define N_NEXT_BLOCK_ROW  WIN_UP + 8
  58. // aEnv
  59. #define LEN_ENV            4              //
  60. #define ENV_SCREEN         1              // DOS/Hybrid settings
  61. #define ENV_CURSOR         2              //
  62. #define ENV_COLOR          3              //
  63. #define ENV_ROW            4              // not avaiable in GUI
  64. // aCargo
  65. #define LEN_A_CARGO       16
  66. #define CG_N_GAME          1              // show Game Status (Play,Pause,Game Over)
  67. #define CG_N_HIGH_SCORE    2              // show High Score
  68. #define CG_N_INIT_SCORE    3
  69. #define CG_N_SCORE         4              // show actual Game Score
  70. #define CG_N_COUNT_LINES   5              // show Lines
  71. #define CG_N_COUNT_BLOCKS  6              // show Blocks
  72. #define CG_N_LEVEL         7              // show Level
  73. #define CG_N_CUR_WAIT      8              // Wait = 1000
  74. #define CG_N_CUR_BLOCK     9              // 1
  75. #define CG_N_NEXT_BLOCK   10              // 1
  76. #define CG_N_BLOCK_SIZE   11              // 4 new Block
  77. #define CG_N_BLOCK_ROW    12              // 0
  78. #define CG_N_BLOCK_COL    13              // 10
  79. #define CG_N_RANDOM       14              // 184
  80. #define CG_N_INIT_TIK     15              // 22924.25
  81. #define CG_N_MAX_BLOCKS   16              // 16
  82. // CG_N_GAME
  83. #define N_GAME_OVER        1
  84. #define N_PLAYED           2
  85. #define N_PAUSED           3
  86. #define A_C_STATUS         {"Game Over", "Play", "Pause"}
  87. // Misc.
  88. #define N_MIN_LEVEL        1
  89. #define N_INIT_MAX_BLOCKS  7
  90. #define N_LEVEL_ADD_BLOCKS 7              // which level Preview :show()
  91. #define N_PT_PER_BLOCK     1
  92. #define N_PT_PER_LINE      5
  93. #define N_BLOCKS_PER_LEVEL 25
  94. #define N_INIT_WAIT        1100           // start time will decrase
  95. #define N_TIME_PER_LEVEL   100            // each level make Game faster
  96. #define C_ELEMENT          "██"           // 2 Charactar !!!
  97. #define N_EMPTY            0
  98. #define N_BORDURE          -1             // DOS/Hybrid
  99. #define C_MASK             "░a▒a▒a▓a▓a▓a▒a▒a░a"
  100. #define C_BOARD_CLR        "N"
  101. #define C_FILE_NAME        "CLIPTRIS.INI" // High Score
  102. #define N_LEN_SCORE        5
  103. #define NTRIM(nVal)        LTRIM(STR(nVal))
  104. #define NPADL(nVal)        PADR(NTRIM(nVal), N_LEN_DISP)
  105. // aScore
  106. #define A_STATE {;
  107.  {00, "High Score:", "R/" , {|aCargo| NPADL(aCargo[CG_N_HIGH_SCORE])}},;
  108.  {02, "Status    :", "R/" , {|aCargo| PADR(A_C_STATUS[aCargo[CG_N_GAME]],N_LEN_DISP)}},;
  109.  {04, "Score     :", "R+/", {|aCargo| NPADL(aCargo[CG_N_SCORE])}},;
  110.  {11, "Level     :", "GR+/",{|aCargo| NPADL(aCargo[CG_N_LEVEL])}},;
  111.  {13, "Lines     :", "G+/", {|aCargo| NPADL(aCargo[CG_N_COUNT_LINES])}},;
  112.  {14, "Blocks    :", "G+/", {|aCargo| NPADL(aCargo[CG_N_COUNT_BLOCKS])}},;
  113.  {15, "Speed     :", "G+/", {|aCargo| NPADL(INT(N_INIT_WAIT/N_INIT_WAIT) +;
  114.                       INT((N_INIT_WAIT - aCargo[CG_N_CUR_WAIT]) / 100))}}}
  115.  
  116. ******************************************************************
  117. *Xbase++ MAIN
  118. ******************************************************************
  119.  
  120. MEMVAR aPlayground , np, aPView, nPV      // PRIVATE
  121. MEMVAR ID_USER, ID_VERSION, ZPATH         // for ErrorSys
  122.  
  123. #IFDEF XPPGUI
  124.  #pragma Library( "XppUi2.lib" )           // XbpBrowse
  125.  
  126. PROCEDURE APPSYS
  127. LOCAL cTitle  := "XppTris"
  128. LOCAL hWndDlg := DllCall("User32.dll",DLL_STDCALL,"FindWindowA",0,cTitle)
  129.    IF !(hWndDlg == 0)
  130.       DllCall("User32.dll",DLL_STDCALL,"SetForegroundWindow",hWndDlg)
  131.       DllCall("User32.dll",DLL_STDCALL,"BringWindowToTop",hWndDlg)
  132.       DllCall("User32.dll",DLL_STDCALL,"ShowWindow",hWndDlg,1)
  133.       DllCall("User32.dll",DLL_STDCALL,"UpdateWindow",hWndDlg)
  134.       QUIT                                // It is a second instance. Bye Bye
  135.    ENDIF
  136. RETURN
  137.  
  138. PROCEDURE MAIN
  139. LOCAL nEvent, mp1, mp2, oXbp
  140. LOCAL oBrowse
  141. LOCAL oPView
  142. LOCAL oCol, i, iMax
  143. LOCAL bBlock
  144. LOCAL oDlg
  145. LOCAL aPos  := {  0,  0}
  146. LOCAL aSize := {400,550}
  147. LOCAL aEnv, aBlocks, aBoard, aCurBlock, aColor, aCargo
  148. LOCAL nKey, cKey, lAllDrop, lNoExit
  149. LOCAL nCol, nRow
  150. LOCAL aText := {}
  151. LOCAL bKeyHandler
  152. LOCAL cRes  := GETENV("XPPRESOURCE")
  153. LOCAL bPP := {{XBP_PP_FGCLR,GRA_CLR_YELLOW},;
  154.               {XBP_PP_BGCLR,GRA_CLR_BLACK }}
  155. LOCAL cPP := {{XBP_PP_FGCLR,GRA_CLR_BLACK },;
  156.               {XBP_PP_BGCLR,XBPSYSCLR_TRANSPARENT}}
  157. *LOCAL aControls := {}                     // Array which XbPart
  158. *LOCAL oNew                                // Pushbutton New
  159.  
  160. PRIVATE aPlayground := LeerArray()        // Playfield
  161. PRIVATE np          := 1                  // index pointer into array
  162. PRIVATE aPView      := LeerPView()        // Preview
  163. PRIVATE nPV         := 1                  // index pointer into array
  164.  
  165. PRIVATE ID_USER     := "Tetris"           // for XppError
  166. PRIVATE ID_VERSION  := C_VERSION+"e"
  167. PRIVATE ZPATH     := LEFT(AppName(.t.),LEN(AppName(.t.)) - LEN(AppName(.f.)))
  168.  
  169.    // center Window
  170.    aPos           := CenterPos(aSize,AppDesktop():currentSize())
  171.  
  172.    oDlg           := XbpDialog():new( ,,aPos, aSize,, .F. )
  173.    oDlg:Icon      := 1004
  174.    oDlg:taskList  := .T.
  175.    oDlg:title     := "XppTris"
  176.    oDlg:maxButton := .F.
  177.    oDlg:minButton := .F.
  178.    oDlg:border    := XBPDLG_DLGBORDER     // no resize
  179.    oDlg:drawingArea:setFontCompoundName( FONT_DEFPROP_SMALL )
  180.    oDlg:drawingArea:bitmap := LoadBMP(cRes,"flash.BMP",aSize)
  181.    oDlg:drawingArea:LbDown := {| aPos, uNIL, self | PostAppEvent(xbeP_Keyboard,xbeK_LEFT ,,self:setparent()) }
  182.    oDlg:drawingArea:RbDown := {| aPos, uNIL, self | PostAppEvent(xbeP_Keyboard,xbeK_RIGHT,,self:setparent()) }
  183.    // rotate with Wheel
  184.    oDlg:drawingArea:wheel  := {| aPos, aWheel, self | WheelUpDn(aWheel,aCargo,self)  }
  185.    // can "click" on Wheel too !
  186.    oDlg:drawingArea:mbDown := {| aPos, uNIL, self | PostAppEvent(xbeP_Keyboard,xbeK_SPACE,,self:setparent()) }
  187.    oDlg:create()
  188.  
  189.    nCol := aSize[2] - 55
  190.    iMax := LEN(A_STATE)
  191.    FOR i := 1 TO iMax
  192.        nCol := nCol - 50
  193.        nRow := aSize[1]-160
  194.        oXbp := XbpStatic():new(oDlg:drawingArea,,{nRow,nCol},{60,24},cPP,.T.)
  195.        oXbp:caption := A_STATE[i,2]
  196.        oXbp:options := XBPSTATIC_TEXT_LEFT+XBPSTATIC_TEXT_VCENTER
  197.        oXbp:create()
  198.  
  199.        nRow := aSize[1]-100
  200.        oXbp := XbpStatic():new(oDlg:drawingArea,,{nRow,nCol},{60,24},bPP,.T.)
  201.        oXbp:options := XBPSTATIC_TEXT_CENTER+XBPSTATIC_TEXT_VCENTER
  202.        oXbp:caption := ""
  203.        oXbp:create()
  204.        AADD(aText,oXbp)                   // add to Array
  205.    NEXT
  206.  
  207.    oBrowse := XbpBrowse():new( oDlg:drawingArea,,{10,40},{aSize[1]-200 ,aSize[2]-121 }, aPRES_PARAM )
  208.    oBrowse:hScroll   := .F.
  209.    oBrowse:vScroll   := .F.
  210.    oBrowse:sizeCols  := .F.
  211.    oBrowse:cursorMode:= XBPBRW_CURSOR_NONE
  212.    oBrowse:create()
  213.  
  214.    oBrowse:skipBlock     := {|nSkip| -np + (np := MAX(1, MIN(LEN(aPlayground), np + nSkip))) }
  215.    oBrowse:goTopBlock    := {|| np := 1}
  216.    oBrowse:goBottomBlock := {|| np := LEN(aPlayground) }
  217.    oBrowse:posBlock      := {|| np }
  218.    oBrowse:phyPosBlock   := {|| np }
  219.    oBrowse:lastPosBlock  := {|| Len( aPlayground ) }
  220.    oBrowse:firstPosBlock := {|| 1  }
  221.  
  222.    iMax  := LEN(aPlayground[1])
  223.    FOR i := 1 TO iMax
  224.       oCol       := XbpColumn():new(,,,,aPRES_PARAM)
  225.       bBlock := "{|xVal| IF(xVal == NIL, aPlayground[np][" +STR(i,3)+ "], aPlayground[np][" +STR(i,3)+ "] := xVal) }"
  226.       oCol:dataLink := &bBlock
  227.       oCol:colorBlock := {|xVal| IF(xVal == "0" ,{GRA_CLR_BLACK    ,GRA_CLR_BLACK    } ,;
  228.                                  IF(xVal == "1" ,{GRA_CLR_CYAN     ,GRA_CLR_CYAN     } ,;
  229.                                  IF(xVal == "2" ,{GRA_CLR_BLUE     ,GRA_CLR_BLUE     } ,;
  230.                                  IF(xVal == "3" ,{GraMakeRGBColor({255,138,025}), GraMakeRGBColor({255,138,025})} ,;
  231.                                  IF(xVal == "4" ,{GraMakeRGBColor({136,030,250}), GraMakeRGBColor({136,030,250})} ,;
  232.                                  IF(xVal == "5" ,{GRA_CLR_RED      ,GRA_CLR_RED      } ,;
  233.                                  IF(xVal == "6" ,{GRA_CLR_GREEN    ,GRA_CLR_GREEN    } ,;
  234.                                  IF(xVal == "7" ,{GRA_CLR_YELLOW   ,GRA_CLR_YELLOW   } ,;
  235.                                  IF(xVal == "8" ,{GRA_CLR_DARKGREEN,GRA_CLR_DARKGREEN} ,;
  236.                                  IF(xVal == "9" ,{GRA_CLR_WHITE    ,GRA_CLR_WHITE    } ,;
  237.                                  IF(xVal == "10",{GRA_CLR_DARKRED  ,GRA_CLR_DARKRED  } ,;
  238.                                  IF(xVal == "11",{GRA_CLR_PINK     ,GRA_CLR_PINK     } ,;
  239.                                  IF(xVal == "12",{GRA_CLR_DARKCYAN ,GRA_CLR_DARKCYAN } ,;
  240.                                  IF(xVal == "13",{GRA_CLR_BROWN    ,GRA_CLR_BROWN    } ,;
  241.                                  IF(xVal == "14",{GRA_CLR_DARKBLUE ,GRA_CLR_DARKBLUE } ,;
  242.                                                  {GRA_CLR_BLACK,GRA_CLR_PALEGRAY} ))))))))))))))) }
  243.       oCol:create()
  244.       oBrowse:addColumn( oCol )
  245.    NEXT
  246. *   oBrowse:LbDown       := {| aPos,y,obj | SetAppFocus( oDlg )} // disable Click
  247. *   oBrowse:RbDown       := {| aPos,y,obj | SetAppFocus( oDlg )} // disable Click
  248.  
  249.    // Preview
  250.    oPView := PVIEW(oDlg,{300,40},{60,80})
  251.    // must reach Level 7
  252.    oPView:hide()
  253.  
  254.    oDlg:show()
  255.    oBrowse:show()
  256.  
  257. *   AADD(aControls,oDlg)                   // control to keyhandler
  258. *   AADD(aControls,oBrowse)                // control to keyhandler
  259. *   AADD(aControls,oPView)                 // control to keyhandler
  260.  
  261.    Make_Env_Win(@aEnv,oDlg)
  262.    Make_Var(@aBlocks, @aBoard, @aColor, @aCargo)
  263.    Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  264.  
  265. *   //
  266. *   // install keyboard handler
  267. *   //
  268. *   bKeyHandler := {| nKey,uNIL,obj | DlgKeys(nKey,obj,;
  269. *                           oDlg, aBlocks, aColor, aCargo, oBrowse, aText,;
  270. *                           aBoard, @aCurBlock, oPView, @lAllDrop, @lNoExit )}
  271. *   AEVAL(aControls,{| o | o:keyBoard := bKeyHandler})
  272.  
  273.    lAllDrop := .F.
  274.    lNoExit  := .T.
  275.  
  276.    SetAppFocus( oDlg )
  277. *   oNew := oDlg:drawingArea:childlist()[18]:childlist()[2]
  278. *   SetAppFocus( oNew )
  279.  
  280.    DO WHILE nEvent <> xbeP_Close .AND. lNoExit
  281.  
  282.       IF .NOT. lAllDrop
  283.          nEvent := AppEvent( @mp1, @mp2, @oXbp,(aCargo[CG_N_CUR_WAIT]/10) )
  284.       ENDIF
  285.       DO CASE
  286.          CASE nEvent == xbe_None          // need for Tic_Tac
  287.  
  288.          CASE nEvent == xbeP_Keyboard
  289.             nKey := mp1
  290.             cKey := UPPER(CHR(nKey))
  291.             DO CASE
  292.                CASE nKey = xbeK_ESC
  293.                   EXIT
  294.  
  295.                CASE nKey = xbeK_F12 .AND. aCargo[CG_N_GAME] != N_GAME_OVER
  296.                   aCargo[CG_N_SCORE]        := 1000
  297.                   aCargo[CG_N_COUNT_LINES]  := 50
  298.                   aCargo[CG_N_COUNT_BLOCKS] := 150
  299.                   aCargo[CG_N_LEVEL]        := 7
  300.                   Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  301.  
  302.                CASE cKey == "R" .AND. aCargo[CG_N_GAME] = N_GAME_OVER
  303.                   RandomTest(aText)
  304.  
  305.                CASE cKey == "N"
  306.                   Init_Game(aBlocks, aBoard, @aCurBlock, aCargo, oPView)
  307.                   oPView:hide()
  308.                   Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  309.  
  310.                CASE aCargo[CG_N_GAME] == N_GAME_OVER
  311.                    // does flicker on Screen
  312. *                  Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  313.  
  314.                CASE aCargo[CG_N_GAME] != N_GAME_OVER
  315.                   DO CASE
  316.                      CASE aCargo[CG_N_GAME] == N_PAUSED .AND. nKey != 0
  317.                           aCargo[CG_N_GAME] := N_PLAYED
  318.  
  319.                      CASE cKey == "P"
  320.                           aCargo[CG_N_GAME] := N_PAUSED
  321.                            // does flicker on Screen
  322. *                          Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  323.  
  324.                      CASE nKey == xbeK_UP .OR. nKey == xbeK_DOWN
  325.                         Draw_Block(aCurBlock, aColor, aCargo, .F.,oBrowse)
  326.                         Rotate_Block(@aCurBlock, aCargo, IF(nKey == xbeK_UP, K_LEFT, K_RIGHT))
  327.                         IF Hit_Block(aBoard, aCurBlock, aCargo)
  328.                            Rotate_Block(@aCurBlock, aCargo, IF(nKey == xbeK_UP, K_RIGHT, K_LEFT))
  329.                         ENDIF
  330.                         Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  331.  
  332.                      CASE nKey == xbeK_LEFT .OR. nKey == xbeK_RIGHT
  333.                         Draw_Block(aCurBlock, aColor, aCargo, .F.,oBrowse)
  334.                         aCargo[CG_N_BLOCK_COL] += IF(nKey == xbeK_LEFT, -2, 2)
  335.                         IF Hit_Block(aBoard, aCurBlock, aCargo)
  336.                            aCargo[CG_N_BLOCK_COL] += IF(nKey == xbeK_LEFT, 2, -2)
  337.                         ENDIF
  338.                         Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  339.  
  340.                      CASE nKey == xbeK_SPACE
  341.                         lAllDrop := .T.
  342.                   ENDCASE
  343.             ENDCASE
  344.       OTHERWISE
  345.          oXbp:handleEvent( nEvent, mp1, mp2 )
  346.       ENDCASE
  347.  
  348.       IF aCargo[CG_N_GAME] == N_PLAYED
  349.          IF lAllDrop .OR. Tic_Tac(aCargo[CG_N_CUR_WAIT], aCargo[CG_N_INIT_TIK])
  350.             Draw_Block(aCurBlock, aColor, aCargo, .F.,oBrowse)
  351.             aCargo[CG_N_BLOCK_ROW]++
  352.             IF Hit_Block(aBoard, aCurBlock, aCargo)
  353.                aCargo[CG_N_BLOCK_ROW]--
  354.                Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  355.                Place_Block(aBlocks, aBoard, @aCurBlock, aColor, aCargo,oBrowse,oPView)
  356.                lAllDrop := .F.
  357.             ENDIF
  358.             Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  359.             aCargo[CG_N_INIT_TIK] := SECONDS()
  360.  
  361.             Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  362.          ENDIF
  363.       ENDIF
  364.    ENDDO
  365.    Rest_Env(aEnv, aCargo)
  366. RETURN
  367.  
  368. STATIC FUNCTION WheelUpDn(aWheel,aCargo,oDraw)
  369.    IF aCargo[CG_N_GAME] != N_GAME_OVER
  370.       IF aWheel[2] > 0
  371.          PostAppEvent(xbeP_Keyboard,xbeK_UP  ,,oDraw:setparent() )
  372.       ELSE
  373.          PostAppEvent(xbeP_Keyboard,xbeK_DOWN,,oDraw:setparent() )
  374.       ENDIF
  375.    ENDIF
  376. RETURN NIL
  377.  
  378. STATIC FUNCTION LeerArray()
  379. LOCAL aPlayground[18][20]
  380. LOCAL i
  381.    FOR i = 1 TO 18
  382.        AFILL(aPlayground[i],"0")
  383.    NEXT
  384. RETURN aPlayground
  385.  
  386. STATIC FUNCTION CENTERPOS(aSize,aRefSize)
  387. RETURN {INT((aRefSize[1] - aSize[1]) / 2) ;
  388.        ,INT((aRefSize[2] - aSize[2]) / 2)}
  389.  
  390. STATIC FUNCTION ISINFIELD(nRow,nCol)
  391.    IF nRow < 1 .OR. nRow > LEN(aPlayground)   .OR.;
  392.       nCol < 1 .OR. nCol > LEN(aPlayground[1])
  393.       TONE(500,1)
  394.       RETURN .F.
  395.    ENDIF
  396. RETURN .T.
  397.  
  398. STATIC FUNCTION LeerPView()
  399. LOCAL aPView[4][7]
  400. LOCAL i
  401.    FOR i = 1 TO 4
  402.        AFILL(aPView[i],"0")
  403.    NEXT
  404. RETURN aPView
  405.  
  406. STATIC FUNCTION PVIEW(oDlg,aPos,aSize)
  407. LOCAL oPView
  408. LOCAL oCol, i, iMax
  409. LOCAL bBlock
  410.  
  411.    oPView := XbpBrowse():new( oDlg:drawingArea,,aPos,aSize , aPRES_PARAM )
  412.    oPView:hScroll   := .F.
  413.    oPView:vScroll   := .F.
  414.    oPView:sizeCols  := .F.
  415.    oPView:cursorMode:= XBPBRW_CURSOR_NONE
  416.    oPView:create()
  417.  
  418.    oPView:skipBlock     := {|nSkip| -nPV + (nPV := MAX(1, MIN(LEN(aPView), nPV + nSkip))) }
  419.    oPView:goTopBlock    := {|| nPV := 1}
  420.    oPView:goBottomBlock := {|| nPV := LEN(aPView) }
  421.    oPView:posBlock      := {|| nPV }
  422.    oPView:phyPosBlock   := {|| nPV }
  423.    oPView:lastPosBlock  := {|| Len( aPView ) }
  424.    oPView:firstPosBlock := {|| 1  }
  425.  
  426.    iMax  := LEN(aPView[1])
  427.    FOR i := 1 TO iMax
  428.       oCol       := XbpColumn():new(,,,,aPRES_PARAM)
  429.       bBlock := "{|xVal| IF(xVal == NIL, aPView[nPV][" +STR(i,3)+ "], aPView[nPV][" +STR(i,3)+ "] := xVal) }"
  430.       oCol:dataLink := &bBlock
  431.       oCol:colorBlock := {|xVal| IF(xVal == "0" ,{GRA_CLR_BLACK    ,GRA_CLR_BLACK    } ,;
  432.                                  IF(xVal == "1" ,{GRA_CLR_CYAN     ,GRA_CLR_CYAN     } ,;
  433.                                  IF(xVal == "2" ,{GRA_CLR_BLUE     ,GRA_CLR_BLUE     } ,;
  434.                                  IF(xVal == "3" ,{GraMakeRGBColor({255,138,025}), GraMakeRGBColor({255,138,025})} ,;
  435.                                  IF(xVal == "4" ,{GraMakeRGBColor({136,030,250}), GraMakeRGBColor({136,030,250})} ,;
  436.                                  IF(xVal == "5" ,{GRA_CLR_RED      ,GRA_CLR_RED      } ,;
  437.                                  IF(xVal == "6" ,{GRA_CLR_GREEN    ,GRA_CLR_GREEN    } ,;
  438.                                  IF(xVal == "7" ,{GRA_CLR_YELLOW   ,GRA_CLR_YELLOW   } ,;
  439.                                  IF(xVal == "8" ,{GRA_CLR_DARKGREEN,GRA_CLR_DARKGREEN} ,;
  440.                                  IF(xVal == "9" ,{GRA_CLR_WHITE    ,GRA_CLR_WHITE    } ,;
  441.                                  IF(xVal == "10",{GRA_CLR_DARKRED  ,GRA_CLR_DARKRED  } ,;
  442.                                  IF(xVal == "11",{GRA_CLR_PINK     ,GRA_CLR_PINK     } ,;
  443.                                  IF(xVal == "12",{GRA_CLR_DARKCYAN ,GRA_CLR_DARKCYAN } ,;
  444.                                  IF(xVal == "13",{GRA_CLR_BROWN    ,GRA_CLR_BROWN    } ,;
  445.                                  IF(xVal == "14",{GRA_CLR_DARKBLUE ,GRA_CLR_DARKBLUE } ,;
  446.                                                  {GRA_CLR_BLACK,GRA_CLR_WHITE} ))))))))))))))) }
  447.       oCol:create()
  448.       oPView:addColumn( oCol )
  449.    NEXT
  450.    oPView:rowPos := LEN(aPView)
  451.    oPView:colPos := LEN(aPView[1])
  452. RETURN oPView
  453.  
  454. PROCEDURE DlgKeys(nKey,obj, oDlg, aBlocks, aColor, aCargo, oBrowse, aText, aBoard, aCurBlock, oPView, lAllDrop, lNoExit)
  455. LOCAL cKey
  456.  
  457.    cKey := UPPER(CHR(nKey))
  458.    DO CASE
  459.       CASE nKey = xbeK_ESC
  460.          lNoExit := .F.
  461.  
  462.       CASE nKey = xbeK_F12 .AND. aCargo[CG_N_GAME] != N_GAME_OVER
  463.          aCargo[CG_N_SCORE]        := 1000
  464.          aCargo[CG_N_COUNT_LINES]  := 50
  465.          aCargo[CG_N_COUNT_BLOCKS] := 150
  466.          aCargo[CG_N_LEVEL]        := 7
  467.          Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  468.  
  469.       CASE nKey = xbeK_F2 .or. cKey == "N"
  470.          Init_Game(aBlocks, aBoard, @aCurBlock, aCargo, oPView)
  471.          oPView:hide()
  472.          Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  473.  
  474.       CASE aCargo[CG_N_GAME] == N_GAME_OVER
  475.          Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  476.  
  477.       CASE aCargo[CG_N_GAME] != N_GAME_OVER
  478.          DO CASE
  479.             CASE aCargo[CG_N_GAME] == N_PAUSED .AND. nKey != 0
  480.                  aCargo[CG_N_GAME] := N_PLAYED
  481.  
  482.             CASE cKey == "P"
  483.                  aCargo[CG_N_GAME] := N_PAUSED
  484.                  Disp_Score(aBlocks, aColor, aCargo, oBrowse, aText)
  485.  
  486.             CASE nKey == xbeK_UP .OR. nKey == xbeK_DOWN
  487.                Draw_Block(aCurBlock, aColor, aCargo, .F.,oBrowse)
  488.                Rotate_Block(@aCurBlock, aCargo, IF(nKey == xbeK_UP, K_LEFT, K_RIGHT))
  489.                IF Hit_Block(aBoard, aCurBlock, aCargo)
  490.                   Rotate_Block(@aCurBlock, aCargo, IF(nKey == xbeK_UP, K_RIGHT, K_LEFT))
  491.                ENDIF
  492.                Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  493.  
  494.             CASE nKey == xbeK_LEFT .OR. nKey == xbeK_RIGHT
  495.                Draw_Block(aCurBlock, aColor, aCargo, .F.,oBrowse)
  496.                aCargo[CG_N_BLOCK_COL] += IF(nKey == xbeK_LEFT, -2, 2)
  497.                IF Hit_Block(aBoard, aCurBlock, aCargo)
  498.                   aCargo[CG_N_BLOCK_COL] += IF(nKey == xbeK_LEFT, 2, -2)
  499.                ENDIF
  500.                Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  501.  
  502.             CASE nKey == xbeK_SPACE
  503. *               TONE(500,1)
  504.                lAllDrop := .T.
  505.          ENDCASE
  506.    ENDCASE
  507.    Setappfocus(oDlg)
  508. RETURN
  509.  
  510. STATIC FUNCTION RAND( nLimit )
  511. LOCAL nRes :=0
  512. DEFAULT nLimit TO 1
  513.  
  514. DO WHILE nRes < 1
  515.    nRes := BaseRandom( nLimit*3 ) - nLimit
  516.    If nRes > nLimit
  517.       nRes := 0
  518.    ENDIF
  519. ENDDO
  520. RETURN( nRes )
  521.  
  522. // BaseRandom Function is example Random Function from Alaska, but
  523. // it has a decided tendancy to avoid numbers near the edge of the range!
  524. STATIC FUNCTION BaseRandom( nLimit )
  525. STATIC snRandom := Nil
  526. LOCAL nDecimals, cLimit
  527.  
  528. IF snRandom == NIL
  529.    snRandom := Seconds() / Exp(1)
  530. ENDIF
  531. snRandom := Log( snRandom + Sqrt(2) ) * Exp(3)
  532. snRandom := Val( Str(snRandom - Int(snRandom), 17, 15 ) )
  533. cLimit := Transform( nLimit, "@N" )
  534. nDecimals := At(".", cLimit)
  535. IF nDecimals > 0
  536.    nDecimals:= Len(cLimit)-nDecimals
  537. ENDIF
  538. RETURN Round( nLimit * snRandom, nDecimals )
  539.  
  540. STATIC FUNCTION RandomTest(aText)
  541. LOCAL nVal := 0
  542. LOCAL i,iMax
  543.  
  544.    iMax  := LEN(aText)
  545.    FOR i := 1 TO iMax
  546.       aText[i]:setCaption("0")
  547.    NEXT
  548.    FOR i := 1 TO 10000
  549.       nVal := INT(RAND(CG_N_RANDOM/2))
  550.       DO CASE
  551.          CASE nVal = 1 ; aText[1]:setCaption(NTRIM(VAL(aText[1]:caption)+1))
  552.          CASE nVal = 2 ; aText[2]:setCaption(NTRIM(VAL(aText[2]:caption)+1))
  553.          CASE nVal = 3 ; aText[3]:setCaption(NTRIM(VAL(aText[3]:caption)+1))
  554.          CASE nVal = 4 ; aText[4]:setCaption(NTRIM(VAL(aText[4]:caption)+1))
  555.          CASE nVal = 5 ; aText[5]:setCaption(NTRIM(VAL(aText[5]:caption)+1))
  556.          CASE nVal = 6 ; aText[6]:setCaption(NTRIM(VAL(aText[6]:caption)+1))
  557.          CASE nVal = 7 ; aText[7]:setCaption(NTRIM(VAL(aText[7]:caption)+1))
  558.       OTHERWISE
  559.       ENDCASE
  560.    NEXT
  561. RETURN NIL
  562.  
  563. STATIC FUNCTION LoadBMP(cRes,cBMP,aSize)
  564. LOCAL oBMP := ExXbpBitmap():new():create()
  565. LOCAL nPosi := AT(";",cRes)
  566. LOCAL cFile
  567.    IF nPosi > 0
  568.       cFile := SUBSTR(cRes,1,nPosi-1)+"\"+cBMP
  569.       IF FILE(cFile)
  570.          oBMP:loadFile(cFile)
  571.          oBMP := BMP2BMP(oBMP,aSize)
  572.       ENDIF
  573.    ELSEIF FILE("fire.bmp")
  574.       oBMP:loadFile("fire.bmp")
  575.       oBMP := BMP2BMP(oBMP,aSize)
  576.    ENDIF
  577. RETURN oBMP
  578.  
  579. STATIC FUNCTION BMP2BMP(oBMP,aXbpSize)
  580. LOCAL oHuge, oTiny, oPS, oRet
  581.    IF aXbpSize[2] > 0
  582.       oHuge := oBMP
  583.       oTiny := XbpBitmap():New():Create()
  584.       oTiny:Make(aXbpSize[1],aXbpSize[2])
  585.       oPS  := XbpPresSpace():new()
  586.       oTiny:presSpace(oPS)
  587.       oHuge:Draw(oPS,{0,0,aXbpSize[1],aXbpSize[2]},,,GRA_BLT_BBO_IGNORE)
  588.       oRet := oTiny
  589.    ELSE
  590.       oRet := oBMP
  591.    ENDIF
  592. RETURN oRet
  593.  
  594. CLASS ExXbpBitmap FROM XbpBitmap
  595.    EXPORTED:
  596.       METHOD Load
  597. ENDCLASS
  598.  
  599. METHOD ExXbpBitmap:Load(cDll,nID,cType)
  600. LOCAL xResource
  601. LOCAL lSuccess
  602.  
  603.    DEFAULT cDll TO "WM9DLL.DLL"
  604.    IF EMPTY(cType)
  605.       lSuccess :=::XbpBitmap:load(cDll,nID)
  606.    ELSE
  607.       xResource := LoadResource(nID,cDll,cType)
  608.       lSuccess  := !EMPTY(xResource)
  609.       ::setBuffer(xResource)
  610.    ENDIF
  611. RETURN (lSuccess)
  612.  
  613. ******************************************************************
  614. * original Hybrid Version
  615. ******************************************************************
  616.  
  617. #ELSE                                     // __XPPGUI__
  618. PROCEDURE MAIN
  619.    PRIVATE ID_USER     := "Tetris"        // for XppError
  620.    PRIVATE ID_VERSION  := C_VERSION
  621.    PRIVATE ZPATH := LEFT(AppName(.t.),LEN(AppName(.t.)) - LEN(AppName(.f.)))
  622.    CLIP_TRIS()
  623. RETURN
  624. #ENDIF
  625.  
  626. FUNCTION CLIP_TRIS()
  627. LOCAL aEnv, aBlocks, aBoard, aCurBlock, aColor, aCargo
  628. LOCAL nKey, cKey, lAllDrop, lNoExit
  629.  
  630. Make_Env_Win(@aEnv)
  631. Make_Var(@aBlocks, @aBoard, @aColor, @aCargo)
  632. lAllDrop := .F.
  633. lNoExit  := .T.
  634. DO WHILE lNoExit
  635.   #IFDEF CL50
  636.     BEGINPAINT()
  637.   #ELSE
  638.    #IFDEF XPPGUI
  639.    #ELSE
  640.     DISPBEGIN()
  641.    #ENDIF
  642.   #ENDIF
  643.  
  644.   cKey := UPPER(CHR(nKey := INKEY()))
  645.   DO CASE
  646.      CASE nKey == K_ESC
  647.       lNoExit := .F.
  648.  
  649.      CASE cKey == "N"
  650.       Init_Game(aBlocks, aBoard, @aCurBlock, aCargo)
  651.       Draw_Block(aCurBlock, aColor, aCargo, .T.)
  652.  
  653.      CASE aCargo[CG_N_GAME] != N_GAME_OVER
  654.       DO CASE
  655.         CASE aCargo[CG_N_GAME] == N_PAUSED .AND. nKey != 0
  656.           aCargo[CG_N_GAME] := N_PLAYED
  657.  
  658.         CASE cKey == "P"
  659.           aCargo[CG_N_GAME] := N_PAUSED
  660.  
  661.         CASE nKey == K_UP .OR. nKey == K_DOWN
  662.           Draw_Block(aCurBlock, aColor, aCargo, .F.)
  663.           Rotate_Block(@aCurBlock, aCargo, IF(nKey == K_UP, K_LEFT, K_RIGHT))
  664.           IF Hit_Block(aBoard, aCurBlock, aCargo)
  665.              Rotate_Block(@aCurBlock, aCargo, IF(nKey == K_UP, K_RIGHT, K_LEFT))
  666.           ENDIF
  667.           Draw_Block(aCurBlock, aColor, aCargo, .T.)
  668.  
  669.         CASE nKey == K_LEFT .OR. nKey == K_RIGHT
  670.           Draw_Block(aCurBlock, aColor, aCargo, .F.)
  671.           aCargo[CG_N_BLOCK_COL] += IF(nKey == K_LEFT, -2, 2)
  672.           IF Hit_Block(aBoard, aCurBlock, aCargo)
  673.             aCargo[CG_N_BLOCK_COL] += IF(nKey == K_LEFT, 2, -2)
  674.           ENDIF
  675.           Draw_Block(aCurBlock, aColor, aCargo, .T.)
  676.  
  677.         CASE nKey == K_SPACE
  678.           lAllDrop := .T.
  679.       ENDCASE
  680.   ENDCASE
  681.  
  682.   IF aCargo[CG_N_GAME] == N_PLAYED
  683.     IF lAllDrop .OR. Tic_Tac(aCargo[CG_N_CUR_WAIT], aCargo[CG_N_INIT_TIK])
  684.        Draw_Block(aCurBlock, aColor, aCargo, .F.)
  685.        aCargo[CG_N_BLOCK_ROW]++
  686.        IF Hit_Block(aBoard, aCurBlock, aCargo)
  687.         aCargo[CG_N_BLOCK_ROW]--
  688.         Draw_Block(aCurBlock, aColor, aCargo, .T.)
  689.         Place_Block(aBlocks, aBoard, @aCurBlock, aColor, aCargo)
  690.         lAllDrop := .F.
  691.        ENDIF
  692.        Draw_Block(aCurBlock, aColor, aCargo, .T.)
  693.        aCargo[CG_N_INIT_TIK] := SECONDS()
  694.     ENDIF
  695.   ENDIF
  696.   Disp_Score(aBlocks, aColor, aCargo)
  697.  
  698.   #IFDEF CL50
  699.       ENDPAINT()
  700.   #ELSE
  701.    #IFDEF XPPGUI
  702.       SLEEP(10)
  703.    #ELSE
  704.       DISPEND()
  705.    #ENDIF
  706.   #ENDIF
  707. ENDDO
  708. Rest_Env(aEnv, aCargo)
  709. RETURN (NIL)
  710.  
  711. STATIC FUNCTION SHADOW (nT, nL, nB, nR)
  712. LOCAL cVerbuff, cHorBuff
  713.    RESTSCREEN (nT, nR - 1, nB - 1, nR, ;
  714.       TRANSFORM(cVerbuff := SAVESCREEN (nT, nR - 1, nB - 1, nR), ;
  715.       REPLICATE("X" + CHR(8), LEN(cVerBuff)/2)))
  716.    RESTSCREEN (nB, nL, nB, nR, ;
  717.       TRANSFORM(cHorBuff := SAVESCREEN (nB, nL, nB, nR), ;
  718.       REPLICATE("X" + CHR(8), LEN(cHorBuff)/2)))
  719. RETURN (NIL)
  720.  
  721. STATIC FUNCTION MAKE_ENV_WIN(aEnv, oMain)                                     // control to keyhandler
  722. #IFDEF XPPGUI
  723.    LOCAL oDraw := oMain:drawingArea
  724.    LOCAL aSize := oDraw:currentsize()
  725.    LOCAL oXbp, oXbp1, oXbp2, oXbp3, oXbp4, oXbp5
  726.    LOCAL nCol, nRow
  727.    LOCAL aPP := {{XBP_PP_COMPOUNDNAME , FONT_DEFPROP_SMALL }, ;
  728.                  {XBP_PP_FGCLR,GRA_CLR_BLACK},;
  729.                  {XBP_PP_BGCLR,GraMakeRGBColor({153,199,255})}}
  730.    LOCAL bPP := {{XBP_PP_COMPOUNDNAME , FONT_DEFPROP_MEDIUM+FONT_STYLE_BOLD }, ;
  731.                  {XBP_PP_FGCLR,GRA_CLR_BLACK},;
  732.                  {XBP_PP_BGCLR,XBPSYSCLR_TRANSPARENT}}
  733.    LOCAL cPP := {{XBP_PP_COMPOUNDNAME , "12.Wingdings" }, ;
  734.                  {XBP_PP_FGCLR,GRA_CLR_BLACK},;
  735.                  {XBP_PP_BGCLR,GraMakeRGBColor({153,199,255})}}
  736.  
  737.    aEnv := ARRAY(LEN_ENV)
  738.    nRow := 10
  739.    nCol := aSize[2]  - 30
  740.  
  741.    oXbp1 := XbpStatic():new(oDraw,,{nRow,nCol},{aSize[1]-20,24},bPP)
  742.    oXbp1:type    := XBPSTATIC_TYPE_RAISEDRECT
  743.    oXbp1:create():show()
  744.  
  745.    oXbp := XbpStatic():new(oXbp1,,{0,0},{aSize[1]-20,24},bPP)
  746.    oXbp:caption := "XppTris " + ID_VERSION + " for Xbase++ by AUGE_OHR"
  747.    oXbp:options := XBPSTATIC_TEXT_CENTER+XBPSTATIC_TEXT_VCENTER
  748.    oXbp:Lbdown  := {| aPos,y,obj | MSGBOX("Yiu Software"+Chr(13)+;
  749.                                           "Siemensstrasse 14"+Chr(13)+;
  750.                                           "21509 Glinde"+Chr(13)+Chr(13)+;
  751.                                           "AUGE_OHR@WEB.DE","Info"),;
  752.                                           SetappFocus(oMain)}
  753.    oXbp:create():show()
  754.  
  755.    nRow := 10
  756.    nCol :=  2
  757.    oXbp1 := XbpStatic():new(oDraw,,{nRow,nCol},{aSize[1]-20,24},aPP)
  758.    oXbp1:caption := "                              " +;
  759.                     " Rotation :       Move :      " +;
  760.                     "   Space Bar: Drop"
  761.  
  762.    oXbp1:options := XBPSTATIC_TEXT_CENTER+XBPSTATIC_TEXT_VCENTER
  763.    oXbp1:create():show()
  764.  
  765.    oXbp := XbpPushButton():new(oXbp1 , , {  0,0}, {30,24},aPP,.T.)
  766.    oXbp:caption := "~Esc"
  767.    oXbp:Tabstop := .T.
  768.    oXbp:create():Show()
  769.    oXbp:activate:= {|| PostAppEvent(xbeP_Keyboard,xbeK_ESC,,oDraw:setparent()), SetappFocus(oMain) }
  770.  
  771.    oXbp := XbpPushButton():new(oXbp1 , , { 40,0}, {30,24},aPP,.T.)
  772.    oXbp:caption := "~New"
  773.    oXbp:Tabstop := .T.
  774.    oXbp:create():Show()
  775.    oXbp:activate:= {|| PostAppEvent(xbeP_Keyboard,ASC("N"),,oDraw:setparent()), SetappFocus(oMain) }
  776.  
  777.    oXbp := XbpPushButton():new(oXbp1 , , { 80,0}, {40,24},aPP,.T.)
  778.    oXbp:caption := "~Pause"
  779.    oXbp:Tabstop := .T.
  780.    oXbp:create():Show()
  781.    oXbp:activate:= {|| PostAppEvent(xbeP_Keyboard,ASC("P"),,oDraw:setparent()), SetappFocus(oMain) }
  782.  
  783.    oXbp2 := XbpStatic():new(oXbp1,,{176,0},{18,24},cPP,.T.)
  784.    oXbp2:caption := "ô"
  785.    oXbp2:options := XBPSTATIC_TEXT_CENTER+XBPSTATIC_TEXT_VCENTER
  786.    oXbp2:create():show()
  787.  
  788.    oXbp3 := XbpStatic():new(oXbp1,,{234,0},{18,24},cPP,.T.)
  789.    oXbp3:caption := "ó"
  790.    oXbp3:options := XBPSTATIC_TEXT_CENTER+XBPSTATIC_TEXT_VCENTER
  791.    oXbp3:create():show()
  792.  
  793. #ELSE
  794.    aEnv := ARRAY(LEN_ENV)
  795.    aEnv[ENV_SCREEN] := SAVESCREEN (0, 0, MAXROW(), MAXCOL())
  796.    aEnv[ENV_CURSOR] := SETCURSOR(0)
  797.    aEnv[ENV_COLOR]  := SETCOLOR("GR+/W")
  798.    aEnv[ENV_ROW]    := ROW()
  799.  
  800.    @ 0, 0 SAY PADC("ClipTris V" + C_VERSION + " - Philippe Bonnardel - " +;
  801.                     C_YEAR, MAXCOL() + 1)
  802.    @ MAXROW(), 0 SAY PADC("Exit: Escape  New: N  Pause: P  " +;
  803.                        CHR(24) + "/" + CHR(25) + ": Rotation  " +;
  804.                        CHR(27) + "/" + CHR(26) + ": Move  " +;
  805.                        "Space Bar: Drop", MAXCOL() + 1)
  806.    RESTSCREEN (1, 0, MAXROW() - 1, MAXCOL(), ;
  807.                REPLICATE (C_MASK, ((MAXCOL() + 1) * (MAXROW() - 1)) / 2))
  808.    SETCOLOR("BG/" + C_BOARD_CLR)
  809.    @ WIN_UP, WIN_LEFT, WIN_UP + BD_HEIGHT + 1, ;
  810.      WIN_LEFT + BD_WIDTH + ST_WIDTH + 2 BOX B_SINGLE + SPACE(1)
  811.    SHADOW(WIN_UP + 1, WIN_LEFT + 2, WIN_UP + BD_HEIGHT + 2, ;
  812.           WIN_LEFT + BD_WIDTH + ST_WIDTH + 4)
  813.    @ WIN_UP, WIN_LEFT, WIN_UP + BD_HEIGHT + 1, WIN_LEFT + BD_WIDTH + 1 BOX B_SINGLE
  814.    @ WIN_UP, WIN_LEFT + BD_WIDTH + 1 SAY "┬"
  815.    @ WIN_UP + BD_HEIGHT + 1, WIN_LEFT + BD_WIDTH + 1 SAY "┴"
  816.    SETCOLOR("W+/" + C_BOARD_CLR)
  817.    AEVAL(A_STATE, {|x| SETPOS(N_ROW_TEXT + x[1], N_COL_TEXT), QQOUT(x[2])})
  818.    @ N_NEXT_BLOCK_ROW, N_COL_TEXT SAY "Next      :"
  819.  
  820. #ENDIF
  821. RETURN (NIL)
  822.  
  823. STATIC FUNCTION REST_ENV(aEnv, aCargo, ljustSave)
  824. LOCAL nHandle
  825.    DEFAULT ljustSave TO .F.
  826.    IF aCargo[CG_N_INIT_SCORE] != aCargo[CG_N_HIGH_SCORE]
  827.       nHandle := FCREATE(C_FILE_NAME)
  828.       IF nHandle != - 1
  829.          FWRITE(nHandle, NTRIM(aCargo[CG_N_HIGH_SCORE]))
  830.          FCLOSE(nHandle)
  831.       ENDIF
  832.    ENDIF
  833. #IFDEF XPPGUI
  834.    // nothing for GUI
  835. #ELSE
  836.    IF .NOT. ljustSave
  837.       RESTSCREEN(0, 0, MAXROW(), MAXCOL(), aEnv[ENV_SCREEN])
  838.       SETCURSOR(aEnv[ENV_CURSOR])
  839.       SETCOLOR(aEnv[ENV_COLOR])
  840.       SETPOS(aEnv[ENV_ROW], 0)
  841.    ENDIF
  842. #ENDIF
  843. RETURN (NIL)
  844.  
  845. STATIC FUNCTION MAKE_VAR(aBlocks, aBoard, aColor, aCargo)
  846. LOCAL cBuffer, nHandle
  847. aBlocks := {{.F.,.T.,.F.,.F.,;            // O
  848.              .F.,.T.,.F.,.F.,;            // O
  849.              .F.,.T.,.F.,.F.,;            // O
  850.              .F.,.T.,.F.,.F.},;           // O
  851.             {.F.,.T.,.T.,;                     // XX
  852.              .F.,.T.,.F.,;                     // X
  853.              .F.,.T.,.F.},;                    // X
  854.             {.T.,.T.,.F.,;                //OO
  855.              .F.,.T.,.F.,;                // O
  856.              .F.,.T.,.F.},;               // O
  857.             {.F.,.T.,.F.,;                     // X
  858.              .T.,.T.,.T.,;                     //XXX
  859.              .F.,.F.,.F.},;                    //
  860.             {.T.,.T.,.F.,;                //OO
  861.              .F.,.T.,.T.,;                // OO
  862.              .F.,.F.,.F.},;               //
  863.             {.F.,.T.,.T.,;                     // XX
  864.              .T.,.T.,.F.,;                     //XX
  865.              .F.,.F.,.F.},;                    //
  866.             {.T.,.T.,;                    //OO
  867.              .T.,.T.},;                   //OO
  868.             {.F.,.T.,.T.,;                     // XX
  869.              .F.,.T.,.F.,;                     // X
  870.              .F.,.T.,.T.},;                    // XX
  871.             {.F.,.T.,.T.,;                // OO
  872.              .F.,.T.,.F.,;                // O
  873.              .T.,.T.,.F.},;               //OO
  874.             {.F.,.T.,.T.,;                     // XX
  875.              .F.,.T.,.T.,;                     // XX
  876.              .F.,.T.,.F.},;                    // X
  877.             {.F.,.T.,.F.,;                // O
  878.              .F.,.T.,.F.,;                // O
  879.              .F.,.T.,.F.},;               // O
  880.             {.T.,.T.,.F.,;                     //XX
  881.              .F.,.T.,.T.,;                     // XX
  882.              .F.,.F.,.T.},;                    //  X
  883.             {.F.,.T.,.F.,;                // O
  884.              .F.,.T.,.F.,;                // O
  885.              .T.,.T.,.T.},;               //OOO
  886.             {.F.,.T.,.F.,;                     // X
  887.              .T.,.T.,.F.,;                     //XX
  888.              .F.,.T.,.T.}}                     // XX
  889.  
  890. aColor := {"W+", "G+", "GR+", "R+", "BG+", "B+", "RB+", "RB", "B", "BG",;
  891.            "R" , "GR", "G", "B"}
  892. aBoard := ARRAY(BD_HEIGHT + 1, BD_WIDTH + 3)
  893. aCargo := ARRAY(LEN_A_CARGO)
  894. aCargo[CG_N_GAME]     := N_GAME_OVER
  895. aCargo[CG_N_RANDOM]   := INT(SECONDS() * 1000)
  896. aCargo[CG_N_CUR_WAIT] := N_INIT_WAIT
  897.  
  898. Init_Score(aCargo)
  899.  
  900. aCargo[CG_N_INIT_SCORE] := aCargo[CG_N_HIGH_SCORE] := 0
  901. IF FILE(C_FILE_NAME)
  902.    nHandle := FOPEN(C_FILE_NAME)
  903.    IF nHandle != - 1
  904.       cBuffer := SPACE(N_LEN_SCORE)
  905.       FREAD(nHandle, @cBuffer, N_LEN_SCORE)
  906.       FCLOSE(nHandle)
  907.       aCargo[CG_N_HIGH_SCORE] := VAL(cBuffer)
  908.    ENDIF
  909. ENDIF
  910. RETURN (NIL)
  911.  
  912. STATIC FUNCTION DISP_SCORE(aBlocks, aColor, aCargo, oBrowse,aText)
  913. STATIC nLast := 0
  914.  
  915. #IFDEF XPPGUI
  916.    LOCAL i,Imax
  917.    LOCAL cText
  918.    LOCAL bBlock
  919.  
  920.    iMax := LEN(aText)
  921.    FOR i := 1 TO iMax
  922.       bBlock := A_STATE[i][4]
  923.       cText  := EVAL( bBlock,aCargo )
  924.       aText[i]:setCaption(cText)
  925.    NEXT
  926. #ELSE
  927.    AEVAL(A_STATE, {|x| SETCOLOR(x[3]+C_BOARD_CLR), ;
  928.                        SETPOS(N_ROW_TEXT + x[1], N_COL_SCORE), ;
  929.                        QQOUT(EVAL(x[4],aCargo))})
  930. #ENDIF
  931.  
  932. #IFDEF XPPGUI
  933.    /*
  934.       while Preview will update too much
  935.       i move it to PLACE_BLOCK()
  936.    */
  937. #ELSE
  938.    IF aCargo[CG_N_LEVEL] >= N_LEVEL_ADD_BLOCKS
  939.       REST_ENV(  , aCargo, .T.)
  940.       Draw_Next_Block(aBlocks, aColor, aCargo, oBrowse)
  941.    ENDIF
  942. #ENDIF
  943.  
  944. RETURN (NIL)
  945.  
  946. STATIC FUNCTION INIT_SCORE(aCargo)
  947.    aCargo[CG_N_SCORE]        := 0
  948.    aCargo[CG_N_COUNT_LINES]  := 0
  949.    aCargo[CG_N_COUNT_BLOCKS] := 0
  950.    aCargo[CG_N_LEVEL]        := N_MIN_LEVEL
  951. RETURN (NIL)
  952.  
  953. STATIC FUNCTION RANDOM_BLOCK(aCargo, nMax)
  954. #define IM      7875
  955. #define IA      421
  956. #define IC      1663
  957. LOCAL nVal := 1
  958.  
  959. #IFDEF XPPGUI
  960.    IF aCargo[CG_N_LEVEL] >= N_LEVEL_ADD_BLOCKS
  961.       aCargo[CG_N_RANDOM]   := INT(RAND(CG_N_RANDOM))
  962.       nVal := INT(RAND(CG_N_RANDOM))
  963.       IF( nVal < 1   , nVal := 1   , NIL)
  964.       IF( nVal > INT(CG_N_RANDOM), nVal := INT(CG_N_RANDOM), NIL)
  965.    ELSE
  966.       aCargo[CG_N_RANDOM]   := INT(RAND(CG_N_RANDOM/2))
  967.       nVal := INT(RAND(CG_N_RANDOM/2))
  968.       IF( nVal < 1   , nVal := 1   , NIL)
  969.       IF( nVal > INT(CG_N_RANDOM/2), nVal := INT(CG_N_RANDOM/2), NIL)
  970.    ENDIF
  971. #ELSE
  972.    aCargo[CG_N_RANDOM]   := (aCargo[CG_N_RANDOM] * IA + IC) % IM
  973.    nVal := (INT((aCargo[CG_N_RANDOM] / IM) * nMax) + 1)
  974.    IF( nVal < 1   , nVal := 1   , NIL)
  975.    IF( nVal > INT(CG_N_RANDOM), nVal := INT(CG_N_RANDOM), NIL)
  976. #ENDIF
  977. RETURN nVal
  978.  
  979. STATIC FUNCTION TIC_TAC(nXms, nTop)
  980. LOCAL nTic, nTac, nElapsed
  981.    nTac     := INT((nXms / 55) + IF(nXms % 55 > 0, 1, 0))
  982.    nElapsed := INT((SECONDS() - nTop) * 1000)
  983.    nTic     := INT((IF(nElapsed < 0, nElapsed += 86400000, nElapsed) / 55) + ;
  984.                     IF(nElapsed % 55 > 0, 1, 0))
  985. RETURN(IF(nTic >= nTac, .T., .F.))
  986.  
  987. STATIC FUNCTION INIT_GAME(aBlocks, aBoard, aCurBlock, aCargo,oPView)
  988. LOCAL i, j
  989. #IFDEF XPPGUI
  990.    FOR i = 1 TO 18
  991.        AFILL(aPlayground[i],"0")
  992.    NEXT
  993. #ELSE
  994.    @ WIN_UP + 1, WIN_LEFT + 1 CLEAR TO WIN_UP + BD_HEIGHT, WIN_LEFT + BD_WIDTH
  995. #ENDIF
  996.  
  997.    FOR i := 1 TO BD_HEIGHT
  998.       FOR j := 2 TO BD_WIDTH + 1
  999.          aBoard[i,j] := N_EMPTY
  1000.       NEXT
  1001.       aBoard[i,1] := aBoard[i,BD_WIDTH+2] := aBoard[i,BD_WIDTH+3] := N_BORDURE
  1002.    NEXT
  1003.    AFILL(aBoard[i], N_BORDURE)
  1004.  
  1005.    aCargo[CG_N_GAME]       := N_PLAYED
  1006.    aCargo[CG_N_CUR_WAIT]   := N_INIT_WAIT
  1007.    aCargo[CG_N_MAX_BLOCKS] := N_INIT_MAX_BLOCKS
  1008.    aCargo[CG_N_NEXT_BLOCK] := Random_Block(aCargo, aCargo[CG_N_MAX_BLOCKS])
  1009.  
  1010.    Init_Score(aCargo)
  1011. #IFDEF XPPGUI
  1012.    Clear_Next_Block(oPView)
  1013. #ELSE
  1014.    Clear_Next_Block()
  1015. #ENDIF
  1016.    New_Block(aBlocks, aBoard, @aCurBlock, aCargo)
  1017.    aCargo[CG_N_INIT_TIK] := SECONDS()
  1018. RETURN (NIL)
  1019.  
  1020. STATIC FUNCTION CLEAR_NEXT_BLOCK(oPView)
  1021. #IFDEF XPPGUI
  1022.   aPView  := LeerPView()
  1023.   oPView:refreshAll()
  1024. #ELSE
  1025. @ N_NEXT_BLOCK_ROW, N_COL_SCORE CLEAR TO ;
  1026.   N_NEXT_BLOCK_ROW + 3, N_COL_SCORE + 7
  1027. #ENDIF
  1028. RETURN (NIL)
  1029.  
  1030. STATIC FUNCTION NEW_BLOCK(aBlocks, aBoard, aCurBlock, aCargo)
  1031. LOCAL i
  1032. aCargo[CG_N_CUR_BLOCK]  := aCargo[CG_N_NEXT_BLOCK]
  1033. aCargo[CG_N_NEXT_BLOCK] := Random_Block(aCargo, aCargo[CG_N_MAX_BLOCKS])
  1034.  
  1035. IF ++aCargo[CG_N_COUNT_BLOCKS] % N_BLOCKS_PER_LEVEL == 0 .AND.;
  1036.      aCargo[CG_N_CUR_WAIT] > 0
  1037.  
  1038.   IF ++aCargo[CG_N_LEVEL]    == N_LEVEL_ADD_BLOCKS
  1039.      aCargo[CG_N_CUR_WAIT]   := N_INIT_WAIT - N_TIME_PER_LEVEL
  1040.      aCargo[CG_N_MAX_BLOCKS] := LEN(aBlocks[aCargo[CG_N_CUR_BLOCK]])
  1041.   ELSE
  1042.      aCargo[CG_N_CUR_WAIT]   -= N_TIME_PER_LEVEL
  1043.   ENDIF
  1044. ENDIF
  1045.  
  1046. aCargo[CG_N_SCORE]         += aCargo[CG_N_LEVEL] * N_PT_PER_BLOCK
  1047. IF aCargo[CG_N_SCORE]       > aCargo[CG_N_HIGH_SCORE]
  1048.    aCargo[CG_N_HIGH_SCORE] := aCargo[CG_N_SCORE]
  1049. ENDIF
  1050.  
  1051. aCargo[CG_N_BLOCK_SIZE] := LEN(aBlocks[aCargo[CG_N_CUR_BLOCK]]) ^ 0.5
  1052. aCargo[CG_N_BLOCK_ROW]  := 0
  1053. aCargo[CG_N_BLOCK_COL]  := BD_WIDTH / 2
  1054. aCurBlock := ACLONE(aBlocks[aCargo[CG_N_CUR_BLOCK]])
  1055.  
  1056. IF Hit_Block(aBoard, aCurBlock, aCargo)
  1057.   ACOPY(aCurBlock, aCurBlock, aCargo[CG_N_BLOCK_SIZE] + 1)
  1058.   AFILL(aCurBlock, .F., LEN(aCurBlock) - aCargo[CG_N_BLOCK_SIZE] + 1)
  1059.   DO WHILE Hit_Block(aBoard, aCurBlock, aCargo)
  1060.      ACOPY(aCurBlock, aCurBlock, aCargo[CG_N_BLOCK_SIZE] + 1)
  1061.   ENDDO
  1062.   aCargo[CG_N_GAME] := N_GAME_OVER
  1063. ENDIF
  1064. RETURN (NIL)
  1065.  
  1066. STATIC FUNCTION DRAW_BLOCK(aCurBlock, aColor, aCargo, lDraw, oBrowse)
  1067. LOCAL i, j
  1068. #IFDEF XPPGUI
  1069.    LOCAL nRow, nCol
  1070.    LOCAL nNo := 0
  1071.  
  1072.    FOR i := 0 TO aCargo[CG_N_BLOCK_SIZE] - 1
  1073.      FOR j := 0 TO aCargo[CG_N_BLOCK_SIZE] - 1
  1074.        IF aCurBlock[i*aCargo[CG_N_BLOCK_SIZE]+j+1]
  1075.          nRow := aCargo[CG_N_BLOCK_ROW] + i + 1
  1076.          nCol := aCargo[CG_N_BLOCK_COL] + j*2 -1
  1077.          nNo  := aCargo[CG_N_CUR_BLOCK]
  1078.          IF ISINFIELD(nRow,nCol)
  1079.             aPlayground[nRow][nCol]   := IF(lDraw, NTRIM(nNo), "0")
  1080.             aPlayground[nRow][nCol+1] := IF(lDraw, NTRIM(nNo), "0")
  1081.          ENDIF
  1082.        ENDIF
  1083.      NEXT
  1084.    NEXT
  1085.    oBrowse:refreshAll()
  1086. #ELSE
  1087.    SETCOLOR(IF(lDraw, aColor[aCargo[CG_N_CUR_BLOCK]], C_BOARD_CLR + "/" + C_BOARD_CLR))
  1088.    FOR i := 0 TO aCargo[CG_N_BLOCK_SIZE] - 1
  1089.       FOR j := 0 TO aCargo[CG_N_BLOCK_SIZE] - 1
  1090.          IF aCurBlock[i*aCargo[CG_N_BLOCK_SIZE]+j+1]
  1091.             @ aCargo[CG_N_BLOCK_ROW] + WIN_UP + i + 1, ;
  1092.               aCargo[CG_N_BLOCK_COL] + WIN_LEFT + j*2 - 1 SAY C_ELEMENT
  1093.          ENDIF
  1094.       NEXT
  1095.    NEXT
  1096. #ENDIF
  1097. RETURN (NIL)
  1098.  
  1099. STATIC FUNCTION DRAW_BCKGND(aBoard, aColor,oBrowse)
  1100. LOCAL i, j
  1101. #IFDEF XPPGUI
  1102.    LOCAL nRow, nCol
  1103.    LOCAL nNo := 0
  1104.  
  1105.    FOR i := 1 TO BD_HEIGHT
  1106.       FOR j := 2 TO BD_WIDTH STEP 2
  1107.          IF aBoard[i,j] != N_EMPTY
  1108.             nNo := aBoard[i,j]
  1109.          ELSE
  1110.             nNo := 0
  1111.          ENDIF
  1112.          nRow := i
  1113.          nCol := j - 1
  1114.          IF ISINFIELD(nRow,nCol)
  1115.             aPlayground[nRow][nCol]   := NTRIM(nNo)
  1116.             aPlayground[nRow][nCol+1] := NTRIM(nNo)
  1117.          ENDIF
  1118.       NEXT
  1119.    NEXT
  1120.    oBrowse:refreshAll()
  1121. #ELSE
  1122.    FOR i := 1 TO BD_HEIGHT
  1123.      FOR j := 2 TO BD_WIDTH STEP 2
  1124.        SETCOLOR(IF (aBoard[i,j] != N_EMPTY, aColor[aBoard[i,j]], C_BOARD_CLR + "/" +C_BOARD_CLR))
  1125.        @ WIN_UP + i, WIN_LEFT + j - 1 SAY C_ELEMENT
  1126.      NEXT
  1127.    NEXT
  1128. #ENDIF
  1129. RETURN(NIL)
  1130.  
  1131. STATIC FUNCTION DRAW_NEXT_BLOCK(aBlocks, aColor, aCargo,oBrowse,oPView)
  1132. LOCAL i, j, nSize
  1133. #IFDEF XPPGUI
  1134.    LOCAL nRow, nCol
  1135.    LOCAL nNo := aCargo[CG_N_NEXT_BLOCK]
  1136.  
  1137.    nSize := LEN(aBlocks[aCargo[CG_N_NEXT_BLOCK]] ) ^ 0.5
  1138.    oPView:show()
  1139.    Clear_Next_Block(oPView)
  1140.    FOR i := 0 TO nSize - 1
  1141.      FOR j := 0 TO nSize - 1
  1142.        IF aBlocks[aCargo[CG_N_NEXT_BLOCK],i*nSize+j+1]
  1143.          nRow := i   + 1                  // N_NEXT_BLOCK_ROW
  1144.          nCol := j*2 + 1                  // N_COL_SCORE
  1145.          aPView[nRow][nCol]   := NTRIM(nNo)
  1146.          aPView[nRow][nCol+1] := NTRIM(nNo)
  1147.        ENDIF
  1148.      NEXT
  1149.    NEXT
  1150.    oPView:refreshAll()
  1151. #ELSE
  1152.    SETCOLOR(aColor[aCargo[CG_N_NEXT_BLOCK]])
  1153.    nSize := LEN(aBlocks[aCargo[CG_N_NEXT_BLOCK]] ) ^ 0.5
  1154.    Clear_Next_Block()
  1155.    FOR i := 0 TO nSize - 1
  1156.      FOR j := 0 TO nSize - 1
  1157.        IF aBlocks[aCargo[CG_N_NEXT_BLOCK],i*nSize+j+1]
  1158.          @ N_NEXT_BLOCK_ROW + i, N_COL_SCORE + j*2 SAY C_ELEMENT
  1159.        ENDIF
  1160.      NEXT
  1161.    NEXT
  1162. #ENDIF
  1163. RETURN (NIL)
  1164.  
  1165. STATIC FUNCTION ROTATE_BLOCK(aCurBlock, aCargo, nSens)
  1166. LOCAL i, j, aTmpBlock
  1167. DO CASE
  1168.    CASE aCargo[CG_N_BLOCK_SIZE] == 4
  1169.       aTmpBlock := ARRAY(LEN(aCurBlock))
  1170.       IF nSens == K_LEFT
  1171.         FOR i := 0 TO 3
  1172.           FOR j := 0 TO 3
  1173.             aTmpBlock[i*4+j+1] := aCurBlock[j*4+i+1]
  1174.           NEXT
  1175.         NEXT
  1176.       ELSE
  1177.         FOR i := 0 TO 3
  1178.           FOR j := 0 TO 3
  1179.             aTmpBlock[j*4+i+1] := aCurBlock[i*4+j+1]
  1180.           NEXT
  1181.         NEXT
  1182.       ENDIF
  1183.       aCurBlock := aTmpBlock
  1184.  
  1185.    CASE aCargo[CG_N_BLOCK_SIZE] == 3
  1186.       aTmpBlock := ARRAY(LEN(aCurBlock))
  1187.       IF nSens == K_LEFT
  1188.         FOR i := 0 TO 2
  1189.           FOR j := 0 TO 2
  1190.             aTmpBlock[(2-j)*3+i+1] := aCurBlock[i*3+j+1]
  1191.           NEXT
  1192.         NEXT
  1193.       ELSE
  1194.         FOR i := 0 TO 2
  1195.           FOR j := 0 TO 2
  1196.             aTmpBlock[i*3+j+1] := aCurBlock[(2-j)*3+i+1]
  1197.           NEXT
  1198.         NEXT
  1199.       ENDIF
  1200.       aCurBlock := aTmpBlock
  1201. ENDCASE
  1202. RETURN (NIL)
  1203.  
  1204. STATIC FUNCTION HIT_BLOCK(aBoard, aCurBlock, aCargo)
  1205. LOCAL i,j
  1206. FOR i := 0 TO aCargo[CG_N_BLOCK_SIZE] - 1
  1207.    FOR j := 0 TO aCargo[CG_N_BLOCK_SIZE] - 1
  1208.       IF aCurBlock[i*aCargo[CG_N_BLOCK_SIZE]+j+1] .AND.;
  1209.          aBoard[aCargo[CG_N_BLOCK_ROW]+i+1,aCargo[CG_N_BLOCK_COL]+j*2+1] != N_EMPTY
  1210.          RETURN(.T.)
  1211.       ENDIF
  1212.    NEXT
  1213. NEXT
  1214. RETURN (.F.)
  1215.  
  1216. STATIC FUNCTION PLACE_BLOCK(aBlocks, aBoard, aCurBlock, aColor, aCargo,oBrowse,oPView)
  1217. LOCAL i,j, nLines
  1218. FOR i := 0 TO aCargo[CG_N_BLOCK_SIZE] -1
  1219.    FOR j := 0 TO aCargo[CG_N_BLOCK_SIZE] -1
  1220.       IF aCurBlock[i*aCargo[CG_N_BLOCK_SIZE]+j+1]
  1221.          aBoard[aCargo[CG_N_BLOCK_ROW]+i+1,aCargo[CG_N_BLOCK_COL]+j*2]   := ;
  1222.          aBoard[aCargo[CG_N_BLOCK_ROW]+i+1,aCargo[CG_N_BLOCK_COL]+j*2+1] := ;
  1223.          aCargo[CG_N_CUR_BLOCK]
  1224.       ENDIF
  1225.    NEXT
  1226. NEXT
  1227. IF Remove_Lines(aBoard, @nLines)
  1228.    TONE(1100,1)
  1229.    TONE(1500,1)
  1230.    Draw_BckGnd(aBoard, aColor,oBrowse)
  1231.    aCargo[CG_N_SCORE] += (aCargo[CG_N_LEVEL] * N_PT_PER_LINE) * nLines
  1232.    aCargo[CG_N_COUNT_LINES] += nLines
  1233. ELSE
  1234.    Draw_Block(aCurBlock, aColor, aCargo, .T.,oBrowse)
  1235. ENDIF
  1236. New_Block(aBlocks, aBoard, @aCurBlock, aCargo,oBrowse)
  1237.  
  1238. #IFDEF XPPGUI                             // moved from DISP_SCORE()
  1239.    IF aCargo[CG_N_LEVEL] >= N_LEVEL_ADD_BLOCKS
  1240.       REST_ENV(  , aCargo, .T.)
  1241.       Draw_Next_Block(aBlocks, aColor, aCargo, oBrowse,oPView)
  1242.    ENDIF
  1243. #ENDIF
  1244. RETURN (NIL)
  1245.  
  1246. STATIC FUNCTION REMOVE_LINES(aBoard, nLines)
  1247. LOCAL i,j,k,l, bRemove
  1248.  
  1249. bRemove := .F.
  1250. i       := BD_HEIGHT
  1251. nLines  := 0
  1252. DO WHILE i >= 1
  1253.    FOR j := 2 TO BD_WIDTH + 1
  1254.       IF aBoard[i,j] == N_EMPTY
  1255.          EXIT
  1256.       ENDIF
  1257.    NEXT
  1258.    IF j > BD_WIDTH + 1
  1259.       FOR k := i TO 2 STEP - 1
  1260.          FOR l := 2 TO BD_WIDTH + 1
  1261.            aBoard[k,l] := aBoard[k-1,l]
  1262.          NEXT
  1263.          FOR l := 2 TO BD_WIDTH + 1
  1264.            aBoard[1,l] := N_EMPTY
  1265.          NEXT
  1266.       NEXT
  1267.       bRemove := .T.
  1268.       nLines++
  1269.    ELSE
  1270.       i--
  1271.    ENDIF
  1272. ENDDO
  1273. RETURN(bRemove)
  1274.  
  1275. *
  1276. * EOF
  1277. *