Advertisement
WarPie90

[Simba] Tetris!

Jul 18th, 2016 (edited)
511
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 10.96 KB | None | 0 0
  1. program Tetris;
  2. (*
  3.   A hacked together tetris game that uses the builtin debug image.
  4.   Requires Simba 1.2-RC5 or later.
  5.   > http://i.imgur.com/q7VhaaD.png
  6. *)
  7.  
  8. const
  9.   //** CONFIGUREATION **//
  10.   TURN_RIGHT = VK_D;
  11.   TURN_LEFT  = VK_A;
  12.  
  13.   MOVE_LEFT  = VK_LEFT;
  14.   MOVE_RIGHT = VK_RIGHT;
  15.  
  16.   MOVE_DOWN  = VK_DOWN;
  17.   DROP_DOWN  = VK_SPACE;
  18.  
  19.   RESTART_GAME = VK_F5;
  20.   PAUSE_GAME = VK_P;
  21.  
  22.   START_LEVEL = 1;
  23.  
  24.   //special conf:
  25.   GAME_WIDTH  = 10;
  26.   GAME_HEIGHT = 20;
  27.  
  28.   BASE_TICK = 700;
  29.  
  30.   POINTSIZE = 24;
  31.  
  32.  
  33. //----------------------------------------------------------------------------\\
  34. //----------------------------------------------------------------------------\\
  35.  
  36. type
  37.   TFace = (f0,f1,f2,f3);
  38.   TState = (stRunning, stCompleted);
  39.  
  40.   TBrick = record
  41.     id: Int32;
  42.     pos: TPoint;
  43.     face: TFace;
  44.   end;
  45.   TBrickArray = array of TBrick;
  46.  
  47.   TTetris = record
  48.     Width,Height:Int32;
  49.     Bounds:TBox;
  50.     Board:TMufasaBitmap;
  51.     Active, Original, Next:TBrick;
  52.     State:TState;
  53.     Score:Int32;
  54.  
  55.     Level:Int32;
  56.     Tick:Int32;
  57.     CollapseCount:Int32;
  58.   end;
  59.  
  60. const
  61.   GLOB_BRICKS:T2DPointArray = [
  62.     [[0,0],[0,1],[1,0],[2,0]], // :''
  63.     [[0,0],[1,0],[2,0],[3,0]], // ....
  64.     [[0,0],[1,0],[2,0],[1,1]], // ':'
  65.     [[1,0],[2,0],[0,1],[1,1]], // .:'
  66.     [[0,0],[1,0],[1,1],[2,1]], // ':.
  67.     [[0,0],[1,0],[0,1],[1,1]], // ::
  68.     [[0,0],[1,0],[2,0],[2,1]]  // '':
  69.   ];
  70.  
  71.   GLOB_COLORS:TIntegerArray = [
  72.     $3388FF,  //orange
  73.     $FFCC33,  //cyan
  74.     $FF33BB,  //purple
  75.     $33FF77,  //green
  76.     $3333FF,  //red / pink
  77.     $33DDFF,  //yellow
  78.     $FF9000   //blue
  79.   ];
  80.  
  81.   BACKGROUND = $333333;
  82.  
  83.  
  84. function TBrick.GetBrickTPA(): TPointArray; constref;
  85. begin
  86.   Result := GLOB_BRICKS[self.id];
  87.   case self.face of
  88.     f0: Result := Copy(Result);
  89.     f1: Result := RotatePoints(Result, radians(90), 1,0);
  90.     f2: Result := RotatePoints(Result, radians(180), 1,0);
  91.     f3: Result := RotatePoints(Result, radians(270), 1,0);
  92.   end;
  93.   OffsetTPA(Result, Self.pos);
  94. end;
  95.  
  96. procedure TTetris.FillBox(x,y:Int32; color:Int32=BACKGROUND);
  97. var
  98.   h,s,l:Extended;
  99. begin
  100.   x *= POINTSIZE;
  101.   y *= POINTSIZE;
  102.   try
  103.     self.Board.DrawTPA(TPAFromBox([x,y,x+POINTSIZE-2,y+POINTSIZE-2]), color);
  104.     if color <> BACKGROUND then
  105.     begin
  106.       ColorToHSL(color, H,S,L);
  107.       color := HSLToColor(H,S-15,L-15);
  108.       self.Board.DrawTPA(EdgeFromBox([x,y,x+POINTSIZE-2,y+POINTSIZE-2]), color);
  109.     end;
  110.   except
  111.   end;
  112. end;
  113.  
  114. function TTetris.IsFilled(x,y:Int32): Boolean;
  115. begin
  116.   Result := (y > 0) and (self.board.GetPixel(x * POINTSIZE, y * POINTSIZE) <> BACKGROUND);
  117. end;
  118.  
  119. procedure TTetris.DrawBrick(brick:TBrick);
  120. var pt:TPoint;
  121. begin
  122.   for pt in brick.GetBrickTPA() do
  123.     self.FillBox(pt.x,pt.y, GLOB_COLORS[brick.id]);
  124. end;
  125.  
  126. procedure TTetris.UndrawBrick(brick:TBrick);
  127. var pt:TPoint;
  128. begin
  129.   for pt in brick.GetBrickTPA() do
  130.     self.FillBox(pt.x,pt.y);
  131. end;
  132.  
  133. function TTetris.Collides(): Boolean;
  134. var
  135.   pt:TPoint;
  136. begin
  137.   for pt in active.GetBrickTPA() do
  138.     if (not(InRange(pt.x, Bounds.x1, Bounds.x2) and InRange(pt.y, Bounds.y1, Bounds.y2))) or
  139.        self.IsFilled(pt.x,pt.y) then
  140.       Exit(True);
  141. end;
  142.  
  143. function TTetris.TryRotateCW(): Boolean;
  144. var
  145.   pt:TPoint;
  146.   oldface:TFace;
  147. begin
  148.   Result := True;
  149.   self.UndrawBrick(self.Active);
  150.  
  151.   oldface := active.face;
  152.   if active.face = f3 then active.face := f0
  153.   else Inc(active.face);
  154.  
  155.   if self.Collides() then
  156.   begin
  157.     active.face := oldface;
  158.     self.DrawBrick(self.Active);
  159.     Result := False;
  160.   end;
  161. end;
  162.  
  163. function TTetris.TryRotateCCW(): Boolean;
  164. var
  165.   pt:TPoint;
  166.   oldface:TFace;
  167. begin
  168.   Result := True;
  169.   self.UndrawBrick(self.Active);
  170.  
  171.   oldface := active.face;
  172.   if active.face = f0 then active.face := f3
  173.   else Dec(active.face);
  174.  
  175.   if self.Collides() then
  176.   begin
  177.     active.face := oldface;
  178.     self.DrawBrick(self.Active);
  179.     Result := False;
  180.   end;
  181. end;
  182.  
  183. function TTetris.TryMove(ox,oy:Int32): Boolean;
  184. var
  185.   pt:TPoint;
  186.   oldpos:TPoint;
  187. begin
  188.   Result := True;
  189.   self.UndrawBrick(self.Active);
  190.  
  191.   oldpos := active.pos;
  192.   active.pos.x += ox;
  193.   active.pos.y += oy;
  194.  
  195.   if self.Collides() then
  196.   begin
  197.     active.pos := oldpos;
  198.     self.DrawBrick(self.Active);
  199.     Result := False;
  200.   end;
  201. end;
  202.  
  203. procedure TTetris.UpdateBrick();
  204. begin
  205.   self.UndrawBrick(Original);
  206.   self.DrawBrick(Active);
  207.   self.Update();
  208. end;
  209.  
  210. procedure TTetris.LevelUp();
  211. begin
  212.   self.Tick := Ceil(self.Tick*0.75);
  213.   if self.Tick < 1 then self.Tick := 1;
  214.   self.Level += 1;
  215.   self.collapseCount := 0;
  216. end;
  217.  
  218. procedure TTetris.CheckRows();
  219. var
  220.   x,y,counter:Int32;
  221.   procedure RemoveRow(row:Int32);
  222.   var x,y,color:Int32;
  223.   begin
  224.     counter += 1;
  225.     for y:=row-1 downto 0 do
  226.       for x:=0 to Bounds.X2 do
  227.       begin
  228.         color := self.board.GetPixel(x * POINTSIZE+1, y * POINTSIZE+1);
  229.         self.FillBox(x,y);
  230.         self.FillBox(x,y+1, color);
  231.       end;
  232.   end;
  233. begin
  234.   for y:=0 to Bounds.Y2 do
  235.   begin
  236.     for x:=0 to Bounds.X2 do
  237.       if not self.IsFilled(x,y) then
  238.         break;
  239.     if (x = self.Width) then RemoveRow(y);
  240.   end;
  241.   self.Score += counter*self.Width;
  242.   self.collapseCount += counter;
  243.   if self.collapseCount >= 10 then self.LevelUp();
  244. end;
  245.  
  246. procedure TTetris.NewBrick();
  247. begin
  248.   self.Original := self.Next;
  249.   self.Active   := self.Next;
  250.  
  251.   self.Next.pos  := Point(self.Width div 2 - 1, -1);
  252.   self.Next.face := f0;
  253.   self.Next.id   := Random(0,High(GLOB_BRICKS));
  254. end;
  255.  
  256. procedure TTetris.Debug();
  257. var
  258.   x:Int32;
  259.   pt:TPoint;
  260.   brick:TBrick;
  261.   procedure _FillBrick(x,y:Int32; size:Int32=15);
  262.   begin
  263.     for pt in brick.GetBrickTPA() do
  264.     begin
  265.       pt.x := x+pt.x*size;
  266.       pt.y := y+pt.y*size;
  267.       self.Board.DrawTPA(TPAFromBox([pt.x,pt.y, pt.x+size-2,pt.y+size-2]), $FFFFFF);
  268.     end;
  269.   end;
  270.  
  271. begin
  272.   x := self.Width*POINTSIZE + 20;
  273.  
  274.   if self.score = 0 then
  275.   begin
  276.     self.Board.setFontName('Arial Black');
  277.     self.Board.setFontSize(14);
  278.     self.Board.DrawText('Score:', Point(x,20),  $AAAAAA);
  279.     self.Board.DrawText('Level:', Point(x,80),  $AAAAAA);
  280.     self.Board.DrawText('Speed:', Point(x,140), $AAAAAA);
  281.     self.Board.DrawText('Next: ', Point(x,200), $AAAAAA);
  282.   end;
  283.  
  284.   //clear
  285.   self.Board.DrawTPA(TPAFromBox([x,40,Board.GetWidth()-1,60]), 0);
  286.   self.Board.DrawTPA(TPAFromBox([x,100,Board.GetWidth()-1,120]), 0);
  287.   self.Board.DrawTPA(TPAFromBox([x,160,Board.GetWidth()-1,180]), 0);
  288.   self.Board.DrawTPA(TPAFromBox([x,220,Board.GetWidth()-1, 220+50]), 0);
  289.  
  290.   //draw
  291.   self.Board.setFontName('Arial');
  292.   self.Board.DrawText(ToStr(self.Score), Point(x,40),  $FFFFFF);
  293.   self.Board.DrawText(ToStr(self.Level), Point(x,100), $FFFFFF);
  294.   self.Board.DrawText(ToStr(Round(BASE_TICK/self.Tick,2)), Point(x,160), $FFFFFF);
  295.  
  296.   brick := self.Next;
  297.   brick.pos := [0,0];
  298.   _FillBrick(x,220,15);
  299.  
  300.   //----
  301.   if self.State = stCompleted then
  302.   begin
  303.      ClearDebug();
  304.      WriteLn('Game over!!');
  305.   end;
  306. end;
  307.  
  308. procedure TTetris.RestartGame();
  309. var x,y:Int32;
  310. begin
  311.   Self.Tick := 1000;
  312.   for x:=0 to Width-1 do
  313.     for y:=0 to Height-1 do
  314.       Self.FillBox(x,y);
  315.  
  316.   Self.Level := 1;
  317.   Self.Tick := BASE_TICK;
  318.   for 1 to START_LEVEL-1 do Self.LevelUp();
  319.   Self.Score := 0;
  320.   Self.State := stRunning;
  321.   Self.NewBrick();
  322.   Self.Debug();
  323. end;
  324.  
  325. procedure TTetris.HandleEvent();
  326. var t,t2:UInt64;
  327. begin
  328.   t := GetTickCount() + Tick;
  329.   while GetTickCount() < t do
  330.   begin
  331.     self.UpdateBrick();
  332.     Original := Active;
  333.     t2 := GetTickCount() + 150;
  334.     if isKeyDown(TURN_RIGHT) then
  335.     begin
  336.       TryRotateCW();
  337.       while isKeyDown(TURN_RIGHT) and (GetTickCount() < t2) do Wait(2);
  338.     end
  339.     else if isKeyDown(TURN_LEFT) then
  340.     begin
  341.       TryRotateCCW();
  342.       while isKeyDown(TURN_LEFT) and (GetTickCount() < t2) do Wait(2);
  343.     end
  344.     else if isKeyDown(MOVE_LEFT) then
  345.     begin
  346.       TryMove(-1,0);
  347.       while isKeyDown(MOVE_LEFT) and (GetTickCount() < t2) do Wait(2);
  348.     end
  349.     else if isKeyDown(MOVE_RIGHT) then
  350.     begin
  351.       TryMove(1,0);
  352.       while isKeyDown(MOVE_RIGHT) and (GetTickCount() < t2) do Wait(2);
  353.     end
  354.     else if isKeyDown(MOVE_DOWN) then
  355.     begin
  356.       while isKeyDown(MOVE_DOWN) and TryMove(0,1) do
  357.       begin
  358.         self.UpdateBrick();
  359.         Wait(4);
  360.       end;
  361.     end
  362.     else if isKeyDown(DROP_DOWN) then
  363.     begin
  364.       while TryMove(0,1) do
  365.       begin
  366.         self.UpdateBrick();
  367.         Wait(4);
  368.       end;
  369.     end
  370.     else if isKeyDown(RESTART_GAME) then
  371.     begin
  372.       self.RestartGame();
  373.     end
  374.     else if isKeyDown(PAUSE_GAME) then
  375.     begin
  376.       ClearDebug();
  377.       WriteLn(self.Score);
  378.       WriteLn('Game is paused!');
  379.       while isKeyDown(PAUSE_GAME) do Wait(16);
  380.       while not isKeyDown(PAUSE_GAME) do Wait(16);
  381.       while isKeyDown(PAUSE_GAME) do Wait(16);
  382.       ClearDebug();
  383.       WriteLn(self.Score);
  384.       WriteLn('Game has been resumed!');
  385.     end;
  386.     Wait(2);
  387.   end;
  388.   self.UpdateBrick();
  389. end;
  390.  
  391. function TTetris.Create(AWidth,AHeight:Int32): TTetris; static;
  392. var
  393.   x,y:Int32;
  394. begin
  395.   Result.Width  := AWidth;
  396.   Result.Height := AHeight;
  397.   Result.Board.Init(client.getMBitmaps);
  398.   Result.Board.SetSize(AWidth*POINTSIZE+150, AHeight*POINTSIZE);
  399.   Result.Bounds := [0,-3,Result.Width-1,Result.Height-1];
  400.  
  401.   x := AWidth*POINTSIZE;
  402.   Result.Board.DrawTPA(TPAFromBox([x,0,x, AHeight*POINTSIZE-1]), $999999);
  403.  
  404.   Result.Level := 1;
  405.   Result.Tick := BASE_TICK;
  406.   for 1 to START_LEVEL-1 do Result.LevelUp();
  407.  
  408.   for x:=0 to AWidth-1 do
  409.     for y:=0 to AHeight-1 do
  410.       Result.FillBox(x,y);
  411. end;
  412.  
  413. procedure TTetris.Display(); constref;
  414. begin
  415.   DisplayDebugImgWindow(Self.board.GetWidth,Self.Board.GetHeight);
  416.   DrawBitmapDebugImg(Self.Board.GetIndex());
  417. end;
  418.  
  419. procedure TTetris.Update(); constref;
  420. begin
  421.   DrawBitmapDebugImg(Self.Board.GetIndex());
  422. end;
  423.  
  424. procedure TTetris.Focus(); constref;
  425. {$IFNDEF LINUX}
  426. var proc:TSysProc;
  427. function SetForegroundWindow(HWND:UInt64): LongBool; external 'SetForegroundWindow@User32.dll';
  428. begin
  429.   for proc in GetProcesses() do
  430.     if proc.Title = 'DebugImgForm' then
  431.       SetForegroundWindow(proc.Handle);
  432. end;
  433. {$ELSE}
  434. begin
  435.   WriteLn('Click / Focus the debug window manually, starting in 1 second');
  436.   Wait(1000);
  437. end;
  438. {$ENDIF}
  439.  
  440. function TTetris.Run(): Boolean;
  441. begin
  442.   self.State := stRunning;
  443.   self.Display();
  444.   self.Focus();
  445.   self.NewBrick();
  446.   self.Debug();
  447.  
  448.   while True do
  449.   begin
  450.     self.HandleEvent();
  451.     Original := Active;
  452.  
  453.     if not self.TryMove(0,1) then
  454.     begin
  455.       self.Score += self.Active.pos.y;
  456.  
  457.       if self.Active.pos.y = -1 then
  458.         self.State := stCompleted
  459.       else
  460.       begin
  461.         self.CheckRows();
  462.         self.NewBrick();
  463.         self.Debug();
  464.         Wait(170);
  465.       end;
  466.     end;
  467.  
  468.     while self.State = stCompleted do
  469.     begin
  470.       Self.Debug();
  471.       self.HandleEvent();
  472.       Wait(8);
  473.     end;
  474.   end;
  475. end;
  476.  
  477.  
  478. var
  479.   Tetris:TTetris;
  480.   tmp:TBrick;
  481. begin
  482.   Tetris := TTetris.Create(GAME_WIDTH,GAME_HEIGHT);
  483.   Tetris.Run();
  484. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement