Merge branch 'v4.7.x' into master
authorArun Persaud <arun@nubati.net>
Sun, 5 Jan 2014 18:51:08 +0000 (10:51 -0800)
committerArun Persaud <arun@nubati.net>
Sun, 5 Jan 2014 18:51:08 +0000 (10:51 -0800)
Conflicts:
dialogs.c
gtk/xboard.c
gtk/xoptions.c
po/es.po
winboard/config.h
winboard/winboard.c

31 files changed:
1  2 
args.h
backend.c
backend.h
board.c
common.h
configure.ac
dialogs.c
draw.c
frontend.h
gamelist.c
gtk/xboard.c
gtk/xoptions.c
menus.c
moves.c
moves.h
nengineoutput.c
parser.c
po/ru.po
usounds.c
usystem.c
winboard/defaults.h
winboard/wclipbrd.c
winboard/wedittags.c
winboard/winboard.c
winboard/winboard.rc
winboard/woptions.c
winboard/wsettings.c
xaw/xboard.c
xaw/xengineoutput.c
xaw/xoptions.c
xboard2.h

diff --combined args.h
--- 1/args.h
--- 2/args.h
+++ b/args.h
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
@@@ -60,7 -60,7 +60,7 @@@
  typedef enum {
    ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
    ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
 -  ArgSettingsFilename, ArgBackupSettingsFile, ArgTwo,
 +  ArgSettingsFilename, ArgBackupSettingsFile, ArgTwo, ArgInstall, ArgMaster,
    ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
  } ArgType;
  
@@@ -102,10 -102,7 +102,10 @@@ typedef struct 
  IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
  
  int junk;
 +unsigned int saveDate;
 +unsigned int dateStamp;
  Boolean singleList;
 +Boolean autoClose;
  char *homeDir;
  char *firstEngineLine;
  char *secondEngineLine;
@@@ -152,9 -149,6 +152,9 @@@ ArgDescriptor argDescriptors[] = 
    { "loadGameFile", ArgFilename, (void *) &appData.loadGameFile, FALSE, INVALID },
    { "", ArgNone, NULL, FALSE, INVALID },
    /* keyword arguments */
 +  { "saveDate", ArgInt, (void *) &saveDate, TRUE, 0 },
 +  { "date", ArgInt, (void *) &dateStamp, FALSE, 0 },
 +  { "autoClose", ArgTrue, (void *) &autoClose, FALSE, FALSE },
    JAWS_ARGS
    { "whitePieceColor", ArgColor, (void *) 0, TRUE, (ArgIniType) WHITE_PIECE_COLOR },
    { "wpc", ArgColor, (void *) 0, FALSE, INVALID },
    { "soundSeek", ArgFilename, (void *) &appData.soundSeek, TRUE, (ArgIniType) "" },
    { "soundMove", ArgFilename, (void *) &appData.soundMove, TRUE, (ArgIniType) "" },
    { "soundBell", ArgFilename, (void *) &appData.soundBell, TRUE, (ArgIniType) SOUND_BELL },
 +  { "soundRoar", ArgFilename, (void *) &appData.soundRoar, TRUE, (ArgIniType) "" },
    { "soundIcsWin", ArgFilename, (void *) &appData.soundIcsWin, TRUE, (ArgIniType) "" },
    { "soundIcsLoss", ArgFilename, (void *) &appData.soundIcsLoss, TRUE, (ArgIniType) "" },
    { "soundIcsDraw", ArgFilename, (void *) &appData.soundIcsDraw, TRUE, (ArgIniType) "" },
    { "secondChessProgramNames", ArgString, (void *) &secondChessProgramNames,
      !XBOARD, (ArgIniType) SCP_NAMES },
    { "themeNames", ArgString, (void *) &appData.themeNames, !XBOARD, (ArgIniType) "native -upf false -ub false -ubt false -pid \"\"\n" },
 +  { "addMasterOption", ArgMaster, NULL, FALSE, INVALID },
 +  { "installEngine", ArgInstall, (void *) &firstChessProgramNames, FALSE, (ArgIniType) "" },
    { "initialMode", ArgString, (void *) &appData.initialMode, FALSE, (ArgIniType) "" },
    { "mode", ArgString, (void *) &appData.initialMode, FALSE, INVALID },
    { "variant", ArgString, (void *) &appData.variant, FALSE, (ArgIniType) "normal" },
    { "useBorder", ArgBoolean, (void *) &appData.useBorder, TRUE, (ArgIniType) FALSE },
    { "ub", ArgBoolean, (void *) &appData.useBorder, FALSE, INVALID },
    { "border", ArgFilename, (void *) &appData.border, TRUE, (ArgIniType) "" },
 +  { "finger", ArgFilename, (void *) &appData.finger, FALSE, (ArgIniType) "" },
  
    // [HGM] tournament options
    { "tourneyFile", ArgFilename, (void *) &appData.tourneyFile, FALSE, (ArgIniType) "" },
    { "topLevel", ArgBoolean, (void *) &appData.topLevel, XBOARD, (ArgIniType) TOPLEVEL },
    { "dialogColor", ArgString, (void *) &appData.dialogColor, XBOARD, (ArgIniType) "" },
    { "buttonColor", ArgString, (void *) &appData.buttonColor, XBOARD, (ArgIniType) "" },
 +  { "firstDrawDepth", ArgInt, (void *) &appData.drawDepth[0], FALSE, (ArgIniType) 0 },
 +  { "secondDrawDepth", ArgInt, (void *) &appData.drawDepth[1], FALSE, (ArgIniType) 0 },
  
  #if ZIPPY
    { "zippyTalk", ArgBoolean, (void *) &appData.zippyTalk, FALSE, (ArgIniType) ZIPPY_TALK },
@@@ -834,30 -822,6 +834,30 @@@ ExitArgError(char *msg, char *badArg, B
    exit(2);
  }
  
 +void
 +AppendToSettingsFile (char *line)
 +{
 +  char buf[MSG_SIZ];
 +  FILE *f;
 +  int c;
 +  if(f = fopen(SETTINGS_FILE, "r")) {
 +    do {
 +      int i = 0;
 +      while((buf[i] = c = fgetc(f)) != '\n' && c != EOF) if(i < MSG_SIZ-1) i++;
 +      buf[i] = NULLCHAR;
 +      if(!strcmp(line, buf)) return; // line occurs
 +    } while(c != EOF);
 +    // line did not occur; add it
 +    fclose(f);
 +    if(f = fopen(SETTINGS_FILE, "a")) {
 +      TimeMark now;
 +      GetTimeMark(&now);
 +      fprintf(f, "-date %10lu\n%s\n", now.sec, line);
 +      fclose(f);
 +    }
 +  }
 +}
 +
  int
  ValidateInt(char *s)
  {
@@@ -909,12 -873,6 +909,12 @@@ ParseSettingsFile(char *name, char **ad
      }
    if (ok) {
      f = fopen(fullname, "r");
 +#ifdef DATADIR
 +    if(f == NULL && *fullname != '/') {         // when a relative name did not work
 +      MySearchPath(DATADIR "/themes/conf", name, fullname); // also look in standard place
 +      f = fopen(fullname, "r");
 +    }
 +#endif
      if (f != NULL) {
        if (addr != NULL) {
            ASSIGN(*addr, fullname);
@@@ -1208,20 -1166,6 +1208,20 @@@ ParseArgs(GetFunc get, void *cl
        ParseCommPortSettings(argValue);
        break;
  
 +    case ArgMaster:
 +      AppendToSettingsFile(argValue);
 +      break;
 +
 +    case ArgInstall:
 +      q = *(char **) ad->argLoc;
 +      if((saveDate == 0 || saveDate - dateStamp < 0) && !strstr(q, argValue) ) {
 +        int l = strlen(q) + strlen(argValue);
 +        *(char **) ad->argLoc = malloc(l+2);
 +        snprintf(*(char **) ad->argLoc, l+2, "%s%s\n", q, argValue);
 +        free(q);
 +      }
 +      break;
 +
      case ArgNone:
        ExitArgError(_("Unrecognized argument %s"), argValue, TRUE);
        break;
@@@ -1457,11 -1401,6 +1457,11 @@@ InitAppData(char *lpCmdLine
      appData.savePositionFile = strdup(buf);
    }
  
 +  if(autoClose) { // was called for updating settingsfile only
 +    if(saveSettingsOnExit) SaveSettings(settingsFileName);
 +    exit(0);
 +  }
 +
    /* Finish initialization for fonts and sounds */
    CreateFonts();
  
@@@ -1492,11 -1431,8 +1492,11 @@@ SaveSettings(char* name
    ArgDescriptor *ad;
    char dir[MSG_SIZ], buf[MSG_SIZ];
    int mps = appData.movesPerSession;
 +  TimeMark now;
 +
 +  if (!MainWindowUp() && !autoClose) return;
  
 -  if (!MainWindowUp()) return;
 +  GetTimeMark(&now); saveDate = now.sec;
  
    GetCurrentDirectory(MSG_SIZ, dir);
    if(MySearchPath(installDir, name, buf)) {
      case ArgNone:
      case ArgBackupSettingsFile:
      case ArgSettingsFilename: ;
 +    case ArgMaster: ;
 +    case ArgInstall: ;
      }
    }
    fclose(f);
diff --combined backend.c
+++ b/backend.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
  #ifdef WIN32
  #include <windows.h>
  
 -int flock(int f, int code);
 -#define LOCK_EX 2
 -#define SLASH '\\'
 +    int flock(int f, int code);
 +#   define LOCK_EX 2
 +#   define SLASH '\\'
 +
 +#   ifdef ARC_64BIT
 +#       define EGBB_NAME "egbbdll64.dll"
 +#   else
 +#       define EGBB_NAME "egbbdll.dll"
 +#   endif
  
  #else
  
 -#include <sys/file.h>
 -#define SLASH '/'
 +#   include <sys/file.h>
 +#   define SLASH '/'
 +
 +#   include <dlfcn.h>
 +#   ifdef ARC_64BIT
 +#       define EGBB_NAME "egbbso64.so"
 +#   else
 +#       define EGBB_NAME "egbbso.so"
 +#   endif
 +    // kludge to allow Windows code in back-end by converting it to corresponding Linux code 
 +#   define CDECL
 +#   define HMODULE void *
 +#   define LoadLibrary(x) dlopen(x, RTLD_LAZY)
 +#   define GetProcAddress dlsym
  
  #endif
  
@@@ -243,7 -225,7 +243,7 @@@ void DisplayTwoMachinesTitle P(())
  static void ExcludeClick P((int index));
  void ToggleSecond P((void));
  void PauseEngine P((ChessProgramState *cps));
 -static int NonStandardBoardSize P((void));
 +static int NonStandardBoardSize P((VariantClass v, int w, int h, int s));
  
  #ifdef WIN32
         extern void ConsoleCreate();
@@@ -287,13 -269,11 +287,13 @@@ char chatPartner[MAX_CHAT][MSG_SIZ]; /
  extern int chatCount;
  int chattingPartner;
  char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */
 +char legal[BOARD_RANKS][BOARD_FILES];  /* [HGM] legal target squares */
  char lastMsg[MSG_SIZ];
  ChessSquare pieceSweep = EmptySquare;
  ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
  int promoDefaultAltered;
  int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */
 +static int initPing = -1;
  
  /* States for ics_getting_history */
  #define H_FALSE 0
@@@ -408,7 -388,6 +408,7 @@@ PosFlags (index
    case VariantShatranj:
    case VariantCourier:
    case VariantMakruk:
 +  case VariantASEAN:
    case VariantGrand:
      flags &= ~F_ALL_CASTLE_OK;
      break;
@@@ -578,20 -557,6 +578,20 @@@ ChessSquare makrukArray[2][BOARD_FILES
          BlackKing, BlackMan, BlackKnight, BlackRook }
  };
  
 +ChessSquare aseanArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */
 +    { WhiteRook, WhiteKnight, WhiteMan, WhiteFerz,
 +        WhiteKing, WhiteMan, WhiteKnight, WhiteRook },
 +    { BlackRook, BlackKnight, BlackMan, BlackFerz,
 +        BlackKing, BlackMan, BlackKnight, BlackRook }
 +};
 +
 +ChessSquare  lionArray[2][BOARD_FILES] = {
 +    { WhiteRook, WhiteLion, WhiteBishop, WhiteQueen,
 +      WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },
 +    { BlackRook, BlackLion, BlackBishop, BlackQueen,
 +      BlackKing, BlackBishop, BlackKnight, BlackRook }
 +};
 +
  
  #if (BOARD_FILES>=10)
  ChessSquare ShogiArray[2][BOARD_FILES] = {
@@@ -636,13 -601,6 +636,13 @@@ ChessSquare GrandArray[2][BOARD_FILES] 
          BlackMarshall, BlackAngel, BlackBishop, BlackKnight, EmptySquare }
  };
  
 +ChessSquare ChuChessArray[2][BOARD_FILES] = {
 +    { WhiteMan, WhiteKnight, WhiteBishop, WhiteCardinal, WhiteLion,
 +        WhiteQueen, WhiteDragon, WhiteBishop, WhiteKnight, WhiteMan },
 +    { BlackMan, BlackKnight, BlackBishop, BlackDragon, BlackQueen,
 +        BlackLion, BlackCardinal, BlackBishop, BlackKnight, BlackMan }
 +};
 +
  #ifdef GOTHIC
  ChessSquare GothicArray[2][BOARD_FILES] = {
      { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall,
@@@ -679,23 -637,8 +679,23 @@@ ChessSquare CourierArray[2][BOARD_FILES
      { BlackRook, BlackKnight, BlackAlfil, BlackBishop, BlackMan, BlackKing,
          BlackFerz, BlackWazir, BlackBishop, BlackAlfil, BlackKnight, BlackRook }
  };
 +ChessSquare ChuArray[6][BOARD_FILES] = {
 +    { WhiteLance, WhiteUnicorn, WhiteMan, WhiteFerz, WhiteWazir, WhiteKing,
 +      WhiteAlfil, WhiteWazir, WhiteFerz, WhiteMan, WhiteUnicorn, WhiteLance },
 +    { BlackLance, BlackUnicorn, BlackMan, BlackFerz, BlackWazir, BlackAlfil,
 +      BlackKing, BlackWazir, BlackFerz, BlackMan, BlackUnicorn, BlackLance },
 +    { WhiteCannon, EmptySquare, WhiteBishop, EmptySquare, WhiteNightrider, WhiteMarshall,
 +      WhiteAngel, WhiteNightrider, EmptySquare, WhiteBishop, EmptySquare, WhiteCannon },
 +    { BlackCannon, EmptySquare, BlackBishop, EmptySquare, BlackNightrider, BlackAngel,
 +      BlackMarshall, BlackNightrider, EmptySquare, BlackBishop, EmptySquare, BlackCannon },
 +    { WhiteFalcon, WhiteSilver, WhiteRook, WhiteCardinal, WhiteDragon, WhiteLion,
 +      WhiteQueen, WhiteDragon, WhiteCardinal, WhiteRook, WhiteSilver, WhiteFalcon },
 +    { BlackFalcon, BlackSilver, BlackRook, BlackCardinal, BlackDragon, BlackQueen,
 +      BlackLion, BlackDragon, BlackCardinal, BlackRook, BlackSilver, BlackFalcon }
 +};
  #else // !(BOARD_FILES>=12)
  #define CourierArray CapablancaArray
 +#define ChuArray CapablancaArray
  #endif // !(BOARD_FILES>=12)
  
  
@@@ -863,7 -806,6 +863,7 @@@ InitEngine (ChessProgramState *cps, in
      /* [HGM] debug */
      cps->debug = FALSE;
  
 +    cps->drawDepth = appData.drawDepth[n];
      cps->supportsNPS = UNKNOWN;
      cps->memSize = FALSE;
      cps->maxCores = FALSE;
      cps->scoreIsAbsolute = appData.scoreIsAbsolute[n]; /* [AS] */
      cps->isUCI = appData.isUCI[n]; /* [AS] */
      cps->hasOwnBookUCI = appData.hasOwnBookUCI[n]; /* [AS] */
 +    cps->highlight = 0;
  
      if (appData.protocolVersion[n] > PROTOVER
        || appData.protocolVersion[n] < 1)
@@@ -974,7 -915,7 +974,7 @@@ char *insert, *wbOptions; // point in C
  void
  Load (ChessProgramState *cps, int i)
  {
 -    char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ];
 +    char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ], buf3[MSG_SIZ], jar;
      if(engineLine && engineLine[0]) { // an engine was selected from the combo box
        snprintf(buf, MSG_SIZ, "-fcp %s", engineLine);
        SwapEngines(i); // kludge to parse -f* / -first* like it is -s* / -second*
        p[-1] = SLASH;
        if(SLASH == '/' && p - engineName > 1) *(p -= 2) = '.'; // for XBoard use ./exeName as command after split!
      } else { ASSIGN(appData.directory[i], "."); }
 +    jar = (strstr(p, ".jar") == p + strlen(p) - 4);
      if(params[0]) {
        if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces
        snprintf(command, MSG_SIZ, "%s %s", p, params);
        p = command;
      }
 +    if(jar) { snprintf(buf3, MSG_SIZ, "java -jar %s", p); p = buf3; }
      ASSIGN(appData.chessProgram[i], p);
      appData.isUCI[i] = isUCI;
      appData.protocolVersion[i] = v1 ? 1 : PROTOVER;
@@@ -1199,7 -1138,6 +1199,7 @@@ InitBackEnd1 (
        case VariantCapablanca: /* [HGM] should work */
        case VariantCourier:    /* [HGM] initial forced moves not implemented */
        case VariantShogi:      /* [HGM] could still mate with pawn drop */
 +      case VariantChu:        /* [HGM] experimental */
        case VariantKnightmate: /* [HGM] should work */
        case VariantCylinder:   /* [HGM] untested */
        case VariantFalcon:     /* [HGM] untested */
        case Variant3Check:     /* should work except for win condition */
        case VariantShatranj:   /* should work except for all win conditions */
        case VariantMakruk:     /* should work except for draw countdown */
 +      case VariantASEAN :     /* should work except for draw countdown */
        case VariantBerolina:   /* might work if TestLegality is off */
        case VariantCapaRandom: /* should work */
        case VariantJanus:      /* should work */
        case VariantSChess:     /* S-Chess, should work */
        case VariantGrand:      /* should work */
        case VariantSpartan:    /* should work */
 +      case VariantLion:       /* should work */
 +      case VariantChuChess:   /* should work */
        break;
        }
      }
@@@ -1550,7 -1485,7 +1550,7 @@@ MatchEvent (int mode
                        NextTourneyGame(-1, &dummy);
                        ReserveGame(-1, 0);
                        if(nextGame <= appData.matchGames) {
 -                          DisplayNote(_("You restarted an already completed tourney\nOne more cycle will now be added to it\nGames commence in 10 sec"));
 +                          DisplayNote(_("You restarted an already completed tourney.\nOne more cycle will now be added to it.\nGames commence in 10 sec."));
                            matchMode = mode;
                            ScheduleDelayedEvent(NextMatchGame, 10000);
                            return;
@@@ -1583,23 -1518,6 +1583,23 @@@ InitBackEnd3 P((void)
      char buf[MSG_SIZ];
      int err, len;
  
 +    if(!appData.icsActive && !appData.noChessProgram && !appData.matchMode &&                         // mode involves only first engine
 +       !strcmp(appData.variant, "normal") &&                                                          // no explicit variant request
 +        appData.NrRanks == -1 && appData.NrFiles == -1 && appData.holdingsSize == -1 &&               // no size overrides requested
 +       !SupportedVariant(first.variants, VariantNormal, 8, 8, 0, first.protocolVersion, "") &&        // but 'normal' won't work with engine
 +       !SupportedVariant(first.variants, VariantFischeRandom, 8, 8, 0, first.protocolVersion, "") ) { // nor will Chess960
 +      char c, *q = first.variants, *p = strchr(q, ',');
 +      if(p) *p = NULLCHAR;
 +      if(StringToVariant(q) != VariantUnknown) { // the engine can play a recognized variant, however
 +          int w, h, s;
 +          if(sscanf(q, "%dx%d+%d_%c", &w, &h, &s, &c) == 4) // get size overrides the engine needs with it (if any)
 +              appData.NrFiles = w, appData.NrRanks = h, appData.holdingsSize = s, q = strchr(q, '_') + 1;
 +          ASSIGN(appData.variant, q); // fake user requested the first variant played by the engine
 +          Reset(TRUE, FALSE);         // and re-initialize
 +      }
 +      if(p) *p = ',';
 +    }
 +
      InitChessProgram(&first, startedFromSetupPosition);
  
      if(!appData.noChessProgram) {  /* [HGM] tidy: redo program version to use name from myname feature */
@@@ -2077,12 -1995,10 +2077,12 @@@ StripHighlight (char *s
      return retbuf;
  }
  
 +char engineVariant[MSG_SIZ];
  char *variantNames[] = VARIANT_NAMES;
  char *
  VariantName (VariantClass v)
  {
 +    if(v == VariantUnknown || *engineVariant) return engineVariant;
      return variantNames[v];
  }
  
@@@ -2112,8 -2028,7 +2112,8 @@@ StringToVariant (char *e
        found = TRUE;
      } else
      for (i=0; i<sizeof(variantNames)/sizeof(char*); i++) {
 -      if (StrCaseStr(e, variantNames[i])) {
 +      if (p = StrCaseStr(e, variantNames[i])) {
 +      if(p && i >= VariantShogi && isalpha(p[strlen(variantNames[i])])) continue;
        v = (VariantClass) i;
        found = TRUE;
        break;
@@@ -3099,10 -3014,8 +3099,10 @@@ read_from_ics (InputSourceRef isr, VOID
                        } else {
                            char tmp[MSG_SIZ];
                            if(gameMode == IcsObserving) // restore original ICS messages
 +                            /* TRANSLATORS: to 'kibitz' is to send a message to all players and the game observers */
                              snprintf(tmp, MSG_SIZ, "%s kibitzes: %s", star_match[0], parse);
                            else
 +                          /* TRANSLATORS: to 'kibitz' is to send a message to all players and the game observers */
                            snprintf(tmp, MSG_SIZ, _("your opponent kibitzes: %s"), parse);
                            SendToPlayer(tmp, strlen(tmp));
                        }
@@@ -4832,7 -4745,7 +4832,7 @@@ ParseBoard12 (char *string
              default:
                break;
              case MT_CHECK:
 -                if(gameInfo.variant != VariantShogi)
 +                if(!IS_SHOGI(gameInfo.variant))
                      strcat(parseList[moveNum - 1], "+");
                break;
              case MT_CHECKMATE:
@@@ -5062,11 -4975,6 +5062,11 @@@ SendMoveToProgram (int moveNum, ChessPr
      char buf[MSG_SIZ];
  
      if(moveList[moveNum][1] == '@' && moveList[moveNum][0] == '@') {
 +      if(gameInfo.variant == VariantLion || gameInfo.variant == VariantChuChess || gameInfo.variant == VariantChu) {
 +          sprintf(buf, "%s@@@@\n", cps->useUsermove ? "usermove " : "");
 +          SendToProgram(buf, cps);
 +          return;
 +      }
        // null move in variant where engine does not understand it (for analysis purposes)
        SendBoard(cps, moveNum + 1); // send position after move in stead.
        return;
        }
        else SendToProgram(moveList[moveNum], cps);
        } else
 +      if(moveList[moveNum][4] == ';') { // [HGM] lion: move is double-step over intermediate square
 +        snprintf(buf, MSG_SIZ, "%c%d%c%d,%c%d%c%d\n", moveList[moveNum][0], moveList[moveNum][1] - '0', // convert to two moves
 +                                             moveList[moveNum][5], moveList[moveNum][6] - '0',
 +                                             moveList[moveNum][5], moveList[moveNum][6] - '0',
 +                                             moveList[moveNum][2], moveList[moveNum][3] - '0');
 +        SendToProgram(buf, cps);
 +      } else
        if(BOARD_HEIGHT > 10) { // [HGM] big: convert ranks to double-digit where needed
        if(moveList[moveNum][1] == '@' && (BOARD_HEIGHT < 16 || moveList[moveNum][0] <= 'Z')) { // drop move
          if(moveList[moveNum][0]== '@') snprintf(buf, MSG_SIZ, "@@@@\n"); else
@@@ -5189,8 -5090,7 +5189,8 @@@ SendMoveToICS (ChessMove moveType, int 
          break;
        case WhitePromotion:
        case BlackPromotion:
 -        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
 +        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
 +           gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
          snprintf(user_move, MSG_SIZ, "%c%c%c%c=%c\n",
                  AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,
                PieceToChar(WhiteFerz));
@@@ -5254,7 -5154,7 +5254,7 @@@ UploadGameEvent (
        SendToICS(ics_prefix);
        SendToICS(buf);
        if(startedFromSetupPosition || backwardMostMove != 0) {
 -        fen = PositionToFEN(backwardMostMove, NULL);
 +        fen = PositionToFEN(backwardMostMove, NULL, 1);
          if(ics_type == ICS_ICC) { // on ICC we can simply send a complete FEN to set everything
            snprintf(buf, MSG_SIZ,"loadfen %s\n", fen);
            SendToICS(buf);
      SendToICS(ics_type == ICS_ICC ? "tag result Game in progress\n" : "commit\n");
  }
  
 +int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove
 +
  void
  CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7])
  {
        if (promoChar == 'x' || promoChar == NULLCHAR) {
          sprintf(move, "%c%c%c%c\n",
                      AAA + ff, ONE + rf, AAA + ft, ONE + rt);
 +        if(killX >= 0 && killY >= 0) sprintf(move+4, ";%c%c\n", AAA + killX, ONE + killY);
        } else {
            sprintf(move, "%c%c%c%c%c\n",
                      AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar);
@@@ -5330,43 -5227,27 +5330,43 @@@ ProcessICSInitScript (FILE *f
  }
  
  
 -static int lastX, lastY, selectFlag, dragging;
 +static int lastX, lastY, lastLeftX, lastLeftY, selectFlag;
 +int dragging;
 +static ClickType lastClickType;
 +
 +int
 +Partner (ChessSquare *p)
 +{ // change piece into promotion partner if one shogi-promotes to the other
 +  int stride = gameInfo.variant == VariantChu ? 22 : 11;
 +  ChessSquare partner;
 +  partner = (*p/stride & 1 ? *p - stride : *p + stride);
 +  if(PieceToChar(*p) != '+' && PieceToChar(partner) != '+') return 0;
 +  *p = partner;
 +  return 1;
 +}
  
  void
  Sweep (int step)
  {
      ChessSquare king = WhiteKing, pawn = WhitePawn, last = promoSweep;
 +    static int toggleFlag;
      if(gameInfo.variant == VariantKnightmate) king = WhiteUnicorn;
      if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway) king = EmptySquare;
      if(promoSweep >= BlackPawn) king = WHITE_TO_BLACK king, pawn = WHITE_TO_BLACK pawn;
      if(gameInfo.variant == VariantSpartan && pawn == BlackPawn) pawn = BlackLance, king = EmptySquare;
 -    if(fromY != BOARD_HEIGHT-2 && fromY != 1) pawn = EmptySquare;
 +    if(fromY != BOARD_HEIGHT-2 && fromY != 1 && gameInfo.variant != VariantChuChess) pawn = EmptySquare;
 +    if(!step) toggleFlag = Partner(&last); // piece has shogi-promotion
      do {
 -      promoSweep -= step;
 +      if(step && !(toggleFlag && Partner(&promoSweep))) promoSweep -= step;
        if(promoSweep == EmptySquare) promoSweep = BlackPawn; // wrap
        else if((int)promoSweep == -1) promoSweep = WhiteKing;
        else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn;
        else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing;
        if(!step) step = -1;
      } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn ||
 -          appData.testLegality && (promoSweep == king ||
 -          gameInfo.variant == VariantShogi && promoSweep != PROMOTED last && last != PROMOTED promoSweep && last != promoSweep));
 +          !toggleFlag && PieceToChar(promoSweep) == '+' || // skip promoted versions of other
 +          appData.testLegality && (promoSweep == king || gameInfo.variant != VariantChuChess &&
 +            (promoSweep == WhiteLion || promoSweep == BlackLion)));
      if(toX >= 0) {
        int victim = boards[currentMove][toY][toX];
        boards[currentMove][toY][toX] = promoSweep;
@@@ -5470,7 -5351,6 +5470,7 @@@ ParseOneMove (char *move, int moveNum, 
        case WhiteNonPromotion:
        case BlackNonPromotion:
        case NormalMove:
 +      case FirstLeg:
        case WhiteCapturesEnPassant:
        case BlackCapturesEnPassant:
        case WhiteKingSideCastle:
        if (appData.testLegality) {
          return (*moveType != IllegalMove);
        } else {
 -        return !(*fromX == *toX && *fromY == *toY) && boards[moveNum][*fromY][*fromX] != EmptySquare &&
 +        return !(*fromX == *toX && *fromY == *toY && killX < 0) && boards[moveNum][*fromY][*fromX] != EmptySquare &&
 +                       // [HGM] lion: if this is a double move we are less critical
                        WhiteOnMove(moveNum) == (boards[moveNum][*fromY][*fromX] < BlackPawn);
        }
  
@@@ -5963,7 -5842,7 +5963,7 @@@ voi
  InitPosition (int redraw)
  {
      ChessSquare (* pieces)[BOARD_FILES];
 -    int i, j, pawnRow, overrule,
 +    int i, j, pawnRow=1, pieceRows=1, overrule,
      oldx = gameInfo.boardWidth,
      oldy = gameInfo.boardHeight,
      oldh = gameInfo.holdingsWidth;
      case VariantMakruk:
        pieces = makrukArray;
        nrCastlingRights = 0;
 -      startedFromSetupPosition = TRUE;
        SetCharTable(pieceToChar, "PN.R.M....SKpn.r.m....sk");
        break;
 +    case VariantASEAN:
 +      pieces = aseanArray;
 +      nrCastlingRights = 0;
 +      SetCharTable(pieceToChar, "PN.R.Q....BKpn.r.q....bk");
 +      break;
      case VariantTwoKings:
        pieces = twoKingsArray;
        break;
        nrCastlingRights = 0;
        SetCharTable(pieceToChar, "PNBRLS...G.++++++Kpnbrls...g.++++++k");
        break;
 +    case VariantChu:
 +      pieces = ChuArray; pieceRows = 3;
 +      gameInfo.boardWidth  = 12;
 +      gameInfo.boardHeight = 12;
 +      nrCastlingRights = 0;
 +      SetCharTable(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN+.++.++++++++++.+++++K"
 +                                "p.brqsexogcathd.vmlifn+.++.++++++++++.+++++k");
 +      break;
      case VariantCourier:
        pieces = CourierArray;
        gameInfo.boardWidth  = 12;
        pieces = SpartanArray;
        SetCharTable(pieceToChar, "PNBRQ................K......lwg.....c...h..k");
        break;
 +    case VariantLion:
 +      pieces = lionArray;
 +      SetCharTable(pieceToChar, "PNBRQ................LKpnbrq................lk");
 +      break;
 +    case VariantChuChess:
 +      pieces = ChuChessArray;
 +      gameInfo.boardWidth = 10;
 +      gameInfo.boardHeight = 10;
 +      SetCharTable(pieceToChar, "PNBRQ.....M.+++......LKpnbrq.....m.+++......lk");
 +      break;
      case VariantFairy:
        pieces = fairyArray;
        SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk");
  
      pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
      if(pawnRow < 1) pawnRow = 1;
 -    if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand) pawnRow = 2;
 +    if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN ||
 +       gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) pawnRow = 2;
 +    if(gameInfo.variant == VariantChu) pawnRow = 3;
  
      /* User pieceToChar list overrules defaults */
      if(appData.pieceToCharTable != NULL)
              initialPosition[i][j] = s;
  
          if(j < BOARD_LEFT || j >= BOARD_RGHT || overrule) continue;
 -        initialPosition[gameInfo.variant == VariantGrand][j] = pieces[0][j-gameInfo.holdingsWidth];
 +        initialPosition[gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess][j] = pieces[0][j-gameInfo.holdingsWidth];
          initialPosition[pawnRow][j] = WhitePawn;
          initialPosition[BOARD_HEIGHT-pawnRow-1][j] = gameInfo.variant == VariantSpartan ? BlackLance : BlackPawn;
          if(gameInfo.variant == VariantXiangqi) {
                  }
              }
          }
 -        if(gameInfo.variant == VariantGrand) {
 +        if(gameInfo.variant == VariantChu) {
 +             if(j == (BOARD_WIDTH-2)/3 || j == BOARD_WIDTH - (BOARD_WIDTH+1)/3)
 +               initialPosition[pawnRow+1][j] = WhiteCobra,
 +               initialPosition[BOARD_HEIGHT-pawnRow-2][j] = BlackCobra;
 +             for(i=1; i<pieceRows; i++) {
 +               initialPosition[i][j] = pieces[2*i][j-gameInfo.holdingsWidth];
 +               initialPosition[BOARD_HEIGHT-1-i][j] =  pieces[2*i+1][j-gameInfo.holdingsWidth];
 +             }
 +        }
 +        if(gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) {
              if(j==BOARD_LEFT || j>=BOARD_RGHT-1) {
                 initialPosition[0][j] = WhiteRook;
                 initialPosition[BOARD_HEIGHT-1][j] = BlackRook;
              }
          }
 -        initialPosition[BOARD_HEIGHT-1-(gameInfo.variant == VariantGrand)][j] =  pieces[1][j-gameInfo.holdingsWidth];
 +        initialPosition[BOARD_HEIGHT-1-(gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess)][j] =  pieces[1][j-gameInfo.holdingsWidth];
      }
 +    if(gameInfo.variant == VariantChuChess) initialPosition[0][BOARD_WIDTH/2] = WhiteKing, initialPosition[BOARD_HEIGHT-1][BOARD_WIDTH/2-1] = BlackKing;
      if( (gameInfo.variant == VariantShogi) && !overrule ) {
  
              j=BOARD_LEFT+1;
@@@ -6294,7 -6139,7 +6294,7 @@@ SendBoard (ChessProgramState *cps, int 
      char message[MSG_SIZ];
  
      if (cps->useSetboard) {
 -      char* fen = PositionToFEN(moveNum, cps->fenOverride);
 +      char* fen = PositionToFEN(moveNum, cps->fenOverride, 1);
        snprintf(message, MSG_SIZ,"setboard %s\n", fen);
        SendToProgram(message, cps);
        free(fen);
@@@ -6477,8 -6322,7 +6477,8 @@@ ChessSquar
  DefaultPromoChoice (int white)
  {
      ChessSquare result;
 -    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
 +    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
 +       gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
        result = WhiteFerz; // no choice
      else if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway)
        result= WhiteKing; // in Suicide Q is the last thing we want
@@@ -6497,7 -6341,7 +6497,7 @@@ HasPromotionChoice (int fromX, int from
      /* [HGM] rewritten IsPromotion to only flag promotions that offer a choice */
      /* [HGM] add Shogi promotions */
      int promotionZoneSize=1, highestPromotingPiece = (int)WhitePawn;
 -    ChessSquare piece;
 +    ChessSquare piece, partner;
      ChessMove moveType;
      Boolean premove;
  
        return FALSE;
  
      piece = boards[currentMove][fromY][fromX];
 -    if(gameInfo.variant == VariantShogi) {
 +    if(gameInfo.variant == VariantChu) {
 +        int p = piece >= BlackPawn ? BLACK_TO_WHITE piece : piece;
 +        promotionZoneSize = BOARD_HEIGHT/3;
 +        highestPromotingPiece = (p >= WhiteLion || PieceToChar(piece + 22) == '.') ? WhitePawn : WhiteLion;
 +    } else if(gameInfo.variant == VariantShogi || gameInfo.variant == VariantChuChess) {
          promotionZoneSize = BOARD_HEIGHT/3;
 -        highestPromotingPiece = (int)WhiteFerz;
 -    } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand) {
 +        highestPromotingPiece = (int)WhiteAlfil;
 +    } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) {
          promotionZoneSize = 3;
      }
  
      if((int)piece >= BlackPawn) {
          if(toY >= promotionZoneSize && fromY >= promotionZoneSize)
               return FALSE;
 +        if(fromY < promotionZoneSize && gameInfo.variant == VariantChuChess) return FALSE;
          highestPromotingPiece = WHITE_TO_BLACK highestPromotingPiece;
      } else {
          if(  toY < BOARD_HEIGHT - promotionZoneSize &&
             fromY < BOARD_HEIGHT - promotionZoneSize) return FALSE;
 +        if(fromY >= BOARD_HEIGHT - promotionZoneSize && gameInfo.variant == VariantChuChess)
 +             return FALSE;
      }
  
      if( (int)piece > highestPromotingPiece ) return FALSE; // non-promoting piece
      }
  
      // we either have a choice what to promote to, or (in Shogi) whether to promote
 -    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) {
 -      *promoChoice = PieceToChar(BlackFerz);  // no choice
 +    if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
 +       gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) {
 +      ChessSquare p=BlackFerz;  // no choice
 +      while(p < EmptySquare) {  //but make sure we use piece that exists
 +          *promoChoice = PieceToChar(p++);
 +          if(*promoChoice != '.') break;
 +      }
        return FALSE;
      }
      // no sense asking what we must promote to if it is going to explode...
      }
      // give caller the default choice even if we will not make it
      *promoChoice = ToLower(PieceToChar(defaultPromoChoice));
 -    if(gameInfo.variant == VariantShogi) *promoChoice = (defaultPromoChoice == piece ? '=' : '+');
 +    partner = piece; // pieces can promote if the pieceToCharTable says so
 +    if(IS_SHOGI(gameInfo.variant)) *promoChoice = (defaultPromoChoice == piece && sweepSelect ? '=' : '+'); // obsolete?
 +    else if(Partner(&partner))     *promoChoice = (defaultPromoChoice == piece && sweepSelect ? NULLCHAR : '+');
      if(        sweepSelect && gameInfo.variant != VariantGreat
                           && gameInfo.variant != VariantGrand
                           && gameInfo.variant != VariantSuper) return FALSE;
              gameMode == IcsPlayingBlack &&  WhiteOnMove(currentMove);
      if(appData.testLegality && !premove) {
        moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
 -                      fromY, fromX, toY, toX, gameInfo.variant == VariantShogi ? '+' : NULLCHAR);
 +                      fromY, fromX, toY, toX, IS_SHOGI(gameInfo.variant) || gameInfo.variant == VariantChuChess ? '+' : NULLCHAR);
 +        if(moveType == IllegalMove) *promoChoice = NULLCHAR; // could be the fact we promoted was illegal
        if(moveType != WhitePromotion && moveType  != BlackPromotion)
            return FALSE;
      }
@@@ -7169,66 -6998,27 +7169,66 @@@ FinishMove (ChessMove moveType, int fro
  }
  
  void
 +MarkByFEN(char *fen)
 +{
 +      int r, f;
 +      if(!appData.markers || !appData.highlightDragging) return;
 +      for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) legal[r][f] = 0;
 +      r=BOARD_HEIGHT-1; f=BOARD_LEFT;
 +      while(*fen) {
 +          int s = 0;
 +          marker[r][f] = 0;
 +          if(*fen == 'M') legal[r][f] = 2; else // request promotion choice
 +          if(*fen >= 'A' && *fen <= 'Z') legal[r][f] = 1; else
 +          if(*fen >= 'a' && *fen <= 'z') *fen += 'A' - 'a';
 +          if(*fen == '/' && f > BOARD_LEFT) f = BOARD_LEFT, r--; else
 +          if(*fen == 'T') marker[r][f++] = 0; else
 +          if(*fen == 'Y') marker[r][f++] = 1; else
 +          if(*fen == 'G') marker[r][f++] = 3; else
 +          if(*fen == 'B') marker[r][f++] = 4; else
 +          if(*fen == 'C') marker[r][f++] = 5; else
 +          if(*fen == 'M') marker[r][f++] = 6; else
 +          if(*fen == 'W') marker[r][f++] = 7; else
 +          if(*fen == 'D') marker[r][f++] = 8; else
 +          if(*fen == 'R') marker[r][f++] = 2; else {
 +              while(*fen <= '9' && *fen >= '0') s = 10*s + *fen++ - '0';
 +            f += s; fen -= s>0;
 +          }
 +          while(f >= BOARD_RGHT) f -= BOARD_RGHT - BOARD_LEFT, r--;
 +          if(r < 0) break;
 +          fen++;
 +      }
 +      DrawPosition(TRUE, NULL);
 +}
 +
 +static char baseMarker[BOARD_RANKS][BOARD_FILES], baseLegal[BOARD_RANKS][BOARD_FILES];
 +
 +void
  Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)
  {
      typedef char Markers[BOARD_RANKS][BOARD_FILES];
      Markers *m = (Markers *) closure;
 -    if(rf == fromY && ff == fromX)
 +    if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2))
        (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare
                         || kind == WhiteCapturesEnPassant
 -                       || kind == BlackCapturesEnPassant);
 +                       || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0);
      else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3;
  }
  
 +static int hoverSavedValid;
 +
  void
  MarkTargetSquares (int clear)
  {
 -  int x, y;
 -  if(clear) // no reason to ever suppress clearing
 -    for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) marker[y][x] = 0;
 -  if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
 -     !appData.testLegality || gameMode == EditPosition) return;
 -  if(!clear) {
 +  int x, y, sum=0;
 +  if(clear) { // no reason to ever suppress clearing
 +    for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) sum += marker[y][x], marker[y][x] = 0;
 +    hoverSavedValid = 0;
 +    if(!sum) return; // nothing was cleared,no redraw needed
 +  } else {
      int capt = 0;
 +    if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
 +       !appData.testLegality || gameMode == EditPosition) return;
      GenLegal(boards[currentMove], PosFlags(currentMove), Mark, (void*) marker, EmptySquare);
      if(PosFlags(0) & F_MANDATORY_CAPTURE) {
        for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x]>1) capt++;
@@@ -7258,59 -7048,19 +7258,59 @@@ ChessSquare gatingPiece = EmptySquare; 
  int
  CanPromote (ChessSquare piece, int y)
  {
 +        int zone = (gameInfo.variant == VariantChuChess ? 3 : 1);
        if(gameMode == EditPosition) return FALSE; // no promotions when editing position
        // some variants have fixed promotion piece, no promotion at all, or another selection mechanism
 -      if(gameInfo.variant == VariantShogi    || gameInfo.variant == VariantXiangqi ||
 +      if(IS_SHOGI(gameInfo.variant)          || gameInfo.variant == VariantXiangqi ||
           gameInfo.variant == VariantSuper    || gameInfo.variant == VariantGreat   ||
           gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
 -                                                gameInfo.variant == VariantMakruk) return FALSE;
 -      return (piece == BlackPawn && y == 1 ||
 -              piece == WhitePawn && y == BOARD_HEIGHT-2 ||
 +         gameInfo.variant == VariantMakruk   || gameInfo.variant == VariantASEAN) return FALSE;
 +      return (piece == BlackPawn && y <= zone ||
 +              piece == WhitePawn && y >= BOARD_HEIGHT-1-zone ||
                piece == BlackLance && y == 1 ||
                piece == WhiteLance && y == BOARD_HEIGHT-2 );
  }
  
  void
 +HoverEvent (int xPix, int yPix, int x, int y)
 +{
 +      static int oldX = -1, oldY = -1, oldFromX = -1, oldFromY = -1;
 +      int r, f;
 +      if(!first.highlight) return;
 +      if(fromX != oldFromX || fromY != oldFromY)  oldX = oldY = -1; // kludge to fake entry on from-click
 +      if(x == oldX && y == oldY) return; // only do something if we enter new square
 +      oldFromX = fromX; oldFromY = fromY;
 +      if(oldX == -1 && oldY == -1 && x == fromX && y == fromY) { // record markings after from-change
 +        for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
 +          baseMarker[r][f] = marker[r][f], baseLegal[r][f] = legal[r][f];
 +        hoverSavedValid = 1;
 +      } else if(oldX != x || oldY != y) {
 +        // [HGM] lift: entered new to-square; redraw arrow, and inform engine
 +        if(hoverSavedValid) // don't restore markers that are supposed to be cleared
 +        for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
 +          marker[r][f] = baseMarker[r][f], legal[r][f] = baseLegal[r][f];
 +        if((marker[y][x] == 2 || marker[y][x] == 6) && legal[y][x]) {
 +          char buf[MSG_SIZ];
 +          snprintf(buf, MSG_SIZ, "hover %c%d\n", x + AAA, y + ONE - '0');
 +          SendToProgram(buf, &first);
 +        }
 +        oldX = x; oldY = y;
 +//      SetHighlights(fromX, fromY, x, y);
 +      }
 +}
 +
 +void ReportClick(char *action, int x, int y)
 +{
 +      char buf[MSG_SIZ]; // Inform engine of what user does
 +      int r, f;
 +      if(action[0] == 'l') // mark any target square of a lifted piece as legal to-square, clear markers
 +        for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) legal[r][f] = 1, marker[r][f] = 0;
 +      if(!first.highlight || gameMode == EditPosition) return;
 +      snprintf(buf, MSG_SIZ, "%s %c%d%s\n", action, x+AAA, y+ONE-'0', controlKey && action[0]=='p' ? "," : "");
 +      SendToProgram(buf, &first);
 +}
 +
 +void
  LeftClick (ClickType clickType, int xPix, int yPix)
  {
      int x, y;
      prevClickTime = lastClickTime; GetTimeMark(&lastClickTime);
  
      if (clickType == Press) ErrorPopDown();
 +    lastClickType = clickType, lastLeftX = xPix, lastLeftY = yPix; // [HGM] alien: remember state
  
      x = EventToSquare(xPix, BOARD_WIDTH);
      y = EventToSquare(yPix, BOARD_HEIGHT);
        if(gameMode == AnalyzeMode && (pausing || controlKey) && first.excludeMoves) { // use pause state to exclude moves
        doubleClick = TRUE; gatingPiece = boards[currentMove][y][x];
        }
 -      fromX = x; fromY = y; toX = toY = -1;
 +      fromX = x; fromY = y; toX = toY = killX = killY = -1;
        if(!appData.oneClick || !OnlyMove(&x, &y, FALSE) ||
         // even if only move, we treat as normal when this would trigger a promotion popup, to allow sweep selection
         appData.sweepSelect && CanPromote(boards[currentMove][fromY][fromX], fromY) && originalY != y) {
            /* First square */
            if (OKToStartUserMove(fromX, fromY)) {
                second = 0;
 +              ReportClick("lift", x, y);
                MarkTargetSquares(0);
                if(gameMode == EditPosition && controlKey) gatingPiece = boards[currentMove][fromY][fromX];
                DragPieceBegin(xPix, yPix, FALSE); dragging = 1;
        fromP = boards[currentMove][fromY][fromX];
        toP = boards[currentMove][y][x];
        frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess;
 -      if ((WhitePawn <= fromP && fromP <= WhiteKing &&
 +      if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect!
 +         ((WhitePawn <= fromP && fromP <= WhiteKing &&
             WhitePawn <= toP && toP <= WhiteKing &&
             !(fromP == WhiteKing && toP == WhiteRook && frc) &&
             !(fromP == WhiteRook && toP == WhiteKing && frc)) ||
            (BlackPawn <= fromP && fromP <= BlackKing &&
             BlackPawn <= toP && toP <= BlackKing &&
             !(fromP == BlackRook && toP == BlackKing && frc) && // allow also RxK as FRC castling
 -           !(fromP == BlackKing && toP == BlackRook && frc))) {
 +           !(fromP == BlackKing && toP == BlackRook && frc)))) {
            /* Clicked again on same color piece -- changed his mind */
            second = (x == fromX && y == fromY);
 +          killX = killY = -1;
            if(second && gameMode == AnalyzeMode && SubtractTimeMarks(&lastClickTime, &prevClickTime) < 200) {
                second = FALSE; // first double-click rather than scond click
                doubleClick = first.excludeMoves; // used by UserMoveEvent to recognize exclude moves
                else gatingPiece = doubleClick ? fromP : EmptySquare;
                fromX = x;
                fromY = y; dragging = 1;
 +              ReportClick("lift", x, y);
                MarkTargetSquares(0);
                DragPieceBegin(xPix, yPix, FALSE);
                if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
        if(x < BOARD_LEFT || x >= BOARD_RGHT) return;
      }
  
 -    if (clickType == Release && x == fromX && y == fromY) {
 +    if (clickType == Release && x == fromX && y == fromY && killX < 0) {
        DragPieceEnd(xPix, yPix); dragging = 0;
        if(clearFlag) {
            // a deferred attempt to click-click move an empty square on top of a piece
  
      clearFlag = 0;
  
 +    if(gameMode != EditPosition && !appData.testLegality && !legal[y][x] && (x != killX || y != killY) && !sweepSelecting) {
 +      if(dragging) DragPieceEnd(xPix, yPix), dragging = 0;
 +      DisplayMessage(_("only marked squares are legal"),"");
 +      DrawPosition(TRUE, NULL);
 +      return; // ignore to-click
 +    }
 +
      /* we now have a different from- and (possibly off-board) to-square */
      /* Completed move */
      if(!sweepSelecting) {
        toX = x;
        toY = y;
 -    } else sweepSelecting = 0; // this must be the up-click corresponding to the down-click that started the sweep
 +    }
 +
 +    piece = boards[currentMove][fromY][fromX];
  
      saveAnimate = appData.animate;
      if (clickType == Press) {
 +      if(gameInfo.variant == VariantChuChess && piece != WhitePawn && piece != BlackPawn) defaultPromoChoice = piece;
        if(gameMode == EditPosition && boards[currentMove][fromY][fromX] == EmptySquare) {
            // must be Edit Position mode with empty-square selected
            fromX = x; fromY = y; DragPieceBegin(xPix, yPix, FALSE); dragging = 1; // consider this a new attempt to drag
            if(x >= BOARD_LEFT && x < BOARD_RGHT) clearFlag = 1; // and defer click-click move of empty-square to up-click
            return;
        }
 -      if(HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
 +      if(dragging == 2) {  // [HGM] lion: just turn buttonless drag into normal drag, and let release to the job
 +          return;
 +      }
 +      if(x == killX && y == killY) {              // second click on this square, which was selected as first-leg target
 +          killX = killY = -1;                     // this informs us no second leg is coming, so treat as to-click without intermediate
 +      } else
 +      if(marker[y][x] == 5) return; // [HGM] lion: to-click on cyan square; defer action to release
 +      if(legal[y][x] == 2 || HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
          if(appData.sweepSelect) {
 -          ChessSquare piece = boards[currentMove][fromY][fromX];
            promoSweep = defaultPromoChoice;
 -          if(PieceToChar(PROMOTED piece) == '+') promoSweep = PROMOTED piece;
 +          if(gameInfo.variant != VariantChuChess && PieceToChar(CHUPROMOTED piece) == '+') promoSweep = CHUPROMOTED piece;
            selectFlag = 0; lastX = xPix; lastY = yPix;
            Sweep(0); // Pawn that is going to promote: preview promotion piece
            sweepSelecting = 1;
        } else {
            ClearHighlights();
        }
 +    } else if(sweepSelecting) { // this must be the up-click corresponding to the down-click that started the sweep
 +      sweepSelecting = 0; appData.animate = FALSE; // do not animate, a selected piece already on to-square
 +      if (appData.animate || appData.highlightLastMove) {
 +          SetHighlights(fromX, fromY, toX, toY);
 +      } else {
 +          ClearHighlights();
 +      }
      } else {
  #if 0
  // [HGM] this must be done after the move is made, as with arrow it could lead to a board redraw with piece still on from square
            ClearHighlights();
        }
  #endif
 +      if(gameInfo.variant == VariantChuChess && piece != WhitePawn && piece != BlackPawn) defaultPromoChoice = piece;
 +      if(marker[y][x] == 5) { // [HGM] lion: this was the release of a to-click or drag on a cyan square
 +        dragging *= 2;            // flag button-less dragging if we are dragging
 +        MarkTargetSquares(1);
 +        if(x == killX && y == killY) killX = killY = -1; else {
 +          killX = x; killY = y;     //remeber this square as intermediate
 +          ReportClick("put", x, y); // and inform engine
 +          ReportClick("lift", x, y);
 +          MarkTargetSquares(0);
 +          return;
 +        }
 +      }
        DragPieceEnd(xPix, yPix); dragging = 0;
        /* Don't animate move and drag both */
        appData.animate = FALSE;
  
      // off-board moves should not be highlighted
      if(x < 0 || y < 0) ClearHighlights();
 +    else ReportClick("put", x, y);
  
      if(gatingPiece != EmptySquare && gameInfo.variant == VariantSChess) promoChoice = ToLower(PieceToChar(gatingPiece));
  
            DisplayMessage("Click in holdings to choose piece", "");
            return;
        }
 -      PromotionPopUp();
 +      PromotionPopUp(promoChoice);
      } else {
        int oldMove = currentMove;
        UserMoveEvent(fromX, fromY, toX, toY, promoChoice);
@@@ -8053,6 -7762,7 +8053,7 @@@ Adjudicate (ChessProgramState *cps
              case MT_NONE:
              default:
                break;
+             case MT_STEALMATE:
              case MT_STALEMATE:
              case MT_STAINMATE:
                reason = "Xboard adjudication: Stalemate";
        return 0;
  }
  
 +typedef int (CDECL *PPROBE_EGBB) (int player, int *piece, int *square);
 +typedef int (CDECL *PLOAD_EGBB) (char *path, int cache_size, int load_options);
 +static int egbbCode[] = { 6, 5, 4, 3, 2, 1 };
 +
 +static int
 +BitbaseProbe ()
 +{
 +    int pieces[10], squares[10], cnt=0, r, f, res;
 +    static int loaded;
 +    static PPROBE_EGBB probeBB;
 +    if(!appData.testLegality) return 10;
 +    if(BOARD_HEIGHT != 8 || BOARD_RGHT-BOARD_LEFT != 8) return 12;
 +    if(gameInfo.holdingsSize && gameInfo.variant != VariantSuper && gameInfo.variant != VariantSChess) return 12;
 +    if(loaded == 2 && forwardMostMove < 2) loaded = 0; // retry on new game
 +    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
 +      ChessSquare piece = boards[forwardMostMove][r][f];
 +      int black = (piece >= BlackPawn);
 +      int type = piece - black*BlackPawn;
 +      if(piece == EmptySquare) continue;
 +      if(type != WhiteKing && type > WhiteQueen) return 12; // unorthodox piece
 +      if(type == WhiteKing) type = WhiteQueen + 1;
 +      type = egbbCode[type];
 +      squares[cnt] = r*(BOARD_RGHT - BOARD_LEFT) + f - BOARD_LEFT;
 +        pieces[cnt] = type + black*6;
 +      if(++cnt > 5) return 11;
 +    }
 +    pieces[cnt] = squares[cnt] = 0;
 +    // probe EGBB
 +    if(loaded == 2) return 13; // loading failed before
 +    if(loaded == 0) {
 +      loaded = 2; // prepare for failure
 +      char *p, *path = strstr(appData.egtFormats, "scorpio:"), buf[MSG_SIZ];
 +      HMODULE lib;
 +      PLOAD_EGBB loadBB;
 +      if(!path) return 13; // no egbb installed
 +      strncpy(buf, path + 8, MSG_SIZ);
 +      if(p = strchr(buf, ',')) *p = NULLCHAR; else p = buf + strlen(buf);
 +      snprintf(p, MSG_SIZ - strlen(buf), "%c%s", SLASH, EGBB_NAME);
 +      lib = LoadLibrary(buf);
 +      if(!lib) { DisplayError(_("could not load EGBB library"), 0); return 13; }
 +      loadBB = (PLOAD_EGBB) GetProcAddress(lib, "load_egbb_xmen");
 +      probeBB = (PPROBE_EGBB) GetProcAddress(lib, "probe_egbb_xmen");
 +      if(!loadBB || !probeBB) { DisplayError(_("wrong EGBB version"), 0); return 13; }
 +      p[1] = NULLCHAR; loadBB(buf, 64*1028, 2); // 2 = SMART_LOAD
 +      loaded = 1; // success!
 +    }
 +    res = probeBB(forwardMostMove & 1, pieces, squares);
 +    return res > 0 ? 1 : res < 0 ? -1 : 0;
 +}
 +
  char *
  SendMoveToBookUser (int moveNr, ChessProgramState *cps, int initial)
  {   // [HGM] book: this routine intercepts moves to simulate book replies
      char *bookHit = NULL;
  
 +    if(cps->drawDepth && BitbaseProbe() == 0) { // [HG} egbb: reduce depth in drawn position
 +      char buf[MSG_SIZ];
 +      snprintf(buf, MSG_SIZ, "sd %d\n", cps->drawDepth);
 +      SendToProgram(buf, cps);
 +    }
      //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
@@@ -8433,12 -8088,11 +8434,12 @@@ static char stashedInputMove[MSG_SIZ]
  void
  HandleMachineMove (char *message, ChessProgramState *cps)
  {
 +    static char firstLeg[20];
      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 promoChar, roar;
      char *p, *pv=buf1;
      int machineWhite, oldError;
      char *bookHit;
@@@ -8576,32 -8230,14 +8577,32 @@@ FakeBookMove: // [HGM] book: we jump he
        }
  
          if(cps->alphaRank) AlphaRank(machineMove, 4);
 +
 +      // [HGM] lion: (some very limited) support for Alien protocol
 +      killX = killY = -1;
 +      if(machineMove[strlen(machineMove)-1] == ',') { // move ends in coma: non-final leg of composite move
 +          safeStrCpy(firstLeg, machineMove, 20); // just remember it for processing when second leg arrives
 +          return;
 +      } else if(firstLeg[0]) { // there was a previous leg;
 +          // only support case where same piece makes two step (and don't even test that!)
 +          char buf[20], *p = machineMove+1, *q = buf+1, f;
 +          safeStrCpy(buf, machineMove, 20);
 +          while(isdigit(*q)) q++; // find start of to-square
 +          safeStrCpy(machineMove, firstLeg, 20);
 +          while(isdigit(*p)) p++;
 +          safeStrCpy(p, q, 20); // glue to-square of second leg to from-square of first, to process over-all move
 +          sscanf(buf, "%c%d", &f, &killY); killX = f - AAA; killY -= ONE - '0'; // pass intermediate square to MakeMove in global
 +          firstLeg[0] = NULLCHAR;
 +      }
 +
          if (!ParseOneMove(machineMove, forwardMostMove, &moveType,
                                &fromX, &fromY, &toX, &toY, &promoChar)) {
            /* Machine move could not be parsed; ignore it. */
          snprintf(buf1, MSG_SIZ*10, _("Illegal move \"%s\" from %s machine"),
                    machineMove, _(cps->which));
            DisplayMoveError(buf1);
 -            snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d",
 -                    machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, moveType);
 +            snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c via %c%c) res=%d",
 +                    machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, killX+AAA, killY+ONE, moveType);
            if (gameMode == TwoMachinesPlay) {
              GameEnds(machineWhite ? BlackWins : WhiteWins,
                         buf1, GE_XBOARD);
  
        MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
  
 +        /* Test suites abort the 'game' after one move */
 +        if(*appData.finger) {
 +           static FILE *f;
 +           char *fen = PositionToFEN(backwardMostMove, NULL, 0); // no counts in EPD
 +           if(!f) f = fopen(appData.finger, "w");
 +           if(f) fprintf(f, "%s bm %s;\n", fen, parseList[backwardMostMove]), fflush(f);
 +           else { DisplayFatalError("Bad output file", errno, 0); return; }
 +           free(fen);
 +           GameEnds(GameUnfinished, NULL, GE_XBOARD);
 +        }
 +
          /* [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;
@@@ -8754,12 -8379,10 +8755,12 @@@ if(appData.debugMode) fprintf(debugFP, 
            cps->other->maybeThinking = TRUE;
        }
  
 +      roar = (killX >= 0 && IS_LION(boards[forwardMostMove][toY][toX]));
 +
        ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/
  
          if (!pausing && appData.ringBellAfterMoves) {
 -          RingBell();
 +          if(!roar) RingBell();
        }
  
        /*
      }
  
      if (!strncmp(message, "setup ", 6) && 
 -      (!appData.testLegality || gameInfo.variant == VariantFairy || NonStandardBoardSize())
 +      (!appData.testLegality || gameInfo.variant == VariantFairy || gameInfo.variant == VariantUnknown ||
 +          NonStandardBoardSize(gameInfo.variant, gameInfo.boardWidth, gameInfo.boardHeight, gameInfo.holdingsSize))
                                        ) { // [HGM] allow first engine to define opening position
 -      int dummy, s=6; char buf[MSG_SIZ];
 +      int dummy, w, h, hand, s=6; char buf[MSG_SIZ], varName[MSG_SIZ];
        if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
 +      *buf = NULLCHAR;
        if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
        if(startedFromSetupPosition) return;
 -      if(sscanf(message+s, "%dx%d+%d", &dummy, &dummy, &dummy) == 3) while(message[s] && message[s++] != ' '); // for compatibility with Alien Edition
 -      ParseFEN(boards[0], &dummy, message+s);
 +      dummy = sscanf(message+s, "%dx%d+%d_%s", &w, &h, &hand, varName);
 +      if(dummy >= 3) {
 +        while(message[s] && message[s++] != ' ');
 +        if(BOARD_HEIGHT != h || BOARD_WIDTH != w + 4*(hand != 0) || gameInfo.holdingsSize != hand ||
 +           dummy == 4 && gameInfo.variant != StringToVariant(varName) ) { // engine wants to change board format or variant
 +          appData.NrFiles = w; appData.NrRanks = h; appData.holdingsSize = hand;
 +          if(dummy == 4) gameInfo.variant = StringToVariant(varName);     // parent variant
 +          InitPosition(1); // calls InitDrawingSizes to let new parameters take effect
 +          if(*buf) SetCharTable(pieceToChar, buf); // do again, for it was spoiled by InitPosition
 +        }
 +      }
 +      ParseFEN(boards[0], &dummy, message+s, FALSE);
        DrawPosition(TRUE, boards[0]);
        startedFromSetupPosition = TRUE;
        return;
  
          GameEnds(GameUnfinished, "Engine aborts game", GE_XBOARD);
  
 -        if (!ParseFEN(initial_position, &blackPlaysFirst, message + 9)) {
 +        if (!ParseFEN(initial_position, &blackPlaysFirst, message + 9, FALSE)) {
              DisplayError(_("Bad FEN received from engine"), 0);
              return ;
          } else {
        }
      }
      if (sscanf(message, "pong %d", &cps->lastPong) == 1) {
 +      if(initPing == cps->lastPong) {
 +          if(gameInfo.variant == VariantUnknown) {
 +              DisplayError(_("Engine did not send setup for non-standard variant"), 0);
 +              *engineVariant = NULLCHAR; appData.variant = VariantNormal; // back to normal as error recovery?
 +              GameEnds(GameUnfinished, NULL, GE_XBOARD);
 +          }
 +          initPing = -1;
 +        }
 +      return;
 +    }
 +    if(!strncmp(message, "highlight ", 10)) {
 +      if(appData.testLegality && appData.markers) return;
 +      MarkByFEN(message+10); // [HGM] alien: allow engine to mark board squares
 +      return;
 +    }
 +    if(!strncmp(message, "click ", 6)) {
 +      char f, c=0; int x, y; // [HGM] alien: allow engine to finish user moves (i.e. engine-driven one-click moving)
 +      if(appData.testLegality || !appData.oneClick) return;
 +      sscanf(message+6, "%c%d%c", &f, &y, &c);
 +      x = f - 'a' + BOARD_LEFT, y -= ONE - '0';
 +      if(flipView) x = BOARD_WIDTH-1 - x; else y = BOARD_HEIGHT-1 - y;
 +      x = x*squareSize + (x+1)*lineGap + squareSize/2;
 +      y = y*squareSize + (y+1)*lineGap + squareSize/2;
 +      f = first.highlight; first.highlight = 0; // kludge to suppress lift/put in response to own clicks
 +      if(lastClickType == Press) // if button still down, fake release on same square, to be ready for next click
 +          LeftClick(Release, lastLeftX, lastLeftY);
 +      controlKey  = (c == ',');
 +      LeftClick(Press, x, y);
 +      LeftClick(Release, x, y);
 +      first.highlight = f;
        return;
      }
      /*
            DisplayInformation(_("Machine accepts your draw offer"));
            GameEnds(GameIsDrawn, "Draw agreed", GE_XBOARD);
          } else {
 -            DisplayInformation(_("Machine offers a draw\nSelect Action / Draw to agree"));
 +            DisplayInformation(_("Machine offers a draw.\nSelect Action / Draw to accept."));
          }
        }
      }
                        if(f = fopen(buf, "w")) { // export PV to applicable PV file
                                fprintf(f, "%5.2f/%-2d %s", curscore/100., plylev, pv);
                                fclose(f);
 -                      } else DisplayError(_("failed writing PV"), 0);
 +                      }
 +                      else
 +                        /* TRANSLATORS: PV = principal variation, the variation the chess engine thinks is the best for everyone */
 +                        DisplayError(_("failed writing PV"), 0);
                }
  
                tempStats.depth = plylev;
@@@ -9659,7 -9237,6 +9660,7 @@@ ParseGameHistory (char *game
          case WhiteNonPromotion:
          case BlackNonPromotion:
          case NormalMove:
 +        case FirstLeg:
          case WhiteCapturesEnPassant:
          case BlackCapturesEnPassant:
          case WhiteKingSideCastle:
          default:
            break;
          case MT_CHECK:
 -            if(gameInfo.variant != VariantShogi)
 +            if(!IS_SHOGI(gameInfo.variant))
                  strcat(parseList[boardIndex - 1], "+");
            break;
          case MT_CHECKMATE:
@@@ -9800,7 -9377,7 +9801,7 @@@ voi
  ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
  {
    ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;
 -  int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
 +  int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1;
  
      /* [HGM] compute & store e.p. status and castling rights for new position */
      /* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */
        }
          piece = board[toY][toX] = (ChessSquare) fromX;
    } else {
 +      ChessSquare victim;
        int i;
  
 -      if( board[toY][toX] != EmptySquare )
 +      if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something
 +           victim = board[killY][killX],
 +           board[killY][killX] = EmptySquare,
             board[EP_STATUS] = EP_CAPTURE;
  
 +      if( board[toY][toX] != EmptySquare ) {
 +           board[EP_STATUS] = EP_CAPTURE;
 +           if( (fromX != toX || fromY != toY) && // not igui!
 +               (captured == WhiteLion && board[fromY][fromX] != BlackLion ||
 +                captured == BlackLion && board[fromY][fromX] != WhiteLion   ) ) { // [HGM] lion: Chu Lion-capture rules
 +               board[EP_STATUS] = EP_IRON_LION; // non-Lion x Lion: no counter-strike allowed
 +           }
 +      }
 +
        if( board[fromY][fromX] == WhiteLance || board[fromY][fromX] == BlackLance ) {
             if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi )
                 board[EP_STATUS] = EP_PAWN_MOVE; // Lance is Pawn-like in most variants
          board[toY][toX+1] = board[fromY][BOARD_LEFT];
          board[fromY][BOARD_LEFT] = EmptySquare;
      } else if ((board[fromY][fromX] == WhitePawn && gameInfo.variant != VariantXiangqi ||
 -                board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi)
 +                board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu)
                 && toY >= BOARD_HEIGHT-promoRank && promoChar // defaulting to Q is done elsewhere
                 ) {
        /* white pawn promotion */
        board[fromY][0] = EmptySquare;
        board[toY][2] = BlackRook;
      } else if ((board[fromY][fromX] == BlackPawn && gameInfo.variant != VariantXiangqi ||
 -                board[fromY][fromX] == BlackLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi)
 +                board[fromY][fromX] == BlackLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu)
               && toY < promoRank && promoChar
                 ) {
        /* black pawn promotion */
                board[fromY][fromX+1] = EmptySquare;
        }
      } else {
 -      board[toY][toX] = board[fromY][fromX];
 +      ChessSquare piece = board[fromY][fromX]; // [HGM] lion: allow for igui (where from == to)
        board[fromY][fromX] = EmptySquare;
 +      board[toY][toX] = piece;
      }
    }
  
        board[toY][toX] = EmptySquare;
        }
      }
 +
      if(gameInfo.variant == VariantSChess && promoChar != NULLCHAR && promoChar != '=' && piece != WhitePawn && piece != BlackPawn) {
          board[fromY][fromX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar)); // S-Chess gating
      } else
      if(promoChar == '+') {
          /* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite ordinary Pawn promotion) */
 -        board[toY][toX] = (ChessSquare) (PROMOTED piece);
 +        board[toY][toX] = (ChessSquare) (CHUPROMOTED piece);
 +        if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight))
 +          board[toY][toX] = piece + WhiteLion - WhiteKnight; // adjust Knight promotions to Lion
      } else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar
          ChessSquare newPiece = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar));
        if((newPiece <= WhiteMan || newPiece >= BlackPawn && newPiece <= BlackMan) // unpromoted piece specified
                board[BOARD_HEIGHT-1-k][0] = EmptySquare;
        }
      }
 -
  }
  
  /* Updates forwardMostMove */
  void
  MakeMove (int fromX, int fromY, int toX, int toY, int promoChar)
  {
 +    int x = toX, y = toY;
 +    char *s = parseList[forwardMostMove];
 +    ChessSquare p = boards[forwardMostMove][toY][toX];
  //    forwardMostMove++; // [HGM] bare: moved downstream
  
 +    if(killX >= 0 && killY >= 0) x = killX, y = killY; // [HGM] lion: make SAN move to intermediate square, if there is one
      (void) CoordsToAlgebraic(boards[forwardMostMove],
                             PosFlags(forwardMostMove),
 -                           fromY, fromX, toY, toX, promoChar,
 -                           parseList[forwardMostMove]);
 +                           fromY, fromX, y, x, promoChar,
 +                           s);
 +    if(killX >= 0 && killY >= 0)
 +        sprintf(s + strlen(s), "%c%c%d", p == EmptySquare || toX == fromX && toY == fromY ? '-' : 'x', toX + AAA, toY + ONE - '0');
  
      if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting (should be separate routine, really) */
          int timeLeft; static int lastLoadFlag=0; int king, piece;
        default:
        break;
        case MT_CHECK:
 -        if(gameInfo.variant != VariantShogi)
 +        if(!IS_SHOGI(gameInfo.variant))
              strcat(parseList[forwardMostMove - 1], "+");
        break;
        case MT_CHECKMATE:
        strcat(parseList[forwardMostMove - 1], "#");
        break;
      }
 -
  }
  
  /* Updates currentMove if not pausing */
@@@ -10252,8 -9809,6 +10253,8 @@@ ShowMove (int fromX, int fromY, int toX
        currentMove = forwardMostMove;
      }
  
 +    killX = killY = -1; // [HGM] lion: used up
 +
      if (instant) return;
  
      DisplayMove(currentMove - 1);
@@@ -10302,75 -9857,37 +10303,75 @@@ SendEgtPath (ChessProgramState *cps
  }
  
  static int
 -NonStandardBoardSize ()
 -{
 -      /* [HGM] Awkward testing. Should really be a table */
 -      int overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
 -      if( gameInfo.variant == VariantXiangqi )
 -           overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 0;
 -      if( gameInfo.variant == VariantShogi )
 -           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 ||
 -          gameInfo.variant == VariantGothic || gameInfo.variant == VariantFalcon || gameInfo.variant == VariantJanus )
 -           overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
 -      if( gameInfo.variant == VariantCourier )
 -           overruled = gameInfo.boardWidth != 12 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
 -      if( gameInfo.variant == VariantSuper )
 -           overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
 -      if( gameInfo.variant == VariantGreat )
 -           overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
 -      if( gameInfo.variant == VariantSChess )
 -           overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 7;
 -      if( gameInfo.variant == VariantGrand )
 -           overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 7;
 -      return overruled;
 +NonStandardBoardSize (VariantClass v, int boardWidth, int boardHeight, int holdingsSize)
 +{
 +      int width = 8, height = 8, holdings = 0;             // most common sizes
 +      if( v == VariantUnknown || *engineVariant) return 0; // engine-defined name never needs prefix
 +      // correct the deviations default for each variant
 +      if( v == VariantXiangqi ) width = 9,  height = 10;
 +      if( v == VariantShogi )   width = 9,  height = 9,  holdings = 7;
 +      if( v == VariantBughouse || v == VariantCrazyhouse) holdings = 5;
 +      if( v == VariantCapablanca || v == VariantCapaRandom ||
 +          v == VariantGothic || v == VariantFalcon || v == VariantJanus )
 +                                width = 10;
 +      if( v == VariantCourier ) width = 12;
 +      if( v == VariantSuper )                            holdings = 8;
 +      if( v == VariantGreat )   width = 10,              holdings = 8;
 +      if( v == VariantSChess )                           holdings = 7;
 +      if( v == VariantGrand )   width = 10, height = 10, holdings = 7;
 +      if( v == VariantChuChess) width = 10, height = 10;
 +      if( v == VariantChu )     width = 12, height = 12;
 +      return boardWidth >= 0   && boardWidth   != width  || // -1 is default,
 +             boardHeight >= 0  && boardHeight  != height || // and thus by definition OK
 +             holdingsSize >= 0 && holdingsSize != holdings;
 +}
 +
 +char variantError[MSG_SIZ];
 +
 +char *
 +SupportedVariant (char *list, VariantClass v, int boardWidth, int boardHeight, int holdingsSize, int proto, char *engine)
 +{     // returns error message (recognizable by upper-case) if engine does not support the variant
 +      char *p, *variant = VariantName(v);
 +      static char b[MSG_SIZ];
 +      if(NonStandardBoardSize(v, boardWidth, boardHeight, holdingsSize)) { /* [HGM] make prefix for non-standard board size. */
 +         snprintf(b, MSG_SIZ, "%dx%d+%d_%s", boardWidth, boardHeight,
 +                                               holdingsSize, variant); // cook up sized variant name
 +           /* [HGM] varsize: try first if this deviant size variant is specifically known */
 +           if(StrStr(list, b) == NULL) {
 +               // specific sized variant not known, check if general sizing allowed
 +               if(proto != 1 && StrStr(list, "boardsize") == NULL) {
 +                   snprintf(variantError, MSG_SIZ, "Board size %dx%d+%d not supported by %s",
 +                            boardWidth, boardHeight, holdingsSize, engine);
 +                   return NULL;
 +               }
 +               /* [HGM] here we really should compare with the maximum supported board size */
 +           }
 +      } else snprintf(b, MSG_SIZ,"%s", variant);
 +      if(proto == 1) return b; // for protocol 1 we cannot check and hope for the best
 +      p = StrStr(list, b);
 +      while(p && (p != list && p[-1] != ',' || p[strlen(b)] && p[strlen(b)] != ',') ) p = StrStr(p+1, b);
 +      if(p == NULL) {
 +          // occurs not at all in list, or only as sub-string
 +          snprintf(variantError, MSG_SIZ, _("Variant %s not supported by %s"), b, engine);
 +          if(p = StrStr(list, b)) { // handle requesting parent variant when only size-overridden is supported
 +              int l = strlen(variantError);
 +              char *q;
 +              while(p != list && p[-1] != ',') p--;
 +              q = strchr(p, ',');
 +              if(q) *q = NULLCHAR;
 +              snprintf(variantError + l, MSG_SIZ - l,  _(", but %s is"), p);
 +              if(q) *q= ',';
 +          }
 +          return NULL;
 +      }
 +      return b;
  }
  
  void
  InitChessProgram (ChessProgramState *cps, int setup)
  /* setup needed to setup FRC opening position */
  {
 -    char buf[MSG_SIZ], b[MSG_SIZ];
 +    char buf[MSG_SIZ], *b;
      if (appData.noChessProgram) return;
      hintRequested = FALSE;
      bookRequested = FALSE;
      if (gameInfo.variant != VariantNormal &&
        gameInfo.variant != VariantLoadable
          /* [HGM] also send variant if board size non-standard */
 -        || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0
 -                                            ) {
 -      char *v = VariantName(gameInfo.variant);
 -      if (cps->protocolVersion != 1 && StrStr(cps->variants, v) == NULL) {
 -        /* [HGM] in protocol 1 we have to assume all variants valid */
 -      snprintf(buf, MSG_SIZ, _("Variant %s not supported by %s"), v, cps->tidy);
 -      DisplayFatalError(buf, 0, 1);
 +        || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0) {
 +
 +      b = SupportedVariant(cps->variants, gameInfo.variant, gameInfo.boardWidth,
 +                           gameInfo.boardHeight, gameInfo.holdingsSize, cps->protocolVersion, cps->tidy);
 +      if (b == NULL) {
 +      DisplayFatalError(variantError, 0, 1);
        return;
        }
  
 -      if(NonStandardBoardSize()) { /* [HGM] make prefix for non-standard board size. */
 -      snprintf(b, MSG_SIZ, "%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) {
 -               // 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) {
 -                   snprintf(buf, MSG_SIZ, "Board size %dx%d+%d not supported by %s",
 -                            gameInfo.boardWidth, gameInfo.boardHeight, gameInfo.holdingsSize, cps->tidy);
 -                       DisplayFatalError(buf, 0, 1);
 -                       return;
 -                   }
 -                   /* [HGM] here we really should compare with the maximum supported board size */
 -               }
 -           }
 -      } else snprintf(b, MSG_SIZ,"%s", VariantName(gameInfo.variant));
        snprintf(buf, MSG_SIZ, "variant %s\n", b);
        SendToProgram(buf, cps);
      }
        SendToProgram("easy\n", cps);
      }
      if (cps->usePing) {
 -      snprintf(buf, MSG_SIZ, "ping %d\n", ++cps->lastPing);
 +      snprintf(buf, MSG_SIZ, "ping %d\n", initPing = ++cps->lastPing);
        SendToProgram(buf, cps);
      }
      cps->initDone = TRUE;
@@@ -10799,7 -10334,6 +10800,7 @@@ SwapEngines (int n
      SWAP(fenOverride, p)
      SWAP(NPS, h)
      SWAP(accumulateTC, h)
 +    SWAP(drawDepth, h)
      SWAP(host, p)
  }
  
@@@ -11081,7 -10615,7 +11082,7 @@@ GameEnds (ChessMove result, char *resul
              result, resultDetails ? resultDetails : "(null)", whosays);
      }
  
 -    fromX = fromY = -1; // [HGM] abort any move the user is entering.
 +    fromX = fromY = killX = killY = -1; // [HGM] abort any move the user is entering. // [HGM] lion
  
      if(pausing) PauseEvent(); // can happen when we abort a paused game (New Game or Quit)
  
                    PlayIcsUnfinishedSound();
                }
            }
 +          if(appData.quitNext) { ExitEvent(0); return; }
        } else if (gameMode == EditGame ||
                   gameMode == PlayFromGameFile ||
                   gameMode == AnalyzeMode ||
@@@ -11480,8 -11013,7 +11481,8 @@@ FeedMovesToProgram (ChessProgramState *
      if(currentlyInitializedVariant != gameInfo.variant) {
        char buf[MSG_SIZ];
          // [HGM] variantswitch: make engine aware of new variant
 -      if(cps->protocolVersion > 1 && StrStr(cps->variants, VariantName(gameInfo.variant)) == NULL)
 +      if(!SupportedVariant(cps->variants, gameInfo.variant, gameInfo.boardWidth,
 +                             gameInfo.boardHeight, gameInfo.holdingsSize, cps->protocolVersion, ""))
                return; // [HGM] refrain from feeding moves altogether if variant is unsupported!
        snprintf(buf, MSG_SIZ, "variant %s\n", VariantName(gameInfo.variant));
        SendToProgram(buf, cps);
@@@ -11564,7 -11096,6 +11565,7 @@@ Reset (int redraw, int init
      lastHint[0] = NULLCHAR;
      ClearGameInfo(&gameInfo);
      gameInfo.variant = StringToVariant(appData.variant);
 +    if(gameInfo.variant == VariantNormal && strcmp(appData.variant, "normal")) gameInfo.variant = VariantUnknown;
      ics_user_moved = ics_clock_paused = FALSE;
      ics_getting_history = H_FALSE;
      ics_gamenum = -1;
      ClearPremoveHighlights();
      gotPremove = FALSE;
      alarmSounded = FALSE;
 +    killX = killY = -1; // [HGM] lion
  
      GameEnds(EndOfFile, NULL, GE_PLAYER);
      if(appData.serverMovesName != NULL) {
@@@ -11759,7 -11289,6 +11760,7 @@@ LoadGameOneMove (ChessMove readAhead
        case WhiteNonPromotion:
        case BlackNonPromotion:
        case NormalMove:
 +      case FirstLeg:
        case WhiteKingSideCastle:
        case WhiteQueenSideCastle:
        case BlackKingSideCastle:
          toX = currentMoveString[2] - AAA;
          toY = currentMoveString[3] - ONE;
        promoChar = currentMoveString[4];
 +      if(promoChar == ';') promoChar = NULLCHAR;
        break;
  
        case WhiteDrop:
  
        thinkOutput[0] = NULLCHAR;
        MakeMove(fromX, fromY, toX, toY, promoChar);
 +      killX = killY = -1; // [HGM] lion: used up
        currentMove = forwardMostMove;
        return TRUE;
      }
  PackMove (int fromX, int fromY, int toX, int toY, ChessSquare promoPiece)
  {
      int sq = fromX + (fromY<<4);
-     int piece = quickBoard[sq];
+     int piece = quickBoard[sq], rook;
      quickBoard[sq] = 0;
      moveDatabase[movePtr].to = pieceList[piece] = sq = toX + (toY<<4);
-     if(piece == pieceList[1] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+     if(piece == pieceList[1] && fromY == toY) {
+       if((toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
        int from = toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT;
        moveDatabase[movePtr++].piece = Q_WCASTL;
        quickBoard[sq] = piece;
        piece = quickBoard[from]; quickBoard[from] = 0;
        moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+       } else if((rook = quickBoard[sq]) && pieceType[rook] == WhiteRook) { // FRC castling
+       quickBoard[sq] = 0; // remove Rook
+       moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2); // King to-square
+       moveDatabase[movePtr++].piece = Q_WCASTL;
+       quickBoard[sq] = pieceList[1]; // put King
+       piece = rook;
+       moveDatabase[movePtr].to = pieceList[rook] = sq = toX>fromX ? sq-1 : sq+1;
+       }
      } else
-     if(piece == pieceList[2] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+     if(piece == pieceList[2] && fromY == toY) {
+       if((toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
        int from = (toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT) + (BOARD_HEIGHT-1 <<4);
        moveDatabase[movePtr++].piece = Q_BCASTL;
        quickBoard[sq] = piece;
        piece = quickBoard[from]; quickBoard[from] = 0;
        moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+       } else if((rook = quickBoard[sq]) && pieceType[rook] == BlackRook) { // FRC castling
+       quickBoard[sq] = 0; // remove Rook
+       moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2);
+       moveDatabase[movePtr++].piece = Q_BCASTL;
+       quickBoard[sq] = pieceList[2]; // put King
+       piece = rook;
+       moveDatabase[movePtr].to = pieceList[rook] = sq = toX>fromX ? sq-1 : sq+1;
+       }
      } else
      if(epOK && (pieceType[piece] == WhitePawn || pieceType[piece] == BlackPawn) && fromX != toX && quickBoard[sq] == 0) {
        quickBoard[(fromY<<4)+toX] = 0;
@@@ -12402,7 -11947,7 +12421,7 @@@ GameContainsPosition (FILE *f, ListGam
        for(next = WhitePawn; next<EmptySquare; next++) keys[next] = random()>>8 ^ random()<<6 ^random()<<20;
        initDone = TRUE;
      }
 -    if(lg->gameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen);
 +    if(lg->gameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen, FALSE);
      else CopyBoard(boards[scratch], initialPosition); // default start position
      if(lg->moves) {
        turn = btm + 1;
            case WhiteNonPromotion:
            case BlackNonPromotion:
            case NormalMove:
 +          case FirstLeg:
            case WhiteKingSideCastle:
            case WhiteQueenSideCastle:
            case BlackKingSideCastle:
@@@ -12511,7 -12055,6 +12530,7 @@@ LoadGame (FILE *f, int gameNumber, cha
      if (gameMode != BeginningOfGame) {
        Reset(FALSE, TRUE);
      }
 +    killX = killY = -1; // [HGM] lion: in case we did not Reset
  
      gameFileFP = f;
      if (lastLoadGameFP != NULL && lastLoadGameFP != f) {
            break;
  
          case NormalMove:
 +        case FirstLeg:
            /* Only a NormalMove can be at the start of a game
             * without a position diagram. */
            if (lastLoadGameStart == EndOfFile ) {
        if (gameInfo.fen != NULL) {
          Board initial_position;
          startedFromSetupPosition = TRUE;
 -        if (!ParseFEN(initial_position, &blackPlaysFirst, gameInfo.fen)) {
 +        if (!ParseFEN(initial_position, &blackPlaysFirst, gameInfo.fen, TRUE)) {
            Reset(TRUE, TRUE);
            DisplayError(_("Bad FEN position in file"), 0);
            return FALSE;
        AnalyzeFileEvent();
      }
  
 +    if(gameInfo.result == GameUnfinished && gameInfo.resultDetails && appData.clockMode) {
 +      long int w, b; // [HGM] adjourn: restore saved clock times
 +      char *p = strstr(gameInfo.resultDetails, "(Clocks:");
 +      if(p && sscanf(p+8, "%ld,%ld", &w, &b) == 2) {
 +          timeRemaining[0][forwardMostMove] = whiteTimeRemaining = 1000*w + 500;
 +          timeRemaining[1][forwardMostMove] = blackTimeRemaining = 1000*b + 500;
 +      }
 +    }
 +
      if(creatingBook) return TRUE;
      if (!matchMode && pos > 0) {
        ToNrEvent(pos); // [HGM] no autoplay if selected on position
@@@ -13064,7 -12597,7 +13083,7 @@@ LoadPosition (FILE *f, int positionNumb
      }
  
      if (fenMode) {
 -      if (!ParseFEN(initial_position, &blackPlaysFirst, line)) {
 +      if (!ParseFEN(initial_position, &blackPlaysFirst, line, TRUE)) {
            DisplayError(_("Bad FEN position in file"), 0);
            return FALSE;
        }
@@@ -13306,7 -12839,7 +13325,7 @@@ SaveGamePGN (FILE *f
      if(appData.numberTag && matchMode) fprintf(f, "[Number \"%d\"]\n", nextGame+1); // [HGM] number tag
  
      if (backwardMostMove > 0 || startedFromSetupPosition) {
 -        char *fen = PositionToFEN(backwardMostMove, NULL);
 +        char *fen = PositionToFEN(backwardMostMove, NULL, 1);
          fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen);
        fprintf(f, "\n{--------------\n");
        PrintPosition(f, backwardMostMove);
      /* Print result */
      if (gameInfo.resultDetails != NULL &&
        gameInfo.resultDetails[0] != NULLCHAR) {
 -      fprintf(f, "{%s} %s\n\n", gameInfo.resultDetails,
 -              PGNResult(gameInfo.result));
 +      char buf[MSG_SIZ], *p = gameInfo.resultDetails;
 +      if(gameInfo.result == GameUnfinished && appData.clockMode &&
 +         (gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack || gameMode == TwoMachinesPlay)) // [HGM] adjourn: save clock settings
 +          snprintf(buf, MSG_SIZ, "%s (Clocks: %ld, %ld)", p, whiteTimeRemaining/1000, blackTimeRemaining/1000), p = buf;
 +      fprintf(f, "{%s} %s\n\n", p, PGNResult(gameInfo.result));
      } else {
        fprintf(f, "%s\n\n", PGNResult(gameInfo.result));
      }
@@@ -13578,7 -13108,7 +13597,7 @@@ SavePosition (FILE *f, int dummy, char 
        PrintPosition(f, currentMove);
        fprintf(f, "--------------]\n");
      } else {
 -      fen = PositionToFEN(currentMove, NULL);
 +      fen = PositionToFEN(currentMove, NULL, 1);
        fprintf(f, "%s\n", fen);
        free(fen);
      }
@@@ -14480,7 -14010,7 +14499,7 @@@ TwoMachinesEvent P((void)
        case MachinePlaysWhite:
        case MachinePlaysBlack:
        if (WhiteOnMove(forwardMostMove) == (gameMode == MachinePlaysWhite)) {
 -          DisplayError(_("Wait until your turn,\nor select Move Now"), 0);
 +          DisplayError(_("Wait until your turn,\nor select 'Move Now'."), 0);
            return;
        }
        /* fall through */
      }
      if(WaitForEngine(&second, TwoMachinesEventIfReady)) return; // (if needed:) started up second engine, so wait for features
  
 -    if(second.protocolVersion >= 2 && !strstr(second.variants, VariantName(gameInfo.variant))) {
 +    if(!SupportedVariant(second.variants, gameInfo.variant, gameInfo.boardWidth,
 +                         gameInfo.boardHeight, gameInfo.holdingsSize, second.protocolVersion, second.tidy)) {
        startingEngine = FALSE;
        DisplayError("second engine does not play this", 0);
        return;
@@@ -14918,15 -14447,11 +14937,15 @@@ EditPositionMenuEvent (ChessSquare sele
  {
      char buf[MSG_SIZ];
      ChessSquare piece = boards[0][y][x];
 +    static Board erasedBoard, currentBoard, menuBoard, nullBoard;
 +    static int lastVariant;
  
      if (gameMode != EditPosition && gameMode != IcsExamining) return;
  
      switch (selection) {
        case ClearBoard:
 +      CopyBoard(currentBoard, boards[0]);
 +      CopyBoard(menuBoard, initialPosition);
        if (gameMode == IcsExamining && ics_type == ICS_FICS) {
            SendToICS(ics_prefix);
            SendToICS("bsetup clear\n");
            SendToICS(ics_prefix);
            SendToICS("clearboard\n");
        } else {
 +            int nonEmpty = 0;
              for (x = 0; x < BOARD_WIDTH; x++) { ChessSquare p = EmptySquare;
                if(x == BOARD_LEFT-1 || x == BOARD_RGHT) p = (ChessSquare) 0; /* [HGM] holdings */
                  for (y = 0; y < BOARD_HEIGHT; y++) {
                            SendToICS(buf);
                        }
                    } else {
 +                      if(boards[0][y][x] != p) nonEmpty++;
                        boards[0][y][x] = p;
                    }
                }
 +              menuBoard[1][x] = menuBoard[BOARD_HEIGHT-2][x] = p;
 +          }
 +          if(gameMode != IcsExamining) { // [HGM] editpos: cycle trough boards
 +              for(x = BOARD_LEFT; x < BOARD_RGHT; x++) { // create 'menu board' by removing duplicates 
 +                  ChessSquare p = menuBoard[0][x];
 +                  for(y = x + 1; y < BOARD_RGHT; y++) if(menuBoard[0][y] == p) menuBoard[0][y] = EmptySquare;
 +                  p = menuBoard[BOARD_HEIGHT-1][x];
 +                  for(y = x + 1; y < BOARD_RGHT; y++) if(menuBoard[BOARD_HEIGHT-1][y] == p) menuBoard[BOARD_HEIGHT-1][y] = EmptySquare;
 +              }
 +              DisplayMessage("Clicking clock again restores position", "");
 +              if(gameInfo.variant != lastVariant) lastVariant = gameInfo.variant, CopyBoard(erasedBoard, boards[0]);
 +              if(!nonEmpty) { // asked to clear an empty board
 +                  CopyBoard(boards[0], menuBoard);
 +              } else
 +              if(CompareBoards(currentBoard, menuBoard)) { // asked to clear an empty board
 +                  CopyBoard(boards[0], initialPosition);
 +              } else
 +              if(CompareBoards(currentBoard, initialPosition) && !CompareBoards(currentBoard, erasedBoard)
 +                                                               && !CompareBoards(nullBoard, erasedBoard)) {
 +                  CopyBoard(boards[0], erasedBoard);
 +              } else
 +                  CopyBoard(erasedBoard, currentBoard);
 +
            }
        }
        if (gameMode == EditPosition) {
          if(gameInfo.variant == VariantShatranj ||
             gameInfo.variant == VariantXiangqi  ||
             gameInfo.variant == VariantCourier  ||
 +           gameInfo.variant == VariantASEAN    ||
             gameInfo.variant == VariantMakruk     )
              selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz);
          goto defaultlabel;
@@@ -15625,7 -15124,7 +15644,7 @@@ RetractMoveEvent (
        case MachinePlaysWhite:
        case MachinePlaysBlack:
        if (WhiteOnMove(forwardMostMove) == (gameMode == MachinePlaysWhite)) {
 -          DisplayError(_("Wait until your turn,\nor select Move Now"), 0);
 +          DisplayError(_("Wait until your turn,\nor select 'Move Now'."), 0);
            return;
        }
        if (forwardMostMove < 2) return;
@@@ -15723,14 -15222,14 +15742,14 @@@ HintEvent (
      switch (gameMode) {
        case MachinePlaysWhite:
        if (WhiteOnMove(forwardMostMove)) {
 -          DisplayError(_("Wait until your turn"), 0);
 +          DisplayError(_("Wait until your turn."), 0);
            return;
        }
        break;
        case BeginningOfGame:
        case MachinePlaysBlack:
        if (!WhiteOnMove(forwardMostMove)) {
 -          DisplayError(_("Wait until your turn"), 0);
 +          DisplayError(_("Wait until your turn."), 0);
            return;
        }
        break;
@@@ -15783,14 -15282,14 +15802,14 @@@ BookEvent (
      switch (gameMode) {
        case MachinePlaysWhite:
        if (WhiteOnMove(forwardMostMove)) {
 -          DisplayError(_("Wait until your turn"), 0);
 +          DisplayError(_("Wait until your turn."), 0);
            return;
        }
        break;
        case BeginningOfGame:
        case MachinePlaysBlack:
        if (!WhiteOnMove(forwardMostMove)) {
 -          DisplayError(_("Wait until your turn"), 0);
 +          DisplayError(_("Wait until your turn."), 0);
            return;
        }
        break;
@@@ -16454,27 -15953,6 +16473,27 @@@ SendTimeRemaining (ChessProgramState *c
      SendToProgram(message, cps);
  }
  
 +char *
 +EngineDefinedVariant (ChessProgramState *cps, int n)
 +{   // return name of n-th unknown variant that engine supports
 +    static char buf[MSG_SIZ];
 +    char *p, *s = cps->variants;
 +    if(!s) return NULL;
 +    do { // parse string from variants feature
 +      VariantClass v;
 +      p = strchr(s, ',');
 +      if(p) *p = NULLCHAR;
 +      v = StringToVariant(s);
 +      if(v == VariantNormal && strcmp(s, "normal") && !strstr(s, "_normal")) v = VariantUnknown; // garbage is recognized as normal
 +      if(v == VariantUnknown) { // non-standard variant in list of engine-supported variants
 +          if(--n < 0) safeStrCpy(buf, s, MSG_SIZ);
 +      }
 +      if(p) *p++ = ',';
 +      if(n < 0) return buf;
 +    } while(s = p);
 +    return NULL;
 +}
 +
  int
  BoolFeature (char **p, char *name, int *loc, ChessProgramState *cps)
  {
@@@ -16689,7 -16167,6 +16708,7 @@@ ParseFeatures (char *args, ChessProgram
      /* End of additions by Tord */
  
      /* [HGM] added features: */
 +    if (BoolFeature(&p, "highlight", &cps->highlight, cps)) continue;
      if (BoolFeature(&p, "debug", &cps->debug, cps)) continue;
      if (BoolFeature(&p, "nps", &cps->supportsNPS, cps)) continue;
      if (IntFeature(&p, "level", &cps->maxNrOfSessions, cps)) continue;
@@@ -16843,7 -16320,7 +16862,7 @@@ TypeInDoneEvent (char *move
        ChessMove moveType;
  
        // [HGM] FENedit
 -      if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
 +      if(gameMode == EditPosition && ParseFEN(board, &n, move, TRUE) ) {
                EditPositionPasteFEN(move);
                return;
        }
@@@ -17545,7 -17022,7 +17564,7 @@@ PGNDate (
  
  
  char *
 -PositionToFEN (int move, char *overrideCastling)
 +PositionToFEN (int move, char *overrideCastling, int moveCounts)
  {
      int i, j, fromX, fromY, toX, toY;
      int whiteToPlay;
                      *p++ = '+';
                      piece = (ChessSquare)(DEMOTED piece);
                  }
 -                *p++ = PieceToChar(piece);
 +                *p++ = (piece == DarkSquare ? '*' : PieceToChar(piece));
                  if(p[-1] == '~') {
                      /* [HGM] flag promoted pieces as '<promoted>~' (Crazyhouse) */
                      p[-1] = PieceToChar((ChessSquare)(DEMOTED piece));
    }
  
    if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&
 -     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) {
 +     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&
 +     gameInfo.variant != VariantMakruk   && gameInfo.variant != VariantASEAN ) {
      /* En passant target square */
      if (move > backwardMostMove) {
          fromX = moveList[move - 1][0] - AAA;
    }
    }
  
 -    /* [HGM] find reversible plies */
 +    if(moveCounts)
      {   int i = 0, j=move;
  
 +        /* [HGM] find reversible plies */
          if (appData.debugMode) { int k;
              fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);
              for(k=backwardMostMove; k<=forwardMostMove; k++)
          if( j == backwardMostMove ) i += initialRulePlies;
          sprintf(p, "%d ", i);
          p += i>=100 ? 4 : i >= 10 ? 3 : 2;
 -    }
 -    /* Fullmove number */
 -    sprintf(p, "%d", (move / 2) + 1);
 +
 +        /* Fullmove number */
 +        sprintf(p, "%d", (move / 2) + 1);
 +    } else *--p = NULLCHAR;
  
      return StrSave(buf);
  }
  
  Boolean
 -ParseFEN (Board board, int *blackPlaysFirst, char *fen)
 +ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
  {
 -    int i, j;
 +    int i, j, k, w=0;
      char *p, c;
      int emptycount, virgin[BOARD_FILES];
      ChessSquare piece;
  
      p = fen;
  
 -    /* [HGM] by default clear Crazyhouse holdings, if present */
 -    if(gameInfo.holdingsWidth) {
 -       for(i=0; i<BOARD_HEIGHT; i++) {
 -           board[i][0]             = EmptySquare; /* black holdings */
 -           board[i][BOARD_WIDTH-1] = EmptySquare; /* white holdings */
 -           board[i][1]             = (ChessSquare) 0; /* black counts */
 -           board[i][BOARD_WIDTH-2] = (ChessSquare) 0; /* white counts */
 -       }
 -    }
 -
      /* Piece placement data */
      for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
        j = 0;
        for (;;) {
 -            if (*p == '/' || *p == ' ' || (*p == '[' && i == 0) ) {
 -                if (*p == '/') p++;
 +            if (*p == '/' || *p == ' ' || *p == '[' ) {
 +              if(j > w) w = j;
                  emptycount = gameInfo.boardWidth - j;
                  while (emptycount--)
                          board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;
 +                if (*p == '/') p++;
 +              else if(autoSize) { // we stumbled unexpectedly into end of board
 +                    for(k=i; k<BOARD_HEIGHT; k++) { // too few ranks; shift towards bottom
 +                      for(j=0; j<BOARD_WIDTH; j++) board[k-i][j] = board[k][j];
 +                    }
 +                  appData.NrRanks = gameInfo.boardHeight - i; i=0;
 +                }
                break;
  #if(BOARD_FILES >= 10)
              } else if(*p=='x' || *p=='X') { /* [HGM] X means 10 */
                  while (emptycount--)
                          board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;
  #endif
 +            } else if (*p == '*') {
 +              board[i][(j++)+gameInfo.holdingsWidth] = DarkSquare; p++;
              } else if (isdigit(*p)) {
                emptycount = *p++ - '0';
                  while(isdigit(*p)) emptycount = 10*emptycount + *p++ - '0'; /* [HGM] allow > 9 */
                  if(*p=='+') {
                      piece = CharToPiece(*++p);
                      if(piece == EmptySquare) return FALSE; /* unknown piece */
 -                    piece = (ChessSquare) (PROMOTED piece ); p++;
 +                    piece = (ChessSquare) (CHUPROMOTED piece ); p++;
                      if(PieceToChar(piece) != '+') return FALSE; /* unpromotable piece */
                  } else piece = CharToPiece(*p++);
  
      }
      while (*p == '/' || *p == ' ') p++;
  
 +    if(autoSize) appData.NrFiles = w, InitPosition(TRUE);
 +
 +    /* [HGM] by default clear Crazyhouse holdings, if present */
 +    if(gameInfo.holdingsWidth) {
 +       for(i=0; i<BOARD_HEIGHT; i++) {
 +           board[i][0]             = EmptySquare; /* black holdings */
 +           board[i][BOARD_WIDTH-1] = EmptySquare; /* white holdings */
 +           board[i][1]             = (ChessSquare) 0; /* black counts */
 +           board[i][BOARD_WIDTH-2] = (ChessSquare) 0; /* white counts */
 +       }
 +    }
 +
      /* [HGM] look for Crazyhouse holdings here */
      while(*p==' ') p++;
      if( gameInfo.holdingsWidth && p[-1] == '/' || *p == '[') {
  
      /* read e.p. field in games that know e.p. capture */
      if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&
 -       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) {
 +       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&
 +       gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN ) {
        if(*p=='-') {
          p++; board[EP_STATUS] = EP_NONE;
        } else {
@@@ -18001,7 -17463,7 +18020,7 @@@ EditPositionPasteFEN (char *fen
    if (fen != NULL) {
      Board initial_position;
  
 -    if (!ParseFEN(initial_position, &blackPlaysFirst, fen)) {
 +    if (!ParseFEN(initial_position, &blackPlaysFirst, fen, TRUE)) {
        DisplayError(_("Bad FEN position in clipboard"), 0);
        return ;
      } else {
diff --combined backend.h
+++ b/backend.h
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
  #ifndef XB_BACKEND
  #define XB_BACKEND
  
- /* unsigned int 64 for engine nodes work and display */
- #ifdef WIN32
-        /* I don't know the name for this type of other compiler
-         * If it not work, just modify here
-         * This is for MS Visual Studio
-         */
-        #ifdef _MSC_VER
-                #define u64 unsigned __int64
-                #define s64 signed __int64
-                #define u64Display "%I64u"
-                #define s64Display "%I64d"
-                #define u64Const(c) (c ## UI64)
-                #define s64Const(c) (c ## I64)
-        #else
-                /* place holder
-                 * or dummy types for other compiler
-                 * [HGM] seems that -mno-cygwin comple needs %I64?
-                 */
-                #define u64 unsigned long long
-                #define s64 signed long long
-                #ifdef USE_I64
-                   #define u64Display "%I64u"
-                   #define s64Display "%I64d"
-                #else
-                   #define u64Display "%llu"
-                   #define s64Display "%lld"
-                #endif
-                #define u64Const(c) (c ## ULL)
-                #define s64Const(c) (c ## LL)
-        #endif
- #else
-        /* GNU gcc */
-        #define u64 unsigned long long
-        #define s64 signed long long
-        #define u64Display "%llu"
-        #define s64Display "%lld"
-        #define u64Const(c) (c ## ull)
-        #define s64Const(c) (c ## ll)
- #endif
  #include "lists.h"
  
  typedef int (*FileProc) P((FILE *f, int n, char *title));
@@@ -115,13 -75,11 +75,13 @@@ extern char lastMsg[MSG_SIZ]
  extern Boolean bookUp;
  extern int tinyLayout, smallLayout;
  extern Boolean mcMode;
 +extern int dragging;
 +extern char variantError[];
  
  void MarkMenuItem P((char *menuRef, int state));
  char *CmailMsg P((void));
  /* Tord: Added the useFEN960 parameter in PositionToFEN() below */
 -char *PositionToFEN P((int move, char* useFEN960));
 +char *PositionToFEN P((int move, char* useFEN960, int moveCounts));
  void AlphaRank P((char *s, int n)); /* [HGM] Shogi move preprocessor */
  void EditPositionPasteFEN P((char *fen));
  void TimeDelay P((long ms));
@@@ -243,9 -201,8 +203,9 @@@ int PromoScroll P((int x, int y))
  void EditBookEvent P((void));
  Boolean DisplayBook P((int moveNr));
  void SaveToBook P((char *text));
 +void HoverEvent P((int hiX, int hiY, int x, int y));
  int PackGame P((Board board));
 -Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
 +Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen, Boolean autoSize));
  void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar, Board board));
  void PackMove P((int fromX, int fromY, int toX, int toY, ChessSquare promoPiece));
  void ics_printf P((char *format, ...));
@@@ -394,7 -351,6 +354,7 @@@ typedef struct XB_CPS 
      int debug;      /* [HGM] ignore engine debug lines starting with '#'    */
      int maxNrOfSessions; /* [HGM] secondary TC: max args in 'level' command */
      int accumulateTC; /* [HGM] secondary TC: how to handle extra sessions   */
 +    int drawDepth;    /* [HGM] egbb: search depth to play egbb draws        */
      int nps;          /* [HGM] nps: factor for node count to replace time   */
      int supportsNPS;
      int alphaRank;    /* [HGM] shogi: engine uses shogi-type coordinates    */
      char *egtFormats; /* [HGM] EGT: supported tablebase formats             */
      int bookSuspend;  /* [HGM] book: go was deferred because of book hit    */
      int pause;        /* [HGM] pause: 1=supports it, 2=actually paused      */
 +    int highlight;    /* [HGM] engine wants to get lift and put commands    */
      int nrOptions;    /* [HGM] options: remembered option="..." features    */
  #define MAX_OPTIONS 200
      Option option[MAX_OPTIONS];
@@@ -443,8 -398,6 +403,8 @@@ extern int errorExitStatus
  extern char *recentEngines;
  extern char *comboLine;
  extern Boolean partnerUp, twoBoards;
 +extern char engineVariant[];
 +char *EngineDefinedVariant P((ChessProgramState *cps, int n));
  void SettingsPopUp P((ChessProgramState *cps)); // [HGM] really in front-end, but CPS not known in frontend.h
  int WaitForEngine P((ChessProgramState *cps, DelayedEventCallback x));
  void Load P((ChessProgramState *cps, int n));
@@@ -453,7 -406,6 +413,7 @@@ void MoveHistorySet P(( char movelist[]
  void MakeEngineOutputTitle P((void));
  void LoadTheme P((void));
  void CreateBookEvent P((void));
 +char *SupportedVariant P((char *list, VariantClass v, int w, int h, int s, int proto, char *engine));
  
  /* A point in time */
  typedef struct {
diff --combined board.c
+++ b/board.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -599,13 -599,11 +599,13 @@@ voi
  AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
  {
    ChessSquare piece;
 -  int hop;
 +  int hop, x = toX, y = toY;
    Pnt      start, finish, mid;
    Pnt      frames[kFactor * 2 + 1];
    int       nFrames, startColor, endColor;
  
 +  if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();
 +
    /* Are we animating? */
    if (!appData.animate || appData.blindfold)
      return;
    piece = board[fromY][fromX];
    if (piece >= EmptySquare) return;
  
 +  if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square
 +
 +again:
 +
  #if DONT_HOP
    hop = FALSE;
  #else
  
    /* Be sure end square is redrawn */
    damage[0][toY][toX] |= True;
 +
 +  if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg
  }
  
  void
@@@ -825,7 -817,6 +825,7 @@@ DrawSquare (int row, int column, ChessS
        snprintf(tString, 3, "%d", piece);
        align = 4; // holdings count in upper-left corner
      }
 +    if(piece == DarkSquare) square_color = 2;
      if(square_color == 2 || appData.blindfold) piece = EmptySquare;
  
      if (do_flash && piece != EmptySquare && appData.flashCount > 0) {
diff --combined common.h
+++ b/common.h
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
@@@ -112,6 -112,46 +112,46 @@@ typedef char *String
  
  /* End compatibility grunge */
  
+ /* unsigned int 64 for engine nodes work and display */
+ #ifdef WIN32
+        /* I don't know the name for this type of other compiler
+         * If it not work, just modify here
+         * This is for MS Visual Studio
+         */
+        #ifdef _MSC_VER
+                #define u64 unsigned __int64
+                #define s64 signed __int64
+                #define u64Display "%I64u"
+                #define s64Display "%I64d"
+                #define u64Const(c) (c ## UI64)
+                #define s64Const(c) (c ## I64)
+        #else
+                /* place holder
+                 * or dummy types for other compiler
+                 * [HGM] seems that -mno-cygwin comple needs %I64?
+                 */
+                #define u64 unsigned long long
+                #define s64 signed long long
+                #ifdef USE_I64
+                   #define u64Display "%I64u"
+                   #define s64Display "%I64d"
+                #else
+                   #define u64Display "%llu"
+                   #define s64Display "%lld"
+                #endif
+                #define u64Const(c) (c ## ULL)
+                #define s64Const(c) (c ## LL)
+        #endif
+ #else
+        /* GNU gcc */
+        #define u64 unsigned long long
+        #define s64 signed long long
+        #define u64Display "%llu"
+        #define s64Display "%lld"
+        #define u64Const(c) (c ## ull)
+        #define s64Const(c) (c ## ll)
+ #endif
  #define PROTOVER                2       /* engine protocol version */
  
  // [HGM] license: Messages that engines must print to satisfy their license requirements for patented variants
     outside world in ASCII. In a similar way, the different rank numbering
     systems (starting at rank 0 or 1) are implemented by redefining '1'.
  */
 -#define BOARD_RANKS             11             /* [HGM] for in declarations  */
 +#define BOARD_RANKS             17            /* [HGM] for in declarations  */
  #define BOARD_FILES             16             /* [HGM] for in declarations  */
  #define BOARD_HEIGHT (gameInfo.boardHeight)    /* [HGM] made user adjustable */
  #define BOARD_WIDTH  (gameInfo.boardWidth + 2*gameInfo.holdingsWidth)
  #define VIRGIN       (BOARD_RANKS-2)           /* [HGM] pieces not moved     */
  #define EP_STATUS    CASTLING][(BOARD_FILES-2) /* [HGM] in upper rank        */
  #define HOLDINGS_SET CASTLING][(BOARD_FILES-1) /* [HGM] in upper-right corner*/
 -#define ONE          ('1'-(BOARD_HEIGHT>9))    /* [HGM] foremost board rank  */
 +#define ONE          ('1'-(BOARD_HEIGHT==10))  /* [HGM] foremost board rank  */
  #define AAA          ('a'-BOARD_LEFT)          /* [HGM] leftmost board file  */
  #define VIRGIN_W                 1             /* [HGM] flags in Board[VIRGIN][X] */
  #define VIRGIN_B                 2
@@@ -248,20 -288,12 +288,20 @@@ typedef enum 
      WhitePawn, WhiteKnight, WhiteBishop, WhiteRook, WhiteQueen,
      WhiteFerz, WhiteAlfil, WhiteAngel, WhiteMarshall, WhiteWazir, WhiteMan,
      WhiteCannon, WhiteNightrider, WhiteCardinal, WhiteDragon, WhiteGrasshopper,
 -    WhiteSilver, WhiteFalcon, WhiteLance, WhiteCobra, WhiteUnicorn, WhiteKing,
 +    WhiteSilver, WhiteFalcon, WhiteLance, WhiteCobra, WhiteUnicorn, WhiteLion,
 +    WhiteTokin, WhiteDagger, WhitePCardinal, WhitePDragon, WhiteCat,
 +    WhitePSword, WhiteMonarch, WhiteMother, WhiteNothing, WhitePRook, WhitePDagger,
 +    WhiteDolphin, WhiteStag, WhiteHorned, WhiteEagle, WhiteSword,
 +    WhiteCrown, WhiteHCrown, WhiteHorse, WhiteDrunk, WhitePBishop, WhiteKing,
      BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen,
      BlackFerz, BlackAlfil, BlackAngel, BlackMarshall, BlackWazir, BlackMan,
      BlackCannon, BlackNightrider, BlackCardinal, BlackDragon, BlackGrasshopper,
 -    BlackSilver, BlackFalcon, BlackLance, BlackCobra, BlackUnicorn, BlackKing,
 -    EmptySquare,
 +    BlackSilver, BlackFalcon, BlackLance, BlackCobra, BlackUnicorn, BlackLion,
 +    BlackTokin, BlackDagger, BlackPCardinal, BlackPDragon, BlackCat,
 +    BlackPSword, BlackMonarch, BlackMother, BlackNothing, BlackPRook, BlackPDagger,
 +    BlackDolphin, BlackStag, BlackHorned, BlackEagle, BlackSword,
 +    BlackCrown, BlackHCrown, BlackHorse, BlackDrunk, BlackPBishop, BlackKing,
 +    EmptySquare, DarkSquare,
      NoRights, // [HGM] gamestate: for castling rights hidden in board[CASTLING]
      ClearBoard, WhitePlay, BlackPlay, PromotePiece, DemotePiece /*for use on EditPosition menus*/
    } ChessSquare;
  #define PROMOTED       (int)WhiteDragon - (int)WhiteRook + (int)
  #define DEMOTED        (int)WhiteRook - (int)WhiteDragon + (int)
  #define SHOGI          (int)EmptySquare + (int)
 +#define CHUPROMOTED    ((int)WhitePDragon - (int)WhiteDragon)*(gameInfo.variant == VariantChu) + PROMOTED
 +#define IS_SHOGI(V)    ((V) == VariantShogi || (V) == VariantChu)
 +#define IS_LION(V)     ((V) == WhiteLion || (V) == BlackLion)
  
  
  typedef ChessSquare Board[BOARD_RANKS][BOARD_FILES];
@@@ -290,7 -319,7 +330,7 @@@ typedef enum 
      WhitePromotion, WhiteNonPromotion,
      BlackPromotion, BlackNonPromotion,
      WhiteCapturesEnPassant, BlackCapturesEnPassant,
 -    WhiteDrop, BlackDrop,
 +    WhiteDrop, BlackDrop, FirstLeg,
      NormalMove, AmbiguousMove, IllegalMove, ImpossibleMove,
      WhiteWins, BlackWins, GameIsDrawn, GameUnfinished,
      GNUChessGame, XBoardGame, MoveNumberOne, Open, Close, Nothing,
@@@ -304,7 -333,7 +344,7 @@@ typedef enum 
  } ColorClass;
  
  typedef enum {
 -    SoundMove, SoundBell, SoundAlarm, SoundIcsWin, SoundIcsLoss,
 +    SoundMove, SoundBell, SoundRoar, SoundAlarm, SoundIcsWin, SoundIcsLoss,
      SoundIcsDraw, SoundIcsUnfinished, NSoundClasses
  } SoundClass;
  
@@@ -334,7 -363,6 +374,7 @@@ typedef enum 
      Variant35,           /* Temporary name for possible future ICC wild 35 */
      Variant36,           /* Temporary name for possible future ICC wild 36 */
      VariantShogi,        /* [HGM] added variants */
 +    VariantChu,
      VariantXiangqi,
      VariantCourier,
      VariantGothic,
      VariantGreat,
      VariantTwilight,
      VariantMakruk,
 +    VariantASEAN,
      VariantSChess,
      VariantGrand,
      VariantSpartan,
 +    VariantLion,
 +    VariantChuChess,
      VariantUnknown       /* Catchall for other unknown variants */
  } VariantClass;
  
    "wild35", \
    "wild36", \
    "shogi", \
 +  "chu", \
    "xiangqi", \
    "courier", \
    "gothic", \
    "great",\
    "twilight",\
    "makruk",\
 +  "asean",\
    "seirawan",\
    "grand",\
    "spartan",\
 +  "lion",\
 +  "chuchess",\
    "unknown" \
  }
  
@@@ -541,7 -562,6 +581,7 @@@ typedef struct 
      char *soundSeek;
      char *soundMove;     // [HGM] IMPORTANT: order must be as in SoundClass
      char *soundBell;
 +    char *soundRoar;
      char *soundIcsAlarm;
      char *soundIcsWin;
      char *soundIcsLoss;
      int zippyShortGame; /* [HGM] aborter   */
  #endif
      Boolean lowTimeWarning; /* [HGM] low time */
 +    Boolean quitNext;
      char *lowTimeWarningColor;
  
      char *serverFileName;
      char *serverMovesName;
 +    char *finger;
      Boolean suppressLoadMoves;
      int serverPause;
      int timeOdds[ENGINES];
 +    int drawDepth[ENGINES];
      int timeOddsMode;
      int accumulateTC[ENGINES];
      int NPS[ENGINES];
diff --combined configure.ac
@@@ -1,7 -1,7 +1,7 @@@
  dnl| configure.in
  dnl|
  dnl| Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, 2007,
- dnl| 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+ dnl| 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
  dnl|
  dnl| GNU XBoard is free software: you can redistribute it and/or modify
  dnl| it under the terms of the GNU General Public License as published by
@@@ -28,7 -28,7 +28,7 @@@ dnl| to regenerate configure.  Then sub
  dnl| the standard version of xboard.
  
  dnl| define second argument as VERSION.PATCHLEVEL. e.g. 4.4.0j
 -AC_INIT([xboard],[4.7.2],[bug-xboard@gnu.org])
 +AC_INIT([xboard],[master-20130828],[bug-xboard@gnu.org])
  
  dnl| need this to be able to compile some files in a subdir (filebrowser)
  AM_INIT_AUTOMAKE([subdir-objects])
@@@ -56,6 -56,7 +56,6 @@@ AH_TEMPLATE([USE_PTYS],[template]
  AH_TEMPLATE([X_WCHAR],[template])
  AH_TEMPLATE([ATTENTION],[template])
  AH_TEMPLATE([DEFINED_SYS_ERRLIST],[template])
 -AH_TEMPLATE([HAVE_LIBXPM],[template])
  AH_TEMPLATE([USE_XAW3D],[template])
  AH_TEMPLATE([X_LOCALE],[template])
  
@@@ -137,61 -138,24 +137,61 @@@ FRONTEND_LIBS="
  
  AC_ARG_WITH([gtk],
              [AS_HELP_STRING([--with-gtk],[use GTK front-end (experimental)])],
 -            [with_GTK=yes],
 -            [with_GTK=no])
 +            [with_GTK=$withval],
 +            [with_GTK="no"])
  
  AC_ARG_WITH([Xaw3d],
              [AS_HELP_STRING([--with-Xaw3d],[use Xaw3d front-end (not fully supported anymore)])],
 -            [with_Xaw3d=yes],
 -            [with_Xaw3d=no])
 +            [with_Xaw3d="$withval"],
 +            [with_Xaw3d="no"])
  
  AC_ARG_WITH([Xaw],
              [AS_HELP_STRING([--with-Xaw],[use Xaw front-end (default)])],
 -            [with_Xaw=yes],
 -            [with_Xaw=no])
 +            [with_Xaw="$withval"],
 +            [with_Xaw="yes"])
 +
 +AC_ARG_WITH([iconsdir],
 +            [AS_HELP_STRING([--with-iconsdir=DIR],
 +            [path where icons get installed (default: $datadir/icons/hicolor/48x48/apps)])],
 +            [ICONSDIR="$withval"],
 +            [ICONSDIR='$(datadir)/icons/hicolor/48x48/apps'])
 +
 +AC_ARG_WITH([svgiconsdir],
 +            [AS_HELP_STRING([--with-svgiconsdir=DIR],
 +            [path where svg icons get installed (default: $datadir/icons/hicolor/scalable/apps)])],
 +            [SVGICONSDIR="$withval"],
 +            [SVGICONSDIR='$(datadir)/icons/hicolor/scalable/apps'])
 +
 +AC_ARG_WITH([desktopdir],
 +            [AS_HELP_STRING([--with-desktopdir=DIR],
 +                            [path where desktop files get installed (default: $datadir/applications)])],
 +            [DESKTOPDIR="$withval"],
 +            [DESKTOPDIR='$(datadir)/applications'])
 +
 +AC_ARG_WITH([mimedir],
 +            [AS_HELP_STRING([--with-mimedir=DIR],
 +                            [path where mime files get installed (default: $datadir/mime/packages)])],
 +            [MIMEDIR="$withval"],
 +            [MIMEDIR='$(datadir)/mime/packages'])
 +
 +AC_ARG_WITH([gamedatadir],
 +            [AS_HELP_STRING([--with-gamedatadir=DIR],
 +                            [path where game data files get installed (default: $datadir/games/xboard)])],
 +            [GAMEDATADIR="$withval"],
 +            [GAMEDATADIR='$(datadir)/games/xboard'])
 +
 +AC_SUBST(ICONSDIR)
 +AC_SUBST(SVGICONSDIR)
 +AC_SUBST(DESKTOPDIR)
 +AC_SUBST(MIMEDIR)
 +AC_SUBST(GAMEDATADIR)
  
  dnl | check for libraries
  if test x"$with_GTK" = x"yes" ; then
    PKG_CHECK_MODULES([GTK], [ gtk+-2.0 >= 2.16.0 gmodule-2.0 ])
    FRONTEND_CFLAGS=$GTK_CFLAGS
    FRONTEND_LIBS=$GTK_LIBS
 +  with_Xaw="no"
  fi
  
  if test x"$with_GTK" = x"no" ; then
@@@ -248,7 -212,8 +248,7 @@@ f
  
  dnl | make results available in Makefile.am
  AM_CONDITIONAL([withGTK],   [test x"$with_GTK" = x"yes"])
 -AM_CONDITIONAL([withXaw],   [test x"$with_Xaw3d" = x"yes"])
 -AM_CONDITIONAL([withXaw],   [test x"$with_Xaw" = x"yes"])
 +AM_CONDITIONAL([withXaw],   [test x"$with_Xaw3d" = x"yes" || test x"$with_Xaw" = x"yes"])
  
  
  AC_SUBST(FRONTEND_CFLAGS)
@@@ -435,6 -400,29 +435,6 @@@ dnl| add some libs for OS 
    ;;
  esac
  
 -AC_ARG_ENABLE(        [xpm],
 -              [AS_HELP_STRING([--enable-xpm],[libXpm will be used if found (default)])],
 -              [enable_xpm="$enableval"],
 -              [enable_xpm="yes"])
 -
 -if test x"$enable_xpm" != "xno"; then
 -  save_cflags="$CFLAGS"
 -  save_cppflags="$CPPFLAGS"
 -  CFLAGS="$CFLAGS $X_CFLAGS"
 -  CPPFLAGS="$CPPFLAGS $X_CFLAGS"
 -  AC_CHECK_HEADERS(X11/xpm.h)
 -  CFLAGS="$save_cflags"
 -  CPPFLAGS="$save_cppflags"
 -  if test "$ac_cv_header_X11_xpm_h" = "yes"; then
 -    save_ldflags="$LDFLAGS"
 -    LDFLAGS="$LDFLAGS $X_LIBS"
 -    AC_CHECK_LIB(Xpm, XpmReadFileToPixmap,
 -                 [X_PRE_LIBS="-lXpm $X_PRE_LIBS"; AC_DEFINE(HAVE_LIBXPM)], [],
 -                 [$X_PRE_LIBS -lX11 $X_EXTRA_LIBS])
 -    LDFLAGS="$save_ldflags"
 -  fi
 -fi
 -
  AC_SUBST(PRE_XMULIB)
  AC_SUBST(POST_XMULIB)
  AC_SUBST(CONF_CFLAGS)
@@@ -513,17 -501,6 +513,17 @@@ if test x"$enable_mimedb" = "xyes"; the
     AC_SUBST(XDG_ICON_RESOURCE)
  fi
  
 +dnl create a string with configure options that can be passed to the
 +dnl program, good for bug reports and version printout, see output below
 +CONFIGURE_OPTIONS="prefix=$prefix; datarootdir=$datarootdir; \
 +datadir=$datadir; gamedatadir=$GAMEDATADIR; desktopdir=$DESKTOPDIR; \
 +mimedir=$MIMEDIR; iconsdir=$ICONSDIR; svgiconsdir=$SVGICONSDIR; infodir=$infodir; \
 +sysconfigdir=$sysconfigdir; update_mimedb=$enable_mimedb; NLS=$USE_NLS; \
 +GKT=$with_GTK; Xaw3d=$with_Xaw3d; Xaw=$with_Xaw; \
 +ptys=$enable_ptys; zippy=$enable_zippy; sigint=$enable_sigint"
 +
 +AC_SUBST(CONFIGURE_OPTIONS)
 +
  dnl |  output Makefile
  AC_CONFIG_FILES([Makefile cmail po/Makefile.in])
  AC_CONFIG_COMMANDS([test-stamp-h],[test -z "$CONFIG_HEADERS" || date > stamp-h])
@@@ -538,12 -515,8 +538,12 @@@ echo " Configurations summary:
  echo ""
  echo "        prefix:          $prefix       "
  echo "        datarootdir:     $datarootdir  "
 -echo "        datadir:         $datadir   (icons will go in \$datadir/icons/hicolor/...)"
 -echo "                                    (bitmaps will go in \$datadir/games/xboard/...)"
 +echo "        datadir:         $datadir      "
 +echo "        gamedatadir:     $GAMEDATADIR  "
 +echo "        desktopdir:      $DESKTOPDIR   "
 +echo "        mimedir:         $MIMEDIR      "
 +echo "        iconsdir:        $ICONSDIR     "
 +echo "        svgiconsdir:     $SVGICONSDIR  "
  echo "        infodir:         $infodir   (info files will go here)"
  echo "        sysconfdir:      $sysconfdir   (xboard.conf will go here)"
  echo ""
@@@ -555,6 -528,7 +555,6 @@@ echo "        GTK:             $with_GT
  echo "        Xaw3d:           $with_Xaw3d"
  echo "        Xaw:             $with_Xaw"
  echo ""
 -echo "        xpm:             $enable_xpm"
  echo "        ptys:            $enable_ptys"
  echo "        zippy:           $enable_zippy"
  echo "        sigint:          $enable_sigint"
diff --combined dialogs.c
+++ b/dialogs.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * dialogs.c -- platform-independent code for dialogs of XBoard
   *
-  * Copyright 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   * ------------------------------------------------------------------------
   *
   * GNU XBoard is free software: you can redistribute it and/or modify
@@@ -184,14 -184,12 +184,14 @@@ GenericReadout (Option *opts, int selec
                    if(x < opts[i].min) x = opts[i].min;
                    if(opts[i].type == Fractional)
                        *(float*) opts[i].target = x; // engines never have float options!
 -                  else if(opts[i].value != x) {
 -                      opts[i].value = x;
 +                  else {
                        if(currentCps) {
 +                        if(opts[i].value != x) { // only to engine if changed
                            snprintf(buf, MSG_SIZ,  "option %s=%.0f\n", opts[i].name, x);
                            SendToProgram(buf, currentCps);
 +                        }
                        } else *(int*) opts[i].target = x;
 +                      opts[i].value = x;
                    }
                    break;
                case CheckBox:
                case SaveButton:
                case Label:
                case Break:
 +              case -1:
              break;
            }
            if(opts[i].type == EndMark) break;
@@@ -260,9 -257,10 +260,9 @@@ MatchOK (int n
  
  static Option matchOptions[] = {
  { 0,  0,          0, NULL, (void*) &tfName, ".trn", NULL, FileName, N_("Tournament file:          ") },
 +{ 0,  0,          0, NULL, NULL, "", NULL, Label, N_("For concurrent playing of tourney with multiple XBoards:") },
  { 0,  0,          0, NULL, (void*) &appData.roundSync, "", NULL, CheckBox, N_("Sync after round") },
 -{ 0, SAME_ROW|LL, 0, NULL, NULL, "", NULL, Label, N_("    (for concurrent playing of a single") },
  { 0,  0,          0, NULL, (void*) &appData.cycleSync, "", NULL, CheckBox, N_("Sync after cycle") },
 -{ 0, SAME_ROW|LL, 0, NULL, NULL, "", NULL, Label, N_("      tourney with multiple XBoards)") },
  { 0,  LR,       175, NULL, NULL, "", NULL, Label, N_("Tourney participants:") },
  { 0, SAME_ROW|RR, 175, NULL, NULL, "", NULL, Label, N_("Select Engine:") },
  { 150, T_VSCRL | T_FILL | T_WRAP,
@@@ -343,7 -341,7 +343,7 @@@ MatchOptionsProc (
     ASSIGN(tfName, appData.tourneyFile[0] ? appData.tourneyFile : MakeName(appData.defName));
     ASSIGN(engineName, appData.participants);
     ASSIGN(engineMnemonic[0], "");
 -   GenericPopUp(matchOptions, _("Match Options"), TransientDlg, BoardWindow, MODAL, 0);
 +   GenericPopUp(matchOptions, _("Tournament Options"), TransientDlg, BoardWindow, MODAL, 0);
  }
  
  // ------------------------------------------- General Options --------------------------------------------------
@@@ -369,7 -367,6 +369,7 @@@ static Option generalOptions[] = 
  { 0,  0, 0, NULL, (void*) &appData.autoCallFlag, "", NULL, CheckBox, N_("Auto Flag") },
  { 0,  0, 0, NULL, (void*) &appData.autoFlipView, "", NULL, CheckBox, N_("Auto Flip View") },
  { 0,  0, 0, NULL, (void*) &appData.blindfold, "", NULL, CheckBox, N_("Blindfold") },
 +/* TRANSLATORS: the drop menu is used to drop a piece, e.g. during bughouse or editing a position */
  { 0,  0, 0, NULL, (void*) &appData.dropMenu, "", NULL, CheckBox, N_("Drop Menu") },
  { 0,  0, 0, NULL, (void*) &appData.variations, "", NULL, CheckBox, N_("Enable Variation Trees") },
  { 0,  0, 0, NULL, (void*) &appData.hideThinkingFromHuman, "", NULL, CheckBox, N_("Hide Thinking from Human") },
@@@ -408,66 -405,47 +408,66 @@@ OptionsProc (
  static void Pick P((int n));
  
  static char warning[MSG_SIZ];
 +static int ranksTmp, filesTmp, sizeTmp;
  
  static Option variantDescriptors[] = {
 -{ VariantNormal,        0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("normal")},
 -{ VariantMakruk, SAME_ROW, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("makruk")},
 +{ VariantNormal,        0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Normal")},
 +{ VariantMakruk, SAME_ROW, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Makruk")},
  { VariantFischeRandom,  0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("FRC")},
 -{ VariantShatranj,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("shatranj")},
 -{ VariantWildCastle,    0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("wild castle")},
 -{ VariantKnightmate,SAME_ROW,135,NULL,(void*) &Pick, "#FFFFFF", NULL, Button, N_("knightmate")},
 -{ VariantNoCastle,      0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("no castle")},
 -{ VariantCylinder,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("cylinder *")},
 +{ VariantShatranj,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Shatranj")},
 +{ VariantWildCastle,    0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Wild castle")},
 +{ VariantKnightmate,SAME_ROW,135,NULL,(void*) &Pick, "#FFFFFF", NULL, Button, N_("Knightmate")},
 +{ VariantNoCastle,      0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("No castle")},
 +{ VariantCylinder,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Cylinder *")},
  { Variant3Check,        0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("3-checks")},
  { VariantBerolina,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("berolina *")},
  { VariantAtomic,        0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("atomic")},
  { VariantTwoKings,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("two kings")},
 +{ -1,                   0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment
 +{ VariantSpartan,SAME_ROW, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")},
  { 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Board size ( -1 = default for selected variant):")},
 -{ 0, -1, BOARD_RANKS-1, NULL, (void*) &appData.NrRanks, "", NULL, Spin, N_("Number of Board Ranks:") },
 -{ 0, -1, BOARD_FILES, NULL, (void*) &appData.NrFiles, "", NULL, Spin, N_("Number of Board Files:") },
 -{ 0, -1, BOARD_RANKS-1, NULL, (void*) &appData.holdingsSize, "", NULL, Spin, N_("Holdings Size:") },
 +{ 0, -1, BOARD_RANKS-1, NULL, (void*) &ranksTmp, "", NULL, Spin, N_("Number of Board Ranks:") },
 +{ 0, -1, BOARD_FILES,   NULL, (void*) &filesTmp, "", NULL, Spin, N_("Number of Board Files:") },
 +{ 0, -1, BOARD_RANKS-1, NULL, (void*) &sizeTmp,  "", NULL, Spin, N_("Holdings Size:") },
  { 0, 0, 275, NULL, NULL, NULL, NULL, Label, warning },
 -{ 0, 0, 275, NULL, NULL, NULL, NULL, Label, "Variants marked with * can only be played\nwith legality testing off"},
 +{ 0, 0, 275, NULL, NULL, NULL, NULL, Label, N_("Variants marked with * can only be played\nwith legality testing off.")},
  { 0, SAME_ROW, 0, NULL, NULL, NULL, NULL, Break, ""},
 -{ VariantFairy,         0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("fairy")},
 +{ VariantASEAN,         0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("ASEAN")},
  { VariantGreat,  SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Great Shatranj (10x8)")},
  { VariantSChess,        0, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Seirawan")},
 -{ VariantFalcon, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("falcon (10x8)")},
 +{ VariantFalcon, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Falcon (10x8)")},
  { VariantSuper,         0, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Superchess")},
  { VariantCapablanca,SAME_ROW,135,NULL,(void*) &Pick, "#BFBFFF", NULL, Button, N_("Capablanca (10x8)")},
 -{ VariantCrazyhouse,    0, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("crazyhouse")},
 +{ VariantCrazyhouse,    0, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Crazyhouse")},
  { VariantGothic, SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Gothic (10x8)")},
 -{ VariantBughouse,      0, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("bughouse")},
 -{ VariantJanus,  SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("janus (10x8)")},
 -{ VariantSuicide,       0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("suicide")},
 +{ VariantBughouse,      0, 135, NULL, (void*) &Pick, "#FFBFBF", NULL, Button, N_("Bughouse")},
 +{ VariantJanus,  SAME_ROW, 135, NULL, (void*) &Pick, "#BFBFFF", NULL, Button, N_("Janus (10x8)")},
 +{ VariantSuicide,       0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("Suicide")},
  { VariantCapaRandom,SAME_ROW,135,NULL,(void*) &Pick, "#BFBFFF", NULL, Button, N_("CRC (10x8)")},
  { VariantGiveaway,      0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("give-away")},
  { VariantGrand,  SAME_ROW, 135, NULL, (void*) &Pick, "#5070FF", NULL, Button, N_("grand (10x10)")},
  { VariantLosers,        0, 135, NULL, (void*) &Pick, "#FFFFBF", NULL, Button, N_("losers")},
  { VariantShogi,  SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("shogi (9x9)")},
 -{ VariantSpartan,       0, 135, NULL, (void*) &Pick, "#FF0000", NULL, Button, N_("Spartan")},
 +{ VariantFairy,         0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("fairy")},
  { VariantXiangqi, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFFF", NULL, Button, N_("xiangqi (9x10)")},
 -{ -1,                   0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment
 +{ VariantLion,          0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("mighty lion")},
  { VariantCourier, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("courier (12x8)")},
 +{ VariantChuChess,      0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("chu chess (10x10)")},
 +{ VariantChu,    SAME_ROW, 135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("chu shogi (12x12)")},
 +//{ -1,                   0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment
 +// optional buttons for engine-defined variants
 +{ VariantUnknown,       0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown,       0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown,       0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown,       0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown,       0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown,       0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
 +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL },
  { 0, NO_OK, 0, NULL, NULL, "", NULL, EndMark , "" }
  };
  
@@@ -475,29 -453,27 +475,29 @@@ static voi
  Pick (int n)
  {
        VariantClass v = variantDescriptors[n].value;
 +      if(v == VariantUnknown) safeStrCpy(engineVariant, variantDescriptors[n].name, MSG_SIZ); else *engineVariant = NULLCHAR;
 +      GenericReadout(variantDescriptors, -1); // read new ranks and file settings
        if(!appData.noChessProgram) {
 -          char *name = VariantName(v), buf[MSG_SIZ];
 -          if (first.protocolVersion > 1 && StrStr(first.variants, name) == NULL) {
 -              /* [HGM] in protocol 2 we check if variant is suported by engine */
 -            snprintf(buf, MSG_SIZ,  _("Variant %s not supported by %s"), name, first.tidy);
 -              DisplayError(buf, 0);
 +          char buf[MSG_SIZ];
 +          if (!SupportedVariant(first.variants, v, filesTmp, ranksTmp, sizeTmp, first.protocolVersion, first.tidy)) {
 +              DisplayError(variantError, 0);
                return; /* ignore OK if first engine does not support it */
            } else
 -          if (second.initDone && second.protocolVersion > 1 && StrStr(second.variants, name) == NULL) {
 -            snprintf(buf, MSG_SIZ,  _("Warning: second engine (%s) does not support this!"), second.tidy);
 +          if (second.initDone &&
 +              !SupportedVariant(second.variants, v, filesTmp, ranksTmp, sizeTmp, second.protocolVersion, second.tidy)) {
 +                snprintf(buf, MSG_SIZ,  _("Warning: second engine (%s) does not support this!"), second.tidy);
                DisplayError(buf, 0);   /* use of second engine is optional; only warn user */
            }
        }
  
 -      GenericReadout(variantDescriptors, -1); // make sure ranks and file settings are read
 -
        gameInfo.variant = v;
        appData.variant = VariantName(v);
  
        shuffleOpenings = FALSE; /* [HGM] shuffle: possible shuffle reset when we switch */
        startedFromPositionFile = FALSE; /* [HGM] loadPos: no longer valid in new variant */
 +      appData.NrRanks = ranksTmp;
 +      appData.NrFiles = filesTmp;
 +      appData.holdingsSize = sizeTmp;
        appData.pieceToCharTable = NULL;
        appData.pieceNickNames = "";
        appData.colorNickNames = "";
  void
  NewVariantProc ()
  {
 -   if(appData.noChessProgram) sprintf(warning, _("Only bughouse is not available in viewer mode")); else
 -   sprintf(warning, _("All variants not supported by first engine\n(currently %s) are disabled"), first.tidy);
 +   static int start;
 +   int i, last;
 +   char buf[MSG_SIZ];
 +   ranksTmp = filesTmp = sizeTmp = -1; // prefer defaults over actual settings
 +   if(appData.noChessProgram) sprintf(warning, _("Only bughouse is not available in viewer mode.")); else
 +   sprintf(warning, _("All variants not supported by the first engine\n(currently %s) are disabled."), first.tidy);
 +   if(!start) while(variantDescriptors[start].type != -1) start++; // locate first spare
 +   last = -1;
 +   for(i=0; variantDescriptors[start+i].type != EndMark; i++) { // create buttons for engine-defined variants
 +     char *v = EngineDefinedVariant(&first, i);
 +     if(v) {
 +      last =  i;
 +      ASSIGN(variantDescriptors[start+i].name, v);
 +      variantDescriptors[start+i].type = Button;
 +     } else variantDescriptors[start+i].type = -1;
 +   }
 +   if(!(last&1)) { // odd number, add filler
 +      ASSIGN(variantDescriptors[start+last+1].name, " ");
 +      variantDescriptors[start+last+1].type = Button;
 +      variantDescriptors[start+last+1].value = -1;
 +   }
 +   safeStrCpy(buf, engineVariant, MSG_SIZ); *engineVariant = NULLCHAR; // yeghh...
     GenericPopUp(variantDescriptors, _("New Variant"), TransientDlg, BoardWindow, MODAL, 0);
 +   safeStrCpy(engineVariant, buf, MSG_SIZ); // must temporarily clear to avoid enabling all variant buttons
  }
  
  //------------------------------------------- Common Engine Options -------------------------------------
@@@ -623,7 -578,6 +623,7 @@@ Option icsOptions[] = 
  { 0, 0, 0, NULL, (void*) &appData.seekGraph, "",   NULL, CheckBox, N_("Seek Graph") },
  { 0, 0, 0, NULL, (void*) &appData.autoRefresh, "", NULL, CheckBox, N_("Auto-Refresh Seek Graph") },
  { 0, 0, 0, NULL, (void*) &appData.autoBox, "", NULL, CheckBox, N_("Auto-InputBox PopUp") },
 +{ 0, 0, 0, NULL, (void*) &appData.quitNext, "", NULL, CheckBox, N_("Quit after game") },
  { 0, 0, 0, NULL, (void*) &appData.premove, "",     NULL, CheckBox, N_("Premove") },
  { 0, 0, 0, NULL, (void*) &appData.premoveWhite, "", NULL, CheckBox, N_("Premove for White") },
  { 0, 0, 0, NULL, (void*) &appData.premoveWhiteText, "", NULL, TextBox, N_("First White Move:") },
@@@ -735,7 -689,6 +735,7 @@@ static char *soundNames[] = 
        N_("Penalty"),
        N_("Phone"),
        N_("Pop"),
 +      N_("Roar"),
        N_("Slap"),
        N_("Wood Thunk"),
        NULL,
@@@ -754,7 -707,6 +754,7 @@@ static char *soundFiles[] = { // sound 
        "penalty.wav",
        "phone.wav",
        "pop2.wav",
 +      "roar.wav",
        "slap.wav",
        "woodthunk.wav",
        NULL,
@@@ -782,7 -734,6 +782,7 @@@ static Option soundOptions[] = 
  { 0, 0, 0, NULL, (void*) &appData.soundTell, (char*) soundFiles, soundNames, ComboBox, N_("Tell:") },
  { 0, 0, 0, NULL, (void*) &appData.soundKibitz, (char*) soundFiles, soundNames, ComboBox, N_("Kibitz:") },
  { 0, 0, 0, NULL, (void*) &appData.soundRequest, (char*) soundFiles, soundNames, ComboBox, N_("Request:") },
 +{ 0, 0, 0, NULL, (void*) &appData.soundRoar, (char*) soundFiles, soundNames, ComboBox, N_("Lion roar:") },
  { 0, 0, 0, NULL, (void*) &appData.soundSeek, (char*) soundFiles, soundNames, ComboBox, N_("Seek:") },
  { 0, SAME_ROW, 0, NULL, NULL, "", NULL, EndMark , "" }
  };
@@@ -863,7 -814,7 +863,7 @@@ static Option boardOptions[] = 
  { 0, 0, 0, NULL, (void*) &appData.upsideDown, "", NULL, CheckBox, N_("Flip Pieces Shogi Style        (Colored buttons restore default)") },
  //{ 0, 0, 0, NULL, (void*) &appData.allWhite, "", NULL, CheckBox, N_("Use Outline Pieces for Black") },
  { 0, 0, 0, NULL, (void*) &appData.monoMode, "", NULL, CheckBox, N_("Mono Mode") },
 -{ 0,-1, 5, NULL, (void*) &appData.overrideLineGap, "", NULL, Spin, N_("Line Gap ( -1 = default for board size):") },
 +{ 0,-1, 5, NULL, (void*) &appData.overrideLineGap, "", NULL, Spin, N_("Line Gap (-1 = default for board size):") },
  { 0, 0, 0, NULL, (void*) &appData.useBitmaps, "", NULL, CheckBox, N_("Use Board Textures") },
  { 0, 0, 0, NULL, (void*) &appData.liteBackTextureFile, ".png", NULL, FileName, N_("Light-Squares Texture File:") },
  { 0, 0, 0, NULL, (void*) &appData.darkBackTextureFile, ".png", NULL, FileName, N_("Dark-Squares Texture File:") },
@@@ -1075,7 -1026,7 +1075,7 @@@ static char *tagsText
  static int
  NewTagsCallback (int n)
  {
 -    ReplaceTags(tagsText, &gameInfo);
 +    if(!bookUp) ReplaceTags(tagsText, &gameInfo);
      return 1;
  }
  
@@@ -1090,7 -1041,7 +1090,7 @@@ static voi
  changeTags (int n)
  {
      GenericReadout(tagsOptions, 1);
 -    if(bookUp) SaveToBook(tagsText); else
 +    if(bookUp) SaveToBook(tagsText), DisplayBook(currentMove); else
      ReplaceTags(tagsText, &gameInfo);
  }
  
@@@ -1416,7 -1367,7 +1416,7 @@@ ShuffleOK (int n
  }
  
  static Option shuffleOptions[] = {
-   {   0,  0,   50, NULL, (void*) &shuffleOpenings, NULL, NULL, CheckBox, N_("shuffle") },
+   {   0,  0,    0, NULL, (void*) &shuffleOpenings, NULL, NULL, CheckBox, N_("shuffle") },
    { 0,-1,2000000000, NULL, (void*) &appData.defaultFrcPosition, "", NULL, Spin, N_("Start-position number:") },
    {   0,  0,    0, NULL, (void*) &SetRandom, NULL, NULL, Button, N_("randomize") },
    {   0,  SAME_ROW,    0, NULL, (void*) &SetRandom, NULL, NULL, Button, N_("pick fixed") },
@@@ -1601,7 -1552,6 +1601,7 @@@ PromoPick (int n
        ClearHighlights();
        return;
      }
 +    if(promoChar == '=' && !IS_SHOGI(gameInfo.variant)) promoChar = NULLCHAR;
      UserMoveEvent(fromX, fromY, toX, toY, promoChar);
  
      if (!appData.highlightLastMove || gotPremove) ClearHighlights();
@@@ -1618,11 -1568,11 +1618,11 @@@ SetPromo (char *name, int nr, char prom
  }
  
  void
 -PromotionPopUp ()
 +PromotionPopUp (char choice)
  { // choice depends on variant: prepare dialog acordingly
    count = 8;
 -  SetPromo(_("Cancel"), --count, 0); // Beware: GenericPopUp cannot handle user buttons named "cancel" (lowe case)!
 -  if(gameInfo.variant != VariantShogi) {
 +  SetPromo(_("Cancel"), --count, -1); // Beware: GenericPopUp cannot handle user buttons named "cancel" (lowe case)!
 +  if(choice != '+') {
      if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
          gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
          gameInfo.variant == VariantGiveaway) {
          SetPromo(_("Chancellor"), --count, 'c');
        }
        SetPromo(_("Queen"), --count, 'q');
 +      if(gameInfo.variant == VariantChuChess)
 +        SetPromo(_("Lion"), --count, 'l');
      }
    } else // [HGM] shogi
    {
@@@ -2188,17 -2136,12 +2188,17 @@@ static Option 
  Exp (int n, int x, int y)
  {
      static int but1, but3, oldW, oldH;
 -    int menuNr = -3, sizing;
 +    int menuNr = -3, sizing, f, r;
  
      if(n == 0) { // motion
        if(SeekGraphClick(Press, x, y, 1)) return NULL;
 -      if(but1 && !PromoScroll(x, y)) DragPieceMove(x, y);
 +      if((but1 || dragging == 2) && !PromoScroll(x, y)) DragPieceMove(x, y);
        if(but3) MovePV(x, y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
 +      if(appData.highlightDragging) {
 +          f = EventToSquare(x, BOARD_WIDTH);  if ( flipView && f >= 0) f = BOARD_WIDTH - 1 - f;
 +          r = EventToSquare(y, BOARD_HEIGHT); if (!flipView && r >= 0) r = BOARD_HEIGHT - 1 - r;
 +          HoverEvent(x, y, f, r);
 +      }
        return NULL;
      }
      if(n != 10 && PopDown(PromoDlg)) fromX = fromY = -1; // user starts fiddling with board when promotion dialog is up
@@@ -2396,6 -2339,7 +2396,6 @@@ static char *Extensions[] = 
  ".trn",
  ".bin",
  ".wav",
 -".xpm",
  ".ini",
  ".log",
  "",
@@@ -2543,13 -2487,17 +2543,17 @@@ Refresh (int pathFlag
      SetWidgetLabel(&browseOptions[0], title);
  }
  
+ static char msg1[] = N_("FIRST TYPE DIRECTORY NAME HERE");
+ static char msg2[] = N_("TRY ANOTHER NAME");
  void
  CreateDir (int n)
  {
      char *name, *errmsg = "";
      GetWidgetText(&browseOptions[n-1], &name);
-     if(!name[0]) errmsg = _("FIRST TYPE DIRECTORY NAME HERE"); else
-     if(mkdir(name, 0755)) errmsg = _("TRY ANOTHER NAME");
+     if(!strcmp(name, msg1) || !strcmp(name, msg2)) return;
+     if(!name[0]) errmsg = _(msg1); else
+     if(mkdir(name, 0755)) errmsg = _(msg2);
      else {
        chdir(name);
        Refresh(-1);
diff --combined draw.c
--- 1/draw.c
--- 2/draw.c
+++ b/draw.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -140,12 -140,11 +140,12 @@@ SelectPieces(VariantClass v
        for(p=0; p<=(int)WhiteKing; p++)
           pngPieceBitmaps[i][p] = pngPieceBitmaps2[i][p]; // defaults
        if(v == VariantShogi) {
 -         pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteKing+1];
 +         pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteTokin];
           pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteKing+2];
 -         pngPieceBitmaps[i][(int)WhiteSilver] = pngPieceBitmaps2[i][(int)WhiteKing+3];
 -         pngPieceBitmaps[i][(int)WhiteGrasshopper] = pngPieceBitmaps2[i][(int)WhiteKing+4];
 +         pngPieceBitmaps[i][(int)WhiteGrasshopper] = pngPieceBitmaps2[i][(int)WhiteKing+3];
 +         pngPieceBitmaps[i][(int)WhiteSilver] = pngPieceBitmaps2[i][(int)WhiteKing+4];
           pngPieceBitmaps[i][(int)WhiteQueen] = pngPieceBitmaps2[i][(int)WhiteLance];
 +         pngPieceBitmaps[i][(int)WhiteFalcon] = pngPieceBitmaps2[i][(int)WhiteMonarch]; // for Sho Shogi
        }
  #ifdef GOTHIC
        if(v == VariantGothic) {
           pngPieceBitmaps[i][(int)WhiteAngel]    = pngPieceBitmaps2[i][(int)WhiteFalcon];
           pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteAlfil];
        }
 +      if(v == VariantChuChess) {
 +         pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteLion];
 +      }
 +      if(v == VariantChu) {
 +         pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteKing+1];
 +         pngPieceBitmaps[i][(int)WhiteUnicorn] = pngPieceBitmaps2[i][(int)WhiteCat];
 +         pngPieceBitmaps[i][(int)WhiteSilver]  = pngPieceBitmaps2[i][(int)WhiteSword];
 +         pngPieceBitmaps[i][(int)WhiteFalcon]  = pngPieceBitmaps2[i][(int)WhiteDagger];
 +      }
      }
  }
  
@@@ -238,16 -228,12 +238,16 @@@ CreatePNGBoard (char *s, int kind
  
  char *pngPieceNames[] = // must be in same order as internal piece encoding
  { "Pawn", "Knight", "Bishop", "Rook", "Queen", "Advisor", "Elephant", "Archbishop", "Marshall", "Gold", "Commoner",
 -  "Canon", "Nightrider", "CrownedBishop", "CrownedRook", "Princess", "Chancellor", "Hawk", "Lance", "Cobra", "Unicorn", "King",
 -  "GoldKnight", "GoldLance", "GoldPawn", "GoldSilver", NULL
 +  "Canon", "Nightrider", "CrownedBishop", "CrownedRook", "Princess", "Chancellor", "Hawk", "Lance", "Cobra", "Unicorn", "Lion",
 +  "GoldPawn", "HSword", "PromoHorse", "PromoDragon", "Leopard", "PromoSword", "Prince", "Phoenix", "Kylin", "PromoRook", "PromoHSword",
 +  "Dolphin", "Chancellor", "Unicorn", "Hawk", "Sword", "Princess", "HCrown", "Knight", "Elephant", "PromoBishop", "King",
 +  "Claw", "GoldKnight", "GoldLance", "GoldSilver", NULL
  };
  
 +char *backupPiece[] = { "King", "Queen", "Lion" }; // pieces that map on other when not kanji
 +
  RsvgHandle *
 -LoadSVG (char *dir, int color, int piece)
 +LoadSVG (char *dir, int color, int piece, int retry)
  {
      char buf[MSG_SIZ];
    RsvgHandle *svg=svgPieces[color][piece];
    cairo_surface_t *img;
    cairo_t *cr;
  
 -    snprintf(buf, MSG_SIZ, "%s/%s%s.svg", dir, color ? "Black" : "White", pngPieceNames[piece]);
 +    snprintf(buf, MSG_SIZ, "%s/%s%s.svg", dir, color ? "Black" : "White",
 +             retry ? backupPiece[piece - WhiteMonarch] : pngPieceNames[piece]);
  
      if(svg || *dir && (svg = rsvg_handle_new_from_file(buf, &svgerror))) {
  
  
        return svg;
      }
 +    if(!retry && piece >= WhiteMonarch && piece <= WhiteNothing) // pieces that are only different in kanji sets
 +        return LoadSVG(dir, color, piece, 1);
      if(svgerror)
        g_error_free(svgerror);
      return NULL;
@@@ -292,22 -275,22 +292,22 @@@ ScaleOnePiece (int color, int piece
  
    g_type_init ();
  
 -  svgPieces[color][piece] = LoadSVG("", color, piece); // this fills pngPieceImages if we had cached svg with bitmap of wanted size
 +  svgPieces[color][piece] = LoadSVG("", color, piece, 0); // this fills pngPieceImages if we had cached svg with bitmap of wanted size
  
    if(!pngPieceImages[color][piece]) { // we don't have cached bitmap (implying we did not have cached svg)
      if(*appData.pieceDirectory) { // user specified piece directory
        snprintf(buf, MSG_SIZ, "%s/%s%s.png", appData.pieceDirectory, color ? "Black" : "White", pngPieceNames[piece]);
        img = cairo_image_surface_create_from_png (buf); // try if there are png pieces there
        if(cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) { // there were not
 -      svgPieces[color][piece] = LoadSVG(appData.pieceDirectory, color, piece); // so try if he has svg there
 +      svgPieces[color][piece] = LoadSVG(appData.pieceDirectory, color, piece, 0); // so try if he has svg there
        } else pngPieceImages[color][piece] = img;
      }
    }
  
    if(!pngPieceImages[color][piece]) { // we still did not manage to acquire a piece bitmap
      static int warned = 0;
 -    if(!(svgPieces[color][piece] = LoadSVG(SVGDIR, color, piece)) && !warned) { // try to fall back on installed svg
 -      char *msg = _("No default pieces installed\nSelect your own -pieceImageDirectory");
 +    if(!(svgPieces[color][piece] = LoadSVG(SVGDIR, color, piece, 0)) && !warned) { // try to fall back on installed svg 
 +      char *msg = _("No default pieces installed!\nSelect your own using '-pieceImageDirectory'.");
        printf("%s\n", msg); // give up
        DisplayError(msg, 0);
        warned = 1; // prevent error message being repeated for each piece type
@@@ -658,8 -641,6 +658,8 @@@ pngDrawPiece (cairo_surface_t *dest, Ch
      cairo_destroy (cr);
  }
  
 +static char *markerColor[8] = { "#FFFF00", "#FF0000", "#00FF00", "#0000FF", "#00FFFF", "#FF00FF", "#FFFFFF", "#000000" };
 +
  void
  DoDrawDot (cairo_surface_t *cs, int marker, int x, int y, int r)
  {
            cairo_stroke_preserve(cr);
            SetPen(cr, 2, marker == 2 ? "#FFFFFF" : "#000000", 0);
        } else {
 -          SetPen(cr, 2, marker == 2 ? "#FF0000" : "#FFFF00", 0);
 +          SetPen(cr, 2, markerColor[marker-1], 0);
        }
        cairo_fill(cr);
  
diff --combined frontend.h
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
@@@ -93,14 -93,13 +93,14 @@@ void DrawSeekDot P((int x, int y, int c
  void PopUpMoveDialog P((char first));
  
  void RingBell P((void));
 +int  Roar P((void));
  void PlayIcsWinSound P((void));
  void PlayIcsLossSound P((void));
  void PlayIcsDrawSound P((void));
  void PlayIcsUnfinishedSound P((void));
  void PlayAlarmSound P((void));
  void PlayTellSound P((void));
 -void PlaySoundFile P((char *name));
 +int  PlaySoundFile P((char *name));
  void PlaySoundByColor P((void));
  void EchoOn P((void));
  void EchoOff P((void));
@@@ -129,7 -128,7 +129,7 @@@ DelayedEventCallback GetDelayedEvent P(
  void CancelDelayedEvent P((void));
  // [HGM] mouse: next six used by mouse handler, which was moved to backend
  extern int fromX, fromY, toX, toY;
 -void PromotionPopUp P((void));
 +void PromotionPopUp P((char choice));
  void DragPieceBegin P((int x, int y, Boolean instantly));
  void DragPieceEnd P((int x, int y));
  void DragPieceMove P((int x, int y));
@@@ -216,7 -215,7 +216,7 @@@ void EnableNamedMenuItem P((char *menuR
  typedef struct FrontEndProgramStats_TAG {
      int which;
      int depth;
-     unsigned long nodes;
+     u64 nodes;
      int score;
      int time;
      char * pv;
diff --combined gamelist.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * gamelist.c -- Functions to manage a gamelist
   *
-  * Copyright 1995, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Copyright 1995, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
@@@ -305,7 -305,7 +305,7 @@@ GameListBuild (FILE *f
            } while (cm == PGNTag || cm == Comment);
            if(1) {
                int btm=0;
 -              if(currentListGame->gameInfo.fen) ParseFEN(boards[scratch], &btm, currentListGame->gameInfo.fen);
 +              if(currentListGame->gameInfo.fen) ParseFEN(boards[scratch], &btm, currentListGame->gameInfo.fen, FALSE);
                else CopyBoard(boards[scratch], initialPosition);
                plyNr = (btm != 0);
                currentListGame->moves = PackGame(boards[scratch]);
diff --combined gtk/xboard.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -167,21 -167,21 +167,22 @@@ extern char *getenv()
  #include "gettext.h"
  #include "draw.h"
  
- #ifdef OSX
- #  include "gtkmacintegration/gtkosxapplication.h"
+ #ifdef __APPLE__
+ #  include <gtkmacintegration/gtkosxapplication.h>
     // prevent pathname of positional file argument provided by OS X being be mistaken for option name
     // (price is that we won't recognize Windows option format anymore).
  #  define SLASH '-'
     // redefine some defaults
  #  undef ICS_LOGON
  #  undef SYSCONFDIR
 +#  undef DATADIR
  #  define ICS_LOGON "Library/Preferences/XboardICS.conf"
  #  define SYSCONFDIR "../etc"
  #  define DATADIR dataDir
     char *dataDir; // for expanding ~~
  #else
  #  define SLASH '/'
+ #  define DATADIR "~~"
  #endif
  
  #ifdef __EMX__
@@@ -679,7 -679,6 +680,7 @@@ PrintArg (ArgType t
      case ArgTwo:
      case ArgNone:
      case ArgCommSettings:
 +    default:
        break;
    }
    return p;
@@@ -729,7 -728,7 +730,7 @@@ SlaveResize (Option *opt
    gtk_window_resize(GTK_WINDOW(shells[DummyDlg]), slaveW + opt->max, slaveH + opt->value);
  }
  
- #ifdef OSX
+ #ifdef __APPLE__
  static char clickedFile[MSG_SIZ];
  static int suppress;
  
@@@ -762,7 -761,7 +763,7 @@@ main (int argc, char **argv
      debugFP = stderr;
  
      if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
 -      printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
 +        printf("%s version %s\n\n  configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
        exit(0);
      }
  
  
      /* set up GTK */
      gtk_init (&argc, &argv);
- #ifdef OSX
+ #ifdef __APPLE__
      {   // prepare to catch OX OpenFile signal, which will tell us the clicked file
        GtkosxApplication *theApp = g_object_new(GTKOSX_TYPE_APPLICATION, NULL);
        dataDir = gtkosx_application_get_bundle_path();
@@@ -1786,7 -1785,7 +1787,7 @@@ TempForwardProc (Widget w, XEvent *even
  void
  ManProc ()
  {   // called from menu
- #ifdef OSX
+ #ifdef __APPLE__
      system("%s ./man.command", appData.sysOpen);
  #else
      system("xterm -e man xboard &");
diff --combined gtk/xoptions.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * xoptions.c -- Move list window, part of X front end for XBoard
   *
-  * Copyright 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   * ------------------------------------------------------------------------
   *
   * GNU XBoard is free software: you can redistribute it and/or modify
@@@ -51,8 -51,8 +51,8 @@@ extern char *getenv()
  #include <cairo/cairo-xlib.h>
  #include <gtk/gtk.h>
  #include <gdk/gdkkeysyms.h>
- #ifdef OSX
- #  include "gtkmacintegration/gtkosxapplication.h"
+ #ifdef __APPLE__
+ #  include <gtkmacintegration/gtkosxapplication.h>
  #endif
  
  #include "common.h"
@@@ -428,7 -428,7 +428,7 @@@ CreateMenuPopup (Option *opt, int n, in
        {
        char *msg = mb[i].string;
        if(!msg) break;
- #ifdef OSX
+ #ifdef __APPLE__
        if(!strcmp(msg, "Quit ")) continue;             // Quit item will appear automatically in App menu
        if(!strcmp(msg, "About XBoard")) msg = "About"; // 'XBoard' will be appended automatically when moved to App menu 1st item
  #endif
            GdkModifierType accelerator_mods;
  
            gtk_accelerator_parse(mb[i].accel, &accelerator_key, &accelerator_mods);
- #ifdef OSX
+ #ifdef __APPLE__
            if(accelerator_mods & GDK_CONTROL_MASK) {  // in OSX use Meta where Linux uses Ctrl
                accelerator_mods &= ~GDK_CONTROL_MASK; // clear Ctrl flag
                accelerator_mods |= GDK_META_MASK;     // set Meta flag
--          } 
++          }
  #endif
            gtk_widget_add_accelerator (GTK_WIDGET(entry), "activate",GtkAccelerators,
                                        accelerator_key, accelerator_mods, GTK_ACCEL_VISIBLE);
@@@ -1498,7 -1498,7 +1498,7 @@@ if(appData.debugMode) printf("n=%d, h=%
            break;
          case BarEnd:
            top--;
- #ifndef OSX
+ #ifndef __APPLE__
              gtk_table_attach(GTK_TABLE(table), menuBar, left, left+r, top, top+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 1);
  
            if(option[i].target) ((ButtonCallback*)option[i].target)(boxStart); // callback that can make sizing decisions
                gtkosx_application_set_menu_bar(theApp, GTK_MENU_SHELL(menuBar));
                gtkosx_application_insert_app_menu_item(theApp, GTK_MENU_ITEM(helpMenu[8].handle), 0); // hack
                gtkosx_application_sync_menubar(theApp);
--          } 
++          }
  #endif
            break;
          case BoxEnd:
diff --combined menus.c
+++ b/menus.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -215,7 -215,7 +215,7 @@@ CopyPositionProc (
      static char *selected_fen_position=NULL;
      if(gameMode == EditPosition) EditPositionDone(TRUE);
      if (selected_fen_position) free(selected_fen_position);
 -    selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
 +    selected_fen_position = (char *)PositionToFEN(currentMove, NULL, 1);
      if (!selected_fen_position) return;
      CopySomething(selected_fen_position);
  }
@@@ -580,8 -580,8 +580,8 @@@ CreateBookDelayed (
  
  MenuItem fileMenu[] = {
    {N_("New Game"),             "<Ctrl>n",          "NewGame",              ResetGameEvent},
 -  {N_("New Shuffle Game ..."),  NULL,              "NewShuffleGame",       ShuffleMenuProc},
 -  {N_("New Variant ..."),      "<Alt><Shift>v",    "NewVariant",           NewVariantProc},// [HGM] variant: not functional yet
 +  {N_("New Shuffle Game..."),   NULL,              "NewShuffleGame",       ShuffleMenuProc},
 +  {N_("New Variant..."),       "<Alt><Shift>v",    "NewVariant",           NewVariantProc},// [HGM] variant: not functional yet
    {"----",                      NULL,               NULL,                  NothingProc},
    {N_("Load Game"),            "<Ctrl>o",          "LoadGame",             LoadGameProc,           CHECK},
    {N_("Load Position"),        "<Ctrl><Shift>o",   "LoadPosition",         LoadPositionProc},
@@@ -681,11 -681,11 +681,11 @@@ MenuItem actionMenu[] = 
  };
  
  MenuItem engineMenu[100] = {
 -  {N_("Load New 1st Engine ..."),  NULL,     "LoadNew1stEngine", LoadEngine1Proc},
 -  {N_("Load New 2nd Engine ..."),  NULL,     "LoadNew2ndEngine", LoadEngine2Proc},
 +  {N_("Load New 1st Engine..."),   NULL,     "LoadNew1stEngine", LoadEngine1Proc},
 +  {N_("Load New 2nd Engine..."),   NULL,     "LoadNew2ndEngine", LoadEngine2Proc},
    {"----",                         NULL,      NULL,              NothingProc},
 -  {N_("Engine #1 Settings ..."),   NULL,     "Engine#1Settings", FirstSettingsProc},
 -  {N_("Engine #2 Settings ..."),   NULL,     "Engine#2Settings", SecondSettingsProc},
 +  {N_("Engine #1 Settings..."),    NULL,     "Engine#1Settings", FirstSettingsProc},
 +  {N_("Engine #2 Settings..."),    NULL,     "Engine#2Settings", SecondSettingsProc},
    {"----",                         NULL,      NULL,              NothingProc},
    {N_("Hint"),                     NULL,     "Hint",             HintEvent},
    {N_("Book"),                     NULL,     "Book",             BookEvent},
  
  MenuItem optionsMenu[] = {
  #ifdef OPTIONSDIALOG
 -  {N_("General ..."),             NULL,             "General",             OptionsProc},
 +  {N_("General..."),              NULL,             "General",             OptionsProc},
  #endif
 -  {N_("Time Control ..."),       "<Alt><Shift>t",   "TimeControl",         TimeControlProc},
 -  {N_("Common Engine ..."),      "<Alt><Shift>u",   "CommonEngine",        UciMenuProc},
 -  {N_("Adjudications ..."),      "<Alt><Shift>j",   "Adjudications",       EngineMenuProc},
 -  {N_("ICS ..."),                 NULL,             "ICS",                 IcsOptionsProc},
 -  {N_("Match ..."),               NULL,             "Match",               MatchOptionsProc},
 -  {N_("Load Game ..."),           NULL,             "LoadGame",            LoadOptionsProc},
 -  {N_("Save Game ..."),           NULL,             "SaveGame",            SaveOptionsProc},
 -  {N_("Game List ..."),           NULL,             "GameList",            GameListOptionsProc},
 -  {N_("Sounds ..."),              NULL,             "Sounds",              SoundOptionsProc},
 +  {N_("Time Control..."),        "<Alt><Shift>t",   "TimeControl",         TimeControlProc},
 +  {N_("Common Engine..."),       "<Alt><Shift>u",   "CommonEngine",        UciMenuProc},
 +  {N_("Adjudications..."),       "<Alt><Shift>j",   "Adjudications",       EngineMenuProc},
 +  {N_("ICS..."),                  NULL,             "ICS",                 IcsOptionsProc},
 +  {N_("Tournament..."),           NULL,             "Match",               MatchOptionsProc},
 +  {N_("Load Game..."),            NULL,             "LoadGame",            LoadOptionsProc},
 +  {N_("Save Game..."),            NULL,             "SaveGame",            SaveOptionsProc},
 +  {N_("Game List..."),            NULL,             "GameList",            GameListOptionsProc},
 +  {N_("Sounds..."),               NULL,             "Sounds",              SoundOptionsProc},
    {"----",                        NULL,              NULL,                 NothingProc},
  #ifndef OPTIONSDIALOG
    {N_("Always Queen"),           "<Ctrl><Shift>q",  "AlwaysQueen",         AlwaysQueenProc},
diff --combined moves.c
+++ b/moves.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
@@@ -98,7 -98,7 +98,7 @@@ SameColor (ChessSquare piece1, ChessSqu
              (int) piece2 <  (int) EmptySquare);
  }
  #else
 -#define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn))
 +#define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn) || piece1 == DarkSquare || piece2 == DarkSquare)
  #endif
  
  char pieceToChar[] = {
@@@ -165,207 -165,6 +165,207 @@@ CompareBoards (Board board1, Board boar
      return TRUE;
  }
  
 +// [HGM] move generation now based on hierarchy of subroutines for rays and combinations of rays
 +
 +void
 +SlideForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int i, rt, ft = ff;
 +  for (i = 1;; i++) {
 +      rt = rf + i;
 +      if (rt >= BOARD_HEIGHT) break;
 +      if (SameColor(board[rf][ff], board[rt][ft])) break;
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +      if (board[rt][ft] != EmptySquare) break;
 +  }
 +}
 +
 +void
 +SlideBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int i, rt, ft = ff;
 +  for (i = 1;; i++) {
 +      rt = rf - i;
 +      if (rt < 0) break;
 +      if (SameColor(board[rf][ff], board[rt][ft])) break;
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +      if (board[rt][ft] != EmptySquare) break;
 +  }
 +}
 +
 +void
 +SlideVertical (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  SlideForward(board, flags, rf, ff, callback, closure);
 +  SlideBackward(board, flags, rf, ff, callback, closure);
 +}
 +
 +void
 +SlideSideways (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int i, s, rt = rf, ft;
 +  for(s = -1; s <= 1; s+= 2) {
 +    for (i = 1;; i++) {
 +      ft = ff + i*s;
 +      if (ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 +      if (SameColor(board[rf][ff], board[rt][ft])) break;
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +      if (board[rt][ft] != EmptySquare) break;
 +    }
 +  }
 +}
 +
 +void
 +SlideDiagForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int i, s, rt, ft;
 +  for(s = -1; s <= 1; s+= 2) {
 +    for (i = 1;; i++) {
 +      rt = rf + i;
 +      ft = ff + i * s;
 +      if (rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 +      if (SameColor(board[rf][ff], board[rt][ft])) break;
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +      if (board[rt][ft] != EmptySquare) break;
 +    }
 +  }
 +}
 +
 +void
 +SlideDiagBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int i, s, rt, ft;
 +  for(s = -1; s <= 1; s+= 2) {
 +    for (i = 1;; i++) {
 +      rt = rf - i;
 +      ft = ff + i * s;
 +      if (rt < 0 || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 +      if (SameColor(board[rf][ff], board[rt][ft])) break;
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +      if (board[rt][ft] != EmptySquare) break;
 +    }
 +  }
 +}
 +
 +void
 +Rook (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  SlideVertical(board, flags, rf, ff, callback, closure);
 +  SlideSideways(board, flags, rf, ff, callback, closure);
 +}
 +
 +void
 +Bishop (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  SlideDiagForward(board, flags, rf, ff, callback, closure);
 +  SlideDiagBackward(board, flags, rf, ff, callback, closure);
 +}
 +
 +void
 +Sting (Board board, int flags, int rf, int ff, int dy, int dx, MoveCallback callback, VOIDSTAR closure)
 +{ // Lion-like move of Horned Falcon and Souring Eagle
 +  int ft = ff + dx, rt = rf + dy;
 +  if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return;
 +  if (!SameColor(board[rf][ff], board[rt][ft]))
 +    callback(board, flags, board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, rf, ff, rt, ft, closure);
 +  ft += dx; rt += dy;
 +  if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return;
 +  if (!SameColor(board[rf][ff], board[rt][ft]))
 +    callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +}
 +
 +void
 +StepForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int ft = ff, rt = rf + 1;
 +  if (rt >= BOARD_HEIGHT) return;
 +  if (SameColor(board[rf][ff], board[rt][ft])) return;
 +  callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +}
 +
 +void
 +StepBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int ft = ff, rt = rf - 1;
 +  if (rt < 0) return;
 +  if (SameColor(board[rf][ff], board[rt][ft])) return;
 +  callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +}
 +
 +void
 +StepSideways (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int ft, rt = rf;
 +  ft = ff + 1;
 +  if (!(rt >= BOARD_HEIGHT || ft >= BOARD_RGHT) && !SameColor(board[rf][ff], board[rt][ft]))
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +  ft = ff - 1;
 +  if (!(rt >= BOARD_HEIGHT || ft < BOARD_LEFT) && !SameColor(board[rf][ff], board[rt][ft]))
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +}
 +
 +void
 +StepDiagForward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int ft, rt = rf + 1;
 +  if (rt >= BOARD_HEIGHT) return;
 +  ft = ff + 1;
 +  if (!(rt >= BOARD_HEIGHT || ft >= BOARD_RGHT) && !SameColor(board[rf][ff], board[rt][ft]))
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +  ft = ff - 1;
 +  if (!(rt >= BOARD_HEIGHT || ft < BOARD_LEFT) && !SameColor(board[rf][ff], board[rt][ft]))
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +}
 +
 +void
 +StepDiagBackward (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  int ft, rt = rf - 1;
 +  if(rt < 0) return;
 +  ft = ff + 1;
 +  if (!(rt < 0 || ft >= BOARD_RGHT) && !SameColor(board[rf][ff], board[rt][ft]))
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +  ft = ff - 1;
 +  if (!(rt < 0 || ft < BOARD_LEFT) && !SameColor(board[rf][ff], board[rt][ft]))
 +      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +}
 +
 +void
 +StepVertical (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  StepForward(board, flags, rf, ff, callback, closure);
 +  StepBackward(board, flags, rf, ff, callback, closure);
 +}
 +
 +void
 +Ferz (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  StepDiagForward(board, flags, rf, ff, callback, closure);
 +  StepDiagBackward(board, flags, rf, ff, callback, closure);
 +}
 +
 +void
 +Wazir (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +  StepVertical(board, flags, rf, ff, callback, closure);
 +  StepSideways(board, flags, rf, ff, callback, closure);
 +}
 +
 +void
 +Knight (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR closure)
 +{
 +    int i, j, s, rt, ft;
 +    for (i = -1; i <= 1; i += 2)
 +      for (j = -1; j <= 1; j += 2)
 +          for (s = 1; s <= 2; s++) {
 +              rt = rf + i*s;
 +              ft = ff + j*(3-s);
 +              if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
 +                  && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)
 +                  && !SameColor(board[rf][ff], board[rt][ft]))
 +                  callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +          }
 +}
  
  /* Call callback once for each pseudo-legal move in the given
     position, except castling moves. A move is pseudo-legal if it is
@@@ -382,7 -181,7 +382,7 @@@ GenPseudoLegal (Board board, int flags
      int rf, ff;
      int i, j, d, s, fs, rs, rt, ft, m;
      int epfile = (signed char)board[EP_STATUS]; // [HGM] gamestate: extract ep status from board
 -    int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
 +    int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1;
  
      for (rf = 0; rf < BOARD_HEIGHT; rf++)
        for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
            if(PieceToChar(piece) == '~')
                   piece = (ChessSquare) ( DEMOTED piece );
            if(filter != EmptySquare && piece != filter) continue;
 -          if(gameInfo.variant == VariantShogi)
 +          if(IS_SHOGI(gameInfo.variant))
                   piece = (ChessSquare) ( SHOGI piece );
  
            switch ((int)piece) {
              case BlackUnicorn:
            case WhiteKnight:
            case BlackKnight:
 -            mounted:
              for (i = -1; i <= 1; i += 2)
                for (j = -1; j <= 1; j += 2)
                  for (s = 1; s <= 2; s++) {
  
              /* Gold General (and all its promoted versions) . First do the */
              /* diagonal forward steps, then proceed as normal Wazir        */
 -            case SHOGI WhiteWazir:
              case SHOGI (PROMOTED WhitePawn):
 +              if(gameInfo.variant == VariantShogi) goto WhiteGold;
 +            case SHOGI (PROMOTED BlackPawn):
 +              if(gameInfo.variant == VariantShogi) goto BlackGold;
 +              SlideVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
              case SHOGI (PROMOTED WhiteKnight):
 -            case SHOGI (PROMOTED WhiteQueen):
 -            case SHOGI (PROMOTED WhiteFerz):
 -            for (s = -1; s <= 1; s += 2) {
 -                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
 -                      !SameColor(board[rf][ff], board[rf + 1][ff + s])) {
 -                      callback(board, flags, NormalMove,
 -                             rf, ff, rf + 1, ff + s, closure);
 -                }
 -              }
 -              goto finishGold;
 +              if(gameInfo.variant == VariantShogi) goto WhiteGold;
 +            case SHOGI BlackDrunk:
 +            case SHOGI BlackAlfil:
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              StepSideways(board, flags, rf, ff, callback, closure);
 +              StepBackward(board, flags, rf, ff, callback, closure);
 +              break;
  
 -            case SHOGI BlackWazir:
 -            case SHOGI (PROMOTED BlackPawn):
              case SHOGI (PROMOTED BlackKnight):
 +              if(gameInfo.variant == VariantShogi) goto BlackGold;
 +            case SHOGI WhiteDrunk:
 +            case SHOGI WhiteAlfil:
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              StepSideways(board, flags, rf, ff, callback, closure);
 +              StepForward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +
 +            case SHOGI WhiteStag:
 +            case SHOGI BlackStag:
 +              if(gameInfo.variant == VariantShogi) goto BlackGold;
 +              SlideVertical(board, flags, rf, ff, callback, closure);
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              StepSideways(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI (PROMOTED WhiteQueen):
 +            case SHOGI WhiteTokin:
 +            case SHOGI WhiteWazir:
 +          WhiteGold:
 +              StepDiagForward(board, flags, rf, ff, callback, closure);
 +              Wazir(board, flags, rf, ff, callback, closure);
 +              break;
 +
              case SHOGI (PROMOTED BlackQueen):
 -            case SHOGI (PROMOTED BlackFerz):
 -            for (s = -1; s <= 1; s += 2) {
 -                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
 -                      !SameColor(board[rf][ff], board[rf - 1][ff + s])) {
 -                      callback(board, flags, NormalMove,
 -                             rf, ff, rf - 1, ff + s, closure);
 -                }
 -            }
 +            case SHOGI BlackTokin:
 +            case SHOGI BlackWazir:
 +            BlackGold:
 +              StepDiagBackward(board, flags, rf, ff, callback, closure);
 +              Wazir(board, flags, rf, ff, callback, closure);
 +              break;
  
              case WhiteWazir:
              case BlackWazir:
 -            finishGold:
 -              for (d = 0; d <= 1; d++)
 -                for (s = -1; s <= 1; s += 2) {
 -                      rt = rf + s * d;
 -                      ft = ff + s * (1 - d);
 -                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
 -                          && !SameColor(board[rf][ff], board[rt][ft]) &&
 -                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
 -                               callback(board, flags, NormalMove,
 -                                        rf, ff, rt, ft, closure);
 -                      }
 -            break;
 +              Wazir(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteMarshall:
 +            case SHOGI BlackMarshall:
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              for (d = 0; d <= 1; d++)
 +                  for (s = -2; s <= 2; s += 4) {
 +                      rt = rf + s * d;
 +                      ft = ff + s * (1 - d);
 +                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
 +                      if (!SameColor(board[rf][ff], board[rt][ft]) )
 +                          callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
 +                  }
 +              break;
 +
 +            case SHOGI WhiteAngel:
 +            case SHOGI BlackAngel:
 +              Wazir(board, flags, rf, ff, callback, closure);
  
              case WhiteAlfil:
              case BlackAlfil:
                            && !SameColor(board[rf][ff], board[rt][ft]))
                                 callback(board, flags, NormalMove,
                                          rf, ff, rt, ft, closure);
 -                      if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier
 -                                                             || gameInfo.variant == VariantXiangqi) continue; // classical Alfil
 +                      if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
 +                         gameInfo.variant == VariantChu      || gameInfo.variant == VariantXiangqi) continue; // classical Alfil
                        rt = rf + rs; // in unknown variant we assume Modern Elephant, which can also do one step
                        ft = ff + fs;
                        if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
              /* Make Dragon-Horse also do Dababba moves outside Shogi, for better disambiguation in variant Fairy */
            case WhiteCardinal:
            case BlackCardinal:
 +              if(gameInfo.variant == VariantChuChess) goto DragonHorse;
                for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
                  for (s = -2; s <= 2; s += 4) {
                      rt = rf + s * d;
              /* Shogi Dragon Horse has to continue with Wazir after Bishop */
              case SHOGI WhiteCardinal:
              case SHOGI BlackCardinal:
 -              m++;
 +            case SHOGI WhitePCardinal:
 +            case SHOGI BlackPCardinal:
 +            DragonHorse:
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              Wazir(board, flags, rf, ff, callback, closure);
 +              break;
  
              /* Capablanca Archbishop continues as Knight                  */
              case WhiteAngel:
              case BlackAngel:
 -              m++;
 +              Knight(board, flags, rf, ff, callback, closure);
  
              /* Shogi Bishops are ordinary Bishops */
              case SHOGI WhiteBishop:
              case SHOGI BlackBishop:
 +            case SHOGI WhitePBishop:
 +            case SHOGI BlackPBishop:
            case WhiteBishop:
            case BlackBishop:
 -            for (rs = -1; rs <= 1; rs += 2)
 -                for (fs = -1; fs <= 1; fs += 2)
 -                for (i = 1;; i++) {
 -                    rt = rf + (i * rs);
 -                    ft = ff + (i * fs);
 -                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 -                    if (SameColor(board[rf][ff], board[rt][ft])) break;
 -                    callback(board, flags, NormalMove,
 -                             rf, ff, rt, ft, closure);
 -                    if (board[rt][ft] != EmptySquare) break;
 -                }
 -                if(m==1) goto mounted;
 -                if(m==2) goto finishGold;
 -                /* Bishop falls through */
 -            break;
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              break;
  
              /* Shogi Lance is unlike anything, and asymmetric at that */
              case SHOGI WhiteQueen:
 +              if(gameInfo.variant == VariantChu) goto doQueen;
                for(i = 1;; i++) {
                        rt = rf + i;
                        ft = ff;
                break;
  
              case SHOGI BlackQueen:
 +              if(gameInfo.variant == VariantChu) goto doQueen;
                for(i = 1;; i++) {
                        rt = rf - i;
                        ft = ff;
              /* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */
            case WhiteDragon:
            case BlackDragon:
 +              if(gameInfo.variant == VariantChuChess) goto DragonKing;
                for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
                  for (s = -2; s <= 2; s += 4) {
                      rt = rf + s * d;
              /* Shogi Dragon King has to continue as Ferz after Rook moves */
              case SHOGI WhiteDragon:
              case SHOGI BlackDragon:
 +            case SHOGI WhitePDragon:
 +            case SHOGI BlackPDragon:
 +            DragonKing:
 +              Rook(board, flags, rf, ff, callback, closure);
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              break;
                m++;
  
              /* Capablanca Chancellor sets flag to continue as Knight      */
              case WhiteMarshall:
              case BlackMarshall:
 -              m++;
 -              m += (gameInfo.variant == VariantSpartan); // in Spartan Chess Chancellor is used for Dragon King.
 +              Rook(board, flags, rf, ff, callback, closure);
 +              if(gameInfo.variant == VariantSpartan) // in Spartan Chess Chancellor is used for Dragon King.
 +                  Ferz(board, flags, rf, ff, callback, closure);
 +              else
 +                  Knight(board, flags, rf, ff, callback, closure);
 +              break;
  
              /* Shogi Rooks are ordinary Rooks */
              case SHOGI WhiteRook:
              case SHOGI BlackRook:
 +            case SHOGI WhitePRook:
 +            case SHOGI BlackPRook:
            case WhiteRook:
            case BlackRook:
            doRook:
 -              for (d = 0; d <= 1; d++)
 -                for (s = -1; s <= 1; s += 2)
 -                for (i = 1;; i++) {
 -                    rt = rf + (i * s) * d;
 -                    ft = ff + (i * s) * (1 - d);
 -                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 -                    if (SameColor(board[rf][ff], board[rt][ft])) break;
 -                    callback(board, flags, NormalMove,
 -                             rf, ff, rt, ft, closure);
 -                    if (board[rt][ft] != EmptySquare || i == rookRange) break;
 -                }
 -                if(m==1) goto mounted;
 -                if(m==2) goto finishSilver;
 -            break;
 +              Rook(board, flags, rf, ff, callback, closure);
 +              break;
  
            case WhiteQueen:
            case BlackQueen:
 -            for (rs = -1; rs <= 1; rs++)
 -              for (fs = -1; fs <= 1; fs++) {
 -                  if (rs == 0 && fs == 0) continue;
 -                  for (i = 1;; i++) {
 -                      rt = rf + (i * rs);
 -                      ft = ff + (i * fs);
 -                        if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 -                      if (SameColor(board[rf][ff], board[rt][ft])) break;
 -                      callback(board, flags, NormalMove,
 -                               rf, ff, rt, ft, closure);
 -                      if (board[rt][ft] != EmptySquare) break;
 -                  }
 -              }
 -            break;
 +            case SHOGI WhiteMother:
 +            case SHOGI BlackMother:
 +          doQueen:
 +              Rook(board, flags, rf, ff, callback, closure);
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +           case SHOGI WhitePawn:
 +              StepForward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI BlackPawn:
 +              StepBackward(board, flags, rf, ff, callback, closure);
 +              break;
  
 -            /* Shogi Pawn and Silver General: first the Pawn move,    */
 -            /* then the General continues like a Ferz                 */
              case WhiteMan:
 -                if(gameInfo.variant != VariantMakruk) goto commoner;
 -            case SHOGI WhitePawn:
 +                if(gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN) goto commoner;
              case SHOGI WhiteFerz:
 -                  if (rf < BOARD_HEIGHT-1 &&
 -                           !SameColor(board[rf][ff], board[rf + 1][ff]) )
 -                           callback(board, flags, NormalMove,
 -                                    rf, ff, rf + 1, ff, closure);
 -              if(piece != SHOGI WhitePawn) goto finishSilver;
 -              break;
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              StepForward(board, flags, rf, ff, callback, closure);
 +              break;
  
              case BlackMan:
 -                if(gameInfo.variant != VariantMakruk) goto commoner;
 -            case SHOGI BlackPawn:
 +                if(gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN) goto commoner;
              case SHOGI BlackFerz:
 -                  if (rf > 0 &&
 -                           !SameColor(board[rf][ff], board[rf - 1][ff]) )
 -                           callback(board, flags, NormalMove,
 -                                    rf, ff, rf - 1, ff, closure);
 -              if(piece == SHOGI BlackPawn) break;
 +              StepBackward(board, flags, rf, ff, callback, closure);
  
              case WhiteFerz:
              case BlackFerz:
 -            finishSilver:
                  /* [HGM] support Shatranj pieces */
 -                for (rs = -1; rs <= 1; rs += 2)
 -                  for (fs = -1; fs <= 1; fs += 2) {
 -                      rt = rf + rs;
 -                      ft = ff + fs;
 -                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
 -                      if (!SameColor(board[rf][ff], board[rt][ft]) &&
 -                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
 -                               callback(board, flags, NormalMove,
 -                                        rf, ff, rt, ft, closure);
 -                }
 -                break;
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              break;
  
            case WhiteSilver:
            case BlackSilver:
 -              m++; // [HGM] superchess: use for Centaur
 +              Knight(board, flags, rf, ff, callback, closure); // [HGM] superchess: use for Centaur
 +
              commoner:
 +            case SHOGI WhiteMonarch:
 +            case SHOGI BlackMonarch:
              case SHOGI WhiteKing:
              case SHOGI BlackKing:
            case WhiteKing:
            case BlackKing:
 -//            walking:
 -            for (i = -1; i <= 1; i++)
 -              for (j = -1; j <= 1; j++) {
 -                  if (i == 0 && j == 0) continue;
 -                  rt = rf + i;
 -                  ft = ff + j;
 -                    if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
 -                  if (SameColor(board[rf][ff], board[rt][ft])) continue;
 -                  callback(board, flags, NormalMove,
 -                           rf, ff, rt, ft, closure);
 -              }
 -              if(m==1) goto mounted;
 -            break;
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              Wazir(board, flags, rf, ff, callback, closure);
 +              break;
  
            case WhiteNightrider:
            case BlackNightrider:
              break;
  
            Amazon:
 -            /* First do Bishop,then continue like Chancellor */
 -            for (rs = -1; rs <= 1; rs += 2)
 -                for (fs = -1; fs <= 1; fs += 2)
 -                for (i = 1;; i++) {
 -                    rt = rf + (i * rs);
 -                    ft = ff + (i * fs);
 -                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
 -                    if (SameColor(board[rf][ff], board[rt][ft])) break;
 -                    callback(board, flags, NormalMove,
 -                             rf, ff, rt, ft, closure);
 -                    if (board[rt][ft] != EmptySquare) break;
 -                }
 -            m++;
 -            goto doRook;
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              Rook(board, flags, rf, ff, callback, closure);
 +              Knight(board, flags, rf, ff, callback, closure);
 +              break;
  
            // Use Lance as Berolina / Spartan Pawn.
            case WhiteLance:
              }
              break;
  
 +            case SHOGI WhiteNothing:
 +            case SHOGI BlackNothing:
 +            case SHOGI WhiteLion:
 +            case SHOGI BlackLion:
 +            case WhiteLion:
 +            case BlackLion:
 +              for(rt = rf - 2; rt <= rf + 2; rt++) for(ft = ff - 2; ft <= ff + 2; ft++) {
 +                if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
 +                if (!(ff == ft && rf == rt) && SameColor(board[rf][ff], board[rt][ft])) continue;
 +                callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove,
 +                         rf, ff, rt, ft, closure);
 +              }
 +              break;
 +
 +            case SHOGI WhiteFalcon:
 +            case SHOGI BlackFalcon:
 +            case SHOGI WhitePDagger:
 +            case SHOGI BlackPDagger:
 +              SlideSideways(board, flags, rf, ff, callback, closure);
 +              StepVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteCobra:
 +            case SHOGI BlackCobra:
 +              StepVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI (PROMOTED WhiteFerz):
 +              if(gameInfo.variant == VariantShogi) goto WhiteGold;
 +            case SHOGI (PROMOTED BlackFerz):
 +              if(gameInfo.variant == VariantShogi) goto BlackGold;
 +            case SHOGI WhitePSword:
 +            case SHOGI BlackPSword:
 +              SlideVertical(board, flags, rf, ff, callback, closure);
 +              StepSideways(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteUnicorn:
 +            case SHOGI BlackUnicorn:
 +              Ferz(board, flags, rf, ff, callback, closure);
 +              StepVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteMan:
 +              StepDiagForward(board, flags, rf, ff, callback, closure);
 +              StepVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI BlackMan:
 +              StepDiagBackward(board, flags, rf, ff, callback, closure);
 +              StepVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteHCrown:
 +            case SHOGI BlackHCrown:
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              SlideSideways(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteCrown:
 +            case SHOGI BlackCrown:
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              SlideVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteHorned:
 +              Sting(board, flags, rf, ff, 1, 0, callback, closure);
 +              callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
 +              if(killX >= 0) break;
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              SlideSideways(board, flags, rf, ff, callback, closure);
 +              SlideBackward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI BlackHorned:
 +              Sting(board, flags, rf, ff, -1, 0, callback, closure);
 +              callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
 +              if(killX >= 0) break;
 +              Bishop(board, flags, rf, ff, callback, closure);
 +              SlideSideways(board, flags, rf, ff, callback, closure);
 +              SlideForward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteEagle:
 +              Sting(board, flags, rf, ff, 1,  1, callback, closure);
 +              Sting(board, flags, rf, ff, 1, -1, callback, closure);
 +              callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
 +              if(killX >= 0) break;
 +              Rook(board, flags, rf, ff, callback, closure);
 +              SlideDiagBackward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI BlackEagle:
 +              Sting(board, flags, rf, ff, -1,  1, callback, closure);
 +              Sting(board, flags, rf, ff, -1, -1, callback, closure);
 +              callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
 +              if(killX >= 0) break;
 +              Rook(board, flags, rf, ff, callback, closure);
 +              SlideDiagForward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteDolphin:
 +            case SHOGI BlackHorse:
 +              SlideDiagBackward(board, flags, rf, ff, callback, closure);
 +              SlideVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI BlackDolphin:
 +            case SHOGI WhiteHorse:
 +              SlideDiagForward(board, flags, rf, ff, callback, closure);
 +              SlideVertical(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI WhiteLance:
 +              SlideForward(board, flags, rf, ff, callback, closure);
 +              break;
 +
 +            case SHOGI BlackLance:
 +              SlideBackward(board, flags, rf, ff, callback, closure);
 +              break;
 +
            case WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere
            case BlackFalcon:
            case WhiteCobra:
@@@ -1039,8 -728,6 +1039,8 @@@ GenLegalCallback (Board board, int flag
  
      if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square
  
 +    if (board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion
 +
      if (!(flags & F_IGNORE_CHECK) ) {
        int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion);
        if(promo) {
@@@ -1224,6 -911,7 +1224,7 @@@ GenLegal (Board board, int  flags, Move
              if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
              for(k=left; k<=right && ft != NoRights; k++) /* first test if blocked */
                  if(k != ft && board[0][k] != EmptySquare) ft = NoRights;
+             if(ft == 0 && ff != 1 && board[0][1] != EmptySquare) ft = NoRights; /* Rook can be blocked on b1 */
              if(ff > BOARD_LEFT+2)
              for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
                  if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
              if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
              for(k=left; k<=right && ft != NoRights; k++) /* first test if blocked */
                  if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = NoRights;
+             if(ft == 0 && ff != 1 && board[BOARD_HEIGHT-1][1] != EmptySquare) ft = NoRights; /* Rook can be blocked on b8 */
              if(ff > BOARD_LEFT+2)
              for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
                  if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
@@@ -1285,9 -974,6 +1287,9 @@@ CheckTestCallback (Board board, int fla
        cl->check++;
        xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1)
      }
 +    if( board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)
 +      && (gameInfo.variant != VariantLion || board[rf][ff] != WhiteKing && board[rf][ff] != BlackKing) )
 +      cl->check++; // [HGM] lion: forbidden counterstrike against Lion equated to putting yourself in check
  }
  
  
@@@ -1303,43 -989,25 +1305,43 @@@ CheckTest (Board board, int flags, int 
  {
      CheckTestClosure cl;
      ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
 -    ChessSquare captured = EmptySquare;
 +    ChessSquare captured = EmptySquare, ep, trampled;
      /*  Suppress warnings on uninitialized variables    */
  
      if(gameInfo.variant == VariantXiangqi)
          king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;
      if(gameInfo.variant == VariantKnightmate)
          king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
 +    if(gameInfo.variant == VariantChu) { // strictly speaking this is not needed, as Chu officially has no check
 +      int r, f, k = king, royals=0, prince = flags & F_WHITE_ON_MOVE ? WhiteMonarch : BlackMonarch;
 +      for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
 +          if(board[r][f] == k || board[r][f] == prince) {
 +              if(++royals > 1) return FALSE; // no check if we have two royals (ignores double captureby Lion!)
 +              king = board[r][f]; // remember hich one we had
 +          }
 +      }
 +    }
  
      if (rt >= 0) {
        if (enPassant) {
            captured = board[rf][ft];
            board[rf][ft] = EmptySquare;
        } else {
 -          captured = board[rt][ft];
 +          captured = board[rt][ft];
 +          if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; }
        }
        if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop
            board[rt][ft] = board[rf][ff];
            board[rf][ff] = EmptySquare;
        }
 +      ep = board[EP_STATUS];
 +      if( captured == WhiteLion || captured == BlackLion ) { // [HGM] lion: Chu Lion-capture rules
 +          ChessSquare victim = killX < 0 ? EmptySquare : trampled;
 +          if( (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) &&           // capturer is Lion
 +              (ff - ft > 1 || ft - ff > 1 || rf - rt > 1 || rt - rf > 1) &&           // captures from a distance
 +              (victim == EmptySquare || victim == WhitePawn || victim == BlackPawn) ) // no or worthless 'bridge'
 +                   board[EP_STATUS] = EP_ROYAL_LION; // on distant Lion x Lion victim must not be pseudo-legally protected
 +      }
      }
  
      /* For compatibility with ICS wild 9, we scan the board in the
            board[rf][ft] = captured;
            board[rt][ft] = EmptySquare;
        } else {
 +          if(killX >= 0) board[killY][killX] = trampled;
            board[rt][ft] = captured;
        }
 +      board[EP_STATUS] = ep;
      }
  
      return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
  }
  
 +int
 +HasLion (Board board, int flags)
 +{
 +    int lion = F_WHITE_ON_MOVE & flags ? WhiteLion : BlackLion;
 +    int r, f;
 +    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
 +        if(board[r][f] == lion) return 1;
 +    return 0;
 +}
 +
  ChessMove
  LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft)
  {   // [HGM] put drop legality testing in separate routine for clarity
@@@ -1482,13 -1138,6 +1484,13 @@@ LegalityTest (Board board, int flags, i
              if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove;
          }
      } else
 +    if(gameInfo.variant == VariantChu) {
 +        if(cl.kind != NormalMove || promoChar == NULLCHAR || promoChar == '=') return cl.kind;
 +        if(promoChar != '+')
 +            return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove;
 +        if(PieceToChar(CHUPROMOTED board[rf][ff]) != '+') return ImpossibleMove;
 +        return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
 +    } else
      if(gameInfo.variant == VariantShogi) {
          /* [HGM] Shogi promotions. '=' means defer */
          if(rf != DROP_RANK && cl.kind == NormalMove) {
@@@ -1523,26 -1172,16 +1525,26 @@@ if(appData.debugMode)fprintf(debugFP,"S
          }
      } else
      if (promoChar != NULLCHAR) {
 +      if(cl.kind == NormalMove && promoChar == '+') { // allow shogi-style promotion is pieceToChar specifies them
 +            ChessSquare piece = board[rf][ff];
 +            if(piece < BlackPawn ? piece > WhiteMan : piece > BlackMan) return ImpossibleMove; // already promoted
 +            // should test if in zone, really
 +            if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight) && HasLion(board, flags))
 +                return IllegalMove;
 +            if(PieceToChar(PROMOTED piece) == '+') return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
 +        } else
        if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
        if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
            ChessSquare piece = CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(promoChar) : ToLower(promoChar));
            if(piece == EmptySquare)
                  cl.kind = ImpossibleMove; // non-existing piece
 -          if(gameInfo.variant == VariantSpartan && cl.kind == BlackPromotion ) {
 +          if(gameInfo.variant == VariantChuChess && promoChar == 'l' && HasLion(board, flags)) {
 +                cl.kind = IllegalMove; // no two Lions
 +          } else if(gameInfo.variant == VariantSpartan && cl.kind == BlackPromotion ) {
                if(promoChar != PieceToChar(BlackKing)) {
                    if(CheckTest(board, flags, rf, ff, rt, ft, FALSE)) cl.kind = IllegalMove; // [HGM] spartan: only promotion to King was possible
                    if(piece == BlackLance) cl.kind = ImpossibleMove;
 -              } else { // promotion to King allowed only if we do not haave two yet
 +              } else { // promotion to King allowed only if we do not have two yet
                    int r, f, kings = 0;
                    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) kings += (board[r][f] == BlackKing);
                    if(kings == 2) cl.kind = IllegalMove;
@@@ -1627,7 -1266,7 +1629,7 @@@ MateTest (Board board, int flags
        else if(gameInfo.variant == VariantGiveaway) return MT_STEALMATE; // no check exists, stalemated = win
  
          return inCheck ? MT_CHECKMATE
 -                     : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj || gameInfo.variant == VariantShogi) ?
 +                     : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj || IS_SHOGI(gameInfo.variant)) ?
                          MT_STAINMATE : MT_STALEMATE;
      }
  }
@@@ -1730,9 -1369,6 +1732,9 @@@ Disambiguate (Board board, int flags, D
              if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove;
          }
      } else
 +    if(gameInfo.variant == VariantChu) {
 +        if(c == '+') closure->kind = (flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion); // for now, accept any
 +    } else
      if(gameInfo.variant == VariantShogi) {
          /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */
          if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
      } else
      if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) {
          if(c == NULLCHAR) { // missing promoChar on mandatory promotion; use default for variant
 -            if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
 +            if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
 +               gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
                  c = PieceToChar(BlackFerz);
              else if(gameInfo.variant == VariantGreat)
                  c = PieceToChar(BlackMan);
              else
                  c = PieceToChar(BlackQueen);
          } else if(c == '=') closure->kind = IllegalMove; // no deferral outside Shogi
 +        else if(c == 'l' && gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove;
 +    } else if (c == '+') { // '+' outside shogi, check if pieceToCharTable enabled it
 +        ChessSquare p = closure->piece;
 +        if(p > WhiteMan && p < BlackPawn || p > BlackMan || PieceToChar(PROMOTED p) != '+')
 +            closure->kind = ImpossibleMove; // used on non-promotable piece
 +        else if(gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove;
      } else if (c != NULLCHAR) closure->kind = IllegalMove;
  
      closure->promoChar = ToLower(c); // this can be NULLCHAR! Note we keep original promoChar even if illegal.
@@@ -1900,7 -1529,7 +1902,7 @@@ CoordsToAlgebraic (Board board, int fla
        /* Use promotion suffix style "=Q" */
        *outp = NULLCHAR;
          if (promoChar != NULLCHAR) {
 -            if(gameInfo.variant == VariantShogi) {
 +            if(IS_SHOGI(gameInfo.variant)) {
                  /* [HGM] ... but not in Shogi! */
                  *outp++ = promoChar == '=' ? '=' : '+';
              } else {
        */
          if( c == '~' || c == '+') {
             /* [HGM] print nonexistent piece as its demoted version */
 -           piece = (ChessSquare) (DEMOTED piece);
 +           piece = (ChessSquare) (DEMOTED piece - 11*(gameInfo.variant == VariantChu));
          }
          if(c=='+') *outp++ = c;
          *outp++ = ToUpper(PieceToChar(piece));
          if(rt+ONE <= '9')
             *outp++ = rt + ONE;
          else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
 -        if (gameInfo.variant == VariantShogi) {
 +        if (IS_SHOGI(gameInfo.variant)) {
              /* [HGM] in Shogi non-pawns can promote */
              *outp++ = promoChar; // Don't bother to correct move type, return value is never used!
          }
 -        else if (gameInfo.variant != VariantSuper && promoChar &&
 +        else if (gameInfo.variant == VariantChuChess && promoChar ||
 +                 gameInfo.variant != VariantSuper && promoChar &&
                   (piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn
              *outp++ = '=';
              *outp++ = ToUpper(promoChar);
diff --combined moves.h
+++ b/moves.h
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * Enhancements Copyright 2005 Alessandro Scotti
   *
@@@ -83,12 -83,10 +83,12 @@@ typedef void (*MoveCallback) P((Board b
  #define F_MANDATORY_CAPTURE 0x200
  
  /* Special epfile values. [HGM] positive values are non-reversible moves! */
 -#define EP_NONE (-4)           /* [HGM] Tricky! order matters:            */
 -#define EP_UNKNOWN (-1)        /*       >= EP_UNKNOWN spils rep-draw      */
 +#define EP_NONE (-6)           /* [HGM] Tricky! order matters:            */
 +#define EP_UNKNOWN (-1)        /*       >= EP_UNKNOWN spoils rep-draw     */
  #define EP_CAPTURE (-2)        /*       <= EP_NONE is reversible move     */
  #define EP_PAWN_MOVE (-3)
 +#define EP_IRON_LION (-4)
 +#define EP_ROYAL_LION (-5)
  #define EP_REP_DRAW   (-15)
  #define EP_RULE_DRAW  (-14)
  #define EP_INSUF_DRAW  (-13)
@@@ -174,4 -172,4 +174,4 @@@ ChessMove CoordsToAlgebraic P((Board bo
                               int rf, int ff, int rt, int ft,
                               int promoChar, char out[MOVE_LEN]));
  
 -extern int quickFlag;
 +extern int quickFlag, killX, killY;
diff --combined nengineoutput.c
@@@ -5,7 -5,7 +5,7 @@@
   *
   * Copyright 2005 Alessandro Scotti
   *
-  * Enhancements Copyright 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Enhancements Copyright 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * ------------------------------------------------------------------------
   *
@@@ -74,18 -74,16 +74,18 @@@ int highTextStart[2], highTextEnd[2]
  int MemoProc P((Option *opt, int n, int x, int y, char *text, int index));
  
  Option engoutOptions[] = {
 -{  0,  LL|T2T,           17, NULL, NULL, NULL, NULL, Icon, " " },
 -{  0, L2L|T2T|SAME_ROW, 163, NULL, NULL, NULL, NULL, Label, N_("engine name") },
 +{  0,  LL|T2T,           18, NULL, NULL, NULL, NULL, Icon, " " },
 +{  0, L2L|T2T|SAME_ROW, 162, NULL, NULL, NULL, NULL, Label, N_("engine name") },
  {  0,     T2T|SAME_ROW,  30, NULL, NULL, NULL, NULL, Icon, " " },
 +/* TRANSLATORS: noun, as in "the move Nf3"*/
  {  0, R2R|T2T|SAME_ROW, 188, NULL, NULL, NULL, NULL, Label, N_("move") },
  {  0,  RR|T2T|SAME_ROW,  80, NULL, NULL, NULL, NULL, Label, N_("NPS") },
  {200, T_VSCRL | T_TOP,  500, NULL, (void*) &mem1, "", (char**) MemoProc, TextBox, "" },
  {  0,         0,         0, NULL, NULL, "", NULL, Break , "" },
 -{  0,  LL|T2T,           17, NULL, NULL, NULL, NULL, Icon, " " },
 -{  0, L2L|T2T|SAME_ROW, 163, NULL, NULL, NULL, NULL, Label, N_("engine name") },
 +{  0,  LL|T2T,           18, NULL, NULL, NULL, NULL, Icon, " " },
 +{  0, L2L|T2T|SAME_ROW, 162, NULL, NULL, NULL, NULL, Label, N_("engine name") },
  {  0,     T2T|SAME_ROW,  30, NULL, NULL, NULL, NULL, Icon, " " },
 +/* TRANSLATORS: noun, as in "the move Nf3"*/
  {  0, R2R|T2T|SAME_ROW, 188, NULL, NULL, NULL, NULL, Label, N_("move") },
  {  0,  RR|T2T|SAME_ROW,  80, NULL, NULL, NULL, NULL, Label, N_("NPS") },
  {200, T_VSCRL | T_TOP,  500, NULL, (void*) &mem2, "", (char**) MemoProc, TextBox, "" },
diff --combined parser.c
+++ b/parser.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * parser.c --
   *
-  * Copyright 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Copyright 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   * ------------------------------------------------------------------------
   *
   * GNU XBoard is free software: you can redistribute it and/or modify
@@@ -151,11 -151,11 +151,11 @@@ PromoSuffix (char **p
  {
      char *start = *p;
      if(**p == 'e' && (Match("ep", p) || Match("e.p.", p))) { *p = start; return NULLCHAR; } // non-compliant e.p. suffix is no promoChar!
 -    if(**p == '+' && gameInfo.variant == VariantShogi) { (*p)++; return '+'; }
 +    if(**p == '+' && IS_SHOGI(gameInfo.variant)) { (*p)++; return '+'; }
      if(**p == '=' || (gameInfo.variant == VariantSChess) && **p == '/') (*p)++; // optional = (or / for Seirawan gating)
      if(**p == '(' && (*p)[2] == ')' && isalpha( (*p)[1] )) { (*p) += 3; return ToLower((*p)[-2]); }
 -    if(isalpha(**p)) return ToLower(*(*p)++);
 -    if(*p != start) return '='; // must be the optional =
 +    if(isalpha(**p) && **p != 'x') return ToLower(*(*p)++); // reserve 'x' for multi-leg captures? 
 +    if(*p != start) return **p == '+' ? *(*p)++ : '='; // must be the optional = (or =+)
      return NULLCHAR; // no suffix detected
  }
  
@@@ -174,6 -174,10 +174,10 @@@ NextUnit (char **p
            if(fromString) return 0; // we are parsing string, so the end is really the end
            *p = inPtr = inputBuf;
            if(!ReadLine()) return 0; // EOF
+       } else if(inPtr > inputBuf + PARSEBUFSIZE/2) { // buffer fills up with already parsed stuff
+           char *q = *p, *r = inputBuf;
+           while(*r++ = *q++);
+           *p = inputBuf; inPtr = r - 1;
        }
        parseStart = oldp = *p; // remember where we begin
  
        } else if(n == 1 && type[0] == NUMERIC && coord[0] > 1) { while(**p == '.') (*p)++; return Nothing; } // fast exit for move numbers
        if(n == 4 && type[2] != type[3] && // we have a valid to-square (kludge: type[3] can be NOTHING on fxg type move)
                     (piece || !promoted) && // promoted indicator only valid on named piece type
 -                   (type[2] == ALPHABETIC || gameInfo.variant == VariantShogi)) { // in Shogi also allow alphabetic rank
 +                   (type[2] == ALPHABETIC || IS_SHOGI(gameInfo.variant))) { // in Shogi also allow alphabetic rank
            DisambiguateClosure cl;
            int fromX, fromY, toX, toY;
  
            if(piece) {
                cl.pieceIn = CharToPiece(wom ? piece : ToLower(piece));
                if(cl.pieceIn == EmptySquare) return ImpossibleMove; // non-existent piece
 -              if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn);
 +              if(promoted) cl.pieceIn = (ChessSquare) (CHUPROMOTED cl.pieceIn);
            } else cl.pieceIn = EmptySquare;
            if(separator == '@' || separator == '*') { // drop move. We only get here without from-square or promoted piece
                fromY = DROP_RANK; fromX = cl.pieceIn;
                fromY = (currentMoveString[1] = coord[1] + '0') - ONE;
                currentMoveString[4] = cl.promoCharIn = PromoSuffix(p);
                currentMoveString[5] = NULLCHAR;
 +              if(!cl.promoCharIn && (**p == '-' || **p == 'x')) { // Lion-type multi-leg move
 +                  currentMoveString[5] = (killX = toX) + AAA; // what we thought was to-square is in fact kill-square
 +                  currentMoveString[6] = (killY = toY) + ONE; // append it as suffix behind long algebraic move
 +                  currentMoveString[4] = ';';
 +                  currentMoveString[7] = NULLCHAR;
 +                  // read new to-square (VERY non-robust! Assumes correct (non-alpha-rank) syntax, and messes up on errors)
 +                  toX = cl.ftIn = (currentMoveString[2] = *++*p) - AAA; ++*p;
 +                  toY = cl.rtIn = (currentMoveString[3] = Number(p) + '0') - ONE;
 +              }
                if(type[0] != NOTHING && type[1] != NOTHING && type[3] != NOTHING) { // fully specified.
 +                  ChessSquare realPiece = boards[yyboardindex][fromY][fromX];
                    // Note that Disambiguate does not work for illegal moves, but flags them as impossible
                    if(piece) { // check if correct piece indicated
                        if(PieceToChar(realPiece) == '~') realPiece = (ChessSquare) (DEMOTED realPiece);
                        if(!(appData.icsActive && PieceToChar(realPiece) == '+') && // trust ICS if it moves promoted pieces
                           piece && realPiece != cl.pieceIn) return ImpossibleMove;
 +                  } else if(!separator && **p == '+') { // could be a protocol move, where bare '+' suffix means shogi-style promotion
 +                      if(realPiece < (wom ?  WhiteCannon : BlackCannon) && PieceToChar(PROMOTED realPiece) == '+') // seems to be that
 +                         currentMoveString[4] = cl.promoCharIn = *(*p)++; // append promochar after all
                    }
                    result = LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), fromY, fromX, toY, toX, cl.promoCharIn);
                    if (currentMoveString[4] == NULLCHAR) { // suppy missing mandatory promotion character
                currentMoveString[0] = cl.ff + AAA;
                currentMoveString[1] = cl.rf + ONE;
                currentMoveString[3] = cl.rt + ONE;
 +              if(killX < 0) // [HGM] lion: do not overwrite kill-square suffix
                currentMoveString[4] = cl.promoChar;
  
                if((cl.kind == WhiteCapturesEnPassant || cl.kind == BlackCapturesEnPassant) && (Match("ep", p) || Match("e.p.", p)));
diff --combined po/ru.po
+++ b/po/ru.po
@@@ -9,573 -9,569 +9,573 @@@ msgid "
  msgstr ""
  "Project-Id-Version: GNU xboard master-20110507\n"
  "Report-Msgid-Bugs-To: bug-xboard@gnu.org\n"
 -"POT-Creation-Date: 2013-08-28 21:49-0700\n"
 +"POT-Creation-Date: 2013-08-28 22:03-0700\n"
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
  "Language-Team: LANGUAGE <LL@li.org>\n"
  "MIME-Version: 1.0\n"
  "Content-Type: text/plain; charset=UTF-8\n"
  "Content-Transfer-Encoding: 8bit\n"
+ "Language: ru\n"
  
 -#: args.h:820
 +#: args.h:821
  #, c-format
  msgid "%s in settings file\n"
  msgstr ""
  
 -#: args.h:830
 +#: args.h:831
  #, c-format
  msgid "Bad integer value %s"
  msgstr ""
  
 -#: args.h:923 args.h:1164
 +#: args.h:924 args.h:1165
  #, c-format
  msgid "Unrecognized argument %s"
  msgstr ""
  
 -#: args.h:954
 +#: args.h:955
  #, c-format
  msgid "No value provided for argument %s"
  msgstr ""
  
 -#: args.h:1014
 +#: args.h:1015
  #, c-format
  msgid "Incomplete \\ escape in value for %s"
  msgstr ""
  
 -#: args.h:1119
 +#: args.h:1120
  #, c-format
  msgid "Failed to open indirection file %s"
  msgstr ""
  
 -#: args.h:1136
 +#: args.h:1137
  #, c-format
  msgid "Unrecognized boolean argument value %s"
  msgstr ""
  
  #. TRANSLATORS: "first" is the first of possible two chess engines. It is inserted into strings
  #. such as "%s engine" / "%s chess program" / "%s machine" - all meaning the same thing
 -#: backend.c:744
 +#: backend.c:753
  msgid "first"
  msgstr ""
  
  #. TRANSLATORS: "second" is the second of possible two chess engines. It is inserted into strings
  #. such as "%s engine" / "%s chess program" / "%s machine" - all meaning the same thing
 -#: backend.c:747
 +#: backend.c:756
  msgid "second"
  msgstr ""
  
 -#: backend.c:827
 +#: backend.c:837
  #, c-format
  msgid "protocol version %d not supported"
  msgstr "версия протокола %d не поддерживается"
  
 -#: backend.c:933
 +#: backend.c:943
  msgid "You did not specify the engine executable"
  msgstr ""
  
 -#: backend.c:989
 +#: backend.c:999
  #, c-format
  msgid "bad timeControl option %s"
  msgstr "timeControl: неверный параметр %s"
  
 -#: backend.c:1004
 +#: backend.c:1014
  #, c-format
  msgid "bad searchTime option %s"
  msgstr "searchTime: неверный параметр %s"
  
 -#: backend.c:1110
 +#: backend.c:1120
  #, c-format
  msgid "Variant %s supported only in ICS mode"
  msgstr "Вариант %s поддерживается только в режиме ICS"
  
 -#: backend.c:1128
 +#: backend.c:1138
  #, c-format
  msgid "Unknown variant name %s"
  msgstr "Неизвестный вариант %s"
  
 -#: backend.c:1375
 +#: backend.c:1386
  msgid "Starting chess program"
  msgstr "Запускается шахматная программа"
  
 -#: backend.c:1398
 +#: backend.c:1409
  msgid "Bad game file"
  msgstr "Неправильный формат файла"
  
 -#: backend.c:1405
 +#: backend.c:1416
  msgid "Bad position file"
  msgstr "Неправильный формат файла позиции"
  
 -#: backend.c:1419
 +#: backend.c:1430
  msgid "Pick new game"
  msgstr ""
  
 -#: backend.c:1488
 +#: backend.c:1499
  msgid ""
  "You restarted an already completed tourney\n"
  "One more cycle will now be added to it\n"
  "Games commence in 10 sec"
  msgstr ""
  
 -#: backend.c:1495
 +#: backend.c:1506
  #, c-format
  msgid "All games in tourney '%s' are already played or playing"
  msgstr ""
  
 -#: backend.c:1502
 +#: backend.c:1513
  msgid "Can't have a match with no chess programs"
  msgstr "Не подключено ни одной шахматной программы"
  
 -#: backend.c:1539
 +#: backend.c:1550
  #, c-format
  msgid "Could not open comm port %s"
  msgstr "Не могу открыть COM-порт %s"
  
 -#: backend.c:1542
 +#: backend.c:1553
  #, c-format
  msgid "Could not connect to host %s, port %s"
  msgstr "Не могу установить связь с %s, порт %s"
  
 -#: backend.c:1598
 +#: backend.c:1609
  #, c-format
  msgid "Unknown initialMode %s"
  msgstr "initialMode: неизвестный режим %s"
  
 -#: backend.c:1624
 +#: backend.c:1635
  msgid "AnalyzeFile mode requires a game file"
  msgstr "Режим анализа: не указан файл для анализа"
  
 -#: backend.c:1651
 +#: backend.c:1662
  msgid "Analysis mode requires a chess engine"
  msgstr "Для анализа необходима шахматная программа"
  
 -#: backend.c:1655
 +#: backend.c:1666
  msgid "Analysis mode does not work with ICS mode"
  msgstr "Режим анализа не совместим с режимом ICS"
  
 -#: backend.c:1666
 +#: backend.c:1677
  msgid "MachineWhite mode requires a chess engine"
  msgstr "В режиме \"Компьютер белыми\" нужна шахматная программа"
  
 -#: backend.c:1671
 +#: backend.c:1682
  msgid "MachineWhite mode does not work with ICS mode"
  msgstr "Режим \"Компьютер белыми\" не совместим с режимом ICS"
  
 -#: backend.c:1678
 +#: backend.c:1689
  msgid "MachineBlack mode requires a chess engine"
  msgstr "В режиме \"Компьютер черными\" нужна шахматная программа (движок)"
  
 -#: backend.c:1683
 +#: backend.c:1694
  msgid "MachineBlack mode does not work with ICS mode"
  msgstr "Режим \"Компьютер черными\" не совместим с режимом ICS"
  
 -#: backend.c:1690
 +#: backend.c:1701
  msgid "TwoMachines mode requires a chess engine"
  msgstr "В режиме \"Два движка\" нужна шахматная программа"
  
 -#: backend.c:1695
 +#: backend.c:1706
  msgid "TwoMachines mode does not work with ICS mode"
  msgstr "Режим \"Два движка\" не совместим с режимом ICS"
  
 -#: backend.c:1706
 +#: backend.c:1717
  msgid "Training mode requires a game file"
  msgstr "Для тренировки необходимо загрузить шахматную партию из файла"
  
 -#: backend.c:1869 backend.c:1924 backend.c:1947 backend.c:2346
 +#: backend.c:1880 backend.c:1935 backend.c:1958 backend.c:2357
  msgid "Error writing to ICS"
  msgstr "Ошибка записи на вход сервера ICS"
  
 -#: backend.c:1884
 +#: backend.c:1895
  msgid "Error reading from keyboard"
  msgstr "Ошибка клавиатуры"
  
 -#: backend.c:1887
 +#: backend.c:1898
  msgid "Got end of file from keyboard"
  msgstr "Получен символ конца файла с клавиатуры"
  
 -#: backend.c:2192
 +#: backend.c:2203
  #, c-format
  msgid "Unknown wild type %d"
  msgstr ""
  
 -#: backend.c:2263 usystem.c:329
 +#: backend.c:2274 usystem.c:329
  msgid "Error writing to display"
  msgstr "Ошибка записи на дисплей"
  
 -#: backend.c:3019
 +#: backend.c:3030
  #, c-format
  msgid "your opponent kibitzes: %s"
  msgstr ""
  
 -#: backend.c:3548
 +#: backend.c:3559
  msgid "Error gathering move list: two headers"
  msgstr "Ошибка чтения списка ходов: два заголовка"
  
 -#: backend.c:3595
 +#: backend.c:3606
  msgid "Error gathering move list: nested"
  msgstr "Ошибка чтения списка ходов: вложенные списки"
  
 -#: backend.c:3699 backend.c:4117 backend.c:4321 backend.c:4880 backend.c:4884
 -#: backend.c:6900 backend.c:12082 backend.c:13797 backend.c:13874
 -#: backend.c:13920 backend.c:13926 backend.c:13931 backend.c:13936
 +#: backend.c:3710 backend.c:4128 backend.c:4332 backend.c:4891 backend.c:4895
 +#: backend.c:6919 backend.c:12213 backend.c:13928 backend.c:14005
 +#: backend.c:14051 backend.c:14057 backend.c:14062 backend.c:14067
  msgid "vs."
  msgstr ""
  
 -#: backend.c:3827
 +#: backend.c:3838
  msgid "Illegal move (rejected by ICS)"
  msgstr ""
  
 -#: backend.c:4165
 +#: backend.c:4176
  msgid "Connection closed by ICS"
  msgstr "Сервер ICS разорвал соединение"
  
 -#: backend.c:4167
 +#: backend.c:4178
  msgid "Error reading from ICS"
  msgstr "Ошибка чтения с сервера ICS"
  
 -#: backend.c:4244
 +#: backend.c:4255
  #, c-format
  msgid ""
  "Failed to parse board string:\n"
  "\"%s\""
  msgstr ""
  
 -#: backend.c:4253 backend.c:9755
 +#: backend.c:4264 backend.c:9885
  msgid "Game too long; increase MAX_MOVES and recompile"
  msgstr ""
  "Слишком длинная партия: увеличьте значение MAX_MOVES и перекомпилируйте "
  "программу"
  
 -#: backend.c:4372
 +#: backend.c:4383
  msgid "Error gathering move list: extra board"
  msgstr "Ошибка чтения списка ходов: лишняя доска"
  
 -#: backend.c:4804 backend.c:4826
 +#: backend.c:4815 backend.c:4837
  #, c-format
  msgid "Couldn't parse move \"%s\" from ICS"
  msgstr "Странный ход \"%s\" получен с сервера ICS"
  
 -#: backend.c:5063
 +#: backend.c:5074
  #, c-format
  msgid "say Internal error; bad moveType %d (%d,%d-%d,%d)"
  msgstr ""
  
 -#: backend.c:5133
 +#: backend.c:5145
  msgid "You cannot do this while you are playing or observing"
  msgstr ""
  
 -#: backend.c:6029
 +#: backend.c:6046
  msgid "Recompile to support this BOARD_RANKS or BOARD_FILES!"
  msgstr ""
  
 -#: backend.c:6491
 +#: backend.c:6510
  msgid "You are playing Black"
  msgstr "Вы играете черными"
  
 -#: backend.c:6500 backend.c:6527
 +#: backend.c:6519 backend.c:6546
  msgid "You are playing White"
  msgstr "Вы играете белыми"
  
 -#: backend.c:6509 backend.c:6535 backend.c:6655 backend.c:6680 backend.c:6696
 -#: backend.c:14573
 +#: backend.c:6528 backend.c:6554 backend.c:6674 backend.c:6699 backend.c:6715
 +#: backend.c:14705
  msgid "It is White's turn"
  msgstr "Ход белых"
  
 -#: backend.c:6513 backend.c:6539 backend.c:6663 backend.c:6686 backend.c:6717
 -#: backend.c:14565
 +#: backend.c:6532 backend.c:6558 backend.c:6682 backend.c:6705 backend.c:6736
 +#: backend.c:14697
  msgid "It is Black's turn"
  msgstr "Ход черных"
  
 -#: backend.c:6552
 +#: backend.c:6571
  msgid "Displayed position is not current"
  msgstr "Показанная позиция не соответствует положению в игре"
  
 -#: backend.c:6790
 +#: backend.c:6809
  msgid "Illegal move"
  msgstr "Неправильный ход"
  
 -#: backend.c:6857
 +#: backend.c:6876
  msgid "End of game"
  msgstr "Сыгран последний записанный ход"
  
 -#: backend.c:6860
 +#: backend.c:6879
  msgid "Incorrect move"
  msgstr "Неверный ход"
  
 -#: backend.c:7169 backend.c:7296
 +#: backend.c:7257 backend.c:7392
  msgid "Pull pawn backwards to under-promote"
  msgstr ""
  
 -#: backend.c:7527
 +#: backend.c:7364
 +msgid "only marked squares are legal"
 +msgstr ""
 +
 +#: backend.c:7624
  msgid "Swiss tourney finished"
  msgstr ""
  
 -#: backend.c:8102
 +#: backend.c:8199
  msgid "Invalid pairing from pairing engine"
  msgstr ""
  
 -#: backend.c:8235
 +#: backend.c:8332
  #, c-format
  msgid "Illegal move \"%s\" from %s machine"
  msgstr "Неправильный ход \"%s\" пытается выполнить движок %s"
  
 -#: backend.c:8456
 +#: backend.c:8564
  msgid "Bad FEN received from engine"
  msgstr ""
  
 -#: backend.c:8600 backend.c:13662 backend.c:13727
 +#: backend.c:8730 backend.c:13793 backend.c:13858
  #, c-format
  msgid "%s does not support analysis"
  msgstr "%s не поддерживает режим анализа"
  
 -#: backend.c:8666
 +#: backend.c:8796
  #, c-format
  msgid "Illegal move \"%s\" (rejected by %s chess program)"
  msgstr "Неправильный ход \"%s\" (не принят движком %s)"
  
 -#: backend.c:8693
 +#: backend.c:8823
  #, c-format
  msgid "Failed to start %s chess program %s on %s: %s\n"
  msgstr "Не удалось запустить %s движок %s на %s: %s\n"
  
 -#: backend.c:8714
 +#: backend.c:8844
  #, c-format
  msgid "Hint: %s"
  msgstr "Подсказка: %s"
  
 -#: backend.c:8719
 +#: backend.c:8849
  #, c-format
  msgid ""
  "Illegal hint move \"%s\"\n"
  "from %s chess program"
  msgstr ""
  
 -#: backend.c:8894
 +#: backend.c:9024
  msgid "Machine accepts your draw offer"
  msgstr "Компьютер согласился на ничью"
  
 -#: backend.c:8897
 +#: backend.c:9027
  msgid ""
  "Machine offers a draw\n"
  "Select Action / Draw to agree"
  msgstr ""
  
 -#: backend.c:8976
 +#: backend.c:9106
  msgid "failed writing PV"
  msgstr ""
  
 -#: backend.c:9274
 +#: backend.c:9404
  #, c-format
  msgid "Ambiguous move in ICS output: \"%s\""
  msgstr "Неоднозначный ход с сервера ICS: \"%s\""
  
 -#: backend.c:9284
 +#: backend.c:9414
  #, c-format
  msgid "Illegal move in ICS output: \"%s\""
  msgstr "Неправильный ход с сервера ICS: \"%s\""
  
 -#: backend.c:9295
 +#: backend.c:9425
  msgid "Gap in move list"
  msgstr "Пропуск в записи ходов"
  
 -#: backend.c:9916 dialogs.c:460
 +#: backend.c:10046 dialogs.c:461
  #, c-format
  msgid "Variant %s not supported by %s"
  msgstr "Вариант %s не поддерживается %s"
  
 -#: backend.c:10037
 +#: backend.c:10167
  #, c-format
  msgid "Startup failure on '%s'"
  msgstr "Ошибка при запуске программы '%s'"
  
 -#: backend.c:10068
 +#: backend.c:10198
  msgid "Waiting for first chess program"
  msgstr "Ждем первую шахматную программу"
  
 -#: backend.c:10073 backend.c:13945
 +#: backend.c:10203 backend.c:14076
  msgid "Waiting for second chess program"
  msgstr "Ждем вторую шахматную программу"
  
 -#: backend.c:10122
 +#: backend.c:10252
  msgid "Could not write on tourney file"
  msgstr ""
  
 -#: backend.c:10196
 +#: backend.c:10326
  msgid ""
  "You cannot replace an engine while it is engaged!\n"
  "Terminate its game first."
  msgstr ""
  
 -#: backend.c:10210
 +#: backend.c:10340
  msgid "No engine with the name you gave is installed"
  msgstr ""
  
 -#: backend.c:10212
 +#: backend.c:10342
  msgid ""
  "First change an engine by editing the participants list\n"
  "of the Tournament Options dialog"
  msgstr ""
  
 -#: backend.c:10213
 +#: backend.c:10343
  msgid "You can only change one engine at the time"
  msgstr ""
  
 -#: backend.c:10228 backend.c:10375
 +#: backend.c:10358 backend.c:10505
  #, c-format
  msgid "No engine %s is installed"
  msgstr ""
  
 -#: backend.c:10248
 +#: backend.c:10378
  msgid ""
  "You must supply a tournament file,\n"
  "for storing the tourney progress"
  msgstr ""
  
 -#: backend.c:10258
 +#: backend.c:10388
  msgid "Not enough participants"
  msgstr ""
  
 -#: backend.c:10459
 +#: backend.c:10589
  msgid "Bad tournament file"
  msgstr ""
  
 -#: backend.c:10471
 +#: backend.c:10601
  msgid "Waiting for other game(s)"
  msgstr ""
  
 -#: backend.c:10484
 +#: backend.c:10614
  msgid "No pairing engine specified"
  msgstr ""
  
 -#: backend.c:10961
 +#: backend.c:11092
  #, c-format
  msgid "Match %s vs. %s: final score %d-%d-%d"
  msgstr "Матч %s против %s: финальный результат %d-%d-%d"
  
 -#: backend.c:11423 backend.c:11454
 +#: backend.c:11554 backend.c:11585
  #, c-format
  msgid "Illegal move: %d.%s%s"
  msgstr "Неправильный ход: %d.%s%s"
  
 -#: backend.c:11443
 +#: backend.c:11574
  #, c-format
  msgid "Ambiguous move: %d.%s%s"
  msgstr "Неоднозначный ход: %d.%s%s"
  
 -#: backend.c:11496 backend.c:12505 backend.c:12698 backend.c:13059
 +#: backend.c:11627 backend.c:12636 backend.c:12829 backend.c:13190
  #, c-format
  msgid "Can't open \"%s\""
  msgstr "Не могу открыть файл \"%s\""
  
 -#: backend.c:11508 menus.c:116
 +#: backend.c:11639 menus.c:116
  msgid "Cannot build game list"
  msgstr "Не удалось создать список партий"
  
 -#: backend.c:11593
 +#: backend.c:11724
  msgid "No more games in this message"
  msgstr "В этом сообщении больше нет шахматных партий"
  
 -#: backend.c:11633
 +#: backend.c:11764
  msgid "No game has been loaded yet"
  msgstr "Нет загруженных шахматных партий"
  
 -#: backend.c:11637 backend.c:12486 ngamelist.c:129
 +#: backend.c:11768 backend.c:12617 ngamelist.c:129
  msgid "Can't back up any further"
  msgstr "Достигнуто начало списка"
  
 -#: backend.c:12058
 +#: backend.c:12189
  msgid "Game number out of range"
  msgstr "Номер партии - вне диапазона"
  
 -#: backend.c:12069
 +#: backend.c:12200
  msgid "Can't seek on game file"
  msgstr "Поиск в файлах записей партий не предусмотрен"
  
 -#: backend.c:12127
 +#: backend.c:12258
  msgid "Game not found in file"
  msgstr "Партия не найдена в файле"
  
 -#: backend.c:12255 backend.c:12582
 +#: backend.c:12386 backend.c:12713
  msgid "Bad FEN position in file"
  msgstr "Неправильная позиция формата FEN в файле"
  
 -#: backend.c:12407
 +#: backend.c:12538
  msgid "No moves in game"
  msgstr "Нет записанных ходов"
  
 -#: backend.c:12482
 +#: backend.c:12613
  msgid "No position has been loaded yet"
  msgstr "Нет загруженных позиций"
  
 -#: backend.c:12543 backend.c:12554
 +#: backend.c:12674 backend.c:12685
  msgid "Can't seek on position file"
  msgstr "Поиск в файлах позиций не предусмотрен"
  
 -#: backend.c:12561 backend.c:12573
 +#: backend.c:12692 backend.c:12704
  msgid "Position not found in file"
  msgstr "Позиция не найдена в файле"
  
 -#: backend.c:12613
 +#: backend.c:12744
  msgid "Black to play"
  msgstr "Ход черных"
  
 -#: backend.c:12616
 +#: backend.c:12747
  msgid "White to play"
  msgstr "Ход белых"
  
 -#: backend.c:12703 backend.c:13064
 +#: backend.c:12834 backend.c:13195
  msgid "Waiting for access to save file"
  msgstr ""
  
 -#: backend.c:12705
 +#: backend.c:12836
  msgid "Saving game"
  msgstr ""
  
 -#: backend.c:12706
 +#: backend.c:12837
  msgid "Bad Seek"
  msgstr ""
  
 -#: backend.c:13066
 +#: backend.c:13197
  msgid "Saving position"
  msgstr ""
  
 -#: backend.c:13192
 +#: backend.c:13323
  msgid ""
  "You have edited the game history.\n"
  "Use Reload Same Game and make your move again."
  msgstr ""
  
 -#: backend.c:13197
 +#: backend.c:13328
  msgid ""
  "You have entered too many moves.\n"
  "Back up to the correct position and try again."
  msgstr ""
  
 -#: backend.c:13202
 +#: backend.c:13333
  msgid ""
  "Displayed position is not current.\n"
  "Step forward to the correct position and try again."
  msgstr ""
  
 -#: backend.c:13249
 +#: backend.c:13380
  msgid "You have not made a move yet"
  msgstr "Вы еще не сделали ход"
  
 -#: backend.c:13270
 +#: backend.c:13401
  msgid ""
  "The cmail message is not loaded.\n"
  "Use Reload CMail Message and make your move again."
  msgstr ""
  
 -#: backend.c:13275
 +#: backend.c:13406
  msgid "No unfinished games"
  msgstr "Нет неоконченных партий"
  
 -#: backend.c:13281
 +#: backend.c:13412
  #, c-format
  msgid ""
  "You have already mailed a move.\n"
  "on the command line."
  msgstr ""
  
 -#: backend.c:13296
 +#: backend.c:13427
  msgid "Failed to invoke cmail"
  msgstr "Ошибка запуска cmail"
  
 -#: backend.c:13358
 +#: backend.c:13489
  #, c-format
  msgid "Waiting for reply from opponent\n"
  msgstr "Ожидание ответного хода\n"
  
 -#: backend.c:13380
 +#: backend.c:13511
  #, c-format
  msgid "Still need to make move for game\n"
  msgstr "Все еще ваша очередь ходить в этой партии\n"
  
 -#: backend.c:13384
 +#: backend.c:13515
  #, c-format
  msgid "Still need to make moves for both games\n"
  msgstr "Все еще ваша очередь ходить в обеих партиях\n"
  
 -#: backend.c:13388
 +#: backend.c:13519
  #, c-format
  msgid "Still need to make moves for all %d games\n"
  msgstr "Все еще ваш ход во всех %d партиях\n"
  
 -#: backend.c:13395
 +#: backend.c:13526
  #, c-format
  msgid "Still need to make a move for game %s\n"
  msgstr "Все еще ваш ход в партии %s\n"
  
 -#: backend.c:13401
 +#: backend.c:13532
  #, c-format
  msgid "No unfinished games\n"
  msgstr "Нет неоконченных партий\n"
  
 -#: backend.c:13403
 +#: backend.c:13534
  #, c-format
  msgid "Ready to send mail\n"
  msgstr "Можно отсылать почту\n"
  
 -#: backend.c:13408
 +#: backend.c:13539
  #, c-format
  msgid "Still need to make moves for games %s\n"
  msgstr "Все еще ваша очередь ходить в партиях %s\n"
  
 -#: backend.c:13612
 +#: backend.c:13743
  msgid "Edit comment"
  msgstr "Правка комментария"
  
 -#: backend.c:13614
 +#: backend.c:13745
  #, c-format
  msgid "Edit comment on %d.%s%s"
  msgstr "Правка комментария к %d.%s%s"
  
 -#: backend.c:13669
 +#: backend.c:13800
  #, c-format
  msgid "You are not observing a game"
  msgstr ""
  
 -#: backend.c:13777
 +#: backend.c:13908
  msgid "It is not White's turn"
  msgstr "Сейчас не ход белых"
  
 -#: backend.c:13858
 +#: backend.c:13989
  msgid "It is not Black's turn"
  msgstr "Сейчас не ход черных"
  
 -#: backend.c:13966
 +#: backend.c:14097
  #, c-format
  msgid "Starting %s chess program"
  msgstr ""
  
 -#: backend.c:13994 backend.c:15108
 +#: backend.c:14125 backend.c:15240
  msgid ""
  "Wait until your turn,\n"
  "or select Move Now"
  msgstr ""
  
 -#: backend.c:14128
 +#: backend.c:14259
  msgid "Training mode off"
  msgstr "Тренировка окончена"
  
 -#: backend.c:14136
 +#: backend.c:14267
  msgid "Training mode on"
  msgstr "Тренировка"
  
 -#: backend.c:14139
 +#: backend.c:14270
  msgid "Already at end of game"
  msgstr "Сыграны все ходы данной партии"
  
 -#: backend.c:14219
 +#: backend.c:14350
  msgid "Warning: You are still playing a game"
  msgstr "Предупреждение: вы все еще продолжаете играть"
  
 -#: backend.c:14222
 +#: backend.c:14353
  msgid "Warning: You are still observing a game"
  msgstr "Предупреждение: вы все еще наблюдаете за игрой"
  
 -#: backend.c:14225
 +#: backend.c:14356
  msgid "Warning: You are still examining a game"
  msgstr "Предупреждение: вы все еще изучаете игру"
  
 -#: backend.c:14292
 +#: backend.c:14423
  msgid "Click clock to clear board"
  msgstr ""
  
 -#: backend.c:14302
 +#: backend.c:14433
  msgid "Close ICS engine analyze..."
  msgstr ""
  
 -#: backend.c:14590
 +#: backend.c:14722
  msgid "That square is occupied"
  msgstr "Это поле занято"
  
 -#: backend.c:14614 backend.c:14640
 +#: backend.c:14746 backend.c:14772
  msgid "There is no pending offer on this move"
  msgstr "К данному ходу никаких предложений не сделано"
  
 -#: backend.c:14676 backend.c:14687
 +#: backend.c:14808 backend.c:14819
  msgid "Your opponent is not out of time"
  msgstr "У вашего соперника еще есть время"
  
 -#: backend.c:14753
 +#: backend.c:14885
  msgid "You must make your move before offering a draw"
  msgstr "Вы должны сделать свой ход прежде, чем предлагать ничью"
  
 -#: backend.c:15090
 +#: backend.c:15222
  msgid "You are not examining a game"
  msgstr "Не включен режим изучения шахматных партий"
  
 -#: backend.c:15094
 +#: backend.c:15226
  msgid "You can't revert while pausing"
  msgstr "Нельзя вернуться к началу пока выбрана \"Пауза\""
  
 -#: backend.c:15148 backend.c:15155
 +#: backend.c:15280 backend.c:15287
  msgid "It is your turn"
  msgstr "Ваш ход"
  
 -#: backend.c:15206 backend.c:15213 backend.c:15266 backend.c:15273
 +#: backend.c:15338 backend.c:15345 backend.c:15398 backend.c:15405
  msgid "Wait until your turn"
  msgstr "Подождите своей очереди ходить"
  
 -#: backend.c:15218
 +#: backend.c:15350
  msgid "No hint available"
  msgstr "Подсказок нет"
  
 -#: backend.c:15234 ngamelist.c:355
 +#: backend.c:15366 ngamelist.c:355
  #, fuzzy
  msgid "Game list not loaded or empty"
  msgstr "Нет загруженных шахматных партий"
  
 -#: backend.c:15241
 +#: backend.c:15373
  msgid "Book file exists! Try again for overwrite."
  msgstr ""
  
 -#: backend.c:15719
 +#: backend.c:15851
  #, c-format
  msgid "Error writing to %s chess program"
  msgstr "Ошибка записи на вход движка %s"
  
 -#: backend.c:15722 backend.c:15753
 +#: backend.c:15854 backend.c:15885
  #, c-format
  msgid "%s program exits in draw position (%s)"
  msgstr ""
  
 -#: backend.c:15748
 +#: backend.c:15880
  #, c-format
  msgid "Error: %s chess program (%s) exited unexpectedly"
  msgstr "Ошибка: движок %s (%s) завершил работу"
  
 -#: backend.c:15766
 +#: backend.c:15898
  #, c-format
  msgid "Error reading from %s chess program (%s)"
  msgstr "Ошибка чтения с выхода движка %s (%s)"
  
 -#: backend.c:16168
 +#: backend.c:16301
  #, c-format
  msgid "%s engine has too many options\n"
  msgstr ""
  
 -#: backend.c:16324
 +#: backend.c:16457
  msgid "Displayed move is not current"
  msgstr "Позиция не отвечает положению в игре"
  
 -#: backend.c:16333
 +#: backend.c:16466
  msgid "Could not parse move"
  msgstr "Невозможно интерпретировать ход"
  
 -#: backend.c:16458 backend.c:16480
 +#: backend.c:16591 backend.c:16613
  msgid "Both flags fell"
  msgstr "У обоих игроков время вышло"
  
 -#: backend.c:16460
 +#: backend.c:16593
  msgid "White's flag fell"
  msgstr "У белых упал флажок"
  
 -#: backend.c:16482
 +#: backend.c:16615
  msgid "Black's flag fell"
  msgstr "У черных упал флажок"
  
 -#: backend.c:16613
 +#: backend.c:16746
  msgid "Clock adjustment not allowed in auto-flag mode"
  msgstr ""
  
 -#: backend.c:17448
 +#: backend.c:17585
  msgid "Bad FEN position in clipboard"
  msgstr "Позиция в буфере обмена не соответствует формату FEN"
  
@@@ -900,7 -896,7 +900,7 @@@ msgstr "
  msgid "First you must specify an existing tourney file to clone"
  msgstr ""
  
 -#: dialogs.c:332 dialogs.c:1320
 +#: dialogs.c:332 dialogs.c:1322
  msgid "# no engines are installed"
  msgstr ""
  
@@@ -968,7 -964,7 +968,7 @@@ msgstr "Периодически обн
  msgid "Play Move(s) of Clicked PV (Analysis)"
  msgstr ""
  
 -#: dialogs.c:379 dialogs.c:514 menus.c:728
 +#: dialogs.c:379 dialogs.c:515 menus.c:728
  msgid "Ponder Next Move"
  msgstr "Думать всегда"
  
@@@ -1092,7 -1088,7 +1092,7 @@@ msgid "Holdings Size:
  msgstr ""
  
  #: dialogs.c:429
 -msgid "fairy"
 +msgid "ASEAN"
  msgstr ""
  
  #: dialogs.c:430
@@@ -1164,999 -1160,995 +1164,999 @@@ msgid "xiangqi (9x10)
  msgstr ""
  
  #: dialogs.c:447
 -msgid " "
 +msgid "fairy"
  msgstr ""
  
 -#: dialogs.c:448
 +#: dialogs.c:449
  msgid "courier (12x8)"
  msgstr ""
  
 -#: dialogs.c:465
 +#: dialogs.c:466
  #, c-format
  msgid "Warning: second engine (%s) does not support this!"
  msgstr "Предупреждение: второй движок (%s) не поддерживает это!"
  
 -#: dialogs.c:488
 +#: dialogs.c:489
  #, c-format
  msgid "Only bughouse is not available in viewer mode"
  msgstr ""
  
 -#: dialogs.c:489
 +#: dialogs.c:490
  #, c-format
  msgid ""
  "All variants not supported by first engine\n"
  "(currently %s) are disabled"
  msgstr ""
  
 -#: dialogs.c:490
 +#: dialogs.c:491
  msgid "New Variant"
  msgstr "Варианты"
  
 -#: dialogs.c:515
 +#: dialogs.c:516
  msgid "Maximum Number of CPUs per Engine:"
  msgstr "Max число CPU:"
  
 -#: dialogs.c:516
 +#: dialogs.c:517
  msgid "Polygot Directory:"
  msgstr ""
  
 -#: dialogs.c:517
 +#: dialogs.c:518
  msgid "Hash-Table Size (MB):"
  msgstr "Размер хеша (МБ):"
  
 -#: dialogs.c:518
 +#: dialogs.c:519
  msgid "Nalimov EGTB Path:"
  msgstr "Путь к ЭБД:"
  
 -#: dialogs.c:519
 +#: dialogs.c:520
  msgid "EGTB Cache Size (MB):"
  msgstr "Кеш ЭБД (МБ):"
  
 -#: dialogs.c:520
 +#: dialogs.c:521
  msgid "Use GUI Book"
  msgstr ""
  
 -#: dialogs.c:521
 +#: dialogs.c:522
  msgid "Opening-Book Filename:"
  msgstr ""
  
 -#: dialogs.c:522
 +#: dialogs.c:523
  msgid "Book Depth (moves):"
  msgstr "Глубина книги:"
  
 -#: dialogs.c:523
 +#: dialogs.c:524
  msgid "Book Variety (0) vs. Strength (100):"
  msgstr "Варьирование:"
  
 -#: dialogs.c:524
 +#: dialogs.c:525
  msgid "Engine #1 Has Own Book"
  msgstr "Своя книга у движка 1"
  
 -#: dialogs.c:525
 +#: dialogs.c:526
  msgid "Engine #2 Has Own Book          "
  msgstr ""
  
 -#: dialogs.c:534
 +#: dialogs.c:535
  msgid "Common Engine Settings"
  msgstr "Общие настройки движков"
  
 -#: dialogs.c:540
 +#: dialogs.c:541
  msgid "Detect all Mates"
  msgstr "Определять мат"
  
 -#: dialogs.c:541
 +#: dialogs.c:542
  msgid "Verify Engine Result Claims"
  msgstr "Проверять требования движка"
  
 -#: dialogs.c:542
 +#: dialogs.c:543
  msgid "Draw if Insufficient Mating Material"
  msgstr "Ничья при нехватке материала"
  
 -#: dialogs.c:543
 +#: dialogs.c:544
  msgid "Adjudicate Trivial Draws (3-Move Delay)"
  msgstr "Ничья в технич. окончаниях"
  
 -#: dialogs.c:544
 +#: dialogs.c:545
  msgid "N-Move Rule:"
  msgstr ""
  
 -#: dialogs.c:545
 +#: dialogs.c:546
  msgid "N-fold Repeats:"
  msgstr ""
  
 -#: dialogs.c:546
 +#: dialogs.c:547
  msgid "Draw after N Moves Total:"
  msgstr "Присудить ничью после"
  
 -#: dialogs.c:547
 +#: dialogs.c:548
  msgid "Win / Loss Threshold:"
  msgstr "Победа/поражение при перевесе в"
  
 -#: dialogs.c:548
 +#: dialogs.c:549
  msgid "Negate Score of Engine #1"
  msgstr "Оценка движка 1 - абсолютная"
  
 -#: dialogs.c:549
 +#: dialogs.c:550
  msgid "Negate Score of Engine #2"
  msgstr "Оценка движка 2 - абсолютная"
  
 -#: dialogs.c:556
 +#: dialogs.c:557
  #, fuzzy
  msgid "Adjudicate non-ICS Games"
  msgstr "Присудить победу белым"
  
 -#: dialogs.c:569
 +#: dialogs.c:570
  msgid "Auto-Kibitz"
  msgstr ""
  
 -#: dialogs.c:570
 +#: dialogs.c:571
  msgid "Auto-Comment"
  msgstr "Комментарии"
  
 -#: dialogs.c:571
 +#: dialogs.c:572
  msgid "Auto-Observe"
  msgstr "Следить за игрой"
  
 -#: dialogs.c:572
 +#: dialogs.c:573
  msgid "Auto-Raise Board"
  msgstr "Раскрывать доску"
  
 -#: dialogs.c:573
 +#: dialogs.c:574
  msgid "Auto-Create Logon Script"
  msgstr ""
  
 -#: dialogs.c:574
 +#: dialogs.c:575
  msgid "Background Observe while Playing"
  msgstr "Следить в фоне"
  
 -#: dialogs.c:575
 +#: dialogs.c:576
  msgid "Dual Board for Background-Observed Game"
  msgstr "Двойная доска"
  
 -#: dialogs.c:576
 +#: dialogs.c:577
  msgid "Get Move List"
  msgstr "Запрашивать запись ходов"
  
 -#: dialogs.c:577
 +#: dialogs.c:578
  msgid "Quiet Play"
  msgstr "Спокойная игра"
  
 -#: dialogs.c:578
 +#: dialogs.c:579
  msgid "Seek Graph"
  msgstr "График поиска"
  
 -#: dialogs.c:579
 +#: dialogs.c:580
  msgid "Auto-Refresh Seek Graph"
  msgstr "Автообновление"
  
 -#: dialogs.c:580
 +#: dialogs.c:581
  msgid "Auto-InputBox PopUp"
  msgstr ""
  
 -#: dialogs.c:581
 +#: dialogs.c:582
 +msgid "Quit after game"
 +msgstr ""
 +
 +#: dialogs.c:583
  msgid "Premove"
  msgstr "Предварительный ход"
  
 -#: dialogs.c:582
 +#: dialogs.c:584
  msgid "Premove for White"
  msgstr ""
  
 -#: dialogs.c:583
 +#: dialogs.c:585
  msgid "First White Move:"
  msgstr "1-й ход белых"
  
 -#: dialogs.c:584
 +#: dialogs.c:586
  msgid "Premove for Black"
  msgstr ""
  
 -#: dialogs.c:585
 +#: dialogs.c:587
  msgid "First Black Move:"
  msgstr "1-й ход черных"
  
 -#: dialogs.c:587
 +#: dialogs.c:589
  msgid "Alarm"
  msgstr "Звонок"
  
 -#: dialogs.c:588
 +#: dialogs.c:590
  msgid "Alarm Time (msec):"
  msgstr ""
  
 -#: dialogs.c:590
 +#: dialogs.c:592
  msgid "Colorize Messages"
  msgstr ""
  
 -#: dialogs.c:591
 +#: dialogs.c:593
  msgid "Shout Text Colors:"
  msgstr ""
  
 -#: dialogs.c:592
 +#: dialogs.c:594
  msgid "S-Shout Text Colors:"
  msgstr ""
  
 -#: dialogs.c:593
 +#: dialogs.c:595
  msgid "Channel #1 Text Colors:"
  msgstr ""
  
 -#: dialogs.c:594
 +#: dialogs.c:596
  msgid "Other Channel Text Colors:"
  msgstr ""
  
 -#: dialogs.c:595
 +#: dialogs.c:597
  msgid "Kibitz Text Colors:"
  msgstr ""
  
 -#: dialogs.c:596
 +#: dialogs.c:598
  msgid "Tell Text Colors:"
  msgstr ""
  
 -#: dialogs.c:597
 +#: dialogs.c:599
  msgid "Challenge Text Colors:"
  msgstr ""
  
 -#: dialogs.c:598
 +#: dialogs.c:600
  msgid "Request Text Colors:"
  msgstr ""
  
 -#: dialogs.c:599
 +#: dialogs.c:601
  msgid "Seek Text Colors:"
  msgstr ""
  
 -#: dialogs.c:606
 +#: dialogs.c:608
  msgid "ICS Options"
  msgstr "Настройки соединения с ICS"
  
 -#: dialogs.c:611
 +#: dialogs.c:613
  msgid "Exact position match"
  msgstr ""
  
 -#: dialogs.c:611
 +#: dialogs.c:613
  msgid "Shown position is subset"
  msgstr ""
  
 -#: dialogs.c:611
 +#: dialogs.c:613
  msgid "Same material with exactly same Pawn chain"
  msgstr ""
  
 -#: dialogs.c:612
 +#: dialogs.c:614
  msgid "Same material"
  msgstr ""
  
 -#: dialogs.c:612
 +#: dialogs.c:614
  msgid "Material range (top board half optional)"
  msgstr ""
  
 -#: dialogs.c:612
 +#: dialogs.c:614
  msgid "Material difference (optional stuff balanced)"
  msgstr ""
  
 -#: dialogs.c:624
 +#: dialogs.c:626
  msgid "Auto-Display Tags"
  msgstr ""
  
 -#: dialogs.c:625
 +#: dialogs.c:627
  msgid "Auto-Display Comment"
  msgstr ""
  
 -#: dialogs.c:626
 +#: dialogs.c:628
  msgid ""
  "Auto-Play speed of loaded games\n"
  "(0 = instant, -1 = off):"
  msgstr ""
  
 -#: dialogs.c:627
 +#: dialogs.c:629
  msgid "Seconds per Move:"
  msgstr ""
  
 -#: dialogs.c:628
 +#: dialogs.c:630
  msgid ""
  "\n"
  "options to use in game-viewer mode:"
  msgstr ""
  
 -#: dialogs.c:630
 +#: dialogs.c:632
  msgid ""
  "\n"
  "Thresholds for position filtering in game list:"
  msgstr ""
  
 -#: dialogs.c:631
 +#: dialogs.c:633
  msgid "Elo of strongest player at least:"
  msgstr ""
  
 -#: dialogs.c:632
 +#: dialogs.c:634
  msgid "Elo of weakest player at least:"
  msgstr ""
  
 -#: dialogs.c:633
 +#: dialogs.c:635
  #, fuzzy
  msgid "No games before year:"
  msgstr "Нет загруженных шахматных партий"
  
 -#: dialogs.c:634
 +#: dialogs.c:636
  msgid "Minimum nr consecutive positions:"
  msgstr ""
  
 -#: dialogs.c:635
 +#: dialogs.c:637
  msgid "Search mode:"
  msgstr ""
  
 -#: dialogs.c:636
 +#: dialogs.c:638
  msgid "Also match reversed colors"
  msgstr ""
  
 -#: dialogs.c:637
 +#: dialogs.c:639
  msgid "Also match left-right flipped position"
  msgstr ""
  
 -#: dialogs.c:645
 +#: dialogs.c:647
  msgid "Load Game Options"
  msgstr "Параметры загрузки"
  
 -#: dialogs.c:657
 +#: dialogs.c:659
  msgid "Auto-Save Games"
  msgstr ""
  
 -#: dialogs.c:658
 +#: dialogs.c:660
  msgid "Own Games Only"
  msgstr ""
  
 -#: dialogs.c:659
 +#: dialogs.c:661
  msgid "Save Games on File:"
  msgstr ""
  
 -#: dialogs.c:660
 +#: dialogs.c:662
  msgid "Save Final Positions on File:"
  msgstr ""
  
 -#: dialogs.c:661
 +#: dialogs.c:663
  msgid "PGN Event Header:"
  msgstr ""
  
 -#: dialogs.c:662
 +#: dialogs.c:664
  msgid "Old Save Style (as opposed to PGN)"
  msgstr ""
  
 -#: dialogs.c:663
 +#: dialogs.c:665
  msgid "Include Number Tag in tourney PGN"
  msgstr ""
  
 -#: dialogs.c:664
 +#: dialogs.c:666
  msgid "Save Score/Depth Info in PGN"
  msgstr ""
  
 -#: dialogs.c:665
 +#: dialogs.c:667
  msgid "Save Out-of-Book Info in PGN           "
  msgstr ""
  
 -#: dialogs.c:672
 +#: dialogs.c:674
  msgid "Save Game Options"
  msgstr "Настройки сохранения"
  
 -#: dialogs.c:681
 +#: dialogs.c:683
  msgid "No Sound"
  msgstr "Без звука"
  
 -#: dialogs.c:682
 +#: dialogs.c:684
  msgid "Default Beep"
  msgstr "Простой сигнал"
  
 -#: dialogs.c:683
 +#: dialogs.c:685
  msgid "Above WAV File"
  msgstr ""
  
 -#: dialogs.c:684
 +#: dialogs.c:686
  msgid "Car Horn"
  msgstr ""
  
 -#: dialogs.c:685
 +#: dialogs.c:687
  msgid "Cymbal"
  msgstr ""
  
 -#: dialogs.c:686
 +#: dialogs.c:688
  msgid "Ding"
  msgstr ""
  
 -#: dialogs.c:687
 +#: dialogs.c:689
  msgid "Gong"
  msgstr ""
  
 -#: dialogs.c:688
 +#: dialogs.c:690
  msgid "Laser"
  msgstr ""
  
 -#: dialogs.c:689
 +#: dialogs.c:691
  msgid "Penalty"
  msgstr ""
  
 -#: dialogs.c:690
 +#: dialogs.c:692
  msgid "Phone"
  msgstr ""
  
 -#: dialogs.c:691
 +#: dialogs.c:693
  msgid "Pop"
  msgstr ""
  
 -#: dialogs.c:692
 +#: dialogs.c:694
  msgid "Slap"
  msgstr ""
  
 -#: dialogs.c:693
 +#: dialogs.c:695
  msgid "Wood Thunk"
  msgstr ""
  
 -#: dialogs.c:695
 +#: dialogs.c:697
  msgid "User File"
  msgstr ""
  
 -#: dialogs.c:717
 +#: dialogs.c:719
  msgid "User WAV File:"
  msgstr ""
  
 -#: dialogs.c:718
 +#: dialogs.c:720
  msgid "Sound Program:"
  msgstr ""
  
 -#: dialogs.c:719
 +#: dialogs.c:721
  msgid "Try-Out Sound:"
  msgstr ""
  
 -#: dialogs.c:720
 +#: dialogs.c:722
  msgid "Play"
  msgstr "Послушать"
  
 -#: dialogs.c:721
 +#: dialogs.c:723
  msgid "Move:"
  msgstr ""
  
 -#: dialogs.c:722
 +#: dialogs.c:724
  msgid "Win:"
  msgstr ""
  
 -#: dialogs.c:723
 +#: dialogs.c:725
  msgid "Lose:"
  msgstr ""
  
 -#: dialogs.c:724
 +#: dialogs.c:726
  msgid "Draw:"
  msgstr ""
  
 -#: dialogs.c:725
 +#: dialogs.c:727
  msgid "Unfinished:"
  msgstr ""
  
 -#: dialogs.c:726
 +#: dialogs.c:728
  msgid "Alarm:"
  msgstr ""
  
 -#: dialogs.c:727
 +#: dialogs.c:729
  msgid "Challenge:"
  msgstr ""
  
 -#: dialogs.c:729
 +#: dialogs.c:731
  msgid "Sounds Directory:"
  msgstr ""
  
 -#: dialogs.c:730
 +#: dialogs.c:732
  msgid "Shout:"
  msgstr ""
  
 -#: dialogs.c:731
 +#: dialogs.c:733
  msgid "S-Shout:"
  msgstr ""
  
 -#: dialogs.c:732
 +#: dialogs.c:734
  msgid "Channel:"
  msgstr ""
  
 -#: dialogs.c:733
 +#: dialogs.c:735
  msgid "Channel 1:"
  msgstr ""
  
 -#: dialogs.c:734
 +#: dialogs.c:736
  msgid "Tell:"
  msgstr ""
  
 -#: dialogs.c:735
 +#: dialogs.c:737
  msgid "Kibitz:"
  msgstr ""
  
 -#: dialogs.c:736
 +#: dialogs.c:738
  msgid "Request:"
  msgstr ""
  
 -#: dialogs.c:737
 +#: dialogs.c:739
  msgid "Seek:"
  msgstr ""
  
 -#: dialogs.c:753
 +#: dialogs.c:755
  msgid "Sound Options"
  msgstr "Звуки"
  
 -#: dialogs.c:774
 +#: dialogs.c:776
  msgid "White Piece Color:"
  msgstr ""
  
  #. TRANSLATORS: R = single letter for the color red
 -#: dialogs.c:777 dialogs.c:786 dialogs.c:792 dialogs.c:798 dialogs.c:804
 -#: dialogs.c:810
 +#: dialogs.c:779 dialogs.c:788 dialogs.c:794 dialogs.c:800 dialogs.c:806
 +#: dialogs.c:812
  msgid "R"
  msgstr ""
  
  #. TRANSLATORS: G = single letter for the color green
 -#: dialogs.c:779 dialogs.c:787 dialogs.c:793 dialogs.c:799 dialogs.c:805
 -#: dialogs.c:811
 +#: dialogs.c:781 dialogs.c:789 dialogs.c:795 dialogs.c:801 dialogs.c:807
 +#: dialogs.c:813
  msgid "G"
  msgstr ""
  
  #. TRANSLATORS: B = single letter for the color blue
 -#: dialogs.c:781 dialogs.c:788 dialogs.c:794 dialogs.c:800 dialogs.c:806
 -#: dialogs.c:812
 +#: dialogs.c:783 dialogs.c:790 dialogs.c:796 dialogs.c:802 dialogs.c:808
 +#: dialogs.c:814
  msgid "B"
  msgstr ""
  
  #. TRANSLATORS: D = single letter to make a color darker
 -#: dialogs.c:783 dialogs.c:789 dialogs.c:795 dialogs.c:801 dialogs.c:807
 -#: dialogs.c:813
 +#: dialogs.c:785 dialogs.c:791 dialogs.c:797 dialogs.c:803 dialogs.c:809
 +#: dialogs.c:815
  msgid "D"
  msgstr ""
  
 -#: dialogs.c:784
 +#: dialogs.c:786
  msgid "Black Piece Color:"
  msgstr "Черные фигуры"
  
 -#: dialogs.c:790
 +#: dialogs.c:792
  msgid "Light Square Color:"
  msgstr "Белые поля"
  
 -#: dialogs.c:796
 +#: dialogs.c:798
  msgid "Dark Square Color:"
  msgstr "Черные поля"
  
 -#: dialogs.c:802
 +#: dialogs.c:804
  msgid "Highlight Color:"
  msgstr "Выделенное поле"
  
 -#: dialogs.c:808
 +#: dialogs.c:810
  msgid "Premove Highlight Color:"
  msgstr "Предварит. ход"
  
 -#: dialogs.c:814
 +#: dialogs.c:816
  msgid "Flip Pieces Shogi Style        (Colored buttons restore default)"
  msgstr ""
  
 -#: dialogs.c:816
 +#: dialogs.c:818
  msgid "Mono Mode"
  msgstr "Монохромная"
  
 -#: dialogs.c:817
 +#: dialogs.c:819
  msgid "Line Gap ( -1 = default for board size):"
  msgstr ""
  
 -#: dialogs.c:818
 +#: dialogs.c:820
  msgid "Use Board Textures"
  msgstr ""
  
 -#: dialogs.c:819
 +#: dialogs.c:821
  msgid "Light-Squares Texture File:"
  msgstr ""
  
 -#: dialogs.c:820
 +#: dialogs.c:822
  msgid "Dark-Squares Texture File:"
  msgstr ""
  
 -#: dialogs.c:821
 +#: dialogs.c:823
  msgid "Use external piece bitmaps with their own colors"
  msgstr ""
  
 -#: dialogs.c:822
 +#: dialogs.c:824
  msgid "Directory with Pieces Images:"
  msgstr ""
  
 -#: dialogs.c:872
 +#: dialogs.c:874
  msgid "Board Options"
  msgstr "Настройки доски"
  
 -#: dialogs.c:925 menus.c:634
 +#: dialogs.c:927 menus.c:634
  msgid "ICS text menu"
  msgstr ""
  
 -#: dialogs.c:947
 +#: dialogs.c:949
  msgid "clear"
  msgstr ""
  
 -#: dialogs.c:948 dialogs.c:1036
 +#: dialogs.c:950 dialogs.c:1038
  msgid "save changes"
  msgstr ""
  
 -#: dialogs.c:1051
 +#: dialogs.c:1053
  #, fuzzy
  msgid "Edit book"
  msgstr "Правка"
  
 -#: dialogs.c:1051 menus.c:636
 +#: dialogs.c:1053 menus.c:636
  msgid "Tags"
  msgstr "Описание"
  
 -#: dialogs.c:1193
 +#: dialogs.c:1195
  msgid "ICS input box"
  msgstr ""
  
 -#: dialogs.c:1225
 +#: dialogs.c:1227
  msgid "Type a move"
  msgstr ""
  
 -#: dialogs.c:1251
 +#: dialogs.c:1253
  msgid "Engine has no options"
  msgstr ""
  
 -#: dialogs.c:1253
 +#: dialogs.c:1255
  msgid "Engine Settings"
  msgstr ""
  
 -#: dialogs.c:1278
 +#: dialogs.c:1280
  msgid "Select engine from list:"
  msgstr ""
  
 -#: dialogs.c:1281
 +#: dialogs.c:1283
  msgid "or specify one below:"
  msgstr ""
  
 -#: dialogs.c:1282
 +#: dialogs.c:1284
  msgid "Nickname (optional):"
  msgstr ""
  
 -#: dialogs.c:1283
 +#: dialogs.c:1285
  msgid "Use nickname in PGN player tags of engine-engine games"
  msgstr ""
  
 -#: dialogs.c:1284
 +#: dialogs.c:1286
  msgid "Engine Directory:"
  msgstr ""
  
 -#: dialogs.c:1285
 +#: dialogs.c:1287
  msgid "Engine Command:"
  msgstr ""
  
 -#: dialogs.c:1286
 +#: dialogs.c:1288
  msgid "(Directory will be derived from engine path when empty)"
  msgstr ""
  
 -#: dialogs.c:1287
 +#: dialogs.c:1289
  msgid "UCI"
  msgstr ""
  
 -#: dialogs.c:1288
 +#: dialogs.c:1290
  msgid "WB protocol v1 (do not wait for engine features)"
  msgstr ""
  
 -#: dialogs.c:1289
 +#: dialogs.c:1291
  msgid "Must not use GUI book"
  msgstr ""
  
 -#: dialogs.c:1290
 +#: dialogs.c:1292
  msgid "Add this engine to the list"
  msgstr ""
  
 -#: dialogs.c:1291
 +#: dialogs.c:1293
  msgid "Force current variant with this engine"
  msgstr ""
  
 -#: dialogs.c:1341
 +#: dialogs.c:1343
  msgid "Load first engine"
  msgstr ""
  
 -#: dialogs.c:1347
 +#: dialogs.c:1349
  msgid "Load second engine"
  msgstr ""
  
 -#: dialogs.c:1370
 +#: dialogs.c:1372
  msgid "shuffle"
  msgstr ""
  
 -#: dialogs.c:1371
 +#: dialogs.c:1373
  msgid "Start-position number:"
  msgstr "Номер позиции:"
  
 -#: dialogs.c:1372
 +#: dialogs.c:1374
  #, fuzzy
  msgid "randomize"
  msgstr "Случайно"
  
 -#: dialogs.c:1373
 +#: dialogs.c:1375
  msgid "pick fixed"
  msgstr ""
  
 -#: dialogs.c:1390
 +#: dialogs.c:1392
  msgid "New Shuffle Game"
  msgstr "Новая в смешанные шахматы..."
  
 -#: dialogs.c:1409
 +#: dialogs.c:1411
  msgid "classical"
  msgstr ""
  
 -#: dialogs.c:1410
 +#: dialogs.c:1412
  msgid "incremental"
  msgstr ""
  
 -#: dialogs.c:1411
 +#: dialogs.c:1413
  msgid "fixed max"
  msgstr ""
  
 -#: dialogs.c:1412
 +#: dialogs.c:1414
  msgid "Moves per session:"
  msgstr ""
  
 -#: dialogs.c:1413
 +#: dialogs.c:1415
  msgid "Initial time (min):"
  msgstr ""
  
 -#: dialogs.c:1414
 +#: dialogs.c:1416
  msgid "Increment or max (sec/move):"
  msgstr ""
  
 -#: dialogs.c:1415
 +#: dialogs.c:1417
  #, fuzzy
  msgid "Time-Odds factors:"
  msgstr "Фактор времени движков:"
  
 -#: dialogs.c:1416
 +#: dialogs.c:1418
  #, fuzzy
  msgid "Engine #1"
  msgstr "Движок"
  
 -#: dialogs.c:1417
 +#: dialogs.c:1419
  #, fuzzy
  msgid "Engine #2 / Human"
  msgstr "Своя книга у движка 1"
  
 -#: dialogs.c:1457 dialogs.c:1460 dialogs.c:1465 dialogs.c:1466
 +#: dialogs.c:1459 dialogs.c:1462 dialogs.c:1467 dialogs.c:1468
  #: gtk/xoptions.c:191
  msgid "Unused"
  msgstr ""
  
 -#: dialogs.c:1478
 +#: dialogs.c:1480
  msgid "Time Control"
  msgstr ""
  
 -#: dialogs.c:1507
 +#: dialogs.c:1509
  msgid "Error writing to chess program"
  msgstr "Ошибка подключения к шахматной программе"
  
 -#: dialogs.c:1574
 +#: dialogs.c:1576
  #, fuzzy
  msgid "Cancel"
  msgstr "Отмена"
  
 -#: dialogs.c:1579 dialogs.c:1971 dialogs.c:1975
 +#: dialogs.c:1581 dialogs.c:1973 dialogs.c:1977
  msgid "King"
  msgstr "Король"
  
 -#: dialogs.c:1582
 +#: dialogs.c:1584
  msgid "Captain"
  msgstr ""
  
 -#: dialogs.c:1583
 +#: dialogs.c:1585
  msgid "Lieutenant"
  msgstr ""
  
 -#: dialogs.c:1584
 +#: dialogs.c:1586
  msgid "General"
  msgstr "Общие..."
  
 -#: dialogs.c:1585
 +#: dialogs.c:1587
  msgid "Warlord"
  msgstr ""
  
 -#: dialogs.c:1587 dialogs.c:1970 dialogs.c:1974 dialogs.c:1993
 +#: dialogs.c:1589 dialogs.c:1972 dialogs.c:1976 dialogs.c:1995
  msgid "Knight"
  msgstr "Конь"
  
 -#: dialogs.c:1588 dialogs.c:1970 dialogs.c:1974 dialogs.c:1993
 +#: dialogs.c:1590 dialogs.c:1972 dialogs.c:1976 dialogs.c:1995
  msgid "Bishop"
  msgstr "Слон"
  
 -#: dialogs.c:1589 dialogs.c:1970 dialogs.c:1974 dialogs.c:1993
 +#: dialogs.c:1591 dialogs.c:1972 dialogs.c:1976 dialogs.c:1995
  msgid "Rook"
  msgstr "Ладья"
  
 -#: dialogs.c:1593 dialogs.c:1972 dialogs.c:1976
 +#: dialogs.c:1595 dialogs.c:1974 dialogs.c:1978
  msgid "Archbishop"
  msgstr "Архиепископ"
  
 -#: dialogs.c:1594 dialogs.c:1972 dialogs.c:1976
 +#: dialogs.c:1596 dialogs.c:1974 dialogs.c:1978
  msgid "Chancellor"
  msgstr "Канцлер"
  
 -#: dialogs.c:1596 dialogs.c:1971 dialogs.c:1975 dialogs.c:1993
 +#: dialogs.c:1598 dialogs.c:1973 dialogs.c:1977 dialogs.c:1995
  msgid "Queen"
  msgstr "Ферзь"
  
 -#: dialogs.c:1600
 +#: dialogs.c:1602
  msgid "Defer"
  msgstr ""
  
 -#: dialogs.c:1601 dialogs.c:1972 dialogs.c:1976
 +#: dialogs.c:1603 dialogs.c:1974 dialogs.c:1978
  msgid "Promote"
  msgstr "Превратить"
  
 -#: dialogs.c:1616
 +#: dialogs.c:1618
  msgid "Chat partner:"
  msgstr ""
  
 -#: dialogs.c:1701
 +#: dialogs.c:1703
  msgid "Chat box"
  msgstr ""
  
 -#: dialogs.c:1742
 +#: dialogs.c:1744
  msgid "factory"
  msgstr "Стандарт"
  
 -#: dialogs.c:1743
 +#: dialogs.c:1745
  msgid "up"
  msgstr "Вверх"
  
 -#: dialogs.c:1744
 +#: dialogs.c:1746
  msgid "down"
  msgstr "Вниз"
  
 -#: dialogs.c:1762
 +#: dialogs.c:1764
  msgid "No tag selected"
  msgstr ""
  
 -#: dialogs.c:1793
 +#: dialogs.c:1795
  #, fuzzy
  msgid "Game-list options"
  msgstr "Параметры загрузки"
  
 -#: dialogs.c:1869 dialogs.c:1883
 +#: dialogs.c:1871 dialogs.c:1885
  msgid "Error"
  msgstr "Ошибка"
  
 -#: dialogs.c:1906
 +#: dialogs.c:1908
  msgid "Fatal Error"
  msgstr "Неисправимая ошибка"
  
 -#: dialogs.c:1906
 +#: dialogs.c:1908
  msgid "Exiting"
  msgstr "Выход"
  
 -#: dialogs.c:1917
 +#: dialogs.c:1919
  msgid "Information"
  msgstr "Информация"
  
 -#: dialogs.c:1924
 +#: dialogs.c:1926
  msgid "Note"
  msgstr "Примечание"
  
 -#: dialogs.c:1970 dialogs.c:2245 dialogs.c:2248
 +#: dialogs.c:1972 dialogs.c:2252 dialogs.c:2255
  msgid "White"
  msgstr "Белые"
  
 -#: dialogs.c:1970 dialogs.c:1974 dialogs.c:1993
 +#: dialogs.c:1972 dialogs.c:1976 dialogs.c:1995
  msgid "Pawn"
  msgstr "Пешка"
  
 -#: dialogs.c:1971 dialogs.c:1975
 +#: dialogs.c:1973 dialogs.c:1977
  msgid "Elephant"
  msgstr "Слон (стар.)"
  
 -#: dialogs.c:1971 dialogs.c:1975
 +#: dialogs.c:1973 dialogs.c:1977
  msgid "Cannon"
  msgstr "Пушка"
  
 -#: dialogs.c:1972 dialogs.c:1976
 +#: dialogs.c:1974 dialogs.c:1978
  msgid "Demote"
  msgstr "Разжаловать"
  
 -#: dialogs.c:1973 dialogs.c:1977
 +#: dialogs.c:1975 dialogs.c:1979
  msgid "Empty square"
  msgstr "Пустое поле"
  
 -#: dialogs.c:1973 dialogs.c:1977
 +#: dialogs.c:1975 dialogs.c:1979
  msgid "Clear board"
  msgstr "Очистить доску"
  
 -#: dialogs.c:1974 dialogs.c:2257 dialogs.c:2260
 +#: dialogs.c:1976 dialogs.c:2264 dialogs.c:2267
  msgid "Black"
  msgstr "Черные"
  
 -#: dialogs.c:2073 menus.c:787
 +#: dialogs.c:2075 menus.c:787
  msgid "File"
  msgstr "Файл"
  
 -#: dialogs.c:2074 menus.c:788
 +#: dialogs.c:2076 menus.c:788
  msgid "Edit"
  msgstr "Правка"
  
 -#: dialogs.c:2075 menus.c:789
 +#: dialogs.c:2077 menus.c:789
  msgid "View"
  msgstr "Вид"
  
 -#: dialogs.c:2076 menus.c:790
 +#: dialogs.c:2078 menus.c:790
  msgid "Mode"
  msgstr "Режим"
  
 -#: dialogs.c:2077 menus.c:791
 +#: dialogs.c:2079 menus.c:791
  msgid "Action"
  msgstr "Игра"
  
 -#: dialogs.c:2078 menus.c:792
 +#: dialogs.c:2080 menus.c:792
  msgid "Engine"
  msgstr "Движок"
  
 -#: dialogs.c:2079 menus.c:793
 +#: dialogs.c:2081 menus.c:793
  msgid "Options"
  msgstr "Настройки"
  
 -#: dialogs.c:2080 menus.c:794
 +#: dialogs.c:2082 menus.c:794
  msgid "Help"
  msgstr "Справка"
  
 -#: dialogs.c:2090
 +#: dialogs.c:2092
  msgid "<<"
  msgstr ""
  
 -#: dialogs.c:2091
 +#: dialogs.c:2093
  msgid "<"
  msgstr ""
  
 -#: dialogs.c:2093
 +#: dialogs.c:2095
  msgid ">"
  msgstr ""
  
 -#: dialogs.c:2094
 +#: dialogs.c:2096
  msgid ">>"
  msgstr ""
  
 -#: dialogs.c:2364
 +#: dialogs.c:2371
  msgid "Directories:"
  msgstr ""
  
 -#: dialogs.c:2365
 +#: dialogs.c:2372
  #, fuzzy
  msgid "Files:"
  msgstr "Файл"
  
 -#: dialogs.c:2366
 +#: dialogs.c:2373
  msgid "by name"
  msgstr ""
  
 -#: dialogs.c:2367
 +#: dialogs.c:2374
  msgid "by type"
  msgstr ""
  
 -#: dialogs.c:2370
 +#: dialogs.c:2377
  #, fuzzy
  msgid "Filename:"
  msgstr "Фильтр"
  
 -#: dialogs.c:2371
 +#: dialogs.c:2378
  msgid "New directory"
  msgstr ""
  
 -#: dialogs.c:2372
 +#: dialogs.c:2379
  #, fuzzy
  msgid "File type:"
  msgstr "Фильтр"
  
 -#: dialogs.c:2447
 +#: dialogs.c:2454
  #, fuzzy
  msgid "Contents of"
  msgstr "Комментарии"
  
 -#: dialogs.c:2473
 +#: dialogs.c:2480
  msgid "  next page"
  msgstr ""
  
 -#: dialogs.c:2495
 +#: dialogs.c:2502
  msgid "FIRST TYPE DIRECTORY NAME HERE"
  msgstr ""
  
 -#: dialogs.c:2496
 +#: dialogs.c:2503
  msgid "TRY ANOTHER NAME"
  msgstr ""
  
diff --combined usounds.c
+++ b/usounds.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -76,22 -76,21 +76,22 @@@ extern char *getenv()
  #include "frontend.h"
  
  
 -void
 +int
  PlaySoundFile (char *name)
  {
    if (*name == NULLCHAR) {
 -    return;
 +    return 0;
    } else if (strcmp(name, "$") == 0) {
      putc(BELLCHAR, stderr);
    } else {
      char buf[2048];
      char *prefix = "", *sep = "";
 -    if(appData.soundProgram[0] == NULLCHAR) return;
 +    if(appData.soundProgram[0] == NULLCHAR) return 1;
      if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
      snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
      system(buf);
    }
 +  return 1;
  }
  
  void
@@@ -136,12 -135,6 +136,12 @@@ PlayTellSound (
    PlaySoundFile(appData.soundTell);
  }
  
 +int
 +Roar ()
 +{
 +  return PlaySoundFile(appData.soundRoar);
 +}
 +
  void
  PlaySoundForColor (ColorClass cc)
  {
diff --combined usystem.c
+++ b/usystem.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -227,7 -227,7 +227,7 @@@ static in
  parse_cpair (ColorClass cc, char *str)
  {
      if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
 -      fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
 +      fprintf(stderr, _("%s: can't parse foreground color in '%s'\n"),
                programName, str);
        return -1;
      }
@@@ -358,9 -358,6 +358,9 @@@ ExpandPathName (char *path
      }
  
      if (*s == '~') {
 +      if(s[1] == '~') { // use ~~ for XBoard's private data directory
 +        snprintf(d, 4*MSG_SIZ, DATADIR "%s", s+2);
 +      } else
        if (*(s+1) == '/') {
          safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
          strcat(d, s+1);
diff --combined winboard/defaults.h
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.\r
   *\r
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.\r
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.\r
   *\r
   * Enhancements Copyright 2005 Alessandro Scotti\r
   *\r
  #define BUILT_IN_SOUND_NAMES {\\r
    "Beepbeep", "Ching", "Click", "Cymbal", "Ding", "Drip", \\r
    "Gong", "Laser", "Move", "Penalty", "Phone", "Pop", "Pop2", \\r
 -  "Slap", "Squeak", "Swish", "Thud", "Whipcrack", \\r
 +  "Roar", "Slap", "Squeak", "Swish", "Thud", "Whipcrack", \\r
    "Alarm", "Challenge", "Channel", "Channel1", "Draw", "Kibitz", \\r
    "Lose", "Request", "Seek", "Shout", "SShout", "Tell", "Unfinished", \\r
    "Win", NULL \\r
  }\r
  \r
  #define SETTINGS_FILE         "winboard.ini"\r
 -#define DEBUG_FILE            "winboard.debug"
 +#define DEBUG_FILE            "winboard.debug"\r
  \r
  #define ICS_LOGON             "ics.ini"\r
  \r
diff --combined winboard/wclipbrd.c
@@@ -1,7 -1,7 +1,7 @@@
  /*\r
   * wclipbrd.c -- Clipboard routines for WinBoard\r
   *\r
-  * Copyright 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.\r
+  * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.\r
   *\r
   * Enhancements Copyright 2005 Alessandro Scotti\r
   *\r
@@@ -42,6 -42,7 +42,6 @@@
  \r
  /* Imports from winboard.c */\r
  extern HWND hwndMain;\r
 -Boolean ParseFEN(Board b, int *stm, char *FEN);\r
  \r
  /* File globals */\r
  static char *copyTemp;\r
@@@ -53,7 -54,7 +53,7 @@@ CopyFENToClipboard(
    char *fen = NULL;\r
  \r
    if(gameMode == EditPosition) EditPositionDone(TRUE); // [HGM] mak sure castling rights are set consistently\r
 -  fen = PositionToFEN(currentMove, NULL);\r
 +  fen = PositionToFEN(currentMove, NULL, 1);\r
    if (!fen) {\r
      DisplayError(_("Unable to convert position to FEN."), 0);\r
      return;\r
@@@ -304,7 -305,7 +304,7 @@@ VOID PasteGameOrFENFromClipboard(
    }\r
  \r
    // [HGM] paste any: make still smarter, to allow pasting of games without tags, recognize FEN in stead\r
 -  if(!ParseFEN(dummyBoard, &dummy, buf) ) {\r
 +  if(!ParseFEN(dummyBoard, &dummy, buf, 0) ) {\r
        PasteGameFromString( buf );\r
    }\r
    else {\r
diff --combined winboard/wedittags.c
@@@ -1,7 -1,7 +1,7 @@@
  /*\r
   * wedittags.c -- EditTags window for WinBoard\r
   *\r
-  * Copyright 1995, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.\r
+  * Copyright 1995, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.\r
   *\r
   * Enhancements Copyright 2005 Alessandro Scotti\r
   *\r
@@@ -118,7 -118,6 +118,7 @@@ EditTagsDialog(HWND hDlg, UINT message
    case WM_COMMAND:\r
      switch (LOWORD(wParam)) {\r
      case IDOK:\r
 +    case OPT_TagsSave:\r
        if (canEditTags) {\r
        char *p, *q;\r
        /* Read changed options from the dialog box */\r
        }\r
        *p = NULLCHAR; err = 0;\r
          if(resPtr) *resPtr = strdup(str); else\r
 -      if(bookUp) SaveToBook(str); else\r
 +      if(bookUp) SaveToBook(str), DisplayBook(currentMove); else\r
        err = ReplaceTags(str, &gameInfo);\r
        if (err) DisplayError(_("Error replacing tags."), err);\r
  \r
        free(str);\r
        }\r
 -      TagsPopDown();\r
 +      if(LOWORD(wParam) == IDOK) TagsPopDown();\r
        return TRUE;\r
        \r
      case IDCANCEL:\r
diff --combined winboard/winboard.c
@@@ -2,10 -2,10 +2,10 @@@
   * WinBoard.c -- Windows NT front end to XBoard\r
   *\r
   * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
-  * Massachusetts. \r
+  * Massachusetts.\r
   *\r
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.\r
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.\r
   *\r
   * Enhancements Copyright 2005 Alessandro Scotti\r
   *\r
@@@ -112,6 -112,7 +112,6 @@@ VOID NewVariantPopup(HWND hwnd)
  int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
                   /*char*/int promoChar));\r
  void DisplayMove P((int moveNumber));\r
 -Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
  void ChatPopUp P((char *s));\r
  typedef struct {\r
    ChessSquare piece;  \r
@@@ -189,7 -190,6 +189,7 @@@ Boolean alwaysOnTop = FALSE
  RECT boardRect;\r
  COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
    blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
 +COLORREF markerColor[8] = { 0x00FFFF, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFF00, 0xFF00FF, 0xFFFFFF, 0x000000 };\r
  HPALETTE hPal;\r
  ColorClass currentColorClass;\r
  \r
@@@ -200,7 -200,7 +200,7 @@@ static HBITMAP pieceBitmap[3][(int) Bla
  static HBRUSH lightSquareBrush, darkSquareBrush,\r
    blackSquareBrush, /* [HGM] for band between board and holdings */\r
    explodeBrush,     /* [HGM] atomic */\r
 -  markerBrush,      /* [HGM] markers */\r
 +  markerBrush[8],   /* [HGM] markers */\r
    whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
  static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];\r
  static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];\r
@@@ -226,6 -226,8 +226,6 @@@ static struct { int x; int y; int mode
  #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
  #else\r
  \r
 -\r
 -\r
  #if defined(_winmajor)\r
  #define oldDialog (_winmajor < 4)\r
  #else\r
@@@ -984,16 -986,17 +984,17 @@@ InitApplication(HINSTANCE hInstance
  \r
  /* Set by InitInstance, used by EnsureOnScreen */\r
  int screenHeight, screenWidth;\r
+ RECT screenGeometry;\r
  \r
  void\r
  EnsureOnScreen(int *x, int *y, int minX, int minY)\r
  {\r
  //  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
    /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
-   if (*x > screenWidth - 32) *x = 0;\r
-   if (*y > screenHeight - 32) *y = 0;\r
-   if (*x < minX) *x = minX;\r
-   if (*y < minY) *y = minY;\r
+   if (*x > screenGeometry.right - 32) *x = screenGeometry.left;\r
+   if (*y > screenGeometry.bottom - 32) *y = screenGeometry.top;\r
+   if (*x < screenGeometry.left + minX) *x = screenGeometry.left + minX;\r
+   if (*y < screenGeometry.top + minY) *y = screenGeometry.top + minY;\r
  }\r
  \r
  VOID\r
@@@ -1054,6 -1057,32 +1055,32 @@@ InitTextures(
    }\r
  }\r
  \r
+ #ifndef SM_CXVIRTUALSCREEN\r
+ #define SM_CXVIRTUALSCREEN 78\r
+ #endif\r
+ #ifndef SM_CYVIRTUALSCREEN\r
+ #define SM_CYVIRTUALSCREEN 79\r
+ #endif\r
+ #ifndef SM_XVIRTUALSCREEN \r
+ #define SM_XVIRTUALSCREEN 76\r
+ #endif\r
+ #ifndef SM_YVIRTUALSCREEN \r
+ #define SM_YVIRTUALSCREEN 77\r
+ #endif\r
\r
+ VOID\r
+ InitGeometry()\r
+ {\r
+   screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
+   if( !screenHeight ) screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
+   screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
+   if( !screenWidth ) screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
+   screenGeometry.left = GetSystemMetrics(SM_XVIRTUALSCREEN);\r
+   screenGeometry.top = GetSystemMetrics(SM_YVIRTUALSCREEN);\r
+   screenGeometry.right = screenGeometry.left + screenWidth;\r
+   screenGeometry.bottom = screenGeometry.top + screenHeight;\r
+ }\r
\r
  BOOL\r
  InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
  {\r
      GetCurrentDirectory(MSG_SIZ, installDir);\r
    }\r
    gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
-   screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
+   InitGeometry();\r
    InitAppData(lpCmdLine);      /* Get run-time parameters */\r
    /* xboard, and older WinBoards, controlled the move sound with the\r
       appData.ringBellAfterMoves option.  In the current WinBoard, we\r
    iconBlack = LoadIcon(hInstance, "icon_black");\r
    iconCurrent = iconWhite;\r
    InitDrawingColors();\r
-   screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
-   screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
\r
    InitPosition(0); // to set nr of ranks and files, which might be non-default through command-line args\r
    for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
      /* Compute window size for each board size, and use the largest\r
@@@ -2167,7 -2195,6 +2193,7 @@@ InsertInPalette(COLORREF color
  VOID\r
  InitDrawingColors()\r
  {\r
 +  int i;\r
    if (pLogPal == NULL) {\r
      /* Allocate enough memory for a logical palette with\r
       * PALETTESIZE entries and set the size and version fields\r
    blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
    iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
    explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
 -  markerBrush = CreateSolidBrush(premoveHighlightColor); // [HGM] markers\r
 -  /* [AS] Force rendering of the font-based pieces */\r
 +    for(i=0; i<8;i++) markerBrush[i] = CreateSolidBrush(markerColor[i]); // [HGM] markers\r
 +\r
 +   /* [AS] Force rendering of the font-based pieces */\r
    if( fontBitmapSquareSize > 0 ) {\r
      fontBitmapSquareSize = 0;\r
    }\r
@@@ -2275,7 -2301,7 +2301,7 @@@ InitDrawingSizes(BoardSize boardSize, i
         && (boardSize < SizePetite || boardSize > SizeBulky) // Archbishop and Chancellor available in entire middle range\r
        || (v == VariantShogi && boardSize != SizeModerate)   // Japanese-style Shogi\r
        ||  v == VariantKnightmate || v == VariantSChess || v == VariantXiangqi || v == VariantSpartan\r
 -      ||  v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy ) {\r
 +      ||  v == VariantShatranj || v == VariantMakruk || v == VariantGreat || v == VariantFairy || v == VariantLion ) {\r
        if(boardSize < SizeMediocre) boardSize = SizePetite; else\r
        if(boardSize > SizeModerate) boardSize = SizeBulky;  else\r
                                     boardSize = SizeMiddling;\r
      pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
      pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
      pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
 +    pieceBitmap[0][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "s");\r
 +    pieceBitmap[1][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "o");\r
 +    pieceBitmap[2][WhiteLion] = DoLoadBitmap(hInst, "ln", squareSize, "w");\r
  \r
      if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
        pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
@@@ -3255,9 -3278,6 +3281,9 @@@ BOOL HasHighlightInfo(
      }\r
  \r
      return result;\r
 +\r
 +\r
 +\r
  }\r
  \r
  BOOL IsDrawArrowEnabled()\r
@@@ -3449,7 -3469,6 +3475,7 @@@ DrawBoardOnDC(HDC hdc, Board board, HD
              DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);\r
        else if( column == BOARD_RGHT) /* right align */\r
              DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);\r
 +      else if( piece == DarkSquare) DisplayHoldingsCount(hdc, x, y, 0, 0);\r
        else\r
        if (appData.monoMode) {\r
          if (piece == EmptySquare) {\r
@@@ -3632,7 -3651,7 +3658,7 @@@ void DrawSeekDot(int x, int y, int colo
  {\r
        int square = color & 0x80;\r
        HBRUSH oldBrush = SelectObject(hdcSeek, \r
 -                      color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);\r
 +                      color == 0 ? markerBrush[1] : color == 1 ? darkSquareBrush : explodeBrush);\r
        color &= 0x7F;\r
        if(square)\r
            Rectangle(hdcSeek, boardRect.left+x - squareSize/9, boardRect.top+y - squareSize/9,\r
@@@ -3925,7 -3944,8 +3951,7 @@@ HDCDrawPosition(HDC hdc, BOOLEAN repain
    for (row = 0; row < BOARD_HEIGHT; row++) {\r
      for (column = 0; column < BOARD_WIDTH; column++) {\r
        if (marker[row][column]) { // marker changes only occur with full repaint!\r
 -          HBRUSH oldBrush = SelectObject(hdcmem, \r
 -                      marker[row][column] == 2 ? markerBrush : explodeBrush);\r
 +          HBRUSH oldBrush = SelectObject(hdcmem, markerBrush[marker[row][column]-1]);\r
            SquareToPos(row, column, &x, &y);\r
            Ellipse(hdcmem, x + squareSize/4, y + squareSize/4,\r
                          x + 3*squareSize/4, y + 3*squareSize/4);\r
@@@ -4281,10 -4301,8 +4307,10 @@@ MouseEvent(HWND hwnd, UINT message, WPA
        } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
        ClockClick(!flipClock); break;\r
        }\r
 +    if(dragging) { // [HGM] lion: don't destroy dragging info if we are already dragging\r
        dragInfo.start.x = dragInfo.start.y = -1;\r
        dragInfo.from = dragInfo.start;\r
 +    }\r
      if(fromX == -1 && frozen) { // not sure where this is for\r
                fromX = fromY = -1; \r
        DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
      if(PromoScroll(pt.x - boardRect.left, pt.y - boardRect.top)) break;\r
      MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);\r
      if ((appData.animateDragging || appData.highlightDragging)\r
 -      && (wParam & MK_LBUTTON)\r
 +      && (wParam & MK_LBUTTON || dragging == 2)\r
        && dragInfo.from.x >= 0) \r
      {\r
        BOOL full_repaint = FALSE;\r
        dragInfo.pos = pt;\r
        }\r
        if (appData.highlightDragging) {\r
 -      SetHighlights(fromX, fromY, x, y);\r
 +      HoverEvent(highlightInfo.sq[1].x, highlightInfo.sq[1].y, x, y);\r
          if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {\r
              full_repaint = TRUE;\r
          }\r
@@@ -4448,8 -4466,6 +4474,8 @@@ ButtonProc(HWND hwnd, UINT message, WPA
    return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);\r
  }\r
  \r
 +static int promoStyle;\r
 +\r
  /* Process messages for Promotion dialog box */\r
  LRESULT CALLBACK\r
  Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
           PieceToChar(BlackMarshall) != '~')   ) ?\r
               SW_SHOW : SW_HIDE);\r
      /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
 -    ShowWindow(GetDlgItem(hDlg, PB_Rook),\r
 -       gameInfo.variant != VariantShogi ?\r
 -             SW_SHOW : SW_HIDE);\r
 -    ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
 -       gameInfo.variant != VariantShogi ?\r
 -             SW_SHOW : SW_HIDE);\r
 -    if(gameInfo.variant == VariantShogi) {\r
 +    ShowWindow(GetDlgItem(hDlg, PB_Rook),   !promoStyle ? SW_SHOW : SW_HIDE);\r
 +    ShowWindow(GetDlgItem(hDlg, PB_Bishop), !promoStyle ? SW_SHOW : SW_HIDE);\r
 +    if(promoStyle) {\r
          SetDlgItemText(hDlg, PB_Queen, "YES");\r
          SetDlgItemText(hDlg, PB_Knight, "NO");\r
          SetWindowText(hDlg, "Promote?");\r
        promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
        break;\r
      case PB_Queen:\r
 -      promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
 +      promoChar = promoStyle ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen));\r
        break;\r
      case PB_Rook:\r
        promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook));\r
        promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel));\r
        break;\r
      case PB_Knight:\r
 -      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight);\r
 +      promoChar = gameInfo.variant == VariantShogi ? '=' : promoStyle ? NULLCHAR : \r
 +                  ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight));\r
        break;\r
      default:\r
        return FALSE;\r
@@@ -4552,9 -4571,8 +4578,9 @@@ PromotionPopup(HWND hwnd
  }\r
  \r
  void\r
 -PromotionPopUp()\r
 +PromotionPopUp(char choice)\r
  {\r
 +  promoStyle = (choice == '+');\r
    DrawPosition(TRUE, NULL);\r
    PromotionPopup(hwndMain);\r
  }\r
@@@ -4771,7 -4789,6 +4797,7 @@@ WndProc(HWND hwnd, UINT message, WPARA
        nnew = RealizePalette(hdc);\r
        if (nnew > 0) {\r
        paletteChanged = TRUE;\r
 +\r
          InvalidateRect(hwnd, &boardRect, FALSE);\r
        }\r
        ReleaseDC(hwnd, hdc);\r
        break;\r
  \r
      case IDM_Rematch:\r
 +\r
        RematchEvent();\r
        break;\r
  \r
@@@ -6272,7 -6288,6 +6298,7 @@@ StartupDialog(HWND hDlg, UINT message, 
        SwapEngines(singleList); // temporarily swap first and second, to load a second 'first', ...\r
        ParseArgs(StringGet, &p);\r
        SwapEngines(singleList); // ... and then make it 'second'\r
 +\r
        appData.noChessProgram = FALSE;\r
        appData.icsActive = FALSE;\r
        } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {\r
@@@ -6850,7 -6865,6 +6876,7 @@@ GothicPopUp(char *title, VariantClass v
  static char *history[HISTORY_SIZE];\r
  int histIn = 0, histP = 0;\r
  \r
 +\r
  VOID\r
  SaveInHistory(char *cmd)\r
  {\r
    histIn = (histIn + 1) % HISTORY_SIZE;\r
    if (history[histIn] != NULL) {\r
      free(history[histIn]);\r
 +\r
      history[histIn] = NULL;\r
    }\r
    histP = histIn;\r
@@@ -7674,7 -7687,6 +7700,7 @@@ DoWriteFile(HANDLE hFile, char *buf, in
        else\r
        err = GetLastError();\r
      }\r
 +\r
    }\r
    return err;\r
  }\r
@@@ -8540,7 -8552,6 +8566,7 @@@ HWND gameListOptionsDialog
  \r
  // low-level front-end: clear text edit / list widget\r
  void\r
 +\r
  GLT_ClearList()\r
  {\r
      SendDlgItemMessage( gameListOptionsDialog, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
@@@ -8732,13 -8743,6 +8758,13 @@@ EditCommentPopUp(int index, char *title
  }\r
  \r
  \r
 +int\r
 +Roar()\r
 +{\r
 +  MyPlaySound(&sounds[(int)SoundRoar]);\r
 +  return 1;\r
 +}\r
 +\r
  VOID\r
  RingBell()\r
  {\r
@@@ -8896,7 -8900,6 +8922,7 @@@ DisplayBlackClock(long timeRemaining, i
    HDC hdc;\r
    char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
  \r
 +\r
    if(appData.noGUI) return;\r
    hdc = GetDC(hwndMain);\r
    if (!IsIconic(hwndMain)) {\r
@@@ -9915,23 -9918,16 +9941,23 @@@ AnimateMove(board, fromX, fromY, toX, t
       int toY;\r
  {\r
    ChessSquare piece;\r
 +  int x = toX, y = toY;\r
    POINT start, finish, mid;\r
    POINT frames[kFactor * 2 + 1];\r
    int nFrames, n;\r
  \r
 +  if(killX >= 0 && IS_LION(board[fromY][fromX])) Roar();\r
 +\r
    if (!appData.animate) return;\r
    if (doingSizing) return;\r
    if (fromY < 0 || fromX < 0) return;\r
    piece = board[fromY][fromX];\r
    if (piece >= EmptySquare) return;\r
  \r
 +  if(killX >= 0) toX = killX, toY = killY; // [HGM] lion: first to kill square\r
 +\r
 +again:\r
 +\r
    ScreenSquare(fromX, fromY, &start);\r
    ScreenSquare(toX, toY, &finish);\r
  \r
    }\r
    animInfo.pos = finish;\r
    DrawPosition(FALSE, NULL);\r
 +\r
 +  if(toX != x || toY != y) { fromX = toX; fromY = toY; toX = x; toY = y; goto again; } // second leg\r
 +\r
    animInfo.piece = EmptySquare;\r
    Explode(board, fromX, fromY, toX, toY);\r
  }\r
diff --combined winboard/winboard.rc
@@@ -44,7 -44,7 +44,7 @@@ BEGI
      LTEXT           "Chessboard for Windows",400,25,15,121,8\r
      LTEXT           "Copyright 1991 Digital Equipment Corporation",201,6,34,\r
                      149,8\r
-     LTEXT           "Enhancements Copyright 1992-2013  Free Software Foundation",\r
+     LTEXT           "Enhancements Copyright 1992-2014  Free Software Foundation",\r
                      OPT_TCtext1,6,45,121,17\r
      CONTROL         "",OPT_TCTime,"Static",SS_BLACKRECT,4,28,159,1\r
      LTEXT           "WinBoard 0.0.0",ABOUTBOX_Version,25,5,160,8\r
@@@ -248,7 -248,7 +248,7 @@@ BEGI
      RTEXT           "Chessboard for Windows",IDC_ChessBoard,196,154,80,8\r
      LTEXT           "Copyright 1991 Digital Equipment Corporation",201,4,168,\r
                      151,8\r
-     LTEXT           "Enhancements Copyright 1992-2013   Free Software Foundation",\r
+     LTEXT           "Enhancements Copyright 1992-2014   Free Software Foundation",\r
                      OPT_TCtext1,4,179,126,17\r
      CONTROL         "",OPT_TCTime,"Static",SS_BLACKRECT,4,164,272,1\r
      LTEXT           "WinBoard 0.0.0",ABOUTBOX_Version,4,154,64,8\r
@@@ -275,17 -275,16 +275,17 @@@ BEGI
      EDITTEXT        IDC_GameListFilter,201,136,78,14,ES_AUTOHSCROLL\r
  END\r
  \r
 -DLG_EditTags DIALOG DISCARDABLE  6, 18, 167, 140\r
 +DLG_EditTags DIALOG DISCARDABLE  6, 18, 223, 140\r
  STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\r
  CAPTION "Edit Tags"\r
  FONT 8, "MS Sans Serif"\r
  BEGIN\r
 -    PUSHBUTTON      "OK",IDOK,58,122,50,14\r
 -    PUSHBUTTON      "Cancel",OPT_TagsCancel,114,122,50,14\r
 +    PUSHBUTTON      "OK",IDOK,114,122,50,14\r
 +    PUSHBUTTON      "Cancel",OPT_TagsCancel,170,122,50,14\r
 +    PUSHBUTTON      "Save",OPT_TagsSave,58,122,50,14\r
      CONTROL         "",OPT_TagsText,"RICHEDIT",ES_MULTILINE | ES_AUTOVSCROLL | \r
                      ES_AUTOHSCROLL | ES_WANTRETURN | WS_BORDER | WS_VSCROLL | \r
 -                    WS_HSCROLL | WS_TABSTOP,2,2,162,115\r
 +                    WS_HSCROLL | WS_TABSTOP,2,2,218,115\r
      PUSHBUTTON      "&Edit",OPT_EditTags,2,122,50,14\r
  END\r
  \r
@@@ -445,7 -444,7 +445,7 @@@ BEGI
      PUSHBUTTON      "Cancel",IDCANCEL,208,86,50,14\r
  END\r
  \r
 -DLG_GeneralOptions DIALOG DISCARDABLE  0, 0, 300, 197\r
 +DLG_GeneralOptions DIALOG DISCARDABLE  0, 0, 300, 211\r
  STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
  CAPTION "General Options"\r
  FONT 8, "MS Sans Serif"\r
@@@ -498,12 -497,8 +498,12 @@@ BEGI
                      "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,160,151,10\r
      CONTROL         "One-Click Move",OPT_SmartMove,\r
                      "Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,160,151,10\r
 -    DEFPUSHBUTTON   "OK",IDOK,180,178,50,14\r
 -    PUSHBUTTON      "Cancel",IDCANCEL,236,178,50,14\r
 +    CONTROL         "auto-Display Tags",OPT_AutoTags,\r
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,174,151,10\r
 +    CONTROL         "auto-Display Comment",OPT_AutoComment,\r
 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,174,151,10\r
 +    DEFPUSHBUTTON   "OK",IDOK,180,192,50,14\r
 +    PUSHBUTTON      "Cancel",IDCANCEL,236,192,50,14\r
  END\r
  \r
  DLG_IcsOptions DIALOGEX 0, 0, 302, 268\r
@@@ -713,8 -708,6 +713,8 @@@ BEGI
                      70,10\r
      CONTROL         "&atomic",OPT_VariantAtomic,"Button",BS_AUTORADIOBUTTON,\r
                      9,104,70,10\r
 +    CONTROL         "&Mighty Lion",OPT_VariantLion,"Button",BS_AUTORADIOBUTTON,\r
 +                    9,114,70,10\r
      CONTROL         "cra&zyhouse",OPT_VariantCrazyhouse,"Button",BS_AUTORADIOBUTTON,80,14,\r
                      70,10\r
      CONTROL         "&bughouse",OPT_VariantBughouse,"Button",BS_AUTORADIOBUTTON,80,24,70,\r
                      94,70,10\r
      CONTROL         "&makruk",OPT_VariantMakruk,"Button",BS_AUTORADIOBUTTON,80,\r
                      104,70,10\r
 +    CONTROL         "&ASEAN",OPT_VariantASEAN,"Button",BS_AUTORADIOBUTTON,80,\r
 +                    114,70,10\r
      CONTROL         "&gothic",OPT_VariantGothic,"Button",BS_AUTORADIOBUTTON,154,14,\r
                      70,10\r
      CONTROL         "&capablanca",OPT_VariantCapablanca,"Button",BS_AUTORADIOBUTTON,154,\r
                      10\r
      CONTROL         "&xiangqi",OPT_VariantXiangqi,"Button",BS_AUTORADIOBUTTON,154,114,70,\r
                      10\r
 -    GROUPBOX        "Variant",GPB_Variant,4,4,215,125\r
 -    LTEXT           "Board size:",GPB_Board,10,165,40,8,WS_TABSTOP\r
 -    LTEXT           "ranks",IDC_Height,77,165,38,8\r
 -    EDITTEXT        IDC_Ranks,60,161,14,14,ES_AUTOHSCROLL\r
 -    LTEXT           "files",IDC_Width,133,165,80,8\r
 -    EDITTEXT        IDC_Files,116,161,14,14,ES_AUTOHSCROLL\r
 -    LTEXT           "Holdings with room for:",IDC_Hand,10,183,90,8\r
 -    EDITTEXT        IDC_Holdings,93,179,14,14,ES_AUTOHSCROLL\r
 -    LTEXT           "pieces",IDC_Pieces,110,183,100,8\r
 -    LTEXT           "('-1' means defaults for selected variant)",IDC_Def,10,201,210,8\r
 +    CONTROL         "",OPT_EngineVariant+0,"Button",BS_AUTORADIOBUTTON,9,134,70,10\r
 +    CONTROL         "",OPT_EngineVariant+1,"Button",BS_AUTORADIOBUTTON,80,134,70,10\r
 +    CONTROL         "",OPT_EngineVariant+2,"Button",BS_AUTORADIOBUTTON,154,134,70,10\r
 +    CONTROL         "",OPT_EngineVariant+3,"Button",BS_AUTORADIOBUTTON,9,144,70,10\r
 +    CONTROL         "",OPT_EngineVariant+4,"Button",BS_AUTORADIOBUTTON,80,144,70,10\r
 +    CONTROL         "",OPT_EngineVariant+5,"Button",BS_AUTORADIOBUTTON,154,144,70,10\r
 +    CONTROL         "",OPT_EngineVariant+6,"Button",BS_AUTORADIOBUTTON,9,154,70,10\r
 +    CONTROL         "",OPT_EngineVariant+7,"Button",BS_AUTORADIOBUTTON,80,154,70,10\r
 +    CONTROL         "",OPT_EngineVariant+8,"Button",BS_AUTORADIOBUTTON,154,154,70,10\r
 +    GROUPBOX        "Variant",GPB_Variant,4,4,215,165\r
 +    LTEXT           "Board size:",GPB_Board,10,183,40,8,WS_TABSTOP\r
 +    LTEXT           "ranks",IDC_Height,77,183,38,8\r
 +    EDITTEXT        IDC_Ranks,60,179,14,14,ES_AUTOHSCROLL\r
 +    LTEXT           "files",IDC_Width,133,183,80,8\r
 +    EDITTEXT        IDC_Files,116,179,14,14,ES_AUTOHSCROLL\r
 +    LTEXT           "Holdings with room for:",IDC_Hand,10,201,90,8\r
 +    EDITTEXT        IDC_Holdings,93,197,14,14,ES_AUTOHSCROLL\r
 +    LTEXT           "pieces",IDC_Pieces,110,201,100,8\r
 +    LTEXT           "('-1' means defaults for selected variant)",IDC_Def,10,217,210,8\r
      DEFPUSHBUTTON   "OK",IDOK,114,232,50,14\r
      PUSHBUTTON      "Cancel",IDCANCEL,170,232,50,14\r
  END\r
@@@ -1918,7 -1900,6 +1918,7 @@@ V72O                    BITMAP  MOVEABL
  S72O                    BITMAP  MOVEABLE PURE   "bitmaps/s72o.bmp"\r
  L72O                    BITMAP  MOVEABLE PURE   "bitmaps/l72o.bmp"\r
  DK72O                   BITMAP  MOVEABLE PURE   "bitmaps/dk72o.bmp"\r
 +LN72O                   BITMAP  MOVEABLE PURE   "bitmaps/ln72o.bmp"\r
  WP72O                   BITMAP  MOVEABLE PURE   "bitmaps/wp72o.bmp"\r
  WN72O                   BITMAP  MOVEABLE PURE   "bitmaps/wn72o.bmp"\r
  WL72O                   BITMAP  MOVEABLE PURE   "bitmaps/wl72o.bmp"\r
@@@ -1939,7 -1920,6 +1939,7 @@@ V72S                    BITMAP  MOVEABL
  S72S                    BITMAP  MOVEABLE PURE   "bitmaps/s72s.bmp"\r
  L72S                    BITMAP  MOVEABLE PURE   "bitmaps/l72s.bmp"\r
  DK72S                   BITMAP  MOVEABLE PURE   "bitmaps/dk72s.bmp"\r
 +LN72S                   BITMAP  MOVEABLE PURE   "bitmaps/ln72s.bmp"\r
  WP72S                   BITMAP  MOVEABLE PURE   "bitmaps/wp72s.bmp"\r
  WN72S                   BITMAP  MOVEABLE PURE   "bitmaps/wn72s.bmp"\r
  WL72S                   BITMAP  MOVEABLE PURE   "bitmaps/wl72s.bmp"\r
@@@ -1960,7 -1940,6 +1960,7 @@@ V72W                    BITMAP  MOVEABL
  S72W                    BITMAP  MOVEABLE PURE   "bitmaps/s72w.bmp"\r
  L72W                    BITMAP  MOVEABLE PURE   "bitmaps/l72w.bmp"\r
  DK72W                   BITMAP  MOVEABLE PURE   "bitmaps/dk72w.bmp"\r
 +LN72W                   BITMAP  MOVEABLE PURE   "bitmaps/ln72w.bmp"\r
  E49O                    BITMAP  MOVEABLE PURE   "bitmaps/e49o.bmp"\r
  A49O                    BITMAP  MOVEABLE PURE   "bitmaps/a49o.bmp"\r
  AA49O                   BITMAP  MOVEABLE PURE   "bitmaps/as49o.bmp"\r
@@@ -1977,7 -1956,6 +1977,7 @@@ V49O                    BITMAP  MOVEABL
  S49O                    BITMAP  MOVEABLE PURE   "bitmaps/s49o.bmp"\r
  L49O                    BITMAP  MOVEABLE PURE   "bitmaps/l49o.bmp"\r
  DK49O                   BITMAP  MOVEABLE PURE   "bitmaps/dk49o.bmp"\r
 +LN49O                   BITMAP  MOVEABLE PURE   "bitmaps/ln49o.bmp"\r
  WP49O                   BITMAP  MOVEABLE PURE   "bitmaps/wp49o.bmp"\r
  WN49O                   BITMAP  MOVEABLE PURE   "bitmaps/wn49o.bmp"\r
  WL49O                   BITMAP  MOVEABLE PURE   "bitmaps/wl49o.bmp"\r
@@@ -1998,7 -1976,6 +1998,7 @@@ V49S                    BITMAP  MOVEABL
  S49S                    BITMAP  MOVEABLE PURE   "bitmaps/s49s.bmp"\r
  L49S                    BITMAP  MOVEABLE PURE   "bitmaps/l49s.bmp"\r
  DK49S                   BITMAP  MOVEABLE PURE   "bitmaps/dk49s.bmp"\r
 +LN49S                   BITMAP  MOVEABLE PURE   "bitmaps/ln49s.bmp"\r
  WP49S                   BITMAP  MOVEABLE PURE   "bitmaps/wp49s.bmp"\r
  WN49S                   BITMAP  MOVEABLE PURE   "bitmaps/wn49s.bmp"\r
  WL49S                   BITMAP  MOVEABLE PURE   "bitmaps/wl49s.bmp"\r
@@@ -2019,7 -1996,6 +2019,7 @@@ V49W                    BITMAP  MOVEABL
  S49W                    BITMAP  MOVEABLE PURE   "bitmaps/s49w.bmp"\r
  L49W                    BITMAP  MOVEABLE PURE   "bitmaps/l49w.bmp"\r
  DK49W                   BITMAP  MOVEABLE PURE   "bitmaps/dk49w.bmp"\r
 +LN49W                   BITMAP  MOVEABLE PURE   "bitmaps/ln49w.bmp"\r
  A33O                    BITMAP  MOVEABLE PURE   "bitmaps/a33o.bmp"\r
  AA33O                   BITMAP  MOVEABLE PURE   "bitmaps/as33o.bmp"\r
  C33O                    BITMAP  MOVEABLE PURE   "bitmaps/c33o.bmp"\r
@@@ -2034,7 -2010,6 +2034,7 @@@ W33O                    BITMAP  MOVEABL
  M33O                    BITMAP  MOVEABLE PURE   "bitmaps/m33o.bmp"\r
  O33O                    BITMAP  MOVEABLE PURE   "bitmaps/o33o.bmp"\r
  DK33O                   BITMAP  MOVEABLE PURE   "bitmaps/dk33o.bmp"\r
 +LN33O                   BITMAP  MOVEABLE PURE   "bitmaps/ln33o.bmp"\r
  WP33O                   BITMAP  MOVEABLE PURE   "bitmaps/wp33o.bmp"\r
  WN33O                   BITMAP  MOVEABLE PURE   "bitmaps/wn33o.bmp"\r
  WL33O                   BITMAP  MOVEABLE PURE   "bitmaps/wl33o.bmp"\r
@@@ -2053,7 -2028,6 +2053,7 @@@ W33W                    BITMAP  MOVEABL
  M33W                    BITMAP  MOVEABLE PURE   "bitmaps/m33w.bmp"\r
  O33W                    BITMAP  MOVEABLE PURE   "bitmaps/o33w.bmp"\r
  DK33W                   BITMAP  MOVEABLE PURE   "bitmaps/dk33w.bmp"\r
 +LN33W                   BITMAP  MOVEABLE PURE   "bitmaps/ln33w.bmp"\r
  A33S                    BITMAP  MOVEABLE PURE   "bitmaps/a33s.bmp"\r
  AA33S                   BITMAP  MOVEABLE PURE   "bitmaps/as33s.bmp"\r
  C33S                    BITMAP  MOVEABLE PURE   "bitmaps/c33s.bmp"\r
@@@ -2068,7 -2042,6 +2068,7 @@@ W33S                    BITMAP  MOVEABL
  M33S                    BITMAP  MOVEABLE PURE   "bitmaps/m33s.bmp"\r
  O33S                    BITMAP  MOVEABLE PURE   "bitmaps/o33s.bmp"\r
  DK33S                   BITMAP  MOVEABLE PURE   "bitmaps/dk33s.bmp"\r
 +LN33S                   BITMAP  MOVEABLE PURE   "bitmaps/ln33s.bmp"\r
  WP33S                   BITMAP  MOVEABLE PURE   "bitmaps/wp33s.bmp"\r
  WN33S                   BITMAP  MOVEABLE PURE   "bitmaps/wn33s.bmp"\r
  WL33S                   BITMAP  MOVEABLE PURE   "bitmaps/wl33s.bmp"\r
@@@ -2235,7 -2208,6 +2235,7 @@@ SSHOUT                  WAVE    DISCARD
  TELL                    WAVE    DISCARDABLE     "sounds/tell.wav"\r
  UNFINISHED              WAVE    DISCARDABLE     "sounds/unfinished.wav"\r
  WIN                     WAVE    DISCARDABLE     "sounds/win.wav"\r
 +ROAR                    WAVE    DISCARDABLE     "sounds/roar.wav"\r
  \r
  /////////////////////////////////////////////////////////////////////////////\r
  //\r
diff --combined winboard/woptions.c
@@@ -1,7 -1,7 +1,7 @@@
  /*\r
   * woptions.c -- Options dialog box routines for WinBoard\r
   *\r
-  * Copyright 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.\r
+  * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.\r
   *\r
   * Enhancements Copyright 2005 Alessandro Scotti\r
   *\r
@@@ -210,8 -210,6 +210,8 @@@ GeneralOptionsDialog(HWND hDlg, UINT me
      CHECK_BOX(OPT_HighlightMoveArrow, appData.highlightMoveWithArrow);\r
      CHECK_BOX(OPT_AutoLogo, appData.autoLogo); // [HGM] logo\r
      CHECK_BOX(OPT_SmartMove, appData.oneClick); // [HGM] one-click\r
 +    CHECK_BOX(OPT_AutoTags, appData.autoDisplayTags); // [HGM]\r
 +    CHECK_BOX(OPT_AutoComment, appData.autoDisplayComment); // [HGM]\r
  \r
  #undef CHECK_BOX\r
  \r
        appData.highlightMoveWithArrow=IS_CHECKED(OPT_HighlightMoveArrow);\r
        appData.autoLogo             =IS_CHECKED(OPT_AutoLogo); // [HGM] logo\r
        appData.oneClick             =IS_CHECKED(OPT_SmartMove); // [HGM] one-click\r
 +      appData.autoDisplayTags      =IS_CHECKED(OPT_AutoTags); // [HGM]\r
 +      appData.autoDisplayComment   =IS_CHECKED(OPT_AutoComment); // [HGM]\r
  \r
  #undef IS_CHECKED\r
  \r
@@@ -699,7 -695,6 +699,7 @@@ BoardOptionsDialog(HWND hDlg, UINT mess
        }\r
        DeleteObject(pieces[0]);\r
        DeleteObject(pieces[1]);\r
 +\r
        DeleteObject(pieces[2]);\r
        return TRUE;\r
  \r
@@@ -843,7 -838,6 +843,7 @@@ int radioButton[] = 
      -1,\r
      -1,\r
      OPT_VariantShogi,\r
 +    -1, // Chu\r
      OPT_VariantXiangqi,\r
      OPT_VariantCourier,\r
      OPT_VariantGothic,\r
      OPT_VariantGreat,\r
      -1, // Twilight,\r
      OPT_VariantMakruk,\r
 +    OPT_VariantASEAN,\r
      OPT_VariantSChess,\r
      OPT_VariantGrand,\r
      OPT_VariantSpartan, // Spartan\r
 +    OPT_VariantLion,\r
      -2 // sentinel\r
  };\r
  \r
@@@ -871,40 -863,23 +871,40 @@@ VariantClas
  VariantWhichRadio(HWND hDlg)\r
  {\r
    int i=0, j;\r
 +  *engineVariant = NULLCHAR;\r
    while((j = radioButton[i++]) != -2) {\r
        if(j == -1) continue; // no menu button\r
        if(IsDlgButtonChecked(hDlg, j) &&\r
           (appData.noChessProgram || strstr(first.variants, VariantName(i-1)))) return (VariantClass) i-1;\r
    }\r
 +  for(i=0; i<9; i++) { // check for engine-defined variants\r
 +    if(IsDlgButtonChecked(hDlg, OPT_EngineVariant+i) ) {\r
 +      GetDlgItemText(hDlg, OPT_EngineVariant+i, engineVariant, MSG_SIZ); // remember name, so we can resolve it later\r
 +      return VariantUnknown;\r
 +    }\r
 +  }\r
    return gameInfo.variant; // If no button checked, keep old\r
  }\r
  \r
  void\r
  VariantShowRadio(HWND hDlg)\r
  {\r
 +  char c = *engineVariant;\r
    int i=0, j;\r
    CheckDlgButton(hDlg, radioButton[gameInfo.variant], TRUE);\r
 +  *engineVariant = NULLCHAR; // [HGM] kludge to prevent VariantName will always return engineVariant\r
    while((j = radioButton[i++]) != -2) {\r
        if(j == -1) continue; // no menu button\r
        EnableWindow(GetDlgItem(hDlg, j), appData.noChessProgram || strstr(first.variants, VariantName(i-1)));\r
    }\r
 +  *engineVariant = c;\r
 +  for(i=0; i<9; i++) { // initialize engine-defined variants\r
 +    char *v = EngineDefinedVariant(&first, i); // get name of #i\r
 +    if(v) { // there is such a variant\r
 +      EnableWindow(GetDlgItem(hDlg, OPT_EngineVariant+i), TRUE);     // and enable the button\r
 +      SetDlgItemText(hDlg, OPT_EngineVariant+i, v);                  // put its name on button\r
 +    } else EnableWindow(GetDlgItem(hDlg, OPT_EngineVariant+i), FALSE); // no such variant; disable button\r
 +  }\r
  }\r
  \r
  LRESULT CALLBACK\r
@@@ -1422,9 -1397,6 +1422,9 @@@ IcsOptionsDialog(HWND hDlg, UINT messag
        UpdateSampleText(hDlg, OPT_SampleSeek, &mca[ColorSeek]);\r
        break;\r
  \r
 +\r
 +\r
 +\r
      case OPT_ChooseNormalColor:\r
        ColorizeTextPopup(hDlg, ColorNormal);\r
        UpdateSampleText(hDlg, OPT_SampleNormal, &mca[ColorNormal]);\r
@@@ -1803,7 -1775,6 +1803,7 @@@ FontsOptionsPopup(HWND hwnd
  SoundComboData soundComboData[] = {\r
    {N_("Move"), NULL},\r
    {N_("Bell"), NULL},\r
 +  {N_("Roar"), NULL},\r
    {N_("ICS Alarm"), NULL},\r
    {N_("ICS Win"), NULL},\r
    {N_("ICS Loss"), NULL},\r
@@@ -3032,13 -3003,6 +3032,13 @@@ BOOL BrowseForFolder( const char * titl
      return result;\r
  }\r
  \r
 +int\r
 +IsMultiFormat(char *s)\r
 +{\r
 +  char *p = strchr(s, ':');\r
 +  return p && p != s+1;\r
 +}\r
 +\r
  LRESULT CALLBACK UciOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
  {\r
    char buf[MAX_PATH];\r
      /* Initialize the dialog items */\r
      SetDlgItemText( hDlg, IDC_PolyglotDir, appData.polyglotDir );\r
      SetDlgItemInt( hDlg, IDC_HashSize, appData.defaultHashSize, TRUE );\r
 +    if(appData.defaultPathEGTB[0])\r
      SetDlgItemText( hDlg, IDC_PathToEGTB, appData.defaultPathEGTB );\r
 +    else\r
 +    SetDlgItemText( hDlg, IDC_PathToEGTB, appData.egtFormats );\r
      SetDlgItemInt( hDlg, IDC_SizeOfEGTB, appData.defaultCacheSizeEGTB, TRUE );\r
      CheckDlgButton( hDlg, IDC_UseBook, (BOOL) appData.usePolyglotBook );\r
      SetDlgItemText( hDlg, IDC_BookFile, appData.polyglotBook );\r
        appData.defaultHashSize = GetDlgItemInt(hDlg, IDC_HashSize, NULL, FALSE );\r
        appData.defaultCacheSizeEGTB = GetDlgItemInt(hDlg, IDC_SizeOfEGTB, NULL, FALSE );\r
        GetDlgItemText( hDlg, IDC_PathToEGTB, buf, sizeof(buf) );\r
 -      appData.defaultPathEGTB = strdup(buf);\r
 +      if(IsMultiFormat(buf)) {\r
 +        ASSIGN(appData.egtFormats, buf);\r
 +      } else {\r
 +        ASSIGN(appData.defaultPathEGTB, buf);\r
 +      }\r
        GetDlgItemText( hDlg, IDC_BookFile, buf, sizeof(buf) );\r
        appData.polyglotBook = strdup(buf);\r
        appData.usePolyglotBook = (Boolean) IsDlgButtonChecked( hDlg, IDC_UseBook );\r
diff --combined winboard/wsettings.c
@@@ -1,4 -1,27 +1,27 @@@
  /*\r
+  * woptions.h -- Options dialog box routines for WinBoard\r
+  *\r
+  * Copyright 2003, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.\r
+  *\r
+  * ------------------------------------------------------------------------\r
+  *\r
+  * GNU XBoard is free software: you can redistribute it and/or modify\r
+  * it under the terms of the GNU General Public License as published by\r
+  * the Free Software Foundation, either version 3 of the License, or (at\r
+  * your option) any later version.\r
+  *\r
+  * GNU XBoard is distributed in the hope that it will be useful, but\r
+  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+  * General Public License for more details.\r
+  *\r
+  * You should have received a copy of the GNU General Public License\r
+  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
+  *\r
+  *------------------------------------------------------------------------\r
+  ** See the file ChangeLog for a revision history.  */\r
\r
+ /*\r
   * Engine-settings dialog. The complexity come from an attempt to present the engine-defined options\r
   * in a nicey formatted layout. To this end we first run a back-end pre-formatter, which will distribute\r
   * the controls over two columns (the minimum required, as some are double width). It also takes care of\r
@@@ -472,7 -495,7 +495,7 @@@ LRESULT CALLBACK SettingsProc(HWND hDlg
                if(j == -2) {\r
                          char filter[] =\r
                                "All files\0*.*\0Game files\0*.pgn;*.gam\0Position files\0*.fen;*.epd;*.pos\0"\r
 -                              "EXE files\0*.exe\0Tournament files (*.trn)\0*.trn\0"\r
 +                              "EXE files\0*.exe;*.jar\0Tournament files (*.trn)\0*.trn\0"\r
                                "BIN Files\0*.bin\0LOG Files\0*.log\0INI Files\0*.ini\0"\r
                                "Image files\0*.bmp\0\0";\r
                          OPENFILENAME ofn;\r
@@@ -689,7 -712,7 +712,7 @@@ Option installOptions[] = 
    {   0,  0,    0, NULL, NULL, NULL, NULL, Label, N_("or specify one below:") },\r
    {   0,  0,    0, NULL, (void*) &nickName, NULL, NULL, TextBox, N_("Nickname (optional):") },\r
    {   0,  0,    0, NULL, (void*) &useNick, NULL, NULL, CheckBox, N_("Use nickname in PGN tag") },\r
 -  {   0,  0, 32+3, NULL, (void*) &engineName, NULL, NULL, FileName, N_("Engine (*.exe):") },\r
 +  {   0,  0, 32+3, NULL, (void*) &engineName, NULL, NULL, FileName, N_("Engine (.exe or .jar):") },\r
    {   0,  0,    0, NULL, (void*) &params, NULL, NULL, TextBox, N_("command-line parameters:") },\r
    {   0,  0,    0, NULL, (void*) &wbOptions, NULL, NULL, TextBox, N_("Special WinBoard options:") },\r
    {   0,  0,    0, NULL, (void*) &engineDir, NULL, NULL, PathName, N_("directory:") },\r
diff --combined xaw/xboard.c
@@@ -5,7 -5,7 +5,7 @@@
   * Massachusetts.
   *
   * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
-  * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   *
   * The following terms apply to Digital Equipment Corporation's copyright
   * interest in XBoard:
@@@ -183,6 -183,13 +183,6 @@@ extern char *getenv()
  // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
  #include "common.h"
  
 -#if HAVE_LIBXPM
 -#include <X11/xpm.h>
 -#define IMAGE_EXT "xpm"
 -#else
 -#define IMAGE_EXT "xim"
 -#endif
 -
  #include "bitmaps/icon_white.bm"
  #include "bitmaps/icon_black.bm"
  #include "bitmaps/checkmark.bm"
@@@ -423,6 -430,128 +423,6 @@@ String xboardResources[] = 
  /* Max possible square size */
  #define MAXSQSIZE 256
  
 -static int xpm_avail[MAXSQSIZE];
 -
 -#ifdef HAVE_DIR_STRUCT
 -
 -/* Extract piece size from filename */
 -static int
 -xpm_getsize (char *name, int len, char *ext)
 -{
 -    char *p, *d;
 -    char buf[10];
 -
 -    if (len < 4)
 -      return 0;
 -
 -    if ((p=strchr(name, '.')) == NULL ||
 -      StrCaseCmp(p+1, ext) != 0)
 -      return 0;
 -
 -    p = name + 3;
 -    d = buf;
 -
 -    while (*p && isdigit(*p))
 -      *(d++) = *(p++);
 -
 -    *d = 0;
 -    return atoi(buf);
 -}
 -
 -/* Setup xpm_avail */
 -static int
 -xpm_getavail (char *dirname, char *ext)
 -{
 -    DIR *dir;
 -    struct dirent *ent;
 -    int  i;
 -
 -    for (i=0; i<MAXSQSIZE; ++i)
 -      xpm_avail[i] = 0;
 -
 -    if (appData.debugMode)
 -      fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
 -
 -    dir = opendir(dirname);
 -    if (!dir)
 -      {
 -        fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
 -                programName, dirname);
 -        exit(1);
 -      }
 -
 -    while ((ent=readdir(dir)) != NULL) {
 -      i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
 -      if (i > 0 && i < MAXSQSIZE)
 -        xpm_avail[i] = 1;
 -    }
 -
 -    closedir(dir);
 -
 -    return 0;
 -}
 -
 -void
 -xpm_print_avail (FILE *fp, char *ext)
 -{
 -    int i;
 -
 -    fprintf(fp, _("Available `%s' sizes:\n"), ext);
 -    for (i=1; i<MAXSQSIZE; ++i) {
 -      if (xpm_avail[i])
 -        printf("%d\n", i);
 -    }
 -}
 -
 -/* Return XPM piecesize closest to size */
 -int
 -xpm_closest_to (char *dirname, int size, char *ext)
 -{
 -    int i;
 -    int sm_diff = MAXSQSIZE;
 -    int sm_index = 0;
 -    int diff;
 -
 -    xpm_getavail(dirname, ext);
 -
 -    if (appData.debugMode)
 -      xpm_print_avail(stderr, ext);
 -
 -    for (i=1; i<MAXSQSIZE; ++i) {
 -      if (xpm_avail[i]) {
 -          diff = size - i;
 -          diff = (diff<0) ? -diff : diff;
 -          if (diff < sm_diff) {
 -              sm_diff = diff;
 -              sm_index = i;
 -          }
 -      }
 -    }
 -
 -    if (!sm_index) {
 -      fprintf(stderr, _("Error: No `%s' files!\n"), ext);
 -      exit(1);
 -    }
 -
 -    return sm_index;
 -}
 -#else /* !HAVE_DIR_STRUCT */
 -/* If we are on a system without a DIR struct, we can't
 -   read the directory, so we can't collect a list of
 -   filenames, etc., so we can't do any size-fitting. */
 -int
 -xpm_closest_to (char *dirname, int size, char *ext)
 -{
 -    fprintf(stderr, _("\
 -Warning: No DIR structure found on this system --\n\
 -         Unable to autosize for XPM/XIM pieces.\n\
 -   Please report this error to %s.\n\
 -   Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
 -    return size;
 -}
 -#endif /* HAVE_DIR_STRUCT */
 -
 -
  /* Arrange to catch delete-window events */
  Atom wm_delete_window;
  void
@@@ -820,8 -949,6 +820,8 @@@ PrintArg (ArgType t
      case ArgTwo:
      case ArgNone:
      case ArgCommSettings:
 +    case ArgMaster:
 +    case ArgInstall:
        break;
    }
    return p;
@@@ -981,7 -1108,7 +981,7 @@@ main (int argc, char **argv
      debugFP = stderr;
  
      if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
 -      printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
 +      printf("%s version %s\n\n  configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
        exit(0);
      }
  
diff --combined xaw/xengineoutput.c
@@@ -5,7 -5,8 +5,8 @@@
   *
   * Copyright 2005 Alessandro Scotti
   *
-  * Enhancements Copyright 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Enhancements Copyright 2009, 2010, 2011, 2012, 2013,
+  * 2014 Free Software Foundation, Inc.
   *
   * ------------------------------------------------------------------------
   *
@@@ -84,40 -85,16 +85,40 @@@ extern char *getenv()
  # define N_(s)  s
  #endif
  
 -#include <X11/xpm.h>
 +// [HGM] bitmaps of some ICONS used in the engine-outut window
 +
 +static unsigned char CLEAR_14[28];
 +
 +static unsigned char WHITE_14[] = {
 +0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x02, 0x10, 0x02, 0x10, 0x01, 0x20, 0x01, 0x20,
 +0x01, 0x20, 0x01, 0x20, 0x02, 0x10, 0x02, 0x10, 0x04, 0x08, 0x18, 0x06, 0xe0, 0x01
 +};
 +
 +static unsigned char BLACK_14[] = {
 +0xe0, 0x01, 0xf8, 0x07, 0xfc, 0x0f, 0xfe, 0x1f, 0xfe, 0x1f, 0xff, 0x3f, 0xff, 0x3f,
 +0xff, 0x3f, 0xff, 0x3f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xe0, 0x01
 +};
 +
 +static unsigned char ANALYZE_14[] = {
 +0x80, 0x03, 0x60, 0x0c, 0x10, 0x10, 0x90, 0x10, 0xc8, 0x20, 0x08, 0x20, 0x08, 0x20,
 +0x10, 0x10, 0x10, 0x10, 0x68, 0x0c, 0x94, 0x03, 0x0a, 0x00, 0x07, 0x00, 0x00, 0x00
 +};
 +
 +static unsigned char THINK_14[] = {
 +0xe0, 0x00, 0x18, 0x03, 0x44, 0x04, 0x42, 0x08, 0x42, 0x08, 0x41, 0x10, 0xe1, 0x13,
 +0x41, 0x10, 0x02, 0x08, 0x02, 0x08, 0x04, 0x04, 0x18, 0x03, 0xe0, 0x00, 0x00, 0x00
 +};
 +
 +static unsigned char PONDER_14[] = {
 +0x30, 0x03, 0x8c, 0x0c, 0x02, 0x10, 0x01, 0x08, 0x01, 0x10, 0x06, 0x20, 0x04, 0x20,
 +0x02, 0x10, 0x04, 0x0c, 0xc8, 0x04, 0x34, 0x03, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00
 +};
 +
 +static unsigned char UNKNOWN_14[] = {
 +0xe0, 0x01, 0x58, 0x07, 0xac, 0x0a, 0x56, 0x15, 0xaa, 0x1a, 0x55, 0x35, 0xab, 0x2a,
 +0x55, 0x35, 0xab, 0x2a, 0x56, 0x15, 0xaa, 0x1a, 0x54, 0x0d, 0xb8, 0x06, 0xe0, 0x01
 +};
  
 -// [HGM] pixmaps of some ICONS used in the engine-outut window
 -#include "pixmaps/WHITE_14.xpm"
 -#include "pixmaps/BLACK_14.xpm"
 -#include "pixmaps/CLEAR_14.xpm"
 -#include "pixmaps/UNKNOWN_14.xpm"
 -#include "pixmaps/THINKING_14.xpm"
 -#include "pixmaps/PONDER_14.xpm"
 -#include "pixmaps/ANALYZING_14.xpm"
  
  
  /* Module variables */
@@@ -127,9 -104,17 +128,9 @@@ static Widget memoWidget
  
  
  static void
 -ReadIcon (char *pixData[], int iconNr, Widget w)
 +ReadIcon (unsigned char pixData[], int iconNr, Widget w)
  {
 -    int r;
 -
 -      if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(w),
 -                                     pixData,
 -                                     &(icons[iconNr]),
 -                                     NULL, NULL /*&attr*/)) != 0) {
 -        fprintf(stderr, _("Error %d loading icon image\n"), r);
 -        exit(1);
 -      }
 +    icons[iconNr] = XCreateBitmapFromData(xDisplay, XtWindow(w), (char*) pixData, 14, 14);
  }
  
  void
diff --combined xaw/xoptions.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * xoptions.c -- Move list window, part of X front end for XBoard
   *
-  * Copyright 2000, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+  * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
   * ------------------------------------------------------------------------
   *
   * GNU XBoard is free software: you can redistribute it and/or modify
@@@ -988,6 -988,7 +988,7 @@@ GenericPopUp (Option *option, char *tit
            } else texts[h] = dialog = NULL; // kludge to position from left margin
            w = option[i].type == Spin || option[i].type == Fractional ? 70 : option[i].max ? option[i].max : 205;
            if(option[i].type == FileName || option[i].type == PathName) w -= 55;
+           if(squareSize > 33) w += (squareSize - 33)/2;
            j = SetPositionAndSize(args, dialog, last, 1 /* border */,
                                   w /* w */, option[i].type == TextBox ? option[i].value : 0 /* h */, 0x91 /* chain full width */);
            if(option[i].type == TextBox) { // decorations for multi-line text-edits
      XtAddCallback(b_ok, XtNcallback, GenericCallback, (XtPointer)(intptr_t) (30001 + (dlgNr<<16)));
      if(!(option[i].min & NO_CANCEL)) {
        XtSetArg(args[1], XtNfromHoriz, b_ok); // overwrites!
 -      b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
 +      b_cancel = XtCreateManagedWidget(_("Cancel"), commandWidgetClass, form, args, j);
        XtAddCallback(b_cancel, XtNcallback, GenericCallback, (XtPointer)(intptr_t) (30000 + (dlgNr<<16)));
      }
    }
diff --combined xboard2.h
+++ b/xboard2.h
@@@ -1,3 -1,25 +1,25 @@@
+ /*
+  * xboard2.h -- Move list window, part of X front end for XBoard
+  *
+  * Copyright 2012, 2013, 2014 Free Software Foundation, Inc.
+  * ------------------------------------------------------------------------
+  *
+  * GNU XBoard is free software: you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation, either version 3 of the License, or (at
+  * your option) any later version.
+  *
+  * GNU XBoard is distributed in the hope that it will be useful, but
+  * WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program. If not, see http://www.gnu.org/licenses/.  *
+  *
+  *------------------------------------------------------------------------
+  ** See the file ChangeLog for a revision history.  */
  void SendToProgram P((char *message, ChessProgramState *cps));
  void SendToICS P((char *buf));
  void InitDrawingSizes P((int i, int j));
@@@ -6,4 -28,4 +28,4 @@@ extern int searchTime
  extern int squareSize, lineGap, defaultLineGap;
  extern int startedFromPositionFile;
  extern char *icsTextMenuString;
 -
 +extern int hi2X, hi2Y;