home *** CD-ROM | disk | FTP | other *** search
/ Sunny 1,000 Collection / SUNNY1000.iso / Files / W31 / Tetris / FGWTET11.ZIP / TETRIS.PAS < prev    next >
Pascal/Delphi Source File  |  1995-10-31  |  26KB  |  833 lines

  1. unit Tetris;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  7.   Forms, Dialogs, FGWinG, ExtCtrls, StdCtrls, Buttons, MMSystem;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     Panel1: TPanel;
  12.     Button1: TButton;
  13.     Timer1: TTimer;
  14.     Header1: THeader;
  15.     procedure AppOnActivate(Sender: Tobject);
  16.     procedure FormCreate(Sender: TObject);
  17.     procedure FormDestroy(Sender: TObject);
  18.     procedure FormPaint(Sender: TObject);
  19.     procedure FormResize(Sender: TObject);
  20.     procedure drop_block(Sender: TObject);
  21.     procedure pause(Sender: TObject);
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.  
  27. {**********************************************************************}
  28. implementation
  29.  
  30. {$R *.DFM}
  31. type
  32.   _block = record                         {Tetris block}
  33.      data : array[0..63] of byte;         {bitmap}
  34.      x: integer;                          {x coordinate}
  35.      y: integer;                          {y coordinate}
  36.      pattern : array [0..8] of byte;      {block pattern}
  37.   end;
  38.  
  39. var
  40.   datapath : String;
  41.   dc : hDC;                               {device context}
  42.   hpal : hPalette;                        {palette handle}
  43.   RGBvalues : array [0..767] of byte;
  44.  
  45.   vb1,vb2             : integer;          {virtual buffer handles}
  46.   vb_width, vb_height : longint;          {dimensions of main virtual buffer}
  47.   cxWidth, cyHeight   : integer;          {dimensions of window}
  48.  
  49.   board : array [-3..21,-2..11] of boolean; {20 x 10 grid with edges}
  50.   block : array[0..7] of _block;          {array of block records}
  51.  
  52.   explosion1 : array[0..31]  of byte;     {explosion bitmaps}
  53.   explosion2 : array[0..25]  of byte;
  54.   langolier1 : array[0..142] of byte;     {little munchy critters}
  55.   langolier2 : array[0..143]  of byte;
  56.   current    : integer;                   {number of current block (1-8)}
  57.   next_block : integer;                   {next block becomes current}
  58.   do_rotate  : boolean;                   {okay to rotate?}
  59.   released   : boolean;                   {button press released?}
  60.   moved      : boolean;                   {block moved left or right?}
  61.   can_move   : boolean;                   {can move?}
  62.   score      : word;                      {points are kept here }
  63.   Jay_Leno   : boolean;                   {Jay speaks once per game}
  64.  
  65. const
  66.   pattern :    array[0..7,0..8] of byte = (
  67.     (0,0,0, 1,1,1, 0,0,0),                {this is how blocks are formed}
  68.     (0,0,0, 0,1,1, 1,1,0),
  69.     (0,0,0, 1,1,1, 0,0,1),
  70.     (0,0,0, 0,1,1, 0,1,1),
  71.     (0,0,0, 0,1,0, 1,1,1),
  72.     (0,0,0, 0,0,1, 1,1,1),
  73.     (0,0,0, 1,0,1, 1,1,1),
  74.     (0,0,0, 1,1,0, 0,1,1));
  75.  
  76. {forward declarations}
  77. procedure build_screen;               forward;
  78. function  can_move_down: boolean;     forward;
  79. function  can_move_left: boolean;     forward;
  80. function  can_move_right: boolean;    forward;
  81. procedure check_rows;                 forward;
  82. procedure clear_block;                forward;
  83. procedure fill_color_palette;         forward;
  84. procedure fix_grid;                   forward;
  85. procedure get_blocks;                 forward;
  86. procedure new_game;                   forward;
  87. procedure new_block;                  forward;
  88. procedure put_block;                  forward;
  89. procedure remove_row(row: integer);   forward;
  90. procedure rotate;                     forward;
  91. procedure tetris_paste;               forward;
  92. procedure paste(x1,x2,y1,y2:integer); forward;
  93.  
  94. {**********************************************************************}
  95. procedure TForm1.AppOnActivate(Sender: TObject);
  96. begin
  97.   fg_realize(hpal);
  98.   Invalidate;
  99. end;
  100.  
  101. {**********************************************************************}
  102. procedure TForm1.FormCreate(Sender: TObject);
  103. var
  104.   i : integer;
  105. begin
  106.   { set up the device context }
  107.   dc := GetDC(Form1.Handle);
  108.   fg_setdc(dc);
  109.  
  110.   { set up the logical palette }
  111.   fill_color_palette;
  112.   hpal := fg_logpal(10,236,RGBvalues);
  113.   fg_realize(hpal);
  114.  
  115.   {initialize the virtual buffers}
  116.   fg_vbinit;
  117.   vb2 := fg_vballoc(88,16); {temporary storage for explosions}
  118.   fg_vbopen(vb2);
  119.   fg_vbcolors;
  120.   vb1 := fg_vballoc(vb_width,vb_height); {primary virtual buffer}
  121.   fg_vbopen(vb1);
  122.   fg_vbcolors;
  123.  
  124.   {set up the application's OnActivate handler }
  125.   Application.OnActivate := AppOnActivate;
  126.  
  127.   {assume resources stored in same directory as EXE file}
  128.   datapath := paramstr(0);
  129.   i := length(datapath);
  130.   while i > 0 do
  131.     begin
  132.       If datapath[i] = '\' Then
  133.       begin
  134.         datapath := copy(datapath,1,i);
  135.         i := 1;
  136.       end;
  137.       dec(i);
  138.     end;
  139.  
  140.   {read the graphics data & prepare to play game}
  141.   get_blocks;
  142.   build_screen;
  143.   randomize;
  144.   new_game;
  145.   new_block;
  146.   do_rotate := False;
  147.   Timer1.Enabled := True;
  148. end;
  149.  
  150. {**********************************************************************}
  151. procedure TForm1.FormDestroy(Sender: TObject);
  152. begin
  153.   fg_vbclose;
  154.   fg_vbfree(vb1);
  155.   fg_vbfree(vb2);
  156.   fg_vbfin;
  157.   DeleteObject(hpal);
  158.   ReleaseDC(Form1.Handle,dc);
  159. end;
  160.  
  161. {**********************************************************************}
  162. procedure TForm1.FormPaint(Sender: TObject);
  163. begin
  164.   fg_vbscale(0,fg_getmaxx,0,fg_getmaxy,0,cxWidth,0,cyHeight);
  165. end;
  166.  
  167. {**********************************************************************}
  168. procedure TForm1.FormResize(Sender: TObject);
  169. begin
  170.   cxWidth := ClientWidth-1;
  171.   cyHeight := ClientHeight-1;
  172. end;
  173.  
  174. {**********************************************************************}
  175. procedure TForm1.pause(Sender: TObject);
  176. begin
  177.   if timer1.enabled = True then
  178.     timer1.enabled := False
  179.   else
  180.     timer1.enabled := True;
  181. end;
  182.  
  183. {**********************************************************************}
  184. procedure TForm1.drop_block(Sender: TObject);
  185. var
  186.   x1,x2 : longint;
  187.   game_over : boolean;
  188.   msg: tMsg;
  189.   xmin,xmax,ymin,ymax : integer;
  190. begin
  191.   {check for game over}
  192.   game_over := False;
  193.   if (block[current].y = 24) and (not can_move_down) then
  194.   begin
  195.     game_over := True;
  196.     timer1.enabled := False;
  197.     if  MessageDlg ('Game Over. Play Again?',mtCustom,
  198.        [mbYes,mbNo], 0) = mrYes then
  199.     begin
  200.       build_screen;
  201.       new_game;
  202.       new_block;
  203.       timer1.enabled := True;
  204.     end
  205.     else
  206.       Halt(0);
  207.   end;
  208.   if game_over then exit;
  209.  
  210.   xmin := block[current].x;
  211.   xmax := block[current].x+24;
  212.   ymin := block[current].y-24;
  213.   ymax := block[current].y;
  214.  
  215.   clear_block;
  216.   moved := True;
  217.   if can_move then
  218.     begin
  219.     {move left}
  220.     if (fg_kbtest(75)=1) and (can_move_left) then
  221.     begin
  222.       block[current].x := block[current].x-8;
  223.       dec(xmin,8);
  224.       moved := True;
  225.       can_move := False;
  226.     end
  227.  
  228.     {move right}
  229.     else if (fg_kbtest(77)=1) and (can_move_right) then
  230.     begin
  231.       block[current].x := block[current].x+8;
  232.       inc(xmax,8);
  233.       moved := True;
  234.       can_move := False;
  235.     end
  236.  
  237.     {drop down}
  238.     else if (fg_kbtest(80)=1) and (block[current].y > 40) then
  239.     begin
  240.       while(can_move_down) do
  241.         inc(block[current].y,2);
  242.       ymax := block[current].y;
  243.       put_block;
  244.       fix_grid;
  245.       check_rows;
  246.       new_block
  247.     end
  248.     else
  249.     begin
  250.       moved := False;
  251.       can_move := True;
  252.     end
  253.   end
  254.   else
  255.   begin
  256.     moved := False;
  257.     can_move := True;
  258.   end;
  259.  
  260.   {rotate only when y coord falls on byte boundary}
  261.   if (fg_kbtest(72) = 1)then
  262.   begin
  263.     if  released = True then
  264.       do_rotate := True;
  265.     released := False;
  266.   end
  267.   else
  268.     released := True;
  269.  
  270.   if (do_rotate) and (block[current].y mod 8 = 0) then
  271.   begin
  272.     rotate;
  273.     moved := True;
  274.     do_rotate := False;
  275.   end;
  276.  
  277.   {go down}
  278.   if not moved then
  279.   begin
  280.     {can move down?}
  281.     if (block[current].y mod 8 = 0) then
  282.     begin
  283.       if (not can_move_down) then
  284.       begin
  285.         put_block;
  286.         fix_grid;
  287.         check_rows;
  288.         new_block ;
  289.       end
  290.       else
  291.         inc(block[current].y,2)
  292.     end
  293.     else
  294.       inc(block[current].y,2);
  295.   end;
  296.  
  297.   if block[current].y > ymax then
  298.     ymax := block[current].y;
  299.   {redraw the screen}
  300.   put_block;
  301.   tetris_paste;
  302.   Header1.Sections.strings[1] := IntToStr(score);
  303. end;
  304.  
  305. {**********************************************************************}
  306. procedure build_screen;
  307. begin
  308.   fg_erase;
  309.   fg_setcolor(48);
  310.   fg_rect(80,159,25,184);
  311.   fg_boxdepth(2,2);
  312.   fg_setcolor(50);
  313.   fg_box(78,161,23,186);
  314.   fg_setcolor(55);
  315.   fg_box(78,163,23,188);
  316. end;
  317.  
  318. {**********************************************************************}
  319. function can_move_down : boolean;
  320. var
  321.  row, col: integer;
  322.  r, c: integer;
  323.  i: integer;
  324. begin
  325.   can_move_down := True;
  326.   col := (block[current].x-80) div 8;
  327.   row := (block[current].y-24) div 8 + 1;
  328.  
  329.   if ((block[current].pattern[0]=1) and (board[row,col]=True))     or
  330.      ((block[current].pattern[1]=1) and (board[row,col+1]=True))   or
  331.      ((block[current].pattern[2]=1) and (board[row,col+2]=True))   or
  332.      ((block[current].pattern[3]=1) and (board[row-1,col]=True))   or
  333.      ((block[current].pattern[4]=1) and (board[row-1,col+1]=True)) or
  334.      ((block[current].pattern[5]=1) and (board[row-1,col+2]=True)) or
  335.      ((block[current].pattern[6]=1) and (board[row-2,col]=True))   or
  336.      ((block[current].pattern[7]=1) and (board[row-2,col+1]=True)) or
  337.      ((block[current].pattern[8]=1) and (board[row-2,col+2]=True)) then
  338.     can_move_down := False;
  339. end;
  340.  
  341. {**********************************************************************}
  342. function can_move_left : boolean;
  343. var
  344.  row, col: integer;
  345. begin
  346.   can_move_left := True;
  347.   col := ((block[current].x-80) div 8)-1; {column to right of block}
  348.   row := (block[current].y-24) div 8;   {row at bottom of block}
  349.   if ((block[current].pattern[0]=1) and (board[row,  col]=True))   or
  350.      ((block[current].pattern[3]=1) and (board[row-1,col]=True))   or
  351.      ((block[current].pattern[6]=1) and (board[row-2,col]=True))   or
  352.      ((block[current].pattern[1]=1) and (board[row,  col+1]=True)) or
  353.      ((block[current].pattern[4]=1) and (board[row-1,col+1]=True)) or
  354.      ((block[current].pattern[7]=1) and (board[row-2,col+1]=True)) or
  355.      ((block[current].pattern[2]=1) and (board[row,  col+2]=True)) or
  356.      ((block[current].pattern[5]=1) and (board[row-1,col+2]=True)) or
  357.      ((block[current].pattern[8]=1) and (board[row-2,col+2]=True)) then
  358.     can_move_left := False;
  359.  
  360.   {Because of smooth vertical scrolling, block may overlap two grid
  361.    rows. Better check them both.}
  362.   if block[current].y mod 8 > 0 then
  363.   inc(row);
  364.   if ((block[current].pattern[0]=1) and (board[row,  col]=True))   or
  365.      ((block[current].pattern[3]=1) and (board[row-1,col]=True))   or
  366.      ((block[current].pattern[6]=1) and (board[row-2,col]=True))   or
  367.      ((block[current].pattern[1]=1) and (board[row,  col+1]=True)) or
  368.      ((block[current].pattern[4]=1) and (board[row-1,col+1]=True)) or
  369.      ((block[current].pattern[7]=1) and (board[row-2,col+1]=True)) or
  370.      ((block[current].pattern[2]=1) and (board[row,  col+2]=True)) or
  371.      ((block[current].pattern[5]=1) and (board[row-1,col+2]=True)) or
  372.      ((block[current].pattern[8]=1) and (board[row-2,col+2]=True)) then
  373.     can_move_left := False;
  374. end;
  375.  
  376. {**********************************************************************}
  377. function can_move_right : boolean;
  378. var
  379.  row, col: integer;
  380. begin
  381.   can_move_right := True;
  382.   col := (block[current].x-80) div 8+3;
  383.   row := (block[current].y-24) div 8;
  384.   if ((block[current].pattern[2]=1) and (board[row,  col]=True))   or
  385.      ((block[current].pattern[5]=1) and (board[row-1,col]=True))   or
  386.      ((block[current].pattern[8]=1) and (board[row-2,col]=True))   or
  387.      ((block[current].pattern[1]=1) and (board[row,  col-1]=True)) or
  388.      ((block[current].pattern[4]=1) and (board[row-1,col-1]=True)) or
  389.      ((block[current].pattern[7]=1) and (board[row-2,col-1]=True)) or
  390.      ((block[current].pattern[0]=1) and (board[row,  col-2]=True)) or
  391.      ((block[current].pattern[3]=1) and (board[row-1,col-2]=True)) or
  392.      ((block[current].pattern[6]=1) and (board[row-2,col-2]=True)) then
  393.     can_move_right := False;
  394.  
  395.   {Because of smooth vertical scrolling, block may overlap two grid
  396.    rows. Better check them both.}
  397.   if block[current].y mod 8 > 0 then
  398.   inc(row);
  399.   if ((block[current].pattern[2]=1) and (board[row,  col]=True))   or
  400.      ((block[current].pattern[5]=1) and (board[row-1,col]=True))   or
  401.      ((block[current].pattern[8]=1) and (board[row-2,col]=True))   or
  402.      ((block[current].pattern[1]=1) and (board[row,  col-1]=True)) or
  403.      ((block[current].pattern[4]=1) and (board[row-1,col-1]=True)) or
  404.      ((block[current].pattern[7]=1) and (board[row-2,col-1]=True)) or
  405.      ((block[current].pattern[0]=1) and (board[row,  col-2]=True)) or
  406.      ((block[current].pattern[3]=1) and (board[row-1,col-2]=True)) or
  407.      ((block[current].pattern[6]=1) and (board[row-2,col-2]=True)) then
  408.     can_move_right := False;
  409. end;
  410.  
  411. {**********************************************************************}
  412. procedure check_rows;
  413. var
  414.   occupied: boolean;
  415.   row, i: integer;
  416. begin
  417.   {can we remove any fully covered rows?}
  418.   row := 20;
  419.   while row > 0 do
  420.   begin
  421.     occupied := True;
  422.     i := 0;
  423.     while ((i < 10) and occupied) do
  424.     begin
  425.       occupied := board[row,i];
  426.       inc(i);
  427.     end;
  428.     if not occupied then
  429.        dec(row)
  430.     else
  431.        remove_row(row);
  432.   end;
  433. end;
  434.  
  435. {**********************************************************************}
  436. procedure clear_block;
  437. var
  438.   i,j,x,y: integer;
  439. begin
  440.   fg_setcolor(48);
  441.   fg_setclip(80,159,25,184);
  442.   for i := 0 to 2 do
  443.   begin
  444.     y := block[current].y-(i*8);
  445.     for j := 0 to 2 do
  446.     begin
  447.       x := block[current].x+(j*8);
  448.       if (block[current].pattern[i*3+j] = 1)then
  449.          fg_clprect(x,x+7,y-7,y);
  450.     end;
  451.   end;
  452.   fg_setclip(0,239,0,199);
  453. end;
  454.  
  455. {**********************************************************************}
  456. const
  457. colors : array [0..707] of byte = (
  458. 21,63,21, 21,63,63, 63,21,21, 63,21,63, 63,63,21, 63,63,63, 59,59,59, 55,55,55,
  459. 52,52,52, 48,48,48, 45,45,45, 42,42,42, 38,38,38, 35,35,35, 31,31,31, 28,28,28,
  460. 25,25,25, 21,21,21, 18,18,18, 14,14,14, 11,11,11,  8, 8, 8, 63, 0, 0, 59, 0, 0,
  461. 56, 0, 0, 53, 0, 0, 50, 0, 0, 47, 0, 0, 44, 0, 0, 41, 0, 0, 38, 0, 0, 34, 0, 0,
  462. 31, 0, 0, 28, 0, 0, 25, 0, 0, 22, 0, 0, 19, 0, 0, 16, 0, 0, 63,54,54, 63,46,46,
  463. 63,39,39, 63,31,31, 63,23,23, 63,16,16, 63, 8, 8, 63, 0, 0, 63,42,23, 63,38,16,
  464. 63,34, 8, 63,30, 0, 57,27, 0, 51,24, 0, 45,21, 0, 39,19, 0, 63,63,54, 63,63,46,
  465. 63,63,39, 63,63,31, 63,62,23, 63,61,16, 63,61, 8, 63,61, 0, 57,54, 0, 51,49, 0,
  466. 45,43, 0, 39,39, 0, 33,33, 0, 28,27, 0, 22,21, 0, 16,16, 0, 52,63,23, 49,63,16,
  467. 45,63, 8, 40,63, 0, 36,57, 0, 32,51, 0, 29,45, 0, 24,39, 0, 54,63,54, 47,63,46,
  468. 39,63,39, 32,63,31, 24,63,23, 16,63,16,  8,63, 8,  0,63, 0,  0,63, 0,  0,59, 0,
  469.  0,56, 0,  0,53, 0,  1,50, 0,  1,47, 0,  1,44, 0,  1,41, 0,  1,38, 0,  1,34, 0,
  470.  1,31, 0,  1,28, 0,  1,25, 0,  1,22, 0,  1,19, 0,  1,16, 0, 54,63,63, 46,63,63,
  471. 39,63,63, 31,63,62, 23,63,63, 16,63,63,  8,63,63,  0,63,63,  0,57,57,  0,51,51,
  472.  0,45,45,  0,39,39,  0,33,33,  0,28,28,  0,22,22,  0,16,16, 23,47,63, 16,44,63,
  473.  8,42,63,  0,39,63,  0,35,57,  0,31,51,  0,27,45,  0,23,39, 54,54,63, 46,47,63,
  474. 39,39,63, 31,32,63, 23,24,63, 16,16,63,  8, 9,63,  0, 1,63,  0, 0,63,  0, 0,59,
  475.  0, 0,56,  0, 0,53,  0, 0,50,  0, 0,47,  0, 0,44,  0, 0,41,  0, 0,38,  0, 0,34,
  476.  0, 0,31,  0, 0,28,  0, 0,25,  0, 0,22,  0, 0,19,  0, 0,16, 60,54,63, 57,46,63,
  477. 54,39,63, 52,31,63, 50,23,63, 47,16,63, 45, 8,63, 42, 0,63, 38, 0,57, 32, 0,51,
  478. 29, 0,45, 24, 0,39, 20, 0,33, 17, 0,28, 13, 0,22, 10, 0,16, 63,54,63, 63,46,63,
  479. 63,39,63, 63,31,63, 63,23,63, 63,16,63, 63, 8,63, 63, 0,63, 56, 0,57, 50, 0,51,
  480. 45, 0,45, 39, 0,39, 33, 0,33, 27, 0,28, 22, 0,22, 16, 0,16, 63,58,55, 63,56,52,
  481. 63,54,49, 63,53,47, 63,51,44, 63,49,41, 63,47,39, 63,46,36, 63,44,32, 63,41,28,
  482. 63,39,24, 60,37,23, 58,35,22, 55,34,21, 52,32,20, 50,31,19, 47,30,18, 45,28,17,
  483. 42,26,16, 40,25,15, 39,24,14, 36,23,13, 34,22,12, 32,20,11, 29,19,10, 27,18, 9,
  484. 23,16, 8, 21,15, 7, 18,14, 6, 16,12, 6, 14,11, 5, 10, 8, 3,  0, 0, 0,  0, 0, 0,
  485.  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0, 49,10,10, 49,19,10,
  486. 49,29,10, 49,39,10, 49,49,10, 39,49,10, 29,49,10, 19,49,10, 10,49,12, 10,49,23,
  487. 10,49,34, 10,49,45, 10,42,49, 10,31,49);
  488.  
  489. {**********************************************************************}
  490. procedure fill_color_palette;
  491. begin
  492.   fg_mapdacs(colors,RGBvalues,236);
  493. end;
  494.  
  495. {**********************************************************************}
  496. procedure fix_grid;
  497. var
  498.   i,j: integer;
  499.   row,col: integer;
  500.   x,y: integer;
  501. begin
  502.    col := (block[current].x-80) div 8;
  503.    row := (block[current].y-24) div 8;
  504.    if (block[current].pattern[0] = 1) then board[row,col]     := True;
  505.    if (block[current].pattern[1] = 1) then board[row,col+1]   := True;
  506.    if (block[current].pattern[2] = 1) then board[row,col+2]   := True;
  507.    if (block[current].pattern[3] = 1) then board[row-1,col]   := True;
  508.    if (block[current].pattern[4] = 1) then board[row-1,col+1] := True;
  509.    if (block[current].pattern[5] = 1) then board[row-1,col+2] := True;
  510.    if (block[current].pattern[6] = 1) then board[row-2,col]   := True;
  511.    if (block[current].pattern[7] = 1) then board[row-2,col+1] := True;
  512.    if (block[current].pattern[8] = 1) then board[row-2,col+2] := True;
  513.  
  514.   {adjust the score}
  515.   inc(score,10);
  516. end;
  517.  
  518. {**********************************************************************}
  519. procedure get_blocks;
  520. var
  521.   num, y: integer;
  522. begin
  523.   {display the graphics (simple RLE)}
  524.   fg_move(0,87);
  525.   fg_showspr(datapath+'tetris.spr'+Chr(0),16);
  526.   y := 7;
  527.  
  528.   {get first 4 blocks}
  529.   for num := 0 to 3 do
  530.   begin
  531.    fg_move(0,y);
  532.    fg_getimage(block[num].data,8,8);
  533.    y := y + 8;
  534.    move(pattern[num],block[num].pattern,9);
  535.   end;
  536.  
  537.   {get next 4 blocks}
  538.   y := 7;
  539.   for num := 4 to 7 do
  540.   begin
  541.     fg_move(8,y);
  542.     fg_getimage(block[num].data,8,8);
  543.     y := y + 8;
  544.     move(pattern[num],block[num].pattern,9);
  545.   end;
  546.  
  547.   {get the other bitmaps}
  548.   fg_setcolor(1);
  549.   fg_move(0,47);
  550.   fg_getmap(explosion2,2,16);
  551.   fg_move(0,60);
  552.   fg_getmap(explosion1,2,13);
  553.   fg_move(0,74);
  554.   fg_getimage(langolier1,11,13);
  555.   fg_move(0,87);
  556.   fg_getimage(langolier2,12,12);
  557. end;
  558.  
  559. {**********************************************************************}
  560. procedure new_block;
  561. var
  562.   x,y,i,j: integer;
  563.   count: integer;
  564. begin
  565.   {start a new random block at top of board}
  566.   current := next_block;
  567.   next_block := random(8);
  568.   count := 1;
  569.   while next_block = current do
  570.   begin
  571.     inc(count);
  572.     next_block := random(8);
  573.     if count > 10 then
  574.     begin
  575.       randomize;
  576.       count := 1;
  577.     end;
  578.   end;
  579.   block[current].x := 112;
  580.   block[current].y := 24;
  581.   move(pattern[current,0],block[current].pattern,9);
  582.  
  583.   {put the next block in the upper left corner}
  584.   fg_setcolor(0);
  585.   fg_rect(20,44,30,60);
  586.   for i := 0 to 2 do
  587.   begin
  588.     y := i*8;
  589.     for j := 0 to 2 do
  590.     begin
  591.       x := j*8;
  592.       fg_move(20+x,60-y);
  593.       if block[next_block].pattern[i*3+j] = 1 then
  594.          fg_clpimage(block[next_block].data,8,8);
  595.     end;
  596.   end;
  597.   fg_vbscale(0,fg_getmaxx div 4,0,fg_getmaxy div 3,0,cxWidth div 4,0,cyHeight div 3);
  598. end;
  599.  
  600. {**********************************************************************}
  601. procedure new_game;
  602. var
  603.   i,j: integer;
  604. begin
  605.   {initialize board by setting center and top grid elements to False}
  606.   for i := -3 to 20 do
  607.     for j := 0 to 9 do
  608.        board[i,j] := False;
  609.  
  610.   {set bottom row (not visible) to True to stop blocks }
  611.   for j := -2 to 9 do
  612.     board[21,j] := True;
  613.  
  614.   {set left and right sides (not visible) to True to stop blocks}
  615.   for i := -3 to 20 do
  616.   begin
  617.     board[i,-1] := True;
  618.     board[i,-2] := True;
  619.     board[i,10] := True;
  620.     board[i,11] := True;
  621.   end;
  622.  
  623.   {clear background}
  624.   fg_setcolor(48);
  625.   fg_rect(80,159,25,184);
  626.  
  627.   {set some globals}
  628.   can_move := True;
  629.   score := 0;
  630.   next_block := random(8);
  631. end;
  632.  
  633. {**********************************************************************}
  634. procedure paste(x1,x2,y1,y2:integer);
  635.  
  636. {blit an area of a virtual buffer proportionatly scaled within a window}
  637. var
  638.   cx1,cx2,cy1,cy2: longint;
  639. begin
  640.  
  641.   {calculate window coords based on buffer coords}
  642.   cx1 := cxWidth*longint(x1) div vb_width + 1;
  643.   cx2 := cxWidth*longint(x2) div vb_width + 1;
  644.   cy1 := cyHeight*longint(y1) div vb_height + 1;
  645.   cy2 := cyHeight*longint(y2) div vb_height + 1;
  646.  
  647.   {check boundary conditions}
  648.   if x1 < 0 then x1 := 0;
  649.   if x2 > vb_width then x2 := vb_width;
  650.   if y1 < 0 then y1 := 0;
  651.   if y2 > vb_height then y2 := vb_height;
  652.   if x2 < x1 then x2 := x1;
  653.   if y2 < y1 then y2 := y1;
  654.  
  655.   if cx1 < 0 then cx1 := 0;
  656.   if cx2 > cxWidth then cx2 := cxWidth;
  657.   if cy1 < 0 then cy1 := 0;
  658.   if cy2 > cyHeight then cy2 := cyHeight;
  659.   if cx2 < cx1 then cx2 := cx1;
  660.   if cy2 < cy1 then cy2 := cy1;
  661.  
  662.   {do the blit}
  663.   fg_vbscale(x1,x2,y1,y2,cx1,cx2,cy1,cy2);
  664. end;
  665.  
  666. {**********************************************************************}
  667. procedure put_block;
  668. var
  669.   i,j,x,y: integer;
  670. begin
  671.   fg_setclip(80,159,25,184);
  672.   for i := 0 to 2 do
  673.   begin
  674.     y := i*8;
  675.     for j := 0 to 2 do
  676.     begin
  677.       x := j*8;
  678.       fg_move(block[current].x+x,block[current].y-y);
  679.       if block[current].pattern[i*3+j] = 1 then
  680.          fg_clpimage(block[current].data,8,8);
  681.     end;
  682.   end;
  683.   fg_setclip(0,239,0,199);
  684. end;
  685.  
  686. {**********************************************************************}
  687. procedure remove_row(row: integer);
  688. var
  689.   i,x,x2,y: integer;
  690.   color, old_color: integer;
  691.   result: boolean;
  692.   snd : string;
  693.   flg: word;
  694.   pc: Pchar;
  695.  
  696. begin
  697.   snd := datapath+'eating.wav'+chr(0);
  698.   pc := @snd[1];
  699.   flg := snd_Async+snd_NoDefault;
  700.  
  701.   {refresh the screen and wait a bit}
  702.   tetris_paste;
  703.   fg_waitfor(3);
  704.   result := sndPlaySound(pc,flg);
  705.  
  706.   {copy the row plus some extra to another virtual buffer}
  707.   y := row*8+24;
  708.   fg_vbcopy(76,163,y-11,y+4,0,15,vb1,vb2);
  709.  
  710.   {draw the munchie critter in the first virtual buffer and blit}
  711.   fg_move(76,y+4);
  712.   fg_drwimage(langolier2,12,12);
  713.   tetris_paste;
  714.   fg_waitfor(3);
  715.  
  716.   {move through all the blocks in the row}
  717.   for i := 0 to 9 do
  718.   begin
  719.  
  720.     {get the color of the current block from second virtual buffer}
  721.     x := i*8+80;
  722.     fg_vbopen(vb2);
  723.     x2 := i*8+4;
  724.     color := fg_getpixel(x2,8);
  725.  
  726.     {now erase that block}
  727.     fg_setcolor(48);
  728.     fg_rect(x2,x2+7,4,11);
  729.  
  730.     {copy remains of row to first virtual buffer (make a clean copy)}
  731.     fg_vbcopy(0,87,0,15,76,y+4,vb2,vb1);
  732.     fg_vbopen(vb1);
  733.  
  734.     {add the explosions (munchy remnants)}
  735.     fg_setcolor(color);
  736.     fg_move(x-4,y+4);
  737.     fg_drawmap(explosion1,2,13);
  738.     if i > 0 then
  739.     begin
  740.        fg_setcolor(old_color);
  741.        fg_move(x-12,y+4);
  742.        fg_drawmap(explosion2,2,15);
  743.     end;
  744.  
  745.     {add the munchy critter}
  746.     if i < 9 then
  747.     begin
  748.       fg_move(x+8,y+4);
  749.       if i mod 2 = 0 then
  750.         fg_drwimage(langolier1,11,13)
  751.       else
  752.         fg_drwimage(langolier2,12,12);
  753.     end;
  754.     old_color := color;
  755.  
  756.     {blit to screen}
  757.     tetris_paste;
  758.     fg_waitfor(3);
  759.   end;
  760.  
  761.   {make a final copy}
  762.   fg_vbcopy(0,87,0,15,76,y+4,vb2,vb1);
  763.  
  764.   {move all the rows down: copy graphics and board data}
  765.   for i := row downto 2 do
  766.   begin
  767.     y := i*8+24;
  768.     fg_vbcopy(80,159,y-15,y-8,80,y,vb1,vb1);
  769.     move(board[i-1,0],board[i,0],10);
  770.   end;
  771.   tetris_paste;
  772.  
  773.   {adjust the score}
  774.   inc(score,100);
  775.  
  776.   {make a surprising sound}
  777.   if (row = 10) and Jay_Leno then
  778.   begin
  779.     snd := datapath+'jayleno.wav'+chr(0);
  780.     result := sndPlaySound(pc,flg);
  781.     Jay_Leno := False;
  782.   end;
  783. end;
  784.  
  785. {**********************************************************************}
  786. procedure rotate;
  787. var
  788.   temp: array[0..8] of byte;
  789.   i: integer;
  790.   row,col: integer;
  791. const
  792.   index: array [0..8] of byte = (6,3,0,7,4,1,8,5,2);
  793. begin
  794.   {don't rotate the square block}
  795.   if current = 3 then exit;
  796.   move(block[current].pattern,temp,9);
  797.  
  798.   {check if legal to rotate}
  799.   row := (block[current].y - 24) div 8;
  800.   col := (block[current].x - 80) div 8;
  801.  
  802.   if ((temp[index[0]] = 1) and (board[row,col]     = True)) or
  803.      ((temp[index[1]] = 1) and (board[row,col+1]   = True)) or
  804.      ((temp[index[2]] = 1) and (board[row,col+2]   = True)) or
  805.      ((temp[index[3]] = 1) and (board[row-1,col]   = True)) or
  806.      ((temp[index[4]] = 1) and (board[row-1,col+1] = True)) or
  807.      ((temp[index[5]] = 1) and (board[row-1,col+2] = True)) or
  808.      ((temp[index[6]] = 1) and (board[row-2,col]   = True)) or
  809.      ((temp[index[7]] = 1) and (board[row-2,col+1] = True)) or
  810.      ((temp[index[8]] = 1) and (board[row-2,col+2] = True)) then
  811.    exit;
  812.   for i := 0 to 8 do
  813.     block[current].pattern[i] := temp[index[i]];
  814. end;
  815.  
  816. {**********************************************************************}
  817. procedure tetris_paste;
  818. var
  819.   cx1,cx2: integer;
  820. begin
  821.   cx1 := cxWidth div 3;
  822.   cx2 := cxWidth * 2 div 3;
  823.   fg_vbscale(80,159,0,199,cx1,cx2,0,cyHeight);
  824. end;
  825.  
  826. {**********************************************************************}
  827.  
  828. initialization
  829.   vb_width  := 240;
  830.   vb_height := 200;
  831.   Jay_Leno  := True;
  832. end.
  833.