Animate piece explosions in drag-drop moves and in XB
authorH.G. Muller <h.g.muller@hccnet.nl>
Thu, 28 Oct 2010 15:51:34 +0000 (17:51 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Thu, 28 Oct 2010 18:23:25 +0000 (20:23 +0200)
This required some code restructuring: the decision if an explosion is
needed is now taken in a new routine Explode() in the backend. This then
calls the front-end driver, and it returns the info if there was an
explosion or not, so the caller (AnimateMove() or the mouse driver) can
take action to repair the damage to the board caused by the blast wave.
A front-end driver for XBoard is provided as well, so that both
click-click (and replay, which is the same) and drag-drop atomic
captures are animated in XB as well as WB.
Explosions on rejected moves are suppressed.

backend.c
backend.h
frontend.h
winboard/winboard.c
xboard.c

index 6c18a36..16fdc62 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -6319,6 +6319,20 @@ MarkTargetSquares(int clear)
   DrawPosition(TRUE, NULL);
 }
 
+int
+Explode(Board board, int fromX, int fromY, int toX, int toY)
+{
+    if(gameInfo.variant == VariantAtomic &&
+       (board[toY][toX] != EmptySquare ||                     // capture?
+        toX != fromX && (board[fromY][fromX] == WhitePawn ||  // e.p. ?
+                         board[fromY][fromX] == BlackPawn   )
+      )) {
+        AnimateAtomicCapture(board, fromX, fromY, toX, toY);
+        return TRUE;
+    }
+    return FALSE;
+}
+
 void LeftClick(ClickType clickType, int xPix, int yPix)
 {
     int x, y;
@@ -6529,9 +6543,13 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
        }
        PromotionPopUp();
     } else {
+       int oldMove = currentMove;
        UserMoveEvent(fromX, fromY, toX, toY, promoChoice);
        if (!appData.highlightLastMove || gotPremove) ClearHighlights();
        if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
+       if(saveAnimate && !appData.animate && currentMove != oldMove && // drag-move was performed
+          Explode(boards[currentMove-1], fromX, fromY, toX, toY))
+           DrawPosition(TRUE, boards[currentMove]);
        fromX = fromY = -1;
     }
     appData.animate = saveAnimate;
index 7b39f88..0b901c1 100644 (file)
--- a/backend.h
+++ b/backend.h
@@ -286,6 +286,7 @@ extern char* StripHighlightAndTitle P((char *));  /* returns static data */
 extern void ics_update_width P((int new_width));
 extern Boolean set_cont_sequence P((char *new_seq));
 extern int wrap P((char *dest, char *src, int count, int width, int *lp));
+int Explode P((Board board, int fromX, int fromY, int toX, int toY));
 
 typedef enum { CheckBox, ComboBox, TextBox, Button, Spin, ResetButton,
                   SaveButton, FileName, PathName, Slider, Message } Control;
index 14fa176..8e57e58 100644 (file)
@@ -191,6 +191,7 @@ void ClearHighlights P((void));
 void SetPremoveHighlights P((int fromX, int fromY, int toX, int toY));
 void ClearPremoveHighlights P((void));
 
+void AnimateAtomicCapture P((Board board, int fromX, int fromY, int toX, int toY));
 void ShutDownFrontEnd P((void));
 void BoardToTop P((void));
 void AnimateMove P((Board board, int fromX, int fromY, int toX, int toY));
index 73a36b6..f818927 100644 (file)
@@ -105,7 +105,6 @@ void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
 VOID NewVariantPopup(HWND hwnd);\r
 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
                   /*char*/int promoChar));\r
-void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
 void DisplayMove P((int moveNumber));\r
 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
 void ChatPopUp P((char *s));\r
@@ -3667,6 +3666,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   if(explodeInfo.radius) { // [HGM] atomic\r
        HBRUSH oldBrush;\r
        int x, y, r=(explodeInfo.radius * squareSize)/100;\r
+        ChessSquare piece = board[explodeInfo.fromY][explodeInfo.fromX];\r
         board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer\r
        SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);\r
        x += squareSize/2;\r
@@ -3679,6 +3679,7 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
        DrawHighlightsOnDC(hdcmem, &highlightInfo, HIGHLIGHT_PEN);\r
        DrawHighlightsOnDC(hdcmem, &premoveHighlightInfo, PREMOVE_PEN);\r
        DrawBoardOnDC(hdcmem, board, tmphdc);\r
+        board[explodeInfo.fromY][explodeInfo.fromX] = piece;\r
        oldBrush = SelectObject(hdcmem, explodeBrush);\r
        Ellipse(hdcmem, x-r, y-r, x+r, y+r);\r
        SelectObject(hdcmem, oldBrush);\r
@@ -9616,26 +9617,26 @@ static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
      POINT frames[], int * nFrames);\r
 \r
 \r
+#define kFactor 4\r
+\r
 void\r
-AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)\r
+AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)\r
 {      // [HGM] atomic: animate blast wave\r
        int i;\r
-if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);\r
+\r
        explodeInfo.fromX = fromX;\r
        explodeInfo.fromY = fromY;\r
        explodeInfo.toX = toX;\r
        explodeInfo.toY = toY;\r
-       for(i=1; i<nFrames; i++) {\r
-           explodeInfo.radius = (i*180)/(nFrames-1);\r
-           DrawPosition(FALSE, NULL);\r
+       for(i=1; i<4*kFactor; i++) {\r
+           explodeInfo.radius = (i*180)/(4*kFactor-1);\r
+           DrawPosition(FALSE, board);\r
            Sleep(appData.animSpeed);\r
        }\r
        explodeInfo.radius = 0;\r
-       DrawPosition(TRUE, NULL);\r
+       DrawPosition(TRUE, board);\r
 }\r
 \r
-#define kFactor 4\r
-\r
 void\r
 AnimateMove(board, fromX, fromY, toX, toY)\r
      Board board;\r
@@ -9694,9 +9695,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
   animInfo.pos = finish;\r
   DrawPosition(FALSE, NULL);\r
   animInfo.piece = EmptySquare;\r
-  if(gameInfo.variant == VariantAtomic && \r
-     (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )\r
-       AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);\r
+  Explode(board, fromX, fromY, toX, toY);\r
 }\r
 \r
 /*      Convert board position to corner of screen rect and color       */\r
index fc6ba3a..67992f1 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -8916,6 +8916,29 @@ FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
   EndAnimation(anim, finish);
 }
 
+void
+AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
+{
+    int i, x, y;
+    ChessSquare piece = board[fromY][toY];
+    board[fromY][toY] = EmptySquare;
+    DrawPosition(FALSE, board);
+    if (flipView) {
+       x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
+       y = lineGap + toY * (squareSize + lineGap);
+    } else {
+       x = lineGap + toX * (squareSize + lineGap);
+       y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
+    }
+    for(i=1; i<4*kFactor; i++) {
+       int r = squareSize * 9 * i/(20*kFactor - 5);
+       XFillArc(xDisplay, xBoardWindow, highlineGC,
+               x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
+       FrameDelay(appData.animSpeed);
+    }
+    board[fromY][toY] = piece;
+}
+
 /* Main control logic for deciding what to animate and how */
 
 void
@@ -8978,6 +9001,11 @@ AnimateMove(board, fromX, fromY, toX, toY)
   else
     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
+  if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
+    int i,j;
+    for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
+      if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
+  }
 
   /* Be sure end square is redrawn */
   damage[0][toY][toX] = True;