home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume2 / nchess / part01 / boardsw.c next >
C/C++ Source or Header  |  1987-11-20  |  34KB  |  1,255 lines

  1. /*
  2.  * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
  3.  * Stanwood, WA  98282.   All rights reserved.
  4.  */
  5.  
  6. /*
  7.  * handle the board subwindow (as well as fielding RPC and chess game
  8.  * process selects)
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <suntool/tool_hs.h>
  13. #include <suntool/panel.h>
  14. #include <suntool/gfxsw.h>
  15. #include <suntool/icon_load.h>
  16. #include <sys/resource.h>
  17. #include <sys/ioctl.h>
  18. #include <strings.h>
  19.  
  20. #include "nchess.h"
  21.  
  22. #define    MOVE_PR_WIDTH    (SQUARE_WIDTH * 2)
  23. #define    MOVE_PR_HEIGHT    (SQUARE_HEIGHT * 2)
  24. #define    MOVE_X_OFFSET    (MOVE_PR_WIDTH/2 - SQUARE_WIDTH/2)
  25. #define    MOVE_Y_OFFSET    (MOVE_PR_HEIGHT/2 - SQUARE_HEIGHT/2)
  26.  
  27. extern int svc_fds;            /* RPC service file descriptor(s) */
  28. int BoardSWMask;            /* board gfx sw file des. */
  29. BOOL Flashing = FALSE;            /* tool icon is flashing */
  30.  
  31. enum {                    /* confirmation state using mouse */
  32.     CONFIRM_WANTED,
  33.     CONFIRM_SETUP_END,
  34.     CONFIRM_WHOSE_TURN,
  35.     CONFIRM_UNDO,
  36.     CONFIRM_RESIGNATION,
  37. } confirmState;
  38.  
  39. MouseState Mouse = IDLE;
  40.  
  41. char * PieceIconFileNames[] = {
  42.     "pawn.icon",
  43.     "knight.icon",
  44.     "bishop.icon",
  45.     "rook.icon",
  46.     "queen.icon",
  47.     "king.icon",
  48. };
  49.  
  50. char * PieceStencilFileNames[] = {
  51.     "pawnStencil.icon",
  52.     "knightStencil.icon",
  53.     "bishopStencil.icon",
  54.     "rookStencil.icon",
  55.     "queenStencil.icon",
  56.     "kingStencil.icon",
  57. };
  58.  
  59. /*
  60.  * piece icons and stencils
  61.  */
  62. unsigned short RookBlackImage[] = {
  63. #include "Icons/rook.icon"
  64. };
  65. unsigned short RookWhiteImage[] = {
  66. #include "Icons/rook.icon"
  67. };
  68. unsigned short RookStencilImage[] = {
  69. #include "Icons/rookStencil.icon"
  70. };
  71. mpr_static(RookBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookBlackImage);
  72. mpr_static(RookWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookWhiteImage);
  73. mpr_static(RookStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, RookStencilImage);
  74.  
  75. unsigned short KnightBlackImage[] = {
  76. #include "Icons/knight.icon"
  77. };
  78. unsigned short KnightWhiteImage[] = {
  79. #include "Icons/knight.icon"
  80. };
  81. unsigned short KnightStencilImage[] = {
  82. #include "Icons/knightStencil.icon"
  83. };
  84. mpr_static(KnightBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightBlackImage);
  85. mpr_static(KnightWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightWhiteImage);
  86. mpr_static(KnightStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KnightStencilImage);
  87.  
  88. unsigned short BishopBlackImage[] = {
  89. #include "Icons/bishop.icon"
  90. };
  91. unsigned short BishopWhiteImage[] = {
  92. #include "Icons/bishop.icon"
  93. };
  94. unsigned short BishopStencilImage[] = {
  95. #include "Icons/bishopStencil.icon"
  96. };
  97. mpr_static(BishopBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopBlackImage);
  98. mpr_static(BishopWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopWhiteImage);
  99. mpr_static(BishopStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BishopStencilImage);
  100.  
  101. unsigned short KingBlackImage[] = {
  102. #include "Icons/king.icon"
  103. };
  104. unsigned short KingWhiteImage[] = {
  105. #include "Icons/king.icon"
  106. };
  107. unsigned short KingStencilImage[] = {
  108. #include "Icons/kingStencil.icon"
  109. };
  110. mpr_static(KingBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingBlackImage);
  111. mpr_static(KingWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingWhiteImage);
  112. mpr_static(KingStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, KingStencilImage);
  113.  
  114. unsigned short QueenBlackImage[] = {
  115. #include "Icons/queen.icon"
  116. };
  117. unsigned short QueenWhiteImage[] = {
  118. #include "Icons/queen.icon"
  119. };
  120. unsigned short QueenStencilImage[] = {
  121. #include "Icons/queenStencil.icon"
  122. };
  123. mpr_static(QueenBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenBlackImage);
  124. mpr_static(QueenWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenWhiteImage);
  125. mpr_static(QueenStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, QueenStencilImage);
  126.  
  127. unsigned short PawnBlackImage[] = {
  128. #include "Icons/pawn.icon"
  129. };
  130. unsigned short PawnWhiteImage[] = {
  131. #include "Icons/pawn.icon"
  132. };
  133. unsigned short PawnStencilImage[] = {
  134. #include "Icons/pawnStencil.icon"
  135. };
  136. mpr_static(PawnBlackPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnBlackImage);
  137. mpr_static(PawnWhitePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnWhiteImage);
  138. mpr_static(PawnStencilPR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, PawnStencilImage);
  139.  
  140. struct pixrect * PieceStencils[6] = {
  141.     &PawnStencilPR,
  142.     &KnightStencilPR,
  143.     &BishopStencilPR,
  144.     &RookStencilPR,
  145.     &QueenStencilPR,
  146.     &KingStencilPR,
  147. };
  148.  
  149. struct pixrect * PieceIcons[6][2] = {
  150.     &PawnBlackPR,    &PawnWhitePR,
  151.     &KnightBlackPR,    &KnightWhitePR,
  152.     &BishopBlackPR,    &BishopWhitePR,
  153.     &RookBlackPR,    &RookWhitePR,
  154.     &QueenBlackPR,    &QueenWhitePR,
  155.     &KingBlackPR,    &KingWhitePR,
  156. };
  157.  
  158. /*
  159.  * blank square pixrects
  160.  */
  161. unsigned short WhiteSquareImage[] = {
  162. #include "Icons/whiteSquare.icon"
  163. };
  164. mpr_static(WhiteSquarePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, WhiteSquareImage);
  165.  
  166. unsigned short BlackSquareImage[] = {
  167. #include "Icons/blackSquare.icon"
  168. };
  169. mpr_static(BlackSquarePR, SQUARE_WIDTH, SQUARE_HEIGHT, 1, BlackSquareImage);
  170.  
  171. /* board subwindow handles */
  172. struct toolsw * BoardSW;
  173. struct gfxsubwindow * Board;
  174.  
  175. /* pixrects used for piece animation */
  176. struct pixrect * MoveFromPR, * MoveToPR;
  177.  
  178. /* pixrect used for victim drawing */
  179. struct pixrect * VictimPR;
  180.  
  181. /*
  182.  * board sigwinch handler 
  183.  */
  184. /*ARGSUSED*/
  185. boardSigwinch(sw)
  186.     caddr_t sw;
  187. {
  188.     gfxsw_interpretesigwinch(Board);
  189.     gfxsw_handlesigwinch(Board);
  190.     if (Board->gfx_flags & GFX_RESTART) {
  191.     Board->gfx_flags &= ~ GFX_RESTART;
  192.     DrawBoard();
  193.     }
  194. }
  195.  
  196. /*
  197.  * map a mouse coordinate to a board coordinate
  198.  */
  199. void
  200. mapMouseToBoard(mlocp, blocp)
  201.     struct pr_pos * mlocp;
  202.     BoardCoordinate * blocp;
  203. {
  204.     if (MyColor == WHITE) {
  205.     blocp->x = mlocp->x / (SQUARE_WIDTH-1);
  206.     blocp->y = mlocp->y / (SQUARE_HEIGHT-1);
  207.     } else {
  208.     blocp->x = (8 * (SQUARE_WIDTH-1) - mlocp->x)/(SQUARE_WIDTH-1);
  209.     blocp->y = (8 * (SQUARE_HEIGHT-1) - mlocp->y)/(SQUARE_HEIGHT-1);
  210.     }
  211. }
  212.  
  213. /* 
  214.  * map a board coordinate to a mouse coordinate
  215.  */
  216. void
  217. mapBoardToMouse(blocp, mlocp)
  218.     BoardCoordinate * blocp;
  219.     struct pr_pos * mlocp;
  220. {
  221.     if (MyColor == WHITE) {
  222.     mlocp->x = blocp->x * (SQUARE_WIDTH-1) - 1;
  223.     mlocp->y = blocp->y * (SQUARE_HEIGHT-1) - 1;
  224.     } else {
  225.     mlocp->x = (7 - blocp->x) * (SQUARE_WIDTH-1) - 1;
  226.     mlocp->y = (7 - blocp->y) * (SQUARE_WIDTH-1) - 1;
  227.     }
  228. }
  229.  
  230. /*
  231.  * put a piece back where we got it (used to abort piece animation for 
  232.  * various reasons)
  233.  */
  234. void
  235. putPieceBack(from, stencil, icon)
  236.     BoardCoordinate * from;
  237.     struct pixrect * stencil, * icon;
  238. {
  239.     struct pr_pos loc;
  240.  
  241.     mapBoardToMouse(from, &loc);
  242.     pw_stencil(Board->gfx_pixwin, 
  243.     loc.x, loc.y,
  244.     SQUARE_WIDTH, SQUARE_HEIGHT,
  245.     PIX_SRC, stencil, 0, 0, icon, 0, 0);
  246. }
  247.  
  248. /*
  249.  * parameters which belong in boardSelected(), but which are shared
  250.  * with RequestUndo() so that we can abort piece animation if the 
  251.  * klutz at the other end panics (via an undo request or a resignation).  
  252.  * all of them need to be static, anyway.
  253.  */
  254.  
  255. BoardCoordinate from, to;
  256. struct pixrect * pieceIcon, * pieceStencil;
  257. struct pr_pos lastMouseLoc;
  258.  
  259. /*
  260.  * abort any mouse activity - this really only means aborting piece 
  261.  * animation.
  262.  */
  263. void
  264. KillMouseActivity()
  265. {
  266.     switch (Mouse) {
  267.     case PROMOTING_PAWN:
  268.     UnDoMove();
  269.     break;
  270.     case MOVING_PIECE:
  271.     /* repaint the background */
  272.     pw_rop(Board->gfx_pixwin,
  273.         lastMouseLoc.x - MOVE_X_OFFSET,
  274.         lastMouseLoc.y - MOVE_Y_OFFSET,
  275.         MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  276.         PIX_SRC, MoveFromPR, 0, 0);
  277.     putPieceBack(&from, pieceStencil, pieceIcon);
  278.     break;
  279.     }
  280. }
  281.  
  282. /*
  283.  * relay a request for an undo by the opponent.
  284.  *
  285.  * this has the side-effect of aborting any mouse activity that the 
  286.  * user had going at the time.  however, setups will not be interrupted 
  287.  * by undo requests since the (spurious) undo request will be prevented 
  288.  * when the opponent's program detects that he hasn't moved yet.
  289.  */
  290. void
  291. RequestUndo()
  292. {
  293.     Message("Your opponent wants to undo - left OK, other not OK");
  294.     KillMouseActivity();
  295.     Mouse = CONFIRMING;
  296.     confirmState = CONFIRM_UNDO;
  297. }
  298.  
  299. /*
  300.  * confirm a wish to resign
  301.  */
  302. void
  303. ConfirmResignation()
  304. {
  305.  
  306.     Message("Sure you want to resign? - left yes, other no");
  307.     Mouse = CONFIRMING;
  308.     confirmState = CONFIRM_RESIGNATION;
  309. }
  310.  
  311. /*
  312.  * board select() handler 
  313.  */
  314. /*ARGSUSED*/
  315. boardSelected(nullsw, ibits, obits, ebits, timer)
  316.     caddr_t * nullsw;
  317.     int * ibits, * obits, * ebits;
  318.     struct timeval ** timer;
  319. {
  320.     static tickCount = 0;
  321.     static Move move;
  322.     static SetupChange setup;
  323.     struct inputevent ie;
  324.     struct pr_pos newMouseLoc;
  325.     Square * sqp;
  326.     long nbytes;
  327.     BOOL clamped;
  328.     int color, i;
  329.     struct pixrect * pr;
  330.  
  331.     /*
  332.      * 1-second ticker.  this cannot use SIGALRM, since the RPC
  333.      * package already has dibs on that signal for implementing timeouts.
  334.      * hence, it uses the subwindow select timeout mechanism.
  335.      * the ticker is used to flash the window every 5 seconds if 
  336.      * there is some event the user hasn't seen yet (opening the 
  337.      * tool window turns the flasher off).
  338.      *
  339.      * note - timeouts render the file descriptor masks undefined, 
  340.      * so we clean up and return w/o checking them.
  341.      */
  342.     if ((*timer)->tv_sec == 0L && (*timer)->tv_usec == 0L) {
  343.     if (Flashing) {
  344.         if (wmgr_iswindowopen(NchessTool->tl_windowfd)) {
  345.         tickCount = 0;
  346.         Flashing = FALSE;
  347.         } else if (tickCount-- <= 0
  348.         && (pr = (struct pixrect *) tool_get_attribute(NchessTool, 
  349.         WIN_ICON_IMAGE)) != (struct pixrect *) -1)
  350.         {
  351.         tickCount = 5;
  352.         pr_rop(pr, 0, 0, pr->pr_size.x, pr->pr_size.x, 
  353.             PIX_NOT(PIX_SRC), pr, 0, 0);
  354.         tool_set_attributes(NchessTool, WIN_ICON_IMAGE, pr, 0);
  355.         pr_rop(pr, 0, 0, pr->pr_size.x, pr->pr_size.x, 
  356.             PIX_NOT(PIX_SRC), pr, 0, 0);
  357.         tool_set_attributes(NchessTool, WIN_ICON_IMAGE, pr, 0);
  358.         tool_free_attribute(WIN_ICON_IMAGE, pr);
  359.         }
  360.     }
  361.     /* reset the timer and the file des. masks */
  362.     (*timer)->tv_sec = 1L;
  363.     (*timer)->tv_usec = 0L;
  364.     * ibits = svc_fds | BoardSWMask 
  365.         | ChessProcessFDs[BLACK] | ChessProcessFDs[WHITE];
  366.     * obits = * ebits = 0;
  367.     return;
  368.     }
  369.     /* 
  370.      * check for RPC service required 
  371.      */
  372.     if (*ibits & svc_fds) {
  373.     svc_getreq(*ibits & svc_fds);
  374.     } 
  375.     /*
  376.      * check for machine move received
  377.      *
  378.      * note: it is possible in some circumstances to receive a move
  379.      * from a machine player after the game is over (for example, 
  380.      * the opponent of the machine which is on move dies).
  381.      * in that event, we simply throw the move away.
  382.      */
  383.     for (color = BLACK , i = 0  ; i < 2 ; color = WHITE , i++) {
  384.     if ((*ibits & ChessProcessFDs[color]) 
  385.     && GetMachineMove(&move, color)
  386.     && ! GameOver) {
  387.         BOOL updateMsgWindow = TRUE;
  388.  
  389.         Flashing = TRUE;
  390.         DoMove(&move, TRUE);
  391.         Turn = OTHERCOLOR(Turn);
  392.         /* 
  393.          * if we are trying to save a game of machine vs. machine,
  394.          * hold up sending the move until both machine states 
  395.          * have been saved.  when subsequently restoring the 
  396.          * game, this move will be resubmitted.
  397.          */
  398.         if (SaveWanted) {
  399.         SaveGame(SaveFileName);
  400.         SaveWanted = FALSE;
  401.         updateMsgWindow = FALSE;
  402.         }
  403.         /* 
  404.          * if the player not moving is a machine, send the move 
  405.          */
  406.         if (IsMachine[OTHERCOLOR(color)]) {
  407.         SendMove(&move, OTHERCOLOR(color));
  408.         /*
  409.          * else if the player not moving is a human that wants an
  410.          * undo, back it out
  411.          */
  412.         } else if (UndoWanted) {
  413.         MachineUndo(color);
  414.         UndoWanted = FALSE;
  415.         Mouse = IDLE;
  416.         }
  417.         if (updateMsgWindow)
  418.         WhoseMoveMessage((char *) 0);
  419.     }
  420.     }
  421.     /*
  422.      * check for board subwindow service required
  423.      */
  424.     if (*ibits & BoardSWMask) {
  425.     if (input_readevent(BoardSW->ts_windowfd, &ie) == -1) {
  426.         perror("input failed");
  427.         abort();
  428.     }
  429.     switch (Mouse) {
  430.     /*
  431.      * locked: ignore all mouse activity
  432.      */
  433.     case LOCKED:
  434.         break;
  435.     /* 
  436.      * we are using the mouse to confirm something 
  437.      */
  438.     case CONFIRMING:
  439.         if (win_inputposevent(&ie) 
  440.         && ie.ie_code >= BUT_FIRST
  441.         && ie.ie_code <= BUT_LAST) {
  442.         Mouse = IDLE;
  443.         switch(confirmState) {
  444.         case CONFIRM_RESIGNATION:
  445.             if (ie.ie_code == MS_LEFT) {
  446.             SendResignation(PeerColor);
  447.             Mouse = LOCKED;        /* game is over */
  448.             DoResignation(MyColor);
  449.             Message("Resigned");
  450.             } else {
  451.             WhoseMoveMessage((char *) 0);
  452.             }
  453.             break;
  454.         case CONFIRM_SETUP_END:
  455.             if (ie.ie_code == MS_LEFT) {
  456.             /* 
  457.              * if either player is a machine, white always moves
  458.              * first following a setup (another brain-damaged
  459.              * attribute of the unix chess program).
  460.              */
  461.             if (IsMachine[WHITE] || IsMachine[BLACK]) {
  462.                 BOOL legalSetup = TRUE;
  463.  
  464.                 Turn = WHITE;
  465.                 if (IsMachine[BLACK]) {
  466.                 legalSetup = MachineSetup(BLACK);
  467.                 }
  468.                 if (legalSetup && IsMachine[WHITE]) {
  469.                 if (legalSetup = MachineSetup(WHITE))
  470.                     MachineFirst(WHITE);
  471.                 }
  472.                 if ( ! legalSetup) {
  473.                 Message("Illegal setup - try again");
  474.                 Mouse = SETUP;
  475.                 } else {
  476.                 /*
  477.                  * if both players are machines, the human part
  478.                  * is over.
  479.                  */
  480.                 if (IsMachine[BLACK] && IsMachine[WHITE]) 
  481.                     Mouse = LOCKED;
  482.                 /*
  483.                  * else we get to play
  484.                  */
  485.                 else 
  486.                     InitialTurn = WHITE;
  487.                 WhoseMoveMessage((char *) 0);
  488.                 SetupMode = FALSE;
  489.                 }
  490.             /*
  491.              * else the opponent is a human, and we can specify
  492.              * who moves first.
  493.              */
  494.             } else {
  495.                 Message("Left button to move first, other to move second");
  496.                 Mouse = CONFIRMING;
  497.                 confirmState = CONFIRM_WHOSE_TURN;
  498.                 SetupMode = FALSE;
  499.             }
  500.             } else {
  501.             Message("Setup: left - source, middle - delete, right - end");
  502.             Mouse = SETUP;
  503.             }
  504.             break;
  505.         case CONFIRM_WHOSE_TURN:
  506.             Turn = InitialTurn = (ie.ie_code == MS_LEFT ? 
  507.             MyColor : 
  508.             OTHERCOLOR(MyColor));
  509.             WhoseMoveMessage((char *) 0);
  510.             SendEndRestore();
  511.             break;
  512.         case CONFIRM_UNDO:
  513.             SendUndoAcknowledgement(ie.ie_code == MS_LEFT);
  514.             break;
  515.         }
  516.         }
  517.         break;
  518.     /*
  519.      * we are setting up an initial board layout
  520.      */
  521.     case SETUP:
  522.         switch (ie.ie_code) {
  523.         /*
  524.          * generate and pick up a source piece
  525.          */
  526.         case MS_LEFT:
  527.         if (win_inputposevent(&ie)) {
  528.             newMouseLoc.x = ie.ie_locx;
  529.             newMouseLoc.y = ie.ie_locy;
  530.             mapMouseToBoard(&newMouseLoc, &from);
  531.             /* if this a source square */
  532.             if (IsSrcPieceAt(&from)) {
  533.             Mouse = MOVING_PIECE;
  534.             sqp = GetSrcSquare(from.x, from.y);
  535.             setup.type = sqp->type;
  536.             setup.color = sqp->color;
  537.             /*
  538.              * create the first background pixrect,
  539.              * centered on the selected board square
  540.              */
  541.             mapBoardToMouse(&from, &lastMouseLoc);
  542.             /* grab the currently displayed image */
  543.             pw_read(MoveFromPR, 
  544.                 0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  545.                 PIX_SRC,
  546.                 Board->gfx_pixwin,
  547.                 lastMouseLoc.x - MOVE_X_OFFSET,
  548.                 lastMouseLoc.y - MOVE_Y_OFFSET);
  549.             /* repaint the blank square */
  550.             pr_rop(MoveFromPR,
  551.                 MOVE_X_OFFSET,
  552.                 MOVE_Y_OFFSET,
  553.                 SQUARE_WIDTH, SQUARE_HEIGHT,
  554.                 PIX_SRC,
  555.                 ((from.x + from.y) & 0x01) ? 
  556.                 &BlackSquarePR :
  557.                 &WhiteSquarePR,
  558.                 0, 0);
  559.             /* 
  560.              * remember the pixrect used to paint the piece 
  561.              * being moved 
  562.              */
  563.             pieceIcon = PieceIcons[(int) sqp->type][sqp->color];
  564.             pieceStencil = PieceStencils[(int) sqp->type];
  565.             /* 
  566.              * if there is a piece at the source square, repaint 
  567.              * the piece on the background pixrect 
  568.              */
  569.             sqp = GetSquare(from.x, from.y);
  570.             if (sqp->type != NULLPC) {
  571.                 pr_stencil(MoveFromPR,
  572.                 MOVE_X_OFFSET,
  573.                 MOVE_Y_OFFSET,
  574.                 SQUARE_WIDTH, SQUARE_HEIGHT,
  575.                 PIX_SRC, 
  576.                 PieceStencils[(int)sqp->type], 0, 0, 
  577.                 PieceIcons[(int) sqp->type][sqp->color], 0, 0);
  578.             }
  579.             }
  580.         }
  581.         break;
  582.         /*
  583.          * delete a piece 
  584.          */
  585.         case MS_MIDDLE:
  586.         if (win_inputposevent(&ie)) {
  587.             newMouseLoc.x = ie.ie_locx;
  588.             newMouseLoc.y = ie.ie_locy;
  589.             mapMouseToBoard(&newMouseLoc, &from);
  590.             setup.x = from.x;
  591.             setup.y = from.y;
  592.             setup.type = NULLPC;
  593.             DoSetupChange(&setup);
  594.             SendSetupChange(&setup, PeerColor);
  595.         }
  596.         break;
  597.         /*
  598.          * exit setup
  599.          */
  600.         case MS_RIGHT:
  601.         if (win_inputposevent(&ie)) {
  602.             Message("Sure you want to end setup? left - yes, other - no");
  603.             Mouse = CONFIRMING;
  604.             confirmState = CONFIRM_SETUP_END;
  605.         }
  606.         break;
  607.         }
  608.         break;
  609.     /*
  610.      * we are promoting a pawn
  611.      */
  612.     case PROMOTING_PAWN:
  613.         switch(ie.ie_code) {
  614.         /*
  615.          * select the next pawn morph
  616.          */
  617.         case MS_LEFT:
  618.         if (win_inputposevent(&ie))
  619.             move.newPieceType = PromotePawn(&to);
  620.         break;
  621.         /*
  622.          * go for the current morph
  623.          */
  624.         case MS_MIDDLE:
  625.         if (win_inputposevent(&ie) && SendMove(&move, PeerColor)) {
  626.             Turn = OTHERCOLOR(Turn);
  627.             WhoseMoveMessage((char *) 0);
  628.             Mouse = IDLE;
  629.         }
  630.         break;
  631.         /*
  632.          * we exited the window - back out the pawn move 
  633.          */
  634.         case LOC_WINEXIT:
  635.         UnDoMove();
  636.         Mouse = IDLE;
  637.         break;
  638.         }
  639.         break;
  640.     /* 
  641.      * we aren't currently doing anything
  642.      */
  643.     case IDLE:
  644.         switch(ie.ie_code) {
  645.         case MS_LEFT:
  646.         /*
  647.          * if this a left button press 
  648.          * and it is our turn
  649.          * and we aren't waiting for an undo acknowledgement
  650.          */
  651.         if (win_inputposevent(&ie) && Turn == MyColor && ! UndoWanted) {
  652.             newMouseLoc.x = ie.ie_locx;
  653.             newMouseLoc.y = ie.ie_locy;
  654.             mapMouseToBoard(&newMouseLoc, &from);
  655.             /* 
  656.              * if there is one of our pieces on this square 
  657.              */
  658.             if (IsOurPieceAt(&from)) {
  659.             Mouse = MOVING_PIECE;
  660.             sqp = GetSquare(from.x, from.y);
  661.             /*
  662.              * create the first background pixrect,
  663.              * centered on the selected board square
  664.              */
  665.             mapBoardToMouse(&from, &lastMouseLoc);
  666.             /* grab the currently displayed image */
  667.             pw_read(MoveFromPR, 
  668.                 0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  669.                 PIX_SRC,
  670.                 Board->gfx_pixwin,
  671.                 lastMouseLoc.x - MOVE_X_OFFSET,
  672.                 lastMouseLoc.y - MOVE_Y_OFFSET);
  673.             /* repaint the blank square */
  674.             pr_rop(MoveFromPR,
  675.                 MOVE_X_OFFSET,
  676.                 MOVE_Y_OFFSET,
  677.                 SQUARE_WIDTH, SQUARE_HEIGHT,
  678.                 PIX_SRC,
  679.                 ((from.x + from.y) & 0x01) ? 
  680.                 &BlackSquarePR :
  681.                 &WhiteSquarePR,
  682.                 0, 0);
  683.             /* 
  684.              * remember the pixrect used to paint the piece 
  685.              * being moved 
  686.              */
  687.             pieceIcon = PieceIcons[(int) sqp->type][sqp->color];
  688.             pieceStencil = PieceStencils[(int) sqp->type];
  689.             /*
  690.              * a bit un-structured, but we are forced to do this
  691.              * if we want the piece to "jump" to the cursor when
  692.              * the button is initially depressed ("forced" in the
  693.              * sense that we are inside a switch statement).
  694.              */
  695.             goto moveIt;
  696.             }
  697.         }
  698.         break;
  699.         }
  700.         break;
  701.     /*
  702.      * we are animating a piece 
  703.      */
  704.     case MOVING_PIECE:
  705.         switch(ie.ie_code) {
  706.         case MS_LEFT:
  707.         /*
  708.          * if we are putting down a piece
  709.          */
  710.         if (win_inputnegevent(&ie)) {
  711.             BOOL legal;
  712.  
  713.             Mouse = IDLE;
  714.             newMouseLoc.x = ie.ie_locx;
  715.             newMouseLoc.y = ie.ie_locy;
  716.             mapMouseToBoard(&newMouseLoc, &to);
  717.             legal = TRUE;
  718.             move.x1 = from.x; move.y1 = from.y;
  719.             move.x2 = to.x; move.y2 = to.y;
  720.             if (SetupMode) {
  721.             /* repaint the background */
  722.             pw_rop(Board->gfx_pixwin,
  723.                 lastMouseLoc.x - MOVE_X_OFFSET,
  724.                 lastMouseLoc.y - MOVE_Y_OFFSET,
  725.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  726.                 PIX_SRC, MoveFromPR, 0, 0);
  727.             /* put the piece down no matter what */
  728.             setup.x = to.x;
  729.             setup.y = to.y;
  730.             DoSetupChange(&setup);
  731.             SendSetupChange(&setup, PeerColor);
  732.             Mouse = SETUP;
  733.             } else if ( ! (from.x == to.x && from.y == to.y) 
  734.             && Turn == MyColor 
  735.             && (legal = IsMoveLegal(&from, &to))) {
  736.             /* if this is a pawn promotion */
  737.             if (GetSquare(from.x, from.y)->type == PAWN
  738.             && (to.y == 0 || to.y == 7)) {
  739.                 /* repaint the background */
  740.                 pw_rop(Board->gfx_pixwin,
  741.                 lastMouseLoc.x - MOVE_X_OFFSET,
  742.                 lastMouseLoc.y - MOVE_Y_OFFSET,
  743.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  744.                 PIX_SRC, MoveFromPR, 0, 0);
  745.                 move.newPieceType = (int) QUEEN;
  746.                 DoMove(&move, TRUE);
  747.                 /* if we are playing the brain-damaged unix chess
  748.                  * program, can only promote to queens */
  749.                 if (IsMachine[OTHERCOLOR(MyColor)]) {
  750.                 Turn = OTHERCOLOR(Turn);
  751.                 SendMove(&move, PeerColor);
  752.                 WhoseMoveMessage((char *) 0);
  753.                 /* else need to have the user select the promoted 
  754.                  * piece type */
  755.                 } else {
  756.                 Message("Left button: select piece type, middle: send move.");
  757.                 Mouse = PROMOTING_PAWN;
  758.                 }
  759.             /* else if we can send the move */
  760.             } else if (SendMove(&move, PeerColor)) {
  761.                 /* repaint the background */
  762.                 pw_rop(Board->gfx_pixwin,
  763.                 lastMouseLoc.x - MOVE_X_OFFSET,
  764.                 lastMouseLoc.y - MOVE_Y_OFFSET,
  765.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  766.                 PIX_SRC, MoveFromPR, 0, 0);
  767.                 DoMove(&move, TRUE);
  768.                 Turn = OTHERCOLOR(Turn);
  769.                 WhoseMoveMessage((char *) 0);
  770.             /* else the peer is dead */
  771.             } else {
  772.                 /* repaint the background */
  773.                 pw_rop(Board->gfx_pixwin,
  774.                 lastMouseLoc.x - MOVE_X_OFFSET,
  775.                 lastMouseLoc.y - MOVE_Y_OFFSET,
  776.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  777.                 PIX_SRC, MoveFromPR, 0, 0);
  778.                 putPieceBack(&from, pieceStencil, pieceIcon);
  779.             }
  780.             } else {
  781.             /* repaint the background */
  782.             pw_rop(Board->gfx_pixwin,
  783.                 lastMouseLoc.x - MOVE_X_OFFSET,
  784.                 lastMouseLoc.y - MOVE_Y_OFFSET,
  785.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  786.                 PIX_SRC, MoveFromPR, 0, 0);
  787.             putPieceBack(&from, pieceStencil, pieceIcon);
  788.             if ( ! legal)
  789.                 Message("Illegal move");
  790.             }
  791.         }
  792.         break;
  793.         /*
  794.          * exited the window - clean it up.
  795.          */
  796.         case LOC_WINEXIT:
  797.         /* repaint the background */
  798.         pw_rop(Board->gfx_pixwin,
  799.             lastMouseLoc.x - MOVE_X_OFFSET,
  800.             lastMouseLoc.y - MOVE_Y_OFFSET,
  801.             MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  802.             PIX_SRC, MoveFromPR, 0, 0);
  803.         if (SetupMode) {
  804.             Mouse = SETUP;
  805.         } else {
  806.             putPieceBack(&from, pieceStencil, pieceIcon);
  807.             Mouse = IDLE;
  808.         }
  809.         break;
  810.         /* 
  811.          * animate the piece
  812.          */
  813.         case LOC_MOVEWHILEBUTDOWN:
  814.     moveIt:
  815.         /* ignore old motion events */
  816.         ioctl(Board->gfx_windowfd, (int) FIONREAD, (char *) &nbytes);
  817.         if (nbytes/sizeof(struct inputevent) <= 3) {
  818.             do {
  819.             newMouseLoc.x = ie.ie_locx - SQUARE_WIDTH/2;
  820.             newMouseLoc.y = ie.ie_locy - SQUARE_HEIGHT/2;
  821.             clamped = FALSE;
  822.             /*
  823.              * clamp motion if necessary
  824.              */
  825.             if (newMouseLoc.x - lastMouseLoc.x >= MOVE_X_OFFSET) {
  826.                 newMouseLoc.x = lastMouseLoc.x + (MOVE_X_OFFSET-1);
  827.                 clamped = TRUE;
  828.             } else if (newMouseLoc.x - lastMouseLoc.x <= - MOVE_X_OFFSET) {
  829.                 newMouseLoc.x = lastMouseLoc.x - (MOVE_X_OFFSET-1);
  830.                 clamped = TRUE;
  831.             } 
  832.             if (newMouseLoc.y - lastMouseLoc.y >= MOVE_Y_OFFSET) {
  833.                 newMouseLoc.y = lastMouseLoc.y + (MOVE_Y_OFFSET-1);
  834.                 clamped = TRUE;
  835.             } else if (newMouseLoc.y - lastMouseLoc.y <= - MOVE_Y_OFFSET) {
  836.                 newMouseLoc.y = lastMouseLoc.y - (MOVE_Y_OFFSET-1);
  837.                 clamped = TRUE;
  838.             }
  839.             /* grab the new area */
  840.             pw_read(MoveToPR, 
  841.                 0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  842.                 PIX_SRC, Board->gfx_pixwin,
  843.                 newMouseLoc.x - MOVE_X_OFFSET,
  844.                 newMouseLoc.y - MOVE_Y_OFFSET);
  845.             /* paste the old background over the new area */
  846.             pr_rop(MoveToPR,
  847.                 lastMouseLoc.x - newMouseLoc.x,
  848.                 lastMouseLoc.y - newMouseLoc.y,
  849.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  850.                 PIX_SRC, MoveFromPR, 0, 0);
  851.             /* save the new background */
  852.             pr_rop(MoveFromPR, 0, 0, MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  853.                 PIX_SRC, MoveToPR, 0, 0);
  854.             /* paint the piece on the new area */
  855.             pr_stencil(MoveToPR, 
  856.                 MOVE_X_OFFSET, MOVE_Y_OFFSET,
  857.                 SQUARE_WIDTH, SQUARE_HEIGHT,
  858.                 PIX_SRC, pieceStencil, 0, 0, pieceIcon, 0, 0);
  859.             /* now paint the new area on the screen */
  860.             pw_rop(Board->gfx_pixwin,
  861.                 newMouseLoc.x - MOVE_X_OFFSET,
  862.                 newMouseLoc.y - MOVE_Y_OFFSET,
  863.                 MOVE_PR_WIDTH, MOVE_PR_HEIGHT,
  864.                 PIX_SRC, MoveToPR, 0, 0);
  865.             lastMouseLoc.x = newMouseLoc.x;
  866.             lastMouseLoc.y = newMouseLoc.y;
  867.             } while (clamped);
  868.         }
  869.         break;
  870.         }
  871.         break;
  872.     }
  873.     }
  874.     * ibits = svc_fds | BoardSWMask | ChessProcessFDs[BLACK] | ChessProcessFDs[WHITE];
  875.     * obits = * ebits = 0;
  876. }
  877.  
  878. /*
  879.  * initialize the board subwindow
  880.  */
  881. void
  882. InitBoardSW(useRetained, iconDirectory)
  883.     BOOL useRetained;            /* use a retained pixrect */
  884.     char * iconDirectory;        /* custom piece icon directory */
  885. {
  886.     static struct timeval tickValue;
  887.     struct inputmask mask;
  888.     register unsigned int i;
  889.     int height = (SQUARE_HEIGHT-1) * 8 + ((7 * SQUARE_HEIGHT)/4) + 10;
  890.  
  891.     /*
  892.      * initialize the subwindow
  893.      */
  894.     if ((BoardSW = gfxsw_createtoolsubwindow(NchessTool, "",
  895.     TOOL_SWEXTENDTOEDGE, 
  896.     /* playing surface    +  victim area */
  897. /*    (SQUARE_HEIGHT-1) * 8 + ((7 * SQUARE_HEIGHT)/4) + 10,  */
  898.     height,
  899.     NULL)) == NULL) 
  900.     {
  901.     fprintf(stderr, "Can't create board subwindow\n");
  902.     exit(1);
  903.     }
  904.     Board = (struct gfxsubwindow *) BoardSW->ts_data;
  905.     if (useRetained)
  906.     gfxsw_getretained(Board); 
  907.     BoardSW->ts_io.tio_handlesigwinch = boardSigwinch;
  908.     BoardSW->ts_io.tio_selected = boardSelected;
  909.     input_imnull(&mask);
  910.     win_setinputcodebit(&mask, MS_LEFT);
  911.     win_setinputcodebit(&mask, MS_MIDDLE);
  912.     win_setinputcodebit(&mask, MS_RIGHT);
  913.     win_setinputcodebit(&mask, LOC_MOVEWHILEBUTDOWN);
  914.     win_setinputcodebit(&mask, LOC_WINEXIT);
  915.     mask.im_flags |= IM_NEGEVENT;
  916.     win_setinputmask(BoardSW->ts_windowfd, &mask, NULL, WIN_NULLLINK);
  917.     /* 
  918.      * add the RPC service and chess process file descriptor select
  919.      * masks to this subwindow.
  920.      */
  921.     BoardSW->ts_io.tio_inputmask = svc_fds 
  922.     | (BoardSWMask = 1 << BoardSW->ts_windowfd) 
  923.     | ChessProcessFDs[BLACK] 
  924.     | ChessProcessFDs[WHITE] ;
  925.     /*
  926.      * set the timeout to 1 second 
  927.      */
  928.     tickValue.tv_sec = 1L;
  929.     tickValue.tv_usec = 0L;
  930.     BoardSW->ts_io.tio_timer = &tickValue;
  931.     /*
  932.      * create the white pieces by inverting the black pieces, using custom
  933.      * pieces where appropriate.
  934.      */
  935.     for ( i = 0 ; i < 6 ; i++ ) {
  936.     if (iconDirectory != (char *) 0) {
  937.         FILE * iconFile, * stencilFile;
  938.         icon_header_object iconHeader, stencilHeader;
  939.         char fileName[512], errorMsg[IL_ERRORMSG_SIZE + 2];
  940.  
  941.         strcpy(fileName, iconDirectory);
  942.         strcat(fileName, "/");
  943.         strcat(fileName, PieceIconFileNames[i]);
  944.         if ((iconFile = icon_open_header(fileName, errorMsg, 
  945.         &iconHeader)) != (FILE *) 0) 
  946.         {
  947.         if (iconHeader.width != SQUARE_WIDTH 
  948.         || iconHeader.height != SQUARE_HEIGHT
  949.         || iconHeader.depth != 1) {
  950.             fprintf(stderr, "warning: bogus icon (ignored): %s\n", fileName);
  951.         } else {
  952.             strcpy(fileName, iconDirectory);
  953.             strcat(fileName, "/");
  954.             strcat(fileName, PieceStencilFileNames[i]);
  955.             if ((stencilFile = icon_open_header(fileName, errorMsg, 
  956.             &stencilHeader)) != (FILE *) 0) 
  957.             {
  958.             if (stencilHeader.width != SQUARE_WIDTH 
  959.             || stencilHeader.height != SQUARE_HEIGHT
  960.             || stencilHeader.depth != 1) {
  961.                 fprintf(stderr, "warning: bogus icon (ignored): %s\n", fileName);
  962.             } else {
  963.                 icon_read_pr(iconFile, &iconHeader, PieceIcons[i][BLACK]);
  964.                 icon_read_pr(stencilFile, &stencilHeader, PieceStencils[i]);
  965.             }
  966.             fclose(stencilFile);
  967.             }
  968.         }
  969.         fclose(iconFile);
  970.         }
  971.     }
  972.     pr_rop(PieceIcons[i][WHITE], 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
  973.         PIX_NOT(PIX_SRC),
  974.         PieceIcons[i][BLACK], 0, 0);
  975.     }
  976.     /* 
  977.      * create the pixrects used for piece animation and victim drawing
  978.      */
  979.     if ((MoveFromPR = mem_create(MOVE_PR_WIDTH, MOVE_PR_HEIGHT, 1)) == (struct pixrect *) 0
  980.     || (MoveToPR = mem_create(MOVE_PR_WIDTH, MOVE_PR_HEIGHT, 1)) == (struct pixrect *) 0
  981.     || (VictimPR = mem_create(SQUARE_WIDTH, SQUARE_HEIGHT, 1)) == (struct pixrect *) 0) {
  982.     fprintf(stderr, "can't create the animation pixrects\n");
  983.     exit(1);
  984.     }
  985. }
  986.  
  987. /*
  988.  * draw a square, including the piece (if any)
  989.  */
  990. void
  991. DrawSquare(x, y, sqp)
  992.     int x, y;
  993.     register Square * sqp;
  994. {
  995.     BoardCoordinate bloc;
  996.     struct pr_pos mloc;
  997.  
  998.     bloc.x = x; bloc.y = y;
  999.     mapBoardToMouse(&bloc, &mloc);
  1000.     /* paint the blank square */
  1001.     pw_rop(Board->gfx_pixwin, 
  1002.     mloc.x, mloc.y,
  1003.     SQUARE_WIDTH, SQUARE_HEIGHT,
  1004.     PIX_SRC, 
  1005.     (((x + y) & 0x01) ? &BlackSquarePR : &WhiteSquarePR), 
  1006.     0, 0);
  1007.     /* paint the piece, if there is one */
  1008.     if (sqp->type != NULLPC) {
  1009.     pw_stencil(Board->gfx_pixwin, mloc.x, mloc.y,
  1010.         SQUARE_WIDTH, SQUARE_HEIGHT,
  1011.         PIX_SRC,
  1012.         PieceStencils[(int) sqp->type], 0, 0,
  1013.         PieceIcons[(int) sqp->type][sqp->color], 0, 0);
  1014.     }
  1015. }
  1016.  
  1017. /*
  1018.  * draw the playing surface and victim area
  1019.  */
  1020. void
  1021. DrawBoard()
  1022. {
  1023.     register int x, y;
  1024.     register Square * sqp;
  1025.  
  1026.     /* clear the board area */
  1027.     pw_rop(Board->gfx_pixwin,
  1028.     0, 0, Board->gfx_rect.r_width, Board->gfx_rect.r_height,
  1029.     PIX_CLR, (struct pixrect *) 0, 0, 0);
  1030.     /* draw the playing area */
  1031.     for (x = 0 ; x < 8 ; x++) {
  1032.     for (y = 0 ; y < 8 ; y++) {
  1033.         sqp = GetSquare(x, y);
  1034.         DrawSquare(x, y, sqp);
  1035.     }
  1036.     }
  1037.     /* draw the victims */
  1038.     drawVictims();
  1039. }
  1040.  
  1041. /*
  1042.  * your basic victim 
  1043.  */
  1044. typedef struct {
  1045.     PieceType type;            /* victim type */
  1046.     BOOL active;            /* victim slot state */
  1047.     int count;                /* victim overflow count */
  1048. } Victim;
  1049.  
  1050. #define    NUM_VICTIM_SLOTS 8
  1051.  
  1052. Victim victims[2 /* pawns(1) vs. pieces(0) */][2 /* color */ ][NUM_VICTIM_SLOTS /* victim slot # */];
  1053.  
  1054. /*
  1055.  * map the victim specified by the triple 
  1056.  * [ isPawn { 0, 1 }, color { BLACK, WHITE }, slot { 0 .. NUM_VICTIM_SLOTS-1 } ]
  1057.  * to a mouse coordinate (relative to the board subwindow)
  1058.  */
  1059. void
  1060. mapVictimToMouse(isPawn, color, slot, mlocp)
  1061.     BOOL isPawn;
  1062.     int color, slot;
  1063.     struct pr_pos * mlocp;
  1064. {
  1065.     mlocp->x = slot * (3 * SQUARE_WIDTH/4) + color * (3 * SQUARE_WIDTH/8);
  1066.     mlocp->y = 8 * (SQUARE_HEIGHT-1) + isPawn * (SQUARE_HEIGHT/2) + color * (SQUARE_HEIGHT/4) + 5;
  1067. }
  1068.  
  1069. /* 
  1070.  * draw the victims
  1071.  */
  1072. drawVictims()
  1073. {
  1074.     register int i, j, k;
  1075.     register Victim * victim;
  1076.     struct pr_pos victimOrigin;
  1077.  
  1078.     for (i = 0 ; i < 2 ; i++) {
  1079.     for (j = 0 ; j < 2 ; j++) {
  1080.         for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
  1081.         victim = &victims[i][j][k];
  1082.         if (victim->active) {
  1083.             mapVictimToMouse(i, j, k, &victimOrigin);
  1084.             pw_stencil(Board->gfx_pixwin, 
  1085.             victimOrigin.x, victimOrigin.y,
  1086.             SQUARE_WIDTH, SQUARE_HEIGHT,
  1087.             PIX_SRC,
  1088.             PieceStencils[(int) victim->type], 0, 0,
  1089.             PieceIcons[(int) victim->type][j], 0, 0);
  1090.         }
  1091.         }
  1092.     }
  1093.     }
  1094. }
  1095.  
  1096. /* 
  1097.  * add a piece to the set of victims 
  1098.  */
  1099. void
  1100. AddVictim(type, color, drawIt) 
  1101.     PieceType type;
  1102.     int color;
  1103.     BOOL drawIt;
  1104. {
  1105.     register int i, j, k;
  1106.     int empty, lastMatch, extras;
  1107.     register Victim * victim;
  1108.     BOOL isPawn = (type == PAWN);
  1109.     struct pr_pos victimOrigin, othersOrigin;
  1110.  
  1111.     /* 
  1112.      * look for the first empty slot and the last slot which 
  1113.      * contains a piece of the same type
  1114.      */
  1115.     for (lastMatch = empty = -1 , i = 0 ; i < NUM_VICTIM_SLOTS ; i++) {
  1116.     victim = &victims[isPawn][color][i];
  1117.     if (empty < 0 && ! victim->active)
  1118.         empty = i;
  1119.     if (victim->active && victim->type == type)
  1120.         lastMatch = i;
  1121.     }
  1122.     /*
  1123.      * if there were no empty slots 
  1124.      */
  1125.     if (empty == -1) {
  1126.     /* 
  1127.      * if there was one or more pieces of the same type, update
  1128.      * the last instance's overflow count (includes coalescing
  1129.      * all overflows of that type at the last instance)
  1130.      */
  1131.     if (lastMatch >= 0) {
  1132.         for (extras = i = 0 ; i < lastMatch ; i++) {
  1133.         victim = &victims[isPawn][color][i];
  1134.         if (victim->active && victim->type == type && victim->count > 1) {
  1135.             extras += victim->count - 1;
  1136.             victim->count = 1;
  1137.         }
  1138.         }
  1139.         victims[isPawn][color][lastMatch].count += extras;
  1140.     }
  1141.     /*
  1142.      * else install the victim in the empty slot 
  1143.      */
  1144.     } else {
  1145.     victim = &victims[isPawn][color][empty];
  1146.     victim->type = type;
  1147.     victim->active = TRUE;
  1148.     victim->count = 1;
  1149.     if (drawIt) {
  1150.         /*
  1151.          * re-draw all the pieces in the victim's slot 
  1152.          */
  1153.         mapVictimToMouse(isPawn, color, empty, &victimOrigin);
  1154.         pr_rop(VictimPR, 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
  1155.         PIX_CLR, (struct pixrect *) 0, 0, 0);
  1156.         for (i = 0 ; i < 2 ; i++) {
  1157.         for (j = 0 ; j < 2 ; j++) {
  1158.             for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
  1159.             victim = &victims[i][j][k];
  1160.             if (victim->active) {
  1161.                 mapVictimToMouse(i, j, k, &othersOrigin);
  1162.                 pr_stencil(VictimPR,
  1163.                 othersOrigin.x - victimOrigin.x,
  1164.                 othersOrigin.y - victimOrigin.y,
  1165.                 SQUARE_WIDTH, SQUARE_HEIGHT,
  1166.                 PIX_SRC,
  1167.                 PieceStencils[(int) victim->type], 0, 0,
  1168.                 PieceIcons[(int) victim->type][j], 0, 0);
  1169.             }
  1170.             }
  1171.         }
  1172.         }
  1173.         /*
  1174.          * now re-draw the slot 
  1175.          */
  1176.         pw_rop(Board->gfx_pixwin,
  1177.         victimOrigin.x, victimOrigin.y, 
  1178.         SQUARE_WIDTH, SQUARE_HEIGHT,
  1179.         PIX_SRC, VictimPR, 0, 0);
  1180.     }
  1181.     }
  1182. }
  1183.  
  1184. /*
  1185.  * reincarnate a victim (via an undo)
  1186.  */
  1187. void
  1188. DeleteVictim(type, color)
  1189.     PieceType type;
  1190.     int color;
  1191. {
  1192.     register int i, j, k;
  1193.     int lastMatch, extras;
  1194.     register Victim * victim;
  1195.     BOOL isPawn = (type == PAWN);
  1196.     struct pr_pos victimOrigin, othersOrigin;
  1197.  
  1198.     /* 
  1199.      * look for the last slot which contains a piece of this type
  1200.      */
  1201.     for (lastMatch = -1 , i = 0 ; i < NUM_VICTIM_SLOTS ; i++) {
  1202.     victim = &victims[isPawn][color][i];
  1203.     if (victim->active && victim->type == type)
  1204.         lastMatch = i;
  1205.     }
  1206.     /*
  1207.      * if there were no matches, don't do anything
  1208.      */
  1209.     if (lastMatch == -1) {
  1210.     /* do nothing */
  1211.     /*
  1212.      * else if the last match slot contains overflows, simply 
  1213.      * decrement the overflow count
  1214.      */
  1215.     } else if ((victim = &victims[isPawn][color][lastMatch])->count > 1) {
  1216.     victim->count--;
  1217.     /*
  1218.      * else zero out the slot and re-draw it as empty
  1219.      */
  1220.     } else {
  1221.     victim->active = FALSE;
  1222.     /*
  1223.      * re-draw all the remaining pieces in the victim's slot 
  1224.      */
  1225.     mapVictimToMouse(isPawn, color, lastMatch, &victimOrigin);
  1226.     pr_rop(VictimPR, 0, 0, SQUARE_WIDTH, SQUARE_HEIGHT,
  1227.         PIX_CLR, (struct pixrect *) 0, 0, 0);
  1228.     for (i = 0 ; i < 2 ; i++) {
  1229.         for (j = 0 ; j < 2 ; j++) {
  1230.         for (k = 0 ; k < NUM_VICTIM_SLOTS ; k++) {
  1231.             victim = &victims[i][j][k];
  1232.             if (victim->active) {
  1233.             mapVictimToMouse(i, j, k, &othersOrigin);
  1234.             pr_stencil(VictimPR,
  1235.                 othersOrigin.x - victimOrigin.x,
  1236.                 othersOrigin.y - victimOrigin.y,
  1237.                 SQUARE_WIDTH, SQUARE_HEIGHT,
  1238.                 PIX_SRC,
  1239.                 PieceStencils[(int) victim->type], 0, 0,
  1240.                 PieceIcons[(int) victim->type][j], 0, 0);
  1241.             }
  1242.         }
  1243.         }
  1244.     }
  1245.     /*
  1246.      * now re-draw the slot 
  1247.      */
  1248.     pw_rop(Board->gfx_pixwin,
  1249.         victimOrigin.x, victimOrigin.y, 
  1250.         SQUARE_WIDTH, SQUARE_HEIGHT,
  1251.         PIX_SRC, VictimPR, 0, 0);
  1252.     }
  1253. }
  1254.  
  1255.