Author Topic: Qbasic Tetris clone takes many minutes to be compiled!  (Read 2859 times)

0 Members and 1 Guest are viewing this topic.

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Qbasic Tetris clone takes many minutes to be compiled!
« on: January 30, 2021, 09:28:21 am »
Hi
I find by googleing this file that is part of a more advanced version of QB that coming before QB PDS
its name is Qblock.bas

It is fine so I post it there as example about game programming.
Code: QB64: [Select]
  1. '                                QBLOCKS.BAS
  2.  
  3.  
  4. '
  5.  
  6.  
  7. ' Press Page Down for information on running and modifying QBlocks.
  8.  
  9.  
  10. '
  11.  
  12.  
  13. ' To run this game, press Shift+F5.
  14.  
  15.  
  16. '
  17.  
  18.  
  19. ' To exit this program, press ALT, F, X.
  20.  
  21.  
  22. '
  23.  
  24.  
  25. ' To get help on a BASIC keyword, move the cursor to the keyword and press
  26.  
  27.  
  28. ' F1 or click the right mouse button.
  29.  
  30.  
  31. '
  32.  
  33.  
  34. '                             Suggested Changes
  35.  
  36.  
  37. '                             -----------------
  38.  
  39.  
  40. '
  41.  
  42.  
  43. ' There are many ways that you can modify this BASIC game.  The CONST
  44.  
  45.  
  46. ' statements below these comments and the DATA statements at the end
  47.  
  48.  
  49. ' of this screen can be modified to change the following:
  50.  
  51.  
  52. '
  53.  
  54.  
  55. '    Block shapes
  56.  
  57.  
  58. '    Block rotation
  59.  
  60.  
  61. '    Number of different block shapes
  62.  
  63.  
  64. '    Score needed to advance to next level
  65.  
  66.  
  67. '    Width of the game well
  68.  
  69.  
  70. '    Height of the game well
  71.  
  72.  
  73. '    Songs played during game
  74.  
  75.  
  76. '
  77.  
  78.  
  79. ' On the right side of each CONST statement, there is a comment that tells
  80.  
  81.  
  82. ' you what it does and how big or small you can set the value.  Above the
  83.  
  84.  
  85. ' DATA statements, there are comments that tell you the format of the
  86.  
  87.  
  88. ' information stored there.
  89.  
  90.  
  91. '
  92.  
  93.  
  94. ' On your own, you can also add exciting sound and visual effects or make any
  95.  
  96.  
  97. ' other changes that your imagination can dream up.  By reading the
  98.  
  99.  
  100. ' Learn BASIC Now book, you'll learn the techniques that will enable you
  101.  
  102.  
  103. ' to fully customize this game and to create games of your own.
  104.  
  105.  
  106. '
  107.  
  108.  
  109. ' If the game won't run after you have changed it, you can exit without
  110.  
  111.  
  112. ' saving your changes by pressing Alt, F, X and choosing NO.
  113.  
  114.  
  115. '
  116.  
  117.  
  118. ' If you do want to save your changes, press Alt, F, A and enter a filename
  119.  
  120.  
  121. ' for saving your version of the program.  Before you save your changes,
  122.  
  123.  
  124. ' however, you should make sure they work by running the program and
  125.  
  126.  
  127. ' verifying that your changes produce the desired results.  Also, always
  128.  
  129.  
  130. ' be sure to keep a backup of the original program.
  131.  
  132.  
  133. '
  134.  
  135.  
  136. DEFINT A-Z
  137.  
  138.  
  139.  
  140.  
  141.  
  142. ' Here are the BASIC CONST statements you can change.  The comments tell
  143.  
  144.  
  145. ' you the range that each CONST value can be changed, or any limitations.
  146.  
  147.  
  148. CONST WELLWIDTH = 10 ' Width of playing field (well).   Range 5 to 13.
  149.  
  150.  
  151. CONST WELLHEIGHT = 21 ' Height of playing field.  Range 4 to 21.
  152.  
  153.  
  154. CONST NUMSTYLES = 7 ' Number of unique shapes.  Range 1 to 20.  Make sure you read the notes above the DATA statements at the end of the main program before you change this number!
  155.  
  156.  
  157. CONST WINGAME = 1000000 ' Points required to win the game.  Range 200 to 9000000.
  158.  
  159.  
  160. CONST NEXTLEVEL = 300 ' Helps determine when the game advances to the next level.  (Each cleared level gives player 100 points) Range 100 to 2000.
  161.  
  162.  
  163. CONST BASESCORE = 1000 ' Number of points needed to advance to first level.
  164.  
  165.  
  166. CONST ROTATEDIR = 1 ' Control rotation of blocks. Can be 1 for clockwise, or 3 for counterclockwise.
  167.  
  168.  
  169. ' The following sound constants are used by the PLAY command to
  170.  
  171.  
  172. ' produce music during the game.  To change the sounds you hear, change
  173.  
  174.  
  175. ' these constants.  Refer to the online help for PLAY for the correct format.
  176.  
  177.  
  178. ' To completely remove sound from the game set the constants equal to null.
  179.  
  180.  
  181. ' For example:  PLAYINTRO = ""
  182.  
  183.  
  184. CONST PLAYCLEARROW = "MBT255L16O4CDEGO6C" ' Tune played when a row is cleared.  Range unlimited.
  185.  
  186.  
  187. CONST PLAYINTRO = "MBT170O1L8CO2CO1CDCA-A-FGFA-F" ' Song played at game start.  Range unlimited.
  188.  
  189.  
  190. CONST PLAYGAMEOVER = "MBT255L16O6CO4GEDC" ' Song when the game is lost.  Range unlimited.
  191.  
  192.  
  193. CONST PLAYNEWBLOCK = "MBT160L28N20L24N5" ' Song when a new block is dropped.  Range unlimited.
  194.  
  195.  
  196. CONST PLAYWINGAME = "T255L16O6CO4GEDCCDEFGO6CEG" ' Song when game is won.  Range unlimited.
  197.  
  198.  
  199.  
  200.  
  201.  
  202. ' The following CONST statements should not be changed like the ones above
  203.  
  204.  
  205. ' because the program relies on them being this value.
  206.  
  207.  
  208. CONST FALSE = 0 ' 0 means FALSE.
  209.  
  210.  
  211. CONST TRUE = NOT FALSE ' Anything but 0 can be thought of as TRUE.
  212.  
  213.  
  214. CONST SPACEBAR = 32 ' ASCII value for space character. Drops the shape.
  215.  
  216.  
  217. CONST DOWNARROW = 80 ' Down arrow key.  Drops the shape.
  218.  
  219.  
  220. CONST RIGHTARROW = 77 ' Right arrow key.  Moves the shape right.
  221.  
  222.  
  223. CONST UPARROW = 72 ' Up arrow key.  Rotates the shape.
  224.  
  225.  
  226. CONST LEFTARROW = 75 ' Left arrow key.  Moves the shape left.
  227.  
  228.  
  229. CONST DOWNARROW2 = 50 ' 2 key.  Drops the shape.
  230.  
  231.  
  232. CONST RIGHTARROW2 = 54 ' 6 key.  Moves the shape right.
  233.  
  234.  
  235. CONST UPARROW2 = 56 ' 8 key.  Rotates the shape.
  236.  
  237.  
  238. CONST LEFTARROW2 = 52 ' 4 key.  Moves the shape left.
  239.  
  240.  
  241. CONST UPARROW3 = 53 ' 5 key.  Rotates the shape.
  242.  
  243.  
  244. CONST QUIT = "Q" ' Q key.  Quits the game.
  245.  
  246.  
  247. CONST PAUSE = "P" ' P key.  Pauses the game.
  248.  
  249.  
  250. CONST XMATRIX = 3 ' Width of the matrix that forms each falling unit.  See the discussions in Suggested Changes #2 and #3.
  251.  
  252.  
  253. CONST YMATRIX = 1 ' Depth of the matrix that forms each falling unit.
  254.  
  255.  
  256. CONST BYTESPERBLOCK = 76 ' Number of bytes required to store one block in Screen mode 7.
  257.  
  258.  
  259. CONST BLOCKVOLUME = (XMATRIX + 1) * (YMATRIX + 1) ' Number of blocks in each shape.
  260.  
  261.  
  262. CONST ELEMENTSPERBLOCK = BLOCKVOLUME * BYTESPERBLOCK \ 2 ' Number of INTEGER array elements needed to store an image of a shape.
  263.  
  264.  
  265. CONST XSIZE = 13 ' Width, in pixels, of each block.  QBlocks assumes that the entire screen is 25 blocks wide.  Since the screen is 320 pixels wide, each block is approximately 13 pixels wide.
  266.  
  267.  
  268. CONST YSIZE = 8 ' Height, in pixels, of each block.  Again, QBlocks assumes that screen is 25 blocks high.  At 200 pixels down, each block is exactly 8 pixels high.
  269.  
  270.  
  271. CONST XOFFSET = 10 ' X position, in blocks, of the well.
  272.  
  273.  
  274. CONST YOFFSET = 2 ' Y position, in blocks, of the well.
  275.  
  276.  
  277. CONST WELLX = XSIZE * XOFFSET ' X position, in pixels, of the start of the well.
  278.  
  279.  
  280. CONST WELLY = YSIZE * YOFFSET ' Y position.
  281.  
  282.  
  283. CONST TILTVALUE = 9999000 ' Points required for QBlocks to tilt.
  284.  
  285.  
  286. CONST WELLCOLOR7 = 0 ' Well color for SCREEN 7.
  287.  
  288.  
  289. CONST WELLCOLOR1 = 0 ' Well color for SCREEN 1.
  290.  
  291.  
  292. CONST BORDERCOLOR1 = 8 ' Border color for SCREEN 1.
  293.  
  294.  
  295. CONST BORDERCOLOR7 = 15 ' Border color for SCREEN 7.
  296.  
  297.  
  298.  
  299.  
  300.  
  301. TYPE BlockType ' Block datatype.
  302.  
  303.  
  304.     X AS INTEGER ' Horizontal location within the well.
  305.  
  306.  
  307.     Y AS INTEGER ' Vertical location within the well.
  308.  
  309.  
  310.     Style AS INTEGER ' Define shape (and color, indirectly).
  311.  
  312.  
  313.     Rotation AS INTEGER ' 4 possible values (0 to 3).
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321. ' SUB and FUNCTION declarations
  322.  
  323.  
  324. DECLARE FUNCTION CheckFit ()
  325.  
  326.  
  327. DECLARE FUNCTION GameOver ()
  328.  
  329.  
  330. DECLARE SUB AddBlockToWell ()
  331.  
  332.  
  333. DECLARE SUB CheckForFullRows ()
  334.  
  335.  
  336. DECLARE SUB Center (M$, Row)
  337.  
  338.  
  339. DECLARE SUB DeleteChunk (Highest%, Lowest%)
  340.  
  341.  
  342. DECLARE SUB DisplayIntro ()
  343.  
  344.  
  345. DECLARE SUB DisplayGameTitle ()
  346.  
  347.  
  348. DECLARE SUB DisplayChanges ()
  349.  
  350.  
  351. DECLARE SUB DrawBlock (X, Y, FillColor)
  352.  
  353.  
  354. DECLARE SUB InitScreen ()
  355.  
  356.  
  357. DECLARE SUB MakeInfoBox ()
  358.  
  359.  
  360. DECLARE SUB NewBlock ()
  361.  
  362.  
  363. DECLARE SUB PerformGame ()
  364.  
  365.  
  366. DECLARE SUB RedrawControls ()
  367.  
  368.  
  369. DECLARE SUB Show (b AS BlockType)
  370.  
  371.  
  372. DECLARE SUB UpdateScoring ()
  373.  
  374.  
  375. DECLARE SUB PutBlock (b AS BlockType)
  376.  
  377.  
  378. DECLARE SUB DrawAllShapes ()
  379.  
  380.  
  381. DECLARE SUB DrawPattern (Patttern)
  382.  
  383.  
  384. DECLARE SUB DrawPlayingField ()
  385.  
  386.  
  387.  
  388.  
  389.  
  390. ' DIM SHARED indicates that a variable is available to all subprograms.
  391.  
  392.  
  393. ' Without this statement, a variable used in one subprogram cannot be
  394.  
  395.  
  396. ' used by another subprogram or the main program.
  397.  
  398.  
  399. DIM SHARED Level AS INTEGER ' Difficulty level.  0 is slowest, 9 is fastest.
  400.  
  401.  
  402. DIM SHARED WellBlocks(WELLWIDTH, WELLHEIGHT) AS INTEGER ' 2 dimensional array to hold the falling shapes that have stopped falling and become part of the well.
  403.  
  404.  
  405. DIM SHARED CurBlock AS BlockType ' The falling shape.
  406.  
  407.  
  408. DIM SHARED BlockShape(0 TO XMATRIX, 0 TO YMATRIX, 1 TO NUMSTYLES) ' Holds the data required to make each shape.  Values determined by the DATA statements at the end of this window.
  409.  
  410.  
  411. DIM SHARED PrevScore AS LONG ' Holds the previous level for scoring purposes.
  412.  
  413.  
  414. DIM SHARED Score AS LONG ' Score.
  415.  
  416.  
  417. DIM SHARED ScreenWidth AS INTEGER ' Width of the screen, in character-sized units.
  418.  
  419.  
  420. DIM SHARED ScreenMode AS INTEGER ' Value of the graphics screen mode used.
  421.  
  422.  
  423. DIM SHARED WellColor AS INTEGER ' Color inside the well.
  424.  
  425.  
  426. DIM SHARED BorderColor AS INTEGER ' Color of well border and text.
  427.  
  428.  
  429. DIM SHARED OldBlock AS BlockType ' An image of the last CurBlock.  Used to erase falling units when they move.
  430.  
  431.  
  432. DIM SHARED TargetTime AS SINGLE ' Time to move the shape down again.
  433.  
  434.  
  435. DIM SHARED GameTiltScore AS LONG ' Holds the value that this game will tilt at.
  436.  
  437.  
  438. DIM SHARED Temp(11175) AS INTEGER ' Used by several GET and PUT statements to store temporary screen images.
  439.  
  440.  
  441. DIM SHARED BlockColor(1 TO NUMSTYLES) AS INTEGER ' Block color array
  442.  
  443.  
  444. DIM SHARED BlockImage((NUMSTYLES * 4 + 3) * ELEMENTSPERBLOCK) AS INTEGER ' Holds the binary image of each rotation of each shape for the PutBlock subprogram to use.
  445.  
  446.  
  447. DIM KeyFlags AS INTEGER ' Internal state of the keyboard flags when game starts.  Hold the state so it can be restored when the games ends.
  448.  
  449.  
  450. DIM BadMode AS INTEGER ' Store the status of a valid screen mode.
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459. ON ERROR GOTO ScreenError ' Set up a place to jump to if an error occurs in the program.
  460.  
  461.  
  462. BadMode = FALSE
  463.  
  464.  
  465. ScreenMode = 7
  466.  
  467.  
  468. SCREEN ScreenMode ' Attempt to go into SCREEN 7 (EGA screen).
  469.  
  470.  
  471. IF BadMode = TRUE THEN ' If this attempt failed.
  472.  
  473.  
  474.     ScreenMode = 1
  475.  
  476.  
  477.     BadMode = FALSE
  478.  
  479.  
  480.     SCREEN ScreenMode ' Attempt to go into SCREEN 1 (CGA screen).
  481.  
  482.  
  483.  
  484.  
  485. ON ERROR GOTO 0 ' Turn off error handling.
  486.  
  487.  
  488.  
  489.  
  490.  
  491. IF BadMode = TRUE THEN ' If no graphics adapter.
  492.  
  493.  
  494.     CLS
  495.  
  496.  
  497.     LOCATE 10, 12: PRINT "CGA, EGA Color, or VGA graphics required to run QBLOCKS.BAS"
  498.  
  499.  
  500.  
  501.  
  502.     RANDOMIZE TIMER ' Create a new sequence of random numbers based on the clock.
  503.  
  504.  
  505.     DisplayIntro ' Show the opening screen.
  506.  
  507.  
  508.  
  509.  
  510.  
  511.     DEF SEG = 0 ' Set the current segment to the low memory area.
  512.  
  513.  
  514.     KeyFlags = PEEK(1047) ' Read the location that holds the keyboard flag.
  515.  
  516.  
  517.     IF (KeyFlags AND 32) = 0 THEN ' If the NUM LOCK key is off
  518.  
  519.  
  520.         POKE 1047, KeyFlays OR 32 ' set the NUM LOCK key to on.
  521.  
  522.  
  523.     END IF
  524.  
  525.  
  526.     DEF SEG ' Restore the default segment.
  527.  
  528.  
  529.  
  530.  
  531.  
  532.     ' Read the pattern for each QBlocks shape.
  533.  
  534.  
  535.     FOR i = 1 TO NUMSTYLES ' Loop for the each shape
  536.  
  537.  
  538.         FOR j = 0 TO YMATRIX ' and for the Y and X dimensions of
  539.  
  540.  
  541.             FOR k = 0 TO XMATRIX ' each shape.
  542.  
  543.  
  544.                 READ BlockShape(k, j, i) ' Actually read the data.
  545.  
  546.  
  547.             NEXT k
  548.  
  549.  
  550.         NEXT j
  551.  
  552.  
  553.     NEXT i
  554.  
  555.  
  556.     DrawAllShapes ' Draw all shapes in all four rotations.
  557.  
  558.  
  559.     PerformGame ' Play the game until the player quits.
  560.  
  561.  
  562.     DisplayChanges ' Show the suggested changes.
  563.  
  564.  
  565.  
  566.  
  567.  
  568.     DEF SEG = 0 ' Set the current segment back to low memory where the keyboard flags are.
  569.  
  570.  
  571.     POKE 1047, KeyFlags AND 233 ' Set the NUM LOCK key back to where it was at the game start.
  572.  
  573.  
  574.     DEF SEG ' Restore the current segment back to BASIC's data group area.
  575.  
  576.  
  577.  
  578.  
  579.  
  580.     IF ScreenMode = 7 THEN PALETTE ' Restore the default color palette if SCREEN 7 was used.
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591. END ' End of the main program code.
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600. ' The DATA statements below define the block shapes used in the game.
  601.  
  602.  
  603. ' Each shape contains 8 blocks (4 x 2).  A "1" means that there
  604.  
  605.  
  606. ' is a block in that space; "0" means that the block is blank.  The pattern
  607.  
  608.  
  609. ' for Style 1, for example, creates a shape that is 4 blocks wide.
  610.  
  611.  
  612. ' To change an existing block's shape, change a "0" to a "1" or a "1" to
  613.  
  614.  
  615. ' a "0".  To add new shapes, insert new DATA statements with the same format
  616.  
  617.  
  618. ' as those below, after the last group of DATA statements (style 7).  Be sure
  619.  
  620.  
  621. ' to change the NUMSTYLES constant at the beginning of this program to reflect
  622.  
  623.  
  624. ' the new number of block shapes for the game.
  625.  
  626.  
  627. ' IMPORTANT! Creating a completely blank block will cause QBlocks to fail.
  628.  
  629.  
  630.  
  631.  
  632.  
  633. ' Data for Style 1: Long
  634.  
  635.  
  636. DATA 1,1,1,1
  637.  
  638.  
  639. DATA 0,0,0,0
  640.  
  641.  
  642.  
  643.  
  644.  
  645. ' Data for Style 2: L Right
  646.  
  647.  
  648. DATA 1,1,1,0
  649.  
  650.  
  651. DATA 0,0,1,0
  652.  
  653.  
  654.  
  655.  
  656.  
  657. ' Data for Style 3: L Left
  658.  
  659.  
  660. DATA 0,1,1,1
  661.  
  662.  
  663. DATA 0,1,0,0
  664.  
  665.  
  666.  
  667.  
  668.  
  669. ' Data for Style 4: Z Right
  670.  
  671.  
  672. DATA 1,1,0,0
  673.  
  674.  
  675. DATA 0,1,1,0
  676.  
  677.  
  678.  
  679.  
  680.  
  681. ' Data for Style 5: Z Left
  682.  
  683.  
  684. DATA 0,1,1,0
  685.  
  686.  
  687. DATA 1,1,0,0
  688.  
  689.  
  690.  
  691.  
  692.  
  693. ' Data for Style 6: T
  694.  
  695.  
  696. DATA 1,1,1,0
  697.  
  698.  
  699. DATA 0,1,0,0
  700.  
  701.  
  702.  
  703.  
  704.  
  705. ' Data for Style 7: Square
  706.  
  707.  
  708. DATA 0,1,1,0
  709.  
  710.  
  711. DATA 0,1,1,0
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.  
  719.  
  720. ScreenError: ' QBlocks uses this error handler to determine the highest available video mode.
  721.  
  722.  
  723. BadMode = TRUE
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731. '----------------------------------------------------------------------------
  732.  
  733.  
  734. ' AddBlockToWell
  735.  
  736.  
  737. '
  738.  
  739.  
  740. '    After a shape stops falling, put it into the WellBlocks array
  741.  
  742.  
  743. '    so later falling shapes know where to stop.
  744.  
  745.  
  746. '
  747.  
  748.  
  749. '           PARAMETERS:    None.
  750.  
  751.  
  752. '----------------------------------------------------------------------------
  753.  
  754.  
  755. SUB AddBlockToWell
  756.  
  757.  
  758.  
  759.  
  760.  
  761.     FOR i = 0 TO XMATRIX ' Loop through all elements in the array.
  762.  
  763.  
  764.         FOR j = 0 TO YMATRIX
  765.  
  766.  
  767.             IF BlockShape(i, j, CurBlock.Style) = 1 THEN ' If there is a block in that space.
  768.  
  769.  
  770.                 SELECT CASE CurBlock.Rotation ' Use the Rotation to determine how the blocks should map into the WellBlocks array.
  771.  
  772.  
  773.                     CASE 0 ' No rotation.
  774.  
  775.  
  776.                         WellBlocks(CurBlock.X + i, CurBlock.Y + j) = CurBlock.Style
  777.  
  778.  
  779.                     CASE 1 ' Rotated 90 degrees clockwise.
  780.  
  781.  
  782.                         WellBlocks(CurBlock.X - j + 2, CurBlock.Y + i - 1) = CurBlock.Style
  783.  
  784.  
  785.                     CASE 2 ' Rotated 180 degrees.
  786.  
  787.  
  788.                         WellBlocks(CurBlock.X - i + 3, CurBlock.Y - j + 1) = CurBlock.Style
  789.  
  790.  
  791.                     CASE 3 ' Rotated 270 degrees clockwise.
  792.  
  793.  
  794.                         WellBlocks(CurBlock.X + j + 1, CurBlock.Y - i + 2) = CurBlock.Style
  795.  
  796.  
  797.                 END SELECT
  798.  
  799.  
  800.             END IF
  801.  
  802.  
  803.         NEXT j
  804.  
  805.  
  806.     NEXT i
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814. '----------------------------------------------------------------------------
  815.  
  816.  
  817. ' Center
  818.  
  819.  
  820. '
  821.  
  822.  
  823. '    Centers a string of text on a specified row.
  824.  
  825.  
  826. '
  827.  
  828.  
  829. '           PARAMETERS:    Text$ - Text to display on the screen.
  830.  
  831.  
  832. '                          Row   - Row on the screen where the text$ is
  833.  
  834.  
  835. '                                  displayed.
  836.  
  837.  
  838. '----------------------------------------------------------------------------
  839.  
  840.  
  841. SUB Center (text$, Row)
  842.  
  843.  
  844.  
  845.  
  846.  
  847.     LOCATE Row, (ScreenWidth - LEN(text$)) \ 2 + 1
  848.  
  849.  
  850.     PRINT text$;
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861. '----------------------------------------------------------------------------
  862.  
  863.  
  864. ' CheckFit
  865.  
  866.  
  867. '
  868.  
  869.  
  870. '    Checks to see if the shape will fit into its new position.
  871.  
  872.  
  873. '    Returns TRUE if it fits and FALSE if it does not fit.
  874.  
  875.  
  876. '
  877.  
  878.  
  879. '           PARAMETERS:    None
  880.  
  881.  
  882. '
  883.  
  884.  
  885. '----------------------------------------------------------------------------
  886.  
  887.  
  888. FUNCTION CheckFit
  889.  
  890.  
  891.  
  892.  
  893.  
  894.     CheckFit = TRUE ' Assume the shape will fit.
  895.  
  896.  
  897.  
  898.  
  899.  
  900.     FOR i = 0 TO XMATRIX ' Loop through all the blocks in the
  901.  
  902.  
  903.         FOR j = 0 TO YMATRIX ' shape and see if any would
  904.  
  905.  
  906.             ' overlap blocks already in the well.
  907.  
  908.  
  909.             IF BlockShape(i, j, CurBlock.Style) = 1 THEN ' 1 means that space, within the falling shape, is filled with a block.
  910.  
  911.  
  912.                 SELECT CASE CurBlock.Rotation ' Base the check on the rotation of the shape.
  913.  
  914.  
  915.                     CASE 0 ' No rotation.
  916.  
  917.  
  918.                         NewX = CurBlock.X + i
  919.  
  920.  
  921.                         NewY = CurBlock.Y + j
  922.  
  923.  
  924.                     CASE 1 ' Rotated 90 degrees clockwise, or 270 degrees counterclockwise.
  925.  
  926.  
  927.                         NewX = CurBlock.X - j + 2
  928.  
  929.  
  930.                         NewY = CurBlock.Y + i - 1
  931.  
  932.  
  933.                     CASE 2 ' Rotated 180 degrees.
  934.  
  935.  
  936.                         NewX = CurBlock.X - i + 3
  937.  
  938.  
  939.                         NewY = CurBlock.Y - j + 1
  940.  
  941.  
  942.                     CASE 3 ' Rotated 270 degrees clockwise, or 90 degrees counterclockwise.
  943.  
  944.  
  945.                         NewX = CurBlock.X + j + 1
  946.  
  947.  
  948.                         NewY = CurBlock.Y - i + 2
  949.  
  950.  
  951.                 END SELECT
  952.  
  953.  
  954.  
  955.  
  956.  
  957.                 ' Set CheckFit to false if the block would be out of the well.
  958.  
  959.  
  960.                 IF (NewX > WELLWIDTH - 1 OR NewX < 0 OR NewY > WELLHEIGHT - 1 OR NewY < 0) THEN
  961.  
  962.  
  963.                     CheckFit = FALSE
  964.  
  965.  
  966.                     EXIT FUNCTION
  967.  
  968.  
  969.  
  970.  
  971.  
  972.                     ' Otherwise, set CheckFit to false if the block overlaps
  973.  
  974.  
  975.                     ' an existing block.
  976.  
  977.  
  978.                 ELSEIF WellBlocks(NewX, NewY) THEN
  979.  
  980.  
  981.                     CheckFit = FALSE
  982.  
  983.  
  984.                     EXIT FUNCTION
  985.  
  986.  
  987.                 END IF
  988.  
  989.  
  990.  
  991.  
  992.  
  993.             END IF
  994.  
  995.  
  996.         NEXT j
  997.  
  998.  
  999.     NEXT i
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010. '----------------------------------------------------------------------------
  1011.  
  1012.  
  1013. ' CheckForFullRows
  1014.  
  1015.  
  1016. '
  1017.  
  1018.  
  1019. '    Checks for filled rows.  If a row is filled, delete it and move
  1020.  
  1021.  
  1022. '    the blocks above down to fill the deleted row.
  1023.  
  1024.  
  1025. '
  1026.  
  1027.  
  1028. '           PARAMETERS:   None
  1029.  
  1030.  
  1031. '----------------------------------------------------------------------------
  1032.  
  1033.  
  1034. SUB CheckForFullRows
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.     DIM RowsToDelete(WELLHEIGHT) ' Temporary array to track rows that should be deleted.
  1041.  
  1042.  
  1043.     NumRowsToDelete = 0
  1044.  
  1045.  
  1046.     i = WELLHEIGHT ' Begin scanning from the bottom up.
  1047.  
  1048.  
  1049.     DO
  1050.  
  1051.  
  1052.         DeleteRow = TRUE ' Assume the row should be deleted.
  1053.  
  1054.  
  1055.         j = 0
  1056.  
  1057.  
  1058.         DO ' Scan within each row for blocks.
  1059.  
  1060.  
  1061.             DeleteRow = DeleteRow * SGN(WellBlocks(j, i)) ' If any position is blank, DeleteRow is 0 (FALSE).
  1062.  
  1063.  
  1064.             j = j + 1
  1065.  
  1066.  
  1067.         LOOP WHILE DeleteRow = TRUE AND j < WELLWIDTH
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.         IF DeleteRow = TRUE THEN
  1074.  
  1075.  
  1076.             ' Walk up the rows and copy them down in the WellBlocks array.
  1077.  
  1078.  
  1079.             NumRowsToDelete = NumRowsToDelete + 1 ' Number of rows to delete.
  1080.  
  1081.  
  1082.             RowsToDelete(i - NumDeleted) = TRUE ' Mark the rows to be deleted, compensating for rows that have already been deleted below it.
  1083.  
  1084.  
  1085.             NumDeleted = NumDeleted + 1 ' Compensates for rows that have been deleted already.
  1086.  
  1087.  
  1088.  
  1089.  
  1090.  
  1091.             ' Logically delete the row by moving all WellBlocks values down.
  1092.  
  1093.  
  1094.             FOR Row = i TO 1 STEP -1
  1095.  
  1096.  
  1097.                 FOR Col = 0 TO WELLWIDTH
  1098.  
  1099.  
  1100.                     WellBlocks(Col, Row) = WellBlocks(Col, Row - 1)
  1101.  
  1102.  
  1103.                 NEXT Col
  1104.  
  1105.  
  1106.             NEXT Row
  1107.  
  1108.  
  1109.         ELSE ' This row will not be deleted.
  1110.  
  1111.  
  1112.             i = i - 1
  1113.  
  1114.  
  1115.         END IF
  1116.  
  1117.  
  1118.     LOOP WHILE i >= 1 ' Stop looping when the top of the well is reached.
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124.     IF NumRowsToDelete > 0 THEN
  1125.  
  1126.  
  1127.         Score = Score + 100 * NumRowsToDelete ' Give 100 points for every row.
  1128.  
  1129.  
  1130.  
  1131.  
  1132.  
  1133.         ' Set Highest and Lowest such that any deleted row will initially set them.
  1134.  
  1135.  
  1136.         Highest = -1
  1137.  
  1138.  
  1139.         Lowest = 100
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145.         ' Find where the highest and lowest rows to delete are.
  1146.  
  1147.  
  1148.         FOR i = WELLHEIGHT TO 1 STEP -1
  1149.  
  1150.  
  1151.             IF RowsToDelete(i) = TRUE THEN
  1152.  
  1153.  
  1154.                 IF i > Highest THEN Highest = i
  1155.  
  1156.  
  1157.                 IF i < Lowest THEN Lowest = i
  1158.  
  1159.  
  1160.             END IF
  1161.  
  1162.  
  1163.         NEXT i
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.         IF (Highest - Lowest) + 1 = NumRowsToDelete THEN ' Only one contiguous group of rows to delete.
  1170.  
  1171.  
  1172.             DeleteChunk Highest, Lowest
  1173.  
  1174.  
  1175.         ELSE ' Two groups of rows to delete.
  1176.  
  1177.  
  1178.             ' Begin at Lowest and scan down for a row NOT to be deleted.
  1179.  
  1180.  
  1181.             ' Then delete everything from Lowest to the row not to be deleted.
  1182.  
  1183.  
  1184.             i = Lowest
  1185.  
  1186.  
  1187.             DO WHILE i <= Highest
  1188.  
  1189.  
  1190.                 IF RowsToDelete(i) = FALSE THEN
  1191.  
  1192.  
  1193.                     DeleteChunk i - 1, Lowest
  1194.  
  1195.  
  1196.                     EXIT DO
  1197.  
  1198.  
  1199.                 ELSE
  1200.  
  1201.  
  1202.                     i = i + 1
  1203.  
  1204.  
  1205.                 END IF
  1206.  
  1207.  
  1208.             LOOP
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.             ' Now look for the second group and delete those rows.
  1215.  
  1216.  
  1217.             Lowest = i
  1218.  
  1219.  
  1220.             DO WHILE RowsToDelete(Lowest) = FALSE
  1221.  
  1222.  
  1223.                 Lowest = Lowest + 1
  1224.  
  1225.  
  1226.             LOOP
  1227.  
  1228.  
  1229.             DeleteChunk Highest, Lowest
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235.         END IF
  1236.  
  1237.  
  1238.     END IF
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.  
  1249. '----------------------------------------------------------------------------
  1250.  
  1251.  
  1252. ' DeleteChunk
  1253.  
  1254.  
  1255. '
  1256.  
  1257.  
  1258. '    Deletes a group of one or more rows.
  1259.  
  1260.  
  1261. '
  1262.  
  1263.  
  1264. '           PARAMETERS:    Highest - Highest row to delete (physically lowest
  1265.  
  1266.  
  1267. '                                    on screen).
  1268.  
  1269.  
  1270. '                          Lowest  - Lowest row to delete (physically highest
  1271.  
  1272.  
  1273. '                                    on screen).
  1274.  
  1275.  
  1276. '----------------------------------------------------------------------------
  1277.  
  1278.  
  1279. SUB DeleteChunk (Highest, Lowest)
  1280.  
  1281.  
  1282.  
  1283.  
  1284.  
  1285.     ' GET the image of the row to delete.
  1286.  
  1287.  
  1288.     GET (WELLX, Lowest * YSIZE + WELLY)-(WELLX + WELLWIDTH * XSIZE, (Highest + 1) * YSIZE + WELLY - 1), Temp()
  1289.  
  1290.  
  1291.     PLAY PLAYCLEARROW
  1292.  
  1293.  
  1294.  
  1295.  
  1296.  
  1297.     ' Flash the rows 3 times.
  1298.  
  1299.  
  1300.     FOR Flash = 1 TO 3
  1301.  
  1302.  
  1303.         PUT (WELLX, Lowest * YSIZE + WELLY), Temp(), PRESET
  1304.  
  1305.  
  1306.         DelayTime! = TIMER + .02
  1307.  
  1308.  
  1309.         DO WHILE TIMER < DelayTime!: LOOP
  1310.  
  1311.  
  1312.         PUT (WELLX, Lowest * YSIZE + WELLY), Temp(), PSET
  1313.  
  1314.  
  1315.         DelayTime! = TIMER + .02
  1316.  
  1317.  
  1318.         DO WHILE TIMER < DelayTime!: LOOP
  1319.  
  1320.  
  1321.     NEXT Flash
  1322.  
  1323.  
  1324.  
  1325.  
  1326.  
  1327.     ' Move all the rows above the deleted ones down.
  1328.  
  1329.  
  1330.     GET (WELLX, WELLY)-(WELLX + WELLWIDTH * XSIZE, Lowest * YSIZE + WELLY), Temp()
  1331.  
  1332.  
  1333.     PUT (WELLX, (Highest - Lowest + 1) * YSIZE + WELLY), Temp(), PSET
  1334.  
  1335.  
  1336.     'Erase the area above the block which just moved down.
  1337.  
  1338.  
  1339.     LINE (WELLX, WELLY)-(WELLX + WELLWIDTH * XSIZE, WELLY + (Highest - Lowest + 1) * YSIZE), WellColor, BF
  1340.  
  1341.  
  1342.  
  1343.  
  1344.  
  1345.  
  1346.  
  1347. '----------------------------------------------------------------------------
  1348.  
  1349.  
  1350. ' DisplayChanges
  1351.  
  1352.  
  1353. '
  1354.  
  1355.  
  1356. '    Displays list of changes that the player can easily make.
  1357.  
  1358.  
  1359. '
  1360.  
  1361.  
  1362. '           PARAMETERS:   None
  1363.  
  1364.  
  1365. '----------------------------------------------------------------------------
  1366.  
  1367.  
  1368. SUB DisplayChanges
  1369.  
  1370.  
  1371.  
  1372.  
  1373.  
  1374.     DisplayGameTitle ' Print game title.
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380.     COLOR 7
  1381.  
  1382.  
  1383.     Center "The following game characteristics can be easily changed from", 5
  1384.  
  1385.  
  1386.     Center "within the QuickBASIC Interpreter.  To change the values of  ", 6
  1387.  
  1388.  
  1389.     Center "these characteristics, locate the corresponding CONST or DATA", 7
  1390.  
  1391.  
  1392.     Center "statements in the source code and change their values, then  ", 8
  1393.  
  1394.  
  1395.     Center "restart the program (press Shift + F5).                      ", 9
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.     COLOR 15
  1402.  
  1403.  
  1404.     Center "Block shapes                         ", 11
  1405.  
  1406.  
  1407.     Center "Block rotation                       ", 12
  1408.  
  1409.  
  1410.     Center "Number of different block shapes     ", 13
  1411.  
  1412.  
  1413.     Center "Score needed to advance to next level", 14
  1414.  
  1415.  
  1416.     Center "Width of the game well               ", 15
  1417.  
  1418.  
  1419.     Center "Height of the game well              ", 16
  1420.  
  1421.  
  1422.     Center "Songs played during game             ", 17
  1423.  
  1424.  
  1425.  
  1426.  
  1427.  
  1428.     COLOR 7
  1429.  
  1430.  
  1431.     Center "The CONST statements and instructions on changing them are   ", 19
  1432.  
  1433.  
  1434.     Center "located at the beginning of the main program.                ", 20
  1435.  
  1436.  
  1437.  
  1438.  
  1439.  
  1440.     DO WHILE INKEY$ = "": LOOP ' Wait for any key to be pressed.
  1441.  
  1442.  
  1443.     CLS ' Clear screen.
  1444.  
  1445.  
  1446.  
  1447.  
  1448.  
  1449.  
  1450.  
  1451.  
  1452.  
  1453.  
  1454. '----------------------------------------------------------------------------
  1455.  
  1456.  
  1457. ' DisplayGameTitle
  1458.  
  1459.  
  1460. '
  1461.  
  1462.  
  1463. '    Displays title of the game.
  1464.  
  1465.  
  1466. '
  1467.  
  1468.  
  1469. '           PARAMETERS:    None.
  1470.  
  1471.  
  1472. '----------------------------------------------------------------------------
  1473.  
  1474.  
  1475. SUB DisplayGameTitle
  1476.  
  1477.  
  1478.  
  1479.  
  1480.  
  1481.     SCREEN 0
  1482.  
  1483.  
  1484.     WIDTH 80, 25 ' Set width to 80, height to 25.
  1485.  
  1486.  
  1487.     COLOR 4, 0 ' Set colors for red on black.
  1488.  
  1489.  
  1490.     CLS ' Clear the screen.
  1491.  
  1492.  
  1493.     ScreenWidth = 80 ' Set screen width variable to match current width.
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.     ' Draw outline around screen with extended ASCII characters.
  1500.  
  1501.  
  1502.     LOCATE 1, 2
  1503.  
  1504.  
  1505.     PRINT CHR$(201); STRING$(76, 205); CHR$(187);
  1506.  
  1507.  
  1508.     FOR i% = 2 TO 24
  1509.  
  1510.  
  1511.         LOCATE i%, 2
  1512.  
  1513.  
  1514.         PRINT CHR$(186); TAB(79); CHR$(186);
  1515.  
  1516.  
  1517.     NEXT i%
  1518.  
  1519.  
  1520.     LOCATE 25, 2
  1521.  
  1522.  
  1523.     PRINT CHR$(200); STRING$(76, 205); CHR$(188);
  1524.  
  1525.  
  1526.  
  1527.  
  1528.  
  1529.     'Print game title centered at top of screen
  1530.  
  1531.  
  1532.     COLOR 0, 4
  1533.  
  1534.  
  1535.     Center "      Microsoft      ", 1
  1536.  
  1537.  
  1538.     Center "    Q B L O C K S    ", 2
  1539.  
  1540.  
  1541.     Center "   Press any key to continue   ", 25 ' Center prompt on line 25.
  1542.  
  1543.  
  1544.     COLOR 7, 0
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555. '----------------------------------------------------------------------------
  1556.  
  1557.  
  1558. ' DisplayIntro
  1559.  
  1560.  
  1561. '
  1562.  
  1563.  
  1564. '    Explains the object of the game and how to play.
  1565.  
  1566.  
  1567. '
  1568.  
  1569.  
  1570. '           PARAMETERS:   None
  1571.  
  1572.  
  1573. '----------------------------------------------------------------------------
  1574.  
  1575.  
  1576. SUB DisplayIntro
  1577.  
  1578.  
  1579.  
  1580.  
  1581.  
  1582.     CLS
  1583.  
  1584.  
  1585.     DisplayGameTitle
  1586.  
  1587.  
  1588.  
  1589.  
  1590.  
  1591.     Center "QBlocks challenges you to keep the well from filling.  Do this by", 5
  1592.  
  1593.  
  1594.     Center "completely filling rows with blocks, making the rows disappear.  ", 6
  1595.  
  1596.  
  1597.     Center "Move and rotate the falling shapes to get them into the best     ", 7
  1598.  
  1599.  
  1600.     Center "position.  The game will get faster as you score more points.    ", 8
  1601.  
  1602.  
  1603.  
  1604.  
  1605.  
  1606.     COLOR 4 ' Change foreground color for line to red.
  1607.  
  1608.  
  1609.     Center STRING$(74, 196), 11 ' Put horizontal red line on screen.
  1610.  
  1611.  
  1612.     COLOR 7 ' White (7) letters.        ' Change foreground color back to white
  1613.  
  1614.  
  1615.     Center " Game Controls ", 11 ' Display game controls.
  1616.  
  1617.  
  1618.     Center "     General                             Block Control      ", 13
  1619.  
  1620.  
  1621.     Center "                                     (Rotate)", 15
  1622.  
  1623.  
  1624.     Center "   P - Pause                                 " + CHR$(24) + " (or 5)   ", 16
  1625.  
  1626.  
  1627.     Center "      Q - Quit                         (Left) " + CHR$(27) + "   " + CHR$(26) + " (Right)   ", 17
  1628.  
  1629.  
  1630.     Center "                                    " + CHR$(25), 18
  1631.  
  1632.  
  1633.     Center "                                          (Drop)      ", 19
  1634.  
  1635.  
  1636.  
  1637.  
  1638.  
  1639.     DO ' Wait for any key to be pressed.
  1640.  
  1641.  
  1642.         kbd$ = UCASE$(INKEY$)
  1643.  
  1644.  
  1645.     LOOP WHILE kbd$ = ""
  1646.  
  1647.  
  1648.     IF kbd$ = "Q" THEN 'Allow player to quit now
  1649.  
  1650.  
  1651.         CLS
  1652.  
  1653.  
  1654.         LOCATE 10, 30: PRINT "Really quit? (Y/N)";
  1655.  
  1656.  
  1657.         DO
  1658.  
  1659.  
  1660.             kbd$ = UCASE$(INKEY$)
  1661.  
  1662.  
  1663.         LOOP WHILE kbd$ = ""
  1664.  
  1665.  
  1666.         IF kbd$ = "Y" THEN
  1667.  
  1668.  
  1669.             CLS
  1670.  
  1671.  
  1672.             END
  1673.  
  1674.  
  1675.         END IF
  1676.  
  1677.  
  1678.     END IF
  1679.  
  1680.  
  1681.  
  1682.  
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688.  
  1689. '----------------------------------------------------------------------------
  1690.  
  1691.  
  1692. ' DrawAllShapes
  1693.  
  1694.  
  1695. '
  1696.  
  1697.  
  1698. '    Quickly draws all shapes in all four rotations.  Uses GET
  1699.  
  1700.  
  1701. '    to store the images so they can be PUT onto the screen
  1702.  
  1703.  
  1704. '    later very quickly.
  1705.  
  1706.  
  1707. '
  1708.  
  1709.  
  1710. '           PARAMETERS:    None.
  1711.  
  1712.  
  1713. '----------------------------------------------------------------------------
  1714.  
  1715.  
  1716. SUB DrawAllShapes
  1717.  
  1718.  
  1719.  
  1720.  
  1721.  
  1722.     DIM b AS BlockType
  1723.  
  1724.  
  1725.     SCREEN ScreenMode ' Set the appropriate screen mode.
  1726.  
  1727.  
  1728.  
  1729.  
  1730.  
  1731.     ' On EGA and VGA systems, appear to blank the screen.
  1732.  
  1733.  
  1734.     IF ScreenMode = 7 THEN
  1735.  
  1736.  
  1737.         DIM Colors(0 TO 15) ' DIM an array of 16 elements.  By default, all elements are 0.
  1738.  
  1739.  
  1740.         PALETTE USING Colors() ' Redefine the colors all to 0.
  1741.  
  1742.  
  1743.         FOR i = 1 TO NUMSTYLES ' Set block colors EGA, VGA
  1744.  
  1745.  
  1746.             BlockColor(i) = ((i - 1) MOD 7) + 1
  1747.  
  1748.  
  1749.         NEXT i
  1750.  
  1751.  
  1752.     ELSE
  1753.  
  1754.  
  1755.         FOR i = 1 TO NUMSTYLES 'Set block colors for CGA
  1756.  
  1757.  
  1758.             BlockColor(i) = ((i - 1) MOD 3) + 1
  1759.  
  1760.  
  1761.         NEXT i
  1762.  
  1763.  
  1764.     END IF
  1765.  
  1766.  
  1767.  
  1768.  
  1769.  
  1770.     CLS
  1771.  
  1772.  
  1773.     Count = 0 ' Count determines how many shapes have been drawn on the screen and vertically where.
  1774.  
  1775.  
  1776.     FOR shape = 1 TO NUMSTYLES ' Loop through all shapes.
  1777.  
  1778.  
  1779.  
  1780.  
  1781.  
  1782.         RtSide = 4
  1783.  
  1784.  
  1785.         DO
  1786.  
  1787.  
  1788.             IF BlockShape(RtSide - 1, 0, shape) = 1 OR BlockShape(RtSide - 1, 1, shape) = 1 THEN EXIT DO
  1789.  
  1790.  
  1791.             RtSide = RtSide - 1
  1792.  
  1793.  
  1794.         LOOP UNTIL RtSide = 1
  1795.  
  1796.  
  1797.  
  1798.  
  1799.  
  1800.         LtSide = 0
  1801.  
  1802.  
  1803.         DO
  1804.  
  1805.  
  1806.             IF BlockShape(LtSide, 0, shape) = 1 OR BlockShape(LtSide, 1, shape) = 1 THEN EXIT DO
  1807.  
  1808.  
  1809.             LtSide = LtSide + 1
  1810.  
  1811.  
  1812.         LOOP UNTIL LtSide = 3
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.         FOR Rotation = 0 TO 3 ' Loop through all rotations.
  1819.  
  1820.  
  1821.             b.X = Rotation * 4 + 2 ' Determine where to put the shape.
  1822.  
  1823.  
  1824.             b.Y = Count + 2
  1825.  
  1826.  
  1827.             b.Rotation = Rotation
  1828.  
  1829.  
  1830.             b.Style = shape
  1831.  
  1832.  
  1833.             Show b ' Draw the shape.
  1834.  
  1835.  
  1836.  
  1837.  
  1838.  
  1839.             X = b.X: Y = b.Y
  1840.  
  1841.  
  1842.             SELECT CASE Rotation ' Based on Rotation, determine where the shape really is on the screen.
  1843.  
  1844.  
  1845.                 CASE 0 ' No rotation.
  1846.  
  1847.  
  1848.                     x1 = X: x2 = X + RtSide: y1 = Y: y2 = Y + 2
  1849.  
  1850.  
  1851.                 CASE 1 ' Rotated 90 degrees clockwise.
  1852.  
  1853.  
  1854.                     x1 = X + 1: x2 = X + 3: y1 = Y - 1: y2 = Y + RtSide - 1
  1855.  
  1856.  
  1857.                 CASE 2 ' 180 degrees.
  1858.  
  1859.  
  1860.                     x1 = X: x2 = X + 4 - LtSide: y1 = Y: y2 = Y + 2
  1861.  
  1862.  
  1863.                 CASE 3 ' Rotated 270 degrees clockwise.
  1864.  
  1865.  
  1866.                     x1 = X + 1: x2 = X + 3: y1 = Y - 1: y2 = Y + 3 - LtSide
  1867.  
  1868.  
  1869.             END SELECT
  1870.  
  1871.  
  1872.  
  1873.  
  1874.  
  1875.             ' Store the image of the rotated shape into an array for fast recall later.
  1876.  
  1877.  
  1878.             GET (x1 * XSIZE, y1 * YSIZE)-(x2 * XSIZE, y2 * YSIZE), BlockImage(((shape - 1) * 4 + Rotation) * ELEMENTSPERBLOCK)
  1879.  
  1880.  
  1881.  
  1882.  
  1883.  
  1884.         NEXT Rotation
  1885.  
  1886.  
  1887.  
  1888.  
  1889.  
  1890.         Count = Count + 5 ' Increase Count by 5 to leave at least one blank line between shapes.
  1891.  
  1892.  
  1893.         IF Count = 20 THEN ' No space for any more shapes.
  1894.  
  1895.  
  1896.             CLS
  1897.  
  1898.  
  1899.             Count = 0
  1900.  
  1901.  
  1902.         END IF
  1903.  
  1904.  
  1905.  
  1906.  
  1907.  
  1908.     NEXT shape
  1909.  
  1910.  
  1911.  
  1912.  
  1913.  
  1914.     CLS
  1915.  
  1916.  
  1917.  
  1918.  
  1919.  
  1920.     ' Changes the color palette if SCREEN is used.
  1921.  
  1922.  
  1923.     IF ScreenMode = 7 THEN
  1924.  
  1925.  
  1926.         PALETTE ' Restore default color settings.
  1927.  
  1928.  
  1929.         PALETTE 6, 14 ' Make brown (6) look like yellow (14).
  1930.  
  1931.  
  1932.         PALETTE 14, 15 ' Make yellow (14) look like bright white (15).
  1933.  
  1934.  
  1935.     END IF
  1936.  
  1937.  
  1938.  
  1939.  
  1940.  
  1941.  
  1942.  
  1943.  
  1944.  
  1945.  
  1946. '----------------------------------------------------------------------------
  1947.  
  1948.  
  1949. ' DrawBlock
  1950.  
  1951.  
  1952. '
  1953.  
  1954.  
  1955. '    Draws one block of a QBlocks shape.
  1956.  
  1957.  
  1958. '
  1959.  
  1960.  
  1961. '           PARAMETERS:    X         - Horizontal screen location.
  1962.  
  1963.  
  1964. '                          Y         - Vertical screen location.
  1965.  
  1966.  
  1967. '                          FillColor - The primary color of the block.
  1968.  
  1969.  
  1970. '                                      The top and left edges will be the
  1971.  
  1972.  
  1973. '                                      brighter shade of that color.
  1974.  
  1975.  
  1976. '----------------------------------------------------------------------------
  1977.  
  1978.  
  1979. SUB DrawBlock (X, Y, FillColor)
  1980.  
  1981.  
  1982.  
  1983.  
  1984.  
  1985.     LINE (X * XSIZE + 2, Y * YSIZE + 2)-((X + 1) * XSIZE - 2, (Y + 1) * YSIZE - 2), FillColor, BF
  1986.  
  1987.  
  1988.     LINE (X * XSIZE + 1, Y * YSIZE + 1)-((X + 1) * XSIZE - 1, Y * YSIZE + 1), FillColor + 8
  1989.  
  1990.  
  1991.     LINE (X * XSIZE + 1, Y * YSIZE + 1)-(X * XSIZE + 1, (Y + 1) * YSIZE - 1), FillColor + 8
  1992.  
  1993.  
  1994.  
  1995.  
  1996.  
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002. '----------------------------------------------------------------------------
  2003.  
  2004.  
  2005. ' DrawPattern
  2006.  
  2007.  
  2008. '
  2009.  
  2010.  
  2011. '    Draws a background pattern that is 32 pixels wide by 20 pixels
  2012.  
  2013.  
  2014. '    deep.  Gets the pattern and duplicates it to fill the screen.
  2015.  
  2016.  
  2017. '
  2018.  
  2019.  
  2020. '           PARAMETERS:    Pattern - Which of the 10 available patterns to
  2021.  
  2022.  
  2023. '                                    draw.
  2024.  
  2025.  
  2026. '----------------------------------------------------------------------------
  2027.  
  2028.  
  2029. SUB DrawPattern (Pattern)
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.     CLS
  2036.  
  2037.  
  2038.     X = 1: Y = 1
  2039.  
  2040.  
  2041.     DIM Temp2(215) AS INTEGER ' Create an array to store the image.
  2042.  
  2043.  
  2044.  
  2045.  
  2046.  
  2047.     ' Draw the pattern specified.
  2048.  
  2049.  
  2050.     SELECT CASE Pattern
  2051.  
  2052.  
  2053.         CASE 0
  2054.  
  2055.  
  2056.             j = Y + 21
  2057.  
  2058.  
  2059.             FOR i = X TO X + 27 STEP 3
  2060.  
  2061.  
  2062.                 j = j - 2
  2063.  
  2064.  
  2065.                 LINE (i, j)-(i, Y + 19), 12, BF
  2066.  
  2067.  
  2068.             NEXT i
  2069.  
  2070.  
  2071.             LINE (X, Y)-(X + 30, Y + 19), 4, B
  2072.  
  2073.  
  2074.             LINE (X + 1, Y + 1)-(X + 31, Y + 18), 4, B
  2075.  
  2076.  
  2077.         CASE 1
  2078.  
  2079.  
  2080.             LINE (X, Y)-(X + 8, Y + 12), 1, BF
  2081.  
  2082.  
  2083.             LINE (X + 9, Y + 8)-(X + 24, Y + 20), 2, BF
  2084.  
  2085.  
  2086.             LINE (X + 25, Y)-(X + 32, Y + 12), 3, BF
  2087.  
  2088.  
  2089.         CASE 2
  2090.  
  2091.  
  2092.             LINE (X, Y)-(X + 29, Y + 18), X / 32 + 1, B
  2093.  
  2094.  
  2095.             LINE (X + 1, Y + 1)-(X + 28, Y + 17), X / 32 + 2, B
  2096.  
  2097.  
  2098.         CASE 3
  2099.  
  2100.  
  2101.             FOR i = 0 TO 9 STEP 2
  2102.  
  2103.  
  2104.                 LINE (X + i, Y + i)-(X + 29 - i, Y + 18 - i), i, B
  2105.  
  2106.  
  2107.             NEXT i
  2108.  
  2109.  
  2110.         CASE 4
  2111.  
  2112.  
  2113.             j = 0
  2114.  
  2115.  
  2116.             FOR i = 1 TO 30 STEP 3
  2117.  
  2118.  
  2119.                 LINE (X + i, Y + j)-(X + 30 - i, Y + j), i
  2120.  
  2121.  
  2122.                 LINE (X + i, Y + 19 - j)-(X + 30 - i, Y + 19 - j), i
  2123.  
  2124.  
  2125.                 j = j + 2
  2126.  
  2127.  
  2128.             NEXT i
  2129.  
  2130.  
  2131.         CASE 5
  2132.  
  2133.  
  2134.             LINE (X, Y)-(X + 29, Y + 4), 1, BF
  2135.  
  2136.  
  2137.             LINE (X, Y)-(X + 4, Y + 18), 1, BF
  2138.  
  2139.  
  2140.             LINE (X + 7, Y + 7)-(X + 29, Y + 11), 5, BF
  2141.  
  2142.  
  2143.             LINE (X + 7, Y + 7)-(X + 11, Y + 18), 5, BF
  2144.  
  2145.  
  2146.             LINE (X + 14, Y + 14)-(X + 29, Y + 18), 4, BF
  2147.  
  2148.  
  2149.         CASE 6
  2150.  
  2151.  
  2152.             LINE (X + 15, Y)-(X + 17, Y + 19), 1
  2153.  
  2154.  
  2155.             LINE (X, Y + 9)-(X + 31, Y + 11), 2
  2156.  
  2157.  
  2158.             LINE (X, Y + 1)-(X + 31, Y + 18), 9
  2159.  
  2160.  
  2161.             LINE (X + 30, Y)-(X + 1, Y + 19), 10
  2162.  
  2163.  
  2164.         CASE 7
  2165.  
  2166.  
  2167.             FOR i = 1 TO 6
  2168.  
  2169.  
  2170.                 CIRCLE (X + 16, Y + 10), i, i
  2171.  
  2172.  
  2173.             NEXT i
  2174.  
  2175.  
  2176.         CASE 8
  2177.  
  2178.  
  2179.             FOR i = X TO X + 30 STEP 10
  2180.  
  2181.  
  2182.                 CIRCLE (i, Y + 9), 10, Y / 20 + 1
  2183.  
  2184.  
  2185.             NEXT i
  2186.  
  2187.  
  2188.         CASE 9
  2189.  
  2190.  
  2191.             LINE (X + 1, Y)-(X + 1, Y + 18), 3
  2192.  
  2193.  
  2194.             LINE (X + 1, Y)-(X + 12, Y + 18), 3
  2195.  
  2196.  
  2197.             LINE (X + 1, Y + 18)-(X + 12, Y + 18), 3
  2198.  
  2199.  
  2200.             LINE (X + 30, Y)-(X + 30, Y + 18), 3
  2201.  
  2202.  
  2203.             LINE (X + 30, Y)-(X + 19, Y + 18), 3
  2204.  
  2205.  
  2206.             LINE (X + 30, Y + 18)-(X + 19, Y + 18), 3
  2207.  
  2208.  
  2209.             LINE (X + 4, Y)-(X + 26, Y), 1
  2210.  
  2211.  
  2212.             LINE (X + 4, Y)-(X + 15, Y + 18), 1
  2213.  
  2214.  
  2215.             LINE (X + 26, Y)-(X + 15, Y + 18), 1
  2216.  
  2217.  
  2218.     END SELECT
  2219.  
  2220.  
  2221.  
  2222.  
  2223.  
  2224.     GET (0, 0)-(31, 19), Temp2() ' GET the image.
  2225.  
  2226.  
  2227.  
  2228.  
  2229.  
  2230.     ' Duplicate the image 10 times across by 10 times down.
  2231.  
  2232.  
  2233.     FOR H = 0 TO 319 STEP 32
  2234.  
  2235.  
  2236.         FOR V = 0 TO 199 STEP 20
  2237.  
  2238.  
  2239.             PUT (H, V), Temp2(), PSET
  2240.  
  2241.  
  2242.         NEXT V
  2243.  
  2244.  
  2245.     NEXT H
  2246.  
  2247.  
  2248.  
  2249.  
  2250.  
  2251.  
  2252.  
  2253.  
  2254.  
  2255.  
  2256. '----------------------------------------------------------------------------
  2257.  
  2258.  
  2259. ' DrawPlayingField
  2260.  
  2261.  
  2262. '
  2263.  
  2264.  
  2265. '    Draws the playing field, including the well, the title, the
  2266.  
  2267.  
  2268. '    score/level box, etc.
  2269.  
  2270.  
  2271. '
  2272.  
  2273.  
  2274. '           PARAMETERS:   None
  2275.  
  2276.  
  2277. '----------------------------------------------------------------------------
  2278.  
  2279.  
  2280. SUB DrawPlayingField
  2281.  
  2282.  
  2283.  
  2284.  
  2285.  
  2286.     SELECT CASE ScreenMode ' Choose the screen colors based on the current mode.
  2287.  
  2288.  
  2289.         CASE 7
  2290.  
  2291.  
  2292.             WellColor = WELLCOLOR7
  2293.  
  2294.  
  2295.             BorderColor = BORDERCOLOR7
  2296.  
  2297.  
  2298.  
  2299.  
  2300.  
  2301.         CASE ELSE ' Setup for SCREEN 1.
  2302.  
  2303.  
  2304.             WellColor = WELLCOLOR1
  2305.  
  2306.  
  2307.             BorderColor = BORDERCOLOR1
  2308.  
  2309.  
  2310.     END SELECT
  2311.  
  2312.  
  2313.  
  2314.  
  2315.  
  2316.     ScreenWidth = 40 ' Set to proper width and colors.
  2317.  
  2318.  
  2319.  
  2320.  
  2321.  
  2322.     ' Draw the background pattern.
  2323.  
  2324.  
  2325.     DrawPattern Level
  2326.  
  2327.  
  2328.  
  2329.  
  2330.  
  2331.     ' Draw the well box.
  2332.  
  2333.  
  2334.     LINE (WELLX - 1, WELLY - 5)-(WELLX + WELLWIDTH * XSIZE + 1, WELLY + WELLHEIGHT * YSIZE + 1), WellColor, BF
  2335.  
  2336.  
  2337.     LINE (WELLX - 1, WELLY - 5)-(WELLX + WELLWIDTH * XSIZE + 1, WELLY + WELLHEIGHT * YSIZE + 1), BorderColor, B
  2338.  
  2339.  
  2340.  
  2341.  
  2342.  
  2343.     ' Draw the title box.
  2344.  
  2345.  
  2346.     LINE (XSIZE, WELLY - 5)-(XSIZE * 8, WELLY + 12), WellColor, BF
  2347.  
  2348.  
  2349.     LINE (XSIZE, WELLY - 5)-(XSIZE * 8, WELLY + 12), BorderColor, B
  2350.  
  2351.  
  2352.  
  2353.  
  2354.  
  2355.     ' Draw the scoring box.
  2356.  
  2357.  
  2358.     LINE (XSIZE, WELLY + 20)-(WELLX - 2 * XSIZE, 78), WellColor, BF
  2359.  
  2360.  
  2361.     LINE (XSIZE, WELLY + 20)-(WELLX - 2 * XSIZE, 78), BorderColor, B
  2362.  
  2363.  
  2364.  
  2365.  
  2366.  
  2367.     MakeInfoBox ' Draw the Information Box.
  2368.  
  2369.  
  2370.  
  2371.  
  2372.  
  2373.     COLOR 12
  2374.  
  2375.  
  2376.     LOCATE 3, 5: PRINT "QBLOCKS" ' Center the program name on line 2.
  2377.  
  2378.  
  2379.     COLOR BorderColor
  2380.  
  2381.  
  2382.  
  2383.  
  2384.  
  2385.     ' Draw the scoring area.
  2386.  
  2387.  
  2388.     LOCATE 6, 4: PRINT "Score:";
  2389.  
  2390.  
  2391.     LOCATE 7, 4: PRINT USING "#,###,###"; Score
  2392.  
  2393.  
  2394.     LOCATE 9, 4: PRINT USING "Level: ##"; Level
  2395.  
  2396.  
  2397.  
  2398.  
  2399.  
  2400.  
  2401.  
  2402.  
  2403.  
  2404.  
  2405. '----------------------------------------------------------------------------
  2406.  
  2407.  
  2408. ' GameOver
  2409.  
  2410.  
  2411. '
  2412.  
  2413.  
  2414. '    Ends the game and asks the player if he/she wants to play
  2415.  
  2416.  
  2417. '    again.  GameOver returns TRUE if the player wishes to stop
  2418.  
  2419.  
  2420. '    or FALSE if the player wants another game.
  2421.  
  2422.  
  2423. '
  2424.  
  2425.  
  2426. '           PARAMETERS:   None
  2427.  
  2428.  
  2429. '----------------------------------------------------------------------------
  2430.  
  2431.  
  2432. FUNCTION GameOver
  2433.  
  2434.  
  2435.  
  2436.  
  2437.  
  2438.     PLAY PLAYGAMEOVER ' Play the game over tune.
  2439.  
  2440.  
  2441.     MakeInfoBox
  2442.  
  2443.  
  2444.  
  2445.  
  2446.  
  2447.     DO WHILE INKEY$ <> "": LOOP ' Clear the keyboard buffer.
  2448.  
  2449.  
  2450.  
  2451.  
  2452.  
  2453.     ' Put Game Over messages into the InfoBox.
  2454.  
  2455.  
  2456.     LOCATE 14, 4: PRINT "Game Over"
  2457.  
  2458.  
  2459.     LOCATE 17, 6: PRINT "Play"
  2460.  
  2461.  
  2462.     LOCATE 18, 5: PRINT "again?"
  2463.  
  2464.  
  2465.     LOCATE 20, 6: PRINT "(Y/N)"
  2466.  
  2467.  
  2468.  
  2469.  
  2470.  
  2471.     ' Wait for the player to press either Y or N.
  2472.  
  2473.  
  2474.     DO
  2475.  
  2476.  
  2477.         a$ = UCASE$(INKEY$) ' UCASE$ assures that the key will be uppercase.  This eliminates the need to check for y and n in addition to Y and N.
  2478.  
  2479.  
  2480.     LOOP UNTIL a$ = "Y" OR a$ = "N"
  2481.  
  2482.  
  2483.  
  2484.  
  2485.  
  2486.     IF a$ = "Y" THEN ' If player selects "Y",
  2487.  
  2488.  
  2489.         GameOver = FALSE ' game is not over,
  2490.  
  2491.  
  2492.     ELSE ' otherwise
  2493.  
  2494.  
  2495.         GameOver = TRUE ' the game is over.
  2496.  
  2497.  
  2498.     END IF
  2499.  
  2500.  
  2501.  
  2502.  
  2503.  
  2504.  
  2505.  
  2506.  
  2507.  
  2508.  
  2509. '----------------------------------------------------------------------------
  2510.  
  2511.  
  2512. ' InitScreen
  2513.  
  2514.  
  2515. '
  2516.  
  2517.  
  2518. '    Draws the playing field and ask for the desired starting level.
  2519.  
  2520.  
  2521. '
  2522.  
  2523.  
  2524. '           PARAMETERS:   None
  2525.  
  2526.  
  2527. '----------------------------------------------------------------------------
  2528.  
  2529.  
  2530. SUB InitScreen
  2531.  
  2532.  
  2533.  
  2534.  
  2535.  
  2536.     DrawPlayingField ' Draw playing field assuming Level 0.
  2537.  
  2538.  
  2539.  
  2540.  
  2541.  
  2542.     ' Prompt for starting level.
  2543.  
  2544.  
  2545.     COLOR 12 ' Change foreground color to bright red.
  2546.  
  2547.  
  2548.     LOCATE 14, 5: PRINT "Select";
  2549.  
  2550.  
  2551.     LOCATE 16, 5: PRINT "start";
  2552.  
  2553.  
  2554.     LOCATE 18, 5: PRINT "level?";
  2555.  
  2556.  
  2557.     LOCATE 20, 5: PRINT "(0 - 9)";
  2558.  
  2559.  
  2560.     COLOR BorderColor ' Restore the default text color to BorderColor (white).
  2561.  
  2562.  
  2563.     Level = TRUE ' Use level as flag as well as a real value.  Level remain TRUE if Q (Quit) is pressed instead of a level.
  2564.  
  2565.  
  2566.  
  2567.  
  2568.  
  2569.     ' Get a value for Level or accept a Q.
  2570.  
  2571.  
  2572.     DO
  2573.  
  2574.  
  2575.         a$ = UCASE$(INKEY$)
  2576.  
  2577.  
  2578.     LOOP WHILE (a$ > "9" OR a$ < "0") AND a$ <> "Q"
  2579.  
  2580.  
  2581.  
  2582.  
  2583.  
  2584.     IF a$ = "Q" THEN
  2585.  
  2586.  
  2587.         EXIT SUB
  2588.  
  2589.  
  2590.     ELSE
  2591.  
  2592.  
  2593.         Level = VAL(a$)
  2594.  
  2595.  
  2596.     END IF
  2597.  
  2598.  
  2599.  
  2600.  
  2601.  
  2602.     IF Level > 0 THEN DrawPlayingField ' Draw new playing field because the background pattern depends on the level.
  2603.  
  2604.  
  2605.     RedrawControls ' Draw the controls.
  2606.  
  2607.  
  2608.  
  2609.  
  2610.  
  2611.  
  2612.  
  2613.  
  2614.  
  2615.  
  2616. '----------------------------------------------------------------------------
  2617.  
  2618.  
  2619. ' MakeInfoBox
  2620.  
  2621.  
  2622. '
  2623.  
  2624.  
  2625. '    Draws the information box.
  2626.  
  2627.  
  2628. '
  2629.  
  2630.  
  2631. '           PARAMETERS:   None
  2632.  
  2633.  
  2634. '----------------------------------------------------------------------------
  2635.  
  2636.  
  2637. SUB MakeInfoBox
  2638.  
  2639.  
  2640.  
  2641.  
  2642.  
  2643.     LINE (WELLX - 9 * XSIZE, 90)-(WELLX - 2 * XSIZE, 185), WellColor, BF ' Clear the Info area.
  2644.  
  2645.  
  2646.     LINE (WELLX - 9 * XSIZE, 90)-(WELLX - 2 * XSIZE, 185), BorderColor, B ' Draw a border around it.
  2647.  
  2648.  
  2649.  
  2650.  
  2651.  
  2652.  
  2653.  
  2654.  
  2655.  
  2656.  
  2657. '----------------------------------------------------------------------------
  2658.  
  2659.  
  2660. ' NewBlock
  2661.  
  2662.  
  2663. '
  2664.  
  2665.  
  2666. '    Initializes a new falling shape about to enter the well.
  2667.  
  2668.  
  2669. '
  2670.  
  2671.  
  2672. '           PARAMETERS:   None
  2673.  
  2674.  
  2675. '----------------------------------------------------------------------------
  2676.  
  2677.  
  2678. SUB NewBlock
  2679.  
  2680.  
  2681.  
  2682.  
  2683.  
  2684.     CurBlock.Style = INT(RND(1) * NUMSTYLES) + 1 ' Randomly pick a block style.
  2685.  
  2686.  
  2687.     CurBlock.X = (WELLWIDTH \ 2) - 1 ' Put the new shape in the horizontal middle of the well
  2688.  
  2689.  
  2690.     CurBlock.Y = 0 ' and at the top of the well.
  2691.  
  2692.  
  2693.     CurBlock.Rotation = 0 ' Begin with no rotation.
  2694.  
  2695.  
  2696.  
  2697.  
  2698.  
  2699.     PLAY PLAYNEWBLOCK
  2700.  
  2701.  
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710. '----------------------------------------------------------------------------
  2711.  
  2712.  
  2713. ' PerformGame
  2714.  
  2715.  
  2716. '
  2717.  
  2718.  
  2719. '    Continues to play the game until the player quits.
  2720.  
  2721.  
  2722. '
  2723.  
  2724.  
  2725. '           PARAMETERS:   None
  2726.  
  2727.  
  2728. '----------------------------------------------------------------------------
  2729.  
  2730.  
  2731. SUB PerformGame
  2732.  
  2733.  
  2734.  
  2735.  
  2736.  
  2737.     DO ' Loop for repetitive games
  2738.  
  2739.  
  2740.         a$ = ""
  2741.  
  2742.  
  2743.         ERASE WellBlocks ' Set all the elements in the WellBlocks array to 0.
  2744.  
  2745.  
  2746.         Score = 0 ' Clear initial score.
  2747.  
  2748.  
  2749.         Level = 0 ' Assume Level 0.
  2750.  
  2751.  
  2752.         PrevScore = BASESCORE - NEXTLEVEL ' Set score needed to get to first level
  2753.  
  2754.  
  2755.         GameTiltScore = WINGAME ' Set the initial win game value.
  2756.  
  2757.  
  2758.  
  2759.  
  2760.  
  2761.         InitScreen ' Prepare the screen and get the difficulty level.
  2762.  
  2763.  
  2764.         IF Level = -1 THEN EXIT SUB ' Player pressed Q instead of a level.
  2765.  
  2766.  
  2767.  
  2768.  
  2769.  
  2770.         TargetTime = TIMER + 1 / (Level + 1) ' TargetTime is when the falling shape will move down again.
  2771.  
  2772.  
  2773.         DO ' Create new falling shapes until the game is over.
  2774.  
  2775.  
  2776.             DoneWithThisBlock = FALSE ' This falling shape is not done falling yet.
  2777.  
  2778.  
  2779.             NewBlock ' Create a new falling unit.
  2780.  
  2781.  
  2782.             IF CheckFit = FALSE THEN EXIT DO ' If it does not fit, then the game is over.
  2783.  
  2784.  
  2785.             PutBlock CurBlock ' Display the new shape.
  2786.  
  2787.  
  2788.  
  2789.  
  2790.  
  2791.             DO ' Continue dropping the falling shape.
  2792.  
  2793.  
  2794.                 OldBlock = CurBlock ' Save current falling shape for possible later use.
  2795.  
  2796.  
  2797.                 DO ' Loop until enough time elapses.
  2798.  
  2799.  
  2800.  
  2801.  
  2802.  
  2803.                     ValidEvent = TRUE ' Assume a key was pressed.
  2804.  
  2805.  
  2806.                     ans$ = UCASE$(INKEY$)
  2807.  
  2808.  
  2809.  
  2810.  
  2811.  
  2812.                     IF ans$ = PAUSE OR ans$ = QUIT THEN
  2813.  
  2814.  
  2815.                         MakeInfoBox
  2816.  
  2817.  
  2818.  
  2819.  
  2820.  
  2821.                         ' SELECT CASE will do different actions based on the
  2822.  
  2823.  
  2824.                         ' value of the SELECTED variable.
  2825.  
  2826.  
  2827.                         SELECT CASE ans$
  2828.  
  2829.  
  2830.                             CASE PAUSE
  2831.  
  2832.  
  2833.                                 SOUND 1100, .75
  2834.  
  2835.  
  2836.                                 LOCATE 16, 6: PRINT "GAME";
  2837.  
  2838.  
  2839.                                 LOCATE 18, 5: PRINT "PAUSED";
  2840.  
  2841.  
  2842.                                 DO WHILE INKEY$ = "": LOOP ' Wait until another key is pressed.
  2843.  
  2844.  
  2845.                             CASE QUIT
  2846.  
  2847.  
  2848.                                 ' Play sounds to tell the player that Q was pressed.
  2849.  
  2850.  
  2851.                                 SOUND 1600, 1
  2852.  
  2853.  
  2854.                                 SOUND 1000, .75
  2855.  
  2856.  
  2857.  
  2858.  
  2859.  
  2860.                                 ' Confirm that the player really wants to quit.
  2861.  
  2862.  
  2863.                                 LOCATE 15, 5: PRINT "Really";
  2864.  
  2865.  
  2866.                                 LOCATE 17, 6: PRINT "quit?";
  2867.  
  2868.  
  2869.                                 LOCATE 19, 6: PRINT "(Y/N)";
  2870.  
  2871.  
  2872.                                 DO
  2873.  
  2874.  
  2875.                                     a$ = UCASE$(INKEY$)
  2876.  
  2877.  
  2878.                                 LOOP UNTIL a$ <> ""
  2879.  
  2880.  
  2881.                                 IF a$ = "Y" THEN EXIT SUB
  2882.  
  2883.  
  2884.                         END SELECT
  2885.  
  2886.  
  2887.                         RedrawControls ' Redraw controls if either Q or P is pressed.
  2888.  
  2889.  
  2890.  
  2891.  
  2892.  
  2893.                     ELSE ' A key was pressed but not Q or P.
  2894.  
  2895.  
  2896.                         ans = ASC(RIGHT$(CHR$(0) + ans$, 1)) ' Convert the key press to an ASCII code for faster processing.
  2897.  
  2898.  
  2899.                         SELECT CASE ans
  2900.  
  2901.  
  2902.                             CASE DOWNARROW, DOWNARROW2, SPACEBAR ' Drop shape immediately.
  2903.  
  2904.  
  2905.                                 DO ' Loop to drop the falling unit one row at a time.
  2906.  
  2907.  
  2908.                                     CurBlock.Y = CurBlock.Y + 1
  2909.  
  2910.  
  2911.                                 LOOP WHILE CheckFit = TRUE ' Keep looping while the falling unit isn't stopped.
  2912.  
  2913.  
  2914.                                 CurBlock.Y = CurBlock.Y - 1 ' Went one down too far, restore to previous.
  2915.  
  2916.  
  2917.                                 TargetTime = TIMER - 1 ' Ensure that the shape falls immediately.
  2918.  
  2919.  
  2920.                             CASE RIGHTARROW, RIGHTARROW2
  2921.  
  2922.  
  2923.                                 CurBlock.X = CurBlock.X + 1 ' Move falling unit right.
  2924.  
  2925.  
  2926.                             CASE LEFTARROW, LEFTARROW2
  2927.  
  2928.  
  2929.                                 CurBlock.X = CurBlock.X - 1 ' Move falling unit left.
  2930.  
  2931.  
  2932.                             CASE UPARROW, UPARROW2, UPARROW3
  2933.  
  2934.  
  2935.                                 CurBlock.Rotation = ((CurBlock.Rotation + ROTATEDIR) MOD 4) ' Rotate falling unit.
  2936.  
  2937.  
  2938.                             CASE ELSE
  2939.  
  2940.  
  2941.                                 ValidEvent = FALSE
  2942.  
  2943.  
  2944.                         END SELECT
  2945.  
  2946.  
  2947.  
  2948.  
  2949.  
  2950.                         IF ValidEvent = TRUE THEN
  2951.  
  2952.  
  2953.                             IF CheckFit = TRUE THEN ' If the move is valid and the shape fits in the new position,
  2954.  
  2955.  
  2956.                                 PutBlock OldBlock ' erase the shape from its old position
  2957.  
  2958.  
  2959.                                 PutBlock CurBlock ' and display it in the new position.
  2960.  
  2961.  
  2962.                                 OldBlock = CurBlock
  2963.  
  2964.  
  2965.                             ELSE
  2966.  
  2967.  
  2968.                                 CurBlock = OldBlock ' If it does not fit then reset CurBlock to the OldBlock.
  2969.  
  2970.  
  2971.                             END IF
  2972.  
  2973.  
  2974.                         END IF
  2975.  
  2976.  
  2977.                     END IF
  2978.  
  2979.  
  2980.  
  2981.  
  2982.  
  2983.                 LOOP UNTIL TIMER >= TargetTime ' Keep repeating the loop until it is time to drop the shape.  This allows many horizontal movements and rotations per vertical step.
  2984.  
  2985.  
  2986.  
  2987.  
  2988.  
  2989.                 TargetTime = TIMER + 1 / (Level + 1) ' The player has less time between vertical movements as the skill level increases.
  2990.  
  2991.  
  2992.                 CurBlock.Y = CurBlock.Y + 1 ' Try to drop the falling unit one row.
  2993.  
  2994.  
  2995.  
  2996.  
  2997.  
  2998.                 IF CheckFit = FALSE THEN ' Cannot fall any more.
  2999.  
  3000.  
  3001.                     DoneWithThisBlock = TRUE ' Done with this block.
  3002.  
  3003.  
  3004.                     CurBlock = OldBlock
  3005.  
  3006.  
  3007.                 END IF
  3008.  
  3009.  
  3010.  
  3011.  
  3012.  
  3013.                 PutBlock OldBlock ' Erase the falling shape from the old position,
  3014.  
  3015.  
  3016.                 PutBlock CurBlock ' and display it in the new position.
  3017.  
  3018.  
  3019.                 OldBlock = CurBlock
  3020.  
  3021.  
  3022.  
  3023.  
  3024.  
  3025.             LOOP UNTIL DoneWithThisBlock ' Continue getting keys and moving shapes until the falling shape stops.
  3026.  
  3027.  
  3028.  
  3029.  
  3030.  
  3031.             AddBlockToWell ' Shape has stopped so logically add it to the well.
  3032.  
  3033.  
  3034.             CheckForFullRows ' Check to see if a row(s) is now full.  If so, deletes it.
  3035.  
  3036.  
  3037.             UpdateScoring ' Use the UpdateScoring subprogram to add to the score.
  3038.  
  3039.  
  3040.  
  3041.  
  3042.  
  3043.             IF Score >= GameTiltScore THEN ' See if the score has hit the tilt score.
  3044.  
  3045.  
  3046.  
  3047.  
  3048.  
  3049.                 PLAY PLAYWINGAME
  3050.  
  3051.  
  3052.                 MakeInfoBox
  3053.  
  3054.  
  3055.                 LOCATE 13, 5: PRINT USING "#######"; Score
  3056.  
  3057.  
  3058.                 PLAY PLAYWINGAME
  3059.  
  3060.  
  3061.  
  3062.  
  3063.  
  3064.                 IF GameTiltScore = TILTVALUE THEN ' If the player has tilted the game.
  3065.  
  3066.  
  3067.                     LOCATE 15, 4: PRINT "GAME TILT"
  3068.  
  3069.  
  3070.                     LOCATE 17, 5: PRINT "You are"
  3071.  
  3072.  
  3073.                     LOCATE 18, 4: PRINT "Awesome!"
  3074.  
  3075.  
  3076.                     LOCATE 20, 4: PRINT "Press any"
  3077.  
  3078.  
  3079.                     LOCATE 21, 6: PRINT "key..."
  3080.  
  3081.  
  3082.                     PLAY PLAYWINGAME
  3083.  
  3084.  
  3085.                     DO WHILE INKEY$ = "": LOOP
  3086.  
  3087.  
  3088.                     EXIT SUB
  3089.  
  3090.  
  3091.                 ELSE ' If they just met the WINGAME value.
  3092.  
  3093.  
  3094.                     LOCATE 15, 4: PRINT "YOU WON!"
  3095.  
  3096.  
  3097.                     LOCATE 17, 5: PRINT "Want to"
  3098.  
  3099.  
  3100.                     LOCATE 18, 4: PRINT "continue"
  3101.  
  3102.  
  3103.                     LOCATE 20, 6: PRINT "(Y/N)"
  3104.  
  3105.  
  3106.  
  3107.  
  3108.  
  3109.                     DO ' DO loop to wait for the player to press anything.
  3110.  
  3111.  
  3112.                         a$ = UCASE$(INKEY$) ' The UCASE$ function assures that a$ always has an uppercase letter in it.
  3113.  
  3114.  
  3115.                     LOOP UNTIL a$ <> ""
  3116.  
  3117.  
  3118.  
  3119.  
  3120.  
  3121.                     IF a$ <> "Y" THEN EXIT DO ' Exit this main loop if the player pressed anything but Y.
  3122.  
  3123.  
  3124.  
  3125.  
  3126.  
  3127.                     GameTiltScore = TILTVALUE ' Reset to the tilt value.
  3128.  
  3129.  
  3130.  
  3131.  
  3132.  
  3133.                     RedrawControls
  3134.  
  3135.  
  3136.                 END IF
  3137.  
  3138.  
  3139.             END IF
  3140.  
  3141.  
  3142.  
  3143.  
  3144.  
  3145.         LOOP ' Unconditional loop.  Each game is stopped by the EXIT DO command at the top of this loop that executes when a new block will not fit in the well.
  3146.  
  3147.  
  3148.     LOOP UNTIL GameOver ' GameOver is always TRUE (-1) unless the user presses X or the well is full.
  3149.  
  3150.  
  3151.  
  3152.  
  3153.  
  3154.  
  3155.  
  3156.  
  3157.  
  3158.  
  3159. '----------------------------------------------------------------------------
  3160.  
  3161.  
  3162. ' PutBlock
  3163.  
  3164.  
  3165. '
  3166.  
  3167.  
  3168. '    Uses very fast graphics PUT command to draw the shape.
  3169.  
  3170.  
  3171. '
  3172.  
  3173.  
  3174. '           PARAMETERS:    B - Block to be put onto the screen.
  3175.  
  3176.  
  3177. '----------------------------------------------------------------------------
  3178.  
  3179.  
  3180. SUB PutBlock (b AS BlockType)
  3181.  
  3182.  
  3183.  
  3184.  
  3185.  
  3186.     SELECT CASE b.Rotation ' Base exact placement on the rotation.
  3187.  
  3188.  
  3189.         CASE 0 ' No rotation.
  3190.  
  3191.  
  3192.             x1 = b.X: y1 = b.Y
  3193.  
  3194.  
  3195.         CASE 1 ' Rotated 90 degrees clockwise, or 270 degrees counterclockwise.
  3196.  
  3197.  
  3198.             x1 = b.X + 1: y1 = b.Y - 1
  3199.  
  3200.  
  3201.         CASE 2 ' Rotated 180 degrees.
  3202.  
  3203.  
  3204.             x1 = b.X: y1 = b.Y
  3205.  
  3206.  
  3207.         CASE 3 ' Rotated 270 degrees clockwise, or 90 degrees counterclockwise.
  3208.  
  3209.  
  3210.             x1 = b.X + 1: y1 = b.Y - 1
  3211.  
  3212.  
  3213.     END SELECT
  3214.  
  3215.  
  3216.  
  3217.  
  3218.  
  3219.     ' Actually PUT the rotated shape on the screen.  The XOR option makes the
  3220.  
  3221.  
  3222.     ' new image blend with whatever used to be there in such a way that
  3223.  
  3224.  
  3225.     ' identical colors cancel each other out.  Therefore, one PUT with the XOR
  3226.  
  3227.  
  3228.     ' option can draw an object while the second PUT to that same location
  3229.  
  3230.  
  3231.     ' erases it without affecting anything else near it.  Often used for animation.
  3232.  
  3233.  
  3234.  
  3235.  
  3236.  
  3237.     PUT (x1 * XSIZE + WELLX, y1 * YSIZE + WELLY), BlockImage(((b.Style - 1) * 4 + b.Rotation) * ELEMENTSPERBLOCK), XOR ' XOR mixes what used to be there on the screen with the new image.  Two identical colors cancel each other.
  3238.  
  3239.  
  3240.  
  3241.  
  3242.  
  3243.  
  3244.  
  3245.  
  3246.  
  3247.  
  3248. '----------------------------------------------------------------------------
  3249.  
  3250.  
  3251. ' RedrawControls
  3252.  
  3253.  
  3254. '
  3255.  
  3256.  
  3257. '    Puts control keys information into the information box.
  3258.  
  3259.  
  3260. '
  3261.  
  3262.  
  3263. '           PARAMETERS:   None
  3264.  
  3265.  
  3266. '----------------------------------------------------------------------------
  3267.  
  3268.  
  3269. SUB RedrawControls
  3270.  
  3271.  
  3272.  
  3273.  
  3274.  
  3275.     ' Draw the InfoBox and erase anything that used to be in it.
  3276.  
  3277.  
  3278.     MakeInfoBox
  3279.  
  3280.  
  3281.  
  3282.  
  3283.  
  3284.     ' Print the key assignments within the Info Box.
  3285.  
  3286.  
  3287.     COLOR BorderColor
  3288.  
  3289.  
  3290.     LOCATE 13, 4: PRINT "Controls"
  3291.  
  3292.  
  3293.     LOCATE 14, 4: PRINT "--------"
  3294.  
  3295.  
  3296.     LOCATE 15, 4: PRINT CHR$(24) + " = Turn"
  3297.  
  3298.  
  3299.     LOCATE 16, 4: PRINT CHR$(27) + " = Left"
  3300.  
  3301.  
  3302.     LOCATE 17, 4: PRINT CHR$(26) + " = Right"
  3303.  
  3304.  
  3305.     LOCATE 18, 4: PRINT CHR$(25) + " = Drop"
  3306.  
  3307.  
  3308.     LOCATE 20, 4: PRINT "P = Pause"
  3309.  
  3310.  
  3311.     LOCATE 21, 4: PRINT "Q = Quit"
  3312.  
  3313.  
  3314.  
  3315.  
  3316.  
  3317.  
  3318.  
  3319.  
  3320.  
  3321.  
  3322. '----------------------------------------------------------------------------
  3323.  
  3324.  
  3325. ' Show
  3326.  
  3327.  
  3328. '
  3329.  
  3330.  
  3331. '    Draws the falling shape one block at a time.  Only used by
  3332.  
  3333.  
  3334. '    DisplayAllShapes.  After that, PutBlock draws all falling
  3335.  
  3336.  
  3337. '    shapes.
  3338.  
  3339.  
  3340. '
  3341.  
  3342.  
  3343. '           PARAMETERS:    B - Block to be put onto the screen.
  3344.  
  3345.  
  3346. '----------------------------------------------------------------------------
  3347.  
  3348.  
  3349. SUB Show (b AS BlockType)
  3350.  
  3351.  
  3352.  
  3353.  
  3354.  
  3355.     ' Loop through all possible block locations.
  3356.  
  3357.  
  3358.     FOR i = 0 TO XMATRIX
  3359.  
  3360.  
  3361.         FOR j = 0 TO YMATRIX
  3362.  
  3363.  
  3364.  
  3365.  
  3366.  
  3367.             IF BlockShape(i, j, b.Style) = 1 THEN ' 1 means there is a block there.
  3368.  
  3369.  
  3370.                 SELECT CASE b.Rotation ' Exact screen position is determined by the rotation.
  3371.  
  3372.  
  3373.                     CASE 0 ' No rotation.
  3374.  
  3375.  
  3376.                         DrawBlock b.X + i, b.Y + j, BlockColor(b.Style)
  3377.  
  3378.  
  3379.                     CASE 1 ' Rotated 90 degrees clockwise, or 270 degrees counterclockwise.
  3380.  
  3381.  
  3382.                         DrawBlock b.X - j + 2, b.Y - 1 + i, BlockColor(b.Style)
  3383.  
  3384.  
  3385.                     CASE 2 ' Rotated 180 degrees.
  3386.  
  3387.  
  3388.                         DrawBlock b.X + 3 - i, b.Y - j + 1, BlockColor(b.Style)
  3389.  
  3390.  
  3391.                     CASE 3 ' Rotated 270 degrees clockwise, or 90 degrees counterclockwise.
  3392.  
  3393.  
  3394.                         DrawBlock b.X + j + 1, b.Y - i + 2, BlockColor(b.Style)
  3395.  
  3396.  
  3397.                 END SELECT
  3398.  
  3399.  
  3400.             END IF
  3401.  
  3402.  
  3403.         NEXT j
  3404.  
  3405.  
  3406.     NEXT i
  3407.  
  3408.  
  3409.  
  3410.  
  3411.  
  3412.  
  3413.  
  3414.  
  3415.  
  3416.  
  3417. '---------------------------------------------------------------------------
  3418.  
  3419.  
  3420. ' UpdateScoring
  3421.  
  3422.  
  3423. '
  3424.  
  3425.  
  3426. '    Puts the new score on the screen.  Checks if the new score forces
  3427.  
  3428.  
  3429. '    a new level.  If so, change the background pattern to match the
  3430.  
  3431.  
  3432. '    new level.
  3433.  
  3434.  
  3435. '
  3436.  
  3437.  
  3438. '           PARAMETERS:     None
  3439.  
  3440.  
  3441. '----------------------------------------------------------------------------
  3442.  
  3443.  
  3444. SUB UpdateScoring
  3445.  
  3446.  
  3447.  
  3448.  
  3449.  
  3450.     ' Increase the level if the score is high enough and the level is not
  3451.  
  3452.  
  3453.     ' maximum already.
  3454.  
  3455.  
  3456.     IF Level < 9 AND Score >= (NEXTLEVEL * (Level + 1) + PrevScore) THEN
  3457.  
  3458.  
  3459.  
  3460.  
  3461.  
  3462.         ' Store the entire well image to quickly PUT it back after the
  3463.  
  3464.  
  3465.         ' background changes.
  3466.  
  3467.  
  3468.         GET (WELLX, WELLY)-(WELLX + WELLWIDTH * XSIZE, WELLY + WELLHEIGHT * YSIZE), Temp()
  3469.  
  3470.  
  3471.  
  3472.  
  3473.  
  3474.         PrevScore = Score ' Save previous Score for next level.
  3475.  
  3476.  
  3477.         Level = Level + 1
  3478.  
  3479.  
  3480.         DrawPlayingField ' Draw playing field again, this time with the new background pattern.
  3481.  
  3482.  
  3483.         PUT (WELLX, WELLY), Temp() ' Restore the image of the old well.
  3484.  
  3485.  
  3486.  
  3487.  
  3488.  
  3489.         RedrawControls ' Show the controls again.
  3490.  
  3491.  
  3492.     END IF
  3493.  
  3494.  
  3495.  
  3496.  
  3497.  
  3498.     LOCATE 7, 4: PRINT USING "#,###,###"; Score ' Print the score and level.
  3499.  
  3500.  
  3501.  
  3502.  
  3503.  
  3504.  
  3505.  
  3506.  
  3507.  
  3508.  
  3509.  

Be patient after hitting F5... in QB64 dev build it takes many minutes before to run.

Fun playing
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Qbasic Tetris clone takes many minutes to be compiled!
« Reply #1 on: January 30, 2021, 10:00:49 am »
Dang! what's with all the blank lines! ?

Fixed:
Code: QB64: [Select]
  1. '                                QBLOCKS.BAS
  2. '
  3. ' Press Page Down for information on running and modifying QBlocks.
  4. '
  5. ' To run this game, press Shift+F5.
  6. '
  7. ' To exit this program, press ALT, F, X.
  8. '
  9. ' To get help on a BASIC keyword, move the cursor to the keyword and press
  10. ' F1 or click the right mouse button.
  11. '
  12. '                             Suggested Changes
  13. '                             -----------------
  14. '
  15. ' There are many ways that you can modify this BASIC game.  The CONST
  16. ' statements below these comments and the DATA statements at the end
  17. ' of this screen can be modified to change the following:
  18. '
  19. '    Block shapes
  20. '    Block rotation
  21. '    Number of different block shapes
  22. '    Score needed to advance to next level
  23. '    Width of the game well
  24. '    Height of the game well
  25. '    Songs played during game
  26. '
  27. ' On the right side of each CONST statement, there is a comment that tells
  28. ' you what it does and how big or small you can set the value.  Above the
  29. ' DATA statements, there are comments that tell you the format of the
  30. ' information stored there.
  31. '
  32. ' On your own, you can also add exciting sound and visual effects or make any
  33. ' other changes that your imagination can dream up.  By reading the
  34. ' Learn BASIC Now book, you'll learn the techniques that will enable you
  35. ' to fully customize this game and to create games of your own.
  36. '
  37. ' If the game won't run after you have changed it, you can exit without
  38. ' saving your changes by pressing Alt, F, X and choosing NO.
  39. '
  40. ' If you do want to save your changes, press Alt, F, A and enter a filename
  41. ' for saving your version of the program.  Before you save your changes,
  42. ' however, you should make sure they work by running the program and
  43. ' verifying that your changes produce the desired results.  Also, always
  44. ' be sure to keep a backup of the original program.
  45. '
  46. DEFINT A-Z
  47. ' Here are the BASIC CONST statements you can change.  The comments tell
  48. ' you the range that each CONST value can be changed, or any limitations.
  49. CONST WELLWIDTH = 10 ' Width of playing field (well).   Range 5 to 13.
  50. CONST WELLHEIGHT = 21 ' Height of playing field.  Range 4 to 21.
  51. CONST NUMSTYLES = 7 ' Number of unique shapes.  Range 1 to 20.  Make sure you read the notes above the DATA statements at the end of the main program before you change this number!
  52. CONST WINGAME = 1000000 ' Points required to win the game.  Range 200 to 9000000.
  53. CONST NEXTLEVEL = 300 ' Helps determine when the game advances to the next level.  (Each cleared level gives player 100 points) Range 100 to 2000.
  54. CONST BASESCORE = 1000 ' Number of points needed to advance to first level.
  55. CONST ROTATEDIR = 1 ' Control rotation of blocks. Can be 1 for clockwise, or 3 for counterclockwise.
  56. ' The following sound constants are used by the PLAY command to
  57. ' produce music during the game.  To change the sounds you hear, change
  58. ' these constants.  Refer to the online help for PLAY for the correct format.
  59. ' To completely remove sound from the game set the constants equal to null.
  60. ' For example:  PLAYINTRO = ""
  61. CONST PLAYCLEARROW = "MBT255L16O4CDEGO6C" ' Tune played when a row is cleared.  Range unlimited.
  62. CONST PLAYINTRO = "MBT170O1L8CO2CO1CDCA-A-FGFA-F" ' Song played at game start.  Range unlimited.
  63. CONST PLAYGAMEOVER = "MBT255L16O6CO4GEDC" ' Song when the game is lost.  Range unlimited.
  64. CONST PLAYNEWBLOCK = "MBT160L28N20L24N5" ' Song when a new block is dropped.  Range unlimited.
  65. CONST PLAYWINGAME = "T255L16O6CO4GEDCCDEFGO6CEG" ' Song when game is won.  Range unlimited.
  66. ' The following CONST statements should not be changed like the ones above
  67. ' because the program relies on them being this value.
  68. CONST FALSE = 0 ' 0 means FALSE.
  69. CONST TRUE = NOT FALSE ' Anything but 0 can be thought of as TRUE.
  70. CONST SPACEBAR = 32 ' ASCII value for space character. Drops the shape.
  71. CONST DOWNARROW = 80 ' Down arrow key.  Drops the shape.
  72. CONST RIGHTARROW = 77 ' Right arrow key.  Moves the shape right.
  73. CONST UPARROW = 72 ' Up arrow key.  Rotates the shape.
  74. CONST LEFTARROW = 75 ' Left arrow key.  Moves the shape left.
  75. CONST DOWNARROW2 = 50 ' 2 key.  Drops the shape.
  76. CONST RIGHTARROW2 = 54 ' 6 key.  Moves the shape right.
  77. CONST UPARROW2 = 56 ' 8 key.  Rotates the shape.
  78. CONST LEFTARROW2 = 52 ' 4 key.  Moves the shape left.
  79. CONST UPARROW3 = 53 ' 5 key.  Rotates the shape.
  80. CONST QUIT = "Q" ' Q key.  Quits the game.
  81. CONST PAUSE = "P" ' P key.  Pauses the game.
  82. CONST XMATRIX = 3 ' Width of the matrix that forms each falling unit.  See the discussions in Suggested Changes #2 and #3.
  83. CONST YMATRIX = 1 ' Depth of the matrix that forms each falling unit.
  84. CONST BYTESPERBLOCK = 76 ' Number of bytes required to store one block in Screen mode 7.
  85. CONST BLOCKVOLUME = (XMATRIX + 1) * (YMATRIX + 1) ' Number of blocks in each shape.
  86. CONST ELEMENTSPERBLOCK = BLOCKVOLUME * BYTESPERBLOCK \ 2 ' Number of INTEGER array elements needed to store an image of a shape.
  87. CONST XSIZE = 13 ' Width, in pixels, of each block.  QBlocks assumes that the entire screen is 25 blocks wide.  Since the screen is 320 pixels wide, each block is approximately 13 pixels wide.
  88. CONST YSIZE = 8 ' Height, in pixels, of each block.  Again, QBlocks assumes that screen is 25 blocks high.  At 200 pixels down, each block is exactly 8 pixels high.
  89. CONST XOFFSET = 10 ' X position, in blocks, of the well.
  90. CONST YOFFSET = 2 ' Y position, in blocks, of the well.
  91. CONST WELLX = XSIZE * XOFFSET ' X position, in pixels, of the start of the well.
  92. CONST WELLY = YSIZE * YOFFSET ' Y position.
  93. CONST TILTVALUE = 9999000 ' Points required for QBlocks to tilt.
  94. CONST WELLCOLOR7 = 0 ' Well color for SCREEN 7.
  95. CONST WELLCOLOR1 = 0 ' Well color for SCREEN 1.
  96. CONST BORDERCOLOR1 = 8 ' Border color for SCREEN 1.
  97. CONST BORDERCOLOR7 = 15 ' Border color for SCREEN 7.
  98. TYPE BlockType ' Block datatype.
  99.     X AS INTEGER ' Horizontal location within the well.
  100.     Y AS INTEGER ' Vertical location within the well.
  101.     Style AS INTEGER ' Define shape (and color, indirectly).
  102.     Rotation AS INTEGER ' 4 possible values (0 to 3).
  103. ' SUB and FUNCTION declarations
  104. DECLARE FUNCTION CheckFit ()
  105. DECLARE FUNCTION GameOver ()
  106. DECLARE SUB AddBlockToWell ()
  107. DECLARE SUB CheckForFullRows ()
  108. DECLARE SUB Center (M$, Row)
  109. DECLARE SUB DeleteChunk (Highest%, Lowest%)
  110. DECLARE SUB DisplayIntro ()
  111. DECLARE SUB DisplayGameTitle ()
  112. DECLARE SUB DisplayChanges ()
  113. DECLARE SUB DrawBlock (X, Y, FillColor)
  114. DECLARE SUB InitScreen ()
  115. DECLARE SUB MakeInfoBox ()
  116. DECLARE SUB NewBlock ()
  117. DECLARE SUB PerformGame ()
  118. DECLARE SUB RedrawControls ()
  119. DECLARE SUB Show (b AS BlockType)
  120. DECLARE SUB UpdateScoring ()
  121. DECLARE SUB PutBlock (b AS BlockType)
  122. DECLARE SUB DrawAllShapes ()
  123. DECLARE SUB DrawPattern (Patttern)
  124. DECLARE SUB DrawPlayingField ()
  125. ' DIM SHARED indicates that a variable is available to all subprograms.
  126. ' Without this statement, a variable used in one subprogram cannot be
  127. ' used by another subprogram or the main program.
  128. DIM SHARED Level AS INTEGER ' Difficulty level.  0 is slowest, 9 is fastest.
  129. DIM SHARED WellBlocks(WELLWIDTH, WELLHEIGHT) AS INTEGER ' 2 dimensional array to hold the falling shapes that have stopped falling and become part of the well.
  130. DIM SHARED CurBlock AS BlockType ' The falling shape.
  131. DIM SHARED BlockShape(0 TO XMATRIX, 0 TO YMATRIX, 1 TO NUMSTYLES) ' Holds the data required to make each shape.  Values determined by the DATA statements at the end of this window.
  132. DIM SHARED PrevScore AS LONG ' Holds the previous level for scoring purposes.
  133. DIM SHARED Score AS LONG ' Score.
  134. DIM SHARED ScreenWidth AS INTEGER ' Width of the screen, in character-sized units.
  135. DIM SHARED ScreenMode AS INTEGER ' Value of the graphics screen mode used.
  136. DIM SHARED WellColor AS INTEGER ' Color inside the well.
  137. DIM SHARED BorderColor AS INTEGER ' Color of well border and text.
  138. DIM SHARED OldBlock AS BlockType ' An image of the last CurBlock.  Used to erase falling units when they move.
  139. DIM SHARED TargetTime AS SINGLE ' Time to move the shape down again.
  140. DIM SHARED GameTiltScore AS LONG ' Holds the value that this game will tilt at.
  141. DIM SHARED Temp(11175) AS INTEGER ' Used by several GET and PUT statements to store temporary screen images.
  142. DIM SHARED BlockColor(1 TO NUMSTYLES) AS INTEGER ' Block color array
  143. DIM SHARED BlockImage((NUMSTYLES * 4 + 3) * ELEMENTSPERBLOCK) AS INTEGER ' Holds the binary image of each rotation of each shape for the PutBlock subprogram to use.
  144. DIM KeyFlags AS INTEGER ' Internal state of the keyboard flags when game starts.  Hold the state so it can be restored when the games ends.
  145. DIM BadMode AS INTEGER ' Store the status of a valid screen mode.
  146. ON ERROR GOTO ScreenError ' Set up a place to jump to if an error occurs in the program.
  147. BadMode = FALSE
  148. ScreenMode = 7
  149. SCREEN ScreenMode ' Attempt to go into SCREEN 7 (EGA screen).
  150. IF BadMode = TRUE THEN ' If this attempt failed.
  151.     ScreenMode = 1
  152.     BadMode = FALSE
  153.     SCREEN ScreenMode ' Attempt to go into SCREEN 1 (CGA screen).
  154. ON ERROR GOTO 0 ' Turn off error handling.
  155. IF BadMode = TRUE THEN ' If no graphics adapter.
  156.     CLS
  157.     LOCATE 10, 12: PRINT "CGA, EGA Color, or VGA graphics required to run QBLOCKS.BAS"
  158.     RANDOMIZE TIMER ' Create a new sequence of random numbers based on the clock.
  159.     DisplayIntro ' Show the opening screen.
  160.     DEF SEG = 0 ' Set the current segment to the low memory area.
  161.     KeyFlags = PEEK(1047) ' Read the location that holds the keyboard flag.
  162.     IF (KeyFlags AND 32) = 0 THEN ' If the NUM LOCK key is off
  163.         POKE 1047, KeyFlays OR 32 ' set the NUM LOCK key to on.
  164.     END IF
  165.     DEF SEG ' Restore the default segment.
  166.     ' Read the pattern for each QBlocks shape.
  167.     FOR i = 1 TO NUMSTYLES ' Loop for the each shape
  168.         FOR j = 0 TO YMATRIX ' and for the Y and X dimensions of
  169.             FOR k = 0 TO XMATRIX ' each shape.
  170.                 READ BlockShape(k, j, i) ' Actually read the data.
  171.             NEXT k
  172.         NEXT j
  173.     NEXT i
  174.     DrawAllShapes ' Draw all shapes in all four rotations.
  175.     PerformGame ' Play the game until the player quits.
  176.     DisplayChanges ' Show the suggested changes.
  177.     DEF SEG = 0 ' Set the current segment back to low memory where the keyboard flags are.
  178.     POKE 1047, KeyFlags AND 233 ' Set the NUM LOCK key back to where it was at the game start.
  179.     DEF SEG ' Restore the current segment back to BASIC's data group area.
  180.     IF ScreenMode = 7 THEN PALETTE ' Restore the default color palette if SCREEN 7 was used.
  181. END ' End of the main program code.
  182. ' The DATA statements below define the block shapes used in the game.
  183. ' Each shape contains 8 blocks (4 x 2).  A "1" means that there
  184. ' is a block in that space; "0" means that the block is blank.  The pattern
  185. ' for Style 1, for example, creates a shape that is 4 blocks wide.
  186. ' To change an existing block's shape, change a "0" to a "1" or a "1" to
  187. ' a "0".  To add new shapes, insert new DATA statements with the same format
  188. ' as those below, after the last group of DATA statements (style 7).  Be sure
  189. ' to change the NUMSTYLES constant at the beginning of this program to reflect
  190. ' the new number of block shapes for the game.
  191. ' IMPORTANT! Creating a completely blank block will cause QBlocks to fail.
  192. ' Data for Style 1: Long
  193. DATA 1,1,1,1
  194. DATA 0,0,0,0
  195. ' Data for Style 2: L Right
  196. DATA 1,1,1,0
  197. DATA 0,0,1,0
  198. ' Data for Style 3: L Left
  199. DATA 0,1,1,1
  200. DATA 0,1,0,0
  201. ' Data for Style 4: Z Right
  202. DATA 1,1,0,0
  203. DATA 0,1,1,0
  204. ' Data for Style 5: Z Left
  205. DATA 0,1,1,0
  206. DATA 1,1,0,0
  207. ' Data for Style 6: T
  208. DATA 1,1,1,0
  209. DATA 0,1,0,0
  210. ' Data for Style 7: Square
  211. DATA 0,1,1,0
  212. DATA 0,1,1,0
  213. ScreenError: ' QBlocks uses this error handler to determine the highest available video mode.
  214. BadMode = TRUE
  215. '----------------------------------------------------------------------------
  216. ' AddBlockToWell
  217. '
  218. '    After a shape stops falling, put it into the WellBlocks array
  219. '    so later falling shapes know where to stop.
  220. '
  221. '           PARAMETERS:    None.
  222. '----------------------------------------------------------------------------
  223. SUB AddBlockToWell
  224.     FOR i = 0 TO XMATRIX ' Loop through all elements in the array.
  225.         FOR j = 0 TO YMATRIX
  226.             IF BlockShape(i, j, CurBlock.Style) = 1 THEN ' If there is a block in that space.
  227.                 SELECT CASE CurBlock.Rotation ' Use the Rotation to determine how the blocks should map into the WellBlocks array.
  228.                     CASE 0 ' No rotation.
  229.                         WellBlocks(CurBlock.X + i, CurBlock.Y + j) = CurBlock.Style
  230.                     CASE 1 ' Rotated 90 degrees clockwise.
  231.                         WellBlocks(CurBlock.X - j + 2, CurBlock.Y + i - 1) = CurBlock.Style
  232.                     CASE 2 ' Rotated 180 degrees.
  233.                         WellBlocks(CurBlock.X - i + 3, CurBlock.Y - j + 1) = CurBlock.Style
  234.                     CASE 3 ' Rotated 270 degrees clockwise.
  235.                         WellBlocks(CurBlock.X + j + 1, CurBlock.Y - i + 2) = CurBlock.Style
  236.                 END SELECT
  237.             END IF
  238.         NEXT j
  239.     NEXT i
  240. '----------------------------------------------------------------------------
  241. ' Center
  242. '
  243. '    Centers a string of text on a specified row.
  244. '
  245. '           PARAMETERS:    Text$ - Text to display on the screen.
  246. '                          Row   - Row on the screen where the text$ is
  247. '                                  displayed.
  248. '----------------------------------------------------------------------------
  249. SUB Center (text$, Row)
  250.     LOCATE Row, (ScreenWidth - LEN(text$)) \ 2 + 1
  251.     PRINT text$;
  252. '----------------------------------------------------------------------------
  253. ' CheckFit
  254. '
  255. '    Checks to see if the shape will fit into its new position.
  256. '    Returns TRUE if it fits and FALSE if it does not fit.
  257. '
  258. '           PARAMETERS:    None
  259. '
  260. '----------------------------------------------------------------------------
  261. FUNCTION CheckFit
  262.     CheckFit = TRUE ' Assume the shape will fit.
  263.     FOR i = 0 TO XMATRIX ' Loop through all the blocks in the
  264.         FOR j = 0 TO YMATRIX ' shape and see if any would
  265.             ' overlap blocks already in the well.
  266.             IF BlockShape(i, j, CurBlock.Style) = 1 THEN ' 1 means that space, within the falling shape, is filled with a block.
  267.                 SELECT CASE CurBlock.Rotation ' Base the check on the rotation of the shape.
  268.                     CASE 0 ' No rotation.
  269.                         NewX = CurBlock.X + i
  270.                         NewY = CurBlock.Y + j
  271.                     CASE 1 ' Rotated 90 degrees clockwise, or 270 degrees counterclockwise.
  272.                         NewX = CurBlock.X - j + 2
  273.                         NewY = CurBlock.Y + i - 1
  274.                     CASE 2 ' Rotated 180 degrees.
  275.                         NewX = CurBlock.X - i + 3
  276.                         NewY = CurBlock.Y - j + 1
  277.                     CASE 3 ' Rotated 270 degrees clockwise, or 90 degrees counterclockwise.
  278.                         NewX = CurBlock.X + j + 1
  279.                         NewY = CurBlock.Y - i + 2
  280.                 END SELECT
  281.                 ' Set CheckFit to false if the block would be out of the well.
  282.                 IF (NewX > WELLWIDTH - 1 OR NewX < 0 OR NewY > WELLHEIGHT - 1 OR NewY < 0) THEN
  283.                     CheckFit = FALSE
  284.                     EXIT FUNCTION
  285.                     ' Otherwise, set CheckFit to false if the block overlaps
  286.                     ' an existing block.
  287.                 ELSEIF WellBlocks(NewX, NewY) THEN
  288.                     CheckFit = FALSE
  289.                     EXIT FUNCTION
  290.                 END IF
  291.             END IF
  292.         NEXT j
  293.     NEXT i
  294. '----------------------------------------------------------------------------
  295. ' CheckForFullRows
  296. '
  297. '    Checks for filled rows.  If a row is filled, delete it and move
  298. '    the blocks above down to fill the deleted row.
  299. '
  300. '           PARAMETERS:   None
  301. '----------------------------------------------------------------------------
  302. SUB CheckForFullRows
  303.     DIM RowsToDelete(WELLHEIGHT) ' Temporary array to track rows that should be deleted.
  304.     NumRowsToDelete = 0
  305.     i = WELLHEIGHT ' Begin scanning from the bottom up.
  306.     DO
  307.         DeleteRow = TRUE ' Assume the row should be deleted.
  308.         j = 0
  309.         DO ' Scan within each row for blocks.
  310.             DeleteRow = DeleteRow * SGN(WellBlocks(j, i)) ' If any position is blank, DeleteRow is 0 (FALSE).
  311.             j = j + 1
  312.         LOOP WHILE DeleteRow = TRUE AND j < WELLWIDTH
  313.         IF DeleteRow = TRUE THEN
  314.             ' Walk up the rows and copy them down in the WellBlocks array.
  315.             NumRowsToDelete = NumRowsToDelete + 1 ' Number of rows to delete.
  316.             RowsToDelete(i - NumDeleted) = TRUE ' Mark the rows to be deleted, compensating for rows that have already been deleted below it.
  317.             NumDeleted = NumDeleted + 1 ' Compensates for rows that have been deleted already.
  318.             ' Logically delete the row by moving all WellBlocks values down.
  319.             FOR Row = i TO 1 STEP -1
  320.                 FOR Col = 0 TO WELLWIDTH
  321.                     WellBlocks(Col, Row) = WellBlocks(Col, Row - 1)
  322.                 NEXT Col
  323.             NEXT Row
  324.         ELSE ' This row will not be deleted.
  325.             i = i - 1
  326.         END IF
  327.     LOOP WHILE i >= 1 ' Stop looping when the top of the well is reached.
  328.     IF NumRowsToDelete > 0 THEN
  329.         Score = Score + 100 * NumRowsToDelete ' Give 100 points for every row.
  330.         ' Set Highest and Lowest such that any deleted row will initially set them.
  331.         Highest = -1
  332.         Lowest = 100
  333.         ' Find where the highest and lowest rows to delete are.
  334.         FOR i = WELLHEIGHT TO 1 STEP -1
  335.             IF RowsToDelete(i) = TRUE THEN
  336.                 IF i > Highest THEN Highest = i
  337.                 IF i < Lowest THEN Lowest = i
  338.             END IF
  339.         NEXT i
  340.         IF (Highest - Lowest) + 1 = NumRowsToDelete THEN ' Only one contiguous group of rows to delete.
  341.             DeleteChunk Highest, Lowest
  342.         ELSE ' Two groups of rows to delete.
  343.             ' Begin at Lowest and scan down for a row NOT to be deleted.
  344.             ' Then delete everything from Lowest to the row not to be deleted.
  345.             i = Lowest
  346.             DO WHILE i <= Highest
  347.                 IF RowsToDelete(i) = FALSE THEN
  348.                     DeleteChunk i - 1, Lowest
  349.                     EXIT DO
  350.                 ELSE
  351.                     i = i + 1
  352.                 END IF
  353.             LOOP
  354.             ' Now look for the second group and delete those rows.
  355.             Lowest = i
  356.             DO WHILE RowsToDelete(Lowest) = FALSE
  357.                 Lowest = Lowest + 1
  358.             LOOP
  359.             DeleteChunk Highest, Lowest
  360.         END IF
  361.     END IF
  362. '----------------------------------------------------------------------------
  363. ' DeleteChunk
  364. '
  365. '    Deletes a group of one or more rows.
  366. '
  367. '           PARAMETERS:    Highest - Highest row to delete (physically lowest
  368. '                                    on screen).
  369. '                          Lowest  - Lowest row to delete (physically highest
  370. '                                    on screen).
  371. '----------------------------------------------------------------------------
  372. SUB DeleteChunk (Highest, Lowest)
  373.     ' GET the image of the row to delete.
  374.     GET (WELLX, Lowest * YSIZE + WELLY)-(WELLX + WELLWIDTH * XSIZE, (Highest + 1) * YSIZE + WELLY - 1), Temp()
  375.     PLAY PLAYCLEARROW
  376.     ' Flash the rows 3 times.
  377.     FOR Flash = 1 TO 3
  378.         PUT (WELLX, Lowest * YSIZE + WELLY), Temp(), PRESET
  379.         DelayTime! = TIMER + .02
  380.         DO WHILE TIMER < DelayTime!: LOOP
  381.         PUT (WELLX, Lowest * YSIZE + WELLY), Temp(), PSET
  382.         DelayTime! = TIMER + .02
  383.         DO WHILE TIMER < DelayTime!: LOOP
  384.     NEXT Flash
  385.     ' Move all the rows above the deleted ones down.
  386.     GET (WELLX, WELLY)-(WELLX + WELLWIDTH * XSIZE, Lowest * YSIZE + WELLY), Temp()
  387.     PUT (WELLX, (Highest - Lowest + 1) * YSIZE + WELLY), Temp(), PSET
  388.     'Erase the area above the block which just moved down.
  389.     LINE (WELLX, WELLY)-(WELLX + WELLWIDTH * XSIZE, WELLY + (Highest - Lowest + 1) * YSIZE), WellColor, BF
  390. '----------------------------------------------------------------------------
  391. ' DisplayChanges
  392. '
  393. '    Displays list of changes that the player can easily make.
  394. '
  395. '           PARAMETERS:   None
  396. '----------------------------------------------------------------------------
  397. SUB DisplayChanges
  398.     DisplayGameTitle ' Print game title.
  399.     COLOR 7
  400.     Center "The following game characteristics can be easily changed from", 5
  401.     Center "within the QuickBASIC Interpreter.  To change the values of  ", 6
  402.     Center "these characteristics, locate the corresponding CONST or DATA", 7
  403.     Center "statements in the source code and change their values, then  ", 8
  404.     Center "restart the program (press Shift + F5).                      ", 9
  405.     COLOR 15
  406.     Center "Block shapes                         ", 11
  407.     Center "Block rotation                       ", 12
  408.     Center "Number of different block shapes     ", 13
  409.     Center "Score needed to advance to next level", 14
  410.     Center "Width of the game well               ", 15
  411.     Center "Height of the game well              ", 16
  412.     Center "Songs played during game             ", 17
  413.     COLOR 7
  414.     Center "The CONST statements and instructions on changing them are   ", 19
  415.     Center "located at the beginning of the main program.                ", 20
  416.     DO WHILE INKEY$ = "": LOOP ' Wait for any key to be pressed.
  417.     CLS ' Clear screen.
  418. '----------------------------------------------------------------------------
  419. ' DisplayGameTitle
  420. '
  421. '    Displays title of the game.
  422. '
  423. '           PARAMETERS:    None.
  424. '----------------------------------------------------------------------------
  425. SUB DisplayGameTitle
  426.     SCREEN 0
  427.     WIDTH 80, 25 ' Set width to 80, height to 25.
  428.     COLOR 4, 0 ' Set colors for red on black.
  429.     CLS ' Clear the screen.
  430.     ScreenWidth = 80 ' Set screen width variable to match current width.
  431.     ' Draw outline around screen with extended ASCII characters.
  432.     LOCATE 1, 2
  433.     PRINT CHR$(201); STRING$(76, 205); CHR$(187);
  434.     FOR i% = 2 TO 24
  435.         LOCATE i%, 2
  436.         PRINT CHR$(186); TAB(79); CHR$(186);
  437.     NEXT i%
  438.     LOCATE 25, 2
  439.     PRINT CHR$(200); STRING$(76, 205); CHR$(188);
  440.     'Print game title centered at top of screen
  441.     COLOR 0, 4
  442.     Center "      Microsoft      ", 1
  443.     Center "    Q B L O C K S    ", 2
  444.     Center "   Press any key to continue   ", 25 ' Center prompt on line 25.
  445.     COLOR 7, 0
  446. '----------------------------------------------------------------------------
  447. ' DisplayIntro
  448. '
  449. '    Explains the object of the game and how to play.
  450. '
  451. '           PARAMETERS:   None
  452. '----------------------------------------------------------------------------
  453. SUB DisplayIntro
  454.     CLS
  455.     DisplayGameTitle
  456.     Center "QBlocks challenges you to keep the well from filling.  Do this by", 5
  457.     Center "completely filling rows with blocks, making the rows disappear.  ", 6
  458.     Center "Move and rotate the falling shapes to get them into the best     ", 7
  459.     Center "position.  The game will get faster as you score more points.    ", 8
  460.     COLOR 4 ' Change foreground color for line to red.
  461.     Center STRING$(74, 196), 11 ' Put horizontal red line on screen.
  462.     COLOR 7 ' White (7) letters.        ' Change foreground color back to white
  463.     Center " Game Controls ", 11 ' Display game controls.
  464.     Center "     General                             Block Control      ", 13
  465.     Center "                                     (Rotate)", 15
  466.     Center "   P - Pause                                 " + CHR$(24) + " (or 5)   ", 16
  467.     Center "      Q - Quit                         (Left) " + CHR$(27) + "   " + CHR$(26) + " (Right)   ", 17
  468.     Center "                                    " + CHR$(25), 18
  469.     Center "                                          (Drop)      ", 19
  470.     DO ' Wait for any key to be pressed.
  471.         kbd$ = UCASE$(INKEY$)
  472.     LOOP WHILE kbd$ = ""
  473.     IF kbd$ = "Q" THEN 'Allow player to quit now
  474.         CLS
  475.         LOCATE 10, 30: PRINT "Really quit? (Y/N)";
  476.         DO
  477.             kbd$ = UCASE$(INKEY$)
  478.         LOOP WHILE kbd$ = ""
  479.         IF kbd$ = "Y" THEN
  480.             CLS
  481.             END
  482.         END IF
  483.     END IF
  484. '----------------------------------------------------------------------------
  485. ' DrawAllShapes
  486. '
  487. '    Quickly draws all shapes in all four rotations.  Uses GET
  488. '    to store the images so they can be PUT onto the screen
  489. '    later very quickly.
  490. '
  491. '           PARAMETERS:    None.
  492. '----------------------------------------------------------------------------
  493. SUB DrawAllShapes
  494.     DIM b AS BlockType
  495.     SCREEN ScreenMode ' Set the appropriate screen mode.
  496.     ' On EGA and VGA systems, appear to blank the screen.
  497.     IF ScreenMode = 7 THEN
  498.         DIM Colors(0 TO 15) ' DIM an array of 16 elements.  By default, all elements are 0.
  499.         PALETTE USING Colors() ' Redefine the colors all to 0.
  500.         FOR i = 1 TO NUMSTYLES ' Set block colors EGA, VGA
  501.             BlockColor(i) = ((i - 1) MOD 7) + 1
  502.         NEXT i
  503.     ELSE
  504.         FOR i = 1 TO NUMSTYLES 'Set block colors for CGA
  505.             BlockColor(i) = ((i - 1) MOD 3) + 1
  506.         NEXT i
  507.     END IF
  508.     CLS
  509.     Count = 0 ' Count determines how many shapes have been drawn on the screen and vertically where.
  510.     FOR shape = 1 TO NUMSTYLES ' Loop through all shapes.
  511.         RtSide = 4
  512.         DO
  513.             IF BlockShape(RtSide - 1, 0, shape) = 1 OR BlockShape(RtSide - 1, 1, shape) = 1 THEN EXIT DO
  514.             RtSide = RtSide - 1
  515.         LOOP UNTIL RtSide = 1
  516.         LtSide = 0
  517.         DO
  518.             IF BlockShape(LtSide, 0, shape) = 1 OR BlockShape(LtSide, 1, shape) = 1 THEN EXIT DO
  519.             LtSide = LtSide + 1
  520.         LOOP UNTIL LtSide = 3
  521.         FOR Rotation = 0 TO 3 ' Loop through all rotations.
  522.             b.X = Rotation * 4 + 2 ' Determine where to put the shape.
  523.             b.Y = Count + 2
  524.             b.Rotation = Rotation
  525.             b.Style = shape
  526.             Show b ' Draw the shape.
  527.             X = b.X: Y = b.Y
  528.             SELECT CASE Rotation ' Based on Rotation, determine where the shape really is on the screen.
  529.                 CASE 0 ' No rotation.
  530.                     x1 = X: x2 = X + RtSide: y1 = Y: y2 = Y + 2
  531.                 CASE 1 ' Rotated 90 degrees clockwise.
  532.                     x1 = X + 1: x2 = X + 3: y1 = Y - 1: y2 = Y + RtSide - 1
  533.                 CASE 2 ' 180 degrees.
  534.                     x1 = X: x2 = X + 4 - LtSide: y1 = Y: y2 = Y + 2
  535.                 CASE 3 ' Rotated 270 degrees clockwise.
  536.                     x1 = X + 1: x2 = X + 3: y1 = Y - 1: y2 = Y + 3 - LtSide
  537.             END SELECT
  538.             ' Store the image of the rotated shape into an array for fast recall later.
  539.             GET (x1 * XSIZE, y1 * YSIZE)-(x2 * XSIZE, y2 * YSIZE), BlockImage(((shape - 1) * 4 + Rotation) * ELEMENTSPERBLOCK)
  540.         NEXT Rotation
  541.         Count = Count + 5 ' Increase Count by 5 to leave at least one blank line between shapes.
  542.         IF Count = 20 THEN ' No space for any more shapes.
  543.             CLS
  544.             Count = 0
  545.         END IF
  546.     NEXT shape
  547.     CLS
  548.     ' Changes the color palette if SCREEN is used.
  549.     IF ScreenMode = 7 THEN
  550.         PALETTE ' Restore default color settings.
  551.         PALETTE 6, 14 ' Make brown (6) look like yellow (14).
  552.         PALETTE 14, 15 ' Make yellow (14) look like bright white (15).
  553.     END IF
  554. '----------------------------------------------------------------------------
  555. ' DrawBlock
  556. '
  557. '    Draws one block of a QBlocks shape.
  558. '
  559. '           PARAMETERS:    X         - Horizontal screen location.
  560. '                          Y         - Vertical screen location.
  561. '                          FillColor - The primary color of the block.
  562. '                                      The top and left edges will be the
  563. '                                      brighter shade of that color.
  564. '----------------------------------------------------------------------------
  565. SUB DrawBlock (X, Y, FillColor)
  566.     LINE (X * XSIZE + 2, Y * YSIZE + 2)-((X + 1) * XSIZE - 2, (Y + 1) * YSIZE - 2), FillColor, BF
  567.     LINE (X * XSIZE + 1, Y * YSIZE + 1)-((X + 1) * XSIZE - 1, Y * YSIZE + 1), FillColor + 8
  568.     LINE (X * XSIZE + 1, Y * YSIZE + 1)-(X * XSIZE + 1, (Y + 1) * YSIZE - 1), FillColor + 8
  569. '----------------------------------------------------------------------------
  570. ' DrawPattern
  571. '
  572. '    Draws a background pattern that is 32 pixels wide by 20 pixels
  573. '    deep.  Gets the pattern and duplicates it to fill the screen.
  574. '
  575. '           PARAMETERS:    Pattern - Which of the 10 available patterns to
  576. '                                    draw.
  577. '----------------------------------------------------------------------------
  578. SUB DrawPattern (Pattern)
  579.     CLS
  580.     X = 1: Y = 1
  581.     DIM Temp2(215) AS INTEGER ' Create an array to store the image.
  582.     ' Draw the pattern specified.
  583.     SELECT CASE Pattern
  584.         CASE 0
  585.             j = Y + 21
  586.             FOR i = X TO X + 27 STEP 3
  587.                 j = j - 2
  588.                 LINE (i, j)-(i, Y + 19), 12, BF
  589.             NEXT i
  590.             LINE (X, Y)-(X + 30, Y + 19), 4, B
  591.             LINE (X + 1, Y + 1)-(X + 31, Y + 18), 4, B
  592.         CASE 1
  593.             LINE (X, Y)-(X + 8, Y + 12), 1, BF
  594.             LINE (X + 9, Y + 8)-(X + 24, Y + 20), 2, BF
  595.             LINE (X + 25, Y)-(X + 32, Y + 12), 3, BF
  596.         CASE 2
  597.             LINE (X, Y)-(X + 29, Y + 18), X / 32 + 1, B
  598.             LINE (X + 1, Y + 1)-(X + 28, Y + 17), X / 32 + 2, B
  599.         CASE 3
  600.             FOR i = 0 TO 9 STEP 2
  601.                 LINE (X + i, Y + i)-(X + 29 - i, Y + 18 - i), i, B
  602.             NEXT i
  603.         CASE 4
  604.             j = 0
  605.             FOR i = 1 TO 30 STEP 3
  606.                 LINE (X + i, Y + j)-(X + 30 - i, Y + j), i
  607.                 LINE (X + i, Y + 19 - j)-(X + 30 - i, Y + 19 - j), i
  608.                 j = j + 2
  609.             NEXT i
  610.         CASE 5
  611.             LINE (X, Y)-(X + 29, Y + 4), 1, BF
  612.             LINE (X, Y)-(X + 4, Y + 18), 1, BF
  613.             LINE (X + 7, Y + 7)-(X + 29, Y + 11), 5, BF
  614.             LINE (X + 7, Y + 7)-(X + 11, Y + 18), 5, BF
  615.             LINE (X + 14, Y + 14)-(X + 29, Y + 18), 4, BF
  616.         CASE 6
  617.             LINE (X + 15, Y)-(X + 17, Y + 19), 1
  618.             LINE (X, Y + 9)-(X + 31, Y + 11), 2
  619.             LINE (X, Y + 1)-(X + 31, Y + 18), 9
  620.             LINE (X + 30, Y)-(X + 1, Y + 19), 10
  621.         CASE 7
  622.             FOR i = 1 TO 6
  623.                 CIRCLE (X + 16, Y + 10), i, i
  624.             NEXT i
  625.         CASE 8
  626.             FOR i = X TO X + 30 STEP 10
  627.                 CIRCLE (i, Y + 9), 10, Y / 20 + 1
  628.             NEXT i
  629.         CASE 9
  630.             LINE (X + 1, Y)-(X + 1, Y + 18), 3
  631.             LINE (X + 1, Y)-(X + 12, Y + 18), 3
  632.             LINE (X + 1, Y + 18)-(X + 12, Y + 18), 3
  633.             LINE (X + 30, Y)-(X + 30, Y + 18), 3
  634.             LINE (X + 30, Y)-(X + 19, Y + 18), 3
  635.             LINE (X + 30, Y + 18)-(X + 19, Y + 18), 3
  636.             LINE (X + 4, Y)-(X + 26, Y), 1
  637.             LINE (X + 4, Y)-(X + 15, Y + 18), 1
  638.             LINE (X + 26, Y)-(X + 15, Y + 18), 1
  639.     END SELECT
  640.     GET (0, 0)-(31, 19), Temp2() ' GET the image.
  641.     ' Duplicate the image 10 times across by 10 times down.
  642.     FOR H = 0 TO 319 STEP 32
  643.         FOR V = 0 TO 199 STEP 20
  644.             PUT (H, V), Temp2(), PSET
  645.         NEXT V
  646.     NEXT H
  647. '----------------------------------------------------------------------------
  648. ' DrawPlayingField
  649. '
  650. '    Draws the playing field, including the well, the title, the
  651. '    score/level box, etc.
  652. '
  653. '           PARAMETERS:   None
  654. '----------------------------------------------------------------------------
  655. SUB DrawPlayingField
  656.     SELECT CASE ScreenMode ' Choose the screen colors based on the current mode.
  657.         CASE 7
  658.             WellColor = WELLCOLOR7
  659.             BorderColor = BORDERCOLOR7
  660.         CASE ELSE ' Setup for SCREEN 1.
  661.             WellColor = WELLCOLOR1
  662.             BorderColor = BORDERCOLOR1
  663.     END SELECT
  664.     ScreenWidth = 40 ' Set to proper width and colors.
  665.     ' Draw the background pattern.
  666.     DrawPattern Level
  667.     ' Draw the well box.
  668.     LINE (WELLX - 1, WELLY - 5)-(WELLX + WELLWIDTH * XSIZE + 1, WELLY + WELLHEIGHT * YSIZE + 1), WellColor, BF
  669.     LINE (WELLX - 1, WELLY - 5)-(WELLX + WELLWIDTH * XSIZE + 1, WELLY + WELLHEIGHT * YSIZE + 1), BorderColor, B
  670.     ' Draw the title box.
  671.     LINE (XSIZE, WELLY - 5)-(XSIZE * 8, WELLY + 12), WellColor, BF
  672.     LINE (XSIZE, WELLY - 5)-(XSIZE * 8, WELLY + 12), BorderColor, B
  673.     ' Draw the scoring box.
  674.     LINE (XSIZE, WELLY + 20)-(WELLX - 2 * XSIZE, 78), WellColor, BF
  675.     LINE (XSIZE, WELLY + 20)-(WELLX - 2 * XSIZE, 78), BorderColor, B
  676.     MakeInfoBox ' Draw the Information Box.
  677.     COLOR 12
  678.     LOCATE 3, 5: PRINT "QBLOCKS" ' Center the program name on line 2.
  679.     COLOR BorderColor
  680.     ' Draw the scoring area.
  681.     LOCATE 6, 4: PRINT "Score:";
  682.     LOCATE 7, 4: PRINT USING "#,###,###"; Score
  683.     LOCATE 9, 4: PRINT USING "Level: ##"; Level
  684. '----------------------------------------------------------------------------
  685. ' GameOver
  686. '
  687. '    Ends the game and asks the player if he/she wants to play
  688. '    again.  GameOver returns TRUE if the player wishes to stop
  689. '    or FALSE if the player wants another game.
  690. '
  691. '           PARAMETERS:   None
  692. '----------------------------------------------------------------------------
  693. FUNCTION GameOver
  694.     PLAY PLAYGAMEOVER ' Play the game over tune.
  695.     MakeInfoBox
  696.     DO WHILE INKEY$ <> "": LOOP ' Clear the keyboard buffer.
  697.     ' Put Game Over messages into the InfoBox.
  698.     LOCATE 14, 4: PRINT "Game Over"
  699.     LOCATE 17, 6: PRINT "Play"
  700.     LOCATE 18, 5: PRINT "again?"
  701.     LOCATE 20, 6: PRINT "(Y/N)"
  702.     ' Wait for the player to press either Y or N.
  703.     DO
  704.         a$ = UCASE$(INKEY$) ' UCASE$ assures that the key will be uppercase.  This eliminates the need to check for y and n in addition to Y and N.
  705.     LOOP UNTIL a$ = "Y" OR a$ = "N"
  706.     IF a$ = "Y" THEN ' If player selects "Y",
  707.         GameOver = FALSE ' game is not over,
  708.     ELSE ' otherwise
  709.         GameOver = TRUE ' the game is over.
  710.     END IF
  711. '----------------------------------------------------------------------------
  712. ' InitScreen
  713. '
  714. '    Draws the playing field and ask for the desired starting level.
  715. '
  716. '           PARAMETERS:   None
  717. '----------------------------------------------------------------------------
  718. SUB InitScreen
  719.     DrawPlayingField ' Draw playing field assuming Level 0.
  720.     ' Prompt for starting level.
  721.     COLOR 12 ' Change foreground color to bright red.
  722.     LOCATE 14, 5: PRINT "Select";
  723.     LOCATE 16, 5: PRINT "start";
  724.     LOCATE 18, 5: PRINT "level?";
  725.     LOCATE 20, 5: PRINT "(0 - 9)";
  726.     COLOR BorderColor ' Restore the default text color to BorderColor (white).
  727.     Level = TRUE ' Use level as flag as well as a real value.  Level remain TRUE if Q (Quit) is pressed instead of a level.
  728.     ' Get a value for Level or accept a Q.
  729.     DO
  730.         a$ = UCASE$(INKEY$)
  731.     LOOP WHILE (a$ > "9" OR a$ < "0") AND a$ <> "Q"
  732.     IF a$ = "Q" THEN
  733.         EXIT SUB
  734.     ELSE
  735.         Level = VAL(a$)
  736.     END IF
  737.     IF Level > 0 THEN DrawPlayingField ' Draw new playing field because the background pattern depends on the level.
  738.     RedrawControls ' Draw the controls.
  739. '----------------------------------------------------------------------------
  740. ' MakeInfoBox
  741. '
  742. '    Draws the information box.
  743. '
  744. '           PARAMETERS:   None
  745. '----------------------------------------------------------------------------
  746. SUB MakeInfoBox
  747.     LINE (WELLX - 9 * XSIZE, 90)-(WELLX - 2 * XSIZE, 185), WellColor, BF ' Clear the Info area.
  748.     LINE (WELLX - 9 * XSIZE, 90)-(WELLX - 2 * XSIZE, 185), BorderColor, B ' Draw a border around it.
  749. '----------------------------------------------------------------------------
  750. ' NewBlock
  751. '
  752. '    Initializes a new falling shape about to enter the well.
  753. '
  754. '           PARAMETERS:   None
  755. '----------------------------------------------------------------------------
  756. SUB NewBlock
  757.     CurBlock.Style = INT(RND(1) * NUMSTYLES) + 1 ' Randomly pick a block style.
  758.     CurBlock.X = (WELLWIDTH \ 2) - 1 ' Put the new shape in the horizontal middle of the well
  759.     CurBlock.Y = 0 ' and at the top of the well.
  760.     CurBlock.Rotation = 0 ' Begin with no rotation.
  761.     PLAY PLAYNEWBLOCK
  762. '----------------------------------------------------------------------------
  763. ' PerformGame
  764. '
  765. '    Continues to play the game until the player quits.
  766. '
  767. '           PARAMETERS:   None
  768. '----------------------------------------------------------------------------
  769. SUB PerformGame
  770.     DO ' Loop for repetitive games
  771.         a$ = ""
  772.         ERASE WellBlocks ' Set all the elements in the WellBlocks array to 0.
  773.         Score = 0 ' Clear initial score.
  774.         Level = 0 ' Assume Level 0.
  775.         PrevScore = BASESCORE - NEXTLEVEL ' Set score needed to get to first level
  776.         GameTiltScore = WINGAME ' Set the initial win game value.
  777.         InitScreen ' Prepare the screen and get the difficulty level.
  778.         IF Level = -1 THEN EXIT SUB ' Player pressed Q instead of a level.
  779.         TargetTime = TIMER + 1 / (Level + 1) ' TargetTime is when the falling shape will move down again.
  780.         DO ' Create new falling shapes until the game is over.
  781.             DoneWithThisBlock = FALSE ' This falling shape is not done falling yet.
  782.             NewBlock ' Create a new falling unit.
  783.             IF CheckFit = FALSE THEN EXIT DO ' If it does not fit, then the game is over.
  784.             PutBlock CurBlock ' Display the new shape.
  785.             DO ' Continue dropping the falling shape.
  786.                 OldBlock = CurBlock ' Save current falling shape for possible later use.
  787.                 DO ' Loop until enough time elapses.
  788.                     ValidEvent = TRUE ' Assume a key was pressed.
  789.                     ans$ = UCASE$(INKEY$)
  790.                     IF ans$ = PAUSE OR ans$ = QUIT THEN
  791.                         MakeInfoBox
  792.                         ' SELECT CASE will do different actions based on the
  793.                         ' value of the SELECTED variable.
  794.                         SELECT CASE ans$
  795.                             CASE PAUSE
  796.                                 SOUND 1100, .75
  797.                                 LOCATE 16, 6: PRINT "GAME";
  798.                                 LOCATE 18, 5: PRINT "PAUSED";
  799.                                 DO WHILE INKEY$ = "": LOOP ' Wait until another key is pressed.
  800.                             CASE QUIT
  801.                                 ' Play sounds to tell the player that Q was pressed.
  802.                                 SOUND 1600, 1
  803.                                 SOUND 1000, .75
  804.                                 ' Confirm that the player really wants to quit.
  805.                                 LOCATE 15, 5: PRINT "Really";
  806.                                 LOCATE 17, 6: PRINT "quit?";
  807.                                 LOCATE 19, 6: PRINT "(Y/N)";
  808.                                 DO
  809.                                     a$ = UCASE$(INKEY$)
  810.                                 LOOP UNTIL a$ <> ""
  811.                                 IF a$ = "Y" THEN EXIT SUB
  812.                         END SELECT
  813.                         RedrawControls ' Redraw controls if either Q or P is pressed.
  814.                     ELSE ' A key was pressed but not Q or P.
  815.                         ans = ASC(RIGHT$(CHR$(0) + ans$, 1)) ' Convert the key press to an ASCII code for faster processing.
  816.                         SELECT CASE ans
  817.                             CASE DOWNARROW, DOWNARROW2, SPACEBAR ' Drop shape immediately.
  818.                                 DO ' Loop to drop the falling unit one row at a time.
  819.                                     CurBlock.Y = CurBlock.Y + 1
  820.                                 LOOP WHILE CheckFit = TRUE ' Keep looping while the falling unit isn't stopped.
  821.                                 CurBlock.Y = CurBlock.Y - 1 ' Went one down too far, restore to previous.
  822.                                 TargetTime = TIMER - 1 ' Ensure that the shape falls immediately.
  823.                             CASE RIGHTARROW, RIGHTARROW2
  824.                                 CurBlock.X = CurBlock.X + 1 ' Move falling unit right.
  825.                             CASE LEFTARROW, LEFTARROW2
  826.                                 CurBlock.X = CurBlock.X - 1 ' Move falling unit left.
  827.                             CASE UPARROW, UPARROW2, UPARROW3
  828.                                 CurBlock.Rotation = ((CurBlock.Rotation + ROTATEDIR) MOD 4) ' Rotate falling unit.
  829.                             CASE ELSE
  830.                                 ValidEvent = FALSE
  831.                         END SELECT
  832.                         IF ValidEvent = TRUE THEN
  833.                             IF CheckFit = TRUE THEN ' If the move is valid and the shape fits in the new position,
  834.                                 PutBlock OldBlock ' erase the shape from its old position
  835.                                 PutBlock CurBlock ' and display it in the new position.
  836.                                 OldBlock = CurBlock
  837.                             ELSE
  838.                                 CurBlock = OldBlock ' If it does not fit then reset CurBlock to the OldBlock.
  839.                             END IF
  840.                         END IF
  841.                     END IF
  842.                 LOOP UNTIL TIMER >= TargetTime ' Keep repeating the loop until it is time to drop the shape.  This allows many horizontal movements and rotations per vertical step.
  843.                 TargetTime = TIMER + 1 / (Level + 1) ' The player has less time between vertical movements as the skill level increases.
  844.                 CurBlock.Y = CurBlock.Y + 1 ' Try to drop the falling unit one row.
  845.                 IF CheckFit = FALSE THEN ' Cannot fall any more.
  846.                     DoneWithThisBlock = TRUE ' Done with this block.
  847.                     CurBlock = OldBlock
  848.                 END IF
  849.                 PutBlock OldBlock ' Erase the falling shape from the old position,
  850.                 PutBlock CurBlock ' and display it in the new position.
  851.                 OldBlock = CurBlock
  852.             LOOP UNTIL DoneWithThisBlock ' Continue getting keys and moving shapes until the falling shape stops.
  853.             AddBlockToWell ' Shape has stopped so logically add it to the well.
  854.             CheckForFullRows ' Check to see if a row(s) is now full.  If so, deletes it.
  855.             UpdateScoring ' Use the UpdateScoring subprogram to add to the score.
  856.             IF Score >= GameTiltScore THEN ' See if the score has hit the tilt score.
  857.                 PLAY PLAYWINGAME
  858.                 MakeInfoBox
  859.                 LOCATE 13, 5: PRINT USING "#######"; Score
  860.                 PLAY PLAYWINGAME
  861.                 IF GameTiltScore = TILTVALUE THEN ' If the player has tilted the game.
  862.                     LOCATE 15, 4: PRINT "GAME TILT"
  863.                     LOCATE 17, 5: PRINT "You are"
  864.                     LOCATE 18, 4: PRINT "Awesome!"
  865.                     LOCATE 20, 4: PRINT "Press any"
  866.                     LOCATE 21, 6: PRINT "key..."
  867.                     PLAY PLAYWINGAME
  868.                     DO WHILE INKEY$ = "": LOOP
  869.                     EXIT SUB
  870.                 ELSE ' If they just met the WINGAME value.
  871.                     LOCATE 15, 4: PRINT "YOU WON!"
  872.                     LOCATE 17, 5: PRINT "Want to"
  873.                     LOCATE 18, 4: PRINT "continue"
  874.                     LOCATE 20, 6: PRINT "(Y/N)"
  875.                     DO ' DO loop to wait for the player to press anything.
  876.                         a$ = UCASE$(INKEY$) ' The UCASE$ function assures that a$ always has an uppercase letter in it.
  877.                     LOOP UNTIL a$ <> ""
  878.                     IF a$ <> "Y" THEN EXIT DO ' Exit this main loop if the player pressed anything but Y.
  879.                     GameTiltScore = TILTVALUE ' Reset to the tilt value.
  880.                     RedrawControls
  881.                 END IF
  882.             END IF
  883.         LOOP ' Unconditional loop.  Each game is stopped by the EXIT DO command at the top of this loop that executes when a new block will not fit in the well.
  884.     LOOP UNTIL GameOver ' GameOver is always TRUE (-1) unless the user presses X or the well is full.
  885. '----------------------------------------------------------------------------
  886. ' PutBlock
  887. '
  888. '    Uses very fast graphics PUT command to draw the shape.
  889. '
  890. '           PARAMETERS:    B - Block to be put onto the screen.
  891. '----------------------------------------------------------------------------
  892. SUB PutBlock (b AS BlockType)
  893.     SELECT CASE b.Rotation ' Base exact placement on the rotation.
  894.         CASE 0 ' No rotation.
  895.             x1 = b.X: y1 = b.Y
  896.         CASE 1 ' Rotated 90 degrees clockwise, or 270 degrees counterclockwise.
  897.             x1 = b.X + 1: y1 = b.Y - 1
  898.         CASE 2 ' Rotated 180 degrees.
  899.             x1 = b.X: y1 = b.Y
  900.         CASE 3 ' Rotated 270 degrees clockwise, or 90 degrees counterclockwise.
  901.             x1 = b.X + 1: y1 = b.Y - 1
  902.     END SELECT
  903.     ' Actually PUT the rotated shape on the screen.  The XOR option makes the
  904.     ' new image blend with whatever used to be there in such a way that
  905.     ' identical colors cancel each other out.  Therefore, one PUT with the XOR
  906.     ' option can draw an object while the second PUT to that same location
  907.     ' erases it without affecting anything else near it.  Often used for animation.
  908.     PUT (x1 * XSIZE + WELLX, y1 * YSIZE + WELLY), BlockImage(((b.Style - 1) * 4 + b.Rotation) * ELEMENTSPERBLOCK), XOR ' XOR mixes what used to be there on the screen with the new image.  Two identical colors cancel each other.
  909. '----------------------------------------------------------------------------
  910. ' RedrawControls
  911. '
  912. '    Puts control keys information into the information box.
  913. '
  914. '           PARAMETERS:   None
  915. '----------------------------------------------------------------------------
  916. SUB RedrawControls
  917.     ' Draw the InfoBox and erase anything that used to be in it.
  918.     MakeInfoBox
  919.     ' Print the key assignments within the Info Box.
  920.     COLOR BorderColor
  921.     LOCATE 13, 4: PRINT "Controls"
  922.     LOCATE 14, 4: PRINT "--------"
  923.     LOCATE 15, 4: PRINT CHR$(24) + " = Turn"
  924.     LOCATE 16, 4: PRINT CHR$(27) + " = Left"
  925.     LOCATE 17, 4: PRINT CHR$(26) + " = Right"
  926.     LOCATE 18, 4: PRINT CHR$(25) + " = Drop"
  927.     LOCATE 20, 4: PRINT "P = Pause"
  928.     LOCATE 21, 4: PRINT "Q = Quit"
  929. '----------------------------------------------------------------------------
  930. ' Show
  931. '
  932. '    Draws the falling shape one block at a time.  Only used by
  933. '    DisplayAllShapes.  After that, PutBlock draws all falling
  934. '    shapes.
  935. '
  936. '           PARAMETERS:    B - Block to be put onto the screen.
  937. '----------------------------------------------------------------------------
  938. SUB Show (b AS BlockType)
  939.     ' Loop through all possible block locations.
  940.     FOR i = 0 TO XMATRIX
  941.         FOR j = 0 TO YMATRIX
  942.             IF BlockShape(i, j, b.Style) = 1 THEN ' 1 means there is a block there.
  943.                 SELECT CASE b.Rotation ' Exact screen position is determined by the rotation.
  944.                     CASE 0 ' No rotation.
  945.                         DrawBlock b.X + i, b.Y + j, BlockColor(b.Style)
  946.                     CASE 1 ' Rotated 90 degrees clockwise, or 270 degrees counterclockwise.
  947.                         DrawBlock b.X - j + 2, b.Y - 1 + i, BlockColor(b.Style)
  948.                     CASE 2 ' Rotated 180 degrees.
  949.                         DrawBlock b.X + 3 - i, b.Y - j + 1, BlockColor(b.Style)
  950.                     CASE 3 ' Rotated 270 degrees clockwise, or 90 degrees counterclockwise.
  951.                         DrawBlock b.X + j + 1, b.Y - i + 2, BlockColor(b.Style)
  952.                 END SELECT
  953.             END IF
  954.         NEXT j
  955.     NEXT i
  956. '---------------------------------------------------------------------------
  957. ' UpdateScoring
  958. '
  959. '    Puts the new score on the screen.  Checks if the new score forces
  960. '    a new level.  If so, change the background pattern to match the
  961. '    new level.
  962. '
  963. '           PARAMETERS:     None
  964. '----------------------------------------------------------------------------
  965. SUB UpdateScoring
  966.     ' Increase the level if the score is high enough and the level is not
  967.     ' maximum already.
  968.     IF Level < 9 AND Score >= (NEXTLEVEL * (Level + 1) + PrevScore) THEN
  969.         ' Store the entire well image to quickly PUT it back after the
  970.         ' background changes.
  971.         GET (WELLX, WELLY)-(WELLX + WELLWIDTH * XSIZE, WELLY + WELLHEIGHT * YSIZE), Temp()
  972.         PrevScore = Score ' Save previous Score for next level.
  973.         Level = Level + 1
  974.         DrawPlayingField ' Draw playing field again, this time with the new background pattern.
  975.         PUT (WELLX, WELLY), Temp() ' Restore the image of the old well.
  976.         RedrawControls ' Show the controls again.
  977.     END IF
  978.     LOCATE 7, 4: PRINT USING "#,###,###"; Score ' Print the score and level.
  979.  
  980.  

Yes, nice program for it's tiny screen size don't like def seg and all the peak and poking. The play is good.

Oh! did not notice anything unusual with compile time, maybe because I am not compiling a bunch of blank lines? ;-))
« Last Edit: January 30, 2021, 11:06:38 am by bplus »

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Qbasic Tetris clone takes many minutes to be compiled!
« Reply #2 on: January 30, 2021, 09:02:06 pm »
I love it! Reminds me of the Tetris that a classroom of students made back in the 90's from QBasic. The teacher asked me to put it on my QBasic website back then so I did. :)

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Qbasic Tetris clone takes many minutes to be compiled!
« Reply #3 on: January 31, 2021, 05:05:53 am »
I remember this version... But somehow it looked a lot bigger on my old monitors.... Still a cool game!
Logic is the beginning of wisdom.

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Qbasic Tetris clone takes many minutes to be compiled!
« Reply #4 on: February 01, 2021, 05:50:01 pm »
Thanks Bplus to put out the real issue....
between the code posted by me and the code posted by you there are (3529-1004) 2525 blank lines!

Interesting issue.
So the compiler wastes its time compiling null strings of void lines of code. But who is the bad boy that passes all those null strings to the compiler?

I have read that compiler/interpreter jumps  spaces and void lines... it seems no this time.
Programming isn't difficult, only it's  consuming time and coffee