Alter assignment method for castling rights in EditPosition
[xboard.git] / backend.c
index 65fc44b..35cc84d 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -126,15 +126,15 @@ extern int gettimeofday(struct timeval *, struct timezone *);
 # include "zippy.h"
 #endif
 #include "backendz.h"
-#include "gettext.h" 
-#ifdef ENABLE_NLS 
-# define _(s) gettext (s) 
-# define N_(s) gettext_noop (s) 
-#else 
-# define _(s) (s) 
-# define N_(s) s 
-#endif 
+#include "gettext.h"
+
+#ifdef ENABLE_NLS
+# define _(s) gettext (s)
+# define N_(s) gettext_noop (s)
+#else
+# define _(s) (s)
+# define N_(s) s
+#endif
 
 
 /* A point in time */
@@ -167,6 +167,7 @@ int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
                   /*char*/int promoChar));
 void BackwardInner P((int target));
 void ForwardInner P((int target));
+int Adjudicate P((ChessProgramState *cps));
 void GameEnds P((ChessMove result, char *resultDetails, int whosays));
 void EditPositionDone P((Boolean fakeRights));
 void PrintOpponents P((FILE *fp));
@@ -241,6 +242,7 @@ int endPV = -1;
 static int exiting = 0; /* [HGM] moved to top */
 static int setboardSpoiledMachineBlack = 0 /*, errorExitFlag = 0*/;
 int startedFromPositionFile = FALSE; Board filePosition;       /* [HGM] loadPos */
+int rightsBoard[BOARD_RANKS][BOARD_FILES];                  /* [HGM] editrights */
 char endingGame = 0;    /* [HGM] crash: flag to prevent recursion of GameEnds() */
 int whiteNPS, blackNPS; /* [HGM] nps: for easily making clocks aware of NPS     */
 VariantClass currentlyInitializedVariant; /* [HGM] variantswitch */
@@ -352,7 +354,7 @@ PosFlags(index)
   case VariantKriegspiel:
     flags |= F_KRIEGSPIEL_CAPTURE;
     break;
-  case VariantCapaRandom: 
+  case VariantCapaRandom:
   case VariantFischeRandom:
     flags |= F_FRC_TYPE_CASTLING; /* [HGM] enable this through flag */
   case VariantNoCastle:
@@ -369,7 +371,7 @@ PosFlags(index)
 
 FILE *gameFileFP, *debugFP;
 
-/* 
+/*
     [AS] Note: sometimes, the sscanf() function is used to parse the input
     into a fixed-size buffer. Because of this, we must be prepared to
     receive strings as long as the size of the input buffer, which is currently
@@ -452,7 +454,7 @@ signed char  initialRights[BOARD_FILES];
 int   nrCastlingRights; // For TwoKings, or to implement castling-unknown status
 int   initialRulePlies, FENrulePlies;
 FILE  *serverMoves = NULL; // next two for broadcasting (/serverMoves option)
-int loadFlag = 0; 
+int loadFlag = 0;
 int shuffleOpenings;
 int mute; // mute all sounds
 
@@ -529,31 +531,31 @@ ChessSquare XiangqiArray[2][BOARD_FILES] = {
 };
 
 ChessSquare CapablancaArray[2][BOARD_FILES] = {
-    { WhiteRook, WhiteKnight, WhiteAngel, WhiteBishop, WhiteQueen, 
+    { WhiteRook, WhiteKnight, WhiteAngel, WhiteBishop, WhiteQueen,
         WhiteKing, WhiteBishop, WhiteMarshall, WhiteKnight, WhiteRook },
-    { BlackRook, BlackKnight, BlackAngel, BlackBishop, BlackQueen, 
+    { BlackRook, BlackKnight, BlackAngel, BlackBishop, BlackQueen,
         BlackKing, BlackBishop, BlackMarshall, BlackKnight, BlackRook }
 };
 
 ChessSquare GreatArray[2][BOARD_FILES] = {
-    { WhiteDragon, WhiteKnight, WhiteAlfil, WhiteGrasshopper, WhiteKing, 
+    { WhiteDragon, WhiteKnight, WhiteAlfil, WhiteGrasshopper, WhiteKing,
         WhiteSilver, WhiteCardinal, WhiteAlfil, WhiteKnight, WhiteDragon },
-    { BlackDragon, BlackKnight, BlackAlfil, BlackGrasshopper, BlackKing, 
+    { BlackDragon, BlackKnight, BlackAlfil, BlackGrasshopper, BlackKing,
         BlackSilver, BlackCardinal, BlackAlfil, BlackKnight, BlackDragon },
 };
 
 ChessSquare JanusArray[2][BOARD_FILES] = {
-    { WhiteRook, WhiteAngel, WhiteKnight, WhiteBishop, WhiteKing, 
+    { WhiteRook, WhiteAngel, WhiteKnight, WhiteBishop, WhiteKing,
         WhiteQueen, WhiteBishop, WhiteKnight, WhiteAngel, WhiteRook },
-    { BlackRook, BlackAngel, BlackKnight, BlackBishop, BlackKing, 
+    { BlackRook, BlackAngel, BlackKnight, BlackBishop, BlackKing,
         BlackQueen, BlackBishop, BlackKnight, BlackAngel, BlackRook }
 };
 
 #ifdef GOTHIC
 ChessSquare GothicArray[2][BOARD_FILES] = {
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall, 
+    { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall,
         WhiteKing, WhiteAngel, WhiteBishop, WhiteKnight, WhiteRook },
-    { BlackRook, BlackKnight, BlackBishop, BlackQueen, BlackMarshall, 
+    { BlackRook, BlackKnight, BlackBishop, BlackQueen, BlackMarshall,
         BlackKing, BlackAngel, BlackBishop, BlackKnight, BlackRook }
 };
 #else // !GOTHIC
@@ -562,9 +564,9 @@ ChessSquare GothicArray[2][BOARD_FILES] = {
 
 #ifdef FALCON
 ChessSquare FalconArray[2][BOARD_FILES] = {
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen, 
+    { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen,
         WhiteKing, WhiteLance, WhiteBishop, WhiteKnight, WhiteRook },
-    { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen, 
+    { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen,
         BlackKing, BlackLance, BlackBishop, BlackKnight, BlackRook }
 };
 #else // !FALCON
@@ -649,7 +651,7 @@ InitBackEnd1()
     if (appData.icsActive) {
        appData.matchMode = FALSE;
        appData.matchGames = 0;
-#if ZIPPY      
+#if ZIPPY
        appData.noChessProgram = !appData.zippyPlay;
 #else
        appData.zippyPlay = FALSE;
@@ -703,7 +705,7 @@ InitBackEnd1()
 
     /* [AS] Adjudication threshold */
     adjudicateLossThreshold = appData.adjudicateLossThreshold;
-    
+
     first.which = "first";
     second.which = "second";
     first.maybeThinking = second.maybeThinking = FALSE;
@@ -823,7 +825,7 @@ InitBackEnd1()
        appData.clockMode = FALSE;
        first.sendTime = second.sendTime = 0;
     }
-    
+
 #if ZIPPY
     /* Override some settings from environment variables, for backward
        compatibility.  Unfortunately it's not feasible to have the env
@@ -833,7 +835,7 @@ InitBackEnd1()
       ZippyInit();
     }
 #endif
-    
+
     if (appData.noChessProgram) {
        programVersion = (char*) malloc(5 + strlen(PACKAGE_STRING));
        sprintf(programVersion, "%s", PACKAGE_STRING);
@@ -969,7 +971,7 @@ int NextSessionFromString( char ** str, int *moves, long * tc, long *inc)
             if(result = NextIntegerFromString( str, &temp2)) return -1;
             *inc = temp2 * 1000;
         } else *inc = 0;
-        *moves = 0; *tc = temp * 1000; 
+        *moves = 0; *tc = temp * 1000;
         return 0;
     } else if(temp % 60 != 0) return -1;     /* moves was given as min:sec */
 
@@ -1064,60 +1066,62 @@ ParseTimeControl(tc, ti, mps)
 void
 InitBackEnd2()
 {
-    if (appData.debugMode) {
-       fprintf(debugFP, "%s\n", programVersion);
-    }
+  if (appData.debugMode) {
+    fprintf(debugFP, "%s\n", programVersion);
+  }
 
-    set_cont_sequence(appData.wrapContSeq);
-    if (appData.matchGames > 0) {
-       appData.matchMode = TRUE;
-    } else if (appData.matchMode) {
-       appData.matchGames = 1;
-    }
-    if(appData.matchMode && appData.sameColorGames > 0) /* [HGM] alternate: overrule matchGames */
-       appData.matchGames = appData.sameColorGames;
-    if(appData.rewindIndex > 1) { /* [HGM] autoinc: rewind implies auto-increment and overrules given index */
-       if(appData.loadPositionIndex >= 0) appData.loadPositionIndex = -1;
-       if(appData.loadGameIndex >= 0) appData.loadGameIndex = -1;
-    }
-    Reset(TRUE, FALSE);
-    if (appData.noChessProgram || first.protocolVersion == 1) {
-      InitBackEnd3();
+  set_cont_sequence(appData.wrapContSeq);
+  if (appData.matchGames > 0) {
+    appData.matchMode = TRUE;
+  } else if (appData.matchMode) {
+    appData.matchGames = 1;
+  }
+  if(appData.matchMode && appData.sameColorGames > 0) /* [HGM] alternate: overrule matchGames */
+    appData.matchGames = appData.sameColorGames;
+  if(appData.rewindIndex > 1) { /* [HGM] autoinc: rewind implies auto-increment and overrules given index */
+    if(appData.loadPositionIndex >= 0) appData.loadPositionIndex = -1;
+    if(appData.loadGameIndex >= 0) appData.loadGameIndex = -1;
+  }
+  Reset(TRUE, FALSE);
+  if (appData.noChessProgram || first.protocolVersion == 1) {
+    InitBackEnd3();
     } else {
-      /* kludge: allow timeout for initial "feature" commands */
-      FreezeUI();
-      DisplayMessage("", _("Starting chess program"));
-      ScheduleDelayedEvent(InitBackEnd3, FEATURE_TIMEOUT);
-    }
+    /* kludge: allow timeout for initial "feature" commands */
+    FreezeUI();
+    DisplayMessage("", _("Starting chess program"));
+    ScheduleDelayedEvent(InitBackEnd3, FEATURE_TIMEOUT);
+  }
 }
 
 void
 InitBackEnd3 P((void))
 {
-    GameMode initialMode;
-    char buf[MSG_SIZ];
-    int err;
-
-    InitChessProgram(&first, startedFromSetupPosition);
-
-
-    if (appData.icsActive) {
-#ifdef WIN32
-        /* [DM] Make a console window if needed [HGM] merged ifs */
-        ConsoleCreate(); 
-#endif
-       err = establish();
-       if (err != 0) {
-           if (*appData.icsCommPort != NULLCHAR) {
-               sprintf(buf, _("Could not open comm port %s"),  
-                       appData.icsCommPort);
-           } else {
-               snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),  
-                       appData.icsHost, appData.icsPort);
-           }
-           DisplayFatalError(buf, err, 1);
-           return;
+  GameMode initialMode;
+  char buf[MSG_SIZ];
+  int err;
+  
+  InitChessProgram(&first, startedFromSetupPosition);
+  
+  
+  if (appData.icsActive) 
+    {
+      err = establish();
+      if (err != 0) 
+       {
+         if (*appData.icsCommPort != NULLCHAR) 
+           {
+             sprintf(buf, _("Could not open comm port %s"),
+                     appData.icsCommPort);
+           }
+         else 
+           {
+             snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"),
+                      appData.icsHost, appData.icsPort);
+           }
+         DisplayFatalError(buf, err, 1);
+         return;
        }
+
        SetICSMode();
        telnetISR =
          AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
@@ -1125,169 +1129,237 @@ InitBackEnd3 P((void))
          AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
        if(appData.keepAlive) // [HGM] alive: schedule sending of dummy 'date' command
            ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000);
-    } else if (appData.noChessProgram) {
-       SetNCPMode();
-    } else {
-       SetGNUMode();
     }
-
-    if (*appData.cmailGameName != NULLCHAR) {
-       SetCmailMode();
-       OpenLoopback(&cmailPR);
-       cmailISR =
-         AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
+  else if (appData.noChessProgram) 
+    {
+      SetNCPMode();
+    } 
+  else 
+    {
+      SetGNUMode();
     }
-    
-    ThawUI();
-    DisplayMessage("", "");
-    if (StrCaseCmp(appData.initialMode, "") == 0) {
+  
+  if (*appData.cmailGameName != NULLCHAR) 
+    {
+      SetCmailMode();
+      OpenLoopback(&cmailPR);
+      cmailISR =
+       AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);
+    }
+  
+  ThawUI();
+  DisplayMessage("", "");
+  if (StrCaseCmp(appData.initialMode, "") == 0) 
+    {
       initialMode = BeginningOfGame;
-    } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) 
+    {
       initialMode = TwoMachinesPlay;
-    } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) {
-      initialMode = AnalyzeFile; 
-    } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) 
+    {
+      initialMode = AnalyzeFile;
+    } 
+  else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) 
+    {
       initialMode = AnalyzeMode;
-    } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) 
+    {
       initialMode = MachinePlaysWhite;
-    } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) 
+    {
       initialMode = MachinePlaysBlack;
-    } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) 
+    {
       initialMode = EditGame;
-    } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) 
+    {
       initialMode = EditPosition;
-    } else if (StrCaseCmp(appData.initialMode, "Training") == 0) {
+    } 
+  else if (StrCaseCmp(appData.initialMode, "Training") == 0) 
+    {
       initialMode = Training;
-    } else {
+    } 
+  else 
+    {
       sprintf(buf, _("Unknown initialMode %s"), appData.initialMode);
       DisplayFatalError(buf, 0, 2);
       return;
     }
-
-    if (appData.matchMode) {
-       /* Set up machine vs. machine match */
-       if (appData.noChessProgram) {
-           DisplayFatalError(_("Can't have a match with no chess programs"),
-                             0, 2);
-           return;
+  
+  if (appData.matchMode) 
+    {
+      /* Set up machine vs. machine match */
+      if (appData.noChessProgram) 
+       {
+         DisplayFatalError(_("Can't have a match with no chess programs"),
+                           0, 2);
+         return;
        }
-       matchMode = TRUE;
-       matchGame = 1;
-       if (*appData.loadGameFile != NULLCHAR) {
-           int index = appData.loadGameIndex; // [HGM] autoinc
-           if(index<0) lastIndex = index = 1;
-           if (!LoadGameFromFile(appData.loadGameFile,
-                                 index,
-                                 appData.loadGameFile, FALSE)) {
-               DisplayFatalError(_("Bad game file"), 0, 1);
-               return;
-           }
-       } else if (*appData.loadPositionFile != NULLCHAR) {
-           int index = appData.loadPositionIndex; // [HGM] autoinc
-           if(index<0) lastIndex = index = 1;
-           if (!LoadPositionFromFile(appData.loadPositionFile,
-                                     index,
-                                     appData.loadPositionFile)) {
-               DisplayFatalError(_("Bad position file"), 0, 1);
-               return;
+      matchMode = TRUE;
+      matchGame = 1;
+      if (*appData.loadGameFile != NULLCHAR) 
+       {
+         int index = appData.loadGameIndex; // [HGM] autoinc
+         if(index<0) lastIndex = index = 1;
+         if (!LoadGameFromFile(appData.loadGameFile,
+                               index,
+                               appData.loadGameFile, FALSE)) 
+           {
+             DisplayFatalError(_("Bad game file"), 0, 1);
+             return;
            }
-       }
-       TwoMachinesEvent();
-    } else if (*appData.cmailGameName != NULLCHAR) {
-       /* Set up cmail mode */
-       ReloadCmailMsgEvent(TRUE);
-    } else {
-       /* Set up other modes */
-       if (initialMode == AnalyzeFile) {
-         if (*appData.loadGameFile == NULLCHAR) {
-           DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);
-           return;
-         }
-       }
-       if (*appData.loadGameFile != NULLCHAR) {
-           (void) LoadGameFromFile(appData.loadGameFile,
-                                   appData.loadGameIndex,
-                                   appData.loadGameFile, TRUE);
-       } else if (*appData.loadPositionFile != NULLCHAR) {
-           (void) LoadPositionFromFile(appData.loadPositionFile,
-                                       appData.loadPositionIndex,
-                                       appData.loadPositionFile);
-            /* [HGM] try to make self-starting even after FEN load */
-            /* to allow automatic setup of fairy variants with wtm */
-            if(initialMode == BeginningOfGame && !blackPlaysFirst) {
-                gameMode = BeginningOfGame;
-                setboardSpoiledMachineBlack = 1;
-            }
-            /* [HGM] loadPos: make that every new game uses the setup */
-            /* from file as long as we do not switch variant          */
-            if(!blackPlaysFirst) {
-                startedFromPositionFile = TRUE;
-                CopyBoard(filePosition, boards[0]);
+       } 
+      else if (*appData.loadPositionFile != NULLCHAR) 
+       {
+         int index = appData.loadPositionIndex; // [HGM] autoinc
+         if(index<0) lastIndex = index = 1;
+         if (!LoadPositionFromFile(appData.loadPositionFile,
+                                   index,
+                                   appData.loadPositionFile)) 
+           {
+             DisplayFatalError(_("Bad position file"), 0, 1);
+             return;
+           }
+       }
+      TwoMachinesEvent();
+    } 
+  else if (*appData.cmailGameName != NULLCHAR) 
+    {
+      /* Set up cmail mode */
+      ReloadCmailMsgEvent(TRUE);
+    } 
+  else 
+    {
+      /* Set up other modes */
+      if (initialMode == AnalyzeFile) 
+       {
+         if (*appData.loadGameFile == NULLCHAR) 
+           {
+             DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);
+             return;
+           }
+       }
+      if (*appData.loadGameFile != NULLCHAR) 
+       {
+         (void) LoadGameFromFile(appData.loadGameFile,
+                                 appData.loadGameIndex,
+                                 appData.loadGameFile, TRUE);
+       } 
+      else if (*appData.loadPositionFile != NULLCHAR) 
+       {
+         (void) LoadPositionFromFile(appData.loadPositionFile,
+                                     appData.loadPositionIndex,
+                                     appData.loadPositionFile);
+         /* [HGM] try to make self-starting even after FEN load */
+         /* to allow automatic setup of fairy variants with wtm */
+         if(initialMode == BeginningOfGame && !blackPlaysFirst) 
+           {
+             gameMode = BeginningOfGame;
+             setboardSpoiledMachineBlack = 1;
             }
-       }
-       if (initialMode == AnalyzeMode) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);
-           return;
-         }
+         /* [HGM] loadPos: make that every new game uses the setup */
+         /* from file as long as we do not switch variant          */
+         if(!blackPlaysFirst) 
+           {
+             startedFromPositionFile = TRUE;
+             CopyBoard(filePosition, boards[0]);
+           }
+       }
+      if (initialMode == AnalyzeMode) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);
+             return;
+           }
          AnalyzeModeEvent();
-       } else if (initialMode == AnalyzeFile) {
+       } 
+      else if (initialMode == AnalyzeFile) 
+       {
          appData.showThinking = TRUE; // [HGM] thinking: moved out of ShowThinkingEvent
          ShowThinkingEvent();
          AnalyzeFileEvent();
          AnalysisPeriodicEvent(1);
-       } else if (initialMode == MachinePlaysWhite) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("MachineWhite mode requires a chess engine"),
-                             0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),
-                             0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == MachinePlaysWhite) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("MachineWhite mode requires a chess engine"),
+                               0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),
+                               0, 2);
+             return;
+           }
          MachineWhiteEvent();
-       } else if (initialMode == MachinePlaysBlack) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("MachineBlack mode requires a chess engine"),
-                             0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),
-                             0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == MachinePlaysBlack) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("MachineBlack mode requires a chess engine"),
+                               0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),
+                               0, 2);
+             return;
+           }
          MachineBlackEvent();
-       } else if (initialMode == TwoMachinesPlay) {
-         if (appData.noChessProgram) {
-           DisplayFatalError(_("TwoMachines mode requires a chess engine"),
-                             0, 2);
-           return;
-         }
-         if (appData.icsActive) {
-           DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),
-                             0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == TwoMachinesPlay) 
+       {
+         if (appData.noChessProgram) 
+           {
+             DisplayFatalError(_("TwoMachines mode requires a chess engine"),
+                               0, 2);
+             return;
+           }
+         if (appData.icsActive) 
+           {
+             DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),
+                               0, 2);
+             return;
+           }
          TwoMachinesEvent();
-       } else if (initialMode == EditGame) {
+       } 
+      else if (initialMode == EditGame) 
+       {
          EditGameEvent();
-       } else if (initialMode == EditPosition) {
+       } 
+      else if (initialMode == EditPosition) 
+       {
          EditPositionEvent();
-       } else if (initialMode == Training) {
-         if (*appData.loadGameFile == NULLCHAR) {
-           DisplayFatalError(_("Training mode requires a game file"), 0, 2);
-           return;
-         }
+       } 
+      else if (initialMode == Training) 
+       {
+         if (*appData.loadGameFile == NULLCHAR) 
+           {
+             DisplayFatalError(_("Training mode requires a game file"), 0, 2);
+             return;
+           }
          TrainingEvent();
        }
     }
+  
+  return;
 }
 
 /*
@@ -1320,7 +1392,7 @@ establish()
                        appData.icsHost, appData.icsPort);
            } else {
                snprintf(buf, sizeof(buf), "%s %s -l %s %s %s %s",
-                       appData.remoteShell, appData.gateway, 
+                       appData.remoteShell, appData.gateway,
                        appData.remoteUser, appData.telnetProgram,
                        appData.icsHost, appData.icsPort);
            }
@@ -1505,7 +1577,7 @@ SendToICSDelayed(s,msdelay)
 
 
 /* Remove all highlighting escape sequences in s
-   Also deletes any suffix starting with '(' 
+   Also deletes any suffix starting with '('
    */
 char *
 StripHighlightAndTitle(s)
@@ -1595,7 +1667,7 @@ StringToVariant(e)
 
     if (!found) {
       if ((StrCaseStr(e, "fischer") && StrCaseStr(e, "random"))
-         || StrCaseStr(e, "wild/fr") 
+         || StrCaseStr(e, "wild/fr")
          || StrCaseStr(e, "frc") || StrCaseStr(e, "960")) {
         v = VariantFischeRandom;
       } else if ((i = 4, p = StrCaseStr(e, "wild")) ||
@@ -1673,7 +1745,7 @@ StringToVariant(e)
          v = VariantShatranj;
          break;
 
-       /* Temporary names for future ICC types.  The name *will* change in 
+       /* Temporary names for future ICC types.  The name *will* change in
           the next xboard/WinBoard release after ICC defines it. */
        case 29:
          v = Variant29;
@@ -1780,7 +1852,7 @@ looking_at(buf, index, pattern)
     char *bufp = &buf[*index], *patternp = pattern;
     int star_count = 0;
     char *matchp = star_match[0];
-    
+
     for (;;) {
        if (*patternp == NULLCHAR) {
            *index = leftover_start = bufp - buf;
@@ -1986,7 +2058,6 @@ VariantSwitch(Board board, VariantClass newVariant)
     * but also when receiving holdings of a crazyhouse game. In the latter
     * case we want to add those holdings to the already received position.
     */
-
    
    if (appData.debugMode) {
      fprintf(debugFP, "Switch board from %s to %s\n",
@@ -2063,6 +2134,203 @@ static int player2Rating = -1;
 ColorClass curColor = ColorNormal;
 int suppressKibitz = 0;
 
+// [HGM] seekgraph
+Boolean soughtPending = FALSE;
+Boolean seekGraphUp;
+#define MAX_SEEK_ADS 200
+#define SQUARE 0x80
+char *seekAdList[MAX_SEEK_ADS];
+int ratingList[MAX_SEEK_ADS], xList[MAX_SEEK_ADS], yList[MAX_SEEK_ADS], seekNrList[MAX_SEEK_ADS], zList[MAX_SEEK_ADS];
+float tcList[MAX_SEEK_ADS];
+char colorList[MAX_SEEK_ADS];
+int nrOfSeekAds = 0;
+int minRating = 1010, maxRating = 2800;
+int hMargin = 10, vMargin = 20, h, w;
+extern int squareSize, lineGap;
+
+void
+PlotSeekAd(int i)
+{
+       int x, y, color = 0, r = ratingList[i]; float tc = tcList[i];
+       xList[i] = yList[i] = -100; // outside graph, so cannot be clicked
+       if(r < minRating+100 && r >=0 ) r = minRating+100;
+       if(r > maxRating) r = maxRating;
+       if(tc < 1.) tc = 1.;
+       if(tc > 95.) tc = 95.;
+       x = (w-hMargin)* log(tc)/log(100.) + hMargin;
+       y = ((double)r - minRating)/(maxRating - minRating)
+           * (h-vMargin-squareSize/8-1) + vMargin;
+       if(ratingList[i] < 0) y = vMargin + squareSize/4;
+       if(strstr(seekAdList[i], " u ")) color = 1;
+       if(!strstr(seekAdList[i], "lightning") && // for now all wilds same color
+          !strstr(seekAdList[i], "bullet") &&
+          !strstr(seekAdList[i], "blitz") &&
+          !strstr(seekAdList[i], "standard") ) color = 2;
+       if(strstr(seekAdList[i], "(C) ")) color |= SQUARE; // plot computer seeks as squares
+       DrawSeekDot(xList[i]=x+3*(color&~SQUARE), yList[i]=h-1-y, colorList[i]=color);
+}
+
+void
+AddAd(char *handle, char *rating, int base, int inc,  char rated, char *type, int nr, Boolean plot)
+{
+       char buf[MSG_SIZ], *ext = "";
+       VariantClass v = StringToVariant(type);
+       if(strstr(type, "wild")) {
+           ext = type + 4; // append wild number
+           if(v == VariantFischeRandom) type = "chess960"; else
+           if(v == VariantLoadable) type = "setup"; else
+           type = VariantName(v);
+       }
+       sprintf(buf, "%s (%s) %d %d %c %s%s", handle, rating, base, inc, rated, type, ext);
+       if(nrOfSeekAds < MAX_SEEK_ADS-1) {
+           if(seekAdList[nrOfSeekAds]) free(seekAdList[nrOfSeekAds]);
+           ratingList[nrOfSeekAds] = -1; // for if seeker has no rating
+           sscanf(rating, "%d", &ratingList[nrOfSeekAds]);
+           tcList[nrOfSeekAds] = base + (2./3.)*inc;
+           seekNrList[nrOfSeekAds] = nr;
+           zList[nrOfSeekAds] = 0;
+           seekAdList[nrOfSeekAds++] = StrSave(buf);
+           if(plot) PlotSeekAd(nrOfSeekAds-1);
+       }
+}
+
+void
+EraseSeekDot(int i)
+{
+    int x = xList[i], y = yList[i], d=squareSize/4, k;
+    DrawSeekBackground(x-squareSize/8, y-squareSize/8, x+squareSize/8+1, y+squareSize/8+1);
+    if(x < hMargin+d) DrawSeekAxis(hMargin, y-squareSize/8, hMargin, y+squareSize/8+1);
+    // now replot every dot that overlapped
+    for(k=0; k<nrOfSeekAds; k++) if(k != i) {
+       int xx = xList[k], yy = yList[k];
+       if(xx <= x+d && xx > x-d && yy <= y+d && yy > y-d)
+           DrawSeekDot(xx, yy, colorList[k]);
+    }
+}
+
+void
+RemoveSeekAd(int nr)
+{
+       int i;
+       for(i=0; i<nrOfSeekAds; i++) if(seekNrList[i] == nr) {
+           EraseSeekDot(i);
+           if(seekAdList[i]) free(seekAdList[i]);
+           seekAdList[i] = seekAdList[--nrOfSeekAds];
+           seekNrList[i] = seekNrList[nrOfSeekAds];
+           ratingList[i] = ratingList[nrOfSeekAds];
+           colorList[i]  = colorList[nrOfSeekAds];
+           tcList[i] = tcList[nrOfSeekAds];
+           xList[i]  = xList[nrOfSeekAds];
+           yList[i]  = yList[nrOfSeekAds];
+           zList[i]  = zList[nrOfSeekAds];
+           seekAdList[nrOfSeekAds] = NULL;
+           break;
+       }
+}
+
+Boolean
+MatchSoughtLine(char *line)
+{
+    char handle[MSG_SIZ], rating[MSG_SIZ], type[MSG_SIZ];
+    int nr, base, inc, u=0; char dummy;
+
+    if(sscanf(line, "%d %s %s %d %d rated %s", &nr, rating, handle, &base, &inc, type) == 6 ||
+       sscanf(line, "%d %s %s %s %d %d rated %c", &nr, rating, handle, type, &base, &inc, &dummy) == 7 ||
+       (u=1) &&
+       (sscanf(line, "%d %s %s %d %d unrated %s", &nr, rating, handle, &base, &inc, type) == 6 ||
+        sscanf(line, "%d %s %s %s %d %d unrated %c", &nr, rating, handle, type, &base, &inc, &dummy) == 7)  ) {
+       // match: compact and save the line
+       AddAd(handle, rating, base, inc, u ? 'u' : 'r', type, nr, FALSE);
+       return TRUE;
+    }
+    return FALSE;
+}
+
+int
+DrawSeekGraph()
+{
+    if(!seekGraphUp) return FALSE;
+    int i;
+    h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
+    w = BOARD_WIDTH  * (squareSize + lineGap) + lineGap;
+
+    DrawSeekBackground(0, 0, w, h);
+    DrawSeekAxis(hMargin, h-1-vMargin, w-5, h-1-vMargin);
+    DrawSeekAxis(hMargin, h-1-vMargin, hMargin, 5);
+    for(i=0; i<4000; i+= 100) if(i>=minRating && i<maxRating) {
+       int yy =((double)i - minRating)/(maxRating - minRating)*(h-vMargin-squareSize/8-1) + vMargin;
+       yy = h-1-yy;
+       DrawSeekAxis(hMargin+5*(i%500==0), yy, hMargin-5, yy); // rating ticks
+       if(i%500 == 0) {
+           char buf[MSG_SIZ];
+           sprintf(buf, "%d", i);
+           DrawSeekText(buf, hMargin+squareSize/8+7, yy);
+       }
+    }
+    DrawSeekText("unrated", hMargin+squareSize/8+7, h-1-vMargin-squareSize/4);
+    for(i=1; i<100; i+=(i<10?1:5)) {
+       int xx = (w-hMargin)* log((double)i)/log(100.) + hMargin;
+       DrawSeekAxis(xx, h-1-vMargin, xx, h-6-vMargin-3*(i%10==0)); // TC ticks
+       if(i<=5 || (i>40 ? i%20 : i%10) == 0) {
+           char buf[MSG_SIZ];
+           sprintf(buf, "%d", i);
+           DrawSeekText(buf, xx-2-3*(i>9), h-1-vMargin/2);
+       }
+    }
+    for(i=0; i<nrOfSeekAds; i++) PlotSeekAd(i);
+    return TRUE;
+}
+
+int SeekGraphClick(ClickType click, int x, int y, int moving)
+{
+    static int lastDown = 0, displayed = 0, lastSecond;
+    if(!seekGraphUp) { // initiate cration of seek graph by requesting seek-ad list
+       if(click == Release || moving) return FALSE;
+       nrOfSeekAds = 0;
+       soughtPending = TRUE;
+       SendToICS(ics_prefix);
+       SendToICS("sought\n"); // should this be "sought all"?
+    } else { // issue challenge based on clicked ad
+       int dist = 10000; int i, closest = 0, second = 0;
+       for(i=0; i<nrOfSeekAds; i++) {
+           int d = (x-xList[i])*(x-xList[i]) +  (y-yList[i])*(y-yList[i]) + zList[i];
+           if(d < dist) { dist = d; closest = i; }
+           second += (d - zList[i] < 120); // count in-range ads
+           if(click == Press && moving != 1 && zList[i]>0) zList[i] *= 0.8; // age priority
+       }
+       if(dist < 120) {
+           char buf[MSG_SIZ];
+           second = (second > 1);
+           if(displayed != closest || second != lastSecond) {
+               DisplayMessage(second ? "!" : "", seekAdList[closest]);
+               lastSecond = second; displayed = closest;
+           }
+           sprintf(buf, "play %d\n", seekNrList[closest]);
+           if(click == Press) {
+               if(moving == 2) zList[closest] = 100; // right-click; push to back on press
+               lastDown = closest;
+               return TRUE;
+           } // on press 'hit', only show info
+           if(moving == 2) return TRUE; // ignore right up-clicks on dot
+           SendToICS(ics_prefix);
+           SendToICS(buf); // should this be "sought all"?
+       } else if(click == Release) { // release 'miss' is ignored
+           zList[lastDown] = 100; // make future selection of the rejected ad more difficult
+           if(moving == 2) { // right up-click
+               nrOfSeekAds = 0; // refresh graph
+               soughtPending = TRUE;
+               SendToICS(ics_prefix);
+               SendToICS("sought\n"); // should this be "sought all"?
+           }
+           return TRUE;
+       } else if(moving) { if(displayed >= 0) DisplayMessage("", ""); displayed = -1; return TRUE; }
+       // press miss or release hit 'pop down' seek graph
+       seekGraphUp = FALSE;
+       DrawPosition(TRUE, NULL);
+    }
+    return TRUE;
+}
+
 void
 read_from_ics(isr, closure, data, count, error)
      InputSourceRef isr;
@@ -2080,7 +2348,7 @@ read_from_ics(isr, closure, data, count, error)
 #define STARTED_CHATTER 5
 #define STARTED_COMMENT 6
 #define STARTED_MOVES_NOHIDE 7
-    
+
     static int started = STARTED_NONE;
     static char parse[20000];
     static int parse_pos = 0;
@@ -2188,7 +2456,7 @@ read_from_ics(isr, closure, data, count, error)
 //     next_out = leftover_len; // [HGM] should we set this to 0, and not print it in advance?
        next_out = 0;
        leftover_start = 0;
-       
+
        i = 0;
        while (i < buf_len) {
            /* Deal with part of the TELNET option negotiation
@@ -2300,23 +2568,27 @@ read_from_ics(isr, closure, data, count, error)
                  next_out = i;
                continue;
            }
-               
+
            /* OK, this at least will *usually* work */
            if (!loggedOn && looking_at(buf, &i, "ics%")) {
                loggedOn = TRUE;
            }
-           
+
            if (loggedOn && !intfSet) {
                if (ics_type == ICS_ICC) {
                  sprintf(str,
                          "/set-quietly interface %s\n/set-quietly style 12\n",
                          programVersion);
+                 if(appData.seekGraph && appData.autoRefresh) // [HGM] seekgraph
+                     strcat(str, "/set-2 51 1\n/set seek 1\n");
                } else if (ics_type == ICS_CHESSNET) {
                  sprintf(str, "/style 12\n");
                } else {
                  strcpy(str, "alias $ @\n$set interface ");
                  strcat(str, programVersion);
                  strcat(str, "\n$iset startpos 1\n$iset ms 1\n");
+                 if(appData.seekGraph && appData.autoRefresh) // [HGM] seekgraph
+                     strcat(str, "$iset seekremove 1\n$set seek 1\n");
 #ifdef WIN32
                  strcat(str, "$iset nohighlight 1\n");
 #endif
@@ -2438,6 +2710,45 @@ read_from_ics(isr, closure, data, count, error)
              continue;
            }
 
+           // [HGM] seekgraph: recognize sought lines and end-of-sought message
+           if(appData.seekGraph) {
+               if(soughtPending && MatchSoughtLine(buf+i)) {
+                   i = strstr(buf+i, "rated") - buf;
+                   next_out = leftover_start = i;
+                   started = STARTED_CHATTER;
+                   suppressKibitz = TRUE;
+                   continue;
+               }
+               if((gameMode == IcsIdle || gameMode == BeginningOfGame)
+                       && looking_at(buf, &i, "* ads displayed")) {
+                   soughtPending = FALSE;
+                   seekGraphUp = TRUE;
+                   DrawSeekGraph();
+                   continue;
+               }
+               if(appData.autoRefresh) {
+                   if(looking_at(buf, &i, "* (*) seeking * * * * *\"play *\" to respond)\n")) {
+                       int s = (ics_type == ICS_ICC); // ICC format differs
+                       if(seekGraphUp)
+                       AddAd(star_match[0], star_match[1], atoi(star_match[2+s]), atoi(star_match[3+s]), 
+                             star_match[4+s][0], star_match[5-3*s], atoi(star_match[7]), TRUE);
+                       looking_at(buf, &i, "*% "); // eat prompt
+                       next_out = i; // suppress
+                       continue;
+                   }
+                   if(looking_at(buf, &i, "Ads removed: *\n") || looking_at(buf, &i, "\031(51 * *\031)")) {
+                       char *p = star_match[0];
+                       while(*p) {
+                           if(seekGraphUp) RemoveSeekAd(atoi(p));
+                           while(*p && *p++ != ' '); // next
+                       }
+                       looking_at(buf, &i, "*% "); // eat prompt
+                       next_out = i;
+                       continue;
+                   }
+               }
+           }
+
            /* skip formula vars */
            if (started == STARTED_NONE &&
                buf[i] == 'f' && isdigit(buf[i+1]) && buf[i+2] == ':') {
@@ -2448,11 +2759,11 @@ read_from_ics(isr, closure, data, count, error)
 
            oldi = i;
            // [HGM] kibitz: try to recognize opponent engine-score kibitzes, to divert them to engine-output window
-           if (appData.autoKibitz && started == STARTED_NONE && 
+           if (appData.autoKibitz && started == STARTED_NONE &&
                 !appData.icsEngineAnalyze &&                     // [HGM] [DM] ICS analyze
                (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || gameMode == IcsObserving)) {
                if(looking_at(buf, &i, "* kibitzes: ") &&
-                  (StrStr(star_match[0], gameInfo.white) == star_match[0] || 
+                  (StrStr(star_match[0], gameInfo.white) == star_match[0] ||
                    StrStr(star_match[0], gameInfo.black) == star_match[0]   )) { // kibitz of self or opponent
                        suppressKibitz = TRUE;
                        if((StrStr(star_match[0], gameInfo.white) == star_match[0]
@@ -2466,11 +2777,13 @@ read_from_ics(isr, closure, data, count, error)
                            savingComment = TRUE;
                            suppressKibitz = gameMode != IcsObserving ? 2 :
                                (StrStr(star_match[0], gameInfo.white) == NULL) + 1;
-                       } 
+                       }
                        continue;
                } else
                if(looking_at(buf, &i, "kibitzed to *\n") && atoi(star_match[0])) {
                    // suppress the acknowledgements of our own autoKibitz
+                   char *p;
+                   if(p = strchr(star_match[0], ' ')) p[1] = NULLCHAR; // clip off "players)" on FICS
                    SendToPlayer(star_match[0], strlen(star_match[0]));
                    looking_at(buf, &i, "*% "); // eat prompt
                    next_out = i;
@@ -2492,14 +2805,14 @@ read_from_ics(isr, closure, data, count, error)
                if(channel >= 0) // channel broadcast; look if there is a chatbox for this channel
                for(p=0; p<MAX_CHAT; p++) {
                    if(channel == atoi(chatPartner[p])) {
-                   talker[0] = '['; strcat(talker, "]");
+                   talker[0] = '['; strcat(talker, "] ");
                    chattingPartner = p; break;
                    }
                } else
                if(buf[i-3] == 'r') // whisper; look if there is a WHISPER chatbox
                for(p=0; p<MAX_CHAT; p++) {
                    if(!strcmp("WHISPER", chatPartner[p])) {
-                       talker[0] = '['; strcat(talker, "]");
+                       talker[0] = '['; strcat(talker, "] ");
                        chattingPartner = p; break;
                    }
                }
@@ -2511,7 +2824,7 @@ read_from_ics(isr, closure, data, count, error)
                if(chattingPartner<0) i = oldi; else {
                    started = STARTED_COMMENT;
                    parse_pos = 0; parse[0] = NULLCHAR;
-                   savingComment = TRUE;
+                   savingComment = 3 + chattingPartner; // counts as TRUE
                    suppressKibitz = TRUE;
                }
            } // [HGM] chat: end of patch
@@ -2706,6 +3019,8 @@ read_from_ics(isr, closure, data, count, error)
                    memcpy(parse, &buf[oldi], parse_pos);
                    parse[parse_pos] = NULLCHAR;
                    started = STARTED_COMMENT;
+                   if(savingComment >= 3) // [HGM] chat: continuation of line for chat box
+                       chattingPartner = savingComment - 3; // kludge to remember the box
                } else {
                    started = STARTED_CHATTER;
                }
@@ -2724,14 +3039,14 @@ read_from_ics(isr, closure, data, count, error)
                SendToICS("refresh\n");
                continue;
            }
-           
+
            if (!have_sent_ICS_logon && looking_at(buf, &i, "login:")) {
                ICSInitScript();
                have_sent_ICS_logon = 1;
                continue;
            }
-             
-           if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ && 
+
+           if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ &&
                (looking_at(buf, &i, "\n<12> ") ||
                 looking_at(buf, &i, "<12> "))) {
                loggedOn = TRUE;
@@ -2814,7 +3129,7 @@ read_from_ics(isr, closure, data, count, error)
                    gameInfo.whiteRating = string_to_rating(star_match[1]);
                    gameInfo.blackRating = string_to_rating(star_match[3]);
                    if (appData.debugMode)
-                     fprintf(debugFP, _("Ratings from header: W %d, B %d\n"), 
+                     fprintf(debugFP, _("Ratings from header: W %d, B %d\n"),
                              gameInfo.whiteRating, gameInfo.blackRating);
                }
                continue;
@@ -2868,11 +3183,16 @@ read_from_ics(isr, closure, data, count, error)
                    break;
                }
                continue;
-           }                           
-           
+           }
+
            if (looking_at(buf, &i, "% ") ||
                ((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE)
                 && looking_at(buf, &i, "}*"))) { char *bookHit = NULL; // [HGM] book
+               if(ics_type == ICS_ICC && soughtPending) { // [HGM] seekgraph: on ICC sought-list has no termination line
+                   soughtPending = FALSE;
+                   seekGraphUp = TRUE;
+                   DrawSeekGraph();
+               }
                if(suppressKibitz) next_out = i;
                savingComment = FALSE;
                suppressKibitz = 0;
@@ -2889,7 +3209,7 @@ read_from_ics(isr, closure, data, count, error)
                            if (WhiteOnMove(forwardMostMove)) {
                                if (first.sendTime) {
                                  if (first.useColors) {
-                                   SendToProgram("black\n", &first); 
+                                   SendToProgram("black\n", &first);
                                  }
                                  SendTimeRemaining(&first, TRUE);
                                }
@@ -2933,7 +3253,7 @@ read_from_ics(isr, closure, data, count, error)
                                  firstMove = TRUE;
                                }
                            }
-                       }                       
+                       }
                    }
 #endif
                    if (gameMode == IcsObserving && ics_gamenum == -1) {
@@ -2976,7 +3296,7 @@ read_from_ics(isr, closure, data, count, error)
                if(bookHit) { // [HGM] book: simulate book reply
                    static char bookMove[MSG_SIZ]; // a bit generous?
 
-                   programStats.nodes = programStats.depth = programStats.time = 
+                   programStats.nodes = programStats.depth = programStats.time =
                    programStats.score = programStats.got_only_move = 0;
                    sprintf(programStats.movelist, "%s (xbook)", bookHit);
 
@@ -2986,14 +3306,14 @@ read_from_ics(isr, closure, data, count, error)
                }
                continue;
            }
-           
+
            if ((started == STARTED_MOVES || started == STARTED_BOARD ||
                 started == STARTED_HOLDINGS ||
                 started == STARTED_MOVES_NOHIDE) && i >= leftover_len) {
                /* Accumulate characters in move list or board */
                parse[parse_pos++] = buf[i];
            }
-           
+
            /* Start of game messages.  Mostly we detect start of game
               when the first board image arrives.  On some versions
               of the ICS, though, we need to do a "refresh" after starting
@@ -3026,7 +3346,7 @@ read_from_ics(isr, closure, data, count, error)
                player2Rating = string_to_rating(star_match[3]);
 
                if (appData.debugMode)
-                 fprintf(debugFP, 
+                 fprintf(debugFP,
                          "Ratings from 'Game notification:' %s %d, %s %d\n",
                          player1Name, player1Rating,
                          player2Name, player2Rating);
@@ -3056,8 +3376,8 @@ read_from_ics(isr, closure, data, count, error)
                    SendToICS("refresh\n");
                }
                continue;
-           }    
-           
+           }
+
            /* Error messages */
 //         if (ics_user_moved) {
            if (1) { // [HGM] old way ignored error after move type in; ics_user_moved is not set then!
@@ -3120,7 +3440,7 @@ read_from_ics(isr, closure, data, count, error)
                   2    empty, white, or black (IGNORED)
                   3    player 2 name (not necessarily black)
                   4    player 2 rating
-                  
+
                   The names/ratings are sorted out when the game
                   actually starts (below).
                */
@@ -3130,14 +3450,14 @@ read_from_ics(isr, closure, data, count, error)
                player2Rating = string_to_rating(star_match[4]);
 
                if (appData.debugMode)
-                 fprintf(debugFP, 
+                 fprintf(debugFP,
                          "Ratings from 'Creating:' %s %d, %s %d\n",
                          player1Name, player1Rating,
                          player2Name, player2Rating);
 
                continue;
            }
-           
+
            /* Improved generic start/end-of-game messages */
            if ((tkind=0, looking_at(buf, &i, "{Game * (* vs. *) *}*")) ||
                (tkind=1, looking_at(buf, &i, "{Game * (*(*) vs. *(*)) *}*"))){
@@ -3291,8 +3611,8 @@ read_from_ics(isr, closure, data, count, error)
                        ClearPremoveHighlights();
                        if (appData.debugMode)
                          fprintf(debugFP, "Sending premove:\n");
-                          UserMoveEvent(premoveFromX, premoveFromY, 
-                                       premoveToX, premoveToY, 
+                          UserMoveEvent(premoveFromX, premoveFromY,
+                                       premoveToX, premoveToY,
                                         premovePromoChar);
                      }
                    }
@@ -3389,11 +3709,11 @@ read_from_ics(isr, closure, data, count, error)
            SendToPlayer(&buf[next_out], leftover_start - next_out);
            next_out = i;
        }
-       
+
        leftover_len = buf_len - leftover_start;
        /* if buffer ends with something we couldn't parse,
           reparse it after appending the next read */
-       
+
     } else if (count == 0) {
        RemoveInputSource(isr);
         DisplayFatalError(_("Connection closed by ICS"), 0, 0);
@@ -3404,13 +3724,13 @@ read_from_ics(isr, closure, data, count, error)
 
 
 /* Board style 12 looks like this:
-   
+
    <12> r-b---k- pp----pp ---bP--- ---p---- q------- ------P- P--Q--BP -----R-K W -1 0 0 0 0 0 0 paf MaxII 0 2 12 21 25 234 174 24 Q/d7-a4 (0:06) Qxa4 0 0
-   
+
  * The "<12> " is stripped before it gets to this routine.  The two
  * trailing 0's (flip state and clock ticking) are later addition, and
  * some chess servers may not have them, or may have only the first.
- * Additional trailing fields may be added in the future.  
+ * Additional trailing fields may be added in the future.
  */
 
 #define PATTERN "%c%d%d%d%d%d%d%d%s%s%d%d%d%d%d%d%d%d%s%s%s%d%d"
@@ -3426,7 +3746,7 @@ read_from_ics(isr, closure, data, count, error)
 void
 ParseBoard12(string)
      char *string;
-{ 
+{
     GameMode newGameMode;
     int gamenum, newGame, newMove, relation, basetime, increment, ics_flip = 0, i;
     int j, k, n, moveNum, white_stren, black_stren, white_time, black_time, takeback;
@@ -3445,7 +3765,7 @@ ParseBoard12(string)
     Boolean weird = FALSE, reqFlag = FALSE;
 
     fromX = fromY = toX = toY = -1;
-    
+
     newGame = FALSE;
 
     if (appData.debugMode)
@@ -3486,7 +3806,7 @@ ParseBoard12(string)
                        0, 1);
       return;
     }
-    
+
     switch (relation) {
       case RELATION_OBSERVING_PLAYED:
       case RELATION_OBSERVING_STATIC:
@@ -3508,14 +3828,14 @@ ParseBoard12(string)
       case RELATION_ISOLATED_BOARD:
       default:
        /* Just display this board.  If user was doing something else,
-          we will forget about it until the next board comes. */ 
+          we will forget about it until the next board comes. */
        newGameMode = IcsIdle;
        break;
       case RELATION_STARTING_POSITION:
        newGameMode = gameMode;
        break;
     }
-    
+
     /* Modify behavior for initial board display on move listing
        of wild games.
        */
@@ -3574,7 +3894,7 @@ ParseBoard12(string)
        different game than is currently being displayed.  */
     if (gamenum != ics_gamenum || newGameMode != gameMode ||
        relation == RELATION_ISOLATED_BOARD) {
-       
+
        /* Forget the old game and get the history (if any) of the new one */
        if (gameMode != BeginningOfGame) {
          Reset(TRUE, TRUE);
@@ -3591,14 +3911,14 @@ ParseBoard12(string)
            sprintf(str, "%smoves %d\n", ics_prefix, gamenum);
            SendToICS(str);
        }
-       
+
        /* Initially flip the board to have black on the bottom if playing
           black or if the ICS flip flag is set, but let the user change
           it with the Flip View button. */
-       flipView = appData.autoFlipView ? 
+       flipView = appData.autoFlipView ?
          (newGameMode == IcsPlayingBlack) || ics_flip :
          appData.flipView;
-       
+
        /* Done with values from previous mode; copy in new ones */
        gameMode = newGameMode;
        ModeHighlight();
@@ -3629,7 +3949,7 @@ ParseBoard12(string)
   }
 
         gameInfo.outOfBook = NULL;
-       
+
        /* Do we have the ratings? */
        if (strcmp(player1Name, white) == 0 &&
            strcmp(player2Name, black) == 0) {
@@ -3655,7 +3975,7 @@ ParseBoard12(string)
            SendToICS("set shout 0\n");
        }
     }
-    
+
     /* Deal with midgame name changes */
     if (!newGame) {
        if (!gameInfo.white || strcmp(gameInfo.white, white) != 0) {
@@ -3667,7 +3987,7 @@ ParseBoard12(string)
            gameInfo.black = StrSave(black);
        }
     }
-    
+
     /* Throw away game result if anything actually changes in examine mode */
     if (gameMode == IcsExamining && !newGame) {
        gameInfo.result = GameUnfinished;
@@ -3676,7 +3996,7 @@ ParseBoard12(string)
            gameInfo.resultDetails = NULL;
        }
     }
-    
+
     /* In pausing && IcsExamining mode, we ignore boards coming
        in if they are in a different variation than we are. */
     if (pauseExamInvalid) return;
@@ -3687,7 +4007,7 @@ ParseBoard12(string)
            return;
        }
     }
-    
+
   if (appData.debugMode) {
     fprintf(debugFP, "load %dx%d board\n", files, ranks);
   }
@@ -3762,14 +4082,14 @@ ParseBoard12(string)
     /* [HGM] e.p. rights. Assume that ICS sends file number here? */
     boards[moveNum][EP_STATUS] = double_push == -1 ? EP_NONE : double_push + BOARD_LEFT;
 
-    
+
     if (ics_getting_history == H_GOT_REQ_HEADER ||
        ics_getting_history == H_GOT_UNREQ_HEADER) {
        /* This was an initial position from a move list, not
           the current position */
        return;
     }
-    
+
     /* Update currentMove and known move number limits */
     newMove = newGame || moveNum > forwardMostMove;
 
@@ -3803,7 +4123,7 @@ ParseBoard12(string)
        if (!pausing || currentMove > forwardMostMove)
          currentMove = forwardMostMove;
     } else {
-       /* New part of history that is not contiguous with old part */ 
+       /* New part of history that is not contiguous with old part */
        if (pausing && gameMode == IcsExamining) {
            pauseExamInvalid = TRUE;
            forwardMostMove = pauseExamForwardMostMove;
@@ -3824,7 +4144,7 @@ ParseBoard12(string)
        }
        forwardMostMove = backwardMostMove = currentMove = moveNum;
     }
-    
+
     /* Update the clocks */
     if (strchr(elapsed_time, '.')) {
       /* Time is in ms */
@@ -3835,7 +4155,7 @@ ParseBoard12(string)
       timeRemaining[0][moveNum] = whiteTimeRemaining = white_time * 1000;
       timeRemaining[1][moveNum] = blackTimeRemaining = black_time * 1000;
     }
-      
+
 
 #if ZIPPY
     if (appData.zippyPlay && newGame &&
@@ -3843,7 +4163,7 @@ ParseBoard12(string)
        gameMode != IcsExamining)
       ZippyFirstBoard(moveNum, basetime, increment);
 #endif
-    
+
     /* Put the move on the move list, first converting
        to canonical algebraic form. */
     if (moveNum > 0) {
@@ -3875,18 +4195,18 @@ ParseBoard12(string)
            startedFromSetupPosition = TRUE;
            fromX = fromY = toX = toY = -1;
        } else {
-         // [HGM] long SAN: if legality-testing is off, disambiguation might not work or give wrong move. 
+         // [HGM] long SAN: if legality-testing is off, disambiguation might not work or give wrong move.
          //                 So we parse the long-algebraic move string in stead of the SAN move
          int valid; char buf[MSG_SIZ], *prom;
 
          // str looks something like "Q/a1-a2"; kill the slash
-         if(str[1] == '/') 
+         if(str[1] == '/')
                sprintf(buf, "%c%s", str[0], str+2);
          else  strcpy(buf, str); // might be castling
-         if((prom = strstr(move_str, "=")) && !strstr(buf, "=")) 
+         if((prom = strstr(move_str, "=")) && !strstr(buf, "="))
                strcat(buf, prom); // long move lacks promo specification!
          if(!appData.testLegality && move_str[1] != '@') { // drops never ambiguous (parser chokes on long form!)
-               if(appData.debugMode) 
+               if(appData.debugMode)
                        fprintf(debugFP, "replaced ICS move '%s' by '%s'\n", move_str, buf);
                strcpy(move_str, buf);
           }
@@ -3939,7 +4259,7 @@ ParseBoard12(string)
 
 #if ZIPPY
        /* Send move to chess program (BEFORE animating it). */
-       if (appData.zippyPlay && !newGame && newMove && 
+       if (appData.zippyPlay && !newGame && newMove &&
           (!appData.getMoveList || backwardMostMove == 0) && first.initDone) {
 
            if ((gameMode == IcsPlayingWhite && WhiteOnMove(moveNum)) ||
@@ -3988,7 +4308,7 @@ ParseBoard12(string)
            SetHighlights(fromX, fromY, toX, toY);
        }
     }
-    
+
     /* Start the clocks */
     whiteFlag = blackFlag = FALSE;
     appData.clockMode = !(basetime == 0 && increment == 0);
@@ -4005,26 +4325,26 @@ ParseBoard12(string)
       DisplayBothClocks();
     else
       StartClocks();
-    
+
     /* Display opponents and material strengths */
     if (gameInfo.variant != VariantBughouse &&
        gameInfo.variant != VariantCrazyhouse && !appData.noGUI) {
        if (tinyLayout || smallLayout) {
            if(gameInfo.variant == VariantNormal)
-               sprintf(str, "%s(%d) %s(%d) {%d %d}", 
+               sprintf(str, "%s(%d) %s(%d) {%d %d}",
                    gameInfo.white, white_stren, gameInfo.black, black_stren,
                    basetime, increment);
            else
-               sprintf(str, "%s(%d) %s(%d) {%d %d w%d}", 
+               sprintf(str, "%s(%d) %s(%d) {%d %d w%d}",
                    gameInfo.white, white_stren, gameInfo.black, black_stren,
                    basetime, increment, (int) gameInfo.variant);
        } else {
            if(gameInfo.variant == VariantNormal)
-               sprintf(str, "%s (%d) vs. %s (%d) {%d %d}", 
+               sprintf(str, "%s (%d) vs. %s (%d) {%d %d}",
                    gameInfo.white, white_stren, gameInfo.black, black_stren,
                    basetime, increment);
            else
-               sprintf(str, "%s (%d) vs. %s (%d) {%d %d %s}", 
+               sprintf(str, "%s (%d) vs. %s (%d) {%d %d %s}",
                    gameInfo.white, white_stren, gameInfo.black, black_stren,
                    basetime, increment, VariantName(gameInfo.variant));
        }
@@ -4034,17 +4354,18 @@ ParseBoard12(string)
   }
     }
 
-   
+
     /* Display the board */
     if (!pausing && !appData.noGUI) {
-      
       if (appData.premove)
-         if (!gotPremove || 
+         if (!gotPremove ||
             ((gameMode == IcsPlayingWhite) && (WhiteOnMove(currentMove))) ||
             ((gameMode == IcsPlayingBlack) && (!WhiteOnMove(currentMove))))
              ClearPremoveHighlights();
 
-      DrawPosition(FALSE, boards[currentMove]);
+      j = seekGraphUp; seekGraphUp = FALSE; // [HGM] seekgraph: when we draw a board, it overwrites the seek graph
+      DrawPosition(j, boards[currentMove]);
+
       DisplayMove(moveNum - 1);
       if (appData.ringBellAfterMoves && /*!ics_user_moved*/ // [HGM] use absolute method to recognize own move
            !((gameMode == IcsPlayingWhite) && (!WhiteOnMove(moveNum)) ||
@@ -4058,7 +4379,7 @@ ParseBoard12(string)
     if(bookHit) { // [HGM] book: simulate book reply
        static char bookMove[MSG_SIZ]; // a bit generous?
 
-       programStats.nodes = programStats.depth = programStats.time = 
+       programStats.nodes = programStats.depth = programStats.time =
        programStats.score = programStats.got_only_move = 0;
        sprintf(programStats.movelist, "%s (xbook)", bookHit);
 
@@ -4132,17 +4453,17 @@ SendMoveToProgram(moveNum, cps)
        AlphaRank(moveList[moveNum], 4); // and back
       } else
       /* Added by Tord: Send castle moves in "O-O" in FRC games if required by
-       * the engine. It would be nice to have a better way to identify castle 
+       * the engine. It would be nice to have a better way to identify castle
        * moves here. */
       if((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom)
                                                                         && cps->useOOCastle) {
-        int fromX = moveList[moveNum][0] - AAA; 
+        int fromX = moveList[moveNum][0] - AAA;
         int fromY = moveList[moveNum][1] - ONE;
-        int toX = moveList[moveNum][2] - AAA; 
+        int toX = moveList[moveNum][2] - AAA;
         int toY = moveList[moveNum][3] - ONE;
-        if((boards[moveNum][fromY][fromX] == WhiteKing 
+        if((boards[moveNum][fromY][fromX] == WhiteKing
             && boards[moveNum][toY][toX] == WhiteRook)
-           || (boards[moveNum][fromY][fromX] == BlackKing 
+           || (boards[moveNum][fromY][fromX] == BlackKing
                && boards[moveNum][toY][toX] == BlackRook)) {
          if(toX > fromX) SendToProgram("O-O\n", cps);
          else SendToProgram("O-O-O\n", cps);
@@ -4292,7 +4613,7 @@ AlphaRank(char *move, int n)
         fprintf(debugFP, "alphaRank(%s,%d)\n", move, n);
     }
 
-    if(move[1]=='*' && 
+    if(move[1]=='*' &&
        move[2]>='0' && move[2]<='9' &&
        move[3]>='a' && move[3]<='x'    ) {
         move[1] = '@';
@@ -4340,7 +4661,7 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
      ChessMove *moveType;
      int *fromX, *fromY, *toX, *toY;
      char *promoChar;
-{       
+{
     if (appData.debugMode) {
         fprintf(debugFP, "move to parse: %s\n", move);
     }
@@ -4566,7 +4887,7 @@ int put(Board board, int pieceType, int rank, int n, int shade)
                        board[rank][i] = (ChessSquare) pieceType;
                        squaresLeft[((i-BOARD_LEFT)&1) + 1]--;
                        squaresLeft[ANY]--;
-                       piecesLeft[pieceType]--; 
+                       piecesLeft[pieceType]--;
                        return i;
                }
        }
@@ -4694,7 +5015,7 @@ int SetCharTable( char *table, const char * map )
 {
     int result = FALSE; int NrPieces;
 
-    if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare 
+    if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare
                     && NrPieces >= 12 && !(NrPieces&1)) {
         int i; /* [HGM] Accept even length from 12 to 34 */
 
@@ -4714,30 +5035,30 @@ int SetCharTable( char *table, const char * map )
 
 void Prelude(Board board)
 {      // [HGM] superchess: random selection of exo-pieces
-       int i, j, k; ChessSquare p; 
+       int i, j, k; ChessSquare p;
        static ChessSquare exoPieces[4] = { WhiteAngel, WhiteMarshall, WhiteSilver, WhiteLance };
 
        GetPositionNumber(); // use FRC position number
 
        if(appData.pieceToCharTable != NULL) { // select pieces to participate from given char table
            SetCharTable(pieceToChar, appData.pieceToCharTable);
-           for(i=(int)WhiteQueen+1, j=0; i<(int)WhiteKing && j<4; i++) 
+           for(i=(int)WhiteQueen+1, j=0; i<(int)WhiteKing && j<4; i++)
                if(PieceToChar((ChessSquare)i) != '.') exoPieces[j++] = (ChessSquare) i;
        }
 
-       j = seed%4;                 seed /= 4; 
+       j = seed%4;                 seed /= 4;
        p = board[0][BOARD_LEFT+j];   board[0][BOARD_LEFT+j] = EmptySquare; k = PieceToNumber(p);
        board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;
        board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;
-       j = seed%3 + (seed%3 >= j); seed /= 3; 
+       j = seed%3 + (seed%3 >= j); seed /= 3;
        p = board[0][BOARD_LEFT+j];   board[0][BOARD_LEFT+j] = EmptySquare; k = PieceToNumber(p);
        board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;
        board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;
-       j = seed%3;                 seed /= 3; 
+       j = seed%3;                 seed /= 3;
        p = board[0][BOARD_LEFT+j+5]; board[0][BOARD_LEFT+j+5] = EmptySquare; k = PieceToNumber(p);
        board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;
        board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;
-       j = seed%2 + (seed%2 >= j); seed /= 2; 
+       j = seed%2 + (seed%2 >= j); seed /= 2;
        p = board[0][BOARD_LEFT+j+5]; board[0][BOARD_LEFT+j+5] = EmptySquare; k = PieceToNumber(p);
        board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;
        board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;
@@ -4775,7 +5096,7 @@ InitPosition(redraw)
         castlingRank[3] = castlingRank[4] = castlingRank[5] = BOARD_HEIGHT-1;
     }
 
-    
+
     /* [HGM] logic here is completely changed. In stead of full positions */
     /* the initialized data only consist of the two backranks. The switch */
     /* selects which one we will use, which is than copied to the Board   */
@@ -4802,7 +5123,7 @@ InitPosition(redraw)
     case VariantShatranj:
       pieces = ShatranjArray;
       nrCastlingRights = 0;
-      SetCharTable(pieceToChar, "PN.R.QB...Kpn.r.qb...k"); 
+      SetCharTable(pieceToChar, "PN.R.QB...Kpn.r.qb...k");
       break;
     case VariantMakruk:
       pieces = makrukArray;
@@ -4818,17 +5139,17 @@ InitPosition(redraw)
     case VariantCapablanca:
       pieces = CapablancaArray;
       gameInfo.boardWidth = 10;
-      SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack"); 
+      SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack");
       break;
     case VariantGothic:
       pieces = GothicArray;
       gameInfo.boardWidth = 10;
-      SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack"); 
+      SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack");
       break;
     case VariantJanus:
       pieces = JanusArray;
       gameInfo.boardWidth = 10;
-      SetCharTable(pieceToChar, "PNBRQ..JKpnbrq..jk"); 
+      SetCharTable(pieceToChar, "PNBRQ..JKpnbrq..jk");
       nrCastlingRights = 6;
         initialPosition[CASTLING][0] = initialRights[0] = BOARD_RGHT-1;
         initialPosition[CASTLING][1] = initialRights[1] = BOARD_LEFT;
@@ -4840,14 +5161,14 @@ InitPosition(redraw)
     case VariantFalcon:
       pieces = FalconArray;
       gameInfo.boardWidth = 10;
-      SetCharTable(pieceToChar, "PNBRQ.............FKpnbrq.............fk"); 
+      SetCharTable(pieceToChar, "PNBRQ.............FKpnbrq.............fk");
       break;
     case VariantXiangqi:
       pieces = XiangqiArray;
       gameInfo.boardWidth  = 9;
       gameInfo.boardHeight = 10;
       nrCastlingRights = 0;
-      SetCharTable(pieceToChar, "PH.R.AE..K.C.ph.r.ae..k.c."); 
+      SetCharTable(pieceToChar, "PH.R.AE..K.C.ph.r.ae..k.c.");
       break;
     case VariantShogi:
       pieces = ShogiArray;
@@ -4855,7 +5176,7 @@ InitPosition(redraw)
       gameInfo.boardHeight = 9;
       gameInfo.holdingsSize = 7;
       nrCastlingRights = 0;
-      SetCharTable(pieceToChar, "PNBRLS...G.++++++Kpnbrls...g.++++++k"); 
+      SetCharTable(pieceToChar, "PNBRLS...G.++++++Kpnbrls...g.++++++k");
       break;
     case VariantCourier:
       pieces = CourierArray;
@@ -4865,7 +5186,7 @@ InitPosition(redraw)
       break;
     case VariantKnightmate:
       pieces = KnightmateArray;
-      SetCharTable(pieceToChar, "P.BRQ.....M.........K.p.brq.....m.........k."); 
+      SetCharTable(pieceToChar, "P.BRQ.....M.........K.p.brq.....m.........k.");
       break;
     case VariantFairy:
       pieces = fairyArray;
@@ -4886,7 +5207,7 @@ InitPosition(redraw)
     case VariantCrazyhouse:
     case VariantBughouse:
       pieces = FIDEArray;
-      SetCharTable(pieceToChar, "PNBRQ.......~~~~Kpnbrq.......~~~~k"); 
+      SetCharTable(pieceToChar, "PNBRQ.......~~~~Kpnbrq.......~~~~k");
       gameInfo.holdingsSize = 5;
       break;
     case VariantWildCastle:
@@ -4940,7 +5261,7 @@ InitPosition(redraw)
         initialPosition[BOARD_HEIGHT-pawnRow-1][j] = BlackPawn;
         if(gameInfo.variant == VariantXiangqi) {
             if(j&1) {
-                initialPosition[pawnRow][j] = 
+                initialPosition[pawnRow][j] =
                 initialPosition[BOARD_HEIGHT-pawnRow-1][j] = EmptySquare;
                 if(j==BOARD_LEFT+1 || j>=BOARD_RGHT-2) {
                    initialPosition[2][j] = WhiteCannon;
@@ -4965,7 +5286,6 @@ InitPosition(redraw)
         /*       This sets default castling rights from none to normal corners   */
         /* Variants with other castling rights must set them themselves above    */
         nrCastlingRights = 6;
-       
         initialPosition[CASTLING][0] = initialRights[0] = BOARD_RGHT-1;
         initialPosition[CASTLING][1] = initialRights[1] = BOARD_LEFT;
         initialPosition[CASTLING][2] = initialRights[2] = BOARD_WIDTH>>1;
@@ -4997,7 +5317,6 @@ InitPosition(redraw)
     }
 
     CopyBoard(boards[0], initialPosition);
-
     if(oldx != gameInfo.boardWidth ||
        oldy != gameInfo.boardHeight ||
        oldh != gameInfo.holdingsWidth
@@ -5010,10 +5329,13 @@ InitPosition(redraw)
        gameInfo.variant == VariantFalcon
 #endif
                                          )
+      {
             InitDrawingSizes(-2 ,0);
+      }
 
     if (redraw)
       DrawPosition(TRUE, boards[currentMove]);
+
 }
 
 void
@@ -5022,7 +5344,7 @@ SendBoard(cps, moveNum)
      int moveNum;
 {
     char message[MSG_SIZ];
-    
+
     if (cps->useSetboard) {
       char* fen = PositionToFEN(moveNum, cps->fenOverride);
       sprintf(message, "setboard %s\n", fen);
@@ -5043,7 +5365,7 @@ SendBoard(cps, moveNum)
        bp = &boards[moveNum][i][BOARD_LEFT];
         for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {
          if ((int) *bp < (int) BlackPawn) {
-           sprintf(message, "%c%c%c\n", PieceToChar(*bp), 
+           sprintf(message, "%c%c%c\n", PieceToChar(*bp),
                     AAA + j, ONE + i);
             if(message[0] == '+' || message[0] == '~') {
                 sprintf(message, "%c%c%c+\n",
@@ -5058,7 +5380,7 @@ SendBoard(cps, moveNum)
          }
        }
       }
-    
+
       SendToProgram("c\n", cps);
       for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
        bp = &boards[moveNum][i][BOARD_LEFT];
@@ -5080,7 +5402,7 @@ SendBoard(cps, moveNum)
          }
        }
       }
-    
+
       SendToProgram(".\n", cps);
     }
     setboardSpoiledMachineBlack = 0; /* [HGM] assume WB 4.2.7 already solves this after sending setboard */
@@ -5251,11 +5573,11 @@ OKToStartUserMove(x, y)
        if (!white_piece && WhiteOnMove(currentMove)) {
            DisplayMoveError(_("It is White's turn"));
            return FALSE;
-       }           
+       }
        if (white_piece && !WhiteOnMove(currentMove)) {
            DisplayMoveError(_("It is Black's turn"));
            return FALSE;
-       }           
+       }
        if (cmailMsgLoaded && (currentMove < cmailOldMove)) {
            /* Editing correspondence game history */
            /* Could disallow this or prompt for confirmation */
@@ -5272,16 +5594,16 @@ OKToStartUserMove(x, y)
            }
        }
        break;
-       
+
       case Training:
        if (!white_piece && WhiteOnMove(currentMove)) {
            DisplayMoveError(_("It is White's turn"));
            return FALSE;
-       }           
+       }
        if (white_piece && !WhiteOnMove(currentMove)) {
            DisplayMoveError(_("It is Black's turn"));
            return FALSE;
-       }           
+       }
        break;
 
       default:
@@ -5297,6 +5619,55 @@ OKToStartUserMove(x, y)
     return TRUE;
 }
 
+Boolean
+OnlyMove(int *x, int *y) {
+    DisambiguateClosure cl;
+    if (appData.zippyPlay) return FALSE;
+    switch(gameMode) {
+      case MachinePlaysBlack:
+      case IcsPlayingWhite:
+      case BeginningOfGame:
+       if(!WhiteOnMove(currentMove)) return FALSE;
+       break;
+      case MachinePlaysWhite:
+      case IcsPlayingBlack:
+       if(WhiteOnMove(currentMove)) return FALSE;
+       break;
+      default:
+       return FALSE;
+    }
+    cl.pieceIn = EmptySquare; 
+    cl.rfIn = *y;
+    cl.ffIn = *x;
+    cl.rtIn = -1;
+    cl.ftIn = -1;
+    cl.promoCharIn = NULLCHAR;
+    Disambiguate(boards[currentMove], PosFlags(currentMove), &cl);
+    if(cl.kind == NormalMove) {
+      fromX = cl.ff;
+      fromY = cl.rf;
+      *x = cl.ft;
+      *y = cl.rt;
+      return TRUE;
+    }
+    if(cl.kind != ImpossibleMove) return FALSE;
+    cl.pieceIn = EmptySquare;
+    cl.rfIn = -1;
+    cl.ffIn = -1;
+    cl.rtIn = *y;
+    cl.ftIn = *x;
+    cl.promoCharIn = NULLCHAR;
+    Disambiguate(boards[currentMove], PosFlags(currentMove), &cl);
+    if(cl.kind == NormalMove) {
+      fromX = cl.ff;
+      fromY = cl.rf;
+      *x = cl.ft;
+      *y = cl.rt;
+      return TRUE;
+    }
+    return FALSE;
+}
+
 FILE *lastLoadGameFP = NULL, *lastLoadPositionFP = NULL;
 int lastLoadGameNumber = 0, lastLoadPositionNumber = 0;
 int lastLoadGameUseList = FALSE;
@@ -5383,7 +5754,7 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
                premoveFromY = fromY;
                premovePromoChar = promoChar;
                gotPremove = 1;
-               if (appData.debugMode) 
+               if (appData.debugMode)
                    fprintf(debugFP, "Got premove: fromX %d,"
                            "fromY %d, toX %d, toY %d\n",
                            fromX, fromY, toX, toY);
@@ -5404,7 +5775,7 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
                premoveFromY = fromY;
                premovePromoChar = promoChar;
                gotPremove = 1;
-               if (appData.debugMode) 
+               if (appData.debugMode)
                    fprintf(debugFP, "Got premove: fromX %d,"
                            "fromY %d, toX %d, toY %d\n",
                            fromX, fromY, toX, toY);
@@ -5421,6 +5792,7 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
           click-click move is possible */
        if (toX == -2 || toY == -2) {
            boards[0][fromY][fromX] = EmptySquare;
+           rightsBoard[fromY][fromX] = 0;
            return AmbiguousMove;
        } else if (toX >= 0 && toY >= 0) {
            boards[0][toY][toX] = boards[0][fromY][fromX];
@@ -5437,6 +5809,7 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
                }
            } else
            boards[0][fromY][fromX] = EmptySquare;
+           rightsBoard[fromY][fromX] = rightsBoard[toY][toX] = 0;
            return AmbiguousMove;
        }
         return ImpossibleMove;
@@ -5447,7 +5820,7 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
     pup = boards[currentMove][toY][toX];
 
     /* [HGM] If move started in holdings, it means a drop */
-    if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { 
+    if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) {
          if( pup != EmptySquare ) return ImpossibleMove;
          if(appData.testLegality) {
              /* it would be more logical if LegalityTest() also figured out
@@ -5461,8 +5834,7 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
          return WhiteDrop; /* Not needed to specify white or black yet */
     }
 
-    userOfferedDraw = FALSE;
-       
+
     /* [HGM] always test for legality, to get promotion info */
     moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
                                          fromY, fromX, toY, toX, promoChar);
@@ -5491,42 +5863,55 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
      int fromX, fromY, toX, toY;
      /*char*/int promoChar;
 {
-    char *bookHit = 0;
+  char *bookHit = 0;
 
-    if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && promoChar != NULLCHAR) { 
-       // [HGM] superchess: suppress promotions to non-available piece
-       int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));
-       if(WhiteOnMove(currentMove)) {
-           if(!boards[currentMove][k][BOARD_WIDTH-2]) return 0;
-       } else {
-           if(!boards[currentMove][BOARD_HEIGHT-1-k][1]) return 0;
+  if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && promoChar != NULLCHAR)
+    {
+      // [HGM] superchess: suppress promotions to non-available piece
+      int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));
+      if(WhiteOnMove(currentMove))
+       {
+         if(!boards[currentMove][k][BOARD_WIDTH-2])
+           return 0;
+       }
+      else
+       {
+         if(!boards[currentMove][BOARD_HEIGHT-1-k][1])
+           return 0;
        }
     }
-
-    /* [HGM] <popupFix> kludge to avoid having to know the exact promotion
-       move type in caller when we know the move is a legal promotion */
-    if(moveType == NormalMove && promoChar)
-        moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);
-
-    /* [HGM] convert drag-and-drop piece drops to standard form */
-    if( (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && fromY != DROP_RANK ){
-         moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop;
-          if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", 
-               moveType, currentMove, fromX, fromY, boards[currentMove][fromY][fromX]);
-          // holdings might not be sent yet in ICS play; we have to figure out which piece belongs here
-          if(fromX == 0) fromY = BOARD_HEIGHT-1 - fromY; // black holdings upside-down
-          fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings
-          while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; 
-         fromY = DROP_RANK;
+  
+  /* [HGM] <popupFix> kludge to avoid having to know the exact promotion
+     move type in caller when we know the move is a legal promotion */
+  if(moveType == NormalMove && promoChar)
+    moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);
+  
+  /* [HGM] <popupFix> kludge to avoid having to know the exact promotion
+     move type in caller when we know the move is a legal promotion */
+  if(moveType == NormalMove && promoChar)
+    moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);
+  
+  /* [HGM] convert drag-and-drop piece drops to standard form */
+  if( (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && fromY != DROP_RANK )
+    {
+      moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop;
+      if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", 
+                                   moveType, currentMove, fromX, fromY, boards[currentMove][fromY][fromX]);
+      // holdings might not be sent yet in ICS play; we have to figure out which piece belongs here
+      if(fromX == 0) fromY = BOARD_HEIGHT-1 - fromY; // black holdings upside-down
+      fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings
+      while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; 
+      fromY = DROP_RANK;
     }
-
-    /* [HGM] <popupFix> The following if has been moved here from
-       UserMoveEvent(). Because it seemed to belong here (why not allow
-       piece drops in training games?), and because it can only be
-       performed after it is known to what we promote. */
-    if (gameMode == Training) {
+  
+  /* [HGM] <popupFix> The following if has been moved here from
+     UserMoveEvent(). Because it seemed to belong here (why not allow
+     piece drops in training games?), and because it can only be
+     performed after it is known to what we promote. */
+  if (gameMode == Training) 
+    {
       /* compare the move played on the board to the next move in the
-       * game. If they match, display the move and the opponent's response. 
+       * game. If they match, display the move and the opponent's response.
        * If they don't match, display an error message.
        */
       int saveAnimate;
@@ -5534,28 +5919,32 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
       CopyBoard(testBoard, boards[currentMove]);
       ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard);
 
-      if (CompareBoards(testBoard, boards[currentMove+1])) {
-       ForwardInner(currentMove+1);
+      if (CompareBoards(testBoard, boards[currentMove+1]))
+       {
+         ForwardInner(currentMove+1);
 
-       /* Autoplay the opponent's response.
-        * if appData.animate was TRUE when Training mode was entered,
-        * the response will be animated.
-        */
-       saveAnimate = appData.animate;
-       appData.animate = animateTraining;
-       ForwardInner(currentMove+1);
-       appData.animate = saveAnimate;
-
-       /* check for the end of the game */
-       if (currentMove >= forwardMostMove) {
-         gameMode = PlayFromGameFile;
-         ModeHighlight();
-         SetTrainingModeOff();
-         DisplayInformation(_("End of game"));
+         /* Autoplay the opponent's response.
+          * if appData.animate was TRUE when Training mode was entered,
+          * the response will be animated.
+          */
+         saveAnimate = appData.animate;
+         appData.animate = animateTraining;
+         ForwardInner(currentMove+1);
+         appData.animate = saveAnimate;
+
+         /* check for the end of the game */
+         if (currentMove >= forwardMostMove)
+           {
+             gameMode = PlayFromGameFile;
+             ModeHighlight();
+             SetTrainingModeOff();
+             DisplayInformation(_("End of game"));
+           }
+       }
+      else
+       {
+         DisplayError(_("Incorrect move"), 0);
        }
-      } else {
-       DisplayError(_("Incorrect move"), 0);
-      }
       return 1;
     }
 
@@ -5577,30 +5966,46 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
 
   MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/
 
-  if (gameMode == BeginningOfGame) {
-    if (appData.noChessProgram) {
-      gameMode = EditGame;
-      SetGameInfo();
-    } else {
-      char buf[MSG_SIZ];
-      gameMode = MachinePlaysBlack;
-      StartClocks();
-      SetGameInfo();
-      sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
-      DisplayTitle(buf);
-      if (first.sendName) {
-       sprintf(buf, "name %s\n", gameInfo.white);
-       SendToProgram(buf, &first);
-      }
-      StartClocks();
+
+ if(Adjudicate(NULL)) return 1; // [HGM] adjudicate: take care of automtic game end
+
+if (gameMode == BeginningOfGame)
+    {
+      if (appData.noChessProgram)
+       {
+         gameMode = EditGame;
+         SetGameInfo();
+       }
+      else
+       {
+         char buf[MSG_SIZ];
+         gameMode = MachinePlaysBlack;
+         StartClocks();
+         SetGameInfo();
+         sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
+         DisplayTitle(buf);
+         if (first.sendName)
+           {
+             sprintf(buf, "name %s\n", gameInfo.white);
+             SendToProgram(buf, &first);
+           }
+         StartClocks();
+       }
+      ModeHighlight();
+
     }
-    ModeHighlight();
-  }
 
   /* Relay move to ICS or chess engine */
+
   if (appData.icsActive) {
     if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
        gameMode == IcsExamining) {
+      if(userOfferedDraw && (signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) {
+        SendToICS(ics_prefix); // [HGM] drawclaim: send caim and move on one line for FICS
+       SendToICS("draw ");
+        SendMoveToICS(moveType, fromX, fromY, toX, toY);
+      }
+      // also send plain move, in case ICS does not understand atomic claims
       SendMoveToICS(moveType, fromX, fromY, toX, toY);
       ics_user_moved = 1;
     }
@@ -5618,51 +6023,57 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
     if (currentMove == cmailOldMove + 1) {
       cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE;
     }
-  }
+    }
 
   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
 
-  switch (gameMode) {
-  case EditGame:
-    switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) {
-    case MT_NONE:
-    case MT_CHECK:
+  switch (gameMode) 
+    {
+    case EditGame:
+      switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) 
+       {
+       case MT_NONE:
+       case MT_CHECK:
+         break;
+       case MT_CHECKMATE:
+       case MT_STAINMATE:
+         if (WhiteOnMove(currentMove)) {
+           GameEnds(BlackWins, "Black mates", GE_PLAYER);
+         } else {
+           GameEnds(WhiteWins, "White mates", GE_PLAYER);
+         }
+         break;
+       case MT_STALEMATE:
+         GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);
+         break;
+       }
       break;
-    case MT_CHECKMATE:
-    case MT_STAINMATE:
-      if (WhiteOnMove(currentMove)) {
-       GameEnds(BlackWins, "Black mates", GE_PLAYER);
-      } else {
-       GameEnds(WhiteWins, "White mates", GE_PLAYER);
-      }
+      
+    case MachinePlaysBlack:
+    case MachinePlaysWhite:
+      /* disable certain menu options while machine is thinking */
+      SetMachineThinkingEnables();
       break;
-    case MT_STALEMATE:
-      GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);
+      
+    default:
       break;
     }
-    break;
-    
-  case MachinePlaysBlack:
-  case MachinePlaysWhite:
-    /* disable certain menu options while machine is thinking */
-    SetMachineThinkingEnables();
-    break;
-
-  default:
-    break;
-  }
-
-  if(bookHit) { // [HGM] book: simulate book reply
+  userOfferedDraw = FALSE; // [HGM] drawclaim: after move made, and tested for claimable draw
+       
+  if(bookHit)
+    { // [HGM] book: simulate book reply
        static char bookMove[MSG_SIZ]; // a bit generous?
 
-       programStats.nodes = programStats.depth = programStats.time = 
+
+      programStats.nodes = programStats.depth = programStats.time =
        programStats.score = programStats.got_only_move = 0;
-       sprintf(programStats.movelist, "%s (xbook)", bookHit);
+      sprintf(programStats.movelist, "%s (xbook)", bookHit);
+
+      strcpy(bookMove, "move ");
+      strcat(bookMove, bookHit);
+      HandleMachineMove(bookMove, &first);
+    }
 
-       strcpy(bookMove, "move ");
-       strcat(bookMove, bookHit);
-       HandleMachineMove(bookMove, &first);
-  }
   return 1;
 }
 
@@ -5678,14 +6089,76 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar)
        slip a promotion popup in between. But that it always needs two
        calls, to the first part, (now called UserMoveTest() ), and to
        FinishMove if the first part succeeded. Calls that do not need
-       to do anything in between, can call this routine the old way. 
+       to do anything in between, can call this routine the old way.
     */
-    ChessMove moveType = UserMoveTest(fromX, fromY, toX, toY, promoChar, FALSE);
-if(appData.debugMode) fprintf(debugFP, "moveType 4 = %d, promochar = %x\n", moveType, promoChar);
-    if(moveType == AmbiguousMove)
-       DrawPosition(FALSE, boards[currentMove]);
-    else if(moveType != ImpossibleMove && moveType != Comment)
-        FinishMove(moveType, fromX, fromY, toX, toY, promoChar);
+  ChessMove moveType = UserMoveTest(fromX, fromY, toX, toY, promoChar, FALSE);
+  if(appData.debugMode) fprintf(debugFP, "moveType 4 = %d, promochar = %x\n", moveType, promoChar);
+  if(moveType == AmbiguousMove)
+    DrawPosition(FALSE, boards[currentMove]);
+  else if(moveType != ImpossibleMove && moveType != Comment)
+    FinishMove(moveType, fromX, fromY, toX, toY, promoChar);
+}
+
+int hTab[(int)EmptySquare/2+1] = { 1,1,1,1,1,1,2,1,2,3,2,3,3,3,2,3,4,3,3,4,4,3,4 };
+int wTab[(int)EmptySquare/2+1] = { 1,1,2,3,4,5,3,7,4,3,5,4,4,5,7,5,4,6,6,5,5,7,6 };
+Board promoBoard;
+int promotionChoice = 0;
+
+void
+PiecePopUp(int x, int y)
+{
+    int i, j, h, w, nWhite=0, nBlack=0;
+    ChessSquare list[EmptySquare];
+    for(i=0; i<EmptySquare/2; i++) {
+       if(PieceToChar(i) != '.') list[nWhite++] = i;
+       if(PieceToChar(i+EmptySquare/2) != '.') list[EmptySquare - ++nBlack] = i + EmptySquare/2;
+    }
+    CopyBoard(promoBoard, boards[currentMove]);
+    for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++) promoBoard[i][j] = EmptySquare;
+    j = nWhite + nBlack + 1;
+    h = sqrt((j+1)/2 + 1.); w = (j+h-1)/h;
+    if(w>BOARD_RGHT-BOARD_LEFT) { w = BOARD_RGHT - BOARD_LEFT; h = (j+w-1)/w; }
+    for(i=0; i<nWhite; i++) promoBoard[i/w][BOARD_LEFT+i%w] = list[nWhite-1-i];
+    if(h==2 && nWhite == nBlack)
+       for(i=0; i<nWhite; i++) promoBoard[1][BOARD_LEFT+i%w] = list[EmptySquare-nBlack+i];
+    else
+       for(i=0; i<nBlack; i++) promoBoard[h-1-i/w][BOARD_LEFT+w-1-i%w] = list[EmptySquare-nBlack+i];
+    promotionChoice = 3;
+    ClearHighlights();
+    PromoDialog(h, w, promoBoard, TRUE, _("Select piece:"), x, y);
+}
+
+void
+PromoPopUp(ChessSquare piece)
+{   // determine the layout of the piece-choice dialog
+    int w, h, i, j, nr;
+    ChessSquare list[EmptySquare];
+
+    for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++) promoBoard[i][j] = EmptySquare;
+    if(gameInfo.variant == VariantShogi) {
+       // non-Pawn promotes; must be shogi
+       h = 1; w = 1; promoBoard[0][BOARD_LEFT+0] = piece;
+       if(PieceToChar(PROMOTED piece) != '.') {
+           // promoted version is enabled
+           w = 2; promoBoard[0][BOARD_LEFT+1] = PROMOTED piece;
+       }
+    } else {
+       // Pawn, promotes to any enabled other piece
+       h = 1; w = nr = 0;
+       for(i=1; i<EmptySquare/2; i++) {
+           if(PieceToChar(piece+i) != '.' 
+          && PieceToChar(piece + i) != '~' // suppress bughouse true pieces
+                                                       ) {
+               list[w++] = piece+i; nr++;
+           }
+       }
+       if(appData.testLegality && gameInfo.variant != VariantSuicide
+                       && gameInfo.variant != VariantGiveaway) nr--,w--; // remove King
+       h = hTab[nr]; w = wTab[nr]; // factorize with nice ratio
+       for(i=0; i < nr; i++) promoBoard[i/w][BOARD_LEFT+i%w] = list[i]; // layout
+    }
+    promotionChoice = 2; // wait for click on board
+    PromoDialog(h, w, promoBoard, FALSE, _("Promote to:"), -1, -1);
 }
 
 void
@@ -5729,9 +6202,15 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
 {
     int x, y;
     Boolean saveAnimate;
-    static int second = 0, promotionChoice = 0;
+    static int second = 0;
     char promoChoice = NULLCHAR;
 
+    if(appData.seekGraph && appData.icsActive && loggedOn &&
+       (gameMode == BeginningOfGame || gameMode == IcsIdle)) {
+       SeekGraphClick(clickType, xPix, yPix, 0);
+       return;
+    }
+
     if (clickType == Press) ErrorPopDown();
     MarkTargetSquares(1);
 
@@ -5745,22 +6224,33 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
     }
 
     if(promotionChoice) { // we are waiting for a click to indicate promotion piece
+       ChessSquare p = EmptySquare; Boolean inHoldings;
+       if(promotionChoice == 3) {
+           if(clickType == Press) EditPositionMenuEvent(promoBoard[y][x], fromX, fromY);
+           else if(clickType == Release) promotionChoice = 0;
+           fromX = fromY = -1;
+           return;
+       }
        if(clickType == Release) return; // ignore upclick of click-click destination
-       promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
        if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
-       if(gameInfo.holdingsWidth && 
+       inHoldings = gameInfo.holdingsWidth &&
                (WhiteOnMove(currentMove) 
                        ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
-                       : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
+                       : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1);
            // click in right holdings, for determining promotion piece
-           ChessSquare p = boards[currentMove][y][x];
+       if(promotionChoice == 1 && inHoldings || promotionChoice == 2 && x >= BOARD_LEFT && x < BOARD_RGHT) {
+           p = promoBoard[y][x];
            if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
            if(p != EmptySquare) {
-               FinishMove(NormalMove, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
+               char promoChar = PieceToChar(p);
+               if(gameInfo.variant == VariantShogi && promoChar != '+') promoChar = '=';
+               FinishMove(NormalMove, fromX, fromY, toX, toY, ToLower(promoChar));
                fromX = fromY = -1;
+               promotionChoice = 0;
                return;
            }
        }
+       promotionChoice = 0; // only one chance: if click not OK it is interpreted as cancel
        DrawPosition(FALSE, boards[currentMove]);
        return;
     }
@@ -5773,6 +6263,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
        return;
 
     if (fromX == -1) {
+      if(!appData.oneClick || !OnlyMove(&x, &y)) {
        if (clickType == Press) {
            /* First square */
            if (OKToStartUserMove(x, y)) {
@@ -5787,6 +6278,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
            }
        }
        return;
+      }
     }
 
     /* fromX != -1 */
@@ -5882,13 +6374,13 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
             
            if(x == BOARD_LEFT-2 && piece >= BlackPawn) {
                n = PieceToNumber(piece - (int)BlackPawn);
-               if(n > gameInfo.holdingsSize) { n = 0; piece = BlackPawn; }
+               if(n >= gameInfo.holdingsSize) { n = 0; piece = BlackPawn; }
                boards[currentMove][BOARD_HEIGHT-1 - n][0] = piece;
                boards[currentMove][BOARD_HEIGHT-1 - n][1]++;
            } else
            if(x == BOARD_RGHT+1 && piece < BlackPawn) {
                n = PieceToNumber(piece);
-               if(n > gameInfo.holdingsSize) { n = 0; piece = WhitePawn; }
+               if(n >= gameInfo.holdingsSize) { n = 0; piece = WhitePawn; }
                boards[currentMove][n][BOARD_WIDTH-1] = piece;
                boards[currentMove][n][BOARD_WIDTH-2]++;
            }
@@ -5907,18 +6399,18 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
        SetHighlights(fromX, fromY, toX, toY);
        if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
            // [HGM] super: promotion to captured piece selected from holdings
-           ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
-           promotionChoice = TRUE;
+           ChessSquare p = boards[currentMove][fromY][fromX];
+           promotionChoice = 1;
+           CopyBoard(promoBoard, boards[currentMove]);
            // kludge follows to temporarily execute move on display, without promoting yet
-           boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
-           boards[currentMove][toY][toX] = p;
-           DrawPosition(FALSE, boards[currentMove]);
-           boards[currentMove][fromY][fromX] = p; // take back, but display stays
-           boards[currentMove][toY][toX] = q;
+           promoBoard[fromY][fromX] = EmptySquare; // move Pawn to 8th rank
+           promoBoard[toY][toX] = p;
+           DrawPosition(FALSE, promoBoard);
            DisplayMessage("Click in holdings to choose piece", "");
            return;
        }
-       PromotionPopUp();
+       CopyBoard(promoBoard, boards[currentMove]);
+       PromoPopUp(boards[currentMove][fromY][fromX]);
     } else {
        UserMoveEvent(fromX, fromY, toX, toY, promoChoice);
        if (!appData.highlightLastMove || gotPremove) ClearHighlights();
@@ -5932,6 +6424,78 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
     }
 }
 
+int RightClick(ClickType action, int x, int y, int *xx, int *yy)
+{   // front-end-free part taken out of PieceMenuPopup
+    int whichMenu; int xSqr, ySqr;
+
+    if(seekGraphUp) { // [HGM] seekgraph
+       if(action == Press)   SeekGraphClick(Press, x, y, 2); // 2 indicates right-click: no pop-down on miss
+       if(action == Release) SeekGraphClick(Release, x, y, 2); // and no challenge on hit
+       return -2;
+    }
+
+    xSqr = EventToSquare(x, BOARD_WIDTH);
+    ySqr = EventToSquare(y, BOARD_HEIGHT);
+    if (flipView)
+      xSqr = BOARD_WIDTH - 1 - xSqr;
+    else
+      ySqr = BOARD_HEIGHT - 1 - ySqr;
+    if(promotionChoice == 3 && action == Release) {
+       EditPositionMenuEvent(promoBoard[ySqr][xSqr], fromX, fromY);
+       fromX = fromY = -1;
+       promotionChoice = 0;
+       return -1;
+    }
+    if (action == Release) UnLoadPV(); // [HGM] pv
+    if (action != Press) return -2; // return code to be ignored
+    switch (gameMode) {
+      case IcsExamining:
+       if(xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return -1;
+      case EditPosition:
+       if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1;
+       if (xSqr < 0 || ySqr < 0) return -1;
+       whichMenu = 0; // edit-position menu
+       break;
+      case IcsObserving:
+       if(!appData.icsEngineAnalyze) return -1;
+      case IcsPlayingWhite:
+      case IcsPlayingBlack:
+       if(!appData.zippyPlay) goto noZip;
+      case AnalyzeMode:
+      case AnalyzeFile:
+      case MachinePlaysWhite:
+      case MachinePlaysBlack:
+      case TwoMachinesPlay: // [HGM] pv: use for showing PV
+       if (!appData.dropMenu) {
+         LoadPV(x, y);
+         return 2; // flag front-end to grab mouse events
+       }
+       if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
+           gameMode == AnalyzeFile || gameMode == IcsObserving) return -1;
+      case EditGame:
+      noZip:
+       if (xSqr < 0 || ySqr < 0) return -1;
+       if (!appData.dropMenu || appData.testLegality &&
+           gameInfo.variant != VariantBughouse &&
+           gameInfo.variant != VariantCrazyhouse) return -1;
+       whichMenu = 1; // drop menu
+       break;
+      default:
+       return -1;
+    }
+
+    if (((*xx = xSqr) < 0) ||
+       ((*yy = ySqr) < 0)) {
+       *xx = *yy = -1;
+       return -1;
+    }
+
+    fromX = *xx; fromY = *yy;
+    if(whichMenu == 0) { PiecePopUp(x, y); return -1; } // suppress EditPosition menu
+
+    return whichMenu;
+}
+
 void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats )
 {
 //    char * hint = lastHint;
@@ -5958,308 +6522,19 @@ void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cp
     SetProgramStats( &stats );
 }
 
-char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial)
-{   // [HGM] book: this routine intercepts moves to simulate book replies
-    char *bookHit = NULL;
-
-    //first determine if the incoming move brings opponent into his book
-    if(appData.usePolyglotBook && (cps == &first ? !appData.firstHasOwnBookUCI : !appData.secondHasOwnBookUCI))
-       bookHit = ProbeBook(moveNr+1, appData.polyglotBook); // returns move
-    if(appData.debugMode) fprintf(debugFP, "book hit = %s\n", bookHit ? bookHit : "(NULL)");
-    if(bookHit != NULL && !cps->bookSuspend) {
-       // make sure opponent is not going to reply after receiving move to book position
-       SendToProgram("force\n", cps);
-       cps->bookSuspend = TRUE; // flag indicating it has to be restarted
-    }
-    if(!initial) SendMoveToProgram(moveNr, cps); // with hit on initial position there is no move
-    // now arrange restart after book miss
-    if(bookHit) {
-       // after a book hit we never send 'go', and the code after the call to this routine
-       // has '&& !bookHit' added to suppress potential sending there (based on 'firstMove').
-       char buf[MSG_SIZ];
-       if (cps->useUsermove) sprintf(buf, "usermove "); // sorry, no SAN yet :(
-       sprintf(buf, "%s\n", bookHit); // force book move into program supposed to play it
-       SendToProgram(buf, cps);
-       if(!initial) firstMove = FALSE; // normally we would clear the firstMove condition after return & sending 'go'
-    } else if(initial) { // 'go' was needed irrespective of firstMove, and it has to be done in this routine
-       SendToProgram("go\n", cps);
-       cps->bookSuspend = FALSE; // after a 'go' we are never suspended
-    } else { // 'go' might be sent based on 'firstMove' after this routine returns
-       if(cps->bookSuspend && !firstMove) // 'go' needed, and it will not be done after we return
-           SendToProgram("go\n", cps); 
-       cps->bookSuspend = FALSE; // anyhow, we will not be suspended after a miss
-    }
-    return bookHit; // notify caller of hit, so it can take action to send move to opponent
-}
-
-char *savedMessage;
-ChessProgramState *savedState;
-void DeferredBookMove(void)
-{
-       if(savedState->lastPing != savedState->lastPong)
-                   ScheduleDelayedEvent(DeferredBookMove, 10);
-       else
-       HandleMachineMove(savedMessage, savedState);
-}
-
-void
-HandleMachineMove(message, cps)
-     char *message;
-     ChessProgramState *cps;
-{
-    char machineMove[MSG_SIZ], buf1[MSG_SIZ*10], buf2[MSG_SIZ];
-    char realname[MSG_SIZ];
-    int fromX, fromY, toX, toY;
-    ChessMove moveType;
-    char promoChar;
-    char *p;
-    int machineWhite;
-    char *bookHit;
-
-    cps->userError = 0;
-
-FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book hit
-    /*
-     * Kludge to ignore BEL characters
-     */
-    while (*message == '\007') message++;
-
-    /*
-     * [HGM] engine debug message: ignore lines starting with '#' character
-     */
-    if(cps->debug && *message == '#') return;
-
-    /*
-     * Look for book output
-     */
-    if (cps == &first && bookRequested) {
-       if (message[0] == '\t' || message[0] == ' ') {
-           /* Part of the book output is here; append it */
-           strcat(bookOutput, message);
-           strcat(bookOutput, "  \n");
-           return;
-       } else if (bookOutput[0] != NULLCHAR) {
-           /* All of book output has arrived; display it */
-           char *p = bookOutput;
-           while (*p != NULLCHAR) {
-               if (*p == '\t') *p = ' ';
-               p++;
-           }
-           DisplayInformation(bookOutput);
-           bookRequested = FALSE;
-           /* Fall through to parse the current output */
-       }
-    }
-
-    /*
-     * Look for machine move.
-     */
-    if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && strcmp(buf2, "...") == 0) ||
-       (sscanf(message, "%s %s", buf1, machineMove) == 2 && strcmp(buf1, "move") == 0)) 
-    {
-        /* This method is only useful on engines that support ping */
-        if (cps->lastPing != cps->lastPong) {
-         if (gameMode == BeginningOfGame) {
-           /* Extra move from before last new; ignore */
-           if (appData.debugMode) {
-               fprintf(debugFP, "Ignoring extra move from %s\n", cps->which);
-           }
-         } else {
-           if (appData.debugMode) {
-               fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n",
-                       cps->which, gameMode);
-           }
-
-            SendToProgram("undo\n", cps);
-         }
-         return;
-       }
-
-       switch (gameMode) {
-         case BeginningOfGame:
-           /* Extra move from before last reset; ignore */
-           if (appData.debugMode) {
-               fprintf(debugFP, "Ignoring extra move from %s\n", cps->which);
-           }
-           return;
-
-         case EndOfGame:
-         case IcsIdle:
-         default:
-           /* Extra move after we tried to stop.  The mode test is
-              not a reliable way of detecting this problem, but it's
-              the best we can do on engines that don't support ping.
-           */
-           if (appData.debugMode) {
-               fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n",
-                       cps->which, gameMode);
-           }
-           SendToProgram("undo\n", cps);
-           return;
-
-         case MachinePlaysWhite:
-         case IcsPlayingWhite:
-           machineWhite = TRUE;
-           break;
-
-         case MachinePlaysBlack:
-         case IcsPlayingBlack:
-           machineWhite = FALSE;
-           break;
-
-         case TwoMachinesPlay:
-           machineWhite = (cps->twoMachinesColor[0] == 'w');
-           break;
-       }
-       if (WhiteOnMove(forwardMostMove) != machineWhite) {
-           if (appData.debugMode) {
-               fprintf(debugFP,
-                       "Ignoring move out of turn by %s, gameMode %d"
-                       ", forwardMost %d\n",
-                       cps->which, gameMode, forwardMostMove);
-           }
-           return;
-       }
-
-    if (appData.debugMode) { int f = forwardMostMove;
-        fprintf(debugFP, "machine move %d, castling = %d %d %d %d %d %d\n", f,
-                boards[f][CASTLING][0],boards[f][CASTLING][1],boards[f][CASTLING][2],
-                boards[f][CASTLING][3],boards[f][CASTLING][4],boards[f][CASTLING][5]);
-    }
-        if(cps->alphaRank) AlphaRank(machineMove, 4);
-        if (!ParseOneMove(machineMove, forwardMostMove, &moveType,
-                              &fromX, &fromY, &toX, &toY, &promoChar)) {
-           /* Machine move could not be parsed; ignore it. */
-            sprintf(buf1, _("Illegal move \"%s\" from %s machine"),
-                   machineMove, cps->which);
-           DisplayError(buf1, 0);
-            sprintf(buf1, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d",
-                    machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, moveType);
-           if (gameMode == TwoMachinesPlay) {
-             GameEnds(machineWhite ? BlackWins : WhiteWins,
-                       buf1, GE_XBOARD);
-           }
-           return;
-       }
-
-        /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */
-        /* So we have to redo legality test with true e.p. status here,  */
-        /* to make sure an illegal e.p. capture does not slip through,   */
-        /* to cause a forfeit on a justified illegal-move complaint      */
-        /* of the opponent.                                              */
-        if( gameMode==TwoMachinesPlay && appData.testLegality
-            && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */
-                                                              ) {
-           ChessMove moveType;
-           moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),
-                             fromY, fromX, toY, toX, promoChar);
-           if (appData.debugMode) {
-                int i;
-                for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ",
-                    boards[forwardMostMove][CASTLING][i], castlingRank[i]);
-                fprintf(debugFP, "castling rights\n");
-           }
-            if(moveType == IllegalMove) {
-                sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",
-                        machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);
-                GameEnds(machineWhite ? BlackWins : WhiteWins,
-                           buf1, GE_XBOARD);
-               return;
-           } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)
-           /* [HGM] Kludge to handle engines that send FRC-style castling
-              when they shouldn't (like TSCP-Gothic) */
-           switch(moveType) {
-             case WhiteASideCastleFR:
-             case BlackASideCastleFR:
-               toX+=2;
-               currentMoveString[2]++;
-               break;
-             case WhiteHSideCastleFR:
-             case BlackHSideCastleFR:
-               toX--;
-               currentMoveString[2]--;
-               break;
-            default: ; // nothing to do, but suppresses warning of pedantic compilers
-           }
-        }
-       hintRequested = FALSE;
-       lastHint[0] = NULLCHAR;
-       bookRequested = FALSE;
-       /* Program may be pondering now */
-       cps->maybeThinking = TRUE;
-       if (cps->sendTime == 2) cps->sendTime = 1;
-       if (cps->offeredDraw) cps->offeredDraw--;
-
-#if ZIPPY
-       if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) &&
-           first.initDone) {
-         SendMoveToICS(moveType, fromX, fromY, toX, toY);
-         ics_user_moved = 1;
-         if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */
-               char buf[3*MSG_SIZ];
-
-               sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %u nodes, %.0f knps) PV=%s\n",
-                       programStats.score / 100.,
-                       programStats.depth,
-                       programStats.time / 100.,
-                       (unsigned int)programStats.nodes,
-                       (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.),
-                       programStats.movelist);
-               SendToICS(buf);
-if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes);
-         }
-       }
-#endif
-       /* currentMoveString is set as a side-effect of ParseOneMove */
-       strcpy(machineMove, currentMoveString);
-       strcat(machineMove, "\n");
-       strcpy(moveList[forwardMostMove], machineMove);
-
-        /* [AS] Save move info and clear stats for next move */
-        pvInfoList[ forwardMostMove ].score = programStats.score;
-        pvInfoList[ forwardMostMove ].depth = programStats.depth;
-        pvInfoList[ forwardMostMove ].time =  programStats.time; // [HGM] PGNtime: take time from engine stats
-        ClearProgramStats();
-        thinkOutput[0] = NULLCHAR;
-        hiddenThinkOutputState = 0;
-
-       MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
-
-        /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */
-        if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
-            int count = 0;
-
-            while( count < adjudicateLossPlies ) {
-                int score = pvInfoList[ forwardMostMove - count - 1 ].score;
-
-                if( count & 1 ) {
-                    score = -score; /* Flip score for winning side */
-                }
-
-                if( score > adjudicateLossThreshold ) {
-                    break;
-                }
-
-                count++;
-            }
-
-            if( count >= adjudicateLossPlies ) {
-               ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
-
-                GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
-                    "Xboard adjudication", 
-                    GE_XBOARD );
-
-                return;
-            }
-        }
-
-       if( gameMode == TwoMachinesPlay ) {
-         // [HGM] some adjudications useful with buggy engines
-            int k, count = 0; static int bare = 1;
-         if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
-
-
+int
+Adjudicate(ChessProgramState *cps)
+{      // [HGM] some adjudications useful with buggy engines
+       // [HGM] adjudicate: made into separate routine, which now can be called after every move
+       //       In any case it determnes if the game is a claimable draw (filling in EP_STATUS).
+       //       Actually ending the game is now based on the additional internal condition canAdjudicate.
+       //       Only when the game is ended, and the opponent is a computer, this opponent gets the move relayed.
+       int k, count = 0; static int bare = 1;
+       ChessProgramState *engineOpponent = (gameMode == TwoMachinesPlay ? cps->other : (cps ? NULL : &first));
+       Boolean canAdjudicate = !appData.icsActive;
+
+       // most tests only when we understand the game, i.e. legality-checking on, and (for the time being) no piece drops
+       if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
            if( appData.testLegality )
            {   /* [HGM] Some more adjudications for obstinate engines */
                int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0,
@@ -6269,6 +6544,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                ChessMove result;
                char *reason = NULL;
 
+
                 /* Count what is on board. */
                for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)
                {   ChessSquare p = boards[forwardMostMove][i][j];
@@ -6319,12 +6595,13 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                if(gameInfo.variant == VariantAtomic && NrK < 2) {
                    // [HGM] atomic: stm must have lost his King on previous move, as destroying own K is illegal
                     boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // make claimable as if stm is checkmated
-                    if(appData.checkMates) {
-                        SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move
+                    if(canAdjudicate && appData.checkMates) {
+                        if(engineOpponent)
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); // make sure opponent gets move
                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                          GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins, 
                                                        "Xboard adjudication: King destroyed", GE_XBOARD );
-                         return;
+                         return 1;
                     }
                }
 
@@ -6332,24 +6609,26 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                 if( NrW == 1 || NrPieces - NrW == 1) {
                   if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first)
                     boards[forwardMostMove][EP_STATUS] = EP_WINS;  // mark as win, so it becomes claimable
-                    if(appData.checkMates) {
-                        SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move
+                    if(canAdjudicate && appData.checkMates) {
+                        if(engineOpponent)
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); // make sure opponent gets to see move
                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                          GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
                                                        "Xboard adjudication: Bare king", GE_XBOARD );
-                         return;
+                         return 1;
                     }
                  } else
                   if( gameInfo.variant == VariantShatranj && --bare < 0)
                   {    /* bare King */
                        boards[forwardMostMove][EP_STATUS] = EP_WINS; // make claimable as win for stm
-                       if(appData.checkMates) {
+                       if(canAdjudicate && appData.checkMates) {
                            /* but only adjudicate if adjudication enabled */
-                           SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move
+                           if(engineOpponent)
+                             SendMoveToProgram(forwardMostMove-1, engineOpponent); // make sure opponent gets move
                            ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                            GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, 
                                                        "Xboard adjudication: Bare king", GE_XBOARD );
-                           return;
+                           return 1;
                        }
                  }
                 } else bare = 1;
@@ -6404,11 +6683,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                    default:
                        result = (ChessMove) 0;
                }
-                if(appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
+                if(canAdjudicate && appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested
+                   if(engineOpponent)
+                     SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
                    ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                    GameEnds( result, reason, GE_XBOARD );
-                   return;
+                   return 1;
                }
 
                 /* Next absolutely insufficient mating material. */
@@ -6421,13 +6701,15 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                      /* always flag draws, for judging claims */
                      boards[forwardMostMove][EP_STATUS] = EP_INSUF_DRAW;
 
-                     if(appData.materialDraws) {
+                     if(canAdjudicate && appData.materialDraws) {
                          /* but only adjudicate them if adjudication enabled */
-                        SendToProgram("force\n", cps->other); // suppress reply
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see last move */
+                        if(engineOpponent) {
+                          SendToProgram("force\n", engineOpponent); // suppress reply
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see last move */
+                        }
                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                          GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD );
-                         return;
+                         return 1;
                      }
                 }
 
@@ -6438,26 +6720,30 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                    || NrWN==2 || NrBN==2     /* KNNK */
                    || NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */
                   ) ) {
-                     if(--moveCount < 0 && appData.trivialDraws)
+                     if(canAdjudicate && --moveCount < 0 && appData.trivialDraws)
                      {    /* if the first 3 moves do not show a tactical win, declare draw */
-                         SendToProgram("force\n", cps->other); // suppress reply
-                         SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
+                         if(engineOpponent) {
+                           SendToProgram("force\n", engineOpponent); // suppress reply
+                           SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                         }
                           ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                           GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD );
-                          return;
+                          return 1;
                      }
                 } else moveCount = 6;
            }
-         }
+       }
          
-         if (appData.debugMode) { int i;
+       if (appData.debugMode) { int i;
            fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n",
                    forwardMostMove, backwardMostMove, boards[backwardMostMove][EP_STATUS],
                    appData.drawRepeats);
            for( i=forwardMostMove; i>=backwardMostMove; i-- )
              fprintf(debugFP, "%d ep=%d\n", i, (signed char)boards[i][EP_STATUS]);
            
-         }
+       }
+
+       // Repetition draws and 50-move rule can be applied independently of legality testing
 
                 /* Check for rep-draws */
                 count = 0;
@@ -6485,11 +6771,13 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                                 boards[forwardMostMove][CASTLING][4] != boards[k][CASTLING][4] )
                                    rights++;
                         }
-                        if( rights == 0 && ++count > appData.drawRepeats-2
+                        if( canAdjudicate && rights == 0 && ++count > appData.drawRepeats-2
                             && appData.drawRepeats > 1) {
                              /* adjudicate after user-specified nr of repeats */
-                            SendToProgram("force\n", cps->other); // suppress reply
-                            SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
+                            if(engineOpponent) {
+                              SendToProgram("force\n", engineOpponent); // suppress reply
+                              SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                            }
                              ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                             if(gameInfo.variant == VariantXiangqi && appData.testLegality) { 
                                // [HGM] xiangqi: check for forbidden perpetuals
@@ -6505,7 +6793,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                                if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit
                                    GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
                                           "Xboard adjudication: perpetual checking", GE_XBOARD );
-                                   return;
+                                   return 1;
                                }
                                if(hisPerpetual && !ourPerpetual)   // he is checking us, but did not repeat yet
                                    break; // (or we would have caught him before). Abort repetition-checking loop.
@@ -6516,7 +6804,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                                    if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit
                                        GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
                                                      "Xboard adjudication: perpetual chasing", GE_XBOARD );
-                                       return;
+                                       return 1;
                                    }
                                    if(hisPerpetual && !ourPerpetual)   // he is chasing us, but did not repeat yet
                                        break; // Abort repetition-checking loop.
@@ -6524,7 +6812,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                                // if neither of us is checking or chasing all the time, or both are, it is draw
                             }
                              GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD );
-                             return;
+                             return 1;
                         }
                         if( rights == 0 && count > 1 ) /* occurred 2 or more times before */
                              boards[forwardMostMove][EP_STATUS] = EP_REP_DRAW;
@@ -6543,12 +6831,14 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                 if( count >= 100)
                          boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW;
                          /* this is used to judge if draw claims are legal */
-                if(appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {
-                        SendToProgram("force\n", cps->other); // suppress reply
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
+                if(canAdjudicate && appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {
+                        if(engineOpponent) {
+                          SendToProgram("force\n", engineOpponent); // suppress reply
+                          SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                        }
                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
                          GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD );
-                         return;
+                         return 1;
                 }
 
                 /* if draw offer is pending, treat it as a draw claim
@@ -6556,7 +6846,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                  * claim draws before making their move to avoid a race
                  * condition occurring after their move
                  */
-                if( cps->other->offeredDraw || cps->offeredDraw ) {
+               if((gameMode == TwoMachinesPlay ? second.offeredDraw : userOfferedDraw) || first.offeredDraw ) {
                          char *p = NULL;
                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_RULE_DRAW)
                              p = "Draw claim: 50-move rule";
@@ -6564,27 +6854,333 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                              p = "Draw claim: 3-fold repetition";
                          if((signed char)boards[forwardMostMove][EP_STATUS] == EP_INSUF_DRAW)
                              p = "Draw claim: insufficient mating material";
-                         if( p != NULL ) {
-                            SendToProgram("force\n", cps->other); // suppress reply
-                            SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
-                             GameEnds( GameIsDrawn, p, GE_XBOARD );
+                         if( p != NULL && canAdjudicate) {
+                            if(engineOpponent) {
+                              SendToProgram("force\n", engineOpponent); // suppress reply
+                              SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                            }
                              ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
-                             return;
+                             GameEnds( GameIsDrawn, p, GE_XBOARD );
+                             return 1;
                          }
                 }
 
-
-               if( appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) {
-                   SendToProgram("force\n", cps->other); // suppress reply
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */
+               if( canAdjudicate && appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) {
+                   if(engineOpponent) {
+                     SendToProgram("force\n", engineOpponent); // suppress reply
+                     SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */
+                   }
                    ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
-
                    GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD );
-
-                   return;
+                   return 1;
                }
+       return 0;
+}
+
+char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial)
+{   // [HGM] book: this routine intercepts moves to simulate book replies
+    char *bookHit = NULL;
+
+    //first determine if the incoming move brings opponent into his book
+    if(appData.usePolyglotBook && (cps == &first ? !appData.firstHasOwnBookUCI : !appData.secondHasOwnBookUCI))
+       bookHit = ProbeBook(moveNr+1, appData.polyglotBook); // returns move
+    if(appData.debugMode) fprintf(debugFP, "book hit = %s\n", bookHit ? bookHit : "(NULL)");
+    if(bookHit != NULL && !cps->bookSuspend) {
+       // make sure opponent is not going to reply after receiving move to book position
+       SendToProgram("force\n", cps);
+       cps->bookSuspend = TRUE; // flag indicating it has to be restarted
+    }
+    if(!initial) SendMoveToProgram(moveNr, cps); // with hit on initial position there is no move
+    // now arrange restart after book miss
+    if(bookHit) {
+       // after a book hit we never send 'go', and the code after the call to this routine
+       // has '&& !bookHit' added to suppress potential sending there (based on 'firstMove').
+       char buf[MSG_SIZ];
+       if (cps->useUsermove) sprintf(buf, "usermove "); // sorry, no SAN yet :(
+       sprintf(buf, "%s\n", bookHit); // force book move into program supposed to play it
+       SendToProgram(buf, cps);
+       if(!initial) firstMove = FALSE; // normally we would clear the firstMove condition after return & sending 'go'
+    } else if(initial) { // 'go' was needed irrespective of firstMove, and it has to be done in this routine
+       SendToProgram("go\n", cps);
+       cps->bookSuspend = FALSE; // after a 'go' we are never suspended
+    } else { // 'go' might be sent based on 'firstMove' after this routine returns
+       if(cps->bookSuspend && !firstMove) // 'go' needed, and it will not be done after we return
+           SendToProgram("go\n", cps); 
+       cps->bookSuspend = FALSE; // anyhow, we will not be suspended after a miss
+    }
+    return bookHit; // notify caller of hit, so it can take action to send move to opponent
+}
+
+char *savedMessage;
+ChessProgramState *savedState;
+void DeferredBookMove(void)
+{
+       if(savedState->lastPing != savedState->lastPong)
+                   ScheduleDelayedEvent(DeferredBookMove, 10);
+       else
+       HandleMachineMove(savedMessage, savedState);
+}
+
+void
+HandleMachineMove(message, cps)
+     char *message;
+     ChessProgramState *cps;
+{
+    char machineMove[MSG_SIZ], buf1[MSG_SIZ*10], buf2[MSG_SIZ];
+    char realname[MSG_SIZ];
+    int fromX, fromY, toX, toY;
+    ChessMove moveType;
+    char promoChar;
+    char *p;
+    int machineWhite;
+    char *bookHit;
+
+    cps->userError = 0;
+
+FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book hit
+    /*
+     * Kludge to ignore BEL characters
+     */
+    while (*message == '\007') message++;
+
+    /*
+     * [HGM] engine debug message: ignore lines starting with '#' character
+     */
+    if(cps->debug && *message == '#') return;
+
+    /*
+     * Look for book output
+     */
+    if (cps == &first && bookRequested) {
+       if (message[0] == '\t' || message[0] == ' ') {
+           /* Part of the book output is here; append it */
+           strcat(bookOutput, message);
+           strcat(bookOutput, "  \n");
+           return;
+       } else if (bookOutput[0] != NULLCHAR) {
+           /* All of book output has arrived; display it */
+           char *p = bookOutput;
+           while (*p != NULLCHAR) {
+               if (*p == '\t') *p = ' ';
+               p++;
+           }
+           DisplayInformation(bookOutput);
+           bookRequested = FALSE;
+           /* Fall through to parse the current output */
+       }
+    }
+
+    /*
+     * Look for machine move.
+     */
+    if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && strcmp(buf2, "...") == 0) ||
+       (sscanf(message, "%s %s", buf1, machineMove) == 2 && strcmp(buf1, "move") == 0))
+    {
+        /* This method is only useful on engines that support ping */
+        if (cps->lastPing != cps->lastPong) {
+         if (gameMode == BeginningOfGame) {
+           /* Extra move from before last new; ignore */
+           if (appData.debugMode) {
+               fprintf(debugFP, "Ignoring extra move from %s\n", cps->which);
+           }
+         } else {
+           if (appData.debugMode) {
+               fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n",
+                       cps->which, gameMode);
+           }
+
+            SendToProgram("undo\n", cps);
+         }
+         return;
+       }
+
+       switch (gameMode) {
+         case BeginningOfGame:
+           /* Extra move from before last reset; ignore */
+           if (appData.debugMode) {
+               fprintf(debugFP, "Ignoring extra move from %s\n", cps->which);
+           }
+           return;
+
+         case EndOfGame:
+         case IcsIdle:
+         default:
+           /* Extra move after we tried to stop.  The mode test is
+              not a reliable way of detecting this problem, but it's
+              the best we can do on engines that don't support ping.
+           */
+           if (appData.debugMode) {
+               fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n",
+                       cps->which, gameMode);
+           }
+           SendToProgram("undo\n", cps);
+           return;
+
+         case MachinePlaysWhite:
+         case IcsPlayingWhite:
+           machineWhite = TRUE;
+           break;
+
+         case MachinePlaysBlack:
+         case IcsPlayingBlack:
+           machineWhite = FALSE;
+           break;
+
+         case TwoMachinesPlay:
+           machineWhite = (cps->twoMachinesColor[0] == 'w');
+           break;
+       }
+       if (WhiteOnMove(forwardMostMove) != machineWhite) {
+           if (appData.debugMode) {
+               fprintf(debugFP,
+                       "Ignoring move out of turn by %s, gameMode %d"
+                       ", forwardMost %d\n",
+                       cps->which, gameMode, forwardMostMove);
+           }
+           return;
+       }
+
+    if (appData.debugMode) { int f = forwardMostMove;
+        fprintf(debugFP, "machine move %d, castling = %d %d %d %d %d %d\n", f,
+                boards[f][CASTLING][0],boards[f][CASTLING][1],boards[f][CASTLING][2],
+                boards[f][CASTLING][3],boards[f][CASTLING][4],boards[f][CASTLING][5]);
+    }
+        if(cps->alphaRank) AlphaRank(machineMove, 4);
+        if (!ParseOneMove(machineMove, forwardMostMove, &moveType,
+                              &fromX, &fromY, &toX, &toY, &promoChar)) {
+           /* Machine move could not be parsed; ignore it. */
+            sprintf(buf1, _("Illegal move \"%s\" from %s machine"),
+                   machineMove, cps->which);
+           DisplayError(buf1, 0);
+            sprintf(buf1, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d",
+                    machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, moveType);
+           if (gameMode == TwoMachinesPlay) {
+             GameEnds(machineWhite ? BlackWins : WhiteWins,
+                       buf1, GE_XBOARD);
+           }
+           return;
+       }
+
+        /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */
+        /* So we have to redo legality test with true e.p. status here,  */
+        /* to make sure an illegal e.p. capture does not slip through,   */
+        /* to cause a forfeit on a justified illegal-move complaint      */
+        /* of the opponent.                                              */
+        if( gameMode==TwoMachinesPlay && appData.testLegality
+            && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */
+                                                              ) {
+           ChessMove moveType;
+           moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),
+                             fromY, fromX, toY, toX, promoChar);
+           if (appData.debugMode) {
+                int i;
+                for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ",
+                    boards[forwardMostMove][CASTLING][i], castlingRank[i]);
+                fprintf(debugFP, "castling rights\n");
+           }
+            if(moveType == IllegalMove) {
+                sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",
+                        machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);
+                GameEnds(machineWhite ? BlackWins : WhiteWins,
+                           buf1, GE_XBOARD);
+               return;
+           } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)
+           /* [HGM] Kludge to handle engines that send FRC-style castling
+              when they shouldn't (like TSCP-Gothic) */
+           switch(moveType) {
+             case WhiteASideCastleFR:
+             case BlackASideCastleFR:
+               toX+=2;
+               currentMoveString[2]++;
+               break;
+             case WhiteHSideCastleFR:
+             case BlackHSideCastleFR:
+               toX--;
+               currentMoveString[2]--;
+               break;
+            default: ; // nothing to do, but suppresses warning of pedantic compilers
+           }
+        }
+       hintRequested = FALSE;
+       lastHint[0] = NULLCHAR;
+       bookRequested = FALSE;
+       /* Program may be pondering now */
+       cps->maybeThinking = TRUE;
+       if (cps->sendTime == 2) cps->sendTime = 1;
+       if (cps->offeredDraw) cps->offeredDraw--;
+
+       /* currentMoveString is set as a side-effect of ParseOneMove */
+       strcpy(machineMove, currentMoveString);
+       strcat(machineMove, "\n");
+       strcpy(moveList[forwardMostMove], machineMove);
+
+       MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
+
+        /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */
+        if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
+            int count = 0;
+
+            while( count < adjudicateLossPlies ) {
+                int score = pvInfoList[ forwardMostMove - count - 1 ].score;
+
+                if( count & 1 ) {
+                    score = -score; /* Flip score for winning side */
+                }
+
+                if( score > adjudicateLossThreshold ) {
+                    break;
+                }
+
+                count++;
+            }
+
+            if( count >= adjudicateLossPlies ) {
+               ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
+
+                GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, 
+                    "Xboard adjudication", 
+                    GE_XBOARD );
+
+                return;
+            }
         }
 
+       if(Adjudicate(cps)) return; // [HGM] adjudicate: for all automatic game ends
+
+#if ZIPPY
+       if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) &&
+           first.initDone) {
+         if(cps->offeredDraw && (signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) {
+               SendToICS(ics_prefix); // [HGM] drawclaim: send caim and move on one line for FICS
+               SendToICS("draw ");
+               SendMoveToICS(moveType, fromX, fromY, toX, toY);
+         }
+         SendMoveToICS(moveType, fromX, fromY, toX, toY);
+         ics_user_moved = 1;
+         if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */
+               char buf[3*MSG_SIZ];
+
+               sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %u nodes, %.0f knps) PV=%s\n",
+                       programStats.score / 100.,
+                       programStats.depth,
+                       programStats.time / 100.,
+                       (unsigned int)programStats.nodes,
+                       (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.),
+                       programStats.movelist);
+               SendToICS(buf);
+if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes);
+         }
+       }
+#endif
+
+        /* [AS] Save move info and clear stats for next move */
+        pvInfoList[ forwardMostMove-1 ].score = programStats.score;
+        pvInfoList[ forwardMostMove-1 ].depth = programStats.depth;
+        pvInfoList[ forwardMostMove-1 ].time =  programStats.time; // [HGM] PGNtime: take time from engine stats
+        ClearProgramStats();
+        thinkOutput[0] = NULLCHAR;
+        hiddenThinkOutputState = 0;
+
        bookHit = NULL;
        if (gameMode == TwoMachinesPlay) {
             /* [HGM] relaying draw offers moved to after reception of move */
@@ -6608,12 +7204,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
        }
 
        ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
-       
+
         if (!pausing && appData.ringBellAfterMoves) {
            RingBell();
        }
 
-       /* 
+       /*
         * Reenable menu items that were disabled while
         * machine was thinking
         */
@@ -6630,7 +7226,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                strcat(bookMove, bookHit);
                message = bookMove;
                cps = cps->other;
-               programStats.nodes = programStats.depth = programStats.time = 
+               programStats.nodes = programStats.depth = programStats.time =
                programStats.score = programStats.got_only_move = 0;
                sprintf(programStats.movelist, "%s (xbook)", bookHit);
 
@@ -6676,7 +7272,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
            CopyBoard(boards[0], initial_position);
            initialRulePlies = FENrulePlies;
            if(blackPlaysFirst) gameMode = MachinePlaysWhite;
-           else gameMode = MachinePlaysBlack;                 
+           else gameMode = MachinePlaysBlack;
            DrawPosition(FALSE, boards[currentMove]);
         }
        return;
@@ -6736,8 +7332,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
        AskQuestion(realname, buf2, buf1, cps->pr);
        return;
     }
-    /* Commands from the engine directly to ICS.  We don't allow these to be 
-     *  sent until we are logged on. Crafty kibitzes have been known to 
+    /* Commands from the engine directly to ICS.  We don't allow these to be
+     *  sent until we are logged on. Crafty kibitzes have been known to
      *  interfere with the login process.
      */
     if (loggedOn) {
@@ -6771,7 +7367,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
      */
     if (strncmp(message + 1, "llegal move", 11) == 0 ||
        strncmp(message, "Error", 5) == 0) {
-       if (StrStr(message, "name") || 
+       if (StrStr(message, "name") ||
            StrStr(message, "rating") || StrStr(message, "?") ||
            StrStr(message, "result") || StrStr(message, "board") ||
            StrStr(message, "bk") || StrStr(message, "computer") ||
@@ -6884,7 +7480,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
           Don't use it. */
        cps->sendTime = 0;
     }
-    
+
     /*
      * If chess program startup fails, exit with an error message.
      * Attempts to recover here are futile.
@@ -6903,8 +7499,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
        DisplayFatalError(buf1, 0, 1);
        return;
     }
-    
-    /* 
+
+    /*
      * Look for hint output
      */
     if (sscanf(message, "Hint: %s", buf1) == 1) {
@@ -6978,7 +7574,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                r = p + 1;
            }
        }
-            
+
         GameEnds(GameIsDrawn, r, GE_ENGINE1 + (cps != &first));
        return;
 
@@ -7103,7 +7699,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
        }
     }
 
-    
+
     /*
      * Look for thinking output
      */
@@ -7212,12 +7808,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
 
                 SendProgramStatsToFrontend( cps, &programStats );
 
-                /* 
+                /*
                     [AS] Protect the thinkOutput buffer from overflow... this
                     is only useful if buf1 hasn't overflowed first!
                 */
                sprintf(thinkOutput, "[%d]%c%+.2f %s%s",
-                       plylev, 
+                       plylev,
                        (gameMode == TwoMachinesPlay ?
                         ToUpper(cps->twoMachinesColor[0]) : ' '),
                        ((double) curscore) / 100.0,
@@ -7263,8 +7859,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                programStats.line_is_book = 1;
 
                 SendProgramStatsToFrontend( cps, &programStats );
-                
-               if (currentMove == forwardMostMove || gameMode==AnalyzeMode || 
+
+               if (currentMove == forwardMostMove || gameMode==AnalyzeMode ||
                            gameMode == AnalyzeFile || appData.icsEngineAnalyze) {
                    DisplayMove(currentMove - 1);
                }
@@ -7334,7 +7930,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
            buf1[0] = NULLCHAR;
 
            if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n",
-                      &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) 
+                      &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5)
             {
                 ChessProgramStats cpstats;
 
@@ -7372,7 +7968,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
 
 /* Parse a game score from the character string "game", and
    record it as the history of the current game.  The game
-   score is NOT assumed to start from the standard position. 
+   score is NOT assumed to start from the standard position.
    The display is not updated in any way.
    */
 void
@@ -7595,10 +8191,10 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
                        gameInfo.variant != VariantBerolina || toX < fromX)
                      board[EP_STATUS] = toX | berolina;
                if(toX<BOARD_RGHT-1 && board[toY][toX+1] == BlackPawn &&
-                       gameInfo.variant != VariantBerolina || toX > fromX) 
-                     board[EP_STATUS] = toX;
+                 gameInfo.variant != VariantBerolina || toX > fromX) 
+                board[EP_STATUS] = toX;
           }
-      } else 
+      } else
       if( board[fromY][fromX] == BlackPawn ) {
            if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers
               board[EP_STATUS] = EP_PAWN_MOVE; 
@@ -7623,7 +8219,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
   /* [HGM] In Shatranj and Courier all promotions are to Ferz */
   if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier || gameInfo.variant == VariantMakruk)
        && promoChar != 0) promoChar = PieceToChar(WhiteFerz);
-         
+
   if (fromX == toX && fromY == toY) return;
 
   if (fromY == DROP_RANK) {
@@ -7812,7 +8408,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
       if (captured != EmptySquare && gameInfo.holdingsSize > 0
           && gameInfo.variant != VariantBughouse        ) {
         /* [HGM] holdings: Add to holdings, if holdings exist */
-       if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { 
+       if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
                // [HGM] superchess: suppress flipping color of captured pieces by reverse pre-flip
                captured = (int) captured >= (int) BlackPawn ? BLACK_TO_WHITE captured : WHITE_TO_BLACK captured;
        }
@@ -7859,8 +8455,8 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
         board[toY][toX] = (ChessSquare) (PROMOTED piece);
     }
 
-    if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) 
-               && promoChar != NULLCHAR && gameInfo.holdingsSize) { 
+    if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
+               && promoChar != NULLCHAR && gameInfo.holdingsSize) {
        // [HGM] superchess: take promotion piece out of holdings
        int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));
        if((int)piece < (int)BlackPawn) { // determine stm from piece color
@@ -7889,10 +8485,10 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
         if(gameInfo.variant == VariantKnightmate)
             king += (int) WhiteUnicorn - (int) WhiteKing;
         if(forwardMostMove == 0) {
-            if(blackPlaysFirst) 
+            if(blackPlaysFirst)
                 fprintf(serverMoves, "%s;", second.tidy);
             fprintf(serverMoves, "%s;", first.tidy);
-            if(!blackPlaysFirst) 
+            if(!blackPlaysFirst)
                 fprintf(serverMoves, "%s;", second.tidy);
         } else fprintf(serverMoves, loadFlag|lastLoadFlag ? ":" : ";");
         lastLoadFlag = loadFlag;
@@ -7977,17 +8573,24 @@ ShowMove(fromX, fromY, toX, toY)
 {
     int instant = (gameMode == PlayFromGameFile) ?
        (matchMode || (appData.timeDelay == 0 && !pausing)) : pausing;
+
     if(appData.noGUI) return;
-    if (!pausing || gameMode == PlayFromGameFile || gameMode == AnalyzeFile) {
-       if (!instant) {
-           if (forwardMostMove == currentMove + 1) {
-               AnimateMove(boards[forwardMostMove - 1],
-                           fromX, fromY, toX, toY);
-           }
-           if (appData.highlightLastMove) {
+
+    if (!pausing || gameMode == PlayFromGameFile || gameMode == AnalyzeFile)
+      {
+       if (!instant)
+         {
+           if (forwardMostMove == currentMove + 1)
+             {
+//TODO
+//             AnimateMove(boards[forwardMostMove - 1],
+//                         fromX, fromY, toX, toY);
+             }
+           if (appData.highlightLastMove)
+             {
                SetHighlights(fromX, fromY, toX, toY);
-           }
-       }
+             }
+         }
        currentMove = forwardMostMove;
     }
 
@@ -7997,6 +8600,8 @@ ShowMove(fromX, fromY, toX, toY)
     DrawPosition(FALSE, boards[currentMove]);
     DisplayBothClocks();
     HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
+
+    return;
 }
 
 void SendEgtPath(ChessProgramState *cps)
@@ -8011,7 +8616,7 @@ void SendEgtPath(ChessProgramState *cps)
            name[0] = ','; // extract next format name from feature and copy with prefixed ','
            while(*p && *p != ',') *q++ = *p++;
            *q++ = ':'; *q = 0;
-           if( appData.defaultPathEGTB && appData.defaultPathEGTB[0] && 
+           if( appData.defaultPathEGTB && appData.defaultPathEGTB[0] &&
                strcmp(name, ",nalimov:") == 0 ) {
                // take nalimov path from the menu-changeable option first, if it is defined
                sprintf(buf, "egtpath nalimov %s\n", appData.defaultPathEGTB);
@@ -8076,7 +8681,7 @@ InitChessProgram(cps, setup)
            overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 9 || gameInfo.holdingsSize != 7;
       if( gameInfo.variant == VariantBughouse || gameInfo.variant == VariantCrazyhouse )
            overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 5;
-      if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantCapaRandom || 
+      if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantCapaRandom ||
                                gameInfo.variant == VariantGothic  || gameInfo.variant == VariantFalcon )
            overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
       if( gameInfo.variant == VariantCourier )
@@ -8087,10 +8692,10 @@ InitChessProgram(cps, setup)
            overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
 
       if(overruled) {
-           sprintf(b, "%dx%d+%d_%s", gameInfo.boardWidth, gameInfo.boardHeight, 
+           sprintf(b, "%dx%d+%d_%s", gameInfo.boardWidth, gameInfo.boardHeight,
                                gameInfo.holdingsSize, VariantName(gameInfo.variant)); // cook up sized variant name
            /* [HGM] varsize: try first if this defiant size variant is specifically known */
-           if(StrStr(cps->variants, b) == NULL) { 
+           if(StrStr(cps->variants, b) == NULL) {
                // specific sized variant not known, check if general sizing allowed
                if (cps->protocolVersion != 1) { // for protocol 1 we cannot check and hope for the best
                    if(StrStr(cps->variants, "boardsize") == NULL) {
@@ -8127,7 +8732,7 @@ InitChessProgram(cps, setup)
                        timeIncrement, appData.searchDepth,
                        searchTime);
     }
-    if (appData.showThinking 
+    if (appData.showThinking
        // [HGM] thinking: four options require thinking output to be sent
        || !appData.hideThinkingFromHuman || appData.adjudicateLossThreshold != 0 || EngineOutputIsUp()
                                ) {
@@ -8146,7 +8751,7 @@ InitChessProgram(cps, setup)
       SendToProgram(buf, cps);
     }
     cps->initDone = TRUE;
-}   
+}
 
 
 void
@@ -8173,7 +8778,7 @@ StartChessProgram(cps)
        }
        err = StartChildProcess(buf, "", &cps->pr);
     }
-    
+
     if (err != 0) {
        sprintf(buf, _("Startup failure on '%s'"), cps->program);
        DisplayFatalError(buf, err, 1);
@@ -8181,7 +8786,7 @@ StartChessProgram(cps)
        cps->isr = NULL;
        return;
     }
-    
+
     cps->isr = AddInputSource(cps->pr, TRUE, ReceiveFromProgram, cps);
     if (cps->protocolVersion > 1) {
       sprintf(buf, "xboard\nprotover %d\n", cps->protocolVersion);
@@ -8221,7 +8826,7 @@ NextMatchGame P((void))
        if(index < 0) { // [HGM] autoinc
            lastIndex = index = (index == -2 && first.twoMachinesColor[0] == 'b') ? lastIndex : lastIndex+1;
            if(appData.rewindIndex > 0 && index > appData.rewindIndex) lastIndex = index = 1;
-       } 
+       }
        LoadGameFromFile(appData.loadGameFile,
                         index,
                         appData.loadGameFile, FALSE);
@@ -8230,7 +8835,7 @@ NextMatchGame P((void))
        if(index < 0) { // [HGM] autoinc
            lastIndex = index = (index == -2 && first.twoMachinesColor[0] == 'b') ? lastIndex : lastIndex+1;
            if(appData.rewindIndex > 0 && index > appData.rewindIndex) lastIndex = index = 1;
-       } 
+       }
        LoadPositionFromFile(appData.loadPositionFile,
                             index,
                             appData.loadPositionFile);
@@ -8297,8 +8902,8 @@ GameEnds(result, resultDetails, whosays)
 
     if (appData.icsActive && (whosays == GE_ENGINE || whosays >= GE_ENGINE1)) {
        /* If we are playing on ICS, the server decides when the
-          game is over, but the engine can offer to draw, claim 
-          a draw, or resign. 
+          game is over, but the engine can offer to draw, claim
+          a draw, or resign.
         */
 #if ZIPPY
        if (appData.zippyPlay && first.initDone) {
@@ -8327,17 +8932,17 @@ GameEnds(result, resultDetails, whosays)
 
     /* If this is an ICS game, only ICS can really say it's done;
        if not, anyone can. */
-    isIcsGame = (gameMode == IcsPlayingWhite || 
-                gameMode == IcsPlayingBlack || 
-                gameMode == IcsObserving    || 
+    isIcsGame = (gameMode == IcsPlayingWhite ||
+                gameMode == IcsPlayingBlack ||
+                gameMode == IcsObserving    ||
                 gameMode == IcsExamining);
 
     if (!isIcsGame || whosays == GE_ICS) {
        /* OK -- not an ICS game, or ICS said it was done */
        StopClocks();
-       if (!isIcsGame && !appData.noChessProgram) 
+       if (!isIcsGame && !appData.noChessProgram)
          SetUserThinkingEnables();
-    
+
         /* [HGM] if a machine claims the game end we verify this claim */
         if(gameMode == TwoMachinesPlay && appData.testClaims) {
            if(appData.testLegality && whosays >= GE_ENGINE1 ) {
@@ -8388,9 +8993,10 @@ GameEnds(result, resultDetails, whosays)
                 }
                 /* (Claiming a loss is accepted no questions asked!) */
            }
+
            /* [HGM] bare: don't allow bare King to win */
            if((gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
-              && gameInfo.variant != VariantLosers && gameInfo.variant != VariantGiveaway 
+              && gameInfo.variant != VariantLosers && gameInfo.variant != VariantGiveaway
               && gameInfo.variant != VariantSuicide // [HGM] losers: except in losers, of course...
               && result != GameIsDrawn)
            {   int i, j, k=0, color = (result==WhiteWins ? (int)WhitePawn : (int)BlackPawn);
@@ -8410,7 +9016,6 @@ GameEnds(result, resultDetails, whosays)
            }
         }
 
-
         if(serverMoves != NULL && !loadFlag) { char c = '=';
             if(result==WhiteWins) c = '+';
             if(result==BlackWins) c = '-';
@@ -8424,7 +9029,7 @@ GameEnds(result, resultDetails, whosays)
            /* display last move only if game was not loaded from file */
            if ((whosays != GE_FILE) && (currentMove == forwardMostMove))
                DisplayMove(currentMove - 1);
-    
+
            if (forwardMostMove != 0) {
                if (gameMode != PlayFromGameFile && gameMode != EditGame
                    && lastSavedGame != GameCheckSum() // [HGM] save: suppress duplicates
@@ -8505,8 +9110,8 @@ GameEnds(result, resultDetails, whosays)
                }
            }
        } else if (gameMode == EditGame ||
-                  gameMode == PlayFromGameFile || 
-                  gameMode == AnalyzeMode || 
+                  gameMode == PlayFromGameFile ||
+                  gameMode == AnalyzeMode ||
                   gameMode == AnalyzeFile) {
            nextGameMode = gameMode;
        } else {
@@ -8546,7 +9151,7 @@ GameEnds(result, resultDetails, whosays)
        if (first.isr != NULL)
          RemoveInputSource(first.isr);
        first.isr = NULL;
-    
+
        if (first.pr != NoProc) {
            ExitAnalyzeMode();
             DoSleep( appData.delayBeforeQuit );
@@ -8572,7 +9177,7 @@ GameEnds(result, resultDetails, whosays)
        if (second.isr != NULL)
          RemoveInputSource(second.isr);
        second.isr = NULL;
-    
+
        if (second.pr != NoProc) {
             DoSleep( appData.delayBeforeQuit );
            SendToProgram("quit\n", &second);
@@ -8636,12 +9241,12 @@ GameEnds(result, resultDetails, whosays)
 /* Assumes program was just initialized (initString sent).
    Leaves program in force mode. */
 void
-FeedMovesToProgram(cps, upto) 
+FeedMovesToProgram(cps, upto)
      ChessProgramState *cps;
      int upto;
 {
     int i;
-    
+
     if (appData.debugMode)
       fprintf(debugFP, "Feeding %smoves %d through %d to %s chess program\n",
              startedFromSetupPosition ? "position and " : "",
@@ -8674,7 +9279,7 @@ ResurrectChessProgram()
        If so, restart it and feed it all the moves made so far. */
 
     if (appData.noChessProgram || first.pr != NoProc) return;
-    
+
     StartChessProgram(&first);
     InitChessProgram(&first, FALSE);
     FeedMovesToProgram(&first, currentMove);
@@ -8728,7 +9333,7 @@ Reset(redraw, init)
     white_holding[0] = black_holding[0] = NULLCHAR;
     ClearProgramStats();
     opponentKibitzes = FALSE; // [HGM] kibitz: do not reserve space in engine-output window in zippy mode
-    
+
     ResetFrontEnd();
     ClearHighlights();
     flipView = appData.flipView;
@@ -8753,6 +9358,7 @@ Reset(redraw, init)
     ExitAnalyzeMode();
     gameMode = BeginningOfGame;
     ModeHighlight();
+
     if(appData.icsActive) gameInfo.variant = VariantNormal;
     currentMove = forwardMostMove = backwardMostMove = 0;
     InitPosition(redraw);
@@ -8762,6 +9368,7 @@ Reset(redraw, init)
            commentList[i] = NULL;
        }
     }
+
     ResetClocks();
     timeRemaining[0][0] = whiteTimeRemaining;
     timeRemaining[1][0] = blackTimeRemaining;
@@ -8771,10 +9378,12 @@ Reset(redraw, init)
     if (init) {
            InitChessProgram(&first, startedFromSetupPosition);
     }
+
     DisplayTitle("");
     DisplayMessage("", "");
     HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1);
     lastSavedGame = 0; // [HGM] save: make sure next game counts as unsaved
+    return;
 }
 
 void
@@ -8814,7 +9423,7 @@ AutoPlayOneMove()
 
       return FALSE;
     }
-    
+
     toX = moveList[currentMove][2] - AAA;
     toY = moveList[currentMove][3] - ONE;
 
@@ -8853,13 +9462,13 @@ LoadGameOneMove(readAhead)
     ChessMove moveType;
     char move[MSG_SIZ];
     char *p, *q;
-    
-    if (gameMode != PlayFromGameFile && gameMode != AnalyzeFile && 
+
+    if (gameMode != PlayFromGameFile && gameMode != AnalyzeFile &&
        gameMode != AnalyzeMode && gameMode != Training) {
        gameFileFP = NULL;
        return FALSE;
     }
-    
+
     yyboardindex = forwardMostMove;
     if (readAhead != (ChessMove)0) {
       moveType = readAhead;
@@ -8868,11 +9477,11 @@ LoadGameOneMove(readAhead)
          return FALSE;
       moveType = (ChessMove) yylex();
     }
-    
+
     done = FALSE;
     switch (moveType) {
       case Comment:
-       if (appData.debugMode) 
+       if (appData.debugMode)
          fprintf(debugFP, "Parsed Comment: %s\n", yy_text);
        p = yy_text;
 
@@ -9084,7 +9693,7 @@ LoadGameOneMove(readAhead)
        /* currentMoveString is set as a side-effect of yylex */
        strcat(currentMoveString, "\n");
        strcpy(moveList[forwardMostMove], currentMoveString);
-       
+
        thinkOutput[0] = NULLCHAR;
        MakeMove(fromX, fromY, toX, toY, promoChar);
        currentMove = forwardMostMove;
@@ -9124,7 +9733,8 @@ LoadGameFromFile(filename, n, title, useList)
            DisplayError(_("Cannot build game list"), error);
        } else if (!ListEmpty(&gameList) &&
                   ((ListGame *) gameList.tailPred)->number > 1) {
-           GameListPopUp(f, title);
+         // TODO convert to GTK
+         //        GameListPopUp(f, title);
            return TRUE;
        }
        GameListDestroy();
@@ -9147,7 +9757,7 @@ MakeRegisteredMove()
            if (appData.debugMode)
              fprintf(debugFP, "Restoring %s for game %d\n",
                      cmailMove[lastLoadGameNumber - 1], lastLoadGameNumber);
-    
+
            thinkOutput[0] = NULLCHAR;
            strcpy(moveList[currentMove], cmailMove[lastLoadGameNumber - 1]);
             fromX = cmailMove[lastLoadGameNumber - 1][0] - AAA;
@@ -9157,12 +9767,11 @@ MakeRegisteredMove()
            promoChar = cmailMove[lastLoadGameNumber - 1][4];
            MakeMove(fromX, fromY, toX, toY, promoChar);
            ShowMove(fromX, fromY, toX, toY);
-             
            switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) {
              case MT_NONE:
              case MT_CHECK:
                break;
-               
+
              case MT_CHECKMATE:
              case MT_STAINMATE:
                if (WhiteOnMove(currentMove)) {
@@ -9171,14 +9780,14 @@ MakeRegisteredMove()
                    GameEnds(WhiteWins, "White mates", GE_PLAYER);
                }
                break;
-               
+
              case MT_STALEMATE:
                GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);
                break;
            }
 
            break;
-           
+
          case CMAIL_RESIGN:
            if (WhiteOnMove(currentMove)) {
                GameEnds(BlackWins, "White resigns", GE_PLAYER);
@@ -9186,11 +9795,11 @@ MakeRegisteredMove()
                GameEnds(WhiteWins, "Black resigns", GE_PLAYER);
            }
            break;
-           
+
          case CMAIL_ACCEPT:
            GameEnds(GameIsDrawn, "Draw agreed", GE_PLAYER);
            break;
-             
+
          default:
            break;
        }
@@ -9286,71 +9895,90 @@ LoadGame(f, gameNumber, title, useList)
     GameMode oldGameMode;
     VariantClass oldVariant = gameInfo.variant; /* [HGM] PGNvariant */
 
-    if (appData.debugMode) 
+    if (appData.debugMode)
        fprintf(debugFP, "LoadGame(): on entry, gameMode %d\n", gameMode);
 
     if (gameMode == Training )
        SetTrainingModeOff();
 
     oldGameMode = gameMode;
-    if (gameMode != BeginningOfGame) {
-      Reset(FALSE, TRUE);
-    }
+    if (gameMode != BeginningOfGame) 
+      {
+       Reset(FALSE, TRUE);
+      };
 
     gameFileFP = f;
-    if (lastLoadGameFP != NULL && lastLoadGameFP != f) {
+    if (lastLoadGameFP != NULL && lastLoadGameFP != f) 
+      {
        fclose(lastLoadGameFP);
-    }
+      };
 
-    if (useList) {
+    if (useList) 
+      {
        lg = (ListGame *) ListElem(&gameList, gameNumber-1);
        
-       if (lg) {
+       if (lg) 
+         {
            fseek(f, lg->offset, 0);
            GameListHighlight(gameNumber);
            gn = 1;
-       }
-       else {
+         }
+       else 
+         {
            DisplayError(_("Game number out of range"), 0);
            return FALSE;
-       }
-    } else {
+         };
+      } 
+    else 
+      {
        GameListDestroy();
-       if (fseek(f, 0, 0) == -1) {
+       if (fseek(f, 0, 0) == -1) 
+         {
            if (f == lastLoadGameFP ?
                gameNumber == lastLoadGameNumber + 1 :
-               gameNumber == 1) {
+               gameNumber == 1) 
+             {
                gn = 1;
-           } else {
+             } 
+           else 
+             {
                DisplayError(_("Can't seek on game file"), 0);
                return FALSE;
-           }
-       }
-    }
-    lastLoadGameFP = f;
-    lastLoadGameNumber = gameNumber;
+             };
+         };
+      };
+
+    lastLoadGameFP     = f;
+    lastLoadGameNumber = gameNumber;
     strcpy(lastLoadGameTitle, title);
     lastLoadGameUseList = useList;
 
     yynewfile(f);
 
-    if (lg && lg->gameInfo.white && lg->gameInfo.black) {
-      snprintf(buf, sizeof(buf), "%s vs. %s", lg->gameInfo.white,
-               lg->gameInfo.black);
-           DisplayTitle(buf);
-    } else if (*title != NULLCHAR) {
-       if (gameNumber > 1) {
+    if (lg && lg->gameInfo.white && lg->gameInfo.black) 
+      {
+       snprintf(buf, sizeof(buf), "%s vs. %s", lg->gameInfo.white,
+                lg->gameInfo.black);
+       DisplayTitle(buf);
+      } 
+    else if (*title != NULLCHAR) 
+      {
+       if (gameNumber > 1) 
+         {
            sprintf(buf, "%s %d", title, gameNumber);
            DisplayTitle(buf);
-       } else {
+         } 
+       else 
+         {
            DisplayTitle(title);
-       }
-    }
+         };
+      };
 
-    if (gameMode != AnalyzeFile && gameMode != AnalyzeMode) {
+    if (gameMode != AnalyzeFile && gameMode != AnalyzeMode) 
+      {
        gameMode = PlayFromGameFile;
        ModeHighlight();
-    }
+      };
 
     currentMove = forwardMostMove = backwardMostMove = 0;
     CopyBoard(boards[0], initialPosition);
@@ -9358,12 +9986,12 @@ LoadGame(f, gameNumber, title, useList)
 
     /*
      * Skip the first gn-1 games in the file.
-     * Also skip over anything that precedes an identifiable 
-     * start of game marker, to avoid being confused by 
-     * garbage at the start of the file.  Currently 
+     * Also skip over anything that precedes an identifiable
+     * start of game marker, to avoid being confused by
+     * garbage at the start of the file.  Currently
      * recognized start of game markers are the move number "1",
      * the pattern "gnuchess .* game", the pattern
-     * "^[#;%] [^ ]* game file", and a PGN tag block.  
+     * "^[#;%] [^ ]* game file", and a PGN tag block.
      * A game that starts with one of the latter two patterns
      * will also have a move number 1, possibly
      * following a position diagram.
@@ -9389,7 +10017,7 @@ LoadGame(f, gameNumber, title, useList)
            gn--;
            lastLoadGameStart = cm;
            break;
-           
+
          case MoveNumberOne:
            switch (lastLoadGameStart) {
              case GNUChessGame:
@@ -9457,7 +10085,7 @@ LoadGame(f, gameNumber, title, useList)
            break;
        }
     }
-    
+
     if (appData.debugMode)
       fprintf(debugFP, "Parsed game start '%s' (%d)\n", yy_text, (int) cm);
 
@@ -9483,11 +10111,11 @@ LoadGame(f, gameNumber, title, useList)
            free(gameInfo.event);
        }
        gameInfo.event = StrSave(yy_text);
-    }  
+    }
 
     startedFromSetupPosition = FALSE;
     while (cm == PGNTag) {
-       if (appData.debugMode) 
+       if (appData.debugMode)
          fprintf(debugFP, "Parsed PGNTag: %s\n", yy_text);
        err = ParsePGNTag(yy_text, &gameInfo);
        if (!err) numPGNTags++;
@@ -9497,7 +10125,7 @@ LoadGame(f, gameNumber, title, useList)
             startedFromPositionFile = FALSE; /* [HGM] loadPos: variant switch likely makes position invalid */
            InitPosition(TRUE);
             oldVariant = gameInfo.variant;
-           if (appData.debugMode) 
+           if (appData.debugMode)
              fprintf(debugFP, "New variant %d\n", (int) oldVariant);
         }
 
@@ -9542,7 +10170,7 @@ LoadGame(f, gameNumber, title, useList)
        /* Handle comments interspersed among the tags */
        while (cm == Comment) {
            char *p;
-           if (appData.debugMode) 
+           if (appData.debugMode)
              fprintf(debugFP, "Parsed Comment: %s\n", yy_text);
            p = yy_text;
            AppendComment(currentMove, p, FALSE);
@@ -9598,13 +10226,13 @@ LoadGame(f, gameNumber, title, useList)
                }
            while (*p == ' ' || *p == '\t' ||
                   *p == '\n' || *p == '\r') p++;
-       
+
            if (strncmp(p, "black", strlen("black"))==0)
              blackPlaysFirst = TRUE;
            else
              blackPlaysFirst = FALSE;
            startedFromSetupPosition = TRUE;
-       
+
            CopyBoard(boards[0], initial_position);
            if (blackPlaysFirst) {
                currentMove = forwardMostMove = backwardMostMove = 1;
@@ -9636,14 +10264,14 @@ LoadGame(f, gameNumber, title, useList)
         fprintf(debugFP, "Load Game\n");
     }
        DisplayBothClocks();
-    }      
+    }
 
     /* [HGM] server: flag to write setup moves in broadcast file as one */
     loadFlag = appData.suppressLoadMoves;
 
     while (cm == Comment) {
        char *p;
-       if (appData.debugMode) 
+       if (appData.debugMode)
          fprintf(debugFP, "Parsed Comment: %s\n", yy_text);
        p = yy_text;
        AppendComment(currentMove, p, FALSE);
@@ -9674,7 +10302,7 @@ LoadGame(f, gameNumber, title, useList)
     if (!matchMode && (pausing || appData.timeDelay != 0)) {
        DisplayComment(currentMove - 1, commentList[currentMove]);
     }
-    if (!matchMode && appData.timeDelay != 0) 
+    if (!matchMode && appData.timeDelay != 0)
       DrawPosition(FALSE, boards[currentMove]);
 
     if (gameMode == AnalyzeFile || gameMode == AnalyzeMode) {
@@ -9682,7 +10310,7 @@ LoadGame(f, gameNumber, title, useList)
     }
 
     /* if the first token after the PGN tags is a move
-     * and not move number 1, retrieve it from the parser 
+     * and not move number 1, retrieve it from the parser
      */
     if (cm != MoveNumberOne)
        LoadGameOneMove(cm);
@@ -9711,7 +10339,7 @@ LoadGame(f, gameNumber, title, useList)
       AutoPlayGameLoop();
     }
 
-    if (appData.debugMode) 
+    if (appData.debugMode)
        fprintf(debugFP, "LoadGame(): on exit, gameMode %d\n", gameMode);
 
     loadFlag = 0; /* [HGM] true game starts */
@@ -9770,7 +10398,7 @@ LoadPosition(f, positionNumber, title)
     char *p, line[MSG_SIZ];
     Board initial_position;
     int i, j, fenMode, pn;
-    
+
     if (gameMode == Training )
        SetTrainingModeOff();
 
@@ -9787,7 +10415,7 @@ LoadPosition(f, positionNumber, title)
     if (first.pr == NoProc) {
       StartChessProgram(&first);
       InitChessProgram(&first, FALSE);
-    }    
+    }
     pn = positionNumber;
     if (positionNumber < 0) {
        /* Negative position number means to seek to that byte offset */
@@ -9837,7 +10465,7 @@ LoadPosition(f, positionNumber, title)
     } else {
        (void) fgets(line, MSG_SIZ, f);
        (void) fgets(line, MSG_SIZ, f);
-    
+
         for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
            (void) fgets(line, MSG_SIZ, f);
             for (p = line, j = BOARD_LEFT; j < BOARD_RGHT; p++) {
@@ -9846,7 +10474,7 @@ LoadPosition(f, positionNumber, title)
                initial_position[i][j++] = CharToPiece(*p);
            }
        }
-    
+
        blackPlaysFirst = FALSE;
        if (!feof(f)) {
            (void) fgets(line, MSG_SIZ, f);
@@ -9855,7 +10483,7 @@ LoadPosition(f, positionNumber, title)
        }
     }
     startedFromSetupPosition = TRUE;
-    
+
     SendToProgram("force\n", &first);
     CopyBoard(boards[0], initial_position);
     if (blackPlaysFirst) {
@@ -9889,7 +10517,7 @@ int i, j;
     timeRemaining[0][1] = whiteTimeRemaining;
     timeRemaining[1][1] = blackTimeRemaining;
     DrawPosition(FALSE, boards[currentMove]);
-   
+
     return TRUE;
 }
 
@@ -9956,7 +10584,7 @@ SavePart(str)
 {
     static char buf[MSG_SIZ];
     char *p;
-    
+
     p = strchr(str, ' ');
     if (p == NULL) return str;
     strncpy(buf, str, p - str);
@@ -10035,7 +10663,7 @@ void GetOutOfBookInfo( char * buf )
                 }
 
                 sprintf( buf+strlen(buf), "%d%s. ", (idx - offset)/2 + 1, idx & 1 ? ".." : "" );
-                sprintf( buf+strlen(buf), "%s%.2f", 
+                sprintf( buf+strlen(buf), "%s%.2f",
                     pvInfoList[idx].score >= 0 ? "+" : "",
                     pvInfoList[idx].score / 100.0 );
             }
@@ -10056,11 +10684,11 @@ SaveGamePGN(f)
     char move_buffer[100]; /* [AS] Buffer for move+PV info */
 
     offset = backwardMostMove & (~1L); /* output move numbers start at 1 */
-    
+
     tm = time((time_t *) NULL);
-    
+
     PrintPGNTags(f, &gameInfo);
-    
+
     if (backwardMostMove > 0 || startedFromSetupPosition) {
         char *fen = PositionToFEN(backwardMostMove, NULL);
         fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen);
@@ -10077,7 +10705,7 @@ SaveGamePGN(f)
             GetOutOfBookInfo( buf );
 
             if( buf[0] != '\0' ) {
-                fprintf( f, "[%s \"%s\"]\n", PGN_OUT_OF_BOOK, buf ); 
+                fprintf( f, "[%s \"%s\"]\n", PGN_OUT_OF_BOOK, buf );
             }
         }
 
@@ -10156,7 +10784,7 @@ SaveGamePGN(f)
                                   sprintf(buf, " %d:%02d%c", seconds/60, seconds%60, 0);
            }
 
-            sprintf( move_buffer, "{%s%.2f/%d%s}", 
+            sprintf( move_buffer, "{%s%.2f/%d%s}",
                 pvInfoList[i].score >= 0 ? "+" : "",
                 pvInfoList[i].score / 100.0,
                 pvInfoList[i].depth,
@@ -10181,7 +10809,7 @@ SaveGamePGN(f)
 
        i++;
     }
-    
+
     /* Start a new line */
     if (linelen > 0) fprintf(f, "\n");
 
@@ -10211,12 +10839,12 @@ SaveGameOldStyle(f)
 {
     int i, offset;
     time_t tm;
-    
+
     tm = time((time_t *) NULL);
-    
+
     fprintf(f, "# %s game file -- %s", programName, ctime(&tm));
     PrintOpponents(f);
-    
+
     if (backwardMostMove > 0 || startedFromSetupPosition) {
        fprintf(f, "\n[--------------\n");
        PrintPosition(f, backwardMostMove);
@@ -10251,7 +10879,7 @@ SaveGameOldStyle(f)
            i++;
        }
     }
-    
+
     if (commentList[i] != NULL) {
        fprintf(f, "[%s]\n", commentList[i]);
     }
@@ -10316,11 +10944,10 @@ SavePosition(f, dummy, dummy2)
 {
     time_t tm;
     char *fen;
-    
     if (gameMode == EditPosition) EditPositionDone(TRUE);
     if (appData.oldSaveStyle) {
        tm = time((time_t *) NULL);
-    
+
        fprintf(f, "# %s position file -- %s", programName, ctime(&tm));
        PrintOpponents(f);
        fprintf(f, "[--------------\n");
@@ -10345,7 +10972,7 @@ ReloadCmailMsgEvent(unregister)
     int i;
     struct stat inbuf, outbuf;
     int status;
-    
+
     /* Any registered moves are unregistered if unregister is set, */
     /* i.e. invoked by the signal handler */
     if (unregister) {
@@ -10373,7 +11000,7 @@ ReloadCmailMsgEvent(unregister)
        outFilename = (char *) malloc(strlen(appData.cmailGameName) + 5);
        sprintf(outFilename, "%s.out", appData.cmailGameName);
     }
-    
+
     status = stat(outFilename, &outbuf);
     if (status < 0) {
        cmailMailedMove = FALSE;
@@ -10381,10 +11008,10 @@ ReloadCmailMsgEvent(unregister)
        status = stat(inFilename, &inbuf);
        cmailMailedMove = (inbuf.st_mtime < outbuf.st_mtime);
     }
-    
+
     /* LoadGameFromFile(CMAIL_MAX_GAMES) with cmailMsgLoaded == TRUE
        counts the games, notes how each one terminated, etc.
-       
+
        It would be nice to remove this kludge and instead gather all
        the information while building the game list.  (And to keep it
        in the game list nodes instead of having a bunch of fixed-size
@@ -10394,7 +11021,7 @@ ReloadCmailMsgEvent(unregister)
        */
     cmailMsgLoaded = TRUE;
     LoadGameFromFile(inFilename, CMAIL_MAX_GAMES, "", FALSE);
-    
+
     /* Load first game in the file or popup game menu */
     LoadGameFromFile(inFilename, 0, appData.cmailGameName, TRUE);
 
@@ -10420,7 +11047,7 @@ RegisterMove()
        cmailMoveRegistered[lastLoadGameNumber - 1] = FALSE;
        nCmailMovesRegistered --;
 
-       if (cmailCommentList[lastLoadGameNumber - 1] != NULL) 
+       if (cmailCommentList[lastLoadGameNumber - 1] != NULL)
          {
              free(cmailCommentList[lastLoadGameNumber - 1]);
              cmailCommentList[lastLoadGameNumber - 1] = NULL;
@@ -10467,11 +11094,11 @@ RegisterMove()
 
        sprintf(string,
                "%s.game.out.%d", appData.cmailGameName, lastLoadGameNumber);
-       
+
        f = fopen(string, "w");
        if (appData.oldSaveStyle) {
            SaveGameOldStyle(f); /* also closes the file */
-           
+
            sprintf(string, "%s.pos.out", appData.cmailGameName);
            f = fopen(string, "w");
            SavePosition(f, 0, NULL); /* also closes the file */
@@ -10479,10 +11106,10 @@ RegisterMove()
            fprintf(f, "{--------------\n");
            PrintPosition(f, currentMove);
            fprintf(f, "--------------}\n\n");
-           
+
            SaveGame(f, 0, NULL); /* also closes the file*/
        }
-       
+
        cmailMoveRegistered[lastLoadGameNumber - 1] = TRUE;
        nCmailMovesRegistered ++;
     } else if (nCmailGames == 1) {
@@ -10525,7 +11152,7 @@ MailMoveEvent()
 #endif
 
     if (! (cmailMailedMove || RegisterMove())) return;
-    
+
     if (   cmailMailedMove
        || (nCmailMovesRegistered + nCmailResults == nCmailGames)) {
        sprintf(string, partCommandString,
@@ -10591,7 +11218,7 @@ CmailMsg()
     char number[5];
     char string[MSG_SIZ];      /* Space for game-list */
     int  i;
-    
+
     if (!cmailMsgLoaded) return "";
 
     if (cmailMailedMove) {
@@ -10608,7 +11235,7 @@ CmailMsg()
                    sprintf(number, "%d", i + 1);
                    prependComma = 1;
                }
-               
+
                strcat(string, number);
            }
        }
@@ -10620,12 +11247,12 @@ CmailMsg()
                sprintf(cmailMsg,
                        _("Still need to make move for game\n"));
                break;
-               
+
              case 2:
                sprintf(cmailMsg,
                        _("Still need to make moves for both games\n"));
                break;
-               
+
              default:
                sprintf(cmailMsg,
                        _("Still need to make moves for all %d games\n"),
@@ -10639,7 +11266,7 @@ CmailMsg()
                        _("Still need to make a move for game %s\n"),
                        string);
                break;
-               
+
              case 0:
                if (nCmailResults == nCmailGames) {
                    sprintf(cmailMsg, _("No unfinished games\n"));
@@ -10647,7 +11274,7 @@ CmailMsg()
                    sprintf(cmailMsg, _("Ready to send mail\n"));
                }
                break;
-               
+
              default:
                sprintf(cmailMsg,
                        _("Still need to make moves for games %s\n"),
@@ -10710,7 +11337,7 @@ ExitEvent(status)
     /* Kill off chess programs */
     if (first.pr != NoProc) {
        ExitAnalyzeMode();
-        
+
         DoSleep( appData.delayBeforeQuit );
        SendToProgram("quit\n", &first);
         DoSleep( appData.delayAfterQuit );
@@ -10748,7 +11375,7 @@ PauseEvent()
            DisplayBothClocks();
        }
        if (gameMode == PlayFromGameFile) {
-           if (appData.timeDelay >= 0) 
+           if (appData.timeDelay >= 0)
                AutoPlayGameLoop();
        } else if (gameMode == IcsExamining && pauseExamInvalid) {
            Reset(FALSE, TRUE);
@@ -10887,10 +11514,10 @@ MachineWhiteEvent()
       return;
 
 
-    if (gameMode == PlayFromGameFile || 
-       gameMode == TwoMachinesPlay  || 
-       gameMode == Training         || 
-       gameMode == AnalyzeMode      || 
+    if (gameMode == PlayFromGameFile ||
+       gameMode == TwoMachinesPlay  ||
+       gameMode == Training         ||
+       gameMode == AnalyzeMode      ||
        gameMode == EndOfGame)
        EditGameEvent();
 
@@ -10901,11 +11528,11 @@ MachineWhiteEvent()
        DisplayError(_("It is not White's turn"), 0);
        return;
     }
-  
+
     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
       ExitAnalyzeMode();
 
-    if (gameMode == EditGame || gameMode == AnalyzeMode || 
+    if (gameMode == EditGame || gameMode == AnalyzeMode ||
        gameMode == AnalyzeFile)
        TruncateGame();
 
@@ -10948,7 +11575,7 @@ MachineWhiteEvent()
     if(bookHit) { // [HGM] book: simulate book reply
        static char bookMove[MSG_SIZ]; // a bit generous?
 
-       programStats.nodes = programStats.depth = programStats.time = 
+       programStats.nodes = programStats.depth = programStats.time =
        programStats.score = programStats.got_only_move = 0;
        sprintf(programStats.movelist, "%s (xbook)", bookHit);
 
@@ -10961,76 +11588,84 @@ MachineWhiteEvent()
 void
 MachineBlackEvent()
 {
-    char buf[MSG_SIZ];
-   char *bookHit = NULL;
-
-    if (appData.noChessProgram || (gameMode == MachinePlaysBlack))
-       return;
-
-
-    if (gameMode == PlayFromGameFile || 
-       gameMode == TwoMachinesPlay  || 
-       gameMode == Training         || 
-       gameMode == AnalyzeMode      || 
-       gameMode == EndOfGame)
-        EditGameEvent();
-
-    if (gameMode == EditPosition) 
-        EditPositionDone(TRUE);
-
-    if (WhiteOnMove(currentMove)) {
-       DisplayError(_("It is not Black's turn"), 0);
-       return;
+  char buf[MSG_SIZ];
+  char *bookHit = NULL;
+  
+  if (appData.noChessProgram || (gameMode == MachinePlaysBlack))
+    return;
+  
+  
+  if (gameMode == PlayFromGameFile 
+      || gameMode == TwoMachinesPlay  
+      || gameMode == Training     
+      || gameMode == AnalyzeMode
+      || gameMode == EndOfGame)
+    EditGameEvent();
+  
+  if (gameMode == EditPosition) 
+    EditPositionDone(TRUE);
+  
+  if (WhiteOnMove(currentMove)) 
+    {
+      DisplayError(_("It is not Black's turn"), 0);
+      return;
     }
-    
-    if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
-      ExitAnalyzeMode();
-
-    if (gameMode == EditGame || gameMode == AnalyzeMode || 
-       gameMode == AnalyzeFile)
-       TruncateGame();
-
-    ResurrectChessProgram();   /* in case it isn't running */
-    gameMode = MachinePlaysBlack;
-    pausing = FALSE;
-    ModeHighlight();
-    SetGameInfo();
-    sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
-    DisplayTitle(buf);
-    if (first.sendName) {
+  
+  if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
+    ExitAnalyzeMode();
+  
+  if (gameMode == EditGame || gameMode == AnalyzeMode 
+      || gameMode == AnalyzeFile)
+    TruncateGame();
+  
+  ResurrectChessProgram();     /* in case it isn't running */
+  gameMode = MachinePlaysBlack;
+  pausing  = FALSE;
+  ModeHighlight();
+  SetGameInfo();
+  sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);
+  DisplayTitle(buf);
+  if (first.sendName) 
+    {
       sprintf(buf, "name %s\n", gameInfo.white);
       SendToProgram(buf, &first);
     }
-    if (first.sendTime) {
-      if (first.useColors) {
-       SendToProgram("white\n", &first); /*gnu kludge*/
-      }
+  if (first.sendTime) 
+    {
+      if (first.useColors) 
+       {
+         SendToProgram("white\n", &first); /*gnu kludge*/
+       }
       SendTimeRemaining(&first, FALSE);
     }
-    if (first.useColors) {
+  if (first.useColors) 
+    {
       SendToProgram("black\n", &first); // [HGM] book: 'go' sent separately
     }
-    bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
-    SetMachineThinkingEnables();
-    first.maybeThinking = TRUE;
-    StartClocks();
-
-    if (appData.autoFlipView && flipView) {
+  bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
+  SetMachineThinkingEnables();
+  first.maybeThinking = TRUE;
+  StartClocks();
+  
+  if (appData.autoFlipView && flipView) 
+    {
       flipView = !flipView;
       DrawPosition(FALSE, NULL);
       DisplayBothClocks();       // [HGM] logo: clocks might have to be exchanged;
     }
-    if(bookHit) { // [HGM] book: simulate book reply
-       static char bookMove[MSG_SIZ]; // a bit generous?
-
-       programStats.nodes = programStats.depth = programStats.time = 
-       programStats.score = programStats.got_only_move = 0;
-       sprintf(programStats.movelist, "%s (xbook)", bookHit);
-
-       strcpy(bookMove, "move ");
-       strcat(bookMove, bookHit);
-       HandleMachineMove(bookMove, &first);
+  if(bookHit) 
+    { // [HGM] book: simulate book reply
+      static char bookMove[MSG_SIZ]; // a bit generous?
+      
+      programStats.nodes = programStats.depth = programStats.time 
+       = programStats.score = programStats.got_only_move = 0;
+      sprintf(programStats.movelist, "%s (xbook)", bookHit);
+      
+      strcpy(bookMove, "move ");
+      strcat(bookMove, bookHit);
+      HandleMachineMove(bookMove, &first);
     }
+  return;
 }
 
 
@@ -11063,7 +11698,7 @@ TwoMachinesEvent P((void))
     char buf[MSG_SIZ];
     ChessProgramState *onmove;
     char *bookHit = NULL;
-    
+
     if (appData.noChessProgram) return;
 
     switch (gameMode) {
@@ -11170,7 +11805,7 @@ TwoMachinesEvent P((void))
     if(bookHit) { // [HGM] book: simulate book reply
        static char bookMove[MSG_SIZ]; // a bit generous?
 
-       programStats.nodes = programStats.depth = programStats.time = 
+       programStats.nodes = programStats.depth = programStats.time =
        programStats.score = programStats.got_only_move = 0;
        sprintf(programStats.movelist, "%s (xbook)", bookHit);
 
@@ -11229,7 +11864,7 @@ IcsClientEvent()
       case AnalyzeFile:
        ExitAnalyzeMode();
        break;
-       
+
       default:
        EditGameEvent();
        break;
@@ -11294,7 +11929,7 @@ EditGameEvent()
       default:
        return;
     }
-    
+
     pausing = FALSE;
     StopClocks();
     first.offeredDraw = second.offeredDraw = 0;
@@ -11321,14 +11956,13 @@ EditGameEvent()
            whiteFlag = blackFlag = 0;
        }
        DisplayTitle("");
-    }          
-    
+    }
+
     gameMode = EditGame;
     ModeHighlight();
     SetGameInfo();
 }
 
-
 void
 EditPositionEvent()
 {
@@ -11336,15 +11970,22 @@ EditPositionEvent()
        EditGameEvent();
        return;
     }
-    
+
     EditGameEvent();
     if (gameMode != EditGame) return;
-    
+
     gameMode = EditPosition;
     ModeHighlight();
     SetGameInfo();
     if (currentMove > 0)
       CopyBoard(boards[0], boards[currentMove]);
+    { int i, r, f; // [HGM] editrights: take note of existing rights
+      for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) rightsBoard[r][f] = 0;
+      for(i=0; i<nrCastlingRights; i++) {
+       if(boards[0][CASTLING][i] != NoRights)
+         rightsBoard [castlingRank[i]] [boards[0][CASTLING][i]] = 1 + (i == 2 || i == 5);
+      }
+    }
     
     blackPlaysFirst = !WhiteOnMove(currentMove);
     ResetClocks();
@@ -11377,7 +12018,22 @@ EditPositionDone(Boolean fakeRights)
     startedFromSetupPosition = TRUE;
     InitChessProgram(&first, FALSE);
     if(fakeRights) { // [HGM] suppress this if we just pasted a FEN.
+      int i, r, f, kf, err;
+      for(i=0; i<nrCastlingRights; i++) boards[0][CASTLING][i] = NoRights;
+      kf = NoRights; err = 0;
+      for(f=BOARD_RGHT-1; f>=0; f--)
+       if(rightsBoard[0][f] == 2) { if(kf != NoRights) err=10; boards[0][CASTLING][2] = kf = f; }
+      for(f=BOARD_RGHT-1; f>=0; f--)
+       if(rightsBoard[0][f] == 1) { err++; boards[0][CASTLING][f<kf] = f; }
+      kf = NoRights; err = 0;
+      for(f=BOARD_RGHT-1; f>=0; f--)
+       if(rightsBoard[BOARD_HEIGHT-1][f] == 2) { if(kf != NoRights) err=10; boards[0][CASTLING][5] = kf = f; }
+      for(f=BOARD_RGHT-1; f>=0; f--)
+       if(rightsBoard[BOARD_HEIGHT-1][f] == 1) { err++; boards[0][CASTLING][3+(f<kf)] = f; }
+      if(err + 2 > nrCastlingRights) DisplayError("unclear castling rights", 0);
+
       boards[0][EP_STATUS] = EP_NONE;
+#if 0
       boards[0][CASTLING][2] = boards[0][CASTLING][5] = BOARD_WIDTH>>1;
     if(boards[0][0][BOARD_WIDTH>>1] == king) {
        boards[0][CASTLING][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? 0 : NoRights;
@@ -11387,6 +12043,7 @@ EditPositionDone(Boolean fakeRights)
        boards[0][CASTLING][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? 0 : NoRights;
        boards[0][CASTLING][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : NoRights;
       } else boards[0][CASTLING][5] = NoRights;
+#endif
     }
     SendToProgram("force\n", &first);
     if (blackPlaysFirst) {
@@ -11435,7 +12092,7 @@ SendMultiLineToICS(buf)
     len = strlen(buf);
     if (len > MSG_SIZ)
       len = MSG_SIZ;
-  
+
     strncpy(temp, buf, len);
     temp[len] = 0;
 
@@ -11484,6 +12141,7 @@ EditPositionMenuEvent(selection, x, y)
 {
     char buf[MSG_SIZ];
     ChessSquare piece = boards[0][y][x];
+    int rights = 0; // [HGM] editrights: most new pieces get no castling rights
 
     if (gameMode != EditPosition && gameMode != IcsExamining) return;
 
@@ -11507,6 +12165,7 @@ EditPositionMenuEvent(selection, x, y)
                        }
                    } else {
                        boards[0][y][x] = p;
+                       rightsBoard[y][x] = 0; // [HGM] editrights: clear all castling rights
                    }
                }
            }
@@ -11558,7 +12217,7 @@ EditPositionMenuEvent(selection, x, y)
            piece > (int)BlackMan && piece <= (int)BlackKing   ) {
             selection = (ChessSquare) (DEMOTED piece);
         } else if(piece == EmptySquare) selection = BlackSilver;
-        else selection = (ChessSquare)((int)piece + 1);       
+        else selection = (ChessSquare)((int)piece + 1);
         goto defaultlabel;
 
       case WhiteQueen:
@@ -11570,12 +12229,24 @@ EditPositionMenuEvent(selection, x, y)
             selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz);
         goto defaultlabel;
 
+      case WhiteRook: // [HGM] editrights: corner Rooks get castling rights by default
+       if(y == 0 && (x == BOARD_LEFT || x == BOARD_RGHT-1)) rights = 1;
+       goto defaultlabel;
+
+      case BlackRook:
+       if(y == BOARD_HEIGHT-1 && (x == BOARD_LEFT || x == BOARD_RGHT-1)) rights = 1;
+       goto defaultlabel;
+
       case WhiteKing:
       case BlackKing:
         if(gameInfo.variant == VariantXiangqi)
             selection = (ChessSquare)((int)selection - (int)WhiteKing + (int)WhiteWazir);
         if(gameInfo.variant == VariantKnightmate)
             selection = (ChessSquare)((int)selection - (int)WhiteKing + (int)WhiteUnicorn);
+      case WhiteUnicorn:
+      case BlackUnicorn:
+       if(y == (selection <= WhiteKing ? 0 : BOARD_HEIGHT-1) && (x == BOARD_WIDTH>>1)) 
+           rights = 2; // [HGM] editrights: King on right-center file gets rights
       default:
         defaultlabel:
        if (gameMode == IcsExamining) {
@@ -11588,18 +12259,19 @@ EditPositionMenuEvent(selection, x, y)
                 int n;
                 if(x == BOARD_LEFT-2 && selection >= BlackPawn) {
                     n = PieceToNumber(selection - BlackPawn);
-                    if(n > gameInfo.holdingsSize) { n = 0; selection = BlackPawn; }
+                    if(n >= gameInfo.holdingsSize) { n = 0; selection = BlackPawn; }
                     boards[0][BOARD_HEIGHT-1-n][0] = selection;
                     boards[0][BOARD_HEIGHT-1-n][1]++;
                 } else
                 if(x == BOARD_RGHT+1 && selection < BlackPawn) {
                     n = PieceToNumber(selection);
-                    if(n > gameInfo.holdingsSize) { n = 0; selection = WhitePawn; }
+                    if(n >= gameInfo.holdingsSize) { n = 0; selection = WhitePawn; }
                     boards[0][n][BOARD_WIDTH-1] = selection;
                     boards[0][n][BOARD_WIDTH-2]++;
                 }
             } else
            boards[0][y][x] = selection;
+           rightsBoard[y][x] = rights; // [HGM] editrights: set default rights of created piece
            DrawPosition(TRUE, boards[0]);
        }
        break;
@@ -11654,7 +12326,7 @@ void
 AcceptEvent()
 {
     /* Accept a pending offer of any kind from opponent */
-    
+
     if (appData.icsActive) {
         SendToICS(ics_prefix);
        SendToICS("accept\n");
@@ -11679,7 +12351,7 @@ void
 DeclineEvent()
 {
     /* Decline a pending offer of any kind from opponent */
-    
+
     if (appData.icsActive) {
         SendToICS(ics_prefix);
        SendToICS("decline\n");
@@ -11751,16 +12423,17 @@ void
 DrawEvent()
 {
     /* Offer draw or accept pending draw offer from opponent */
-    
+
     if (appData.icsActive) {
        /* Note: tournament rules require draw offers to be
           made after you make your move but before you punch
           your clock.  Currently ICS doesn't let you do that;
           instead, you immediately punch your clock after making
           a move, but you can offer a draw at any time. */
-       
+
         SendToICS(ics_prefix);
        SendToICS("draw\n");
+        userOfferedDraw = TRUE; // [HGM] drawclaim: also set flag in ICS play
     } else if (cmailMsgLoaded) {
        if (currentMove == cmailOldMove &&
            commentList[cmailOldMove] != NULL &&
@@ -11792,7 +12465,7 @@ void
 AdjournEvent()
 {
     /* Offer Adjourn or accept pending Adjourn offer from opponent */
-    
+
     if (appData.icsActive) {
         SendToICS(ics_prefix);
        SendToICS("adjourn\n");
@@ -11806,7 +12479,7 @@ void
 AbortEvent()
 {
     /* Offer Abort or accept pending Abort offer from opponent */
-    
+
     if (appData.icsActive) {
         SendToICS(ics_prefix);
        SendToICS("abort\n");
@@ -11819,7 +12492,7 @@ void
 ResignEvent()
 {
     /* Resign.  You can do this even if it's not your turn. */
-    
+
     if (appData.icsActive) {
         SendToICS(ics_prefix);
        SendToICS("resign\n");
@@ -11880,12 +12553,12 @@ ForwardInner(target)
 
     if (gameMode == PlayFromGameFile && !pausing)
       PauseEvent();
-    
+
     if (gameMode == IcsExamining && pausing)
       limit = pauseExamForwardMostMove;
     else
       limit = forwardMostMove;
-    
+
     if (target > limit) target = limit;
 
     if (target > 0 && moveList[target - 1][0]) {
@@ -11907,8 +12580,8 @@ ForwardInner(target)
            }
        }
     }
-    if (gameMode == EditGame || gameMode == AnalyzeMode || 
-       gameMode == Training || gameMode == PlayFromGameFile || 
+    if (gameMode == EditGame || gameMode == AnalyzeMode ||
+       gameMode == Training || gameMode == PlayFromGameFile ||
        gameMode == AnalyzeFile) {
        while (currentMove < target) {
            SendMoveToProgram(currentMove++, &first);
@@ -11916,7 +12589,7 @@ ForwardInner(target)
     } else {
        currentMove = target;
     }
-    
+
     if (gameMode == EditGame || gameMode == EndOfGame) {
        whiteTimeRemaining = timeRemaining[0][currentMove];
        blackTimeRemaining = timeRemaining[1][currentMove];
@@ -11949,13 +12622,13 @@ ToEndEvent()
        /* to optimze, we temporarily turn off analysis mode while we feed
         * the remaining moves to the engine. Otherwise we get analysis output
         * after each move.
-        */ 
+        */
         if (first.analysisSupport) {
          SendToProgram("exit\nforce\n", &first);
          first.analyzing = FALSE;
        }
     }
-       
+
     if (gameMode == IcsExamining && !pausing) {
         SendToICS(ics_prefix);
        SendToICS("forward 999999\n");
@@ -11990,7 +12663,7 @@ BackwardInner(target)
     }
     if (gameMode == PlayFromGameFile && !pausing)
       PauseEvent();
-    
+
     if (moveList[target][0]) {
        int fromX, fromY, toX, toY;
         toX = moveList[target][2] - AAA;
@@ -12019,7 +12692,7 @@ BackwardInner(target)
     } else {
        currentMove = target;
     }
-    
+
     if (gameMode == EditGame || gameMode == EndOfGame) {
        whiteTimeRemaining = timeRemaining[0][currentMove];
        blackTimeRemaining = timeRemaining[1][currentMove];
@@ -12049,7 +12722,7 @@ ToStartEvent()
     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
        /* to optimize, we temporarily turn off analysis mode while we undo
         * all the moves. Otherwise we get analysis output after each undo.
-        */ 
+        */
         if (first.analysisSupport) {
          SendToProgram("exit\nforce\n", &first);
          first.analyzing = FALSE;
@@ -12274,7 +12947,7 @@ PrintPosition(fp, move)
      int move;
 {
     int i, j;
-    
+
     for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
         for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {
            char c = PieceToChar(boards[move][i][j]);
@@ -12652,18 +13325,18 @@ SendToProgram(message, cps)
 
     if (cps->pr == NULL) return;
     Attention(cps);
-    
+
     if (appData.debugMode) {
        TimeMark now;
        GetTimeMark(&now);
-       fprintf(debugFP, "%ld >%-6s: %s", 
+       fprintf(debugFP, "%ld >%-6s: %s",
                SubtractTimeMarks(&now, &programStartTime),
                cps->which, message);
     }
-    
+
     count = strlen(message);
     outCount = OutputToProcess(cps->pr, message, count, &error);
-    if (outCount < count && !exiting 
+    if (outCount < count && !exiting
                          && !endingGame) { /* [HGM] crash: to not hang GameEnds() writing to deceased engines */
        sprintf(buf, _("Error writing to %s chess program"), cps->which);
         if(gameInfo.resultDetails==NULL) { /* [HGM] crash: if game in progress, give reason for abort */
@@ -12724,12 +13397,12 @@ ReceiveFromProgram(isr, closure, message, count, error)
        }
        return;
     }
-    
+
     if ((end_str = strchr(message, '\r')) != NULL)
       *end_str = NULLCHAR;
     if ((end_str = strchr(message, '\n')) != NULL)
       *end_str = NULLCHAR;
-    
+
     if (appData.debugMode) {
        TimeMark now; int print = 1;
        char *quote = ""; char c; int i;
@@ -12737,7 +13410,7 @@ ReceiveFromProgram(isr, closure, message, count, error)
        if(appData.engineComments != 1) { /* [HGM] debug: decide if protocol-violating output is written */
                char start = message[0];
                if(start >='A' && start <= 'Z') start += 'a' - 'A'; // be tolerant to capitalizing
-               if(sscanf(message, "%d%c%d%d%d", &i, &c, &i, &i, &i) != 5 && 
+               if(sscanf(message, "%d%c%d%d%d", &i, &c, &i, &i, &i) != 5 &&
                   sscanf(message, "move %c", &c)!=1  && sscanf(message, "offer%c", &c)!=1 &&
                   sscanf(message, "resign%c", &c)!=1 && sscanf(message, "feature %c", &c)!=1 &&
                   sscanf(message, "error %c", &c)!=1 && sscanf(message, "illegal %c", &c)!=1 &&
@@ -12749,8 +13422,8 @@ ReceiveFromProgram(isr, closure, message, count, error)
        }
        if(print) {
                GetTimeMark(&now);
-               fprintf(debugFP, "%ld <%-6s: %s%s\n", 
-                       SubtractTimeMarks(&now, &programStartTime), cps->which, 
+               fprintf(debugFP, "%ld <%-6s: %s%s\n",
+                       SubtractTimeMarks(&now, &programStartTime), cps->which,
                        quote,
                        message);
        }
@@ -12759,7 +13432,7 @@ ReceiveFromProgram(isr, closure, message, count, error)
     /* [DM] if icsEngineAnalyze is active we block all whisper and kibitz output, because nobody want to see this */
     if (appData.icsEngineAnalyze) {
         if (strstr(message, "whisper") != NULL ||
-             strstr(message, "kibitz") != NULL || 
+             strstr(message, "kibitz") != NULL ||
             strstr(message, "tellics") != NULL) return;
     }
 
@@ -12837,7 +13510,7 @@ SendTimeControl(cps, mps, tc, inc, sd, st)
 ChessProgramState *WhitePlayer()
 /* [HGM] return pointer to 'first' or 'second', depending on who plays white */
 {
-    if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b' || 
+    if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b' ||
        gameMode == BeginningOfGame || gameMode == MachinePlaysBlack)
         return &second;
     return &first;
@@ -12870,7 +13543,7 @@ SendTimeRemaining(cps, machineWhite)
 
     if (time <= 0) time = 1;
     if (otime <= 0) otime = 1;
-    
+
     sprintf(message, "time %ld\n", time);
     SendToProgram(message, cps);
 
@@ -12942,7 +13615,7 @@ StringFeature(p, name, loc, cps)
   return FALSE;
 }
 
-int 
+int
 ParseOption(Option *opt, ChessProgramState *cps)
 // [HGM] options: process the string that defines an engine option, and determine
 // name, type, default value, and allowed value range
@@ -13037,7 +13710,7 @@ FeatureDone(cps, val)
 void
 ParseFeatures(args, cps)
      char* args;
-     ChessProgramState *cps;  
+     ChessProgramState *cps;
 {
   char *p = args;
   char *q;
@@ -13049,10 +13722,10 @@ ParseFeatures(args, cps)
     if (*p == NULLCHAR) return;
 
     if (BoolFeature(&p, "setboard", &cps->useSetboard, cps)) continue;
-    if (BoolFeature(&p, "time", &cps->sendTime, cps)) continue;    
-    if (BoolFeature(&p, "draw", &cps->sendDrawOffers, cps)) continue;    
-    if (BoolFeature(&p, "sigint", &cps->useSigint, cps)) continue;    
-    if (BoolFeature(&p, "sigterm", &cps->useSigterm, cps)) continue;    
+    if (BoolFeature(&p, "time", &cps->sendTime, cps)) continue;
+    if (BoolFeature(&p, "draw", &cps->sendDrawOffers, cps)) continue;
+    if (BoolFeature(&p, "sigint", &cps->useSigint, cps)) continue;
+    if (BoolFeature(&p, "sigterm", &cps->useSigterm, cps)) continue;
     if (BoolFeature(&p, "reuse", &val, cps)) {
       /* Engine can disable reuse, but can't enable it if user said no */
       if (!val) cps->reuse = FALSE;
@@ -13191,7 +13864,7 @@ ShowThinkingEvent()
     int newState = appData.showThinking
        // [HGM] thinking: other features now need thinking output as well
        || !appData.hideThinkingFromHuman || appData.adjudicateLossThreshold != 0 || EngineOutputIsUp();
-    
+
     if (oldState == newState) return;
     oldState = newState;
     if (gameMode == EditPosition) EditPositionDone(TRUE);
@@ -13228,8 +13901,8 @@ DisplayMove(moveNumber)
     char cpThinkOutput[MSG_SIZ];
 
     if(appData.noGUI) return; // [HGM] fast: suppress display of moves
-    
-    if (moveNumber == forwardMostMove - 1 || 
+
+    if (moveNumber == forwardMostMove - 1 ||
        gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
 
        safeStrCpy(cpThinkOutput, thinkOutput, sizeof(cpThinkOutput));
@@ -13285,7 +13958,6 @@ DisplayComment(moveNumber, text)
     char title[MSG_SIZ];
     char buf[8000]; // comment can be long!
     int score, depth;
-    
     if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) {
       strcpy(title, "Comment");
     } else {
@@ -13302,7 +13974,7 @@ DisplayComment(moveNumber, text)
       text = buf;
     }
     if (text != NULL && (appData.autoDisplayComment || commentUp))
-        CommentPopUp(title, text);
+      CommentPopUp(title, text);
 }
 
 /* This routine sends a ^C interrupt to gnuchess, to awaken it if it
@@ -13441,7 +14113,7 @@ GetTimeMark(tm)
     struct timezone timeZone;
 
     gettimeofday(&timeVal, &timeZone);
-    tm->sec = (long) timeVal.tv_sec; 
+    tm->sec = (long) timeVal.tv_sec;
     tm->ms = (int) (timeVal.tv_usec / 1000L);
 
 #else /*!HAVE_GETTIMEOFDAY*/
@@ -13480,7 +14152,7 @@ SubtractTimeMarks(tm2, tm1)
  * We give the human user a slight advantage if he is playing white---the
  * clocks don't run until he makes his first move, so it takes zero time.
  * Also, we don't account for network lag, so we could get out of sync
- * with GNU Chess's clock -- but then, referees are always right.  
+ * with GNU Chess's clock -- but then, referees are always right.
  */
 
 static TimeMark tickStartTM;
@@ -13513,7 +14185,7 @@ AdjustClock(Boolean which, int dir)
 
 /* Stop clocks and reset to a fresh time control */
 void
-ResetClocks() 
+ResetClocks()
 {
     (void) StopClockTimer();
     if (appData.icsActive) {
@@ -13544,7 +14216,7 @@ DecrementClocks()
 
     if (!appData.clockMode) return;
     if (gameMode==AnalyzeMode || gameMode == AnalyzeFile) return;
-       
+
     GetTimeMark(&now);
 
     lastTickLength = SubtractTimeMarks(&now, &tickStartTM);
@@ -13566,7 +14238,7 @@ DecrementClocks()
     }
 
     if (CheckFlags()) return;
-       
+
     tickStartTM = now;
     intendedTickLength = NextTickLength(timeRemaining - fudge) + fudge;
     StartClockTimer(intendedTickLength);
@@ -13574,9 +14246,9 @@ DecrementClocks()
     /* if the time remaining has fallen below the alarm threshold, sound the
      * alarm. if the alarm has sounded and (due to a takeback or time control
      * with increment) the time remaining has increased to a level above the
-     * threshold, reset the alarm so it can sound again. 
+     * threshold, reset the alarm so it can sound again.
      */
-    
+
     if (appData.icsActive && appData.icsAlarm) {
 
        /* make sure we are dealing with the user's clock */
@@ -13586,7 +14258,7 @@ DecrementClocks()
 
        if (alarmSounded && (timeRemaining > appData.icsAlarmTime)) {
            alarmSounded = FALSE;
-       } else if (!alarmSounded && (timeRemaining <= appData.icsAlarmTime)) { 
+       } else if (!alarmSounded && (timeRemaining <= appData.icsAlarmTime)) {
            PlayAlarmSound();
            alarmSounded = TRUE;
        }
@@ -13625,7 +14297,7 @@ SwitchClocks()
           whiteTimeRemaining -= lastTickLength;
            /* [HGM] PGNtime: save time for PGN file if engine did not give it */
 //         if(pvInfoList[forwardMostMove-1].time == -1)
-                 pvInfoList[forwardMostMove-1].time = 
+                 pvInfoList[forwardMostMove-1].time =
                       (timeRemaining[0][forwardMostMove-1] - whiteTimeRemaining)/10;
        }
        flagged = CheckFlags();
@@ -13661,12 +14333,12 @@ SwitchClocks()
       whiteTimeRemaining : blackTimeRemaining);
     StartClockTimer(intendedTickLength);
 }
-       
+
 
 /* Stop both clocks */
 void
 StopClocks()
-{      
+{
     long lastTickLength;
     TimeMark now;
 
@@ -13687,7 +14359,7 @@ StopClocks()
     }
     CheckFlags();
 }
-       
+
 /* Start clock of player on move.  Time may have been reset, so
    if clock is already running, stop and restart it. */
 void
@@ -13705,7 +14377,7 @@ StartClocks()
       whiteTimeRemaining : blackTimeRemaining);
 
    /* [HGM] nps: figure out nps factors, by determining which engine plays white and/or black once and for all */
-    whiteNPS = blackNPS = -1; 
+    whiteNPS = blackNPS = -1;
     if(gameMode == MachinePlaysWhite || gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'w'
        || appData.zippyPlay && gameMode == IcsPlayingBlack) // first (perhaps only) engine has white
        whiteNPS = first.nps;
@@ -13728,7 +14400,7 @@ TimeString(ms)
     long second, minute, hour, day;
     char *sign = "";
     static char buf[32];
-    
+
     if (ms > 0 && ms <= 9900) {
       /* convert milliseconds to tenths, rounding up */
       double tenths = floor( ((double)(ms + 99L)) / 100.00 );
@@ -13746,14 +14418,14 @@ TimeString(ms)
        sign = "-";
        second = -second;
     }
-    
+
     day = second / (60 * 60 * 24);
     second = second % (60 * 60 * 24);
     hour = second / (60 * 60);
     second = second % (60 * 60);
     minute = second / 60;
     second = second % 60;
-    
+
     if (day > 0)
       sprintf(buf, " %s%ld:%02ld:%02ld:%02ld ",
              sign, day, hour, minute, second);
@@ -13761,7 +14433,7 @@ TimeString(ms)
       sprintf(buf, " %s%ld:%02ld:%02ld ", sign, hour, minute, second);
     else
       sprintf(buf, " %s%2ld:%02ld ", sign, minute, second);
-    
+
     return buf;
 }
 
@@ -13774,13 +14446,13 @@ StrStr(string, match)
      char *string, *match;
 {
     int i, length;
-    
+
     length = strlen(match);
-    
+
     for (i = strlen(string) - length; i >= 0; i--, string++)
       if (!strncmp(match, string, length))
        return string;
-    
+
     return NULL;
 }
 
@@ -13789,9 +14461,9 @@ StrCaseStr(string, match)
      char *string, *match;
 {
     int i, j, length;
-    
+
     length = strlen(match);
-    
+
     for (i = strlen(string) - length; i >= 0; i--, string++) {
        for (j = 0; j < length; j++) {
            if (ToLower(match[j]) != ToLower(string[j]))
@@ -13809,7 +14481,7 @@ StrCaseCmp(s1, s2)
      char *s1, *s2;
 {
     char c1, c2;
-    
+
     for (;;) {
        c1 = ToLower(*s1++);
        c2 = ToLower(*s2++);
@@ -13909,7 +14581,7 @@ PositionToFEN(move, overrideCastling)
                     /* [HGM] write promoted pieces as '+<unpromoted>' (Shogi) */
                     *p++ = '+';
                     piece = (ChessSquare)(DEMOTED piece);
-                } 
+                }
                 *p++ = PieceToChar(piece);
                 if(p[-1] == '~') {
                     /* [HGM] flag promoted pieces as '<promoted>~' (Crazyhouse) */
@@ -14041,7 +14713,7 @@ PositionToFEN(move, overrideCastling)
     }
     /* Fullmove number */
     sprintf(p, "%d", (move / 2) + 1);
-    
+
     return StrSave(buf);
 }
 
@@ -14149,7 +14821,7 @@ ParseFEN(board, blackPlaysFirst, fen)
       case 'w':
         *blackPlaysFirst = FALSE;
        break;
-      case 'b': 
+      case 'b':
        *blackPlaysFirst = TRUE;
        break;
       default:
@@ -14282,7 +14954,7 @@ ParseFEN(board, blackPlaysFirst, fen)
 
     return TRUE;
 }
-      
+
 void
 EditPositionPasteFEN(char *fen)
 {