added option for work-around for some FRC engines in regards to FRCFENs
[xboard.git] / winboard / winboard.c
index 1e88dfb..fb317b7 100644 (file)
@@ -7,6 +7,9 @@
  * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software\r
  * Foundation, Inc.\r
  *\r
+ * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
+ * which was written and is copyrighted by Wayne Christopher.\r
+ *\r
  * The following terms apply to Digital Equipment Corporation's copyright\r
  * interest in XBoard:\r
  * ------------------------------------------------------------------------\r
@@ -54,6 +57,7 @@
 #include <windows.h>\r
 #include <winuser.h>\r
 #include <winsock.h>\r
+#include <commctrl.h>\r
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
@@ -66,6 +70,7 @@
 #include <dlgs.h>\r
 #include <richedit.h>\r
 #include <mmsystem.h>\r
+#include <ctype.h>\r
 \r
 #if __GNUC__\r
 #include <errno.h>\r
@@ -95,6 +100,10 @@ extern int whiteFlag, blackFlag;
 Boolean flipClock = FALSE;\r
 \r
 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
+VOID NewVariantPopup(HWND hwnd);\r
+int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
+                  /*char*/int promoChar));\r
+void AnimateAtomicCapture(int toX, int toY, int nFrames);\r
 \r
 typedef struct {\r
   ChessSquare piece;  \r
@@ -122,6 +131,12 @@ typedef struct {
 static HighlightInfo highlightInfo        = { {{-1, -1}, {-1, -1}} };\r
 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
 \r
+typedef struct { // [HGM] atomic\r
+  int x, y, radius;\r
+} ExplodeInfo;\r
+\r
+static ExplodeInfo explodeInfo = {0, 0, 0};\r
+\r
 /* Window class names */\r
 char szAppName[] = "WinBoard";\r
 char szConsoleName[] = "WBConsole";\r
@@ -173,7 +188,8 @@ static HWND hwndPause;    /* pause button */
 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
+  explodeBrush,     /* [HGM] atomic */\r
+  whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
 static HPEN gridPen = NULL;\r
@@ -243,7 +259,7 @@ SizeInfo sizeInfo[] =
   { NULL, 0, 0, 0, 0, 0, 0 }\r
 };\r
 \r
-#define MF(x) {x, {0, }, {0, }, 0}\r
+#define MF(x) {x, {{0,}, 0. }, {0, }, 0}\r
 MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
 {\r
   { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },\r
@@ -474,6 +490,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 {\r
   MSG msg;\r
   HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
+//  INITCOMMONCONTROLSEX ex;\r
 \r
   debugFP = stderr;\r
 \r
@@ -487,6 +504,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
     return (FALSE);\r
   }\r
 \r
+//  InitCommonControlsEx(&ex);\r
+  InitCommonControls();\r
+\r
   hAccelMain = LoadAccelerators (hInstance, szAppName);\r
   hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");\r
   hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */\r
@@ -567,12 +587,14 @@ int screenHeight, screenWidth;
 void\r
 EnsureOnScreen(int *x, int *y)\r
 {\r
-  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
+//  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
   if (*x > screenWidth - 32) *x = 0;\r
   if (*y > screenHeight - 32) *y = 0;\r
-  if (*x < 10) *x = 10;\r
-  if (*y < gap) *y = gap;\r
+  if (*x < 0) *x = 0;\r
+  if (*y < 0) *y = 0;\r
+//  if (*x < 10) *x = 10;\r
+//  if (*y < gap) *y = gap;\r
 }\r
 \r
 BOOL\r
@@ -1222,6 +1244,8 @@ ArgDescriptor argDescriptors[] = {
   { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
   { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
   { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
+  { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
+  { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
 \r
 #ifdef ZIPPY\r
   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
@@ -1401,6 +1425,7 @@ FileGet(void *getClosure)
   FILE* f = (FILE*) getClosure;\r
 \r
   c = getc(f);\r
+  if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
   if (c == EOF)\r
     return NULLCHAR;\r
   else\r
@@ -1414,8 +1439,14 @@ ParseSettingsFile(char *name, char fullname[MSG_SIZ])
 {\r
   char *dummy;\r
   FILE *f;\r
+  int ok; char buf[MSG_SIZ];\r
 \r
-  if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {\r
+  ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
+  if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
+    sprintf(buf, "%s.ini", name);\r
+    ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
+  }\r
+  if (ok) {\r
     f = fopen(fullname, "r");\r
     if (f != NULL) {\r
       ParseArgs(FileGet, f);\r
@@ -1666,6 +1697,8 @@ ParseArgs(GetFunc get, void *cl)
     case ArgNone:\r
       ExitArgError("Unrecognized argument", argValue);\r
       break;\r
+    case ArgTrue:\r
+    case ArgFalse: ;\r
     }\r
   }\r
 }\r
@@ -1839,6 +1872,7 @@ InitAppData(LPSTR lpCmdLine)
   appData.reuseSecond = TRUE;\r
   appData.blindfold = FALSE;\r
   appData.icsEngineAnalyze = FALSE;\r
+  memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
   dcb.DCBlength = sizeof(DCB);\r
   dcb.BaudRate = 9600;\r
   dcb.fBinary = TRUE;\r
@@ -1853,12 +1887,6 @@ InitAppData(LPSTR lpCmdLine)
   dcb.fNull = FALSE;\r
   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
   dcb.fAbortOnError = FALSE;\r
-  /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */\r
-  #if (defined(_MSC_VER) && _MSC_VER <= 1200) \r
-       //dcb.wReserved = 0;\r
-  #else\r
-    dcb.wReserved = 0;\r
-  #endif\r
   dcb.ByteSize = 7;\r
   dcb.Parity = SPACEPARITY;\r
   dcb.StopBits = ONESTOPBIT;\r
@@ -2277,14 +2305,14 @@ SaveSettings(char* name)
     case ArgColor:\r
       {\r
        COLORREF color = *(COLORREF *)ad->argLoc;\r
-       fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName, \r
+       fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
          color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
       }\r
       break;\r
     case ArgAttribs:\r
       {\r
        MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
-       fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,\r
+       fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
           (ta->effects & CFE_BOLD) ? "b" : "",\r
           (ta->effects & CFE_ITALIC) ? "i" : "",\r
           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
@@ -2322,6 +2350,8 @@ SaveSettings(char* name)
       break;\r
     case ArgCommSettings:\r
       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
+    case ArgNone:\r
+    case ArgSettingsFilename: ;\r
     }\r
   }\r
   fclose(f);\r
@@ -2992,7 +3022,7 @@ InitDrawingColors()
   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
-\r
+  explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
   /* [AS] Force rendering of the font-based pieces */\r
   if( fontBitmapSquareSize > 0 ) {\r
     fontBitmapSquareSize = 0;\r
@@ -3023,8 +3053,8 @@ ResizeBoard(int newSizeX, int newSizeY, int flags)
   if (recurse > 0) return;\r
   recurse++;\r
   while (newSize > 0) {\r
-       InitDrawingSizes(newSize, 0);\r
-       if(newSizeX >= sizeInfo[newSize].cliWidth ||\r
+       InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
+       if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
           newSizeY >= sizeInfo[newSize].cliHeight) break;\r
     newSize--;\r
   } \r
@@ -3051,7 +3081,10 @@ 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
+  int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only\r
+  if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }\r
+\r
+  /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */\r
   if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
 \r
   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
@@ -3154,6 +3187,7 @@ InitDrawingSizes(BoardSize boardSize, int flags)
 \r
   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
+  if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only\r
   winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;\r
   winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +\r
     GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;\r
@@ -3245,7 +3279,6 @@ InitDrawingSizes(BoardSize boardSize, int flags)
        boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
         BOARD_WIDTH * (squareSize + lineGap);\r
-       lineGap / 2 + (i * (squareSize + lineGap));\r
       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
     }\r
     for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
@@ -3665,8 +3698,8 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
   } else {\r
     tmpSize = squareSize;\r
     if(minorSize &&\r
-        (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||\r
-         piece >= (int)BlackNightrider && piece <= BlackGrasshopper)  ) {\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
@@ -4202,9 +4235,9 @@ void fputDW(FILE *f, int x)
 VOID\r
 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)\r
 {\r
-  HBITMAP bufferBitmap;\r
+//  HBITMAP bufferBitmap;\r
   BITMAP bi;\r
-  RECT Rect;\r
+//  RECT Rect;\r
   HDC tmphdc;\r
   HBITMAP hbm;\r
   int w = 100, h = 50;\r
@@ -4456,7 +4489,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         atomic, where the piece moves to an empty square and then\r
         explodes.  The old and new positions both had an empty square\r
         at the destination, but animation has drawn a piece there and\r
-        we have to remember to erase it. */\r
+        we have to remember to erase it. [HGM] moved until after setting lastDrawn */\r
       lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
     }\r
   }\r
@@ -4475,10 +4508,27 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   }\r
 \r
   /* Do all the drawing to the memory DC */\r
-  DrawGridOnDC(hdcmem);\r
-  DrawHighlightsOnDC(hdcmem);\r
-  DrawBoardOnDC(hdcmem, board, tmphdc);\r
-\r
+  if(explodeInfo.radius) { // [HGM] atomic\r
+       HBRUSH oldBrush;\r
+       int x, y, r=(explodeInfo.radius * squareSize)/100;\r
+       SquareToPos(explodeInfo.y, explodeInfo.x, &x, &y);\r
+       x += squareSize/2;\r
+       y += squareSize/2;\r
+        if(!fullrepaint) {\r
+         clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);\r
+         ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);\r
+       }\r
+       DrawGridOnDC(hdcmem);\r
+       DrawHighlightsOnDC(hdcmem);\r
+       DrawBoardOnDC(hdcmem, board, tmphdc);\r
+       oldBrush = SelectObject(hdcmem, explodeBrush);\r
+       Ellipse(hdcmem, x-r, y-r, x+r, y+r);\r
+       SelectObject(hdcmem, oldBrush);\r
+  } else {\r
+    DrawGridOnDC(hdcmem);\r
+    DrawHighlightsOnDC(hdcmem);\r
+    DrawBoardOnDC(hdcmem, board, tmphdc);\r
+  }\r
   if(logoHeight) {\r
        DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);\r
        DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);\r
@@ -4543,7 +4593,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         boardRect.bottom - boardRect.top,\r
         tmphdc, boardRect.left, boardRect.top, SRCCOPY);\r
   if(saveDiagFlag) { \r
-    BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000]; \r
+    BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000]; \r
     BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
 \r
     GetObject(bufferBitmap, sizeof(b), &b);\r
@@ -4587,7 +4637,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
                    while(p&3) pData[p++] = 0;\r
                }\r
                fac = 3;\r
-               wb = (wb+31>>5)<<2;\r
+               wb = ((wb+31)>>5)<<2;\r
        }\r
        // write BITMAPFILEHEADER\r
        fprintf(diagFile, "BM");\r
@@ -4647,9 +4697,6 @@ int
 SaveDiagram(f)\r
      FILE *f;\r
 {\r
-    time_t tm;\r
-    char *fen;\r
-\r
     saveDiagFlag = 1; diagFile = f;\r
     HDCDrawPosition(NULL, TRUE, NULL);\r
 \r
@@ -4674,7 +4721,7 @@ PaintProc(HWND hwnd)
   PAINTSTRUCT ps;\r
   HFONT       oldFont;\r
 \r
-  if(hdc = BeginPaint(hwnd, &ps)) {\r
+  if((hdc = BeginPaint(hwnd, &ps))) {\r
     if (IsIconic(hwnd)) {\r
       DrawIcon(hdc, 2, 2, iconCurrent);\r
     } else {\r
@@ -4767,7 +4814,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   POINT pt;\r
   static int recursive = 0;\r
   HMENU hmenu;\r
-  BOOLEAN needsRedraw = FALSE;\r
+//  BOOLEAN needsRedraw = FALSE;\r
   BOOLEAN saveAnimate;\r
   BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
   static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;\r
@@ -4842,7 +4889,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
       if (!appData.highlightLastMove) {\r
         ClearHighlights();\r
-       DrawPosition(forceFullRepaint || FALSE, NULL);\r
+       DrawPosition((int) (forceFullRepaint || FALSE), NULL);\r
       }\r
       fromX = fromY = -1;\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
@@ -4851,8 +4898,8 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     } 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
+              || (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
@@ -4882,8 +4929,8 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         if(moveType != ImpossibleMove) {\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
+            ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
+              appData.alwaysPromoteToQueen)) {\r
                   FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
                   if (!appData.highlightLastMove) {\r
                       ClearHighlights();\r
@@ -4988,8 +5035,8 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
           /* [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
+            ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
+              appData.alwaysPromoteToQueen)) \r
                FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
           else \r
           if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
@@ -5006,7 +5053,11 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                    break;\r
                  } else\r
                PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
-        } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
+          } else {\r
+           if(saveAnimate /* ^$!%@#$!$ */  && gameInfo.variant == VariantAtomic \r
+                       && boards[currentMove][toY][toX] != EmptySquare) AnimateAtomicCapture(toX, toY, 20);\r
+           FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
+         }\r
       }\r
       if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
       appData.animate = saveAnimate;\r
@@ -5048,15 +5099,19 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     break;\r
 \r
   case WM_MOUSEWHEEL: // [DM]\r
+    {  static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events\r
        /* Mouse Wheel is being rolled forward\r
         * Play moves forward\r
         */\r
-       if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) ForwardEvent();\r
+       if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) \r
+               { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction\r
        /* Mouse Wheel is being rolled backward\r
         * Play moves backward\r
         */\r
-       if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) BackwardEvent();\r
-       break;\r
+       if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) \r
+               { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }\r
+    }\r
+    break;\r
 \r
   case WM_MBUTTONDOWN:\r
   case WM_RBUTTONDOWN:\r
@@ -5212,16 +5267,16 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
               SW_SHOW : SW_HIDE);\r
     /* [HGM] Only allow C & A promotions if these pieces are defined */\r
     ShowWindow(GetDlgItem(hDlg, PB_Archbishop),\r
-       (PieceToChar(WhiteAngel) >= 'A' &&\r
-        PieceToChar(WhiteAngel) != '~' ||\r
-        PieceToChar(BlackAngel) >= 'A' &&\r
-        PieceToChar(BlackAngel) != '~'   ) ?\r
+       ((PieceToChar(WhiteAngel) >= 'A' &&\r
+         PieceToChar(WhiteAngel) != '~') ||\r
+        (PieceToChar(BlackAngel) >= 'A' &&\r
+         PieceToChar(BlackAngel) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
     ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
-       (PieceToChar(WhiteMarshall) >= 'A' &&\r
-        PieceToChar(WhiteMarshall) != '~' ||\r
-        PieceToChar(BlackMarshall) >= 'A' &&\r
-        PieceToChar(BlackMarshall) != '~'   ) ?\r
+       ((PieceToChar(WhiteMarshall) >= 'A' &&\r
+         PieceToChar(WhiteMarshall) != '~') ||\r
+        (PieceToChar(BlackMarshall) >= 'A' &&\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
@@ -6222,6 +6277,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
   /* [AS] Also move "attached" child windows */\r
   case WM_WINDOWPOSCHANGING:\r
+\r
     if( hwnd == hwndMain && appData.useStickyWindows ) {\r
         LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;\r
 \r
@@ -6229,11 +6285,17 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             /* Window is moving */\r
             RECT rcMain;\r
 \r
-            GetWindowRect( hwnd, &rcMain );\r
+//            GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old\r
+           rcMain.left   = boardX;           //              replace by these 4 lines to reconstruct old rect\r
+           rcMain.right  = boardX + winWidth;\r
+           rcMain.top    = boardY;\r
+           rcMain.bottom = boardY + winHeight;\r
             \r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );\r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );\r
             ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );\r
+           boardX = lpwp->x;\r
+            boardY = lpwp->y;\r
         }\r
     }\r
     break;\r
@@ -6771,7 +6833,7 @@ SetStartupDialogEnables(HWND hDlg)
 {\r
   EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),\r
     IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||\r
-    appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));\r
+    (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));\r
   EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),\r
     IsDlgButtonChecked(hDlg, OPT_ChessEngine));\r
   EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),\r
@@ -7397,8 +7459,6 @@ VOID
 GothicPopUp(char *title, VariantClass variant)\r
 {\r
   FARPROC lpProc;\r
-  char *p, *q;\r
-  BOOLEAN modal = hwndMain == NULL;\r
   static char *lastTitle;\r
 \r
   strncpy(errorTitle, title, sizeof(errorTitle));\r
@@ -7479,7 +7539,7 @@ IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
 void\r
 ParseIcsTextMenu(char *icsTextMenuString)\r
 {\r
-  int flags = 0;\r
+//  int flags = 0;\r
   IcsTextMenuEntry *e = icsTextMenuEntry;\r
   char *p = icsTextMenuString;\r
   while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {\r
@@ -7922,8 +7982,8 @@ LRESULT CALLBACK
 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
   static SnapData sd;\r
-  static HWND hText, hInput, hFocus;\r
-  InputSource *is = consoleInputSource;\r
+  static HWND hText, hInput /*, hFocus*/;\r
+//  InputSource *is = consoleInputSource;\r
   RECT rect;\r
   static int sizeX, sizeY;\r
   int newSizeX, newSizeY;\r
@@ -8288,7 +8348,7 @@ void CheckForInputBufferFull( InputSource * is )
 \r
         if( p >= is->next ) {\r
             if (appData.debugMode) {\r
-                fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );\r
+                fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );\r
             }\r
 \r
             is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */\r
@@ -8337,7 +8397,7 @@ InputThread(LPVOID arg)
   CloseHandle(is->hFile);\r
 \r
   if (appData.debugMode) {\r
-    fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );\r
+    fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );\r
   }\r
 \r
   return 0;\r
@@ -8851,7 +8911,7 @@ DisplayMessage(char *str1, char *str2)
   }\r
   messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;\r
 \r
-  if (IsIconic(hwndMain)) return;\r
+  if (hwndMain == NULL || IsIconic(hwndMain)) return;\r
   hdc = GetDC(hwndMain);\r
   oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);\r
   ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,\r
@@ -9219,7 +9279,7 @@ LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LP
             {\r
                 char * pc = lpUserGLT;\r
                 int idx = 0;\r
-                int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
+//                int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
                 char id;\r
 \r
                 do {\r
@@ -9770,7 +9830,7 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
         result = TerminateProcess( cp->hProcess, 0 );\r
 \r
         if ( appData.debugMode) {\r
-            fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );\r
+            fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );\r
         }\r
     }\r
     else if( signal == 10 ) {\r
@@ -9780,7 +9840,7 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
             result = TerminateProcess( cp->hProcess, 0 );\r
 \r
             if ( appData.debugMode) {\r
-                fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );\r
+                fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );\r
             }\r
 \r
         }\r
@@ -10534,6 +10594,22 @@ static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
      POINT frames[], int * nFrames);\r
 \r
 \r
+void\r
+AnimateAtomicCapture(int toX, int toY, int nFrames)\r
+{      // [HGM] atomic: animate blast wave\r
+       int i;\r
+if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);\r
+       explodeInfo.x = toX;\r
+       explodeInfo.y = toY;\r
+       for(i=0; i<nFrames; i++) {\r
+           explodeInfo.radius = (i*180)/(nFrames-1);\r
+           DrawPosition(FALSE, NULL);\r
+           Sleep(appData.animSpeed);\r
+       }\r
+       explodeInfo.radius = 0;\r
+       DrawPosition(TRUE, NULL);\r
+}\r
+\r
 #define kFactor 4\r
 \r
 void\r
@@ -10594,6 +10670,8 @@ AnimateMove(board, fromX, fromY, toX, toY)
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
   animInfo.piece = EmptySquare;\r
+  if(gameInfo.variant == VariantAtomic && board[toY][toX] != EmptySquare)\r
+    AnimateAtomicCapture(toX, toY, 2*nFrames);\r
 }\r
 \r
 /*      Convert board position to corner of screen rect and color       */\r