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);
541 // To work around Flash() lockups on Windows...
545 this, delay = 0.2, true;
562 void NextColorPlayed()
564 if(gameState.numPlayers == 1)
566 if(++colorPlayed > green) colorPlayed = 0;
568 else if(gameState.numPlayers == 2)
570 if((colorPlayed+=2) > green) colorPlayed = firstColor;
572 else if(gameState.numPlayers == 3)
574 colorPlayed = (colorPlayed == firstColor && gameState.rotatingColor == firstColor) ? green : firstColor;
578 void UpdatePlayerNames()
581 if(gameState.numPlayers == 1)
583 for(c = 0; c < 4; c++)
584 playerNames[c] = panel.playerNames[0];
586 else if(gameState.numPlayers == 2)
588 for(c = 0; c < 2; c++)
590 playerNames[c] = panel.playerNames[c];
591 playerNames[c+2] = panel.playerNames[c];
594 else if(gameState.numPlayers == 3)
596 for(c = 0; c < 3; c++)
597 playerNames[c] = panel.playerNames[c];
598 playerNames[3] = panel.playerNames[gameState.rotatingColor];
600 else if(gameState.numPlayers == 4)
602 for(c = 0; c < 4; c++)
603 playerNames[c] = panel.playerNames[c];
607 void DrawSquare(Surface surface, int x, int y, CornerBlocksColor color, int shade)
609 surface.background = colors[shade][color];
610 surface.Area(x+1, y+1, x + squareWidth-1, y + squareWidth-1);
611 surface.foreground = lightGray;
612 surface.VLine(y+blockOffset1, y + blockOffset2, x + blockOffset1);
613 surface.HLine(x+blockOffset1, x + blockOffset3, y + blockOffset1);
614 surface.foreground = white;
615 surface.Rectangle(x + blockOffset0,y+blockOffset0, x + squareWidth-blockOffset0, y + squareWidth - blockOffset0);
618 bool OnClose(bool parentClosing)
620 if((gameStarted && !gameState.over) || hosting)
622 if(MessageBox { type = okCancel,
623 caption = "Ecere CornerBlocks", contents = "Quit Ecere CornerBlocks?" }.Modal() == cancel)
632 server.Disconnect(0);
635 scoresPanel.Destroy(0);
643 bool OnMouseMove(int mx, int my, Modifiers mods)
647 Piece * piece = &pieces[selectedPiece];
648 int w = (direction & 1) ? piece->h : piece->w;
649 int h = (direction & 1) ? piece->w : piece->h;
650 drag = { offset.x + mx, offset.y + my };
652 if(mx - squareDragged.x * squareWidth >= boardStartX - 10 && mx - squareDragged.x * squareWidth < boardStartX + ((boardSize-w)+1) * squareWidth + 10 &&
653 my - squareDragged.y * squareWidth >= boardStartY - 10 && my - squareDragged.y * squareWidth < boardStartY + ((boardSize-h)+1) * squareWidth + 10)
656 x = Max(0,mx - squareDragged.x * squareWidth - boardStartX) / squareWidth;
657 y = Max(0,my - squareDragged.y * squareWidth - boardStartY) / squareWidth;
658 x = Min(x, boardSize-w);
659 y = Min(y, boardSize-h);
660 drag.x = boardStartX + x * squareWidth;
661 drag.y = boardStartY + y * squareWidth;
672 bool OnLeftButtonUp(int mx, int my, Modifiers mods)
678 if(gameStarted && colorPlayed == gameState.colorTurn)
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;
737 int x = squareDragged.x, y = squareDragged.y;
739 bool isDown = key == wheelDown || key == right || key == down;
743 if(++direction == 4) direction = 0;
747 if(--direction == -1) direction = 3;
749 w = (direction & 1) ? piece->h : piece->w;
750 h = (direction & 1) ? piece->w : piece->h;
752 offset.x += squareDragged.x * squareWidth;
753 offset.y += squareDragged.y * squareWidth;
755 squareDragged = { w-1-y, x };
757 squareDragged = { y, h-1-x };
759 offset.x -= squareDragged.x * squareWidth;
760 offset.y -= squareDragged.y * squareWidth;
762 OnMouseMove(mx,my,0);
769 bool OnLeftButtonDown(int mx, int my, Modifiers mods)
771 if( mx > squareWidth * boardSize + 40)
774 bool selected = false;
779 // Draw Player Pieces
780 bx = squareWidth * boardSize + 40;
782 for(c = 0; c < numPieces; c++)
784 if(gameState.playerPieces[colorPlayed][c])
786 int w = pieces[c].w, h = pieces[c].h;
788 for(y = 0; y < 5; y++)
791 for(x = 0; x < 5; x++)
793 if(PieceBlock(c, x, y, 0, false))
795 int dx = bx + x * squareWidth;
796 int dy = by + y * squareWidth;
797 if(mx >= dx && mx < dx + squareWidth &&
798 my >= dy && my < dy + squareWidth)
802 offset = { bx - mx, by - my };
803 squareDragged = { x, y };
812 bx += w * squareWidth + squareWidth;
814 if(bx + 5 * squareWidth > clientSize.w)
816 bx = squareWidth * boardSize + 40;
817 by += (rh+1) * squareWidth;
827 selectedPiece = pieceNum;
828 this.offset = offset;
830 OnMouseMove(mx, my, mods);
837 float lightValue, lightDir;
846 lightValue += lightDir;
847 if(lightValue < 0) { lightValue = 0; lightDir = .1f; }
848 if(lightValue > 1) { lightValue = 1; lightDir =-.1f; }
854 void OnRedraw(Surface surface)
857 int bx = boardStartX;
858 int by = boardStartY;
862 Color turnLight = white;
863 if(gameStarted && !gameState.over)
865 ColorRGB empty = colors[1][gameState.colorTurn] /*gray*/, full = white;
868 empty.r + lightValue * (full.r - empty.r),
869 empty.g + lightValue * (full.g - empty.g),
870 empty.b + lightValue * (full.b - empty.b)
874 surface.foreground = aqua;
875 for(c = 0; c <= boardSize; c++)
877 surface.HLine(bx,bx+squareWidth*boardSize, by + c * squareWidth);
878 surface.VLine(by,by+squareWidth*boardSize, bx + c * squareWidth);
881 surface.background = colors[cornerBlocks.gameStarted][blue];
884 surface.Area(x - 10, y - 10, x + 10, y-1);
885 surface.Area(x - 10, y - 10, x - 1, y+10);
887 s = playerNames[PlayerColor::blue];
891 surface.foreground = (gameState.colorTurn == blue) ? turnLight : white;
892 surface.WriteText(x + 15, y - 20, s, len);
895 surface.background = colors[cornerBlocks.gameStarted][yellow];
896 x = bx + boardSize*squareWidth;
898 surface.Area(x - 10, y - 10, x + 10, y-1);
899 surface.Area(x + 1, y - 10, x + 10, y+10);
901 s = playerNames[PlayerColor::yellow];
905 surface.TextExtent(s, len, &tw, null);
906 surface.foreground = (gameState.colorTurn == yellow) ? turnLight : white;
907 surface.WriteText(x - 15 - tw, y - 20, s, len);
910 surface.background = colors[cornerBlocks.gameStarted][red];
911 x = bx + boardSize*squareWidth;
912 y = by + boardSize*squareWidth;
913 surface.Area(x - 10, y + 1, x + 10, y+10);
914 surface.Area(x + 1, y - 10, x + 10, y+10);
915 s = playerNames[PlayerColor::red];
919 surface.TextExtent(s, len, &tw, null);
920 surface.foreground = (gameState.colorTurn == red) ? turnLight : white;
921 surface.WriteText(x - 15 - tw, y, s, len);
924 surface.background = colors[cornerBlocks.gameStarted][green];
926 y = by + boardSize*squareWidth;
927 surface.Area(x - 10, y + 1, x + 10, y+10);
928 surface.Area(x - 10, y - 10, x - 1, y+10);
929 s = playerNames[PlayerColor::green];
933 surface.foreground = (gameState.colorTurn == green) ? turnLight : white;
934 surface.WriteText(x + 15, y, s, len);
939 surface.font = yourTurnFont.font;
940 surface.foreground = crimson;
941 surface.CenterTextf(x + boardSize*squareWidth/2, y + 3, "Game Over");
943 else if(gameState.numPlayers > 1 && gameStarted && colorPlayed == gameState.colorTurn)
945 surface.font = yourTurnFont.font;
946 surface.foreground = tomato;
947 surface.CenterTextf(x + boardSize*squareWidth/2, y + 3, "Your turn");
950 for(y = 0; y < boardSize; y++)
952 for(x = 0; x < boardSize; x++)
954 CornerBlocksColor color = gameState.board[y * boardSize + x];
957 DrawSquare(surface, bx + x * squareWidth, by + y * squareWidth, color, cornerBlocks.gameStarted);
964 // Draw Player Pieces
965 bx = squareWidth * boardSize + 40;
967 for(c = 0; c < numPieces; c++)
969 if(gameState.playerPieces[colorPlayed][c])
971 int w = pieces[c].w, h = pieces[c].h;
972 for(y = 0; y < 5; y++)
974 for(x = 0; x < 5; x++)
976 if(PieceBlock(c, x, y, 0, false))
978 if(!dragging || selectedPiece != c)
980 bx + x * squareWidth,
981 by + y * squareWidth,
983 gameStarted && (gameState.colorTurn == colorPlayed && gameState.validPieces[c]));
988 bx += w * squareWidth + squareWidth;
989 if(bx + 5 * squareWidth > clientSize.w)
991 bx = squareWidth * boardSize + 40;
992 by += rh * squareWidth + squareWidth;
997 // Draw Dragged piece
1000 for(y = 0; y < 5; y++)
1001 for(x = 0; x < 5; x++)
1003 if(PieceBlock(selectedPiece, x, y, direction, flip))
1006 drag.x + x * squareWidth,
1007 drag.y + y * squareWidth,
1009 gameStarted && gameState.colorTurn == colorPlayed && gameState.validPieces[selectedPiece]);
1011 if(x == 0 || !PieceBlock(selectedPiece, x-1, y, direction, flip))
1013 surface.foreground = white;
1014 surface.VLine(drag.y + y * squareWidth-1, drag.y + (y+1) * squareWidth+1, drag.x + x * squareWidth - 1);
1015 surface.foreground = lime;
1016 surface.VLine(drag.y + y * squareWidth-2, drag.y + (y+1) * squareWidth+2, drag.x + x * squareWidth - 2);
1019 if(y == 0 || !PieceBlock(selectedPiece, x, y-1, direction, flip))
1021 surface.foreground = white;
1022 surface.HLine(drag.x + x * squareWidth-1, drag.x + (x+1) * squareWidth+1, drag.y + y * squareWidth - 1);
1023 surface.foreground = lime;
1024 surface.HLine(drag.x + x * squareWidth-2, drag.x + (x+1) * squareWidth+2, drag.y + y * squareWidth - 2);
1027 if(x == 4 || !PieceBlock(selectedPiece, x+1, y, direction, flip))
1029 surface.foreground = white;
1030 surface.VLine(drag.y + y * squareWidth-1, drag.y + (y+1) * squareWidth+1, drag.x + (x+1) * squareWidth + 1);
1031 surface.foreground = lime;
1032 surface.VLine(drag.y + y * squareWidth-2, drag.y + (y+1) * squareWidth+2, drag.x + (x+1) * squareWidth + 2);
1035 if(y == 4 || !PieceBlock(selectedPiece, x, y+1, direction, flip))
1037 surface.foreground = white;
1038 surface.HLine(drag.x + x * squareWidth-1, drag.x + (x+1) * squareWidth+1, drag.y + (y+1) * squareWidth + 1);
1039 surface.foreground = lime;
1040 surface.HLine(drag.x + x * squareWidth-2, drag.x + (x+1) * squareWidth+2, drag.y + (y+1) * squareWidth + 2);
1050 this, size = { boardSize*squareWidth }, anchor = { left = boardStartX, top = boardStartY + boardSize*squareWidth + 20, bottom = 5 };
1051 font = { "Arial", 11, bold = true };
1052 editTextColor = white;
1053 logTextColor = white;
1055 log.hasVertScroll = bool::true;
1056 log.inactive = bool::true;
1059 bool ProcessCommand(const char * command)
1061 cornerBlocks.server.SendMessage(command);
1068 this, caption = "No Move Available! Pass...",
1069 //anchor = { right = 5, bottom = 5 };
1070 anchor = { left = squareWidth * boardSize + 40, bottom = 5 };
1074 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1076 btnPass.visible = false;
1077 cornerBlocks.passed[cornerBlocks.gameState.colorTurn] = true;
1085 class CornerBlocksScores : Window
1087 master = cornerBlocks;
1089 borderStyle = fixed;
1091 caption = "CornerBlocks Final Scores";
1092 clientSize = { 580, 210 };
1093 font = { "Arial", 12, bold = true };
1094 icon = { ":ollie.png" };
1095 void OnRedraw(Surface surface)
1102 CornerBlocksGameState * state = &cornerBlocks.gameState;
1103 surface.foreground = white;
1104 s = "Score"; len = strlen(s);
1105 surface.WriteText(10, 40, s, len);
1107 s = "Bonus"; len = strlen(s);
1108 surface.WriteText(10, 60, s, len);
1110 s = "Total"; len = strlen(s);
1111 surface.WriteText(10, 100, s, len);
1113 if(state->numPlayers < 3)
1115 s = "Grand Total"; len = strlen(s);
1116 surface.WriteText(10, 160, s, len);
1119 for(p = blue; p <= green; p++)
1121 int x = 80 + p * 120;
1122 surface.foreground = colors[1][p];
1123 /* // GCC internal compiler error with -O2, MinGW GCC 4.4.0
1124 s = (state->numPlayers == 3 && p == green) ? "* Green *" : cornerBlocks.playerNames[p];
1126 surface.WriteText(x, 20, s, len);
1128 if(state->numPlayers == 3 && p == green)
1132 surface.WriteText(x, 20, s, len);
1134 else if(cornerBlocks.playerNames[p])
1136 s = cornerBlocks.playerNames[p];
1138 surface.WriteText(x, 20, s, len);
1141 s = temp; sprintf(temp, "%d", state->scores[p]);
1143 surface.WriteText(x + 30, 40, s, len);
1147 s = temp; sprintf(temp, "%d", state->bonus[p]);
1149 surface.WriteText(x + 30, 60, s, len);
1152 if(state->numPlayers > 2)
1153 grandTotals[p] = state->scores[p] + state->bonus[p];
1154 s = temp; sprintf(temp, "%d", state->scores[p] + state->bonus[p]);
1156 surface.WriteText(x + 30, 100, s, len);
1158 if((state->numPlayers == 2 && p <= yellow) ||
1159 (state->numPlayers == 1 && p == blue))
1161 if(state->numPlayers == 2)
1162 grandTotals[p] = state->scores[p] + state->bonus[p] +
1163 state->scores[p+2] + state->bonus[p+2];
1165 grandTotals[p] = state->scores[0] + state->bonus[0] +
1166 state->scores[1] + state->bonus[1] +
1167 state->scores[2] + state->bonus[2] +
1168 state->scores[3] + state->bonus[3];
1170 if(cornerBlocks.playerNames[p])
1172 s = cornerBlocks.playerNames[p];
1174 surface.WriteText(x, 140, s, len);
1177 s = temp; sprintf(temp, "%d", grandTotals[p]);
1179 surface.WriteText(x + 30, 160, s, len);
1182 if(state->numPlayers > 1)
1185 int c, greatest = -MAXINT;
1186 int numTies = 0, ties[3], winner;
1189 for(c = 0; c < state->numPlayers; c++)
1191 if(grandTotals[c] > greatest)
1193 greatest = grandTotals[c];
1197 else if(grandTotals[c] == greatest)
1204 ties[numTies++] = c;
1209 for(c = 0; c < numTies; c++)
1211 strcat(string, cornerBlocks.playerNames[ties[c]]);
1213 strcat(string, ", ");
1214 else if(c < numTies-1)
1215 strcat(string, " and ");
1217 surface.foreground = white;
1218 strcat(string, " tied!");
1222 surface.foreground = colors[1][(PlayerColor)winner];
1223 sprintf(string, "%s won!", cornerBlocks.playerNames[winner]);
1226 len = strlen(string);
1227 surface.WriteText(100, 180, string, strlen(string));
1232 CornerBlocksScores scoresPanel { visible = false };
1234 CornerBlocks cornerBlocks { };
1236 class CornerBlocksApp : GuiApplication
1238 //fullScreen = true;
1241 cornerBlocks.Create();
1246 bool Cycle(bool idle)
1248 // This is here because it hangs in MovePlayed() (Why?)
1249 scoresPanel.visible = cornerBlocks.gameStarted && cornerBlocks.gameState.over;
1251 /*if(cornerBlocks.gameState.over)
1252 panel.btnStart.NotifyClicked(panel, panel.btnStart, 0, 0, 0);*/
1259 cornerBlocksService.Stop();
1263 import remote "CornerBlocksServer"
1265 define app = ((CornerBlocksApp)__thisModule.application);
1267 define CORNERBLOCKS_PORT = 1495;
1268 static bool hosting;
1269 define MaxPlayers = 4;
1271 class CommunicationPanel : Window
1273 caption = "CornerBlocks Communication Panel";
1274 background = lightSlateGray;
1275 borderStyle = fixed;
1278 clientSize = { 430, 300 };
1280 anchor = { right = 0, bottom = 0 };
1282 icon = { ":ollie.png" };
1284 // Other player info
1285 char playerNames[MaxPlayers][256];
1287 DataField fldName { header = "Name", width = 100 };
1288 DataField fldAddr { header = "Address" };
1290 bool OnClose(bool parentClosing)
1292 if(!cornerBlocks || cornerBlocks.destroyed || cornerBlocks.Destroy(0))
1301 cornerBlocksService.Stop();
1305 CommunicationPanel()
1307 listPlayers.AddField(fldName);
1308 listPlayers.AddField(fldAddr);
1314 listPlayers.Clear();
1315 fldAddr.header = hosting ? "Address" : "";
1316 for(c = 0; c<MaxPlayers; c++)
1320 if(serverPlayers[c])
1322 DataRow row = listPlayers.AddRow();
1323 DCOMServerObject object = (DCOMServerObject)serverPlayers[c].connection._vTbl[-1];
1325 row.tag = serverPlayers[c].id;
1326 row.SetData(fldName, serverPlayers[c].name);
1327 row.SetData(fldAddr, object.serverSocket.inetAddress);
1330 else if(playerNames[c][0])
1332 DataRow row = listPlayers.AddRow();
1333 row.SetData(fldName, playerNames[c]);
1338 void UpdateControlsStates()
1344 for(c = 0; c<MaxPlayers; c++)
1345 if(serverPlayers[c])
1348 lblServerAddress.disabled = serverAddress.disabled = cornerBlocks.server ? true : false;
1349 lblPlayerName.disabled = playerName.disabled = cornerBlocks.server ? true : false;
1350 lblServerAddress.Update(null);
1351 lblPlayerName.Update(null);
1352 btnConnect.visible = cornerBlocks.server ? false : true;
1353 btnDisconnect.visible = cornerBlocks.server ? true : false;
1354 cornerBlocks.chat.visible = cornerBlocks.server ? true : false;
1356 btnHost.visible = !hosting && !cornerBlocks.server;
1357 btnStopHosting.visible = hosting;
1358 btnStart.visible = hosting && (!serverGameStarted || serverGameState.over) && numPlayers > 0;
1359 btnStopGame.visible = hosting && (serverGameStarted && !serverGameState.over);
1360 listPlayers.visible = (hosting && (serverGameStarted || numPlayers > 0)) || (!hosting && cornerBlocks.server && cornerBlocks.gameStarted);
1361 btnKick.visible = hosting && !serverGameStarted && numPlayers > 0;
1362 btnKick.disabled = listPlayers.currentRow ? false : true;
1364 EditBox serverAddress
1366 this, caption = "Server Address:", altA, font = { "Tahoma", 10, bold = true }, size = { 220, 24 }, position = { 16, 64 }, contents = "localhost"
1368 Label lblServerAddress { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 40 }, labeledWindow = serverAddress };
1371 this, caption = "Connect", altC, isDefault = true, font = { "Arial", 16, bold = true }, size = { 126, 32 }, position = { 256, 64 };
1373 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1375 if(!cornerBlocks.server)
1377 cornerBlocks.server = ServerConnection
1379 void OnDisconnect(int code)
1384 delete cornerBlocks.server;
1385 cornerBlocks.gameStarted = false;
1386 cornerBlocks.turnLightTimer.Stop();
1387 cornerBlocks.lightValue = 1;
1388 cornerBlocks.lightDir = -.1f;
1389 cornerBlocks.Update(null);
1390 panel.UpdateControlsStates();
1391 panel.ListPlayers();
1393 DCOMClientObject::OnDisconnect(code);
1397 void GameStarted(GameInfo gameInfo)
1401 cornerBlocks.gameState.numPlayers = gameInfo.numPlayers;
1402 cornerBlocks.firstColor = gameInfo.firstColor;
1403 cornerBlocks.colorPlayed = cornerBlocks.firstColor;
1405 for(c = 0; c<MaxPlayers; c++)
1407 if(gameInfo.players[c][0])
1408 strcpy(panel.playerNames[np++], gameInfo.players[c]);
1411 cornerBlocks.btnPass.visible = false;
1412 cornerBlocks.gameState.NewGame();
1413 cornerBlocks.passed[0] = false;
1414 cornerBlocks.passed[1] = false;
1415 cornerBlocks.passed[2] = false;
1416 cornerBlocks.passed[3] = false;
1417 cornerBlocks.gameStarted = true;
1418 cornerBlocks.lightValue = 1;
1419 cornerBlocks.lightDir = -.1f;
1420 cornerBlocks.turnLightTimer.Start();
1421 cornerBlocks.UpdatePlayerNames();
1423 cornerBlocks.Update(null);
1425 panel.UpdateControlsStates();
1426 panel.ListPlayers();
1431 panel.ListPlayers();
1432 cornerBlocks.gameStarted = false;
1433 cornerBlocks.btnPass.visible = false;
1434 cornerBlocks.Update(null);
1437 void MovePlayed(PlayerColor color, int pieceType, int direction, bool flip, int boardX, int boardY)
1439 cornerBlocks.gameState.PlayMove(pieceType, direction, flip, boardX, boardY);
1440 if(color == cornerBlocks.colorPlayed)
1441 cornerBlocks.NextColorPlayed();
1443 cornerBlocks.gotMove = true;
1445 if(cornerBlocks.colorPlayed == cornerBlocks.gameState.colorTurn && !cornerBlocks.gameState.over)
1447 if(!cornerBlocks.gameState.validMove)
1449 if(!cornerBlocks.passed[cornerBlocks.gameState.colorTurn])
1451 cornerBlocks.btnPass.visible = true;
1452 if(!cornerBlocks.active)
1453 cornerBlocks.Flash();
1456 cornerBlocks.server.Pass();
1458 else if(!cornerBlocks.active)
1459 cornerBlocks.Flash();
1462 // This hangs here, why?
1463 /*if(cornerBlocks.gameState.over)
1464 scoresPanel.visible = true;*/
1467 cornerBlocks.UpdatePlayerNames();
1468 cornerBlocks.Update(null);
1472 void Passed(PlayerColor color)
1474 cornerBlocks.gameState.Pass();
1475 if(color == cornerBlocks.colorPlayed)
1476 cornerBlocks.NextColorPlayed();
1477 else if(!cornerBlocks.active)
1478 cornerBlocks.Flash();
1480 if(cornerBlocks.colorPlayed == cornerBlocks.gameState.colorTurn && !cornerBlocks.gameState.over)
1482 if(!cornerBlocks.gameState.validMove)
1484 if(!cornerBlocks.passed[cornerBlocks.gameState.colorTurn])
1486 cornerBlocks.btnPass.visible = true;
1487 if(!cornerBlocks.active)
1488 cornerBlocks.Flash();
1491 cornerBlocks.server.Pass();
1493 else if(!cornerBlocks.active)
1494 cornerBlocks.Flash();
1499 cornerBlocks.UpdatePlayerNames();
1500 cornerBlocks.Update(null);
1504 void NotifyMessage(const String name, const String msg)
1506 EditBox log = cornerBlocks.chat.log;
1507 const char * format = (log.numLines > 1 || log.line.count) ?
1508 "\n%s: %s" : "%s: %s";
1509 int len = strlen(msg);
1510 // Avoid buffer overflow...
1511 if(len >= MAX_F_STRING-100)
1512 ((char *)msg)[MAX_F_STRING-100] = 0;
1513 cornerBlocks.chat.Log(format, name, msg);
1516 incref cornerBlocks.server;
1517 if(cornerBlocks.server.Connect(serverAddress.contents, CORNERBLOCKS_PORT))
1519 int playerID = cornerBlocks.server.Join();
1520 if(cornerBlocks.server && playerID != -1)
1521 cornerBlocks.server.SetName(playerName.contents);
1523 cornerBlocks.server.Disconnect(0);
1524 UpdateControlsStates();
1527 delete cornerBlocks.server;
1532 Button btnDisconnect
1534 this, caption = "Disconnect", altD, font = { "Arial", 16, bold = true }, size = { 126, 32 }, position = { 256, 64 }, visible = false;
1536 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1538 if(!cornerBlocks.gameStarted || cornerBlocks.gameState.over ||
1539 MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1540 contents = "Game in progress! Disconnect?"
1543 if(cornerBlocks.server)
1544 cornerBlocks.server.Disconnect(0);
1551 this, caption = "Host", altH, font = { "Arial", 16, bold = true }, size = { 90, 32 }, position = { 16, 112 };
1553 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1555 if(!cornerBlocks.gameStarted)
1557 if(cornerBlocksService.Start())
1561 UpdateControlsStates();
1567 Button btnStopHosting
1569 this, caption = "Stop Hosting", altP, font = { "Arial", 16, bold = true }, position = { 16, 112 }, visible = false;
1571 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1575 for(c = 0; c<MaxPlayers; c++)
1576 if(serverPlayers[c])
1579 MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1580 contents = "Players connected! Stop hosting?"
1584 cornerBlocksService.Stop();
1588 UpdateControlsStates();
1595 this, caption = "Start Game", altS, font = { "Arial", 16, bold = true }, size = { 124, 32 }, position = { 256, 112 }, visible = false;
1597 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1602 UpdateControlsStates();
1609 this, caption = "Stop Game", altG, font = { "Arial", 16, bold = true }, position = { 256, 112 }, visible = false;
1611 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1613 if(!serverGameStarted || serverGameState.over ||
1614 MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1615 contents = "Stop game in progress?"
1619 UpdateControlsStates();
1626 this, caption = "Players Connected", altD, size = { 236, 84 }, position = { 16, 176 }, visible = false, hasHeader = true;
1628 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
1630 UpdateControlsStates();
1634 Label lblListPlayers { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 152 }, visible = false, labeledWindow = listPlayers };
1637 this, caption = "Kick", altK, font = { "Arial", 16, bold = true }, size = { 80, 32 }, position = { 264, 224 }, visible = false;
1639 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1641 DataRow row = listPlayers.currentRow;
1644 int id = (int)row.tag;
1646 sprintf(msg, "Kick %s?", serverPlayers[id].name);
1647 if(MessageBox { type = okCancel, caption = "Ecere Corner Blocks",
1657 this, caption = "Player Name:", altN, font = { "Arial", 12 }, size = { 132, 24 }, position = { 104, 8 }, contents = "Player"
1659 Label lblPlayerName { this, font = { "Tahoma", 8.25f, bold = true }, position = { 16, 16 }, labeledWindow = playerName };
1662 CommunicationPanel panel { };
1664 DCOMService cornerBlocksService { port = CORNERBLOCKS_PORT };