changes by H.G. Muller; version 4.3.4
[xboard.git] / winboard / winboard.c
index d2facc2..21460fd 100644 (file)
@@ -93,6 +93,8 @@ void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
 \r
 extern int whiteFlag, blackFlag;\r
 \r
+void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
+\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -168,6 +170,7 @@ HWND hCommPort = NULL;    /* currently open comm port */
 static HWND hwndPause;    /* pause button */\r
 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
 static HBRUSH lightSquareBrush, darkSquareBrush,\r
+  blackSquareBrush, /* [HGM] for band between board and holdings */\r
   whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;\r
 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
@@ -584,6 +587,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   } else {\r
     GetCurrentDirectory(MSG_SIZ, installDir);\r
   }\r
+  gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
   if (appData.debugMode) {\r
     debugFP = fopen(appData.nameOfDebugFile, "w");\r
@@ -1163,11 +1167,16 @@ ArgDescriptor argDescriptors[] = {
   { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
   { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
 \r
-  /* [HGM] User-selectable board size */\r
+  /* [HGM] board-size, adjudication and misc. options */\r
   { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
   { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
+  { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
   { "matchPause", ArgInt, (LPVOID) &appData.matchPause, FALSE },\r
+  { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, TRUE },\r
   { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
+  { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
+  { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
+  { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
   { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
   { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
 \r
@@ -1875,13 +1884,18 @@ InitAppData(LPSTR lpCmdLine)
   InitWindowPlacement( &wpEvalGraph );\r
   InitWindowPlacement( &wpEngineOutput );\r
 \r
-  /* [HGM] User-selectable board size */\r
-  appData.NrFiles = 8;\r
-  appData.NrRanks = 8;\r
-  appData.matchPause  = 10000;\r
-  appData.testClaims  = FALSE;\r
-  appData.ruleMoves   = 51;\r
-  appData.drawRepeats = 6;\r
+  /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
+  appData.NrFiles      = -1;\r
+  appData.NrRanks      = -1;\r
+  appData.holdingsSize = -1;\r
+  appData.testClaims   = FALSE;\r
+  appData.checkMates   = FALSE;\r
+  appData.materialDraws= FALSE;\r
+  appData.trivialDraws = FALSE;\r
+  appData.ruleMoves    = 51;\r
+  appData.drawRepeats  = 6;\r
+  appData.matchPause   = 10000;\r
+  appData.alphaRank    = FALSE;\r
 \r
 #ifdef ZIPPY\r
   appData.zippyTalk = ZIPPY_TALK;\r
@@ -2285,37 +2299,37 @@ enum {
     PM_WN = (int) WhiteKnight, \r
     PM_WB = (int) WhiteBishop, \r
     PM_WR = (int) WhiteRook, \r
+    PM_WQ = (int) WhiteQueen, \r
 #ifdef FAIRY\r
-    PM_WA  = (int) WhiteCardinal, \r
-    PM_WC  = (int) WhiteMarshall, \r
-    PM_WFP = (int) WhiteFairyPawn, \r
-    PM_WFN = (int) WhiteFairyKnight, \r
-    PM_WFB = (int) WhiteFairyBishop, \r
-    PM_WFR = (int) WhiteFairyRook, \r
-    PM_WFA = (int) WhiteFairyCardinal, \r
-    PM_WFC = (int) WhiteFairyMarshall, \r
-    PM_WFQ = (int) WhiteFairyQueen, \r
-    PM_WFK = (int) WhiteFairyKing, \r
+    PM_WF = (int) WhiteFerz, \r
+    PM_WW = (int) WhiteWazir, \r
+    PM_WE = (int) WhiteAlfil, \r
+    PM_WH = (int) WhiteNightrider, \r
+    PM_WA = (int) WhiteCardinal, \r
+    PM_WC = (int) WhiteMarshall, \r
+    PM_WG = (int) WhiteGrasshopper, \r
+    PM_WO = (int) WhiteCannon, \r
+    PM_WM = (int) WhiteMan, \r
+    PM_WU = (int) WhiteUnicorn, \r
 #endif\r
-    PM_WQ = (int) WhiteQueen, \r
     PM_WK = (int) WhiteKing,\r
     PM_BP = (int) BlackPawn, \r
     PM_BN = (int) BlackKnight, \r
     PM_BB = (int) BlackBishop, \r
     PM_BR = (int) BlackRook, \r
+    PM_BQ = (int) BlackQueen, \r
 #ifdef FAIRY\r
-    PM_BA  = (int) BlackCardinal, \r
-    PM_BC  = (int) BlackMarshall, \r
-    PM_BFP = (int) BlackFairyPawn, \r
-    PM_BFN = (int) BlackFairyKnight, \r
-    PM_BFB = (int) BlackFairyBishop, \r
-    PM_BFR = (int) BlackFairyRook, \r
-    PM_BFA = (int) BlackFairyCardinal, \r
-    PM_BFC = (int) BlackFairyMarshall, \r
-    PM_BFQ = (int) BlackFairyQueen, \r
-    PM_BFK = (int) BlackFairyKing,\r
+    PM_BF = (int) BlackFerz, \r
+    PM_BW = (int) BlackWazir, \r
+    PM_BE = (int) BlackAlfil, \r
+    PM_BH = (int) BlackNightrider, \r
+    PM_BA = (int) BlackCardinal, \r
+    PM_BC = (int) BlackMarshall, \r
+    PM_BG = (int) BlackGrasshopper, \r
+    PM_BO = (int) BlackCannon, \r
+    PM_BM = (int) BlackMan,\r
+    PM_BU = (int) BlackUnicorn, \r
 #endif\r
-    PM_BQ = (int) BlackQueen, \r
     PM_BK = (int) BlackKing\r
 };\r
 \r
@@ -2324,15 +2338,15 @@ static HBITMAP hPieceMask[(int) EmptySquare];
 static HBITMAP hPieceFace[(int) EmptySquare];\r
 static int fontBitmapSquareSize = 0;\r
 static char pieceToFontChar[(int) EmptySquare] =\r
-                              { 'p', 'n', 'b', 'r',\r
+                              { 'p', 'n', 'b', 'r', 'q', \r
 #ifdef FAIRY\r
                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
 #endif\r
-                      'q', 'k', 'o', 'm', 'v', 't', \r
+                      'k', 'o', 'm', 'v', 't', 'w', \r
 #ifdef FAIRY\r
                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
 #endif\r
-                                                              'w', 'l' };\r
+                                                              'l' };\r
 \r
 static BOOL SetPieceToFontCharTable( const char * map )\r
 {\r
@@ -2343,13 +2357,11 @@ static BOOL SetPieceToFontCharTable( const char * map )
         int i; /* [HGM] Accept even length from 12 to 32 */\r
 \r
         for( i=0; i<(int) EmptySquare; i++ ) pieceToFontChar[i] = 0;\r
-        for( i=0; i<NrPieces/2-2; i++ ) {\r
+        for( i=0; i<NrPieces/2-1; i++ ) {\r
             pieceToFontChar[i] = map[i];\r
             pieceToFontChar[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];\r
         }\r
-        pieceToFontChar[(int) WhiteQueen] = map[NrPieces/2-2];\r
         pieceToFontChar[(int) WhiteKing]  = map[NrPieces/2-1];\r
-        pieceToFontChar[(int) BlackQueen] = map[NrPieces-2];\r
         pieceToFontChar[(int) BlackKing]  = map[NrPieces-1];\r
 \r
         result = TRUE;\r
@@ -2574,42 +2586,42 @@ static int TranslatePieceToFontPiece( int piece )
         return PM_BA;\r
     case BlackMarshall:\r
         return PM_BC;\r
-    case BlackFairyPawn:\r
-        return PM_BFP;\r
-    case BlackFairyKnight:\r
-        return PM_BFN;\r
-    case BlackFairyBishop:\r
-        return PM_BFB;\r
-    case BlackFairyRook:\r
-        return PM_BFR;\r
-    case BlackFairyCardinal:\r
-        return PM_BFA;\r
-    case BlackFairyMarshall:\r
-        return PM_BFC;\r
-    case BlackFairyQueen:\r
-        return PM_BFQ;\r
-    case BlackFairyKing:\r
-        return PM_BFK;\r
+    case BlackFerz:\r
+        return PM_BF;\r
+    case BlackNightrider:\r
+        return PM_BH;\r
+    case BlackAlfil:\r
+        return PM_BE;\r
+    case BlackWazir:\r
+        return PM_BW;\r
+    case BlackUnicorn:\r
+        return PM_BU;\r
+    case BlackCannon:\r
+        return PM_BO;\r
+    case BlackGrasshopper:\r
+        return PM_BG;\r
+    case BlackMan:\r
+        return PM_BM;\r
     case WhiteCardinal:\r
         return PM_WA;\r
     case WhiteMarshall:\r
         return PM_WC;\r
-    case WhiteFairyPawn:\r
-        return PM_WFP;\r
-    case WhiteFairyKnight:\r
-        return PM_WFN;\r
-    case WhiteFairyBishop:\r
-        return PM_WFB;\r
-    case WhiteFairyRook:\r
-        return PM_WFR;\r
-    case WhiteFairyCardinal:\r
-        return PM_WFA;\r
-    case WhiteFairyMarshall:\r
-        return PM_WFC;\r
-    case WhiteFairyQueen:\r
-        return PM_WFQ;\r
-    case WhiteFairyKing:\r
-        return PM_WFK;\r
+    case WhiteFerz:\r
+        return PM_WF;\r
+    case WhiteNightrider:\r
+        return PM_WH;\r
+    case WhiteAlfil:\r
+        return PM_WE;\r
+    case WhiteWazir:\r
+        return PM_WW;\r
+    case WhiteUnicorn:\r
+        return PM_WU;\r
+    case WhiteCannon:\r
+        return PM_WO;\r
+    case WhiteGrasshopper:\r
+        return PM_WG;\r
+    case WhiteMan:\r
+        return PM_WM;\r
 #endif\r
     }\r
 \r
@@ -2726,24 +2738,24 @@ void CreatePiecesFromFont()
 #ifdef FAIRY\r
             CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
             CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFP );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFN );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFR );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFA );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFQ );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_WFK );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
             CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
             CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFP );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFN );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFB );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFR );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFA );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFC );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFQ );\r
-            CreatePieceMaskFromFont( hdc_window, hdc, PM_BFK );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
 #endif\r
 \r
             SelectObject( hdc, hfont_old );\r
@@ -2828,6 +2840,7 @@ InitDrawingColors()
   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
 \r
   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
+  blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
@@ -2890,6 +2903,9 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   int offby;\r
   LOGBRUSH logbrush;\r
 \r
+  /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */\r
+  if(boardSize == (BoardSize)(-1) ) boardSize = oldBoardSize;\r
+\r
   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
   smallLayout = sizeInfo[boardSize].smallLayout;\r
   squareSize = sizeInfo[boardSize].squareSize;\r
@@ -3103,36 +3119,65 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
 #ifdef FAIRY\r
   if(squareSize==72 || squareSize==49) { /* experiment with some home-made bitmaps */\r
+  pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
+  pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
+  pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
+  pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
+  pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
+  pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+  if(!strcmp(appData.variant, "shogi")) { /* promoted Gold represemtations */\r
+  pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
+  pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
+  pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+  pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");\r
+  pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");\r
+  pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+  pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
+  pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wl", squareSize, "o");\r
+  pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+  pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
+  pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
+  pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+  } else {\r
+  pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
+  pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
+  pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
+  pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
+  pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
+  pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
   pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
-  pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyPawn] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyKnight] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyBishop] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyRook] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyQueen] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyCardinal] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyMarshall] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
-  pieceBitmap[0][WhiteFairyKing] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
   pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
-  pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyPawn] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyKnight] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyBishop] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyRook] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyQueen] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyCardinal] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyMarshall] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
-  pieceBitmap[1][WhiteFairyKing] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
   pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
+  pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
+  pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
+  pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
+  pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
+  pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
+  pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
+  }\r
+  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][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
+  pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
+  pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
+  if(strcmp(appData.variant, "crazyhouse") && strcmp(appData.variant, "shogi")) {\r
+  pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
+  pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
   pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyPawn] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyKnight] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyBishop] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyRook] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyQueen] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyCardinal] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyMarshall] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
-  pieceBitmap[2][WhiteFairyKing] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
+  } else {\r
+  pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "s");\r
+  pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "o");\r
+  pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "w");\r
+  }\r
+  if(!strcmp(appData.variant, "xiangqi") || !strcmp(appData.variant, "shogi")) {\r
+      for(i=0; i<2; i++)\r
+      if (pieceBitmap[i][WhiteQueen] != NULL)\r
+        DeleteObject(pieceBitmap[i][WhiteQueen]);\r
+  pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
+  pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
+  pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
+  }\r
   }\r
 #endif\r
 \r
@@ -3750,13 +3795,37 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
 \r
       square_color = ((column + row) % 2) == 1;\r
       if(!strcmp(appData.variant, "xiangqi") ) {\r
-          square_color = 1;\r
-          if( (row < 3 || row > BOARD_HEIGHT-4) &&\r
-              column < (BOARD_WIDTH + 4)/2 &&\r
-              column > (BOARD_WIDTH - 5)/2 ) square_color = 0;\r
+          square_color = !InPalace(row, column);\r
+          if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }\r
+          else if(row < BOARD_HEIGHT/2) square_color ^= 1;\r
       }\r
       piece_color = (int) piece < (int) BlackPawn;\r
 \r
+\r
+#ifdef FAIRY\r
+      /* [HGM] holdings file: light square or black */\r
+      if(column == BOARD_LEFT-2) {\r
+            if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )\r
+                square_color = 1;\r
+            else {\r
+                DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */\r
+                continue;\r
+            }\r
+      } else\r
+      if(column == BOARD_RGHT + 1 ) {\r
+            if( row < gameInfo.holdingsSize )\r
+                square_color = 1;\r
+            else {\r
+                DisplayHoldingsCount(hdc, x, y, 0, 0); \r
+                continue;\r
+            }\r
+      }\r
+      if(column == BOARD_LEFT-1 ) /* left align */\r
+            DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);\r
+      else if( column == BOARD_RGHT) /* right align */\r
+            DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);\r
+      else\r
+#endif\r
       if (appData.monoMode) {\r
         if (piece == EmptySquare) {\r
           BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,\r
@@ -3784,8 +3853,9 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
           }\r
       }\r
       else {\r
-        oldBrush = SelectObject(hdc, square_color ?\r
-                               lightSquareBrush : darkSquareBrush);\r
+        HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;\r
+\r
+        oldBrush = SelectObject(hdc, brush );\r
         BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);\r
         SelectObject(hdc, oldBrush);\r
         if (piece != EmptySquare)\r
@@ -3904,6 +3974,22 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   hdcmem = CreateCompatibleDC(hdc);\r
   tmphdc = CreateCompatibleDC(hdc);\r
 \r
+  /* If dragging is in progress, we temporarely remove the piece */\r
+  /* [HGM] or temporarily decrease count if stacked              */\r
+  /*       !! Moved to before board compare !!                   */\r
+  if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {\r
+    dragged_piece = board[dragInfo.from.y][dragInfo.from.x];\r
+    if(dragInfo.from.x == BOARD_LEFT-2 ) {\r
+            if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )\r
+        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+    } else \r
+    if(dragInfo.from.x == BOARD_RGHT+1) {\r
+            if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )\r
+        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+    } else \r
+        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+  }\r
+\r
   /* Figure out which squares need updating by comparing the \r
    * newest board with the last drawn board and checking if\r
    * flipping has changed.\r
@@ -3997,12 +4083,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     }\r
   }\r
 \r
-  /* If dragging is in progress, we temporarely remove the piece */\r
-  if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {\r
-    dragged_piece = board[dragInfo.from.y][dragInfo.from.x];\r
-    board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
-  }\r
-\r
   /* Are we animating a move?  \r
    * If so, \r
    *   - remove the piece from the board (temporarely)\r
@@ -4051,8 +4131,17 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
 \r
   DrawCoordsOnDC(hdcmem);\r
 \r
-  /* Put the dragged piece back into place and draw it */\r
-  if (dragged_piece != EmptySquare) {\r
+  CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */\r
+                 /* to make sure lastDrawn contains what is actually drawn */\r
+\r
+  /* Put the dragged piece back into place and draw it (out of place!) */\r
+    if (dragged_piece != EmptySquare) {\r
+    /* [HGM] or restack */\r
+    if(dragInfo.from.x == BOARD_LEFT-2 )\r
+                 board[dragInfo.from.y][dragInfo.from.x+1]++;\r
+    else\r
+    if(dragInfo.from.x == BOARD_RGHT+1 )\r
+                 board[dragInfo.from.y][dragInfo.from.x-1]++;\r
     board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;\r
     x = dragInfo.pos.x - squareSize / 2;\r
     y = dragInfo.pos.y - squareSize / 2;\r
@@ -4113,7 +4202,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
       CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);\r
   }\r
 \r
-  CopyBoard(lastDrawn, board);\r
+/*  CopyBoard(lastDrawn, board);*/\r
   lastDrawnHighlight = highlightInfo;\r
   lastDrawnPremove   = premoveHighlightInfo;\r
   lastDrawnFlipView = flipView;\r
@@ -4230,6 +4319,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   BOOLEAN saveAnimate;\r
   BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
   static BOOLEAN sameAgain = FALSE;\r
+  ChessMove moveType;\r
 \r
   if (recursive) {\r
     if (message == WM_MBUTTONUP) {\r
@@ -4283,15 +4373,24 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
       break;\r
-    } else if (x < 0 || y < 0) {\r
+    } else if (x < 0 || y < 0\r
+      /* [HGM] block clicks between board and holdings */\r
+              || x == BOARD_LEFT-1 || x == BOARD_RGHT\r
+              || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize\r
+              || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize\r
+                               ) {\r
       break;\r
     } else if (fromX == x && fromY == y) {\r
       /* Downclick on same square again */\r
       ClearHighlights();\r
       DrawPosition(forceFullRepaint || FALSE, NULL);\r
       sameAgain = TRUE;  \r
-    } else if (fromX != -1) {\r
-      /* Downclick on different square */\r
+    } else if (fromX != -1 &&\r
+               x != BOARD_LEFT-2 && x != BOARD_RGHT+1 \r
+                                                                        ) {\r
+      /* Downclick on different square. */\r
+      /* [HGM] if on holdings file, should count as new first click ! */\r
+       \r
       ChessSquare pdown, pup;\r
       pdown = boards[currentMove][fromY][fromX];\r
       pup = boards[currentMove][y][x];\r
@@ -4304,30 +4403,37 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
           click-click move is possible */\r
        toX = x;\r
        toY = y;\r
-       if (IsPromotion(fromX, fromY, toX, toY)) {\r
-         if (appData.alwaysPromoteToQueen) {\r
-           UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
-           if (!appData.highlightLastMove) {\r
-             ClearHighlights();\r
-             DrawPosition(forceFullRepaint || FALSE, NULL);\r
-           }\r
-         } else {\r
-           SetHighlights(fromX, fromY, toX, toY);\r
-           DrawPosition(forceFullRepaint || FALSE, NULL);\r
-           PromotionPopup(hwnd);\r
-         }\r
-       } else {        /* not a promotion */\r
-         if (appData.animate || appData.highlightLastMove) {\r
-           SetHighlights(fromX, fromY, toX, toY);\r
-         } else {\r
-           ClearHighlights();\r
-         }\r
-         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);\r
-         if (appData.animate && !appData.highlightLastMove) {\r
-           ClearHighlights();\r
-           DrawPosition(forceFullRepaint || FALSE, NULL);\r
-         }\r
-       }\r
+        moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
+        if(moveType != ImpossibleMove) {\r
+          if (IsPromotion(fromX, fromY, toX, toY)) {\r
+             /* [HGM] <popupFix> UserMoveEvent requires two calls now,\r
+                to make sure move is legal before showing promotion popup */\r
+             if (appData.alwaysPromoteToQueen) {\r
+                  FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
+                  if (!appData.highlightLastMove) {\r
+                      ClearHighlights();\r
+                      DrawPosition(forceFullRepaint || FALSE, NULL);\r
+                  }\r
+             } else {\r
+                  SetHighlights(fromX, fromY, toX, toY);\r
+                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
+                  /* [HGM] <popupFix> Popup calls FinishMove now.\r
+                     If promotion to Q is legal, all are legal! */\r
+                  PromotionPopup(hwnd);\r
+             }\r
+          } else {       /* not a promotion */\r
+             if (appData.animate || appData.highlightLastMove) {\r
+                 SetHighlights(fromX, fromY, toX, toY);\r
+             } else {\r
+                 ClearHighlights();\r
+             }\r
+             FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
+             if (appData.animate && !appData.highlightLastMove) {\r
+                  ClearHighlights();\r
+                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
+             }\r
+          }\r
+        }\r
        if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
        fromX = fromY = -1;\r
        break;\r
@@ -4356,7 +4462,6 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     ReleaseCapture();\r
     if (fromX == -1) break;\r
     if (x == fromX && y == fromY) {\r
-      dragInfo.from.x = dragInfo.from.y = -1;\r
       /* Upclick on same square */\r
       if (sameAgain) {\r
        /* Clicked same square twice: abort click-click move */\r
@@ -4367,26 +4472,31 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        /* First square clicked: start click-click move */\r
        SetHighlights(fromX, fromY, -1, -1);\r
       }\r
+      dragInfo.from.x = dragInfo.from.y = -1;\r
       DrawPosition(forceFullRepaint || FALSE, NULL);\r
     } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {\r
       /* Errant click; ignore */\r
       break;\r
     } else {\r
-      /* Finish drag move */\r
+      /* Finish drag move. */\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "release\n");\r
+    }\r
       dragInfo.from.x = dragInfo.from.y = -1;\r
       toX = x;\r
       toY = y;\r
       saveAnimate = appData.animate; /* sorry, Hawk :) */\r
       appData.animate = appData.animate && !appData.animateDragging;\r
-      if (IsPromotion(fromX, fromY, toX, toY)) {\r
-       if (appData.alwaysPromoteToQueen) {\r
-         UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
-       } else {\r
-         DrawPosition(forceFullRepaint || FALSE, NULL);\r
-         PromotionPopup(hwnd);\r
-       }\r
-      } else {\r
-       UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);\r
+      moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
+      if(moveType != ImpossibleMove) {\r
+        if (IsPromotion(fromX, fromY, toX, toY)) {\r
+          if (appData.alwaysPromoteToQueen)\r
+                  FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
+          else {\r
+            DrawPosition(forceFullRepaint || FALSE, NULL);\r
+            PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
+          }\r
+        } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
       }\r
       if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
       appData.animate = saveAnimate;\r
@@ -4410,12 +4520,13 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     {\r
       BOOL full_repaint = FALSE;\r
 \r
+      sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */\r
       if (appData.animateDragging) {\r
        dragInfo.pos = pt;\r
       }\r
       if (appData.highlightDragging) {\r
        SetHighlights(fromX, fromY, x, y);\r
-        if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y > BOARD_WIDTH) ) {\r
+        if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {\r
             full_repaint = TRUE;\r
         }\r
       }\r
@@ -4614,7 +4725,11 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       return FALSE;\r
     }\r
     EndDialog(hDlg, TRUE); /* Exit the dialog */\r
-    UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
+    /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we\r
+       only show the popup when we are already sure the move is valid or\r
+       legal. We pass a faulty move type, but the kludge is that FinishMove\r
+       will figure out it is a promotion from the promoChar. */\r
+    FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);\r
     if (!appData.highlightLastMove) {\r
       ClearHighlights();\r
       DrawPosition(FALSE, NULL);\r
@@ -4831,6 +4946,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
       break;\r
 \r
+    case IDM_NewVariant:\r
+      NewVariantPopup(hwnd);\r
+      break;\r
+\r
     case IDM_LoadGame:\r
       LoadGameDialog(hwnd, "Load Game from File");\r
       break;\r
@@ -7278,6 +7397,37 @@ ConsoleOutput(char* data, int length, int forceVisible)
 \r
 \r
 void\r
+DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)\r
+{\r
+  char buf[100];\r
+  char *str;\r
+  COLORREF oldFg, oldBg;\r
+  HFONT oldFont;\r
+  RECT rect;\r
+\r
+  if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;\r
+\r
+  oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */\r
+  oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */\r
+  oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
+\r
+  rect.left = x;\r
+  rect.right = x + squareSize;\r
+  rect.top  = y;\r
+  rect.bottom = y + squareSize;\r
+  str = buf;\r
+\r
+  ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN\r
+                    + (rightAlign ? (squareSize*2)/3 : 0),\r
+             y, ETO_CLIPPED|ETO_OPAQUE,\r
+             &rect, str, strlen(str), NULL);\r
+\r
+  (void) SetTextColor(hdc, oldFg);\r
+  (void) SetBkColor(hdc, oldBg);\r
+  (void) SelectObject(hdc, oldFont);\r
+}\r
+\r
+void\r
 DisplayAClock(HDC hdc, int timeRemaining, int highlight,\r
               RECT *rect, char *color, char *flagFell)\r
 {\r