Allow engine to force user to make non-standard promotion
[xboard.git] / backend.c
index b7aafee..a67ca7c 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -6702,6 +6702,8 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i
       !(fromX >=0 && fromY >= 0 && toX >= 0 && toY >= 0) ) // invalid move
        return FALSE;
 
+    if(legal[toY][toX] == 4) return FALSE;
+
     piece = boards[currentMove][fromY][fromX];
     if(gameInfo.variant == VariantChu) {
         promotionZoneSize = BOARD_HEIGHT/3;
@@ -7403,6 +7405,7 @@ MarkByFEN(char *fen)
            int s = 0;
            marker[r][f] = 0;
            if(*fen == 'M') legal[r][f] = 2; else // request promotion choice
+           if(*fen == 'B') legal[r][f] = 4; else // request auto-promotion to victim
            if(*fen >= 'A' && *fen <= 'Z') legal[r][f] = 3; else
            if(*fen >= 'a' && *fen <= 'z') *fen += 'A' - 'a';
            if(*fen == '/' && f > BOARD_LEFT) f = BOARD_LEFT, r--; else
@@ -7537,12 +7540,13 @@ void ReportClick(char *action, int x, int y)
 }
 
 Boolean right; // instructs front-end to use button-1 events as if they were button 3
+Boolean deferChoice;
 
 void
 LeftClick (ClickType clickType, int xPix, int yPix)
 {
     int x, y;
-    Boolean saveAnimate;
+    static Boolean saveAnimate;
     static int second = 0, promotionChoice = 0, clearFlag = 0, sweepSelecting = 0, flashing = 0, saveFlash;
     char promoChoice = NULLCHAR;
     ChessSquare piece;
@@ -7550,6 +7554,7 @@ LeftClick (ClickType clickType, int xPix, int yPix)
 
     if(flashing) return;
 
+  if(!deferChoice) { // when called for a retry, skip everything to the point where we left off
     x = EventToSquare(xPix, BOARD_WIDTH);
     y = EventToSquare(yPix, BOARD_HEIGHT);
     if (!flipView && y >= 0) {
@@ -7897,8 +7902,19 @@ LeftClick (ClickType clickType, int xPix, int yPix)
     else ReportClick("put", x, y);
 
     if(gatingPiece != EmptySquare && gameInfo.variant == VariantSChess) promoChoice = ToLower(PieceToChar(gatingPiece));
-
-    if(legal[toY][toX] == 2) promoChoice = ToLower(PieceToChar(defaultPromoChoice)); // highlight-induced promotion
+ }
+
+    if(legal[toY][toX] == 2) { // highlight-induced promotion
+       if(piece == defaultPromoChoice) promoChoice = NULLCHAR; // deferral
+       else promoChoice = ToLower(PieceToChar(defaultPromoChoice));
+    } else if(legal[toY][toX] == 4) { // blue target square: engine must supply promotion choice
+      if(!*promoRestrict) {           // but has not done that yet
+       deferChoice = TRUE;           // set up retry for when it does
+       return;                       // and wait for that
+      }
+      promoChoice = ToLower(*promoRestrict); // force engine's choice
+      deferChoice = FALSE;
+    }
 
     if (legal[toY][toX] == 2 && !appData.sweepSelect || HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) {
        SetHighlights(fromX, fromY, toX, toY);
@@ -9167,9 +9183,13 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
       }
       return;
     }
-    if(sscanf(message, "choice %s", promoRestrict) == 1 && promoSweep != EmptySquare) {
-      promoSweep = CharToPiece(currentMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
-      Sweep(0);
+    if(sscanf(message, "choice %s", promoRestrict) == 1) {
+      if(deferChoice) {
+        LeftClick(Press, 0, 0); // finish the click that was interrupted
+      } else if(promoSweep != EmptySquare) {
+        promoSweep = CharToPiece(currentMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
+        if(strlen(promoRestrict) > 1) Sweep(0);
+      }
       return;
     }
     /* [HGM] Allow engine to set up a position. Don't ask me why one would
@@ -19038,6 +19058,8 @@ LoadVariation (int index, char *text)
        ToNrEvent(currentMove+1);
 }
 
+int transparency[2];
+
 void
 LoadTheme ()
 {
@@ -19060,9 +19082,13 @@ LoadTheme ()
                appData.liteBackTextureMode,
                appData.darkBackTextureMode );
       } else {
-       snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ubt false -lsc %s -dsc %s",
-               Col2Text(2),   // lightSquareColor
-               Col2Text(3) ); // darkSquareColor
+       snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ubt false");
+      }
+      if(!appData.useBitmaps || transparency[0]) {
+       snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -lsc %s", Col2Text(2) ); // lightSquareColor
+      }
+      if(!appData.useBitmaps || transparency[1]) {
+       snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -dsc %s", Col2Text(3) ); // darkSquareColor
       }
       if(appData.useBorder) {
        snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ub true -border \"%s\"",
@@ -19077,9 +19103,13 @@ LoadTheme ()
                Col2Text(9),    // appData.fontBackColorWhite
                Col2Text(10) ); // appData.fontForeColorBlack
       } else {
-       snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -upf false -pid \"%s\"",
-               appData.pieceDirectory);
-       if(!appData.pieceDirectory[0])
+       snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -upf false");
+       if(appData.pieceDirectory[0]) {
+         snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -pid \"%s\"", appData.pieceDirectory);
+         if(appData.trueColors != 2) // 2 is a kludge to suppress this in WinBoard
+           snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -trueColors %s", appData.trueColors ? "true" : "false");
+       }
+       if(!appData.pieceDirectory[0] && !appData.trueColors)
          snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -wpc %s -bpc %s",
                Col2Text(0),   // whitePieceColor
                Col2Text(1) ); // blackPieceColor