Fix ArrowDamage out-of-bounds access on drop moves
[xboard.git] / board.c
diff --git a/board.c b/board.c
index 2b0c624..4de6269 100644 (file)
--- a/board.c
+++ b/board.c
@@ -108,7 +108,7 @@ extern char *getenv();
 #endif
 
 
-int squareSize, lineGap, hOffset;
+int squareSize, lineGap;
 
 int damage[2][BOARD_RANKS][BOARD_FILES];
 
@@ -118,6 +118,9 @@ int damage[2][BOARD_RANKS][BOARD_FILES];
 AnimState anims[NrOfAnims];
 
 static void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
+static Boolean IsDrawArrowEnabled P((void));
+static void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
+static void ArrowDamage P((int s_col, int s_row, int d_col, int d_row));
 
 static void
 drawHighlight (int file, int rank, int type)
@@ -145,6 +148,8 @@ int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
 void
 SetHighlights (int fromX, int fromY, int toX, int toY)
 {
+    int arrow = hi2X >= 0 && hi1Y >= 0 && IsDrawArrowEnabled();
+
     if (hi1X != fromX || hi1Y != fromY) {
        if (hi1X >= 0 && hi1Y >= 0) {
            drawHighlight(hi1X, hi1Y, 0);
@@ -156,6 +161,10 @@ SetHighlights (int fromX, int fromY, int toX, int toY)
            drawHighlight(hi2X, hi2Y, 0);
        }
     }
+    
+    if(arrow) // there currently is an arrow displayed
+       ArrowDamage(hi1X, hi1Y, hi2X, hi2Y); // mark which squares it damaged
+
     if (hi1X != fromX || hi1Y != fromY) {
        if (fromX >= 0 && fromY >= 0) {
            drawHighlight(fromX, fromY, 1);
@@ -167,13 +176,13 @@ SetHighlights (int fromX, int fromY, int toX, int toY)
        }
     }
 
-    if(toX<0) // clearing the highlights must have damaged arrow
-       DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); // for now, redraw it (should really be cleared!)
-
     hi1X = fromX;
     hi1Y = fromY;
     hi2X = toX;
     hi2Y = toY;
+
+    if(arrow || toX >= 0 && fromY >= 0 && IsDrawArrowEnabled())
+       DrawPosition(FALSE, NULL); // repair any arrow damage, or draw a new one
 }
 
 void
@@ -778,8 +787,6 @@ DrawSquare (int row, int column, ChessSquare piece, int do_flash)
          (squareSize + lineGap);
     }
 
-    if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
-
     square_color = SquareColor(row, column);
 
     string[1] = NULLCHAR;
@@ -885,6 +892,7 @@ DrawPosition (int repaint, Board board)
     static int lastFlipView = 0;
     static int lastBoardValid[2] = {0, 0};
     static Board lastBoard[2];
+    static char lastMarker[BOARD_RANKS][BOARD_FILES];
     Arg args[16];
     int rrow, rcol;
     int nr = twoBoards*partnerUp;
@@ -899,6 +907,8 @@ DrawPosition (int repaint, Board board)
        MarkMenuItem("View.Flip View", flipView);
     }
 
+    if(nr) { SlavePopUp(); SwitchWindow(); } // [HGM] popup board if not yet popped up, and switch drawing to it.
+
     /*
      * It would be simpler to clear the window with XClearWindow()
      * but this causes a very distracting flicker.
@@ -907,7 +917,7 @@ DrawPosition (int repaint, Board board)
     if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
 
        if ( lineGap && IsDrawArrowEnabled())
-           DrawGrid(0);
+           DrawGrid();
 
        /* If too much changes (begin observing new game, etc.), don't
           do flashing */
@@ -928,7 +938,7 @@ DrawPosition (int repaint, Board board)
           is flashing on its new square */
        for (i = 0; i < BOARD_HEIGHT; i++)
          for (j = 0; j < BOARD_WIDTH; j++)
-           if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
+           if (((board[i][j] != lastBoard[nr][i][j] || !nr && marker[i][j] != lastMarker[i][j]) && board[i][j] == EmptySquare)
                || damage[nr][i][j]) {
                DrawSquare(i, j, board[i][j], 0);
                damage[nr][i][j] = False;
@@ -937,12 +947,12 @@ DrawPosition (int repaint, Board board)
        /* Second pass -- Draw piece(s) in new position and flash them */
        for (i = 0; i < BOARD_HEIGHT; i++)
          for (j = 0; j < BOARD_WIDTH; j++)
-           if (board[i][j] != lastBoard[nr][i][j]) {
+           if (board[i][j] != lastBoard[nr][i][j] || !nr && marker[i][j] != lastMarker[i][j]) {
                DrawSquare(i, j, board[i][j], do_flash);
            }
     } else {
        if (lineGap > 0)
-         DrawGrid(twoBoards & partnerUp);
+         DrawGrid();
 
        for (i = 0; i < BOARD_HEIGHT; i++)
          for (j = 0; j < BOARD_WIDTH; j++) {
@@ -955,6 +965,9 @@ DrawPosition (int repaint, Board board)
     lastBoardValid[nr] = 1;
   if(nr == 0) { // [HGM] dual: no highlights on second board yet
     lastFlipView = flipView;
+    for (i = 0; i < BOARD_HEIGHT; i++)
+       for (j = 0; j < BOARD_WIDTH; j++)
+           lastMarker[i][j] = marker[i][j];
 
     /* Draw highlights */
     if (pm1X >= 0 && pm1Y >= 0) {
@@ -971,10 +984,13 @@ DrawPosition (int repaint, Board board)
     }
     DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
   }
+  else DrawArrowHighlight (board[EP_STATUS-3], board[EP_STATUS-4], board[EP_STATUS-1], board[EP_STATUS-2]);
+
     /* If piece being dragged around board, must redraw that too */
     DrawDragPiece();
 
     FlashDelay(0); // this flushes drawing queue;
+    if(nr) SwitchWindow();
 }
 
 /* [AS] Arrow highlighting support */
@@ -1009,7 +1025,7 @@ SquareToPos (int rank, int file, int *x, int *y)
 }
 
 /* Draw an arrow between two points using current settings */
-void
+static void
 DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
 {
     Pnt arrow[8];
@@ -1112,22 +1128,22 @@ DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
 //    Polygon( hdc, arrow, 7 );
 }
 
-void
+static void
 ArrowDamage (int s_col, int s_row, int d_col, int d_row)
 {
-    int hor, vert, i;
+    int hor, vert, i, n = partnerUp * twoBoards;
     hor = 64*s_col + 32; vert = 64*s_row + 32;
     for(i=0; i<= 64; i++) {
-            damage[0][vert+6>>6][hor+6>>6] = True;
-            damage[0][vert-6>>6][hor+6>>6] = True;
-            damage[0][vert+6>>6][hor-6>>6] = True;
-            damage[0][vert-6>>6][hor-6>>6] = True;
+            damage[n][vert+6>>6][hor+6>>6] = True;
+            damage[n][vert-6>>6][hor+6>>6] = True;
+            damage[n][vert+6>>6][hor-6>>6] = True;
+            damage[n][vert-6>>6][hor-6>>6] = True;
             hor += d_col - s_col; vert += d_row - s_row;
     }
 }
 
 /* [AS] Draw an arrow between two squares */
-void
+static void
 DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
 {
     int s_x, s_y, d_x, d_y;
@@ -1170,13 +1186,13 @@ DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
     ArrowDamage(s_col, s_row, d_col, d_row);
 }
 
-Boolean
+static Boolean
 IsDrawArrowEnabled ()
 {
-    return appData.highlightMoveWithArrow && squareSize >= 32;
+    return (appData.highlightMoveWithArrow || twoBoards && partnerUp) && squareSize >= 32;
 }
 
-void
+static void
 DrawArrowHighlight (int fromX, int fromY, int toX,int toY)
 {
     if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)