3 public enum CornerBlocksColor : byte { none, blue, yellow, red, green };
5 public enum PlayerColor : byte
7 blue, yellow, red, green;
8 property CornerBlocksColor
10 get { return (CornerBlocksColor)((int)this+1); }
14 static Color colors[2][CornerBlocksColor] =
16 // TOFIX: (omitting Color { })
17 { 0, Color { 64, 64, 96 }, Color { 141, 114, 48 }, Color { 96, 32, 32 }, Color { 64, 96, 64 } },
18 { 0, blue, goldenrod, red, green }
20 Point corners[PlayerColor] =
24 { boardSize-1, boardSize-1 },
28 define numPieces = 21;
30 define boardSize = 20; //10;
32 define boardSize = 20;
36 define squareWidth = 60;
37 define boardStartX = 20;
38 define boardStartY = 30;
40 define blockOffset0 = 4;
41 define blockOffset1 = 10;
42 define blockOffset2 = 30;
43 define blockOffset3 = 36;
45 define squareWidth = 28;
46 define blockOffset0 = 2;
47 define blockOffset1 = 5;
48 define blockOffset2 = 15;
49 define blockOffset3 = 18;
50 define boardStartX = 20;
51 define boardStartY = 30;
61 Piece pieces[numPieces] =
231 struct CornerBlocksGameState
233 byte playerPieces[PlayerColor][numPieces];
234 bool firstPiece[PlayerColor];
235 CornerBlocksColor board[boardSize * boardSize];
236 PlayerColor colorTurn;
237 PlayerColor rotatingColor;
239 bool validPieces[numPieces];
250 for(p = 0; p < PlayerColor::enumSize; p++)
252 for(i = 0; i < numPieces; i++)
253 playerPieces[p][i] = 1;
254 firstPiece[p] = true;
258 for(i = 0; i < boardSize * boardSize; i++)
263 rotatingColor = blue;
265 validMove = CheckValidMoves(colorTurn, validPieces);
268 bool ValidMove(PlayerColor playerColor, int selectedPiece, int direction, bool flip, int boardX, int boardY)
270 Piece * piece = &pieces[selectedPiece];
273 bool touchCorner = false;
274 int w = (direction & 1) ? piece->h : piece->w;
275 int h = (direction & 1) ? piece->w : piece->h;
277 if(!playerPieces[playerColor][selectedPiece]) return false;
279 if(boardX < 0 || boardY < 0 || boardX + w > boardSize || boardY + h > boardSize) return false;
281 for(y = 0; y < 5; y++)
282 for(x = 0; x < 5; x++)
283 if(PieceBlock(selectedPiece, x, y, direction, flip))
285 int bx = x + boardX, by = y + boardY;
286 if(board[by * boardSize + bx] ||
287 (by > 0 && board[(by-1) * boardSize + bx] == playerColor) ||
288 (by < boardSize-1 && board[(by+1) * boardSize + bx] == playerColor) ||
289 (bx > 0 && board[by * boardSize + bx - 1] == playerColor) ||
290 (bx < boardSize-1 && board[by * boardSize + bx + 1] == playerColor))
295 if((by > 0 && bx > 0 && board[(by-1) * boardSize + (bx-1)] == playerColor) ||
296 (by > 0 && bx < boardSize-1 && board[(by-1) * boardSize + (bx+1)] == playerColor) ||
297 (by < boardSize-1 && bx > 0 && board[(by+1) * boardSize + (bx-1)] == playerColor) ||
298 (by < boardSize-1 && bx < boardSize-1 && board[(by+1) * boardSize + (bx+1)] == playerColor))
301 if(valid && firstPiece[playerColor])
303 for(y = 0; y < 5; y++)
304 for(x = 0; x < 5; x++)
305 if(PieceBlock(selectedPiece, x, y, direction, flip))
307 int bx = x + boardX, by = y + boardY;
308 if(bx == corners[playerColor].x && by == corners[playerColor].y)
316 return valid && touchCorner;
319 bool CheckValidMoves(PlayerColor playerColor, bool validPieces[21])
323 for(p = 0; p < numPieces; p++)
325 bool validMove = false;
326 if(playerPieces[playerColor][p])
329 for(y = 0; y < boardSize && !validMove; y++)
331 for(x = 0; x < boardSize && !validMove; x++)
335 for(direction = 0; direction < 4 && !validMove; direction++)
337 for(flip = 0; flip <= 1 && !validMove; flip++)
339 if(ValidMove(playerColor, p, direction, flip, x, y))
340 result = validMove = true;
346 if(validPieces) validPieces[p] = validMove;
351 void PlayMove(int pieceType, int direction, bool flip, int boardX, int boardY)
355 for(y = 0; y < 5; y++)
356 for(x = 0; x < 5; x++)
357 if(PieceBlock(pieceType, x, y, direction, flip))
358 board[(y + boardY) * boardSize + x + boardX] = colorTurn;
359 playerPieces[colorTurn][pieceType] = 0;
360 scores[colorTurn] = 0;
361 for(p = 0; p < numPieces; p++)
363 if(playerPieces[colorTurn][p])
365 Piece * piece = &pieces[p];
367 for(y = 0; y < piece->h; y++)
368 for(x = 0; x < piece->w; x++)
369 if(piece->blocks[y * piece->w + x])
373 if(scores[colorTurn] == 0)
374 bonus[colorTurn] = (pieceType == 0) ? 20 : 15;
376 firstPiece[colorTurn] = false;
377 if(numPlayers == 3 && colorTurn == green)
379 if(++rotatingColor == green) rotatingColor = 0;
381 if(++colorTurn > green) colorTurn = 0;
383 validMove = CheckValidMoves(colorTurn, validPieces);
390 if(numPlayers == 3 && colorTurn == green)
392 if(++rotatingColor == green) rotatingColor = 0;
394 if(++colorTurn > green) colorTurn = 0;
396 validMove = CheckValidMoves(colorTurn, validPieces);
403 PlayerColor turn = colorTurn;
405 for(c = 0; c < 3; c++)
407 if(++turn > green) turn = 0;
408 if(CheckValidMoves(turn, null))
416 int PieceBlock(int p, int x, int y, int direction, bool flip)
418 Piece * piece = &pieces[p];
419 int w = piece->w, h = piece->h;
423 case 0: rx = x; ry = y; break;
424 case 1: ry = h-1 - x; rx = y; break;
425 case 2: ry = h-1 - y; rx = w -1- x; break;
426 case 3: ry = x; rx = w-1-y; break;
428 if(rx < w && ry < h && rx >= 0 && ry >= 0)
429 return piece->blocks[ry * w + (flip ? (w-1-rx) : rx)];
433 class CornerBlocks : Window
435 caption = "Ecere Corner Blocks";
437 minClientSize = { 1068 /*800*/, 700 };
439 anchor = { 0, 0, 0, 0 };
441 borderStyle = sizable;
445 clientSize = { 1276, 708 };
447 font = { "Arial", 12, bold = true };
448 FontResource yourTurnFont { "Arial", 12, bold = true, italic = true, window = this };
449 icon = { ":ollie.png" };
451 ServerConnection server;
454 PlayerColor firstColor;
455 char *playerNames[MaxPlayers];
457 // Current game state
458 CornerBlocksGameState gameState;
461 PlayerColor colorPlayed; // Color currently (or next) being played
463 bool dragging, onBoard;
479 server.SendMessage("Hello :)");
492 if(gotMove && gameStarted && colorPlayed == gameState.colorTurn)
495 btnPass.NotifyClicked(this, btnPass, 0, 0, 0);
496 else if(gameState.validMove)
500 int p = GetRandom(0, numPieces);
501 if(gameState.validPieces[p])
503 bool validMove = false;
505 for(y = 0; y < boardSize && !validMove; y++)
507 for(x = 0; x < boardSize && !validMove; x++)
511 for(direction = 0; direction < 4 && !validMove; direction++)
513 for(flip = 0; flip <= 1 && !validMove; flip++)
515 if(gameState.ValidMove(colorPlayed, p, direction, flip, x, y))
519 result = server.PlayPiece(p, direction, flip, x, y);
540 // To work around Flash() lockups on Windows...
544 this, delay = 0.2, true;
561 void NextColorPlayed()
563 if(gameState.numPlayers == 1)
565 if(++colorPlayed > green) colorPlayed = 0;
567 else if(gameState.numPlayers == 2)
569 if((colorPlayed+=2) > green) colorPlayed = firstColor;
571 else if(gameState.numPlayers == 3)
573 colorPlayed = (colorPlayed == firstColor && gameState.rotatingColor == firstColor) ? green : firstColor;
577 void UpdatePlayerNames()
580 if(gameState.numPlayers == 1)
582 for(c = 0; c < 4; c++)
583 playerNames[c] = panel.playerNames[0];
585 else if(gameState.numPlayers == 2)
587 for(c = 0; c < 2; c++)
589 playerNames[c] = panel.playerNames[c];
590 playerNames[c+2] = panel.playerNames[c];
593 else if(gameState.numPlayers == 3)
595 for(c = 0; c < 3; c++)
596 playerNames[c] = panel.playerNames[c];
597 playerNames[3] = panel.playerNames[gameState.rotatingColor];
599 else if(gameState.numPlayers == 4)
601 for(c = 0; c < 4; c++)
602 playerNames[c] = panel.playerNames[c];
606 void DrawSquare(Surface surface, int x, int y, CornerBlocksColor color, int shade)
608 surface.background = colors[shade][color];
609 surface.Area(x+1, y+1, x + squareWidth-1, y + squareWidth-1);
610 surface.foreground = lightGray;
611 surface.VLine(y+blockOffset1, y + blockOffset2, x + blockOffset1);
612 surface.HLine(x+blockOffset1, x + blockOffset3, y + blockOffset1);
613 surface.foreground = white;
614 surface.Rectangle(x + blockOffset0,y+blockOffset0, x + squareWidth-blockOffset0, y + squareWidth - blockOffset0);
617 bool OnClose(bool parentClosing)
619 if((gameStarted && !gameState.over) || hosting)
621 if(MessageBox { type = okCancel,
622 caption = "Ecere CornerBlocks", contents = "Quit Ecere CornerBlocks?" }.Modal() == cancel)
631 server.Disconnect(0);
634 scoresPanel.Destroy(0);
642 bool OnMouseMove(int mx, int my, Modifiers mods)
646 Piece * piece = &pieces[selectedPiece];
647 int w = (direction & 1) ? piece->h : piece->w;
648 int h = (direction & 1) ? piece->w : piece->h;
649 drag = { offset.x + mx, offset.y + my };
651 if(mx - squareDragged.x * squareWidth >= boardStartX - 10 && mx - squareDragged.x * squareWidth < boardStartX + ((boardSize-w)+1) * squareWidth + 10 &&
652 my - squareDragged.y * squareWidth >= boardStartY - 10 && my - squareDragged.y * squareWidth < boardStartY + ((boardSize-h)+1) * squareWidth + 10)
655 x = Max(0,mx - squareDragged.x * squareWidth - boardStartX) / squareWidth;
656 y = Max(0,my - squareDragged.y * squareWidth - boardStartY) / squareWidth;
657 x = Min(x, boardSize-w);
658 y = Min(y, boardSize-h);
659 drag.x = boardStartX + x * squareWidth;
660 drag.y = boardStartY + y * squareWidth;
671 bool OnLeftButtonUp(int mx, int my, Modifiers mods)
677 if(gameStarted && colorPlayed == gameState.colorTurn)
679 Piece * piece = &pieces[selectedPiece];
680 if(gameState.ValidMove(gameState.colorTurn, selectedPiece, direction, flip, boardPos.x, boardPos.y))
681 server.PlayPiece(selectedPiece, direction, flip, boardPos.x, boardPos.y);
691 bool OnRightButtonDown(int mx, int my, Modifiers mods)
693 Piece * piece = &pieces[selectedPiece];
694 int x = squareDragged.x, y = squareDragged.y;
697 w = (direction & 1) ? piece->h : piece->w;
698 h = (direction & 1) ? piece->w : piece->h;
700 offset.x += squareDragged.x * squareWidth;
701 offset.y += squareDragged.y * squareWidth;
702 squareDragged = (direction & 1) ? { x, h-1-y } : { w-1-x, y };
704 offset.x -= squareDragged.x * squareWidth;
705 offset.y -= squareDragged.y * squareWidth;
707 OnMouseMove(mx,my,mods);
713 bool OnSysKeyDown(Key key, unichar ch)
715 // Temporarily disable chat when dragging to get Android arrow keys
717 chat.disabled = true;
721 bool OnKeyDown(Key key, unichar ch)
723 chat.disabled = false;
727 bool OnKeyHit(Key key, unichar ch)
731 OnRightButtonDown(drag.x - offset.x, drag.y - offset.y, 0);
733 if(key == wheelDown || key == down || key == left || key == wheelUp || key == up || key == right)
735 Piece * piece = &pieces[selectedPiece];
736 int mx = drag.x - offset.x, my = drag.y - offset.y;
738 int x = squareDragged.x, y = squareDragged.y;
740 bool isDown = key == wheelDown || key == right || key == down;
744 if(++direction == 4) direction = 0;
748 if(--direction == -1) direction = 3;
750 w = (direction & 1) ? piece->h : piece->w;
751 h = (direction & 1) ? piece->w : piece->h;
753 offset.x += squareDragged.x * squareWidth;
754 offset.y += squareDragged.y * squareWidth;
756 squareDragged = { w-1-y, x };
758 squareDragged = { y, h-1-x };
760 offset.x -= squareDragged.x * squareWidth;
761 offset.y -= squareDragged.y * squareWidth;
763 OnMouseMove(mx,my,0);
770 bool OnLeftButtonDown(int mx, int my, Modifiers mods)
772 if( mx > squareWidth * boardSize + 40)
775 bool selected = false;
780 // Draw Player Pieces
781 bx = squareWidth * boardSize + 40;
783 for(c = 0; c < numPieces; c++)
785 if(gameState.playerPieces[colorPlayed][c])
787 int w = pieces[c].w, h = pieces[c].h;
789 for(y = 0; y < 5; y++)
792 for(x = 0; x < 5; x++)
794 if(PieceBlock(c, x, y, 0, false))
796 int dx = bx + x * squareWidth;
797 int dy = by + y * squareWidth;
798 if(mx >= dx && mx < dx + squareWidth &&
799 my >= dy && my < dy + squareWidth)
803 offset = { bx - mx, by - my };
804 squareDragged = { x, y };
813 bx += w * squareWidth + squareWidth;
815 if(bx + 5 * squareWidth > clientSize.w)
817 bx = squareWidth * boardSize + 40;
818 by += (rh+1) * squareWidth;
828 selectedPiece = pieceNum;
829 this.offset = offset;
831 OnMouseMove(mx, my, mods);
838 float lightValue, lightDir;
847 lightValue += lightDir;
848 if(lightValue < 0) { lightValue = 0; lightDir = .1f; }
849 if(lightValue > 1) { lightValue = 1; lightDir =-.1f; }
855 void OnRedraw(Surface surface)
858 int bx = boardStartX;
859 int by = boardStartY;
863 Color turnLight = white;
864 if(gameStarted && !gameState.over)
866 ColorRGB empty = colors[1][gameState.colorTurn] /*gray*/, full = white;
869 empty.r + lightValue * (full.r - empty.r),
870 empty.g + lightValue * (full.g - empty.g),
871 empty.b + lightValue * (full.b - empty.b)
875 surface.foreground = aqua;
876 for(c = 0; c <= boardSize; c++)
878 surface.HLine(bx,bx+squareWidth*boardSize, by + c * squareWidth);
879 surface.VLine(by,by+squareWidth*boardSize, bx + c * squareWidth);
882 surface.background = colors[cornerBlocks.gameStarted][blue];
885 surface.Area(x - 10, y - 10, x + 10, y-1);
886 surface.Area(x - 10, y - 10, x - 1, y+10);
888 s = playerNames[PlayerColor::blue];
892 surface.foreground = (gameState.colorTurn == blue) ? turnLight : white;
893 surface.WriteText(x + 15, y - 20, s, len);
896 surface.background = colors[cornerBlocks.gameStarted][yellow];
897 x = bx + boardSize*squareWidth;
899 surface.Area(x - 10, y - 10, x + 10, y-1);
900 surface.Area(x + 1, y - 10, x + 10, y+10);
902 s = playerNames[PlayerColor::yellow];
906 surface.TextExtent(s, len, &tw, null);
907 surface.foreground = (gameState.colorTurn == yellow) ? turnLight : white;
908 surface.WriteText(x - 15 - tw, y - 20, s, len);
911 surface.background = colors[cornerBlocks.gameStarted][red];
912 x = bx + boardSize*squareWidth;
913 y = by + boardSize*squareWidth;
914 surface.Area(x - 10, y + 1, x + 10, y+10);
915 surface.Area(x + 1, y - 10, x + 10, y+10);
916 s = playerNames[PlayerColor::red];
920 surface.TextExtent(s, len, &tw, null);
921 surface.foreground = (gameState.colorTurn == red) ? turnLight : white;
922 surface.WriteText(x - 15 - tw, y, s, len);
925 surface.background = colors[cornerBlocks.gameStarted][green];
927 y = by + boardSize*squareWidth;
928 surface.Area(x - 10, y + 1, x + 10, y+10);
929 surface.Area(x - 10, y - 10, x - 1, y+10);
930 s = playerNames[PlayerColor::green];
934 surface.foreground = (gameState.colorTurn == green) ? turnLight : white;
935 surface.WriteText(x + 15, y, s, len);
940 surface.font = yourTurnFont.font;
941 surface.foreground = crimson;
942 surface.CenterTextf(x + boardSize*squareWidth/2, y + 3, "Game Over");
944 else if(gameState.numPlayers > 1 && gameStarted && colorPlayed == gameState.colorTurn)
946 surface.font = yourTurnFont.font;
947 surface.foreground = tomato;
948 surface.CenterTextf(x + boardSize*squareWidth/2, y + 3, "Your turn");
951 for(y = 0; y < boardSize; y++)
953 for(x = 0; x < boardSize; x++)
955 CornerBlocksColor color = gameState.board[y * boardSize + x];
958 DrawSquare(surface, bx + x * squareWidth, by + y * squareWidth, color, cornerBlocks.gameStarted);
965 // Draw Player Pieces
966 bx = squareWidth * boardSize + 40;
968 for(c = 0; c < numPieces; c++)
970 if(gameState.playerPieces[colorPlayed][c])
972 int w = pieces[c].w, h = pieces[c].h;
973 for(y = 0; y < 5; y++)
975 for(x = 0; x < 5; x++)
977 if(PieceBlock(c, x, y, 0, false))
979 if(!dragging || selectedPiece != c)
981 bx + x * squareWidth,
982 by + y * squareWidth,
984 gameStarted && (gameState.colorTurn == colorPlayed && gameState.validPieces[c]));
989 bx += w * squareWidth + squareWidth;
990 if(bx + 5 * squareWidth > clientSize.w)
992 bx = squareWidth * boardSize + 40;
993 by += rh * squareWidth + squareWidth;
998 // Draw Dragged piece
1001 for(y = 0; y < 5; y++)
1002 for(x = 0; x < 5; x++)
1004 if(PieceBlock(selectedPiece, x, y, direction, flip))
1007 drag.x + x * squareWidth,
1008 drag.y + y * squareWidth,
1010 gameStarted && gameState.colorTurn == colorPlayed && gameState.validPieces[selectedPiece]);
1012 if(x == 0 || !PieceBlock(selectedPiece, x-1, y, direction, flip))
1014 surface.foreground = white;
1015 surface.VLine(drag.y + y * squareWidth-1, drag.y + (y+1) * squareWidth+1, drag.x + x * squareWidth - 1);
1016 surface.foreground = lime;
1017 surface.VLine(drag.y + y * squareWidth-2, drag.y + (y+1) * squareWidth+2, drag.x + x * squareWidth - 2);
1020 if(y == 0 || !PieceBlock(selectedPiece, x, y-1, direction, flip))
1022 surface.foreground = white;
1023 surface.HLine(drag.x + x * squareWidth-1, drag.x + (x+1) * squareWidth+1, drag.y + y * squareWidth - 1);
1024 surface.foreground = lime;
1025 surface.HLine(drag.x + x * squareWidth-2, drag.x + (x+1) * squareWidth+2, drag.y + y * squareWidth - 2);
1028 if(x == 4 || !PieceBlock(selectedPiece, x+1, y, direction, flip))
1030 surface.foreground = white;
1031 surface.VLine(drag.y + y * squareWidth-1, drag.y + (y+1) * squareWidth+1, drag.x + (x+1) * squareWidth + 1);
1032 surface.foreground = lime;
1033 surface.VLine(drag.y + y * squareWidth-2, drag.y + (y+1) * squareWidth+2, drag.x + (x+1) * squareWidth + 2);
1036 if(y == 4 || !PieceBlock(selectedPiece, x, y+1, direction, flip))
1038 surface.foreground = white;
1039 surface.HLine(drag.x + x * squareWidth-1, drag.x + (x+1) * squareWidth+1, drag.y + (y+1) * squareWidth + 1);
1040 surface.foreground = lime;
1041 surface.HLine(drag.x + x * squareWidth-2, drag.x + (x+1) * squareWidth+2, drag.y + (y+1) * squareWidth + 2);
1051 this, size = { boardSize*squareWidth }, anchor = { left = boardStartX, top = boardStartY + boardSize*squareWidth + 20, bottom = 5 };
1052 font = { "Arial", 11, bold = true };
1053 editTextColor = white;
1054 logTextColor = white;
1056 log.hasVertScroll = bool::true;
1057 log.inactive = bool::true;
1060 bool ProcessCommand(char * command)
1062 cornerBlocks.server.SendMessage(command);
1069 this, caption = "No Move Available! Pass...",
1070 //anchor = { right = 5, bottom = 5 };
1071 anchor = { left = squareWidth * boardSize + 40, bottom = 5 };
1075 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1077 btnPass.visible = false;
1078 cornerBlocks.passed[cornerBlocks.gameState.colorTurn] = true;
1086 class CornerBlocksScores : Window
1088 master = cornerBlocks;
1090 borderStyle = fixed;
1092 caption = "CornerBlocks Final Scores";
1093 clientSize = { 580, 210 };
1094 font = { "Arial", 12, bold = true };
1095 icon = { ":ollie.png" };
1096 void OnRedraw(Surface surface)
1103 CornerBlocksGameState * state = &cornerBlocks.gameState;
1104 surface.foreground = white;
1105 s = "Score"; len = strlen(s);
1106 surface.WriteText(10, 40, s, len);
1108 s = "Bonus"; len = strlen(s);
1109 surface.WriteText(10, 60, s, len);
1111 s = "Total"; len = strlen(s);
1112 surface.WriteText(10, 100, s, len);
1114 if(state->numPlayers < 3)
1116 s = "Grand Total"; len = strlen(s);
1117 surface.WriteText(10, 160, s, len);
1120 for(p = blue; p <= green; p++)
1122 int x = 80 + p * 120;
1123 surface.foreground = colors[1][p];
1124 /* // GCC internal compiler error with -O2, MinGW GCC 4.4.0
1125 s = (state->numPlayers == 3 && p == green) ? "* Green *" : cornerBlocks.playerNames[p];
1127 surface.WriteText(x, 20, s, len);
1129 if(state->numPlayers == 3 && p == green)
1133 surface.WriteText(x, 20, s, len);
1135 else if(cornerBlocks.playerNames[p])
1137 s = cornerBlocks.playerNames[p];
1139 surface.WriteText(x, 20, s, len);
1142 s = temp; sprintf(temp, "%d", state->scores[p]);
1144 surface.WriteText(x + 30, 40, s, len);
1148 s = temp; sprintf(temp, "%d", state->bonus[p]);
1150 surface.WriteText(x + 30, 60, s, len);
1153 if(state->numPlayers > 2)
1154 grandTotals[p] = state->scores[p] + state->bonus[p];
1155 s = temp; sprintf(temp, "%d", state->scores[p] + state->bonus[p]);
1157 surface.WriteText(x + 30, 100, s, len);
1159 if((state->numPlayers == 2 && p <= yellow) ||
1160 (state->numPlayers == 1 && p == blue))
1162 if(state->numPlayers == 2)
1163 grandTotals[p] = state->scores[p] + state->bonus[p] +
1164 state->scores[p+2] + state->bonus[p+2];
1166 grandTotals[p] = state->scores[0] + state->bonus[0] +
1167 state->scores[1] + state->bonus[1] +
1168 state->scores[2] + state->bonus[2] +
1169 state->scores[3] + state->bonus[3];
1171 if(cornerBlocks.playerNames[p])
1173 s = cornerBlocks.playerNames[p];
1175 surface.WriteText(x, 140, s, len);
1178 s = temp; sprintf(temp, "%d", grandTotals[p]);
1180 surface.WriteText(x + 30, 160, s, len);
1183 if(state->numPlayers > 1)
1186 int c, greatest = -MAXINT;
1187 int numTies = 0, ties[3], winner;
1190 for(c = 0; c < state->numPlayers; c++)
1192 if(grandTotals[c] > greatest)
1194 greatest = grandTotals[c];
1198 else if(grandTotals[c] == greatest)
1205 ties[numTies++] = c;
1210 for(c = 0; c < numTies; c++)
1212 strcat(string, cornerBlocks.playerNames[c]);
1214 strcat(string, ", ");
1215 else if(c < numTies-1)
1216 strcat(string, " and ");
1218 surface.foreground = white;
1219 strcat(string, " tied!");
1223 surface.foreground = colors[1][(PlayerColor)winner];
1224 sprintf(string, "%s won!", cornerBlocks.playerNames[winner]);
1227 len = strlen(string);
1228 surface.WriteText(100, 180, string, strlen(string));
1233 CornerBlocksScores scoresPanel { visible = false };
1235 CornerBlocks cornerBlocks { };
1237 class CornerBlocksApp : GuiApplication
1239 //fullScreen = true;
1242 cornerBlocks.Create();
1247 bool Cycle(bool idle)
1249 // This is here because it hangs in MovePlayed() (Why?)
1250 scoresPanel.visible = cornerBlocks.gameStarted && cornerBlocks.gameState.over;
1252 /*if(cornerBlocks.gameState.over)
1253 panel.btnStart.NotifyClicked(panel, panel.btnStart, 0, 0, 0);*/
1260 cornerBlocksService.Stop();
1264 import remote "CornerBlocksServer"
1266 define app = ((CornerBlocksApp)__thisModule.application);
1268 define CORNERBLOCKS_PORT = 1495;
1269 static bool hosting;
1270 define MaxPlayers = 4;
1272 class CommunicationPanel : Window
1274 caption = "CornerBlocks Communication Panel";
1275 background = lightSlateGray;
1276 borderStyle = fixed;
1279 clientSize = { 430, 300 };
1281 anchor = { right = 0, bottom = 0 };
1283 icon = { ":ollie.png" };
1285 // Other player info
1286 char playerNames[MaxPlayers][256];
1288 DataField fldName { header = "Name", width = 100 };
1289 DataField fldAddr { header = "Address" };
1291 bool OnClose(bool parentClosing)
1293 if(!cornerBlocks || cornerBlocks.destroyed || cornerBlocks.Destroy(0))
1302 cornerBlocksService.Stop();
1306 CommunicationPanel()
1308 listPlayers.AddField(fldName);
1309 listPlayers.AddField(fldAddr);
1315 listPlayers.Clear();
1316 fldAddr.header = hosting ? "Address" : "";
1317 for(c = 0; c<MaxPlayers; c++)
1321 if(serverPlayers[c])
1323 DataRow row = listPlayers.AddRow();
1324 DCOMServerObject object = (DCOMServerObject)serverPlayers[c].connection._vTbl[-1];
1326 row.tag = serverPlayers[c].id;
1327 row.SetData(fldName, serverPlayers[c].name);
1328 row.SetData(fldAddr, object.serverSocket.inetAddress);
1331 else if(playerNames[c][0])
1333 DataRow row = listPlayers.AddRow();
1334 row.SetData(fldName, playerNames[c]);
1339 void UpdateControlsStates()
1345 for(c = 0; c<MaxPlayers; c++)
1346 if(serverPlayers[c])
1349 lblServerAddress.disabled = serverAddress.disabled = cornerBlocks.server ? true : false;
1350 lblPlayerName.disabled = playerName.disabled = cornerBlocks.server ? true : false;
1351 lblServerAddress.Update(null);
1352 lblPlayerName.Update(null);
1353 btnConnect.visible = cornerBlocks.server ? false : true;
1354 btnDisconnect.visible = cornerBlocks.server ? true : false;
1355 cornerBlocks.chat.visible = cornerBlocks.server ? true : false;
1357 btnHost.visible = !hosting && !cornerBlocks.server;
1358 btnStopHosting.visible = hosting;
1359 btnStart.visible = hosting && (!serverGameStarted || serverGameState.over) && numPlayers > 0;
1360 btnStopGame.visible = hosting && (serverGameStarted && !serverGameState.over);
1361 listPlayers.visible = (hosting && (serverGameStarted || numPlayers > 0)) || (!hosting && cornerBlocks.server && cornerBlocks.gameStarted);
1362 btnKick.visible = hosting && !serverGameStarted && numPlayers > 0;
1363 btnKick.disabled = listPlayers.currentRow ? false : true;
1365 EditBox serverAddress
1367 this, caption = "Server Address:", altA, font = { "Tahoma", 10, bold = true }, size = { 220, 24 }, position = { 16, 64 }, contents = "localhost"
1369 Label lblServerAddress { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 40 }, labeledWindow = serverAddress };
1372 this, caption = "Connect", altC, isDefault = true, font = { "Arial", 16, bold = true }, size = { 126, 32 }, position = { 256, 64 };
1374 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1376 if(!cornerBlocks.server)
1378 cornerBlocks.server = ServerConnection
1380 void OnDisconnect(int code)
1385 delete cornerBlocks.server;
1386 cornerBlocks.gameStarted = false;
1387 cornerBlocks.turnLightTimer.Stop();
1388 cornerBlocks.lightValue = 1;
1389 cornerBlocks.lightDir = -.1f;
1390 cornerBlocks.Update(null);
1391 panel.UpdateControlsStates();
1392 panel.ListPlayers();
1394 DCOMClientObject::OnDisconnect(code);
1398 void GameStarted(GameInfo gameInfo)
1403 cornerBlocks.gameState.numPlayers = gameInfo.numPlayers;
1404 cornerBlocks.firstColor = gameInfo.firstColor;
1405 cornerBlocks.colorPlayed = cornerBlocks.firstColor;
1407 for(c = 0; c<MaxPlayers; c++)
1409 if(gameInfo.players[c][0])
1410 strcpy(panel.playerNames[np++], gameInfo.players[c]);
1413 cornerBlocks.btnPass.visible = false;
1414 cornerBlocks.gameState.NewGame();
1415 cornerBlocks.passed[0] = false;
1416 cornerBlocks.passed[1] = false;
1417 cornerBlocks.passed[2] = false;
1418 cornerBlocks.passed[3] = false;
1419 cornerBlocks.gameStarted = true;
1420 cornerBlocks.lightValue = 1;
1421 cornerBlocks.lightDir = -.1f;
1422 cornerBlocks.turnLightTimer.Start();
1423 cornerBlocks.UpdatePlayerNames();
1425 cornerBlocks.Update(null);
1427 panel.UpdateControlsStates();
1428 panel.ListPlayers();
1435 panel.ListPlayers();
1436 cornerBlocks.gameStarted = false;
1437 cornerBlocks.btnPass.visible = false;
1438 cornerBlocks.Update(null);
1441 void MovePlayed(PlayerColor color, int pieceType, int direction, bool flip, int boardX, int boardY)
1443 cornerBlocks.gameState.PlayMove(pieceType, direction, flip, boardX, boardY);
1444 if(color == cornerBlocks.colorPlayed)
1445 cornerBlocks.NextColorPlayed();
1447 cornerBlocks.gotMove = true;
1449 if(cornerBlocks.colorPlayed == cornerBlocks.gameState.colorTurn && !cornerBlocks.gameState.over)
1451 if(!cornerBlocks.gameState.validMove)
1453 if(!cornerBlocks.passed[cornerBlocks.gameState.colorTurn])
1455 cornerBlocks.btnPass.visible = true;
1456 if(!cornerBlocks.active)
1457 cornerBlocks.Flash();
1460 cornerBlocks.server.Pass();
1462 else if(!cornerBlocks.active)
1463 cornerBlocks.Flash();
1466 // This hangs here, why?
1467 /*if(cornerBlocks.gameState.over)
1468 scoresPanel.visible = true;*/
1471 cornerBlocks.UpdatePlayerNames();
1472 cornerBlocks.Update(null);
1476 void Passed(PlayerColor color)
1478 cornerBlocks.gameState.Pass();
1479 if(color == cornerBlocks.colorPlayed)
1480 cornerBlocks.NextColorPlayed();
1481 else if(!cornerBlocks.active)
1482 cornerBlocks.Flash();
1484 if(cornerBlocks.colorPlayed == cornerBlocks.gameState.colorTurn && !cornerBlocks.gameState.over)
1486 if(!cornerBlocks.gameState.validMove)
1488 if(!cornerBlocks.passed[cornerBlocks.gameState.colorTurn])
1490 cornerBlocks.btnPass.visible = true;
1491 if(!cornerBlocks.active)
1492 cornerBlocks.Flash();
1495 cornerBlocks.server.Pass();
1497 else if(!cornerBlocks.active)
1498 cornerBlocks.Flash();
1503 cornerBlocks.UpdatePlayerNames();
1504 cornerBlocks.Update(null);
1508 void NotifyMessage(String name, String msg)
1510 EditBox log = cornerBlocks.chat.log;
1511 char * format = (log.numLines > 1 || log.line.count) ?
1512 "\n%s: %s" : "%s: %s";
1513 int len = strlen(msg);
1514 // Avoid buffer overflow...
1515 if(len >= MAX_F_STRING-100)
1516 msg[MAX_F_STRING-100] = 0;
1517 cornerBlocks.chat.Log(format, name, msg);
1520 incref cornerBlocks.server;
1521 if(cornerBlocks.server.Connect(serverAddress.contents, CORNERBLOCKS_PORT))
1523 int playerID = cornerBlocks.server.Join();
1524 if(cornerBlocks.server && playerID != -1)
1525 cornerBlocks.server.SetName(playerName.contents);
1527 cornerBlocks.server.Disconnect(0);
1528 UpdateControlsStates();
1531 delete cornerBlocks.server;
1536 Button btnDisconnect
1538 this, caption = "Disconnect", altD, font = { "Arial", 16, bold = true }, size = { 126, 32 }, position = { 256, 64 }, visible = false;
1540 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1542 if(!cornerBlocks.gameStarted || cornerBlocks.gameState.over ||
1543 MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1544 contents = "Game in progress! Disconnect?"
1547 if(cornerBlocks.server)
1548 cornerBlocks.server.Disconnect(0);
1555 this, caption = "Host", altH, font = { "Arial", 16, bold = true }, size = { 90, 32 }, position = { 16, 112 };
1557 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1559 if(!cornerBlocks.gameStarted)
1561 if(cornerBlocksService.Start())
1565 UpdateControlsStates();
1571 Button btnStopHosting
1573 this, caption = "Stop Hosting", altP, font = { "Arial", 16, bold = true }, position = { 16, 112 }, visible = false;
1575 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1579 for(c = 0; c<MaxPlayers; c++)
1580 if(serverPlayers[c])
1583 MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1584 contents = "Players connected! Stop hosting?"
1588 cornerBlocksService.Stop();
1592 UpdateControlsStates();
1599 this, caption = "Start Game", altS, font = { "Arial", 16, bold = true }, size = { 124, 32 }, position = { 256, 112 }, visible = false;
1601 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1606 UpdateControlsStates();
1613 this, caption = "Stop Game", altG, font = { "Arial", 16, bold = true }, position = { 256, 112 }, visible = false;
1615 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1617 if(!serverGameStarted || serverGameState.over ||
1618 MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1619 contents = "Stop game in progress?"
1623 UpdateControlsStates();
1630 this, caption = "Players Connected", altD, size = { 236, 84 }, position = { 16, 176 }, visible = false, hasHeader = true;
1632 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1634 UpdateControlsStates();
1638 Label lblListPlayers { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 152 }, visible = false, labeledWindow = listPlayers };
1641 this, caption = "Kick", altK, font = { "Arial", 16, bold = true }, size = { 80, 32 }, position = { 264, 224 }, visible = false;
1643 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1645 DataRow row = listPlayers.currentRow;
1648 int id = (int)row.tag;
1650 sprintf(msg, "Kick %s?", serverPlayers[id].name);
1651 if(MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1661 this, caption = "Player Name:", altN, font = { "Arial", 12 }, size = { 132, 24 }, position = { 104, 8 }, contents = "Player"
1663 Label lblPlayerName { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 16 }, labeledWindow = playerName };
1666 CommunicationPanel panel { };
1668 DCOMService cornerBlocksService { port = CORNERBLOCKS_PORT };