cleaned all trailing white space from source files.
[sdk] / samples / games / tetris / tetris.ec
1 /****************************************************************************
2    Tetris Game
3
4    Copyright (c) 2001-2007 Jerome Jacovella-St-Louis
5    All Rights Reserved.
6
7    tetris.ec - Tetris
8 ****************************************************************************/
9 import "ecere"
10
11 // --- Definitions ---
12
13 define SERVER = 0;
14 define CLIENT = 1;
15
16 define NUM_COLUMNS  = 8;
17 define NUM_ROWS     = 8;
18
19 define CUBE_WIDTH   = 40;
20 define CUBE_HEIGHT  = 40;
21
22 define TETRIS_PORT = 7779;
23
24 struct Piece
25 {
26    int w, h;
27    int x0, x1;
28    byte data[9];
29 };
30
31 static Piece pieces[7] =
32 {
33    {
34       4, 1, -1, 1,
35       {
36          1,1,1,1
37       }
38    },
39    {
40       3, 2, 0, 0,
41       {
42         4,4,4,
43         4,0,0
44       }
45    },
46    {
47       3, 2, 0, 0,
48       {
49          3,3,3,
50          0,0,3
51       }
52    },
53    {
54       3, 2, 0, 0,
55       {
56          5,5,0,
57          0,5,5
58       }
59    },
60    {
61       3, 2, 0, 0,
62       {
63          0,1,1,
64          1,1,0
65       }
66    },
67    {
68       2, 2, 0, 0,
69       {
70          2,2,
71          2,2
72       }
73    },
74    {
75       3, 2, 0, 0,
76       {
77          2,2,2,
78          0,2,0
79       }
80    }
81 };
82
83 define MSG_NEWGAME  = 1;
84 define MSG_POSITION = 2;
85
86 typedef struct
87 {
88    byte type;
89    byte player,x,y;
90 } TPacket;
91
92 define WIDTH  = 12;
93 define HEIGHT = 22;
94
95 // --- Main Function ---
96 class TetrisApp : GuiApplication
97 {
98    appName = "ECERE Tetris";
99 }
100
101 Tetris tetris { };
102
103 TetrisService service { };
104
105 class TetrisService : Service
106 {
107    port = TETRIS_PORT;
108    Tetris tetris;
109    void OnAccept()
110    {
111       if(!tetris.sockets[CLIENT] && !tetris.gameRunning)
112       {
113          TetrisSocket socket { this };
114          TPacket packet;
115
116          tetris.sockets[CLIENT] = socket;
117          packet.type = MSG_NEWGAME;
118          tetris.sockets[CLIENT].Send((byte *)&packet, sizeof(TPacket));
119          tetris.NewGame();
120          tetris.gameRunning = true;
121          tetris.EnableButtons();
122          tetris.Update(null);
123       }
124    }
125 }
126
127 class TetrisSocket : Socket
128 {
129    // --- Tetris Communication ---
130    Tetris tetris;
131    static void OnDisconnect(int code)
132    {
133       if(this == tetris.sockets[CLIENT])
134       {
135          tetris.sockets[CLIENT] = null;
136          tetris.gameRunning = false;
137       }
138       else if(this == tetris.sockets[SERVER])
139       {
140          tetris.sockets[SERVER] = null;
141          tetris.gameRunning = false;
142       }
143
144       tetris.EnableButtons();
145       tetris.Update(null);
146    }
147
148    uint OnReceive(const byte * buffer, uint count)
149    {
150       if(count >= sizeof(TPacket))
151       {
152          TPacket packet = *(TPacket *)buffer;
153          switch(packet.type)
154          {
155             case MSG_POSITION:
156                break;
157             case MSG_NEWGAME:
158                tetris.gameRunning = true;
159                tetris.NewGame();
160                break;
161          }
162          return sizeof(TPacket);
163       }
164       return 0;
165    }
166
167    void OnConnect()
168    {
169       tetris.sockets[SERVER] = this;
170       tetris.gameRunning = true;
171       tetris.EnableButtons();
172       tetris.NewGame();
173    }
174 }
175
176 class Tetris : Window
177 {
178    text = "ECERE Tetris";
179    hasClose = true;
180    clientSize = { 300, 420 };
181
182    Button host
183    {
184       this, text = "Host", position = { 10, 360 }, size = { 60, 20 };
185       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
186       {
187          if(service.Start())
188          {
189             hosting = true;
190             EnableButtons();
191             Update(null);
192          }
193          return true;
194       }
195
196    };
197    Button stop
198    {
199       this, text = "Stop", position = { 80, 360 }, size = { 60, 20 };
200
201       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
202       {
203          hosting = false;
204          service.Stop();
205          EnableButtons();
206          Update(null);
207          return true;
208       }
209    };
210    Button join
211    {
212       this, text = "Join", position = { 10, 380 }, size = { 40, 20 };
213
214       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
215       {
216          TetrisSocket socket { tetris = this };
217          sockets[SERVER] = socket;
218          socket.Connect(address.contents, TETRIS_PORT);
219          EnableButtons();
220          Update(null);
221          return true;
222       }
223    };
224    Button disconnect
225    {
226       this, text = "Disconnect", position = { 170, 370 }, size = { 100, 20 };
227
228       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
229       {
230          sockets[SERVER].Disconnect(0);
231          Update(null);
232          return true;
233       }
234    };
235    EditBox address
236    {
237       this, disabled = true, position = { 60, 380 }, size = { 100, 20 }, contents = "localhost";
238    };
239
240    bool hosting, gameRunning, local;
241    byte turn;
242    Bitmap squares[5];
243    Bitmap backgroundBmp { };
244    Socket sockets[2];
245    byte board[HEIGHT][WIDTH];
246    bool gameOver;
247    int angle;
248    int playerx, playery;
249    int newpiece;
250    int nextAngle, nextPiece;
251
252    background = black;
253    tabCycle = true;
254
255    // --- Tetris Utilities ---
256
257    void NewGame()
258    {
259       int x,y;
260       gameOver = false ;
261       for(y = 0; y<HEIGHT; y++)
262          for(x = 0; x<WIDTH; x++)
263             board[y][x] = 0;
264       turn = CLIENT;
265       Update(null);
266       RandomSeed((uint)(GetTime() * 1000));
267       nextPiece = GetRandom(0, 6);
268       nextAngle = GetRandom(0, 3);
269       NewPiece();
270    }
271
272    void EnableButtons()
273    {
274       join.disabled = false;
275       host.disabled = false;
276       disconnect.disabled = false;
277       stop.disabled = false;
278
279       if(!hosting)
280          stop.disabled = true;
281       if(!sockets[SERVER])
282          disconnect.disabled = true;
283
284       if(hosting || sockets[SERVER])
285          host.disabled = true;
286
287       if(sockets[CLIENT] || hosting)
288          join.disabled = true;
289
290       // address.disabled = join.disabled;
291    }
292
293    // --- Tetris Window Class ---
294
295    void OnRedraw(Surface surface)
296    {
297       // Background...
298       surface.Blit(backgroundBmp, 0,0, 0,0, backgroundBmp.width, backgroundBmp.height);
299
300       //if(GameRunning)
301       {
302          Piece * piece = &pieces[newpiece];
303          int x,y;
304          for(x = 0; x<WIDTH; x++)
305          {
306             for(y = 0; y<HEIGHT; y++)
307             {
308                int square = board[y][x];
309                if(square)
310                   surface.Blit(squares[square-1], x * 16, y * 16, 0, 0, 16, 16);
311             }
312          }
313          if(!gameOver)
314          {
315             for(x = 0; x<piece->w; x++)
316                for(y = 0; y<piece->h; y++)
317                {
318                   int square;
319                   int rx, ry;
320
321                   switch(angle)
322                   {
323                      case 0: rx = x; ry = y; break;
324                      case 1: rx = piece->h-1 - y; ry = x; break;
325                      case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
326                      case 3: rx = y; ry = piece->w-1 - x; break;
327                   }
328
329                   switch(angle)
330                   {
331                      case 0: case 2: rx += piece->x0; break;
332                      case 1: case 3: rx += piece->x1; break;
333                   }
334
335                   square = piece->data[y * piece->w + x];
336                   if(square)
337                      surface.Blit(squares[square-1], (rx + playerx) * 16, (ry + playery) * 16, 0, 0, 16, 16);
338                }
339          }
340          piece = &pieces[nextPiece];
341          for(x = 0; x<piece->w; x++)
342             for(y = 0; y<piece->h; y++)
343             {
344                int square;
345                int rx, ry;
346
347                switch(nextAngle)
348                {
349                   case 0: rx = x; ry = y; break;
350                   case 1: rx = piece->h-1 - y; ry = x; break;
351                   case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
352                   case 3: rx = y; ry = piece->w-1 - x; break;
353                }
354
355                switch(nextAngle)
356                {
357                   case 0: case 2: rx += piece->x0; break;
358                   case 1: case 3: rx += piece->x1; break;
359                }
360
361                square = piece->data[y * piece->w + x];
362                if(square)
363                   surface.Blit(squares[square-1], rx * 16 + (WIDTH + 2) * 16, ry * 16 + 10, 0, 0, 16, 16);
364             }
365       }
366    }
367
368    bool OnCreate()
369    {
370       playerx = 5;
371       NewGame();
372       EnableButtons();
373       return true;
374    }
375
376    void OnDestroy()
377    {
378       if(sockets[0]) sockets[0].OnDisconnect = null;
379       if(sockets[1]) sockets[1].OnDisconnect = null;
380    }
381
382    bool OnLoadGraphics()
383    {
384       int c;
385       Bitmap tetrisBlocks { };
386       if(tetrisBlocks.Load(":tetris.bmp", null, null))
387       {
388          for(c=0; c<5; c++)
389          {
390             if(!squares[c]) squares[c] = Bitmap { };
391             squares[c].Allocate(null, 16,16,16, pixelFormat888, false);
392             squares[c].Grab(tetrisBlocks, c*16, 0);
393             squares[c].MakeDD(displaySystem);
394          }
395
396          backgroundBmp.Allocate(null, 192,352,192, pixelFormat888, false);
397          backgroundBmp.Grab(tetrisBlocks, 0, 24);
398          backgroundBmp.MakeDD(displaySystem);
399       }
400       delete tetrisBlocks;
401       return true;
402    }
403
404    void OnUnloadGraphics()
405    {
406       int c;
407       for(c=0; c<5; c++)
408          squares[c].Free();
409       backgroundBmp.Free();
410    }
411
412    bool OnKeyDown(Key key, unichar ch)
413    {
414       switch(key)
415       {
416          case escape:
417             Destroy(0);
418             break;
419       }
420       return true;
421    }
422
423    void NewPiece()
424    {
425       newpiece = nextPiece;
426       angle = nextAngle;
427       playerx = 5;
428       playery = 0;
429       if(CheckPiece())
430       {
431          gameOver = true;
432       }
433       else
434       {
435          nextPiece = GetRandom(0, 6);
436          nextAngle = GetRandom(0, 3);
437       }
438    }
439
440    void FreezePiece()
441    {
442       Piece * piece = &pieces[newpiece];
443       int x,y;
444       int numLines = 0;
445       for(x = 0; x<piece->w; x++)
446       {
447          for(y = 0; y<piece->h; y++)
448          {
449             int square;
450             int rx, ry;
451
452             switch(angle)
453             {
454                case 0: rx = x; ry = y; break;
455                case 1: rx = piece->h-1 - y; ry = x; break;
456                case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
457                case 3: rx = y; ry = piece->w-1 - x; break;
458             }
459
460             switch(angle)
461             {
462                case 0: case 2: rx += piece->x0; break;
463                case 1: case 3: rx += piece->x1; break;
464             }
465             square = piece->data[y * piece->w + x];
466             if(square)
467                board[ry + playery][rx + playerx] = (byte)square;
468          }
469       }
470       for(y = HEIGHT - 1; y >= 0; y--)
471       {
472          for(x = 0; x < WIDTH; x++)
473          {
474             if(!board[y][x]) break;
475          }
476          if(x == WIDTH)
477          {
478             numLines++;
479             if(y > 0)
480                memmove(&board[1], &board, y * WIDTH);
481             memset(&board, 0, WIDTH);
482             y++;
483          }
484       }
485
486       NewPiece();
487    }
488
489    void DropPiece()
490    {
491       while(!CheckPiece())
492       {
493          playery++;
494       }
495       playery--;
496       FreezePiece();
497    }
498
499    bool CheckPiece()
500    {
501       Piece * piece = &pieces[newpiece];
502       bool result = false;
503       if(((angle == 0 || angle == 2) ? piece->h : piece->w) + playery > HEIGHT)
504       {
505          //playery = HEIGHT - ((angle == 0 || angle == 2) ? piece->h : piece->w);
506          result = true;
507       }
508       if(!result)
509       {
510          int x,y;
511          for(x = 0; x<piece->w && !result; x++)
512             for(y = 0; y<piece->h && !result; y++)
513             {
514                int square;
515                int rx, ry;
516
517                switch(angle)
518                {
519                   case 0: rx = x; ry = y; break;
520                   case 1: rx = piece->h-1 - y; ry = x; break;
521                   case 2: rx = piece->w-1 - x; ry = piece->h -1- y; break;
522                   case 3: rx = y; ry = piece->w-1 - x; break;
523                }
524
525                switch(angle)
526                {
527                   case 0: case 2: rx += piece->x0; break;
528                   case 1: case 3: rx += piece->x1; break;
529                }
530                square = piece->data[y * piece->w + x];
531                if(square && board[ry + playery][rx + playerx])
532                {
533                   //playery--;
534                   result = true;
535                }
536             }
537       }
538       /*if(result)
539          FreezePiece();*/
540       return result;
541    }
542
543    bool OnKeyHit(Key key, unichar ch)
544    {
545       Piece * piece = &pieces[newpiece];
546       if(!gameOver)
547       {
548          switch(key)
549          {
550             case left:
551             case right:
552                if(key == left) playerx--; else playerx++;
553                playerx = Max(playerx, -((angle == 0 || angle == 2) ? (piece->x0) : (piece->x1)));
554                playerx = Min(playerx, 12 - ((angle == 0 || angle == 2) ? (piece->x0 + piece->w) : (piece->x1 + piece->h)));
555                if(CheckPiece())
556                {
557                   if(key == left) playerx++; else playerx--;
558                }
559                break;
560             case down:
561                playery++;
562                if(CheckPiece())
563                {
564                   playery--;
565                   FreezePiece();
566                }
567                break;
568             case up:
569             {
570                int oldx = playerx;
571                angle++;
572                if(angle>3) angle = 0;
573                playerx = Max(playerx, -((angle == 0 || angle == 2) ? (piece->x0) : (piece->x1)));
574                playerx = Min(playerx, 12 - ((angle == 0 || angle == 2) ? (piece->x0 + piece->w) : (piece->x1 + piece->h)));
575
576                if(CheckPiece())
577                {
578                   angle--;
579                   if(angle < 0) angle += 4;
580                   playerx = oldx;
581                }
582                break;
583             }
584             case space:
585             {
586                DropPiece();
587                break;
588             }
589          }
590          Update(null);
591       }
592       return true;
593    }
594
595    bool OnLeftButtonDown(int x, int y, Modifiers mods)
596    {
597       x /= CUBE_WIDTH;
598       y /= CUBE_HEIGHT;
599
600       if(sockets[1-turn])
601       {
602          if(x < NUM_COLUMNS && y < NUM_ROWS)
603          {
604             TPacket packet;
605             packet.type = MSG_POSITION;
606             packet.player = turn;
607             packet.x = (byte)x;
608             packet.y = (byte)y;
609             sockets[turn].Send((byte *)&packet, sizeof(TPacket));
610          }
611       }
612       return true;
613    }
614 }