Merge branch 'v4.7.x' into master
[xboard.git] / winboard / winboard.c
index 6a51191..1b8460b 100644 (file)
@@ -112,7 +112,6 @@ VOID NewVariantPopup(HWND hwnd);
 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
                   /*char*/int promoChar));\r
 void DisplayMove P((int moveNumber));\r
-Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
 void ChatPopUp P((char *s));\r
 typedef struct {\r
   ChessSquare piece;  \r
@@ -190,6 +189,7 @@ Boolean alwaysOnTop = FALSE;
 RECT boardRect;\r
 COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
   blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
+COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };\r
 HPALETTE hPal;\r
 ColorClass currentColorClass;\r
 \r
@@ -200,7 +200,7 @@ static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred
 static HBRUSH lightSquareBrush, darkSquareBrush,\r
   blackSquareBrush, /* [HGM] for band between board and holdings */\r
   explodeBrush,     /* [HGM] atomic */\r
-  markerBrush,      /* [HGM] markers */\r
+  markerBrush[8],   /* [HGM] markers */\r
   whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];\r
 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];\r
@@ -226,8 +226,6 @@ static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOA
 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
 #else\r
 \r
-\r
-\r
 #if defined(_winmajor)\r
 #define oldDialog (_winmajor < 4)\r
 #else\r
@@ -2195,6 +2193,7 @@ InsertInPalette(COLORREF color)
 VOID\r
 InitDrawingColors()\r
 {\r
+  int i;\r
   if (pLogPal == NULL) {\r
     /* Allocate enough memory for a logical palette with\r
      * PALETTESIZE entries and set the size and version fields\r
@@ -2226,8 +2225,9 @@ InitDrawingColors()
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
-  markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers\r
-  /* [AS] Force rendering of the font-based pieces */\r
+    for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers\r
+\r
+   /* [AS] Force rendering of the font-based pieces */\r
   if( fontBitmapSquareSize > 0 ) {\r
     fontBitmapSquareSize = 0;\r
   }\r
@@ -2301,7 +2301,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
        && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range\r
       || (v == VariantShogi && boardSize != SizeModerate)   // Japanese-style Shogi\r
       ||  v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan\r
-      ||  v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {\r
+      ||  v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {\r
       if(boardSize < SizeMediocre) boardSize = SizePetite; else\r
       if(boardSize > SizeModerate) boardSize = SizeBulky;  else\r
                                    boardSize = SizeMiddling;\r
@@ -2657,6 +2657,9 @@ InitDrawingSizes(BoardSize boardSize, int flags)
     pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
     pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
     pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
+    pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");\r
+    pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");\r
+    pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");\r
 \r
     if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
       pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
@@ -3278,6 +3281,9 @@ BOOL HasHighlightInfo()
     }\r
 \r
     return result;\r
+\r
+\r
+\r
 }\r
 \r
 BOOL IsDrawArrowEnabled()\r
@@ -3469,6 +3475,7 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
             DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);\r
       else if( column == BOARD_RGHT) /* right align */\r
             DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);\r
+      else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);\r
       else\r
       if (appData.monoMode) {\r
         if (piece == EmptySquare) {\r
@@ -3651,7 +3658,7 @@ void DrawSeekDot(int x, int y, int color)
 {\r
        int square = color & 0x80;\r
        HBRUSH oldBrush = SelectObject(hdcSeek, \r
-                       color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);\r
+                       color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);\r
        color &= 0x7F;\r
        if(square)\r
            Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,\r
@@ -3944,8 +3951,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   for (row = 0; row < BOARD_HEIGHT; row++) {\r
     for (column = 0; column < BOARD_WIDTH; column++) {\r
        if (marker[row][column]) { // marker changes only occur with full repaint!\r
-           HBRUSH oldBrush = SelectObject(hdcmem, \r
-                       marker[row][column] == 2 ? markerBrush : explodeBrush);\r
+           HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);\r
            SquareToPos(row, column, &x, &y);\r
            Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,\r
                          x + 3*squareSize/4, y + 3*squareSize/4);\r
@@ -4301,8 +4307,10 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
        ClockClick(!flipClock); break;\r
       }\r
+    if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
+    }\r
     if(fromX == -1 && frozen) { // not sure where this is for\r
                fromX = fromY = -1; \r
       DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
@@ -4322,7 +4330,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;\r
     MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);\r
     if ((appData.animateDragging || appData.highlightDragging)\r
-       && (wParam & MK_LBUTTON)\r
+       && (wParam & MK_LBUTTON || dragging == 2)\r
        && dragInfo.from.x >= 0) \r
     {\r
       BOOL full_repaint = FALSE;\r
@@ -4331,7 +4339,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        dragInfo.pos = pt;\r
       }\r
       if (appData.highlightDragging) {\r
-       SetHighlights(fromX, fromY, x, y);\r
+       HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);\r
         if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {\r
             full_repaint = TRUE;\r
         }\r
@@ -4466,6 +4474,8 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);\r
 }\r
 \r
+static int promoStyle;\r
+\r
 /* Process messages for Promotion dialog box */\r
 LRESULT CALLBACK\r
 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
@@ -4496,13 +4506,9 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
          PieceToChar(BlackMarshall) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
-    ShowWindow(GetDlgItem(hDlg, PB_Rook),\r
-       gameInfo.variant != VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
-    ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
-       gameInfo.variant != VariantShogi ?\r
-              SW_SHOW : SW_HIDE);\r
-    if(gameInfo.variant == VariantShogi) {\r
+    ShowWindow(GetDlgItem(hDlg, PB_Rook),   !promoStyle ? SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);\r
+    if(promoStyle) {\r
         SetDlgItemText(hDlg, PB_Queen, "YES");\r
         SetDlgItemText(hDlg, PB_Knight, "NO");\r
         SetWindowText(hDlg, "Promote?");\r
@@ -4523,7 +4529,7 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
+      promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
       break;\r
     case PB_Rook:\r
       promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));\r
@@ -4540,7 +4546,8 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
       break;\r
     case PB_Knight:\r
-      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR : \r
+                  ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));\r
       break;\r
     default:\r
       return FALSE;\r
@@ -4571,8 +4578,9 @@ PromotionPopup(HWND hwnd)
 }\r
 \r
 void\r
-PromotionPopUp()\r
+PromotionPopUp(char choice)\r
 {\r
+  promoStyle = (choice == '+');\r
   DrawPosition(TRUE, NULL);\r
   PromotionPopup(hwndMain);\r
 }\r
@@ -4789,6 +4797,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       nnew = RealizePalette(hdc);\r
       if (nnew > 0) {\r
        paletteChanged = TRUE;\r
+\r
         InvalidateRect(hwnd, &boardRect, FALSE);\r
       }\r
       ReleaseDC(hwnd, hdc);\r
@@ -5131,6 +5140,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       break;\r
 \r
     case IDM_Rematch:\r
+\r
       RematchEvent();\r
       break;\r
 \r
@@ -6288,6 +6298,7 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
        SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...\r
        ParseArgs(StringGet, &p);\r
        SwapEngines(singleList); // ... and then make it 'second'\r
+\r
        appData.noChessProgram = FALSE;\r
        appData.icsActive = FALSE;\r
       } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
@@ -6865,6 +6876,7 @@ GothicPopUp(char *title, VariantClass variant)
 static char *history[HISTORY_SIZE];\r
 int histIn = 0, histP = 0;\r
 \r
+\r
 VOID\r
 SaveInHistory(char *cmd)\r
 {\r
@@ -6877,6 +6889,7 @@ SaveInHistory(char *cmd)
   histIn = (histIn + 1) % HISTORY_SIZE;\r
   if (history[histIn] != NULL) {\r
     free(history[histIn]);\r
+\r
     history[histIn] = NULL;\r
   }\r
   histP = histIn;\r
@@ -7687,6 +7700,7 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
       else\r
        err = GetLastError();\r
     }\r
+\r
   }\r
   return err;\r
 }\r
@@ -8552,6 +8566,7 @@ HWND gameListOptionsDialog;
 \r
 // low-level front-end: clear text edit / list widget\r
 void\r
+\r
 GLT_ClearList()\r
 {\r
     SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
@@ -8743,6 +8758,13 @@ EditCommentPopUp(int index, char *title, char *str)
 }\r
 \r
 \r
+int\r
+Roar()\r
+{\r
+  MyPlaySound(&sounds[(int)SoundRoar]);\r
+  return 1;\r
+}\r
+\r
 VOID\r
 RingBell()\r
 {\r
@@ -8900,6 +8922,7 @@ DisplayBlackClock(long timeRemaining, int highlight)
   HDC hdc;\r
   char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
 \r
+\r
   if(appData.noGUI) return;\r
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
@@ -9918,16 +9941,23 @@ AnimateMove(board, fromX, fromY, toX, toY)
      int toY;\r
 {\r
   ChessSquare piece;\r
+  int x = toX, y = toY;\r
   POINT start, finish, mid;\r
   POINT frames[kFactor * 2 + 1];\r
   int nFrames, n;\r
 \r
+  if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();\r
+\r
   if (!appData.animate) return;\r
   if (doingSizing) return;\r
   if (fromY < 0 || fromX < 0) return;\r
   piece = board[fromY][fromX];\r
   if (piece >= EmptySquare) return;\r
 \r
+  if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square\r
+\r
+again:\r
+\r
   ScreenSquare(fromX, fromY, &start);\r
   ScreenSquare(toX, toY, &finish);\r
 \r
@@ -9966,6 +9996,9 @@ AnimateMove(board, fromX, fromY, toX, toY)
   }\r
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
+\r
+  if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg\r
+\r
   animInfo.piece = EmptySquare;\r
   Explode(board, fromX, fromY, toX, toY);\r
 }\r