changes from H.G. Muller; version 4.3.7
[xboard.git] / winboard / winboard.c
index 21460fd..7369520 100644 (file)
@@ -92,6 +92,7 @@ void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
   void mysrandom(unsigned int seed);\r
 \r
 extern int whiteFlag, blackFlag;\r
+Boolean flipClock = FALSE;\r
 \r
 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
 \r
@@ -137,7 +138,7 @@ char installDir[MSG_SIZ];
 BoardSize boardSize;\r
 BOOLEAN chessProgram;\r
 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;\r
-static int squareSize, lineGap;\r
+static int squareSize, lineGap, minorSize;\r
 static int winWidth, winHeight;\r
 static RECT messageRect, whiteRect, blackRect;\r
 static char messageText[MESSAGE_TEXT_MAX];\r
@@ -423,7 +424,7 @@ VOID EngineOutputPopDown();
 BOOL EngineOutputIsUp();\r
 VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
 \r
-VOID GothicPopUp(char *title);\r
+VOID GothicPopUp(char *title, char up);\r
 /*\r
  * Setting "frozen" should disable all user input other than deleting\r
  * the window.  We do this while engines are initializing themselves.\r
@@ -694,13 +695,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   if( gameInfo.variant != VariantFischeRandom ) {\r
       EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );\r
   }\r
-#ifdef FAIRY\r
-#ifdef GOTHIC\r
-  /* [HGM] Gothic licensing requirement */\r
-  if(gameInfo.variant == VariantGothic)\r
-      GothicPopUp(GOTHIC);\r
-#endif // GOTHIC\r
-#endif // FAIRY\r
+\r
   if (hwndConsole) {\r
 #if AOT_CONSOLE\r
     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
@@ -1171,8 +1166,11 @@ ArgDescriptor argDescriptors[] = {
   { "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
+  { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
+  { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
+  { "flipBlack", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
+  { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
+  { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
   { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
   { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
   { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
@@ -1896,6 +1894,8 @@ InitAppData(LPSTR lpCmdLine)
   appData.drawRepeats  = 6;\r
   appData.matchPause   = 10000;\r
   appData.alphaRank    = FALSE;\r
+  appData.allWhite     = FALSE;\r
+  appData.upsideDown   = FALSE;\r
 \r
 #ifdef ZIPPY\r
   appData.zippyTalk = ZIPPY_TALK;\r
@@ -2300,36 +2300,32 @@ enum {
     PM_WB = (int) WhiteBishop, \r
     PM_WR = (int) WhiteRook, \r
     PM_WQ = (int) WhiteQueen, \r
-#ifdef FAIRY\r
     PM_WF = (int) WhiteFerz, \r
     PM_WW = (int) WhiteWazir, \r
     PM_WE = (int) WhiteAlfil, \r
+    PM_WM = (int) WhiteMan, \r
+    PM_WO = (int) WhiteCannon, \r
+    PM_WU = (int) WhiteUnicorn, \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_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_BF = (int) BlackFerz, \r
     PM_BW = (int) BlackWazir, \r
     PM_BE = (int) BlackAlfil, \r
+    PM_BM = (int) BlackMan,\r
+    PM_BO = (int) BlackCannon, \r
+    PM_BU = (int) BlackUnicorn, \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_BK = (int) BlackKing\r
 };\r
 \r
@@ -2339,36 +2335,13 @@ static HBITMAP hPieceFace[(int) EmptySquare];
 static int fontBitmapSquareSize = 0;\r
 static char pieceToFontChar[(int) EmptySquare] =\r
                               { 'p', 'n', 'b', 'r', 'q', \r
-#ifdef FAIRY\r
                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
-#endif\r
                       'k', 'o', 'm', 'v', 't', 'w', \r
-#ifdef FAIRY\r
                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
-#endif\r
                                                               'l' };\r
 \r
-static BOOL SetPieceToFontCharTable( const char * map )\r
-{\r
-    BOOL result = FALSE; int NrPieces;\r
-\r
-    if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare \r
-                    && NrPieces >= 12 && !(NrPieces&1)) {\r
-        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-1; i++ ) {\r
-            pieceToFontChar[i] = map[i];\r
-            pieceToFontChar[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];\r
-        }\r
-        pieceToFontChar[(int) WhiteKing]  = map[NrPieces/2-1];\r
-        pieceToFontChar[(int) BlackKing]  = map[NrPieces-1];\r
-\r
-        result = TRUE;\r
-    }\r
-\r
-    return result;\r
-}\r
+extern BOOL SetCharTable( char *table, const char * map );\r
+/* [HGM] moved to backend.c */\r
 \r
 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
 {\r
@@ -2692,31 +2665,29 @@ void CreatePiecesFromFont()
         }\r
         else {\r
             /* Setup font-to-piece character table */\r
-            if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) {\r
+            if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
                 /* No (or wrong) global settings, try to detect the font */\r
                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
                     /* Alpha */\r
-                    SetPieceToFontCharTable("phbrqkojntwl");\r
+                    SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
                 }\r
                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
                     /* DiagramTT* family */\r
-                    SetPieceToFontCharTable("PNLRQKpnlrqk");\r
+                    SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
                 }\r
-#ifdef FAIRY\r
                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
                     /* Fairy symbols */\r
-                        SetPieceToFontCharTable("PNBRACFHEWUOGMQKpnbracfewuogmqk");\r
+                     SetCharTable(pieceToFontChar, "PNBRQFWEMOUHACGSKpnbrqfwemouhacgsk");\r
                 }\r
-#endif\r
                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
                     /* Good Companion (Some characters get warped as literal :-( */\r
                     char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
-                    SetPieceToFontCharTable(s);\r
+                    SetCharTable(pieceToFontChar, s);\r
                 }\r
                 else {\r
                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
-                    SetPieceToFontCharTable("pnbrqkomvtwl");\r
+                    SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
                 }\r
             }\r
 \r
@@ -2904,12 +2875,13 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   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
+  if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
 \r
   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
   smallLayout = sizeInfo[boardSize].smallLayout;\r
   squareSize = sizeInfo[boardSize].squareSize;\r
   lineGap = sizeInfo[boardSize].lineGap;\r
+  minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted  */\r
 \r
   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
       lineGap = appData.overrideLineGap;\r
@@ -3085,7 +3057,12 @@ InitDrawingSizes(BoardSize boardSize, int flags)
     }\r
   }\r
 \r
-  if (boardSize == oldBoardSize) return;\r
+#ifdef GOTHIC\r
+  /* [HGM] Gothic licensing requirement */\r
+  GothicPopUp( GOTHIC, gameInfo.variant == VariantGothic );\r
+#endif\r
+\r
+/*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
   oldBoardSize = boardSize;\r
   oldTinyLayout = tinyLayout;\r
 \r
@@ -3103,21 +3080,26 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");\r
   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");\r
-  pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");\r
   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");\r
   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");\r
   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");\r
   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");\r
-  pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");\r
   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");\r
   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
-  pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
-#ifdef FAIRY\r
+  if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\r
+  pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+  pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+  pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+  } else {\r
+  pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
+  pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
+  pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
+  }\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
@@ -3125,43 +3107,46 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   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][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][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
+  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][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
+  pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
+  pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
+  if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
+  pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
+  pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
+  pieceBitmap[2][WhiteUnicorn] = 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[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
+  pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
+  pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+  pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
+  pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", 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][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][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[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", 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
+  pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+  pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+  pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "l", 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
+  if(gameInfo.variant != VariantCrazyhouse && gameInfo.variant != VariantShogi) {\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
@@ -3170,17 +3155,22 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   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
+  } else { /* other size, no special bitmaps available. Use smaller symbols */\r
+      if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;\r
+      else  minorSize = sizeInfo[(int)boardSize - 2].squareSize;\r
+  pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");\r
+  pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");\r
+  pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");\r
+  pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");\r
+  pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");\r
+  pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");\r
+  pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "s");\r
+  pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "o");\r
+  pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "w");\r
+  pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");\r
+  pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");\r
+  pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");\r
   }\r
-#endif\r
-\r
 }\r
 \r
 HBITMAP\r
@@ -3368,9 +3358,19 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
     BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,\r
           sqcolor ? SRCCOPY : NOTSRCCOPY);\r
   } else {\r
-    if (color) {\r
+    if(minorSize &&\r
+        (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||\r
+         piece >= (int)BlackNightrider && piece <= BlackGrasshopper)  ) {\r
+      /* [HGM] no bitmap available for promoted pieces in Crazyhouse        */\r
+      /* Bitmaps of smaller size are substituted, but we have to align them */\r
+      x += (squareSize - minorSize)>>1;\r
+      y += squareSize - minorSize - 2;\r
+    }\r
+    if (color || appData.allWhite ) {\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));\r
-      oldBrush = SelectObject(hdc, whitePieceBrush);\r
+      if( color )\r
+              oldBrush = SelectObject(hdc, whitePieceBrush);\r
+      else    oldBrush = SelectObject(hdc, blackPieceBrush);\r
       BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);\r
 #if 0\r
       /* Use black piece color for outline of white pieces */\r
@@ -4351,18 +4351,22 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     if (y == -2) {\r
       /* Downclick vertically off board; check if on clock */\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-       if (gameMode == EditPosition) {\r
+        if (gameMode == EditPosition) {\r
          SetWhiteToPlayEvent();\r
        } else if (gameMode == IcsPlayingBlack ||\r
                   gameMode == MachinePlaysWhite) {\r
          CallFlagEvent();\r
-       }\r
+        } else if (gameMode == EditGame) {\r
+          AdjustClock(flipClock, -1);\r
+        }\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
        if (gameMode == EditPosition) {\r
          SetBlackToPlayEvent();\r
        } else if (gameMode == IcsPlayingWhite ||\r
                   gameMode == MachinePlaysBlack) {\r
          CallFlagEvent();\r
+        } else if (gameMode == EditGame) {\r
+          AdjustClock(!flipClock, -1);\r
        }\r
       }\r
       if (!appData.highlightLastMove) {\r
@@ -4378,6 +4382,8 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
               || 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
+       /* EditPosition, empty square, or different color piece;\r
+          click-click move is possible */\r
                                ) {\r
       break;\r
     } else if (fromX == x && fromY == y) {\r
@@ -4390,37 +4396,29 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                                                                         ) {\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
-      if (gameMode == EditPosition || /* [HGM] max piece > King! */\r
-          !((WhitePawn <= pdown && pdown < BlackPawn &&\r
-             WhitePawn <= pup && pup < BlackPawn) ||\r
-            (BlackPawn <= pdown && pdown < EmptySquare &&\r
-             BlackPawn <= pup && pup < EmptySquare))) {\r
-       /* EditPosition, empty square, or different color piece;\r
-          click-click move is possible */\r
+      { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */\r
        toX = x;\r
        toY = y;\r
+        /* [HGM] <popupFix> UserMoveEvent requires two calls now,\r
+           to make sure move is legal before showing promotion popup */\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
+          /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */\r
+          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
+             (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
+              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
+          } else\r
+          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\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
@@ -4489,13 +4487,16 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       appData.animate = appData.animate && !appData.animateDragging;\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
+          /* [HGM] use move type to determine if move is promotion.\r
+             Knight is Shogi kludge for mandatory promotion, Queen means choice */\r
+          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
+             (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
+              appData.alwaysPromoteToQueen) \r
+               FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
+          else \r
+          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
+               DrawPosition(forceFullRepaint || FALSE, NULL);\r
+               PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
         } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
       }\r
       if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
@@ -4549,6 +4550,14 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     if (appData.highlightDragging) {\r
       ClearHighlights();\r
     }\r
+    if(y == -2) {\r
+      /* [HGM] right mouse button in clock area edit-game mode ups clock */\r
+      if (PtInRect((LPRECT) &whiteRect, pt)) {\r
+          if (gameMode == EditGame) AdjustClock(flipClock, 1);\r
+      } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
+          if (gameMode == EditGame) AdjustClock(!flipClock, 1);\r
+      }\r
+    }\r
     DrawPosition(TRUE, NULL);\r
 \r
     switch (gameMode) {\r
@@ -4577,7 +4586,10 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        /* Just have one menu, on the right button.  Windows users don't\r
           think to try the middle one, and sometimes other software steals\r
           it, or it doesn't really exist. */\r
-       MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
+        if(gameInfo.variant != VariantShogi)\r
+            MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
+        else\r
+            MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\r
 #endif\r
       }\r
       break;\r
@@ -4678,17 +4690,22 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
        gameInfo.variant == VariantGiveaway) ?\r
               SW_SHOW : SW_HIDE);\r
-#ifdef FAIRY\r
-    /* [HGM] Only allow C & A promotions in Capablanca Chess */\r
+    /* [HGM] Only allow C & A promotions if these pieces are defined */\r
     ShowWindow(GetDlgItem(hDlg, PB_Archbishop),\r
-      (gameInfo.variant == VariantCapablanca || \r
-       gameInfo.variant == VariantGothic) ?\r
+       (PieceToChar(WhiteCardinal) != '.' ||\r
+        PieceToChar(BlackCardinal) != '.'   ) ?\r
               SW_SHOW : SW_HIDE);\r
     ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
-      (gameInfo.variant == VariantCapablanca || \r
-       gameInfo.variant == VariantGothic) ?\r
+       (PieceToChar(WhiteMarshall) != '.' ||\r
+        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
-#endif\r
     return TRUE;\r
 \r
   case WM_COMMAND: /* message: received a command */\r
@@ -4699,27 +4716,25 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       DrawPosition(FALSE, NULL);\r
       return TRUE;\r
     case PB_King:\r
-      promoChar = 'k';\r
+      promoChar = PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = 'q';\r
+      promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);\r
       break;\r
     case PB_Rook:\r
-      promoChar = 'r';\r
+      promoChar = PieceToChar(BlackRook);\r
       break;\r
     case PB_Bishop:\r
-      promoChar = 'b';\r
+      promoChar = PieceToChar(BlackBishop);\r
       break;\r
-#ifdef FAIRY\r
     case PB_Chancellor:\r
-      promoChar = 'c';\r
+      promoChar = PieceToChar(BlackMarshall);\r
       break;\r
     case PB_Archbishop:\r
-      promoChar = 'a';\r
+      promoChar = PieceToChar(BlackCardinal);\r
       break;\r
-#endif\r
     case PB_Knight:\r
-      promoChar = 'n';\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);\r
       break;\r
     default:\r
       return FALSE;\r
@@ -5288,6 +5303,11 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       DrawPosition(FALSE, NULL);\r
       break;\r
 \r
+    case IDM_FlipClock:\r
+      flipClock = !flipClock;\r
+      DisplayBothClocks();\r
+      break;\r
+\r
     case IDM_GeneralOptions:\r
       GeneralOptionsPopup(hwnd);\r
       DrawPosition(TRUE, NULL);\r
@@ -5437,6 +5457,36 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case EP_WhiteFerz:\r
+      EditPositionMenuEvent(WhiteFerz, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteWazir:\r
+      EditPositionMenuEvent(WhiteWazir, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteAlfil:\r
+      EditPositionMenuEvent(WhiteAlfil, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteCannon:\r
+      EditPositionMenuEvent(WhiteCannon, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteCardinal:\r
+      EditPositionMenuEvent(WhiteCardinal, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteMarshall:\r
+      EditPositionMenuEvent(WhiteMarshall, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
     case EP_WhiteKing:\r
       EditPositionMenuEvent(WhiteKing, fromX, fromY);\r
       fromX = fromY = -1;\r
@@ -5467,6 +5517,36 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case EP_BlackFerz:\r
+      EditPositionMenuEvent(BlackFerz, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackWazir:\r
+      EditPositionMenuEvent(BlackWazir, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackAlfil:\r
+      EditPositionMenuEvent(BlackAlfil, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackCannon:\r
+      EditPositionMenuEvent(BlackCannon, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackCardinal:\r
+      EditPositionMenuEvent(BlackCardinal, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackMarshall:\r
+      EditPositionMenuEvent(BlackMarshall, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
     case EP_BlackKing:\r
       EditPositionMenuEvent(BlackKing, fromX, fromY);\r
       fromX = fromY = -1;\r
@@ -5492,6 +5572,16 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case EP_Promote:\r
+      EditPositionMenuEvent(PromotePiece, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_Demote:\r
+      EditPositionMenuEvent(DemotePiece, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
     case DP_Pawn:\r
       DropMenuEvent(WhitePawn, fromX, fromY);\r
       fromX = fromY = -1;\r
@@ -6626,6 +6716,8 @@ ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 }\r
 \r
 #ifdef GOTHIC\r
+HWND gothicDialog = NULL;\r
+\r
 LRESULT CALLBACK\r
 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
@@ -6646,7 +6738,7 @@ GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
         and it doesn't work when you resize the dialog.\r
         For now, just give it a default position.\r
     */\r
-\r
+    gothicDialog = hDlg;\r
     SetWindowText(hDlg, errorTitle);\r
     hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
     SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
@@ -6669,7 +6761,7 @@ GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 }\r
 \r
 VOID\r
-GothicPopUp(char *title)\r
+GothicPopUp(char *title, char up)\r
 {\r
   FARPROC lpProc;\r
   char *p, *q;\r
@@ -6677,11 +6769,16 @@ GothicPopUp(char *title)
 \r
   strncpy(errorTitle, title, sizeof(errorTitle));\r
   errorTitle[sizeof(errorTitle) - 1] = '\0';\r
-  \r
+\r
+  if(up && gothicDialog == NULL) {\r
     lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);\r
     CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),\r
                 hwndMain, (DLGPROC)lpProc);\r
     FreeProcInstance(lpProc);\r
+  } else if(!up && gothicDialog != NULL) {\r
+    DestroyWindow(gothicDialog);\r
+    gothicDialog = NULL;\r
+  }\r
 }\r
 #endif\r
 \r
@@ -8694,7 +8791,7 @@ DisplayWhiteClock(long timeRemaining, int highlight)
   char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
 \r
   if (!IsIconic(hwndMain)) {\r
-    DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White", flag);\r
+    DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);\r
   }\r
   if (highlight && iconCurrent == iconBlack) {\r
     iconCurrent = iconWhite;\r
@@ -8716,7 +8813,7 @@ DisplayBlackClock(long timeRemaining, int highlight)
 \r
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
-    DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black", flag);\r
+    DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);\r
   }\r
   if (highlight && iconCurrent == iconWhite) {\r
     iconCurrent = iconBlack;\r