home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / Kibitz / DoEvent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-06  |  17.9 KB  |  721 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        doevent.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10.  
  11.  
  12. /*****************************************************************************/
  13.  
  14.  
  15.  
  16. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  17. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  18. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  19.  
  20. #ifndef __AEUTILS__
  21. #include <AEUtils.h>
  22. #endif
  23.  
  24. #ifndef __DESK__
  25. #include <Desk.h>
  26. #endif
  27.  
  28. #ifndef __DISKINIT__
  29. #include <DiskInit.h>
  30. #endif
  31.  
  32. #ifndef __ERRORS__
  33. #include <Errors.h>
  34. #endif
  35.  
  36. #ifndef __MENUS__
  37. #include <Menus.h>
  38. #endif
  39.  
  40. #ifndef __OSEVENTS__
  41. #include <OSEvents.h>
  42. #endif
  43.  
  44. #ifndef __RESOURCES__
  45. #include <Resources.h>
  46. #endif
  47.  
  48. #ifndef __TEXTEDITCONTROL__
  49. #include <TextEditControl.h>
  50. #endif
  51.  
  52. #ifndef __TOOLUTILS__
  53. #include <ToolUtils.h>
  54. #endif
  55.  
  56. #ifndef __UTILITIES__
  57. #include <Utilities.h>
  58. #endif
  59.  
  60.  
  61.  
  62. /*****************************************************************************/
  63.  
  64.  
  65.  
  66. extern Cursor    *gCurrentCursor;
  67.  
  68. unsigned long    gStatusTime;
  69. Boolean            gAlertTimeout, gComputerResigns;
  70.  
  71.  
  72.  
  73. /*****************************************************************************/
  74. /*****************************************************************************/
  75.  
  76.  
  77.  
  78. /* Do the right thing for an event.  Determine what kind of event it is, and
  79. ** call the appropriate routines. */
  80.  
  81. #pragma segment Main
  82. void    DoEvent(EventRecord *event)
  83. {
  84.     short            part, err;
  85.     WindowPtr        window;
  86.     char            key;
  87.     Point            aPoint;
  88.     FileRecHndl        frHndl;
  89.     ControlHandle    ctl;
  90.     long            tick;
  91.     Rect            boardRct;
  92.     short            retval, width, dir;
  93.  
  94.     switch(event->what) {
  95.  
  96.         case nullEvent:
  97.             DoIdleTasks(true);
  98.             break;
  99.  
  100.         case mouseDown:
  101.             gCurrentCursor = nil;
  102.                 /* No shortcuts when we recalculate the cursor region. */
  103.  
  104.             part = FindWindow(event->where, &window);
  105.             if (part != inContent) DoSetCursor(&qd.arrow);
  106.  
  107.             switch(part) {
  108.  
  109.                 case inContent:
  110.                     if (window != FrontWindow()) {
  111.                         SelectWindow(window);
  112.                         if (IsAppWindow(window)) {
  113.                             DoUpdate(window);
  114.                             boardRct = GlobalBoardRect(window);
  115.                             if (PtInRect(event->where, &boardRct))
  116.                                 DoEvent(event);
  117.                         }
  118.                                     /* Do first click if over board. */
  119.                     } else
  120.                         DoContentClick(window, event);
  121.                     break;
  122.  
  123.                 case inDrag:            
  124.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  125.                     break;        /* Pass screenBits.bounds to
  126.                                 ** get all gDevices. */
  127.  
  128.                 case inGoAway:
  129.                     if (TrackGoAway(window, event->where)) {
  130.                         CloseOneWindow(window, iClose);
  131.                     }
  132.                     break;
  133.  
  134.                 case inGrow:
  135.                     break;
  136.  
  137.                 case inMenuBar:        /* Process mouse menu command (if any). */
  138.                     AdjustMenus();
  139.                     DoMenuCommand(MenuSelect(event->where), event);
  140.                     break;
  141.  
  142.                 case inSysWindow:    /* Let the system handle the mouseDown. */
  143.                     SystemClick(event, window);
  144.                     break;
  145.  
  146.                 case inZoomIn:
  147.                 case inZoomOut:
  148.                     if (TrackBox(window, event->where, part)) {
  149.                         width = window->portRect.right - window->portRect.left;
  150.                         if (width == rWindowWidth) width = rJustBoardWindowWidth;
  151.                         else                       width = rWindowWidth;
  152.                         ZoomToWindowDevice(window, width, rWindowHeight, inZoomOut, true);
  153.                     }
  154.                     break;
  155.  
  156.             }
  157.             break;
  158.  
  159.         case activateEvt:
  160.             gCurrentCursor = nil;        /* No shortcuts when we recalculate the cursor region. */
  161.             DoActivate((WindowPtr)event->message, (event->modifiers & activeFlag));
  162.             break;
  163.  
  164.         case autoKey:
  165.         case keyDown:                    /* Check for menukey equivalents. */
  166.             key = event->message & charCodeMask;
  167.             if (event->modifiers & cmdKey) {        /* Command key down. */
  168.                 if (event->what == keyDown) {
  169.                     AdjustMenus();
  170.                         /* Enable/disable/check menu items properly. */
  171.                     DoMenuCommand(MenuKey(key), event);
  172.                 }
  173.             }
  174.             else {
  175.                 if (!IsAppWindow(window = FrontWindow())) break;
  176.                 frHndl = (FileRecHndl)GetWRefCon(window);
  177.                 if (key == 0x03) {
  178.                     ctl = (*frHndl)->doc.sendMessage;
  179.                     if (!(*ctl)->contrlHilite) {
  180.                         HiliteControl(ctl, 1);
  181.                         tick = TickCount();
  182.                         while (TickCount() < tick + 10) {};
  183.                         HiliteControl(ctl, 0);
  184.                         SendMssg(frHndl, kTextMssg);
  185.                     }
  186.                 }
  187.                 else {
  188.                     if (event->modifiers & optionKey) {
  189.                         dir = 0;
  190.                         if ((key == chLeft)  || (key == chUp))   dir = -1;
  191.                         if ((key == chRight) || (key == chDown)) dir = 1;
  192.                         if (dir) {
  193.                             SetFilePort(frHndl);
  194.                             RepositionBoard(frHndl, (*frHndl)->doc.gameIndex + dir, true);
  195.                             ImageDocument(frHndl, true);
  196.                             AdjustGameSlider(frHndl);
  197.                             if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kResync, nil);
  198.                             return;
  199.                         }
  200.                     }
  201.                     retval = CTEKey(window, event);
  202.                     if (retval) {
  203.                         if (retval == 2) (*frHndl)->fileState.docDirty = true;
  204.                             /* Out-box was edited, so dirty document. */
  205.                         AdjustMenus();        /* Avoid unnecessary DoCursor() and speed */
  206.                         return;                /* up TextEdit entry. */
  207.                     }
  208.                 }
  209.             }
  210.             break;
  211.  
  212.         case diskEvt:
  213.             gCurrentCursor = nil;
  214.                 /* No shortcuts when we recalculate the cursor region. */
  215.  
  216.             if (HiWord(event->message) != noErr) {
  217.                 SetPt(&aPoint, kDILeft, kDITop);
  218.                 err = DIBadMount(aPoint, event->message);
  219.             }
  220.             break;        /* It is not a bad idea to at least call DIBadMount
  221.                         ** in response to a diskEvt, so that the user can
  222.                         ** format a floppy.
  223.                         */
  224.         case kHighLevelEvent:
  225.             gCurrentCursor = nil;
  226.                 /* No shortcuts when we recalculate the cursor region. */
  227.  
  228.             DoHighLevelEvent(event);
  229.             break;
  230.  
  231.         case kOSEvent:
  232.             gCurrentCursor = nil;
  233.                 /* No shortcuts when we recalculate the cursor region. */
  234.  
  235.             switch ((event->message >> 24) & 0x0FF) {
  236.                     /* Must logical and with 0x0FF to get only low byte. */
  237.                     /* High byte of message. */
  238.  
  239.                 case kMouseMovedMessage:
  240.                     DoIdleTasks(true);
  241.                     break;
  242.  
  243.                 case kSuspendResumeMessage:
  244.                         /* Suspend/resume is also an activate/deactivate. */
  245.                     gInBackground = !((event->message) & kResumeMask);
  246.                     CTEConvertClipboard((event->message) & convertClipboardFlag, !gInBackground);
  247.                     DoActivate(FrontWindow(), !gInBackground);
  248.                     break;
  249.             }
  250.             break;
  251.  
  252.         case updateEvt:
  253.             DoUpdate((WindowPtr)event->message);
  254.             break;
  255.  
  256.     }
  257.  
  258.     DoCursor();
  259.     AdjustMenus();
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************/
  265.  
  266.  
  267.  
  268. /* This is called when a window is activated or deactivated. */
  269.  
  270. #pragma segment Main
  271. void    DoActivate(WindowPtr window, Boolean becomingActive)
  272. {
  273.     FileRecHndl        frHndl;
  274.     short            hilite;
  275.     ControlHandle    ctl;
  276.  
  277.     NotifyCancel();
  278.  
  279.     if (IsAppWindow(window)) {
  280.  
  281.         frHndl = (FileRecHndl)GetWRefCon(window);
  282.  
  283.         SetPort(window);
  284.         SetOrigin((*frHndl)->doc.arrangeBoard * 4096, 0);
  285.  
  286.         hilite = 0;
  287.         if (!becomingActive) hilite = 255;
  288.  
  289.         HiliteControl((*frHndl)->doc.gameSlider, hilite);
  290.         HiliteControl((*frHndl)->doc.resign, hilite);
  291.         HiliteControl((*frHndl)->doc.draw, hilite);
  292.  
  293.         if (!(*frHndl)->doc.twoPlayer) hilite = 255;
  294.  
  295.         HiliteControl(ctl = (*frHndl)->doc.sendMessage, hilite);
  296.         OutlineControl(ctl);
  297.         HiliteControl((*frHndl)->doc.beepOnMove, hilite);
  298.         HiliteControl((*frHndl)->doc.beepOnMssg, hilite);
  299.  
  300.         if (!SoundInputAvaliable()) hilite = 255;
  301.         HiliteControl((*frHndl)->doc.record, hilite);
  302.         if (!(*frHndl)->doc.sound) hilite = 255;
  303.         HiliteControl((*frHndl)->doc.sendSnd, hilite);
  304.  
  305.         if (!(*frHndl)->doc.arrangeBoard) CTEWindActivate(window, true);
  306.  
  307.         DoDrawControls(window, true);
  308.         SetOrigin(0, 0);
  309.     }
  310. }
  311.  
  312.  
  313.  
  314. /*****************************************************************************/
  315.  
  316.  
  317.  
  318. /* This is called when an update event is received for a window.  It calls
  319. ** ImageDocument to draw the contents of an application window.  As an
  320. ** effeciency measure that does not have to be followed, it calls the drawing
  321. ** routine only if the visRgn is non-empty.  This will handle situations where
  322. ** calculations for drawing or drawing itself is very time-consuming. */
  323.  
  324. #pragma segment Main
  325. void    DoUpdate(WindowPtr window)
  326. {
  327.     if (IsAppWindow(window)) {
  328.         BeginUpdate(window);                /* This sets up the visRgn. */
  329.         if (!EmptyRgn(window->visRgn)) {    /* Draw if updating needs doing. */
  330.             SetPort(window);
  331.             ImageDocument((FileRecHndl)GetWRefCon(window), false);
  332.         }
  333.         EndUpdate(window);
  334.     }
  335. }
  336.  
  337.  
  338.  
  339. /*****************************************************************************/
  340.  
  341.  
  342.  
  343. /* This is called when a mouse-down event occurs in the content of a window.
  344. ** Other applications might want to call FindControl, TEClick, etc., to
  345. ** further process the click. */
  346.  
  347. #pragma segment Main
  348. void    DoContentClick(WindowPtr window, EventRecord *event)
  349. {
  350.     Boolean            invertBoard, legalMove;
  351.     short            fromRow, fromCol, toRow, toCol, i, myColor;
  352.     short            fromSq, toSq, promotion, piece, item;
  353.     short            numLegalMoves, part, twoPlayer, whosMove;
  354.     OSErr            err;
  355.     long            ref;
  356.     Point            clickLoc, releaseLoc;
  357.     Rect            boardRect, fromRect;
  358.     FileRecHndl        frHndl;
  359.     MoveListHndl    legalMoves;
  360.     DialogPtr        promoteDialog;
  361.     short            itemType, ctlNum, val, action;
  362.     Handle            itemHndl;
  363.     Rect            itemRect;
  364.     ControlHandle    ctlHit;
  365.     EventRecord        option;
  366.  
  367.     if (!IsAppWindow(window)) return;
  368.  
  369.     frHndl = (FileRecHndl)GetWRefCon(window);
  370.     SetPort(window);
  371.     SetOrigin((*frHndl)->doc.arrangeBoard * 4096, 0);
  372.  
  373.     twoPlayer = (*frHndl)->doc.twoPlayer;
  374.  
  375.     clickLoc = event->where;
  376.     GlobalToLocal(&clickLoc);
  377.  
  378.     if (CTEClick(window, event, &action)) {
  379.         SetOrigin(0, 0);
  380.         return;
  381.     }
  382.         /* If TextEdit control handled the click, we are done. */
  383.  
  384.     part = FindControl(clickLoc, window, &ctlHit);
  385.     if (part) {
  386.         ctlNum = ref = GetControlReference(ctlHit);
  387.         if ((ref) && (ref < 10)) {
  388.             if (TrackControl(ctlHit, clickLoc, nil)) {
  389.                 switch (ctlNum) {
  390.                     case 1:
  391.                         SendMssg(frHndl, kTextMssg);
  392.                         break;
  393.                     case 2:
  394.                     case 3:
  395.                         SetControlValue(ctlHit, val = (GetControlValue(ctlHit) ^ 1));
  396.                         if (val)
  397.                             if ((event->modifiers) & optionKey) SendMssg(frHndl, kBeepMssg);
  398.                         break;
  399.                     case 4:
  400.                     case 5:
  401.                         SetControlValue(ctlHit, 1);
  402.                         SetControlValue((*frHndl)->doc.wbStart[5 - ctlNum], 0);
  403.                         (*frHndl)->doc.startColor = ctlNum - 4;
  404.                         break;
  405.                     case 6:
  406.                         EndTheGame(frHndl, kWhiteResigns + (*frHndl)->doc.myColor);
  407.                         SayTheMove(frHndl);
  408.                         UpdateGameStatus(frHndl);
  409.                         if (twoPlayer) {
  410.                             SendGame(frHndl, kIsMove, nil);
  411.                                 /* Show the dialog at the other end. */
  412.                             SendGame(frHndl, kResync, nil);
  413.                                 /* Make sure that simultaneous hits on the
  414.                                 ** resign button are taken care of. */
  415.                         }
  416.                         break;
  417.                     case 7:
  418.                         i = ((*frHndl)->doc.drawBtnState ^ 0x02);
  419.                         if (!twoPlayer) i = 0x06;
  420.                         if (i >= 0x06) {
  421.                             EndTheGame(frHndl, kDrawGame);
  422.                             SayTheMove(frHndl);
  423.                         }
  424.                         DrawButtonTitle(frHndl, i);
  425.                         if (twoPlayer) {
  426.                             SendGame(frHndl, kIsMove, nil);
  427.                                 /* Show the dialog at the other end. */
  428.                             SendGame(frHndl, kResync, nil);
  429.                                 /* Make sure that simultaneous hits on the
  430.                                 ** draw button are taken care of. */
  431.                         }
  432.                         break;
  433.                     case 8:
  434.                         err = RecordSound(frHndl);
  435.                         if ((err) && (err != userCanceledErr))
  436.                             Alert(rErrorAlert, gAlertFilterUPP);
  437.                         break;
  438.                     case 9:
  439.                         SendMssg(frHndl, kSoundMssg);
  440.                         break;
  441.                 }
  442.             }
  443.         }
  444.         SetOrigin(0, 0);
  445.  
  446.         if (ctlHit == (*frHndl)->doc.gameSlider)
  447.             TrackControl(ctlHit, clickLoc, nil);
  448.  
  449.         return;
  450.     }
  451.  
  452.     if ((*frHndl)->fileState.readOnly) {
  453.         SetOrigin(0, 0);
  454.         return;
  455.     }                    /* Don't allow changes if read-only. */
  456.  
  457.     if ((*frHndl)->doc.arrangeBoard) {
  458.         DoArrangeBoard(frHndl, event, clickLoc);
  459.         return;
  460.     }
  461.  
  462.     SetOrigin(0, 0);
  463.  
  464.     invertBoard = (*frHndl)->doc.invertBoard;
  465.  
  466.     boardRect = BoardRect();
  467.     if (!PtInRect(clickLoc, &boardRect)) return;
  468.  
  469.     fromRow = (clickLoc.v - kBoardVOffset) / kBoardSqSize;
  470.     fromCol = (clickLoc.h - kBoardHOffset) / kBoardSqSize;
  471.     fromRect.top    = 1 + fromRow * kBoardSqSize;
  472.     fromRect.left   = 1 + fromCol * kBoardSqSize;
  473.     fromRect.bottom = fromRect.top  + 32;
  474.     fromRect.right  = fromRect.left + 32;
  475.  
  476.     if (invertBoard) {
  477.         fromRow = 7 - fromRow;
  478.         fromCol = 7 - fromCol;
  479.     }
  480.     fromSq  = START_IBNDS + 10 * fromRow + fromCol;
  481.  
  482.     if (GameStatus(frHndl) != kGameContinues) return;
  483.         /* Game over, so no moves. */
  484.  
  485.     if ((*frHndl)->doc.resync != kIsMove) return;
  486.         /* Don't allow moves until we are resynced. */
  487.  
  488.     numLegalMoves = (*frHndl)->doc.numLegalMoves;
  489.     legalMoves    = (*frHndl)->doc.legalMoves;
  490.  
  491.     for (i = 0; i < numLegalMoves; ++i)
  492.         if ((**legalMoves)[i].moveFrom == fromSq) break;
  493.  
  494.     if (i == numLegalMoves) return;
  495.         /* Clicked on a empty square or on a piece that can't move. */
  496.  
  497.     whosMove = WhosMove(frHndl);
  498.     myColor  = (*frHndl)->doc.myColor;
  499.     OSEventAvail(nullEvent, &option);
  500.     if (option.modifiers & optionKey)
  501.         if (myColor != kMessageDoc) myColor = whosMove;
  502.  
  503.     if ((twoPlayer) && (whosMove != myColor)) return;
  504.         /* It's the other player's turn. */
  505.  
  506.     if ((whosMove == WHITE) && ((*frHndl)->doc.compMovesWhite)) return;
  507.     if ((whosMove == BLACK) && ((*frHndl)->doc.compMovesBlack)) return;
  508.         /* Computer is moving this color, so ignore click. */
  509.  
  510.     SetCursor(*GetCursor(closedHandCursor));
  511.     gCurrentCursor = nil;
  512.  
  513.     releaseLoc.h = releaseLoc.v = 0x4000;
  514.     MoveThePiece(frHndl, fromSq, fromRect, clickLoc, &releaseLoc);
  515.  
  516.     toRow = (releaseLoc.v - kBoardVOffset) / kBoardSqSize;
  517.     toCol = (releaseLoc.h - kBoardHOffset) / kBoardSqSize;
  518.     if (invertBoard) {
  519.         toRow = 7 - toRow;
  520.         toCol = 7 - toCol;
  521.     }
  522.     toSq = START_IBNDS + 10 * toRow + toCol;
  523.  
  524.     for (i = 0; i < numLegalMoves; ++i)
  525.         if (
  526.             ((**legalMoves)[i].moveFrom == fromSq) &&
  527.             ((**legalMoves)[i].moveTo   == toSq)
  528.         ) break;
  529.  
  530.     promotion = QUEEN;        /* If there is a promotion, assume queen. */
  531.  
  532.     legalMove = (i < numLegalMoves);
  533.     if (legalMove) {
  534.  
  535.         if ((toRow == 0) || (toRow == 7)) {        /* Possible pawn promotion... */
  536.  
  537.             piece = (*frHndl)->doc.theBoard[fromSq];
  538.             if (piece < 0) piece = -piece;
  539.  
  540.             if (piece == PAWN) {                /* It is a pawn promotion... */
  541.  
  542.                 if (option.modifiers & shiftKey) promotion = QUEEN;
  543.                 else {
  544.  
  545.                     MakeMove(frHndl, fromSq, toSq, PAWN);
  546.                     ImageDocument(frHndl, true);
  547.                     MakeMove(frHndl, -1, 0, 0);
  548.  
  549.                     promoteDialog = GetCenteredDialog(rPawnPromotion, nil,
  550.                                                       FrontWindow(), (WindowPtr)-1L);
  551.                     if (promoteDialog) {
  552.                         SetPort(promoteDialog);
  553.                         OutlineDialogItem(promoteDialog, 1);
  554.                         DoSetCursor(&qd.arrow);
  555.  
  556.                         for (item = QUEEN;;) {
  557.                             if (promotion != item) {
  558.                                 GetDialogItem(promoteDialog, promotion + 1, &itemType, &itemHndl, &itemRect);
  559.                                 SetControlValue((ControlHandle)itemHndl, false);
  560.                             }
  561.  
  562.                             GetDialogItem(promoteDialog, item + 1, &itemType, &itemHndl, &itemRect);
  563.                             SetControlValue((ControlHandle)itemHndl, true);
  564.                             promotion = item;
  565.  
  566.                             ModalDialog(gKeyEquivFilterUPP, &item);
  567.                             if (item == 1) break;
  568.                             --item;
  569.                         }
  570.                         DisposeDialog(promoteDialog);
  571.                         SetPort(window);
  572.                     }
  573.                 }
  574.             }
  575.         }
  576.     }
  577.  
  578.     if (GameStatus(frHndl)) ImageDocument(frHndl, true);
  579.     else {
  580.         if (legalMove) MakeMove(frHndl, fromSq, toSq, promotion);
  581.         ImageDocument(frHndl, true);
  582.         DrawTime(frHndl);
  583.         if (legalMove) AdjustGameSlider(frHndl);
  584.         DrawButtonTitle(frHndl, twoPlayer);
  585.         UpdateGameStatus(frHndl);
  586.         if ((legalMove) && (twoPlayer)) SendGame(frHndl, kIsMove, nil);
  587.         if (legalMove) {
  588.             SayTheMove(frHndl);
  589.             AlertIfGameOver(frHndl);
  590.         }
  591.         (frHndl);
  592.     }
  593. }
  594.  
  595.  
  596.  
  597. /*****************************************************************************/
  598.  
  599.  
  600.  
  601. extern TheDoc    newDocData;
  602.  
  603. #pragma segment Main
  604. short    AlertIfGameOver(FileRecHndl frHndl)
  605. {
  606.     WindowPtr        oldPort;
  607.     DialogPtr        dialogPtr;
  608.     short            status, i, theAlert, item;
  609.     Str255            gameStatMssg;
  610.     Handle            rsrc, txt;
  611.     long            l;
  612.     static Str255    whichMessage;
  613.     static ModalFilterUPP    statusFilterUPP;
  614.  
  615.     theAlert = rGameStat;
  616.  
  617.     if ((status = GameStatus(frHndl)) != kGameContinues) {
  618.  
  619.         if (gComputerResigns) {
  620.             if (!whichMessage[0]) {
  621.                 rsrc = GetResource('STR#', rComputerResigns);
  622.                 whichMessage[0] = **(short **)rsrc;
  623.                 for (i = 1; i <= whichMessage[0]; ++i) whichMessage[i] = i;
  624.             }
  625.             theAlert = rComputerResigns;
  626.             gComputerResigns = false;
  627.             l  = Random();
  628.             l &= 0x0000FFFFL;
  629.             l *= whichMessage[0];
  630.             l /= 0x10000L;
  631.             status = whichMessage[++l];
  632.             whichMessage[l] = whichMessage[whichMessage[0]--];
  633.         }
  634.  
  635.         UpdateGameStatus(frHndl);
  636.         GetIndString(gameStatMssg, theAlert, status);
  637.  
  638.         ParamText(gameStatMssg, nil, nil, nil);
  639.         DoSetCursor(&qd.arrow);
  640.  
  641.         gStatusTime = TickCount();
  642.         if (((*frHndl)->doc.compMovesWhite) && ((*frHndl)->doc.compMovesBlack))
  643.             status = kGameContinues;
  644.  
  645.         gAlertTimeout = false;
  646.  
  647.         GetPort(&oldPort);
  648.         dialogPtr = GetCenteredDialog(theAlert, nil, nil, (WindowPtr)-1);
  649.         if (dialogPtr) {
  650.             SetPort(dialogPtr);
  651.             DrawDialog(dialogPtr);
  652.             OutlineDialogItem(dialogPtr, 1);
  653.             SetEmptyRgn(((WindowPeek)dialogPtr)->updateRgn);    /* Did it by hand -- prevent redraw. */
  654.  
  655.             if ((*frHndl)->doc.doSpeech) {
  656.                 txt = NewHandle(gameStatMssg[0]);
  657.                 if (txt) {
  658.                     for (i = 1; i <= gameStatMssg[0]; ++i)
  659.                         if (gameStatMssg[i] == (unsigned char)'’')
  660.                             gameStatMssg[i] = '\'';
  661.                     BlockMove(gameStatMssg + 1, *txt, gameStatMssg[0]);
  662.                     SayText(nil, txt, (*frHndl)->doc.theVoice);
  663.                     DisposeHandle(txt);
  664.                 }
  665.             }
  666.  
  667.             if (!statusFilterUPP)
  668.                 statusFilterUPP = NewModalFilterProc(statusFilter);
  669.             for (;;) {
  670.                 ModalDialog(statusFilterUPP, &item);
  671.                 if (item == 1) break;
  672.             }
  673.             DisposeDialog(dialogPtr);
  674.         }
  675.         else gAlertTimeout = true;
  676.         SetPort(oldPort);
  677.  
  678.         if (!gAlertTimeout) status = GameStatus(frHndl);
  679.  
  680.         if (status == kGameContinues) {
  681.             oldPort = SetFilePort(frHndl);
  682.             RepositionBoard(frHndl, 0, true);
  683.             UpdateGameStatus(frHndl);
  684.             if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kResync, nil);
  685.             AdjustGameSlider(frHndl);
  686.             for (i = 0; i < 2; ++i)
  687.                 if ((*frHndl)->doc.timeLeft[i] != -1)
  688.                     (*frHndl)->doc.timeLeft[i] = (*frHndl)->doc.displayTime[i] =
  689.                         (*frHndl)->doc.defaultTime[i];
  690.             (*frHndl)->doc.timerRefTick = TickCount();
  691.             UpdateTime(frHndl, false);
  692.             DrawTime(frHndl);
  693.             SetPort(oldPort);
  694.         }            
  695.     }
  696.  
  697.     return(status);
  698. }
  699.  
  700.  
  701.  
  702. /*****************************************************************************/
  703.  
  704.  
  705.  
  706. #pragma segment Config
  707. pascal Boolean    statusFilter(DialogPtr dlg, EventRecord *event, short *item)
  708. {
  709.     if (KeyEquivFilter(dlg, event, item)) return(true);
  710.     if ((gStatusTime) && (gStatusTime + 600 < TickCount())) {
  711.         *item = 1;
  712.         gAlertTimeout = true;
  713.         return(true);
  714.     }
  715.  
  716.     return(false);
  717. }
  718.  
  719.  
  720.  
  721.