Fix home-dir crash
[xboard.git] / backend.c
index caaeabd..bd641fe 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -957,6 +957,7 @@ InitBackEnd1()
       case VariantJanus:      /* should work */
       case VariantSuper:      /* experimental */
       case VariantGreat:      /* experimental, requires legality testing to be off */
+      case VariantSChess:     /* S-Chess, should work */
        break;
       }
     }
@@ -3854,7 +3855,7 @@ ParseBoard12(string)
     int j, k, n, moveNum, white_stren, black_stren, white_time, black_time, takeback;
     int double_push, castle_ws, castle_wl, castle_bs, castle_bl, irrev_count;
     char to_play, board_chars[200];
-    char move_str[500], str[500], elapsed_time[500];
+    char move_str[MSG_SIZ], str[MSG_SIZ], elapsed_time[MSG_SIZ];
     char black[32], white[32];
     Board board;
     int prevMove = currentMove;
@@ -3895,7 +3896,7 @@ ParseBoard12(string)
               &ticking);
 
     if (n < 21) {
-        snprintf(str, sizeof(str), _("Failed to parse board string:\n\"%s\""), string);
+        snprintf(str, MSG_SIZ, _("Failed to parse board string:\n\"%s\""), string);
        DisplayError(str, 0);
        return;
     }
@@ -4344,7 +4345,7 @@ ParseBoard12(string)
          if(!appData.testLegality && move_str[1] != '@') { // drops never ambiguous (parser chokes on long form!)
                if(appData.debugMode)
                        fprintf(debugFP, "replaced ICS move '%s' by '%s'\n", move_str, buf);
-               safeStrCpy(move_str, buf, sizeof(move_str)/sizeof(move_str[0]));
+               safeStrCpy(move_str, buf, MSG_SIZ);
           }
          valid = ParseOneMove(move_str, moveNum - 1, &moveType,
                                &fromX, &fromY, &toX, &toY, &promoChar)
@@ -5348,12 +5349,12 @@ InitPosition(redraw)
     if(startVariant == gameInfo.variant) // [HGM] nicks: enable nicknames in original variant
          SetCharTable(pieceNickName, appData.pieceNickNames);
     else SetCharTable(pieceNickName, "............");
+    pieces = FIDEArray;
 
     switch (gameInfo.variant) {
     case VariantFischeRandom:
       shuffleOpenings = TRUE;
     default:
-      pieces = FIDEArray;
       break;
     case VariantShatranj:
       pieces = ShatranjArray;
@@ -5381,6 +5382,10 @@ InitPosition(redraw)
       gameInfo.boardWidth = 10;
       SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack");
       break;
+    case VariantSChess:
+      SetCharTable(pieceToChar, "PNBRQ..HEKpnbrq..hek");
+      gameInfo.holdingsSize = 7;
+      break;
     case VariantJanus:
       pieces = JanusArray;
       gameInfo.boardWidth = 10;
@@ -5537,6 +5542,14 @@ InitPosition(redraw)
        initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan;
        initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9;
      }
+     if( gameInfo.variant == VariantSChess ) {
+      initialPosition[1][0] = BlackMarshall;
+      initialPosition[2][0] = BlackAngel;
+      initialPosition[6][BOARD_WIDTH-1] = WhiteMarshall;
+      initialPosition[5][BOARD_WIDTH-1] = WhiteAngel;
+      initialPosition[1][1] = initialPosition[2][1] = 
+      initialPosition[6][BOARD_WIDTH-2] = initialPosition[5][BOARD_WIDTH-2] = 1;
+     }
   if (appData.debugMode) {
     fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings);
   }
@@ -6327,6 +6340,8 @@ Explode(Board board, int fromX, int fromY, int toX, int toY)
     return FALSE;
 }
 
+ChessSquare gatingPiece = EmptySquare; // exported to front-end, for dragging
+
 void LeftClick(ClickType clickType, int xPix, int yPix)
 {
     int x, y;
@@ -6383,8 +6398,15 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
     autoQueen = appData.alwaysPromoteToQueen;
 
     if (fromX == -1) {
+      gatingPiece = EmptySquare;
+      if (clickType != Press) {
+       if(dragging) { // [HGM] from-square must have been reset due to game end since last press
+           DragPieceEnd(xPix, yPix); dragging = 0;
+           DrawPosition(FALSE, NULL);
+       }
+       return;
+      }
       if(!appData.oneClick || !OnlyMove(&x, &y, FALSE)) {
-       if (clickType == Press) {
            /* First square */
            if (OKToStartUserMove(x, y)) {
                fromX = x;
@@ -6396,12 +6418,8 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
                    SetHighlights(x, y, -1, -1);
                }
            }
-       } else if(dragging) { // [HGM] from-square must have been reset due to game end since last press
-           DragPieceEnd(xPix, yPix); dragging = 0;
-           DrawPosition(FALSE, NULL);
+           return;
        }
-       return;
-      }
     }
 
     /* fromX != -1 */
@@ -6416,7 +6434,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
        /* Check if clicking again on the same color piece */
        fromP = boards[currentMove][fromY][fromX];
        toP = boards[currentMove][y][x];
-       frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom;
+       frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess;
        if ((WhitePawn <= fromP && fromP <= WhiteKing &&
             WhitePawn <= toP && toP <= WhiteKing &&
             !(fromP == WhiteKing && toP == WhiteRook && frc) &&
@@ -6434,13 +6452,19 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
                ClearHighlights();
            }
            if (OKToStartUserMove(x, y)) {
+               if(gameInfo.variant == VariantSChess && // S-Chess: back-rank piece selected after holdings means gating
+                 (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) &&
+               y == (toP < BlackPawn ? 0 : BOARD_HEIGHT-1))
+                 gatingPiece = boards[currentMove][fromY][fromX];
+               else gatingPiece = EmptySquare;
                fromX = x;
                fromY = y; dragging = 1;
                MarkTargetSquares(0);
                DragPieceBegin(xPix, yPix);
            }
-           return;
           }
+          if(x == fromX && y == fromY) return; // if OnlyMove altered (x,y) we go on
+          second = FALSE; 
        }
        // ignore clicks on holdings
        if(x < BOARD_LEFT || x >= BOARD_RGHT) return;
@@ -6456,6 +6480,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
            /* Second up/down in same square; just abort move */
            second = 0;
            fromX = fromY = -1;
+           gatingPiece = EmptySquare;
            ClearHighlights();
            gotPremove = 0;
            ClearPremoveHighlights();
@@ -6520,6 +6545,8 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
     // off-board moves should not be highlighted
     if(x < 0 || y < 0) ClearHighlights();
 
+    if(gatingPiece != EmptySquare) promoChoice = ToLower(PieceToChar(gatingPiece));
+
     if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice)) {
        SetHighlights(fromX, fromY, toX, toY);
        if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
@@ -8431,21 +8458,21 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
          king += (int) WhiteUnicorn - (int) WhiteKing;
 
     /* Code added by Tord: */
-    /* FRC castling assumed when king captures friendly rook. */
-    if (board[fromY][fromX] == WhiteKing &&
-            board[toY][toX] == WhiteRook) {
+    /* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */
+    if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook ||
+        board[fromY][fromX] == WhiteRook && board[toY][toX] == WhiteKing) {
       board[fromY][fromX] = EmptySquare;
       board[toY][toX] = EmptySquare;
-      if(toX > fromX) {
+      if((toX > fromX) != (piece == WhiteRook)) {
         board[0][BOARD_RGHT-2] = WhiteKing; board[0][BOARD_RGHT-3] = WhiteRook;
       } else {
         board[0][BOARD_LEFT+2] = WhiteKing; board[0][BOARD_LEFT+3] = WhiteRook;
       }
-    } else if (board[fromY][fromX] == BlackKing &&
-              board[toY][toX] == BlackRook) {
+    } else if (board[fromY][fromX] == BlackKing && board[toY][toX] == BlackRook ||
+               board[fromY][fromX] == BlackRook && board[toY][toX] == BlackKing) {
       board[fromY][fromX] = EmptySquare;
       board[toY][toX] = EmptySquare;
-      if(toX > fromX) {
+      if((toX > fromX) != (piece == BlackRook)) {
         board[BOARD_HEIGHT-1][BOARD_RGHT-2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_RGHT-3] = BlackRook;
       } else {
         board[BOARD_HEIGHT-1][BOARD_LEFT+2] = BlackKing; board[BOARD_HEIGHT-1][BOARD_LEFT+3] = BlackRook;
@@ -8578,10 +8605,11 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
       /* [HGM] OK, so I have written it. Holdings are stored in the */
       /* penultimate board files, so they are automaticlly stored   */
       /* in the game history.                                       */
-      if (fromY == DROP_RANK) {
+      if (fromY == DROP_RANK || gameInfo.variant == VariantSChess
+                                && promoChar && piece != WhitePawn && piece != BlackPawn) {
         /* Delete from holdings, by decreasing count */
         /* and erasing image if necessary            */
-        p = (int) fromX;
+        p = fromY == DROP_RANK ? (int) fromX : CharToPiece(piece > BlackPawn ? ToLower(promoChar) : ToUpper(promoChar));
         if(p < (int) BlackPawn) { /* white drop */
              p -= (int)WhitePawn;
                 p = PieceToNumber((ChessSquare)p);
@@ -8601,7 +8629,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
         }
       }
       if (captured != EmptySquare && gameInfo.holdingsSize > 0
-          && gameInfo.variant != VariantBughouse        ) {
+          && gameInfo.variant != VariantBughouse && gameInfo.variant != VariantSChess        ) {
         /* [HGM] holdings: Add to holdings, if holdings exist */
        if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {
                // [HGM] superchess: suppress flipping color of captured pieces by reverse pre-flip
@@ -8645,6 +8673,9 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
        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 orinary Pawn promotion) */
         board[toY][toX] = (ChessSquare) (PROMOTED piece);