fixed different use of engine option compared to Polyglot
[xboard.git] / winboard / winboard.c
index fb64ff7..7d8c272 100644 (file)
@@ -2,8 +2,10 @@
  * WinBoard.c -- Windows NT front end to XBoard\r
  * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $\r
  *\r
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
- * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.\r
+ * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
+ * Massachusetts.  Enhancements Copyright\r
+ * 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
  * SOFTWARE.\r
  * ------------------------------------------------------------------------\r
  *\r
- * The following terms apply to the enhanced version of XBoard distributed\r
- * by the Free Software Foundation:\r
+ * The following terms apply to the enhanced version of XBoard\r
+ * distributed by the Free Software Foundation:\r
  * ------------------------------------------------------------------------\r
- * This program is free software; you can redistribute it and/or modify\r
+ *\r
+ * GNU XBoard is free software: you can redistribute it and/or modify\r
  * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
+ * the Free Software Foundation, either version 3 of the License, or (at\r
+ * your option) any later version.\r
  *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
+ * GNU XBoard is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
  *\r
  * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- * ------------------------------------------------------------------------\r
- */\r
+ * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
+ *\r
+ *------------------------------------------------------------------------\r
+ ** See the file ChangeLog for a revision history.  */\r
 \r
 #include "config.h"\r
 \r
 #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
@@ -1162,8 +1184,10 @@ ArgDescriptor argDescriptors[] = {
   { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
   { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
   { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+  { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
   { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
   { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+  { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
   { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
   { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
   { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
@@ -1218,6 +1242,8 @@ ArgDescriptor argDescriptors[] = {
   { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
   { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
   { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
+  { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
+  { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
 \r
 #ifdef ZIPPY\r
   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
@@ -1397,6 +1423,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
@@ -1410,8 +1437,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
@@ -1662,6 +1695,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
@@ -1835,6 +1870,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
@@ -1849,12 +1885,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
@@ -1936,6 +1966,8 @@ InitAppData(LPSTR lpCmdLine)
   appData.defaultHashSize = 64;\r
   appData.defaultCacheSizeEGTB = 4;\r
   appData.defaultPathEGTB = "c:\\egtb";\r
+  appData.firstOptions = "";\r
+  appData.secondOptions = "";\r
 \r
   InitWindowPlacement( &wpMoveHistory );\r
   InitWindowPlacement( &wpEvalGraph );\r
@@ -2271,14 +2303,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
@@ -2316,6 +2348,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
@@ -2986,7 +3020,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
@@ -3017,8 +3051,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
@@ -3045,7 +3079,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
@@ -3148,6 +3185,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
@@ -3239,7 +3277,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
@@ -3659,8 +3696,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
@@ -4196,9 +4233,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
@@ -4444,14 +4481,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
       x2 = boardRect.left + animInfo.pos.x;\r
       y2 = boardRect.top + animInfo.pos.y;\r
       clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);\r
-      /* Slight kludge.  The real problem is that after AnimateMove is\r
-        done, the position on the screen does not match lastDrawn.\r
-        This currently causes trouble only on e.p. captures in\r
-        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
-      lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
+      /* [HGM] old location of "slight kludge" below */\r
     }\r
   }\r
 \r
@@ -4469,10 +4499,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
@@ -4511,6 +4558,14 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     DrawPieceOnDC(hdcmem, animInfo.piece,\r
                  ((int) animInfo.piece < (int) BlackPawn),\r
                   (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);\r
+      /* Slight kludge.  The real problem is that after AnimateMove is\r
+        done, the position on the screen does not match lastDrawn.\r
+        This currently causes trouble only on e.p. captures in\r
+        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. [HGM] moved until after setting lastDrawn */\r
+      lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;\r
   }\r
 \r
   /* Release the bufferBitmap by selecting in the old bitmap \r
@@ -4537,7 +4592,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
@@ -4581,7 +4636,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
@@ -4641,9 +4696,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
@@ -4668,7 +4720,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
@@ -4761,7 +4813,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
@@ -4836,7 +4888,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
@@ -4845,8 +4897,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
@@ -4876,8 +4928,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
@@ -4982,8 +5034,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
@@ -5000,7 +5052,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
@@ -5042,15 +5098,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
@@ -5206,16 +5266,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
@@ -6765,7 +6825,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
@@ -7391,8 +7451,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
@@ -7473,7 +7531,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
@@ -7916,8 +7974,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
@@ -8282,7 +8340,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
@@ -8331,7 +8389,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
@@ -8845,7 +8903,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
@@ -9213,7 +9271,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
@@ -9764,7 +9822,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
@@ -9774,7 +9832,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
@@ -10528,6 +10586,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
@@ -10588,6 +10662,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