3 public enum BlokusColor : byte { none, blue, yellow, red, green };
5 public enum PlayerColor : byte
7 blue, yellow, red, green;
10 // TOFIX: get { return (BlokusColor)((int)this+1); }
11 get { return (BlokusColor)*(int *)&this+1; }
15 static Color colors[2][BlokusColor] =
17 // TOFIX: (omitting Color { })
18 { 0, Color { 64, 64, 96 }, Color { 141, 114, 48 }, Color { 96, 32, 32 }, Color { 64, 96, 64 } },
19 { 0, blue, goldenrod, red, green }
21 Point corners[PlayerColor] =
25 { boardSize-1, boardSize-1 },
29 define numPieces = 21;
31 define boardSize = 20; //10;
33 define boardSize = 20;
37 define squareWidth = 60;
38 define boardStartX = 20;
39 define boardStartY = 30;
41 define blockOffset0 = 4;
42 define blockOffset1 = 10;
43 define blockOffset2 = 30;
44 define blockOffset3 = 36;
46 define squareWidth = 28;
47 define blockOffset0 = 2;
48 define blockOffset1 = 5;
49 define blockOffset2 = 15;
50 define blockOffset3 = 18;
51 define boardStartX = 20;
52 define boardStartY = 30;
62 Piece pieces[numPieces] =
232 struct BlokusGameState
234 byte playerPieces[PlayerColor][numPieces];
235 bool firstPiece[PlayerColor];
236 BlokusColor board[boardSize * boardSize];
237 PlayerColor colorTurn;
238 PlayerColor rotatingColor;
240 bool validPieces[numPieces];
251 // TOFIX: for(p = 0; p < PlayerColor::enumSize; p++)
252 for(p = blue; p <= green; p++)
254 for(i = 0; i < numPieces; i++)
255 playerPieces[p][i] = 1;
256 firstPiece[p] = true;
260 for(i = 0; i < boardSize * boardSize; i++)
265 rotatingColor = blue;
267 validMove = CheckValidMoves(colorTurn, validPieces);
270 bool ValidMove(PlayerColor playerColor, int selectedPiece, int direction, bool flip, int boardX, int boardY)
272 Piece * piece = &pieces[selectedPiece];
275 bool touchCorner = false;
276 int w = (direction & 1) ? piece->h : piece->w;
277 int h = (direction & 1) ? piece->w : piece->h;
279 if(!playerPieces[playerColor][selectedPiece]) return false;
281 if(boardX < 0 || boardY < 0 || boardX + w > boardSize || boardY + h > boardSize) return false;
283 for(y = 0; y < 5; y++)
284 for(x = 0; x < 5; x++)
285 if(PieceBlock(selectedPiece, x, y, direction, flip))
287 int bx = x + boardX, by = y + boardY;
288 if(board[by * boardSize + bx] ||
289 (by > 0 && board[(by-1) * boardSize + bx] == playerColor) ||
290 (by < boardSize-1 && board[(by+1) * boardSize + bx] == playerColor) ||
291 (bx > 0 && board[by * boardSize + bx - 1] == playerColor) ||
292 (bx < boardSize-1 && board[by * boardSize + bx + 1] == playerColor))
297 if((by > 0 && bx > 0 && board[(by-1) * boardSize + (bx-1)] == playerColor) ||
298 (by > 0 && bx < boardSize-1 && board[(by-1) * boardSize + (bx+1)] == playerColor) ||
299 (by < boardSize-1 && bx > 0 && board[(by+1) * boardSize + (bx-1)] == playerColor) ||
300 (by < boardSize-1 && bx < boardSize-1 && board[(by+1) * boardSize + (bx+1)] == playerColor))
303 if(valid && firstPiece[playerColor])
305 for(y = 0; y < 5; y++)
306 for(x = 0; x < 5; x++)
307 if(PieceBlock(selectedPiece, x, y, direction, flip))
309 int bx = x + boardX, by = y + boardY;
310 if(bx == corners[playerColor].x && by == corners[playerColor].y)
318 return valid && touchCorner;
321 bool CheckValidMoves(PlayerColor playerColor, bool validPieces[21])
325 for(p = 0; p < numPieces; p++)
327 bool validMove = false;
328 if(playerPieces[playerColor][p])
331 for(y = 0; y < boardSize && !validMove; y++)
333 for(x = 0; x < boardSize && !validMove; x++)
337 for(direction = 0; direction < 4 && !validMove; direction++)
339 for(flip = 0; flip <=1 && !validMove; flip++)
341 if(ValidMove(playerColor, p, direction, flip, x, y))
342 result = validMove = true;
348 if(validPieces) validPieces[p] = validMove;
353 void PlayMove(int pieceType, int direction, bool flip, int boardX, int boardY)
357 for(y = 0; y < 5; y++)
358 for(x = 0; x < 5; x++)
359 if(PieceBlock(pieceType, x, y, direction, flip))
360 board[(y + boardY) * boardSize + x + boardX] = colorTurn;
361 playerPieces[colorTurn][pieceType] = 0;
362 scores[colorTurn] = 0;
363 for(p = 0; p < numPieces; p++)
365 if(playerPieces[colorTurn][p])
367 Piece * piece = &pieces[p];
369 for(y = 0; y < piece->h; y++)
370 for(x = 0; x < piece->w; x++)
371 if(piece->blocks[y * piece->w + x])
375 if(scores[colorTurn] == 0)
376 bonus[colorTurn] = (pieceType == 0) ? 20 : 15;
378 firstPiece[colorTurn] = false;
379 if(numPlayers == 3 && colorTurn == green)
381 if(++rotatingColor == green) rotatingColor = 0;
383 if(++colorTurn > green) colorTurn = 0;
385 validMove = CheckValidMoves(colorTurn, validPieces);
392 if(numPlayers == 3 && colorTurn == green)
394 if(++rotatingColor == green) rotatingColor = 0;
396 if(++colorTurn > green) colorTurn = 0;
398 validMove = CheckValidMoves(colorTurn, validPieces);
405 PlayerColor turn = colorTurn;
407 for(c = 0; c < 3; c++)
409 if(++turn > green) turn = 0;
410 if(CheckValidMoves(turn, null))
418 int PieceBlock(int p, int x, int y, int direction, bool flip)
420 Piece * piece = &pieces[p];
421 int w = piece->w, h = piece->h;
425 case 0: rx = x; ry = y; break;
426 case 1: ry = h-1 - x; rx = y; break;
427 case 2: ry = h-1 - y; rx = w -1- x; break;
428 case 3: ry = x; rx = w-1-y; break;
430 if(rx < w && ry < h && rx >= 0 && ry >= 0)
431 return piece->blocks[ry * w + (flip ? (w-1-rx) : rx)];
435 class Blokus : Window
437 caption = "Ecere Blokus";
439 minClientSize = { 1068 /*800*/, 700 };
441 anchor = { 0, 0, 0, 0 };
443 borderStyle = sizable;
447 clientSize = { 1276, 708 };
449 font = { "Arial", 12, bold = true };
450 FontResource yourTurnFont { "Arial", 12, bold = true, italic = true, window = this };
451 icon = { ":ollie.png" };
453 ServerConnection server;
456 PlayerColor firstColor;
457 char *playerNames[MaxPlayers];
459 // Current game state
460 BlokusGameState gameState;
463 PlayerColor colorPlayed; // Color currently (or next) being played
465 bool dragging, onBoard;
481 server.SendMessage("Hello :)");
494 if(gotMove && gameStarted && colorPlayed == gameState.colorTurn)
497 btnPass.NotifyClicked(this, btnPass, 0, 0, 0);
498 else if(gameState.validMove)
502 int p = GetRandom(0, numPieces);
503 if(gameState.validPieces[p])
505 bool validMove = false;
507 for(y = 0; y < boardSize && !validMove; y++)
509 for(x = 0; x < boardSize && !validMove; x++)
513 for(direction = 0; direction < 4 && !validMove; direction++)
515 for(flip = 0; flip <=1 && !validMove; flip++)
517 if(gameState.ValidMove(colorPlayed, p, direction, flip, x, y))
521 result = server.PlayPiece(p, direction, flip, x, y);
542 // To work around Flash() lockups on Windows...
546 this, delay = 0.2, true;
563 void NextColorPlayed()
565 if(gameState.numPlayers == 1)
567 if(++colorPlayed > green) colorPlayed = 0;
569 else if(gameState.numPlayers == 2)
571 if((colorPlayed+=2) > green) colorPlayed = firstColor;
573 else if(gameState.numPlayers == 3)
575 colorPlayed = (colorPlayed == firstColor && gameState.rotatingColor == firstColor) ? green : firstColor;
579 void UpdatePlayerNames()
582 if(gameState.numPlayers == 1)
584 for(c = 0; c < 4; c++)
585 playerNames[c] = panel.playerNames[0];
587 else if(gameState.numPlayers == 2)
589 for(c = 0; c < 2; c++)
591 playerNames[c] = panel.playerNames[c];
592 playerNames[c+2] = panel.playerNames[c];
595 else if(gameState.numPlayers == 3)
597 for(c = 0; c < 3; c++)
598 playerNames[c] = panel.playerNames[c];
599 playerNames[3] = panel.playerNames[gameState.rotatingColor];
601 else if(gameState.numPlayers == 4)
603 for(c = 0; c < 4; c++)
604 playerNames[c] = panel.playerNames[c];
608 void DrawSquare(Surface surface, int x, int y, BlokusColor color, int shade)
610 surface.background = colors[shade][color];
611 surface.Area(x+1, y+1, x + squareWidth-1, y + squareWidth-1);
612 surface.foreground = lightGray;
613 surface.VLine(y+blockOffset1, y + blockOffset2, x + blockOffset1);
614 surface.HLine(x+blockOffset1, x + blockOffset3, y + blockOffset1);
615 surface.foreground = white;
616 surface.Rectangle(x + blockOffset0,y+blockOffset0, x + squareWidth-blockOffset0, y + squareWidth - blockOffset0);
619 bool OnClose(bool parentClosing)
621 if((gameStarted && !gameState.over) || hosting)
623 if(MessageBox { type = okCancel,
624 caption = "Ecere Blokus", contents = "Quit Ecere Blokus?" }.Modal() == cancel)
633 server.Disconnect(0);
636 scoresPanel.Destroy(0);
644 bool OnMouseMove(int mx, int my, Modifiers mods)
648 Piece * piece = &pieces[selectedPiece];
649 int w = (direction & 1) ? piece->h : piece->w;
650 int h = (direction & 1) ? piece->w : piece->h;
651 drag = { offset.x + mx, offset.y + my };
653 if(mx - squareDragged.x * squareWidth >= boardStartX - 10 && mx - squareDragged.x * squareWidth < boardStartX + ((boardSize-w)+1) * squareWidth + 10 &&
654 my - squareDragged.y * squareWidth >= boardStartY - 10 && my - squareDragged.y * squareWidth < boardStartY + ((boardSize-h)+1) * squareWidth + 10)
657 x = Max(0,mx - squareDragged.x * squareWidth - boardStartX) / squareWidth;
658 y = Max(0,my - squareDragged.y * squareWidth - boardStartY) / squareWidth;
659 x = Min(x, boardSize-w);
660 y = Min(y, boardSize-h);
661 drag.x = boardStartX + x * squareWidth;
662 drag.y = boardStartY + y * squareWidth;
673 bool OnLeftButtonUp(int mx, int my, Modifiers mods)
679 if(gameStarted && colorPlayed == gameState.colorTurn)
681 Piece * piece = &pieces[selectedPiece];
682 if(gameState.ValidMove(gameState.colorTurn, selectedPiece, direction, flip, boardPos.x, boardPos.y))
683 server.PlayPiece(selectedPiece, direction, flip, boardPos.x, boardPos.y);
693 bool OnRightButtonDown(int mx, int my, Modifiers mods)
695 Piece * piece = &pieces[selectedPiece];
696 int x = squareDragged.x, y = squareDragged.y;
699 w = (direction & 1) ? piece->h : piece->w;
700 h = (direction & 1) ? piece->w : piece->h;
702 offset.x += squareDragged.x * squareWidth;
703 offset.y += squareDragged.y * squareWidth;
704 squareDragged = (direction & 1) ? { x, h-1-y } : { w-1-x, y };
706 offset.x -= squareDragged.x * squareWidth;
707 offset.y -= squareDragged.y * squareWidth;
709 OnMouseMove(mx,my,mods);
715 bool OnSysKeyDown(Key key, unichar ch)
717 // Temporarily disable chat when dragging to get Android arrow keys
719 chat.disabled = true;
723 bool OnKeyDown(Key key, unichar ch)
725 chat.disabled = false;
729 bool OnKeyHit(Key key, unichar ch)
733 OnRightButtonDown(drag.x - offset.x, drag.y - offset.y, 0);
735 if(key == wheelDown || key == down || key == left || key == wheelUp || key == up || key == right)
737 Piece * piece = &pieces[selectedPiece];
738 int mx = drag.x - offset.x, my = drag.y - offset.y;
740 int x = squareDragged.x, y = squareDragged.y;
742 bool isDown = key == wheelDown || key == right || key == down;
746 if(++direction == 4) direction = 0;
750 if(--direction == -1) direction = 3;
752 w = (direction & 1) ? piece->h : piece->w;
753 h = (direction & 1) ? piece->w : piece->h;
755 offset.x += squareDragged.x * squareWidth;
756 offset.y += squareDragged.y * squareWidth;
758 squareDragged = { w-1-y, x };
760 squareDragged = { y, h-1-x };
762 offset.x -= squareDragged.x * squareWidth;
763 offset.y -= squareDragged.y * squareWidth;
765 OnMouseMove(mx,my,0);
772 bool OnLeftButtonDown(int mx, int my, Modifiers mods)
774 if( mx > squareWidth * boardSize + 40)
777 bool selected = false;
782 // Draw Player Pieces
783 bx = squareWidth * boardSize + 40;
785 for(c = 0; c < numPieces; c++)
787 if(gameState.playerPieces[colorPlayed][c])
789 int w = pieces[c].w, h = pieces[c].h;
791 for(y = 0; y < 5; y++)
794 for(x = 0; x < 5; x++)
796 if(PieceBlock(c, x, y, 0, false))
798 int dx = bx + x * squareWidth;
799 int dy = by + y * squareWidth;
800 if(mx >= dx && mx < dx + squareWidth &&
801 my >= dy && my < dy + squareWidth)
805 offset = { bx - mx, by - my };
806 squareDragged = { x, y };
815 bx += w * squareWidth + squareWidth;
817 if(bx + 5 * squareWidth > clientSize.w)
819 bx = squareWidth * boardSize + 40;
820 by += (rh+1) * squareWidth;
830 selectedPiece = pieceNum;
831 this.offset = offset;
833 OnMouseMove(mx, my, mods);
840 float lightValue, lightDir;
849 lightValue += lightDir;
850 if(lightValue < 0) { lightValue = 0; lightDir = .1f; }
851 if(lightValue > 1) { lightValue = 1; lightDir =-.1f; }
857 void OnRedraw(Surface surface)
860 int bx = boardStartX;
861 int by = boardStartY;
865 Color turnLight = white;
866 if(gameStarted && !gameState.over)
868 ColorRGB empty = colors[1][gameState.colorTurn] /*gray*/, full = white;
871 empty.r + lightValue * (full.r - empty.r),
872 empty.g + lightValue * (full.g - empty.g),
873 empty.b + lightValue * (full.b - empty.b)
877 surface.foreground = aqua;
878 for(c = 0; c <= boardSize; c++)
880 surface.HLine(bx,bx+squareWidth*boardSize, by + c * squareWidth);
881 surface.VLine(by,by+squareWidth*boardSize, bx + c * squareWidth);
884 surface.background = colors[blokus.gameStarted][blue];
887 surface.Area(x - 10, y - 10, x + 10, y-1);
888 surface.Area(x - 10, y - 10, x - 1, y+10);
890 s = playerNames[PlayerColor::blue];
894 surface.foreground = (gameState.colorTurn == blue) ? turnLight : white;
895 surface.WriteText(x + 15, y - 20, s, len);
898 surface.background = colors[blokus.gameStarted][yellow];
899 x = bx + boardSize*squareWidth;
901 surface.Area(x - 10, y - 10, x + 10, y-1);
902 surface.Area(x + 1, y - 10, x + 10, y+10);
904 s = playerNames[PlayerColor::yellow];
908 surface.TextExtent(s, len, &tw, null);
909 surface.foreground = (gameState.colorTurn == yellow) ? turnLight : white;
910 surface.WriteText(x - 15 - tw, y - 20, s, len);
913 surface.background = colors[blokus.gameStarted][red];
914 x = bx + boardSize*squareWidth;
915 y = by + boardSize*squareWidth;
916 surface.Area(x - 10, y + 1, x + 10, y+10);
917 surface.Area(x + 1, y - 10, x + 10, y+10);
918 s = playerNames[PlayerColor::red];
922 surface.TextExtent(s, len, &tw, null);
923 surface.foreground = (gameState.colorTurn == red) ? turnLight : white;
924 surface.WriteText(x - 15 - tw, y, s, len);
927 surface.background = colors[blokus.gameStarted][green];
929 y = by + boardSize*squareWidth;
930 surface.Area(x - 10, y + 1, x + 10, y+10);
931 surface.Area(x - 10, y - 10, x - 1, y+10);
932 s = playerNames[PlayerColor::green];
936 surface.foreground = (gameState.colorTurn == green) ? turnLight : white;
937 surface.WriteText(x + 15, y, s, len);
942 surface.font = yourTurnFont.font;
943 surface.foreground = crimson;
944 surface.CenterTextf(x + boardSize*squareWidth/2, y + 3, "Game Over");
946 else if(gameState.numPlayers > 1 && gameStarted && colorPlayed == gameState.colorTurn)
948 surface.font = yourTurnFont.font;
949 surface.foreground = tomato;
950 surface.CenterTextf(x + boardSize*squareWidth/2, y + 3, "Your turn");
953 for(y = 0; y < boardSize; y++)
955 for(x = 0; x < boardSize; x++)
957 BlokusColor color = gameState.board[y * boardSize + x];
960 DrawSquare(surface, bx + x * squareWidth, by + y * squareWidth, color, blokus.gameStarted);
967 // Draw Player Pieces
968 bx = squareWidth * boardSize + 40;
970 for(c = 0; c < numPieces; c++)
972 if(gameState.playerPieces[colorPlayed][c])
974 int w = pieces[c].w, h = pieces[c].h;
975 for(y = 0; y < 5; y++)
977 for(x = 0; x < 5; x++)
979 if(PieceBlock(c, x, y, 0, false))
981 if(!dragging || selectedPiece != c)
983 bx + x * squareWidth,
984 by + y * squareWidth,
986 gameStarted && (gameState.colorTurn == colorPlayed && gameState.validPieces[c]));
991 bx += w * squareWidth + squareWidth;
992 if(bx + 5 * squareWidth > clientSize.w)
994 bx = squareWidth * boardSize + 40;
995 by += rh * squareWidth + squareWidth;
1000 // Draw Dragged piece
1003 for(y = 0; y < 5; y++)
1004 for(x = 0; x < 5; x++)
1006 if(PieceBlock(selectedPiece, x, y, direction, flip))
1009 drag.x + x * squareWidth,
1010 drag.y + y * squareWidth,
1012 gameStarted && gameState.colorTurn == colorPlayed && gameState.validPieces[selectedPiece]);
1014 if(x == 0 || !PieceBlock(selectedPiece, x-1, y, direction, flip))
1016 surface.foreground = white;
1017 surface.VLine(drag.y + y * squareWidth-1, drag.y + (y+1) * squareWidth+1, drag.x + x * squareWidth - 1);
1018 surface.foreground = lime;
1019 surface.VLine(drag.y + y * squareWidth-2, drag.y + (y+1) * squareWidth+2, drag.x + x * squareWidth - 2);
1022 if(y == 0 || !PieceBlock(selectedPiece, x, y-1, direction, flip))
1024 surface.foreground = white;
1025 surface.HLine(drag.x + x * squareWidth-1, drag.x + (x+1) * squareWidth+1, drag.y + y * squareWidth - 1);
1026 surface.foreground = lime;
1027 surface.HLine(drag.x + x * squareWidth-2, drag.x + (x+1) * squareWidth+2, drag.y + y * squareWidth - 2);
1030 if(x == 4 || !PieceBlock(selectedPiece, x+1, y, direction, flip))
1032 surface.foreground = white;
1033 surface.VLine(drag.y + y * squareWidth-1, drag.y + (y+1) * squareWidth+1, drag.x + (x+1) * squareWidth + 1);
1034 surface.foreground = lime;
1035 surface.VLine(drag.y + y * squareWidth-2, drag.y + (y+1) * squareWidth+2, drag.x + (x+1) * squareWidth + 2);
1038 if(y == 4 || !PieceBlock(selectedPiece, x, y+1, direction, flip))
1040 surface.foreground = white;
1041 surface.HLine(drag.x + x * squareWidth-1, drag.x + (x+1) * squareWidth+1, drag.y + (y+1) * squareWidth + 1);
1042 surface.foreground = lime;
1043 surface.HLine(drag.x + x * squareWidth-2, drag.x + (x+1) * squareWidth+2, drag.y + (y+1) * squareWidth + 2);
1053 this, size = { boardSize*squareWidth }, anchor = { left = boardStartX, top = boardStartY + boardSize*squareWidth + 20, bottom = 5 };
1054 font = { "Arial", 11, bold = true };
1055 editTextColor = white;
1056 logTextColor = white;
1058 log.hasVertScroll = bool::true;
1059 log.inactive = bool::true;
1062 bool ProcessCommand(char * command)
1064 blokus.server.SendMessage(command);
1071 this, caption = "No Move Available! Pass...",
1072 //anchor = { right = 5, bottom = 5 };
1073 anchor = { left = squareWidth * boardSize + 40, bottom = 5 };
1077 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1079 btnPass.visible = false;
1080 blokus.passed[blokus.gameState.colorTurn] = true;
1088 class BlokusScores : Window
1092 borderStyle = fixed;
1094 caption = "Blokus Final Scores";
1095 clientSize = { 580, 210 };
1096 font = { "Arial", 12, bold = true };
1097 icon = { ":ollie.png" };
1098 void OnRedraw(Surface surface)
1105 BlokusGameState * state = &blokus.gameState;
1106 surface.foreground = white;
1107 s = "Score"; len = strlen(s);
1108 surface.WriteText(10, 40, s, len);
1110 s = "Bonus"; len = strlen(s);
1111 surface.WriteText(10, 60, s, len);
1113 s = "Total"; len = strlen(s);
1114 surface.WriteText(10, 100, s, len);
1116 if(state->numPlayers < 3)
1118 s = "Grand Total"; len = strlen(s);
1119 surface.WriteText(10, 160, s, len);
1122 for(p = blue; p <= green; p++)
1124 // TOFIX: bug here, why is -1 required?
1125 int x = 80 + (p-1) * 120;
1126 surface.foreground = colors[1][p];
1127 /* // GCC internal compiler error with -O2, MinGW GCC 4.4.0
1128 s = (state->numPlayers == 3 && p == green) ? "* Green *" : blokus.playerNames[p];
1130 surface.WriteText(x, 20, s, len);
1132 if(state->numPlayers == 3 && p == green)
1136 surface.WriteText(x, 20, s, len);
1138 else if(blokus.playerNames[p])
1140 s = blokus.playerNames[p];
1142 surface.WriteText(x, 20, s, len);
1145 s = temp; sprintf(temp, "%d", state->scores[p]);
1147 surface.WriteText(x + 30, 40, s, len);
1151 s = temp; sprintf(temp, "%d", state->bonus[p]);
1153 surface.WriteText(x + 30, 60, s, len);
1156 if(state->numPlayers > 2)
1157 grandTotals[p] = state->scores[p] + state->bonus[p];
1158 s = temp; sprintf(temp, "%d", state->scores[p] + state->bonus[p]);
1160 surface.WriteText(x + 30, 100, s, len);
1162 if((state->numPlayers == 2 && p <= yellow) ||
1163 (state->numPlayers == 1 && p == blue))
1165 // TOFIX: Annoying +2 conversion issue
1166 if(state->numPlayers == 2)
1167 grandTotals[p] = state->scores[p] + state->bonus[p] +
1168 state->scores[p+red /*2*/] + state->bonus[p+red /*2*/];
1170 grandTotals[p] = state->scores[0] + state->bonus[0] +
1171 state->scores[1] + state->bonus[1] +
1172 state->scores[2] + state->bonus[2] +
1173 state->scores[3] + state->bonus[3];
1175 if(blokus.playerNames[p])
1177 s = blokus.playerNames[p];
1179 surface.WriteText(x, 140, s, len);
1182 s = temp; sprintf(temp, "%d", grandTotals[p]);
1184 surface.WriteText(x + 30, 160, s, len);
1187 if(state->numPlayers > 1)
1190 int c, greatest = -MAXINT;
1191 int numTies = 0, ties[3], winner;
1194 for(c = 0; c < state->numPlayers; c++)
1196 if(grandTotals[c] > greatest)
1198 greatest = grandTotals[c];
1202 else if(grandTotals[c] == greatest)
1209 ties[numTies++] = c;
1214 for(c = 0; c < numTies; c++)
1216 strcat(string, blokus.playerNames[c]);
1218 strcat(string, ", ");
1219 else if(c < numTies-1)
1220 strcat(string, " and ");
1222 surface.foreground = white;
1223 strcat(string, " tied!");
1227 surface.foreground = colors[1][(PlayerColor)winner];
1228 sprintf(string, "%s won!", blokus.playerNames[winner]);
1231 len = strlen(string);
1232 surface.WriteText(100, 180, string, strlen(string));
1237 BlokusScores scoresPanel { visible = false };
1241 class BlokusApp : GuiApplication
1243 //fullScreen = true;
1251 bool Cycle(bool idle)
1253 // This is here because it hangs in MovePlayed() (Why?)
1254 scoresPanel.visible = blokus.gameStarted && blokus.gameState.over;
1256 /*if(blokus.gameState.over)
1257 panel.btnStart.NotifyClicked(panel, panel.btnStart, 0, 0, 0);*/
1264 blokusService.Stop();
1268 import remote "BlokusServer"
1270 define app = ((BlokusApp)__thisModule.application);
1272 define BLOKUS_PORT = 1495;
1273 static bool hosting;
1274 define MaxPlayers = 4;
1276 class CommunicationPanel : Window
1278 caption = "Blokus Communication Panel";
1279 background = lightSlateGray;
1280 borderStyle = fixed;
1283 clientSize = { 430, 300 };
1285 anchor = { right = 0, bottom = 0 };
1287 icon = { ":ollie.png" };
1289 // Other player info
1290 char playerNames[MaxPlayers][256];
1292 DataField fldName { header = "Name", width = 100 };
1293 DataField fldAddr { header = "Address" };
1295 bool OnClose(bool parentClosing)
1297 if(!blokus || blokus.destroyed || blokus.Destroy(0))
1306 blokusService.Stop();
1310 CommunicationPanel()
1312 listPlayers.AddField(fldName);
1313 listPlayers.AddField(fldAddr);
1319 listPlayers.Clear();
1320 fldAddr.header = hosting ? "Address" : "";
1321 for(c = 0; c<MaxPlayers; c++)
1325 if(serverPlayers[c])
1327 DataRow row = listPlayers.AddRow();
1328 DCOMServerObject object = (DCOMServerObject)serverPlayers[c].connection._vTbl[-1];
1330 row.tag = serverPlayers[c].id;
1331 row.SetData(fldName, serverPlayers[c].name);
1332 row.SetData(fldAddr, object.serverSocket.inetAddress);
1335 else if(playerNames[c][0])
1337 DataRow row = listPlayers.AddRow();
1338 row.SetData(fldName, playerNames[c]);
1343 void UpdateControlsStates()
1349 for(c = 0; c<MaxPlayers; c++)
1350 if(serverPlayers[c])
1353 lblServerAddress.disabled = serverAddress.disabled = blokus.server ? true : false;
1354 lblPlayerName.disabled = playerName.disabled = blokus.server ? true : false;
1355 lblServerAddress.Update(null);
1356 lblPlayerName.Update(null);
1357 btnConnect.visible = blokus.server ? false : true;
1358 btnDisconnect.visible = blokus.server ? true : false;
1359 blokus.chat.visible = blokus.server ? true : false;
1361 btnHost.visible = !hosting && !blokus.server;
1362 btnStopHosting.visible = hosting;
1363 btnStart.visible = hosting && (!serverGameStarted || serverGameState.over) && numPlayers > 0;
1364 btnStopGame.visible = hosting && (serverGameStarted && !serverGameState.over);
1365 listPlayers.visible = (hosting && (serverGameStarted || numPlayers > 0)) || (!hosting && blokus.server && blokus.gameStarted);
1366 btnKick.visible = hosting && !serverGameStarted && numPlayers > 0;
1367 btnKick.disabled = listPlayers.currentRow ? false : true;
1369 EditBox serverAddress
1371 this, caption = "Server Address:", altA, font = { "Tahoma", 10, bold = true }, size = { 220, 24 }, position = { 16, 64 }, contents = "localhost"
1373 Label lblServerAddress { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 40 }, labeledWindow = serverAddress };
1376 this, caption = "Connect", altC, isDefault = true, font = { "Arial", 16, bold = true }, size = { 126, 32 }, position = { 256, 64 };
1378 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1382 blokus.server = ServerConnection
1384 void OnDisconnect(int code)
1389 delete blokus.server;
1390 blokus.gameStarted = false;
1391 blokus.turnLightTimer.Stop();
1392 blokus.lightValue = 1;
1393 blokus.lightDir = -.1f;
1394 blokus.Update(null);
1395 panel.UpdateControlsStates();
1396 panel.ListPlayers();
1398 DCOMClientObject::OnDisconnect(code);
1402 void GameStarted(GameInfo gameInfo)
1407 blokus.gameState.numPlayers = gameInfo.numPlayers;
1408 blokus.firstColor = gameInfo.firstColor;
1409 blokus.colorPlayed = blokus.firstColor;
1411 for(c = 0; c<MaxPlayers; c++)
1413 if(gameInfo.players[c][0])
1414 strcpy(panel.playerNames[np++], gameInfo.players[c]);
1417 blokus.btnPass.visible = false;
1418 blokus.gameState.NewGame();
1419 blokus.passed[0] = false;
1420 blokus.passed[1] = false;
1421 blokus.passed[2] = false;
1422 blokus.passed[3] = false;
1423 blokus.gameStarted = true;
1424 blokus.lightValue = 1;
1425 blokus.lightDir = -.1f;
1426 blokus.turnLightTimer.Start();
1427 blokus.UpdatePlayerNames();
1429 blokus.Update(null);
1431 panel.UpdateControlsStates();
1432 panel.ListPlayers();
1439 panel.ListPlayers();
1440 blokus.gameStarted = false;
1441 blokus.btnPass.visible = false;
1442 blokus.Update(null);
1445 void MovePlayed(PlayerColor color, int pieceType, int direction, bool flip, int boardX, int boardY)
1447 blokus.gameState.PlayMove(pieceType, direction, flip, boardX, boardY);
1448 if(color == blokus.colorPlayed)
1449 blokus.NextColorPlayed();
1451 blokus.gotMove = true;
1453 if(blokus.colorPlayed == blokus.gameState.colorTurn && !blokus.gameState.over)
1455 if(!blokus.gameState.validMove)
1457 if(!blokus.passed[blokus.gameState.colorTurn])
1459 blokus.btnPass.visible = true;
1464 blokus.server.Pass();
1466 else if(!blokus.active)
1470 // This hangs here, why?
1471 /*if(blokus.gameState.over)
1472 scoresPanel.visible = true;*/
1475 blokus.UpdatePlayerNames();
1476 blokus.Update(null);
1480 void Passed(PlayerColor color)
1482 blokus.gameState.Pass();
1483 if(color == blokus.colorPlayed)
1484 blokus.NextColorPlayed();
1485 else if(!blokus.active)
1488 if(blokus.colorPlayed == blokus.gameState.colorTurn && !blokus.gameState.over)
1490 if(!blokus.gameState.validMove)
1492 if(!blokus.passed[blokus.gameState.colorTurn])
1494 blokus.btnPass.visible = true;
1499 blokus.server.Pass();
1501 else if(!blokus.active)
1507 blokus.UpdatePlayerNames();
1508 blokus.Update(null);
1512 void NotifyMessage(String name, String msg)
1514 EditBox log = blokus.chat.log;
1515 char * format = (log.numLines > 1 || log.line.count) ?
1516 "\n%s: %s" : "%s: %s";
1517 int len = strlen(msg);
1518 // Avoid buffer overflow...
1519 if(len >= MAX_F_STRING-100)
1520 msg[MAX_F_STRING-100] = 0;
1521 blokus.chat.Log(format, name, msg);
1524 incref blokus.server;
1525 if(blokus.server.Connect(serverAddress.contents, BLOKUS_PORT))
1527 int playerID = blokus.server.Join();
1528 if(blokus.server && playerID != -1)
1529 blokus.server.SetName(playerName.contents);
1531 blokus.server.Disconnect(0);
1532 UpdateControlsStates();
1535 delete blokus.server;
1540 Button btnDisconnect
1542 this, caption = "Disconnect", altD, font = { "Arial", 16, bold = true }, size = { 126, 32 }, position = { 256, 64 }, visible = false;
1544 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1546 if(!blokus.gameStarted || blokus.gameState.over ||
1547 MessageBox { type = okCancel, caption = "Ecere Blokus",
1548 contents = "Game in progress! Disconnect?"
1552 blokus.server.Disconnect(0);
1559 this, caption = "Host", altH, font = { "Arial", 16, bold = true }, size = { 90, 32 }, position = { 16, 112 };
1561 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1563 if(!blokus.gameStarted)
1565 if(blokusService.Start())
1569 UpdateControlsStates();
1575 Button btnStopHosting
1577 this, caption = "Stop Hosting", altP, font = { "Arial", 16, bold = true }, position = { 16, 112 }, visible = false;
1579 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1583 for(c = 0; c<MaxPlayers; c++)
1584 if(serverPlayers[c])
1587 MessageBox { type = okCancel, caption = "Ecere Blokus",
1588 contents = "Players connected! Stop hosting?"
1592 blokusService.Stop();
1596 UpdateControlsStates();
1603 this, caption = "Start Game", altS, font = { "Arial", 16, bold = true }, size = { 124, 32 }, position = { 256, 112 }, visible = false;
1605 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1610 UpdateControlsStates();
1617 this, caption = "Stop Game", altG, font = { "Arial", 16, bold = true }, position = { 256, 112 }, visible = false;
1619 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1621 if(!serverGameStarted || serverGameState.over ||
1622 MessageBox { type = okCancel, caption = "Ecere Blokus",
1623 contents = "Stop game in progress?"
1627 UpdateControlsStates();
1634 this, caption = "Players Connected", altD, size = { 236, 84 }, position = { 16, 176 }, visible = false, hasHeader = true;
1636 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1638 UpdateControlsStates();
1642 Label lblListPlayers { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 152 }, visible = false, labeledWindow = listPlayers };
1645 this, caption = "Kick", altK, font = { "Arial", 16, bold = true }, size = { 80, 32 }, position = { 264, 224 }, visible = false;
1647 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1649 DataRow row = listPlayers.currentRow;
1652 int id = (int)row.tag;
1654 sprintf(msg, "Kick %s?", serverPlayers[id].name);
1655 if(MessageBox { type = okCancel, caption = "Ecere Blokus",
1665 this, caption = "Player Name:", altN, font = { "Arial", 12 }, size = { 132, 24 }, position = { 104, 8 }, contents = "BlokusPlayer"
1667 Label lblPlayerName { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 16 }, labeledWindow = playerName };
1670 CommunicationPanel panel { };
1672 DCOMService blokusService { port = BLOKUS_PORT };