1 /****************************************************************************
4 Copyright (c) 2001-2007 Jerome Jacovella-St-Louis
8 ****************************************************************************/
11 // --- Definitions ---
16 define NUM_COLUMNS = 8;
19 define CUBE_WIDTH = 40;
20 define CUBE_HEIGHT = 40;
22 define TETRIS_PORT = 7779;
31 static Piece pieces[7] =
83 define MSG_NEWGAME = 1;
84 define MSG_POSITION = 2;
95 // --- Main Function ---
96 class TetrisApp : GuiApplication
98 appName = "ECERE Tetris";
103 TetrisService service { };
105 class TetrisService : Service
111 if(!tetris.sockets[CLIENT] && !tetris.gameRunning)
113 TetrisSocket socket { this };
116 tetris.sockets[CLIENT] = socket;
117 packet.type = MSG_NEWGAME;
118 tetris.sockets[CLIENT].Send((byte *)&packet, sizeof(TPacket));
120 tetris.gameRunning = true;
121 tetris.EnableButtons();
127 class TetrisSocket : Socket
129 // --- Tetris Communication ---
131 static void OnDisconnect(int code)
133 if(this == tetris.sockets[CLIENT])
135 tetris.sockets[CLIENT] = null;
136 tetris.gameRunning = false;
138 else if(this == tetris.sockets[SERVER])
140 tetris.sockets[SERVER] = null;
141 tetris.gameRunning = false;
144 tetris.EnableButtons();
148 uint OnReceive(const byte * buffer, uint count)
150 if(count >= sizeof(TPacket))
152 TPacket packet = *(TPacket *)buffer;
158 tetris.gameRunning = true;
162 return sizeof(TPacket);
169 tetris.sockets[SERVER] = this;
170 tetris.gameRunning = true;
171 tetris.EnableButtons();
176 class Tetris : Window
178 text = "ECERE Tetris";
180 clientSize = { 300, 420 };
184 this, text = "Host", position = { 10, 360 }, size = { 60, 20 };
185 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
199 this, text = "Stop", position = { 80, 360 }, size = { 60, 20 };
201 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
212 this, text = "Join", position = { 10, 380 }, size = { 40, 20 };
214 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
216 TetrisSocket socket { tetris = this };
217 sockets[SERVER] = socket;
218 socket.Connect(address.contents, TETRIS_PORT);
226 this, text = "Disconnect", position = { 170, 370 }, size = { 100, 20 };
228 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
230 sockets[SERVER].Disconnect(0);
237 this, disabled = true, position = { 60, 380 }, size = { 100, 20 }, contents = "localhost";
240 bool hosting, gameRunning, local;
243 Bitmap backgroundBmp { };
245 byte board[HEIGHT][WIDTH];
248 int playerx, playery;
250 int nextAngle, nextPiece;
255 // --- Tetris Utilities ---
261 for(y = 0; y<HEIGHT; y++)
262 for(x = 0; x<WIDTH; x++)
266 RandomSeed((uint)(GetTime() * 1000));
267 nextPiece = GetRandom(0, 6);
268 nextAngle = GetRandom(0, 3);
274 join.disabled = false;
275 host.disabled = false;
276 disconnect.disabled = false;
277 stop.disabled = false;
280 stop.disabled = true;
282 disconnect.disabled = true;
284 if(hosting || sockets[SERVER])
285 host.disabled = true;
287 if(sockets[CLIENT] || hosting)
288 join.disabled = true;
290 // address.disabled = join.disabled;
293 // --- Tetris Window Class ---
295 void OnRedraw(Surface surface)
298 surface.Blit(backgroundBmp, 0,0, 0,0, backgroundBmp.width, backgroundBmp.height);
302 Piece * piece = &pieces[newpiece];
304 for(x = 0; x<WIDTH; x++)
306 for(y = 0; y<HEIGHT; y++)
308 int square = board[y][x];
310 surface.Blit(squares[square-1], x * 16, y * 16, 0, 0, 16, 16);
315 for(x = 0; x<piece->w; x++)
316 for(y = 0; y<piece->h; y++)
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;
331 case 0: case 2: rx += piece->x0; break;
332 case 1: case 3: rx += piece->x1; break;
335 square = piece->data[y * piece->w + x];
337 surface.Blit(squares[square-1], (rx + playerx) * 16, (ry + playery) * 16, 0, 0, 16, 16);
340 piece = &pieces[nextPiece];
341 for(x = 0; x<piece->w; x++)
342 for(y = 0; y<piece->h; y++)
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;
357 case 0: case 2: rx += piece->x0; break;
358 case 1: case 3: rx += piece->x1; break;
361 square = piece->data[y * piece->w + x];
363 surface.Blit(squares[square-1], rx * 16 + (WIDTH + 2) * 16, ry * 16 + 10, 0, 0, 16, 16);
378 if(sockets[0]) sockets[0].OnDisconnect = null;
379 if(sockets[1]) sockets[1].OnDisconnect = null;
382 bool OnLoadGraphics()
385 Bitmap tetrisBlocks { };
386 if(tetrisBlocks.Load(":tetris.bmp", null, null))
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);
396 backgroundBmp.Allocate(null, 192,352,192, pixelFormat888, false);
397 backgroundBmp.Grab(tetrisBlocks, 0, 24);
398 backgroundBmp.MakeDD(displaySystem);
404 void OnUnloadGraphics()
409 backgroundBmp.Free();
412 bool OnKeyDown(Key key, unichar ch)
425 newpiece = nextPiece;
435 nextPiece = GetRandom(0, 6);
436 nextAngle = GetRandom(0, 3);
442 Piece * piece = &pieces[newpiece];
445 for(x = 0; x<piece->w; x++)
447 for(y = 0; y<piece->h; y++)
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;
462 case 0: case 2: rx += piece->x0; break;
463 case 1: case 3: rx += piece->x1; break;
465 square = piece->data[y * piece->w + x];
467 board[ry + playery][rx + playerx] = (byte)square;
470 for(y = HEIGHT - 1; y >= 0; y--)
472 for(x = 0; x < WIDTH; x++)
474 if(!board[y][x]) break;
480 memmove(&board[1], &board, y * WIDTH);
481 memset(&board, 0, WIDTH);
501 Piece * piece = &pieces[newpiece];
503 if(((angle == 0 || angle == 2) ? piece->h : piece->w) + playery > HEIGHT)
505 //playery = HEIGHT - ((angle == 0 || angle == 2) ? piece->h : piece->w);
511 for(x = 0; x<piece->w && !result; x++)
512 for(y = 0; y<piece->h && !result; y++)
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;
527 case 0: case 2: rx += piece->x0; break;
528 case 1: case 3: rx += piece->x1; break;
530 square = piece->data[y * piece->w + x];
531 if(square && board[ry + playery][rx + playerx])
543 bool OnKeyHit(Key key, unichar ch)
545 Piece * piece = &pieces[newpiece];
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)));
557 if(key == left) playerx++; else playerx--;
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)));
579 if(angle < 0) angle += 4;
595 bool OnLeftButtonDown(int x, int y, Modifiers mods)
602 if(x < NUM_COLUMNS && y < NUM_ROWS)
605 packet.type = MSG_POSITION;
606 packet.player = turn;
609 sockets[turn].Send((byte *)&packet, sizeof(TPacket));