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

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        aechess.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved.
  9. **
  10. ** This is the custom AppleEvents code.  The required AppleEvents code is in
  11. ** the file AppleEvents.c, which is Keith Rollin's work. */
  12.  
  13.  
  14.  
  15. /*****************************************************************************/
  16.  
  17.  
  18.  
  19. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  20. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  21. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  22.  
  23. #ifndef __AEUTILS__
  24. #include <AEUtils.h>
  25. #endif
  26.  
  27. #ifndef __ERRORS__
  28. #include <Errors.h>
  29. #endif
  30.  
  31. #ifndef __FONTS__
  32. #include <Fonts.h>
  33. #endif
  34.  
  35. #ifndef __LOWMEM__
  36. #include <LowMem.h>
  37. #endif
  38.  
  39. #ifndef __MEMORY__
  40. #include <Memory.h>
  41. #endif
  42.  
  43. #ifndef __NOTIFICATION__
  44. #include <Notification.h>
  45. #endif
  46.  
  47. #ifndef __OSUTILS__
  48. #include <OSUtils.h>
  49. #endif
  50.  
  51. #ifndef __PPC__
  52. #include "PPC.h"
  53. #endif
  54.  
  55. #ifndef __RESOURCES__
  56. #include <Resources.h>
  57. #endif
  58.  
  59. #ifndef __SOUND__
  60. #include <Sound.h>
  61. #endif
  62.  
  63. #ifndef __STRING__
  64. #include <String.h>
  65. #endif
  66.  
  67. #ifndef __TOOLUTILS__
  68. #include <ToolUtils.h>
  69. #endif
  70.  
  71. #ifndef __TEXTEDITCONTROL__
  72. #include <TextEditControl.h>
  73. #endif
  74.  
  75. #ifndef __UTILITIES__
  76. #include <Utilities.h>
  77. #endif
  78.  
  79.  
  80.  
  81. /*****************************************************************************/
  82.  
  83.  
  84.  
  85. #define PRIORITY        kAENormalPriority
  86. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  87.  
  88.  
  89.  
  90. /*****************************************************************************/
  91.  
  92.  
  93.  
  94. static pascal void    CancelNotify(NMRecPtr nmReqPtr);
  95. static void            GetFullPathAndAppName(StringPtr path, StringPtr app);
  96.  
  97. static void            GetAppFullPath(StringPtr path);
  98.  
  99.  
  100.  
  101. /*****************************************************************************/
  102.  
  103.  
  104.  
  105. struct triplets{
  106.     AEEventClass        theEventClass;
  107.     AEEventID            theEventID;
  108.     ProcPtr                theHandler;
  109.     AEEventHandlerUPP    theUPP;
  110. };
  111. typedef struct triplets triplets;
  112. static triplets keywordsToInstall[] = {
  113.     { kCoreEventClass,        kAEAnswer,                (ProcPtr)DoAEAnswer,    nil },
  114.     { kCustomEventClass,    kibitzAESendGame,        (ProcPtr)ReceiveGame,    nil },
  115.     { kCustomEventClass,    kibitzAESendMssg,        (ProcPtr)ReceiveMssg,    nil }
  116. };        /* These are the custom AppleEvents. */
  117.  
  118.  
  119.  
  120. /*****************************************************************************/
  121.  
  122.  
  123.  
  124. extern Boolean        gHasAppleEvents;
  125. extern Boolean        gHasPPCToolbox;
  126.  
  127. extern RgnHandle    gCurrentCursorRgn;
  128. extern Cursor        *gCurrentCursor;
  129.  
  130. extern short        gMenuMods;
  131.  
  132.  
  133.  
  134. /*****************************************************************************/
  135. /*****************************************************************************/
  136.  
  137.  
  138.  
  139. /* InitCustomAppleEvents
  140. **
  141. ** Install our custom AppleEvents.  This is done in addition to installing
  142. ** the required AppleEvents.  InitAppleEvents, which installs the required
  143. ** AppleEvents, must be called first, since it sets up some global values. */
  144.  
  145. #pragma segment AppleEvents
  146. void    InitCustomAppleEvents(void)
  147. {
  148.     OSErr    err;
  149.     short    i;
  150.  
  151.     if (gHasAppleEvents) {
  152.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
  153.  
  154.             if (!keywordsToInstall[i].theUPP)
  155.                 keywordsToInstall[i].theUPP = NewAEEventHandlerProc(keywordsToInstall[i].theHandler);
  156.  
  157.             err = AEInstallEventHandler(
  158.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  159.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  160.                 keywordsToInstall[i].theUPP,        /* The AppleEvent handler. */
  161.                 0L,                                    /* Unused refcon.           */
  162.                 false                                /* Only for our app.       */
  163.             );
  164.  
  165.             if (err) {
  166.                 Alert(rErrorAlert, gAlertFilterUPP);
  167.                 return;
  168.             }
  169.         }
  170.     }
  171. }
  172.  
  173.  
  174.  
  175. /*****************************************************************************/
  176.  
  177.  
  178.  
  179. #pragma segment AppleEvents
  180. pascal OSErr    DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon)
  181. {
  182. #ifndef __MWERKS__
  183. #pragma unused (refcon)
  184. #endif
  185.  
  186.     OSErr    err;
  187.  
  188.     gCurrentCursor = nil;
  189.         /* Force re-calc of cursor region and cursor to use. */
  190.  
  191.     err = ReceiveGameReply(message, reply);
  192.  
  193.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  194.         reply,                    /* The AppleEvent.              */
  195.         keyReplyErr,            /* AEKeyword                 */
  196.         typeShortInteger,        /* Desired type.             */
  197.         (Ptr)&err,                /* Pointer to area for data. */ 
  198.         sizeof(short)            /* Size of data area.         */
  199.     );
  200.  
  201.     return(noErr);
  202. }
  203.  
  204.  
  205.  
  206. /*****************************************************************************/
  207.  
  208.  
  209.  
  210. /* SendGame
  211. **
  212. ** This routine acquires an opponent and sends the opponent the current game.
  213. ** Various changes are made to the game record to indicate that this game
  214. ** has an opponent, which color we are, where we are located (so the
  215. ** opponent can send moves back), the ID of our game, etc.  Once this
  216. ** information is in the game record, the game is transmitted to the
  217. ** opponent.  Upon receiving the game, the opponent sends back confirmation,
  218. ** which also includes the ID of the game on the opponent's end.  The return
  219. ** information is sent back as via AEAnswer, so we will extablish a two-player
  220. ** game until we receive this event.  Once we do establish a two-player game,
  221. ** we will store the opponent's game ID in the game record as well.  With our
  222. ** ID and the opponents ID, we will be able to determine which game the data
  223. ** is for at both ends.  This allows two opponents to play multiple games with
  224. ** the same machines. */
  225.  
  226. void    TogglePPCPatches(Boolean on);
  227.  
  228. #pragma segment AppleEvents
  229. OSErr    SendGame(FileRecHndl frHndl, short sendReason, StringPtr nbpType)
  230. {
  231.     AEAddressDesc    locOfOpponent;
  232.     Boolean            twoPlayer;
  233.     OSErr            err;
  234.     AEDescList        sendGameList;
  235.     long            gameID[2], size, timeout;
  236.     char            hstate;
  237.     Ptr                ptr1, ptr2;
  238.     GameListHndl    gameMoves;
  239.     AppleEvent        theAevt, reply;
  240.     short            replyType;
  241.     Str255            macText, appText, opponentName, reconnectPath;
  242.     Str32            reconnectApp;
  243.     Handle            userNameHndl;
  244.     static PPCFilterUPP    kibitzPortFilterUPP;
  245.  
  246.     sendGameList.dataHandle = theAevt.dataHandle = reply.dataHandle = nil;
  247.         /* Make sure disposing of the descriptors is okay in all cases.
  248.         ** This will not be necessary after 7.0b3, since the calls that
  249.         ** attempt to create the descriptors will nil automatically
  250.         ** upon failure. */
  251.  
  252.     err = noErr;
  253.         /* We may not make the first operation that can cause an error,
  254.         ** so we have to initialize err. */
  255.  
  256.     locOfOpponent.dataHandle = nil;
  257.         /* Make it safe to dispose of in all cases. */
  258.  
  259.     if ((*frHndl)->doc.resync < ((*frHndl)->doc.sendReason = sendReason))
  260.         (*frHndl)->doc.resync = sendReason;
  261.             /* Bump up resync, if needed. */
  262.  
  263.     UpdateTime(frHndl, false);
  264.         /* Make sure timers are current before we give them to opponent. */
  265.  
  266.     twoPlayer = (*frHndl)->doc.twoPlayer;
  267.     if (!twoPlayer) {            /* If we don't have a live opponent yet... */
  268.         GetIndString(macText, rPPCText, sTitleText);
  269.         GetIndString(appText, rPPCText, sAppText);
  270.  
  271.         if ((*frHndl)->doc.reconnectZone[0]) {
  272.             for (timeout = TickCount() + 600; timeout > TickCount();) {
  273.                 err = GetRemoteProcessTarget(frHndl, &locOfOpponent, KibitzFilter);
  274.                 if (err) break;
  275.                 if (locOfOpponent.dataHandle) break;
  276.             }
  277.         }
  278.         else {
  279. #ifndef powerc
  280.             if (gMenuMods & shiftKey) TogglePPCPatches(true);
  281. #endif
  282.             if (!kibitzPortFilterUPP)
  283.                 kibitzPortFilterUPP = NewPPCFilterProc (KibitzPortFilter);
  284.             err = MakeTarget(&locOfOpponent, false, kAEWaitReply,
  285.                 macText, appText, kibitzPortFilterUPP, (char *)nbpType);
  286.                     /* Generate the target for our opponent. */
  287. #ifndef powerc
  288.             if (gMenuMods & shiftKey) TogglePPCPatches(false);
  289. #endif
  290.         }
  291.  
  292.         (*frHndl)->doc.gameID_0      = gameID[0] = (TickCount() & 0xFFFFFFFE);
  293.         (*frHndl)->doc.gameID_1      = gameID[0];
  294.         (*frHndl)->doc.locOfOpponent = locOfOpponent;
  295.     }
  296.     else locOfOpponent = (*frHndl)->doc.locOfOpponent;
  297.  
  298.     if (!err) {        /* If we have an opponent... */
  299.         err = AECreateList(        /* CREATE THE LIST TO HOLD THE GAME. */
  300.             nil,                /* No factoring.             */
  301.             0,                    /* No factoring.             */
  302.             false,                /* Not an AppleEvent record. */
  303.             &sendGameList        /* List descriptor.             */
  304.         );
  305.     }
  306.  
  307.     if (!err) {        /* If we have an empty list to add to... */
  308.         hstate = LockHandleHigh((Handle)frHndl);
  309.         ptr1   = (Ptr)&((*frHndl)->doc);
  310.         ptr2   = (Ptr)&((*frHndl)->doc.endSendInfo);
  311.         size   = (long)ptr2 - (long)ptr1;
  312.         err = AEPutPtr(        /* ADD BOARD INFO TO THE APPLEEVENT. */
  313.             &sendGameList,    /* List to add to.                     */
  314.             1L,                /* Make this element #1.             */
  315.             typeTheBoard,    /* It is a descriptor for the board. */
  316.             ptr1,            /* Pointer to the board data.         */
  317.             size            /* Size of the board data.             */
  318.         );
  319.         HSetState((Handle)frHndl, hstate);
  320.     }
  321.  
  322.     /* For a new opponent, the field twoPlayer in sendGameList (to be sent
  323.     ** to the opponent) indicates that there is no live opponent.  When the
  324.     ** receiver gets a board with twoPlayer false, this indicates a new game
  325.     ** is being set up.  If twoPlayer is true, then it is an existing game. */
  326.  
  327.     if (!err) {        /* If we could add the board info to the list... */
  328.         gameMoves = (*frHndl)->doc.gameMoves;
  329.         size      = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  330.         hstate    = LockHandleHigh((Handle)gameMoves);
  331.         err = AEPutPtr(            /* ADD GAME MOVES TO THE LIST.             */
  332.             &sendGameList,        /* List to add to.                         */
  333.             2L,                    /* Make this element #2.                 */
  334.             typeGameMoves,        /* Descriptor for the moves of the game. */
  335.             (Ptr)(*gameMoves),    /* Pointer to the move data.             */
  336.             size                /* Size of the move data.                 */
  337.         );
  338.         HSetState((Handle)gameMoves, hstate);
  339.     }
  340.  
  341.     if ((!err) && (!twoPlayer)) {
  342.         hstate = LockHandleHigh((Handle)frHndl);
  343.         ptr1   = (Ptr)&((*frHndl)->fileState.fss);
  344.         err = AEPutPtr(            /* ADD FSSpec TO LIST TO PASS THE GAME NAME. */
  345.             &sendGameList,        /* List to add to.         */
  346.             3L,                    /* Make this element #3. */
  347.             typeFSS,            /* FSSpec descriptor.     */
  348.             ptr1,                /* Pointer to the data.     */
  349.             sizeof(FSSpec)        /* Size of the data.     */
  350.         );
  351.         HSetState((Handle)frHndl, hstate);
  352.         if (!err) {
  353.             opponentName[0] = 0;
  354.             userNameHndl = GetResource('STR ', -16096);
  355.             if (userNameHndl)
  356.                 pcpy(opponentName, (StringPtr)(*userNameHndl));
  357.             err = AEPutPtr(            /* ADD USER NAME TO LIST. */
  358.                 &sendGameList,        /* List to add to.             */
  359.                 4L,                    /* Make this element #4.     */
  360.                 typePascal,            /* Pascal string descriptor. */
  361.                 (Ptr)opponentName,    /* Pointer to the data.         */
  362.                 opponentName[0] + 1    /* Size of the data.         */
  363.             );
  364.             if (!err) {
  365.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  366.                 err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  367.                     &sendGameList,            /* List to add to.             */
  368.                     5L,                        /* Make this element #5.     */
  369.                     typePascal2,            /* Pascal string descriptor. */
  370.                     (Ptr)reconnectPath,        /* Pointer to the data.         */
  371.                     reconnectPath[0] + 1    /* Size of the data.         */
  372.                 );
  373.                 if (!err) {
  374.                     err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  375.                         &sendGameList,            /* List to add to.             */
  376.                         6L,                        /* Make this element #5.     */
  377.                         typePascal3,            /* Pascal string descriptor. */
  378.                         (Ptr)reconnectApp,        /* Pointer to the data.         */
  379.                         reconnectApp[0] + 1        /* Size of the data.         */
  380.                     );
  381.                 }
  382.             }
  383.         }
  384.     }
  385.  
  386.     if (!err) {        /* If we could add the game moves to the list... */
  387.         err = AECreateAppleEvent(            /* CREATE EMPTY APPLEEVENT.     */
  388.             kCustomEventClass,                /* Event class.                 */
  389.             kibitzAESendGame,                /* Event ID.                 */
  390.             &locOfOpponent,                    /* Address of receiving app. */
  391.             kAutoGenerateReturnID,            /* This value causes the     */
  392.                                             /* AppleEvent manager to     */
  393.                                             /* assign a return ID that     */
  394.                                             /* is unique to the session. */
  395.             kAnyTransactionID,                /* Ignore transaction ID.     */
  396.             &theAevt                        /* Location of event.         */
  397.         );
  398.     }
  399.  
  400.     if (!err) {        /* If we have an empty AppleEvent... */
  401.         err = AEPutParamDesc(    /* PUT THE LIST INTO THE APPLEEVENT.  */
  402.             &theAevt,            /* AppleEvent to add list to.          */
  403.             keyDirectObject,    /* This is our direct (only) object.  */
  404.             &sendGameList        /* The list to add to the AppleEvent. */
  405.         );
  406.     }
  407.  
  408.     replyType = (!twoPlayer) ? kAEQueueReply : kAENoReply;
  409.         /* Queue a reply only for a new game. */
  410.  
  411.     if (!err) {        /* If we have an AppleEvent ready to send... */
  412.         err = AESend(        /* SEND APPLEEVENT.                */
  413.             &theAevt,        /* Our Apple Event to send.        */
  414.             &reply,            /* We may have a reply.            */
  415.             replyType,        /* Type of reply.                */
  416.             PRIORITY,        /* App. send priority.            */
  417.             0,                /* We aren't waiting.            */
  418.             nil,            /* We aren't waiting.            */
  419.             nil                /* EventFilterProcPtr.            */
  420.         );
  421.     }
  422.     if (replyType == kAEQueueReply)
  423.         if (locOfOpponent.descriptorType == typeProcessSerialNumber)
  424.             err = ReceiveGameReply(&reply, &reply);
  425.                 /* If we want a queue reply, and if we are sending to ourselves,
  426.                 ** then we already have the reply.  Since we are sending to
  427.                 ** ourselves, we don't have to wait for an event.  Stuff happens
  428.                 ** right away.  We're (probably) happy. */
  429.  
  430.     AEDisposeDesc(&sendGameList);
  431.     AEDisposeDesc(&theAevt);
  432.     AEDisposeDesc(&reply);
  433.         /* Dispose of the descriptors, created or not.
  434.         ** If not created, no harm done by calling. */
  435.  
  436.     if (err) {
  437.         AEDisposeDesc(&locOfOpponent);
  438.             /* If we didn't connect, get rid of the target descriptor. */
  439.  
  440.         (*frHndl)->doc.gameID_0 = 0;
  441.         (*frHndl)->doc.gameID_1 = 0;
  442.             /* Mark this window so that it will never be found if we somehow
  443.             ** do get an answer from the receiver, even after failure. */
  444.     }
  445.  
  446.     return(err);
  447. }
  448.  
  449.  
  450.  
  451. /*****************************************************************************/
  452.  
  453.  
  454.  
  455. /* This code is executed only after an game is initially sent and we receive
  456. ** an AEAnswer event.  The "answer" is acknowledgment that the opponent
  457. ** received the game and that the opponent is set up for a two-player game.
  458. ** In the reply, we receive the opponent's game ID, which is used to match
  459. ** up which game receives the AppleEvents. */
  460.  
  461. #pragma segment AppleEvents
  462. pascal OSErr    ReceiveGameReply(AppleEvent *message, AppleEvent *reply)
  463. {
  464. #ifndef __MWERKS__
  465. #pragma unused (reply)
  466. #endif
  467.  
  468.     OSErr            err, replyErr;
  469.     DescType        actualType;
  470.     long            gameID[2], actualSize, mssgSize;
  471.     char            hstate;
  472.     WindowPtr        window;
  473.     FileRecHndl        frHndl;
  474.     Handle            mssgData;
  475.     Str32            opponentName, zone, machine, application;
  476.     Str255            reconnectPath;
  477.     Str32            reconnectApp;
  478.     AEAddressDesc    locOfOpponent;
  479.     short            txFont, txSize;
  480.     Style            txFace;
  481.     WindowPtr        oldPort, curPort;
  482.     Handle            finf;
  483.  
  484.     err = AEGetParamPtr(        /* CHECK FOR A RECEIVER ERROR... */
  485.         message,                /* The AppleEvent.              */
  486.         keyReplyErr,            /* AEKeyword                 */
  487.         typeShortInteger,        /* Desired type.             */
  488.         &actualType,            /* Type code.                 */
  489.         (Ptr)&replyErr,            /* Pointer to area for data. */ 
  490.         sizeof(short),            /* Size of data area.         */
  491.         &actualSize                /* Returned size of data.     */
  492.     );
  493.     if (!err) err = replyErr;
  494.  
  495.     if (!err) {
  496.         err = AEGetParamPtr(    /* GET RECEIVER GAME ID. */
  497.             message,            /* The AppleEvent.              */
  498.             keyGameID,            /* AEKeyword                 */
  499.             typeDoubleLong,        /* Desired type.             */
  500.             &actualType,        /* Type code.                 */
  501.             (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  502.             2 * sizeof(long),    /* Size of data area.         */
  503.             &actualSize            /* Returned size of data.     */
  504.         );
  505.     }
  506.  
  507.     if (!err) {        /* If we got the receiver game ID... */
  508.  
  509.         window = GetGameWindow(gameID[1], gameID[1]);
  510.             /* The ID's are still both ours, since this is where we
  511.             ** get the receiver's ID returned.  gameID[0] holds the
  512.             ** receiver's ID, and gameID[1] holds ours. */
  513.  
  514.         if (window) {
  515.             frHndl = (FileRecHndl)GetWRefCon(window);
  516.             if (!(*frHndl)->doc.twoPlayer) {
  517.                 err = AEGetParamPtr(
  518.                     message,            /* The AppleEvent.              */
  519.                     keyPascalReply,        /* AEKeyword                 */
  520.                     typePascal,            /* Desired type.             */
  521.                     &actualType,        /* Type code.                 */
  522.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  523.                     sizeof(Str32),        /* Size of data area.         */
  524.                     &actualSize            /* Returned size of data.     */
  525.                 );
  526.  
  527.                 (*frHndl)->doc.opponentName[0] = 0;
  528.                 if (!err) {
  529.                     (*frHndl)->doc.gameID_1 = gameID[0];
  530.                     pcpy(&(*frHndl)->doc.opponentName[0], opponentName);
  531.                     SetOpponentType(frHndl, kTwoPlayer);
  532.                     locOfOpponent = (*frHndl)->doc.locOfOpponent;
  533.                     zone[0] = machine[0] = 0;
  534.                     GetTargetInfo(locOfOpponent, zone, machine, application);
  535.                     pcpy(&(*frHndl)->doc.opponentZone[0], zone);
  536.                     pcpy(&(*frHndl)->doc.opponentMachine[0], machine);
  537.  
  538.                     err = AEGetParamPtr(
  539.                         message,            /* The AppleEvent.              */
  540.                         keyPascal2Reply,    /* AEKeyword                 */
  541.                         typePascal2,        /* Desired type.             */
  542.                         &actualType,        /* Type code.                 */
  543.                         (Ptr)reconnectPath,    /* Pointer to area for data. */ 
  544.                         sizeof(Str255),        /* Size of data area.         */
  545.                         &actualSize            /* Returned size of data.     */
  546.                     );
  547.                     (*frHndl)->doc.reconnectPath[0] = 0;
  548.                     if (!err) pcpy(&(*frHndl)->doc.reconnectPath[0], reconnectPath);
  549.  
  550.                     err = AEGetParamPtr(
  551.                         message,            /* The AppleEvent.              */
  552.                         keyPascal3Reply,    /* AEKeyword                 */
  553.                         typePascal3,        /* Desired type.             */
  554.                         &actualType,        /* Type code.                 */
  555.                         (Ptr)reconnectApp,    /* Pointer to area for data. */ 
  556.                         sizeof(Str32),        /* Size of data area.         */
  557.                         &actualSize            /* Returned size of data.     */
  558.                     );
  559.                     (*frHndl)->doc.reconnectApp[0] = 0;
  560.                     if (!err) pcpy(&(*frHndl)->doc.reconnectApp[0], reconnectApp);
  561.  
  562.                     if (!err) {
  563.                         err = AEGetParamPtr(
  564.                             message,                /* The AppleEvent.              */
  565.                             keyTextMessage,            /* AEKeyword                 */
  566.                             typeMssg,                /* Desired type.             */
  567.                             &actualType,            /* Type code.                 */
  568.                             nil,                    /* Pointer to area for data. */ 
  569.                             0,                        /* Size of data area.         */
  570.                             &mssgSize                /* Returned size of data.     */
  571.                         );
  572.                     }
  573.                     mssgData = nil;
  574.                     if (!err) {        /* Get the data... */
  575.                         mssgData = NewHandle(mssgSize);
  576.                         if (mssgData) {
  577.                             hstate = LockHandleHigh(mssgData);
  578.                             err = AEGetParamPtr(
  579.                                 message,                /* The AppleEvent.              */
  580.                                 keyTextMessage,            /* AEKeyword                 */
  581.                                 typeMssg,                /* Desired type.             */
  582.                                 &actualType,            /* Type code.                 */
  583.                                 *mssgData,                /* Pointer to area for data. */ 
  584.                                 mssgSize,                /* Size of data area.         */
  585.                                 &actualSize                /* Returned size of data.     */
  586.                             );
  587.                         }
  588.                         else err = memFullErr;
  589.                     }
  590.                     if (!err) {
  591.                         oldPort = SetFilePort(frHndl);
  592.                         GetPort(&curPort);
  593.                         txFont = curPort->txFont;
  594.                         txSize = curPort->txSize;
  595.                         txFace = curPort->txFace;
  596.                         finf = GetResource('finf', 128);
  597.                         TextFont((*(short **)finf)[1]);
  598.                         TextSize((*(short **)finf)[3]);
  599.                         TextFace(normal);
  600.                         mssgData = CTESwapText((*frHndl)->doc.message[kMessageIn],
  601.                                                 mssgData, nil, true);
  602.                         TextFont(txFont);
  603.                         TextSize(txSize);
  604.                         TextFace(txFace);
  605.                         SetPort(oldPort);
  606.                     }
  607.                     if (mssgData) DisposeHandle(mssgData);
  608.  
  609.                     if (err == errAEDescNotFound) err = noErr;
  610.                 }
  611.                 if (err) (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  612.                 else GetDateTime(&((*frHndl)->doc.timeLastReceive));
  613.             }
  614.         }
  615.     }
  616.  
  617.     return(err);
  618. }
  619.  
  620.  
  621.  
  622. /*****************************************************************************/
  623.  
  624.  
  625.  
  626. /* ReceiveGame
  627. **
  628. ** This routine receives a board from an opponent.  It receives it for various
  629. ** purposes.  These are:
  630. **   1) Establishing a new game.
  631. **   2) Receiving a move.
  632. **   3) Receiving a new board position, due to scrolling.
  633. **
  634. ** Establishing a new game is determined by the fact that the value twoPlayer
  635. ** is false.  If it is a previously established game, then this field is true.
  636. **
  637. ** If it is a previously established game, then whether or not it is a new move
  638. ** is determined by field "sendReason".  If sendReason != kIsMove, then it is some
  639. ** other change, such as scrolling or resyncing by of the sender.
  640. ** These other cases should not cause a win/loss/tie dialog to appear.
  641. **
  642. ** If it is a regular move, (sendReason == kIsMove), then the win/loss/draw dialogs
  643. ** should be displayed, if the game is indeed over after the move. */
  644.  
  645. #pragma segment AppleEvents
  646. pascal OSErr    ReceiveGame(AppleEvent *message, AppleEvent *reply, long refcon)
  647. {
  648. #ifndef __MWERKS__
  649. #pragma unused (refcon)
  650. #endif
  651.  
  652.     OSErr            err;
  653.     FileRecHndl        frHndl, newFrHndl, oldFrHndl, mssgFrHndl;
  654.     FileRecPtr        frPtr;
  655.     AEDescList        receiveGameList;
  656.     char            hstate;
  657.     Ptr                ptr1, ptr2;
  658.     long            size, gameID[2];
  659.     Boolean            twoPlayer;
  660.     AEAddressDesc    senderTarget;
  661.     AEKeyword        ignoredKeyWord;
  662.     DescType        ignoredType;
  663.     Size            ignoredSize;
  664.     GameListHndl    gameMoves;
  665.     WindowPtr        oldPort, window, fwindow, behindWindow;
  666.     WindowPeek        wpeek;
  667.     FSSpec            myFSS;
  668.     Str32            opponentName, zone, machine, application;
  669.     Str255            reconnectPath;
  670.     Str32            reconnectApp;
  671.     Handle            userNameHndl, hText;
  672.     short            i, drawBtnState, sendReason, myColor, invertBoard, fromSq, toSq;
  673.     GameListHndl    oldGame, newGame;
  674.     GameElement        *optr, *nptr;
  675.     short            oldGameIndex, newGameIndex, oldNumMoves, newNumMoves, identical;
  676.     TEHandle        te;
  677.  
  678.     err = noErr;
  679.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  680.         reply,                    /* The AppleEvent.              */
  681.         keyReplyErr,            /* AEKeyword                 */
  682.         typeShortInteger,        /* Desired type.             */
  683.         (Ptr)&err,                /* Pointer to area for data. */ 
  684.         sizeof(short)            /* Size of data area.         */
  685.     );
  686.  
  687.     receiveGameList.dataHandle = nil;
  688.         /* Make sure disposing of the descriptors is okay in all cases.
  689.         ** This will not be necessary after 7.0b3, since the calls that
  690.         ** attempt to create the descriptors will nil automatically
  691.         ** upon failure. */
  692.  
  693.     IncNewFileNum(false);
  694.     err = AppNewDocument(&newFrHndl, ksOrigName);
  695.     IncNewFileNum(true);
  696.  
  697.     if (err) return(err);
  698.  
  699.     /* We have a new document... */
  700.     err = AEGetParamDesc(    /* GET THE APPLEEVENT LIST.  */
  701.         message,            /* AppleEvent to holding list.          */
  702.         keyDirectObject,    /* This is our direct (only) object.  */
  703.         typeWildCard,        /* Desired type is game list.          */
  704.         &receiveGameList    /* The list to add to the AppleEvent. */
  705.     );
  706.  
  707.     if (!err) {        /* If we got the list descriptor... */
  708.         hstate = LockHandleHigh((Handle)newFrHndl);
  709.         ptr1   = (Ptr)&((*newFrHndl)->doc);
  710.         ptr2   = (Ptr)&((*newFrHndl)->doc.endSendInfo);
  711.         size   = (long)ptr2 - (long)ptr1;
  712.         err = AEGetNthPtr(        /* GET BOARD INFO FROM THE LIST.     */
  713.             &receiveGameList,    /* List to get from.                 */
  714.             1L,                    /* Get first item in list.             */
  715.             typeTheBoard,        /* First item is the board.             */
  716.             &ignoredKeyWord,    /* Returned keyword -- we know.         */
  717.             &ignoredType,        /* Returned type -- we know.         */
  718.             ptr1,                /* Where to put the board info.         */
  719.             size,                /* Size of the board.                 */
  720.             &ignoredSize        /* Actual size -- we know.             */
  721.         );
  722.         HSetState((Handle)newFrHndl, hstate);
  723.     }
  724.  
  725.     if (!err) {        /* If we got the board... */
  726.         gameMoves = (*newFrHndl)->doc.gameMoves;
  727.         size      = (*newFrHndl)->doc.numGameMoves * sizeof(GameElement);
  728.         SetHandleSize((Handle)gameMoves, size);
  729.         err = MemError();
  730.         if (!err) {
  731.             hstate = LockHandleHigh((Handle)gameMoves);
  732.             err = AEGetNthPtr(        /* GET GAME MOVES FROM THE LIST.     */
  733.                 &receiveGameList,    /* List to get from.                 */
  734.                 2L,                    /* Get second item in list.             */
  735.                 typeGameMoves,        /* Second item is the game moves.     */
  736.                 &ignoredKeyWord,    /* Returned keyword -- we know.         */
  737.                 &ignoredType,        /* Returned type -- we know.         */
  738.                 (Ptr)(*gameMoves),    /* Where to put the moves.             */
  739.                 size,                /* Size of the board.                 */
  740.                 &ignoredSize        /* Actual size -- we know.             */
  741.             );
  742.             HSetState((Handle)gameMoves, hstate);
  743.         }
  744.     }
  745.  
  746.  
  747.  
  748.     if (!err) {
  749.  
  750.         /* We now have the board and game moves, in newFrHndl.  This is either a
  751.         ** new opponent, or an update from an old opponent.  Let's see... */
  752.  
  753.         twoPlayer = (*newFrHndl)->doc.twoPlayer;
  754.         (*newFrHndl)->doc.twoPlayer = false;
  755.             /* See if this is an already existing opponent, or a new one. */
  756.     
  757.         if (!twoPlayer) {        /* If new game... */
  758.             err = AEGetAttributeDesc(    /* GET ADDRESS OF NEW OPPONENT.     */
  759.                 message,                /* Get address of sender from message.         */
  760.                 keyAddressAttr,            /* We want an address.                         */
  761.                 typeWildCard,            /* We want the address of the sender.         */
  762.                 &senderTarget            /* Address of sender.                         */
  763.             );
  764.             if (!err) {
  765.                 (*newFrHndl)->doc.twoPlayer     = true;
  766.                 (*newFrHndl)->doc.arrangeBoard  = false;
  767.                 (*newFrHndl)->doc.locOfOpponent = senderTarget;
  768.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  769.                     &receiveGameList,    /* List to get from.            */
  770.                     3L,                    /* Get second item in list.        */
  771.                     typeFSS,            /* Third item is the FSSpec.    */
  772.                     &ignoredKeyWord,    /* Returned keyword -- we know. */
  773.                     &ignoredType,        /* Returned type -- we know.    */
  774.                     (Ptr)&myFSS,        /* Where to put the FSSpec.        */
  775.                     sizeof(FSSpec),        /* Size of the data.            */
  776.                     &ignoredSize        /* Actual size -- we know.        */
  777.                 );
  778.                 if (!err)
  779.                     pcpy((*newFrHndl)->fileState.fss.name, myFSS.name);
  780.             }
  781.             if (!err) {
  782.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  783.                     &receiveGameList,    /* List to get from.                */
  784.                     4L,                    /* Get second item in list.            */
  785.                     typePascal,            /* Third item is the opponent name.    */
  786.                     &ignoredKeyWord,    /* Returned keyword -- we know.     */
  787.                     &ignoredType,        /* Returned type -- we know.        */
  788.                     (Ptr)opponentName,    /* Where to put the opponent name.    */
  789.                     sizeof(Str32),        /* Size of the data.                */
  790.                     &ignoredSize        /* Actual size.                        */
  791.                 );
  792.                 (*newFrHndl)->doc.opponentName[0] = 0;
  793.                 if (!err) {
  794.                     pcpy((*newFrHndl)->doc.opponentName, opponentName);
  795.                     zone[0] = machine[0] = 0;
  796.                     GetTargetInfo(senderTarget, zone, machine, application);
  797.                     pcpy((*newFrHndl)->doc.opponentZone, zone);
  798.                     pcpy((*newFrHndl)->doc.opponentMachine, machine);
  799.                     GetDateTime(&((*newFrHndl)->doc.timeLastReceive));
  800.                 }
  801.                 if (!err) {
  802.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  803.                         &receiveGameList,    /* List to get from.                */
  804.                         5L,                    /* Get second item in list.            */
  805.                         typePascal2,        /* Third item is the opponent name.    */
  806.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  807.                         &ignoredType,        /* Returned type -- we know.        */
  808.                         (Ptr)reconnectPath,    /* Where to put the opponent name.    */
  809.                         sizeof(Str255),        /* Size of the data.                */
  810.                         &ignoredSize        /* Actual size.                        */
  811.                     );
  812.                     (*newFrHndl)->doc.reconnectPath[0] = 0;
  813.                     if (!err) pcpy((*newFrHndl)->doc.reconnectPath, reconnectPath);
  814.                 }
  815.                 if (!err) {
  816.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  817.                         &receiveGameList,    /* List to get from.                */
  818.                         6L,                    /* Get second item in list.            */
  819.                         typePascal3,        /* Third item is the opponent name.    */
  820.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  821.                         &ignoredType,        /* Returned type -- we know.        */
  822.                         (Ptr)reconnectApp,    /* Where to put the opponent name.    */
  823.                         sizeof(Str32),        /* Size of the data.                */
  824.                         &ignoredSize        /* Actual size.                        */
  825.                     );
  826.                     (*newFrHndl)->doc.reconnectApp[0] = 0;
  827.                     if (!err) pcpy((*newFrHndl)->doc.reconnectApp, reconnectApp);
  828.                 }
  829.             }
  830.         }
  831.     }
  832.  
  833.     if (!err) {        /* If we got the opponent address... */
  834.  
  835.         if (!twoPlayer) {        /* It is a new game... */
  836.  
  837.             (*newFrHndl)->doc.timerRefTick = TickCount();
  838.                 /* Set the timer reference early as possible.
  839.                 ** This syncs the two clocks as much as possible. */
  840.  
  841.                 /* For a new opponent, then we need to ID the receiver side
  842.                 ** of the sender/receiver ID pair.  We also need to send
  843.                 ** back the receiver portion of the ID pair for the sender. */
  844.  
  845.             (*newFrHndl)->doc.gameID_0 = gameID[0] = (TickCount() | 0x01);
  846.             (*newFrHndl)->doc.myColor     ^= 1;
  847.             (*newFrHndl)->doc.invertBoard ^= 1;
  848.                 /* We are the opposite color/side as the opponent. */
  849.  
  850.             if ((*newFrHndl)->doc.version != kVersion) err = errAEWrongDataType;
  851.                 /* Incompatible file format. */
  852.  
  853.             if (!err) {
  854.                 gameID[1] = (*newFrHndl)->doc.gameID_1;
  855.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  856.                     reply,                /* The AppleEvent.              */
  857.                     keyGameID,            /* AEKeyword                 */
  858.                     typeDoubleLong,        /* Type code.                 */
  859.                     (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  860.                     2 * sizeof(long)    /* Size of data area.         */
  861.                 );
  862.             }
  863.  
  864.             if (!err) {
  865.                 opponentName[0] = 0;
  866.                 userNameHndl = GetResource('STR ', -16096);
  867.                 if (userNameHndl)
  868.                     pcpy(opponentName, (StringPtr)(*userNameHndl));
  869.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  870.                     reply,                /* The AppleEvent.              */
  871.                     keyPascalReply,        /* AEKeyword                 */
  872.                     typePascal,            /* Type code.                 */
  873.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  874.                     opponentName[0] + 1    /* Size of data area.         */
  875.                 );
  876.             }
  877.  
  878.             if (!err) {
  879.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  880.                 err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  881.                     reply,                    /* The AppleEvent.              */
  882.                     keyPascal2Reply,        /* AEKeyword                 */
  883.                     typePascal2,            /* Type code.                 */
  884.                     (Ptr)reconnectPath,        /* Pointer to area for data. */ 
  885.                     reconnectPath[0] + 1    /* Size of data area.         */
  886.                 );
  887.                 if (!err) {
  888.                     err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  889.                         reply,                    /* The AppleEvent.              */
  890.                         keyPascal3Reply,        /* AEKeyword                 */
  891.                         typePascal3,            /* Type code.                 */
  892.                         (Ptr)reconnectApp,        /* Pointer to area for data. */ 
  893.                         reconnectApp[0] + 1    /* Size of data area.         */
  894.                     );
  895.                 }
  896.             }
  897.  
  898.             if (!err) {
  899.                 if (IsAppWindow(fwindow = FrontWindow())) {
  900.                     frPtr = *(frHndl = (FileRecHndl)GetWRefCon(fwindow));
  901.                     if (
  902.                         (frPtr->doc.myColor != kMessageDoc) &&
  903.                         (!(frPtr->doc.arrangeBoard)) &&
  904.                         (!(frPtr->doc.twoPlayer)) &&
  905.                         (!(frPtr->doc.numGameMoves)) &&
  906.                         (!(frPtr->doc.gameID_0)) &&
  907.                         (!(frPtr->doc.timeLastReceive))
  908.                     ) {
  909.                         AppDisposeDocument(frHndl);
  910.                         DisposeAnyWindow(fwindow);
  911.                     }
  912.                 }
  913.                 behindWindow = (WindowPtr)-1;
  914.                 for (wpeek = LMGetWindowList(); wpeek; wpeek = wpeek->nextWindow) {
  915.                     if (IsAppWindow((WindowPtr)wpeek)) {
  916.                         frPtr = *(FileRecHndl)GetWRefCon((WindowPtr)wpeek);
  917.                         if (
  918.                             (frPtr->doc.myColor != kMessageDoc) &&
  919.                             (!(frPtr->doc.arrangeBoard)) &&
  920.                             (!(frPtr->doc.twoPlayer)) &&
  921.                             (!(frPtr->doc.numGameMoves))
  922.                         ) break;
  923.                         behindWindow = (WindowPtr)wpeek;
  924.                     }
  925.                 }
  926.                 err = AppNewWindow(newFrHndl, nil, behindWindow);
  927.             }
  928.  
  929.                 /* If everything worked for new opponent, give the new document a window. */
  930.  
  931.             if (!err) {
  932.                 AdjustGameSlider(newFrHndl);
  933.  
  934.                 DrawButtonTitle(newFrHndl, kTwoPlayer);
  935.                     /* Convert the draw button to two player. */
  936.  
  937.                 (*newFrHndl)->doc.gotUpdateTick = TickCount();
  938.                     /* Record when we got the event. */
  939.  
  940.                 fwindow = FrontWindow();
  941.                 mssgFrHndl = (FileRecHndl)GetWRefCon((WindowPtr)fwindow);
  942.                 if ((*mssgFrHndl)->doc.myColor == kMessageDoc) {
  943.                     te     = (*mssgFrHndl)->doc.message[kMessageOut];
  944.                     hText  = (*te)->hText;
  945.                     hstate = LockHandleHigh(hText);
  946.                     size   = (*te)->teLength;
  947.                     err = AEPutParamPtr(
  948.                         reply,
  949.                         keyTextMessage,
  950.                         typeMssg,
  951.                         *hText,
  952.                         size
  953.                     );
  954.                     HSetState(hText, hstate);
  955.                 }
  956.             }
  957.         }
  958.         else {        /* It is an update to an existing game. */
  959.  
  960.             window = GetGameWindow(
  961.                 (*newFrHndl)->doc.gameID_1, (*newFrHndl)->doc.gameID_0);
  962.                     /* Get the window for the existing game. */
  963.  
  964.             if (window) {        /* This game still exists... */
  965.  
  966.                 oldFrHndl = (FileRecHndl)GetWRefCon(window);
  967.                 UpdateTime(oldFrHndl, false);
  968.  
  969.                 if ((*oldFrHndl)->doc.resync < (sendReason = (*newFrHndl)->doc.sendReason))
  970.                     (*oldFrHndl)->doc.resync = sendReason;
  971.                         /* Bump up resync, if needed. */
  972.  
  973.                 if (sendReason == kScrolling) {
  974.                     if (
  975.                         ((*oldFrHndl)->doc.resync == kResync) || 
  976.                         ((*oldFrHndl)->doc.gotUpdateTick + 30 > TickCount())
  977.                     ) {
  978.                         window = nil;
  979.                         AppDisposeDocument(newFrHndl);
  980.                                 /* Temporary document now gone. */
  981.                     }    /* If it has been less than 1/2 second since the last
  982.                         ** scroll update received, or if the user has finished
  983.                         ** scrolling, then we can ignore this scroll event.
  984.                         ** This keeps us from getting behind in the processing
  985.                         ** of scroll events. */
  986.                 }
  987.             }
  988.             else
  989.                 err = memFullErr;
  990.                     /* Can't find the old window, so cause some kind of error. */
  991.  
  992.             if (window) {        /* This game still exists... */
  993.  
  994.                 if (sendReason != kIsMove) {
  995.                     for (i = 0; i < 2; ++i)
  996.                         (*newFrHndl)->doc.timeLeft[i] = (*oldFrHndl)->doc.timeLeft[i];
  997.                             /* Keep our clock values if opponent is scrolling or resyncing. */
  998.                 }
  999.  
  1000.                 frPtr        = *oldFrHndl;
  1001.                 oldGameIndex = frPtr->doc.gameIndex;
  1002.                 oldNumMoves  = frPtr->doc.numGameMoves;
  1003.                 oldGame      = frPtr->doc.gameMoves;
  1004.                 frPtr        = *newFrHndl;
  1005.                 newGameIndex = frPtr->doc.gameIndex;
  1006.                 newNumMoves  = frPtr->doc.numGameMoves;
  1007.                 newGame      = frPtr->doc.gameMoves;
  1008.                 if ((oldGameIndex == newGameIndex) && (oldNumMoves == newNumMoves)) {
  1009.                     optr = &(**oldGame)[0];
  1010.                     nptr = &(**newGame)[0];
  1011.                     identical = true;
  1012.                     for (i = 0; i < oldNumMoves; ++i, ++optr, ++nptr) {
  1013.                         if (
  1014.                             (optr->moveFrom          != nptr->moveFrom) ||
  1015.                             (optr->moveTo            != nptr->moveTo) ||
  1016.                             (optr->pieceCaptured     != nptr->pieceCaptured) ||
  1017.                             (optr->pieceCapturedFrom != nptr->pieceCapturedFrom) ||
  1018.                             (optr->promoteTo         != nptr->promoteTo)
  1019.                         ) {
  1020.                             identical = false;
  1021.                             break;
  1022.                         }
  1023.                     }
  1024.                 }
  1025.                 else identical = false;
  1026.  
  1027.                 myColor     = (*oldFrHndl)->doc.myColor;
  1028.                 invertBoard = (*oldFrHndl)->doc.invertBoard;
  1029.                     /* These need to be saved, so they are in that section,
  1030.                     ** but they are private info, so cache them. */
  1031.  
  1032.                 ptr1 = (Ptr)&((*newFrHndl)->doc);
  1033.                 ptr2 = (Ptr)&((*newFrHndl)->doc.endFileInfo1);
  1034.                 size = (long)ptr2 - (long)ptr1;
  1035.                 ptr2 = (Ptr)&((*oldFrHndl)->doc);
  1036.                 BlockMove(ptr1, ptr2, size);
  1037.  
  1038.                 (*oldFrHndl)->doc.myColor     = myColor;
  1039.                 (*oldFrHndl)->doc.invertBoard = invertBoard;
  1040.                     /* Restore our private cached values. */
  1041.  
  1042.                 (*newFrHndl)->doc.gameMoves = (*oldFrHndl)->doc.gameMoves;
  1043.                 (*oldFrHndl)->doc.gameMoves = gameMoves;
  1044.                     /* Swap the game move handles.  The existing document
  1045.                     ** is now updated completely.  We can dispose of the
  1046.                     ** temporary new one.  (gameMoves is set above for
  1047.                     ** the handle for the new document.) */
  1048.  
  1049.                 i = (*newFrHndl)->doc.drawBtnState;
  1050.                 drawBtnState = kTwoPlayer;
  1051.                 if (i & 0x02) drawBtnState |= 0x04;
  1052.                 if (i & 0x04) drawBtnState |= 0x02;
  1053.  
  1054.                 AppDisposeDocument(newFrHndl);
  1055.                     /* Temporary document now gone. */
  1056.  
  1057.                 GetPort(&oldPort);
  1058.                 SetPort(window);
  1059.  
  1060.                 if (!identical) {        /* There was a change, so show it. */
  1061.                     if (sendReason == kIsMove) {
  1062.                     if (GetControlValue((*oldFrHndl)->doc.beepOnMove)) SysBeep(1);
  1063.                         if (GameStatus(oldFrHndl) <= kDrawByRep) {
  1064.                             MakeMove(oldFrHndl, -1, 0, 0);
  1065.                             oldGame      = (*oldFrHndl)->doc.gameMoves;
  1066.                             oldGameIndex = (*oldFrHndl)->doc.gameIndex;
  1067.                             fromSq = (**oldGame)[oldGameIndex].moveFrom;
  1068.                             toSq   = (**oldGame)[oldGameIndex].moveTo;
  1069.                             SlideThePiece(oldFrHndl, fromSq, toSq);
  1070.                             MakeMove(oldFrHndl, 1, 0, 0);
  1071.                             SayTheMove(oldFrHndl);
  1072.                         }
  1073.                     }
  1074.                     ImageDocument(oldFrHndl, true);
  1075.                     AdjustGameSlider(oldFrHndl);
  1076.                 }
  1077.  
  1078.                 DrawButtonTitle(oldFrHndl, drawBtnState);
  1079.                 UpdateGameStatus(oldFrHndl);
  1080.                     /* Update the text of the draw button. */
  1081.  
  1082.                 DrawTime(oldFrHndl);
  1083.  
  1084.                 (*oldFrHndl)->doc.gotUpdateTick = TickCount();
  1085.                     /* Record when we got the event. */
  1086.  
  1087.                 if (sendReason == kIsMove) {
  1088.                     (*oldFrHndl)->fileState.docDirty = true;
  1089.                     AlertIfGameOver(oldFrHndl);
  1090.                         /* For non-moves, we don't want to beep or
  1091.                         ** show a game-over dialog. */
  1092.                 }
  1093.                 SetPort(oldPort);
  1094.             }
  1095.         }
  1096.     }
  1097.  
  1098.     if (err) AppDisposeDocument(newFrHndl);
  1099.         /* This won't get done twice, even though there is an
  1100.         ** AppDisposeDocument(newFrHndl) earlier.  The earlier
  1101.         ** one only happens if no error occured, and this one
  1102.         ** only happens on an error condition. */
  1103.  
  1104.     AEDisposeDesc(&receiveGameList);
  1105.         /* Dispose of the descriptors, created or not.
  1106.         ** If not created, no harm done by calling. */
  1107.  
  1108.     if (!err) NotifyUser();
  1109.     return(err);
  1110. }
  1111.  
  1112.  
  1113.  
  1114. /*****************************************************************************/
  1115.  
  1116.  
  1117.  
  1118. /* Send one of various messages to the opponent.  There is a common set of
  1119. ** data that needs to be sent so that the opponent can determine which game
  1120. ** the message should be applied.  Then there is message-specific data that
  1121. ** is handled case by case.  Once the message is completed, it is sent off
  1122. ** to the opponent.  The additional task of updating the state of our game
  1123. ** is also handled here.  For example:  When text is sent, the text on our
  1124. ** machine is selected to make it easier to replace the old text with new
  1125. ** text.  Any typing by the user will replace the selected text (all the text)
  1126. ** with the newly typed text.  */
  1127.  
  1128. #pragma segment AppleEvents
  1129. Boolean    SendMssg(FileRecHndl frHndl, short messageType)
  1130. {
  1131.     AEAddressDesc    locOfOpponent;
  1132.     OSErr            err;
  1133.     TEHandle        teIn, teOut;
  1134.     char            hstate;
  1135.     AppleEvent        theAevt, reply;
  1136.     Handle            hText, snd, intxt, outtxt;
  1137.     RgnHandle        oldClip, newClip;
  1138.     TextStyle        styl;
  1139.     long            size, gameID[2], time[2];
  1140.     short            i, inlen, outlen, overflow;
  1141.     Boolean            twoPlayer;
  1142.     WindowPtr        oldPort, curPort;
  1143.     Point            pt;
  1144.     short            txFont, txSize;
  1145.     Style            txFace;
  1146.     Handle            finf;
  1147.  
  1148.     oldPort = SetFilePort(frHndl);
  1149.     GetPort(&curPort);
  1150.  
  1151.     theAevt.dataHandle = reply.dataHandle = nil;
  1152.         /* Make sure disposing of the descriptors is okay in all cases.
  1153.         ** This will not be necessary after 7.0b3, since the calls that
  1154.         ** attempt to create the descriptors will nil automatically
  1155.         ** upon failure. */
  1156.  
  1157.     err = noErr;
  1158.  
  1159.     twoPlayer = (*frHndl)->doc.twoPlayer;
  1160.     if (twoPlayer) {
  1161.  
  1162.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1163.  
  1164.         err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  1165.             kCustomEventClass,            /* Event class.                 */
  1166.             kibitzAESendMssg,            /* Event ID.                 */
  1167.             &locOfOpponent,                /* Address of receiving app. */
  1168.             kAutoGenerateReturnID,        /* This value causes the     */
  1169.                                         /* AppleEvent manager to     */
  1170.                                         /* assign a return ID that     */
  1171.                                         /* is unique to the session. */
  1172.             kAnyTransactionID,            /* Ignore transaction ID.     */
  1173.             &theAevt                    /* Location of event.         */
  1174.         );
  1175.  
  1176.         if (!err) {            /* Say what the message is. */
  1177.             AEPutParamPtr(
  1178.                 &theAevt,
  1179.                 keyDirectObject,
  1180.                 typeShortInteger,
  1181.                 (Ptr)&messageType,
  1182.                 sizeof(short)
  1183.             );
  1184.         }
  1185.  
  1186.         if (!err) {            /* Say what window message is for. */
  1187.             gameID[0] = (*frHndl)->doc.gameID_0;
  1188.             gameID[1] = (*frHndl)->doc.gameID_1;
  1189.             AEPutParamPtr(
  1190.                 &theAevt,
  1191.                 keyGameID,
  1192.                 typeDoubleLong,
  1193.                 (Ptr)&gameID[0],
  1194.                 2 * sizeof(long)
  1195.             );
  1196.         }
  1197.     }
  1198.  
  1199.     /* The stuff that applies to all messages is now done.  Now specifically
  1200.     ** handle all the different message types. */
  1201.  
  1202.     if (!err) {
  1203.         switch (messageType) {
  1204.  
  1205.             case kAmWhiteMssg:
  1206.             case kAmBlackMssg:
  1207.                 (*frHndl)->doc.configColor       = messageType;
  1208.                 (*frHndl)->doc.configColorChange = true;
  1209.                 (*frHndl)->doc.resync            = kHandResync;
  1210.                     /* The AppleEvent already has all the data the opponent
  1211.                     ** needs.  Post that a color change is happening.  The
  1212.                     ** reason that it is posted, instead of immediately applied,
  1213.                     ** is that we want to make sure that the opponent isn't
  1214.                     ** doing a color change operation at the same time.  The
  1215.                     ** color change will only occur when we get a NULL event.
  1216.                     ** The NULL event indicates that the opponent isn't sending
  1217.                     ** any AppleEvents at that time.  Waiting for quiescence
  1218.                     ** helps prevent the state of the game from getting
  1219.                     ** confused.  Also, the creator of the game echos the
  1220.                     ** color change, just to make sure that both machines are
  1221.                     ** in the same state.  (The echo doesn't occur until
  1222.                     ** there are no other AppleEvents happening.  This helps
  1223.                     ** keep the number of AppleEvents down, as well.) */
  1224.                 break;
  1225.  
  1226.             case kDisconnectMssg:
  1227.                     /* All the information we need is already in the AppleEvent. */
  1228.                 break;
  1229.  
  1230.             case kTimeMssg:
  1231.                 for (i = 0; i < 2; ++i)
  1232.                     time[i] = (*frHndl)->doc.configTime[i] = (*frHndl)->doc.timeLeft[i];
  1233.                 if (twoPlayer) {
  1234.                     err = AEPutParamPtr(
  1235.                         &theAevt,
  1236.                         keyTime,
  1237.                         typeDoubleLong,
  1238.                         (Ptr)&time[0],
  1239.                         2 * sizeof(long)
  1240.                     );
  1241.                     if ((*frHndl)->doc.resync)
  1242.                         (*frHndl)->doc.configTimeChange = true;
  1243.                     else {
  1244.                         for (i = 0; i < 2; ++i)
  1245.                             (*frHndl)->doc.timeLeft[i] =
  1246.                                 (*frHndl)->doc.displayTime[i] =
  1247.                                     (*frHndl)->doc.configTime[i];
  1248.                         UpdateTime(frHndl, false);
  1249.                         DrawTime(frHndl);
  1250.                     }
  1251.                 }
  1252.                 break;
  1253.  
  1254.             case kTextMssg:
  1255.                 if (twoPlayer) {
  1256.                     teOut  = (*frHndl)->doc.message[kMessageOut];
  1257.                     hText  = (*teOut)->hText;
  1258.                     hstate = LockHandleHigh(hText);
  1259.                     size   = (*teOut)->teLength;
  1260.                     err = AEPutParamPtr(
  1261.                         &theAevt,
  1262.                         keyTextMessage,
  1263.                         typeMssg,
  1264.                         *hText,
  1265.                         size
  1266.                     );
  1267.                     HSetState(hText, hstate);
  1268.                 }
  1269.                 break;
  1270.  
  1271.             case kSoundMssg:
  1272.                 if (twoPlayer) {
  1273.                     snd = (*frHndl)->doc.sound;
  1274.                     if (snd) {
  1275.                         hstate = LockHandleHigh(snd);
  1276.                         size   = GetHandleSize(snd);
  1277.                         err = AEPutParamPtr(
  1278.                             &theAevt,
  1279.                             keySoundMessage,
  1280.                             typeMssg,
  1281.                             *snd,
  1282.                             size
  1283.                         );
  1284.                         HSetState(snd, hstate);
  1285.                     }
  1286.                 }
  1287.                 break;
  1288.         }
  1289.     }
  1290.  
  1291.     if (twoPlayer) {
  1292.         if (!err) {        /* If everything looks good... */
  1293.             err = AESend(                /* SEND APPLEEVENT.                 */
  1294.                 &theAevt,                /* Our Apple Event to send.         */
  1295.                 &reply,                    /* We may have a reply.             */
  1296.                 kAENoReply,                /* Don't wait for reply.         */
  1297.                 PRIORITY,                /* App. send priority.             */
  1298.                 0,                        /* We aren't waiting.             */
  1299.                 nil,                    /* We don't wait, so no idleProc */
  1300.                 nil                        /* EventFilterProcPtr.             */
  1301.             );
  1302.         }
  1303.         if (!err) {
  1304.             switch (messageType) {
  1305.                 case kTextMssg:
  1306.  
  1307.                     finf = GetResource('finf', 128);
  1308.                     styl.tsFont = (*(short **)finf)[1];
  1309.  
  1310.                     teIn   = (*frHndl)->doc.message[kMessageIn];
  1311.                     intxt  = (*teIn)->hText;
  1312.  
  1313.                     txFont = curPort->txFont;
  1314.                     txSize = curPort->txSize;
  1315.                     txFace = curPort->txFace;
  1316.                     TextFont(styl.tsFont);
  1317.                     TextSize((*(short **)finf)[3]);
  1318.                     TextFace(normal);
  1319.                     outtxt = CTESwapText(teOut, NewHandle(0), nil, true);
  1320.                     TextFont(txFont);
  1321.                     TextSize(txSize);
  1322.                     TextFace(txFace);
  1323.  
  1324.                     inlen  = (*teIn)->teLength;
  1325.                     outlen = GetHandleSize(outtxt);
  1326.  
  1327.                     GetClip(oldClip = NewRgn());
  1328.                     SetClip(newClip = NewRgn());
  1329.  
  1330.                     overflow = inlen + outlen - 31998;
  1331.                     if (overflow > 0) {
  1332.                         if (overflow > inlen) overflow = inlen;
  1333.                         TESetSelect(0, overflow, teIn);
  1334.                         TEDelete(teIn);
  1335.                         inlen -= overflow;
  1336.                     }
  1337.  
  1338.                     inlen = (*teIn)->teLength;
  1339.                     TESetSelect(inlen, inlen, teIn);
  1340.                     if ((inlen) && (outlen < 31998)) {
  1341.                         i = ((*intxt)[inlen - 1] == 13) ? 1 : 2;
  1342.                         for (;i--;) {
  1343.                             TEKey(13, teIn);
  1344.                             ++inlen;
  1345.                         }
  1346.                         styl.tsSize = 4;
  1347.                         TESetSelect(inlen - 1, inlen, teIn);
  1348.                         TESetStyle((doFont | doSize), &styl, false, teIn);
  1349.                         TESetSelect(inlen, inlen, teIn);
  1350.                     }
  1351.  
  1352.                     HLock(outtxt);
  1353.                     TEInsert(*outtxt, outlen, teIn);
  1354.                     DisposeHandle(outtxt);
  1355.  
  1356.                     TESetSelect(inlen, (*teIn)->teLength, teIn);
  1357.  
  1358.                     styl.tsFace = italic;
  1359.                     styl.tsSize = 9;
  1360.                     TESetStyle((doFont | doFace | doSize), &styl, false, teIn);
  1361.  
  1362.                     TECalText(teIn);
  1363.                     pt = TEGetPoint(inlen, teIn);
  1364.                     pt.v -= 12;
  1365.                     TEScroll(0, (*teIn)->viewRect.top - pt.v, teIn);
  1366.  
  1367.                     SetClip(oldClip);
  1368.                     DisposeRgn(oldClip);
  1369.                     DisposeRgn(newClip);
  1370.  
  1371.                     CTEUpdate(teIn, CTEViewFromTE(teIn), false);
  1372.                     CTEAdjustTEBottom(teIn);
  1373.                     CTEAdjustScrollValues(teIn);
  1374.  
  1375.                     break;
  1376.  
  1377.                 case kSoundMssg:
  1378.                     SndPlay(nil, (*frHndl)->doc.sound, false);
  1379.                     break;
  1380.             }
  1381.         }
  1382.  
  1383.         AEDisposeDesc(&theAevt);
  1384.         AEDisposeDesc(&reply);
  1385.             /* Dispose of the descriptors, created or not.
  1386.             ** If not created, no harm done by calling. */
  1387.     }
  1388.  
  1389.     SetPort(oldPort);
  1390.     return(err);
  1391. }
  1392.  
  1393.  
  1394.  
  1395. /*****************************************************************************/
  1396.  
  1397.  
  1398.  
  1399. #pragma segment AppleEvents
  1400. pascal OSErr    ReceiveMssg(AppleEvent *message, AppleEvent *reply, long refcon)
  1401. {
  1402. #ifndef __MWERKS__
  1403. #pragma unused (refcon)
  1404. #endif
  1405.  
  1406.     OSErr            err;
  1407.     long            gameID[2], time[2];
  1408.     short            messageType, i, inlen, outlen, overflow;
  1409.     WindowPtr        oldPort, window;
  1410.     FileRecHndl        frHndl;
  1411.     DescType        actualType;
  1412.     long            actualSize, mssgSize;
  1413.     unsigned long    key;
  1414.     char            hstate;
  1415.     Handle            mssgData, intxt, outtxt;
  1416.     AEAddressDesc    locOfOpponent;
  1417.     RgnHandle        oldClip, newClip;
  1418.     TEHandle        teIn;
  1419.     TextStyle        styl;
  1420.     Point            pt;
  1421.     Handle            finf;
  1422.  
  1423.     err = noErr;
  1424.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  1425.         reply,                    /* The AppleEvent.              */
  1426.         keyReplyErr,            /* AEKeyword                 */
  1427.         typeShortInteger,        /* Desired type.             */
  1428.         (Ptr)&err,                /* Pointer to area for data. */ 
  1429.         sizeof(short)            /* Size of data area.         */
  1430.     );
  1431.  
  1432.     err = AEGetParamPtr(        /* GET THE MESSAGE TYPE.     */
  1433.         message,                /* The AppleEvent.              */
  1434.         keyDirectObject,        /* AEKeyword                 */
  1435.         typeShortInteger,        /* Desired type.             */
  1436.         &actualType,            /* Type code.                 */
  1437.         (Ptr)&messageType,        /* Pointer to area for data. */ 
  1438.         2 * sizeof(long),        /* Size of data area.         */
  1439.         &actualSize                /* Returned size of data.     */
  1440.     );
  1441.  
  1442.     if (!err) {
  1443.         err = AEGetParamPtr(        /* GET WINDOW MESSAGE IS FOR. */
  1444.             message,                /* The AppleEvent.               */
  1445.             keyGameID,                /* AEKeyword                  */
  1446.             typeDoubleLong,            /* Desired type.              */
  1447.             &actualType,            /* Type code.                  */
  1448.             (Ptr)&gameID[0],        /* Pointer to area for data.  */ 
  1449.             2 * sizeof(long),        /* Size of data area.          */
  1450.             &actualSize                /* Returned size of data.      */
  1451.         );
  1452.     }
  1453.  
  1454.     if (!err) {            /* See if the requested window exists... */
  1455.         window = GetGameWindow(gameID[1], gameID[0]);
  1456.         if (window) {
  1457.             frHndl = (FileRecHndl)GetWRefCon(window);
  1458.                 /* The game still exists... */
  1459.         }
  1460.         else
  1461.             err = userCanceledErr;
  1462.                 /* User (or computer) canceled game by disconnecting improperly. */
  1463.     }
  1464.  
  1465.     if (!err) {        /* If everything is cool, then do the specific task... */
  1466.  
  1467.         switch(messageType) {
  1468.  
  1469.             case kAmWhiteMssg:
  1470.             case kAmBlackMssg:
  1471.                 messageType ^= 1;
  1472.                 (*frHndl)->doc.configColor       = messageType;
  1473.                 (*frHndl)->doc.configColorChange = true;
  1474.                 (*frHndl)->doc.resync            = kHandResync;
  1475.                 if ((*frHndl)->doc.creator)
  1476.                     SendMssg(frHndl, messageType);
  1477.                         /* If we are the creator, echo the message to make sure
  1478.                         ** that both players aren't the same color. */
  1479.                 break;
  1480.  
  1481.             case kDisconnectMssg:
  1482.                 locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1483.                 AEDisposeDesc(&locOfOpponent);
  1484.                 (*frHndl)->doc.twoPlayer = kLimbo;
  1485.                     /* We set the state of the game to NOT two-player, and NOT
  1486.                     ** what we are now.  This allows us to call SetOpponentType
  1487.                     ** to do all the work we need done.  If we didn't fudge the
  1488.                     ** state of the game (from two-player) then SetOpponentType
  1489.                     ** would send a disconnect message (and we would end up
  1490.                     ** back here.)  This would be an ugly situation, which is
  1491.                     ** completely prevented by fudging the state of the game. */
  1492.                 SetOpponentType(frHndl, kOnePlayer);
  1493.                 break;
  1494.  
  1495.             case kTimeMssg:
  1496.                 AEGetParamPtr(
  1497.                     message,                /* The AppleEvent.              */
  1498.                     keyTime,                /* AEKeyword                 */
  1499.                     typeDoubleLong,            /* Desired type.             */
  1500.                     &actualType,            /* Type code.                 */
  1501.                     (Ptr)&time[0],            /* Pointer to area for data. */ 
  1502.                     2 * sizeof(long),        /* Size of data area.         */
  1503.                     &mssgSize                /* Returned size of data.     */
  1504.                 );
  1505.                 for (i = 0; i < 2; ++i)
  1506.                     (*frHndl)->doc.configTime[i] = time[i];
  1507.                 if ((*frHndl)->doc.resync)
  1508.                     (*frHndl)->doc.configTimeChange = true;
  1509.                 else {
  1510.                     for (i = 0; i < 2; ++i)
  1511.                         (*frHndl)->doc.timeLeft[i] =
  1512.                             (*frHndl)->doc.displayTime[i] = time[i];
  1513.                     UpdateTime(frHndl, false);
  1514.                     DrawTime(frHndl);
  1515.                 }
  1516.                 if ((*frHndl)->doc.creator)
  1517.                     SendMssg(frHndl, kTimeMssg);
  1518.                         /* If we are the creator, echo the message to make sure
  1519.                         ** the clocks are in sync. */
  1520.                 break;
  1521.  
  1522.             case kTextMssg:
  1523.             case kSoundMssg:
  1524.                 /* Both the text and sound message simply send a block of
  1525.                 ** data less than 32k.  Get the data from the AppleEvent
  1526.                 ** for both cases, and then decide what kind of data it is. */
  1527.  
  1528.                 key = (messageType == kTextMssg) ? keyTextMessage : keySoundMessage;
  1529.                 if (!err) {        /* Determine the size of the data... */
  1530.                     err = AEGetParamPtr(
  1531.                         message,                /* The AppleEvent.              */
  1532.                         key,                    /* AEKeyword                 */
  1533.                         typeMssg,                /* Desired type.             */
  1534.                         &actualType,            /* Type code.                 */
  1535.                         nil,                    /* Pointer to area for data. */ 
  1536.                         0,                        /* Size of data area.         */
  1537.                         &mssgSize                /* Returned size of data.     */
  1538.                     );
  1539.                 }
  1540.                 mssgData = nil;
  1541.                 if (!err) {        /* Get the data... */
  1542.                     mssgData = NewHandle(mssgSize);
  1543.                     if (mssgData) {
  1544.                         hstate = LockHandleHigh(mssgData);
  1545.                         err = AEGetParamPtr(
  1546.                             message,                /* The AppleEvent.              */
  1547.                             key,                    /* AEKeyword                 */
  1548.                             typeMssg,                /* Desired type.             */
  1549.                             &actualType,            /* Type code.                 */
  1550.                             *mssgData,                /* Pointer to area for data. */ 
  1551.                             mssgSize,                /* Size of data area.         */
  1552.                             &actualSize                /* Returned size of data.     */
  1553.                         );
  1554.                     }
  1555.                     else err = memFullErr;
  1556.                 }
  1557.                 if (!err) {
  1558.                     if (messageType == kTextMssg) {
  1559.  
  1560.                         finf = GetResource('finf', 128);
  1561.                         styl.tsFont = (*(short **)finf)[1];
  1562.  
  1563.                         teIn   = (*frHndl)->doc.message[kMessageIn];
  1564.                         intxt  = (*teIn)->hText;
  1565.                         outtxt = mssgData;
  1566.                         inlen  = (*teIn)->teLength;
  1567.                         outlen = GetHandleSize(outtxt);
  1568.  
  1569.                         oldPort = SetFilePort(frHndl);
  1570.                         GetClip(oldClip = NewRgn());
  1571.                         SetClip(newClip = NewRgn());
  1572.  
  1573.                         overflow = inlen + outlen - 31998;
  1574.                         if (overflow > 0) {
  1575.                             if (overflow > inlen) overflow = inlen;
  1576.                             TESetSelect(0, overflow, teIn);
  1577.                             TEDelete(teIn);
  1578.                             inlen -= overflow;
  1579.                         }
  1580.  
  1581.                         inlen = (*teIn)->teLength;
  1582.                         TESetSelect(inlen, inlen, teIn);
  1583.                         if ((inlen) && (outlen < 31998)) {
  1584.                             i = ((*intxt)[inlen - 1] == 13) ? 1 : 2;
  1585.                             for (;i--;) {
  1586.                                 TEKey(13, teIn);
  1587.                                 ++inlen;
  1588.                             }
  1589.                             styl.tsSize = 4;
  1590.                             TESetSelect(inlen - 1, inlen, teIn);
  1591.                             TESetStyle((doFont | doSize), &styl, false, teIn);
  1592.                             TESetSelect(inlen, inlen, teIn);
  1593.                         }
  1594.  
  1595.                         HLock(outtxt);
  1596.                         TEInsert(*outtxt, outlen, teIn);
  1597.  
  1598.                         TESetSelect(inlen, (*teIn)->teLength, teIn);
  1599.  
  1600.                         styl.tsFace = normal;
  1601.                         styl.tsSize = (*(short **)finf)[3];
  1602.                         TESetStyle((doFont | doFace | doSize), &styl, false, teIn);
  1603.  
  1604.                         TECalText(teIn);
  1605.                         pt = TEGetPoint(inlen, teIn);
  1606.                         pt.v -= 12;
  1607.                         TEScroll(0, (*teIn)->viewRect.top - pt.v, teIn);
  1608.  
  1609.                         SetClip(oldClip);
  1610.                         DisposeRgn(oldClip);
  1611.                         DisposeRgn(newClip);
  1612.                         SetPort(oldPort);
  1613.  
  1614.                         CTEUpdate(teIn, CTEViewFromTE(teIn), false);
  1615.                         CTEAdjustTEBottom(teIn);
  1616.                         CTEAdjustScrollValues(teIn);
  1617.  
  1618.                         if ((*frHndl)->doc.doSpeech)
  1619.                             SayText(teIn, nil, (*frHndl)->doc.theVoice);
  1620.  
  1621.                         if (GetControlValue((*frHndl)->doc.beepOnMssg))
  1622.                             if (mssgSize) SysBeep(1);
  1623.                     }
  1624.                     else SndPlay(nil, mssgData, false);
  1625.                 }
  1626.                 if (mssgData) DisposeHandle(mssgData);
  1627.                 if (!err) NotifyUser();
  1628.                 break;
  1629.  
  1630.             case kBeepMssg:
  1631.                 SysBeep(1);
  1632.                 break;
  1633.  
  1634.         }
  1635.     }
  1636.  
  1637.     return(err);
  1638. }
  1639.  
  1640.  
  1641.  
  1642. /*****************************************************************************/
  1643. /*****************************************************************************/
  1644.  
  1645.  
  1646.  
  1647. /* GetGameWindow
  1648. **
  1649. ** Find the window with the specified game ID's. */
  1650.  
  1651. #pragma segment AppleEvents
  1652. WindowPtr    GetGameWindow(long gameID_0, long gameID_1)
  1653. {
  1654.     WindowPeek    window;
  1655.     FileRecHndl    frHndl;
  1656.  
  1657.     for (window = LMGetWindowList(); window; window = window->nextWindow) {
  1658.         if (IsAppWindow((WindowPtr)window)) {
  1659.             frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
  1660.             if (
  1661.                 ((*frHndl)->doc.gameID_0 == gameID_0) &&
  1662.                 ((*frHndl)->doc.gameID_1 == gameID_1)
  1663.             ) return((WindowPtr)window);
  1664.         }
  1665.     }
  1666.  
  1667.     return(nil);
  1668. }
  1669.  
  1670.  
  1671.  
  1672. /*****************************************************************************/
  1673.  
  1674.  
  1675.  
  1676. /* KibitzPortFilter
  1677. **
  1678. ** Don't allow PPCBrowser to show any applications other than Kibitz. */
  1679.  
  1680. #pragma segment AppleEvents
  1681. pascal Boolean    KibitzPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1682. {
  1683. #ifndef __MWERKS__
  1684. #pragma unused (locationName)
  1685. #endif
  1686.  
  1687.     long    type;
  1688.  
  1689.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1690.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1691.             /* The BlockMove is so that we don't get an address error
  1692.             ** on a 68000-based machine due to referencing a long at
  1693.             ** an odd-address. */
  1694.         if (type == gameCreator) return(true);
  1695.     }
  1696.  
  1697.     return(false);
  1698. }
  1699.  
  1700.  
  1701.  
  1702. /*****************************************************************************/
  1703.  
  1704.  
  1705.  
  1706. /* SetOpponentType
  1707. **
  1708. ** Change the opponent type from whatever it currently is to the specified
  1709. ** type.  In so doing, change the state of any controls, etc., that need
  1710. ** to be changed due to the new opponent type. */
  1711.  
  1712. #pragma segment AppleEvents
  1713. void    SetOpponentType(FileRecHndl frHndl, short newOpponentType)
  1714. {
  1715.     WindowPtr        oldPort, window;
  1716.     short            oldOpponentType, hilite, i, toggle;
  1717.     AEAddressDesc    locOfOpponent;
  1718.     Rect            boardRect;
  1719.     ControlHandle    ctl;
  1720.     RgnHandle        oldClip, newClip;
  1721.  
  1722.     if (!(*frHndl)->fileState.window) return;
  1723.  
  1724.     if (!(oldOpponentType = (*frHndl)->doc.arrangeBoard))
  1725.         oldOpponentType = (*frHndl)->doc.twoPlayer;
  1726.  
  1727.     if (oldOpponentType == newOpponentType) return;
  1728.  
  1729.     (*frHndl)->doc.arrangeBoard = false;
  1730.  
  1731.     oldPort = SetFilePort(frHndl);
  1732.     GetPort(&window);
  1733.  
  1734.     oldClip = NewRgn();
  1735.     newClip = NewRgn();
  1736.     GetClip(oldClip);
  1737.  
  1738.     toggle = false;
  1739.     if ((newOpponentType == kArrangeBoard) || (oldOpponentType == kArrangeBoard)) {
  1740.         toggle = true;
  1741.         SetClip(newClip);        /* Prevent stuff from drawing. */
  1742.     }
  1743.  
  1744.     if (oldOpponentType == kTwoPlayer) {
  1745.         SendMssg(frHndl, kDisconnectMssg);
  1746.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1747.         AEDisposeDesc(&locOfOpponent);
  1748.     }
  1749.  
  1750.     if (newOpponentType == kTwoPlayer) {
  1751.         hilite = 0;
  1752.         (*frHndl)->doc.timerRefTick = TickCount();
  1753.         (*frHndl)->doc.creator = true;
  1754.         if ((*frHndl)->doc.myColor == WHITE) (*frHndl)->doc.compMovesBlack = false;
  1755.         else                                 (*frHndl)->doc.compMovesWhite = false;
  1756.     }
  1757.     else {
  1758.         hilite = 255;
  1759.         (*frHndl)->doc.creator = false;
  1760.         (*frHndl)->doc.resync  = kIsMove;
  1761.         (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  1762.     }
  1763.  
  1764.     SetPort(window);
  1765.  
  1766.     if (newOpponentType == kArrangeBoard) {
  1767.         CTEActivate(false, CTEFindActive(window));
  1768.         (*frHndl)->doc.king[BLACK].rookMoves[QSIDE] = 0;
  1769.         (*frHndl)->doc.king[BLACK].rookMoves[KSIDE] = 0;
  1770.         (*frHndl)->doc.king[WHITE].rookMoves[QSIDE] = 0;
  1771.         (*frHndl)->doc.king[WHITE].rookMoves[KSIDE] = 0;
  1772.         (*frHndl)->doc.enPasMove        = 0;
  1773.         (*frHndl)->doc.enPasPawnLoc     = 0;
  1774.         (*frHndl)->doc.arngEnPasMove    = 0;
  1775.         (*frHndl)->doc.arngEnPasPawnLoc = 0;
  1776.         (*frHndl)->doc.numLegalMoves    = 0;
  1777.         (*frHndl)->doc.gameIndex        = 0;
  1778.         (*frHndl)->doc.numGameMoves     = 0;
  1779.         (*frHndl)->doc.compMovesWhite   = false;
  1780.         (*frHndl)->doc.compMovesBlack   = false;
  1781.         AdjustGameSlider(frHndl);
  1782.     }
  1783.     if (oldOpponentType == kArrangeBoard) CTEWindActivate(window, true);
  1784.  
  1785.     if (newOpponentType == kArrangeBoard) {
  1786.         (*frHndl)->doc.arrangeBoard = kArrangeBoard;
  1787.         newOpponentType = kOnePlayer;
  1788.     }
  1789.     (*frHndl)->doc.twoPlayer = newOpponentType;
  1790.  
  1791.     HiliteControl(ctl = (*frHndl)->doc.sendMessage, hilite);
  1792.     OutlineControl(ctl);
  1793.     HiliteControl((*frHndl)->doc.beepOnMove, hilite);
  1794.     HiliteControl((*frHndl)->doc.beepOnMssg, hilite);
  1795.  
  1796.     if (!SoundInputAvaliable()) hilite = 255;
  1797.     HiliteControl((*frHndl)->doc.record, hilite);
  1798.     if (!(*frHndl)->doc.sound) hilite = 255;
  1799.     HiliteControl((*frHndl)->doc.sendSnd, hilite);
  1800.     DrawButtonTitle(frHndl, newOpponentType);
  1801.  
  1802.     if (toggle) {
  1803.         SetClip(oldClip);
  1804.         for (i = 0; i < 2; ++i) (*frHndl)->doc.timeLeft[i] = -1;
  1805.         boardRect = BoardRect();
  1806.         boardRect.left = boardRect.right + 1;
  1807.         boardRect.right = 1000;
  1808.         EraseRect(&boardRect);
  1809.         ImageDocument(frHndl, false);
  1810.     }
  1811.  
  1812.     DisposeRgn(oldClip);
  1813.     DisposeRgn(newClip);
  1814.     SetPort(oldPort);
  1815. }
  1816.  
  1817.  
  1818.  
  1819. /*****************************************************************************/
  1820.  
  1821.  
  1822.  
  1823. #pragma segment AppleEvents
  1824. void    GetFullPathAndAppName(StringPtr path, StringPtr app)
  1825. {
  1826.     ProcessSerialNumber    psn;
  1827.     ProcessInfoRec        pinfo;
  1828.     FSSpec                fss;
  1829.  
  1830.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  1831.     pinfo.processName       = app;
  1832.     pinfo.processAppSpec    = &fss;
  1833.  
  1834.     psn.lowLongOfPSN  = kCurrentProcess;
  1835.     psn.highLongOfPSN = kNoProcess;
  1836.     GetProcessInformation(&psn, &pinfo);
  1837.  
  1838.     PathNameFromDirID(pinfo.processAppSpec->parID, pinfo.processAppSpec->vRefNum, path);
  1839. }
  1840.  
  1841.  
  1842.  
  1843. /*****************************************************************************/
  1844.  
  1845.  
  1846.  
  1847. /* Don't allow DoIPCListPorts to find anything but the finder. */
  1848.  
  1849. #pragma segment AppleEvents
  1850. pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1851. {
  1852. #ifndef __MWERKS__
  1853. #pragma unused (locationName)
  1854. #endif
  1855.  
  1856.     OSType    type;
  1857.  
  1858.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1859.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1860.             /* The BlockMove is so that we don't get an address error
  1861.             ** on a 68000-based machine due to referencing a long at
  1862.             ** an odd-address. */
  1863.         if (type == 'MACS') return(true);
  1864.     }
  1865.  
  1866.     return(false);
  1867. }
  1868.  
  1869. /***/
  1870.  
  1871. /* Don't allow DoIPCListPorts to find anything but Kibitz. */
  1872.  
  1873. #pragma segment AppleEvents
  1874. static pascal Boolean    KibitzFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1875. {
  1876. #ifndef __MWERKS__
  1877. #pragma unused (locationName)
  1878. #endif
  1879.  
  1880.     OSType    type;
  1881.  
  1882.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1883.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1884.             /* The BlockMove is so that we don't get an address error
  1885.             ** on a 68000-based machine due to referencing a long at
  1886.             ** an odd-address. */
  1887.         if (type == 'KBTZ') return(true);
  1888.     }
  1889.  
  1890.     return(false);
  1891. }
  1892.  
  1893. /***/
  1894.  
  1895. OSErr    GetRemoteProcessTarget(FileRecHndl frHndl, AEDesc *retDesc, GRPTProcPtr proc)
  1896. {
  1897.     OSErr            err;
  1898.     char            hstate;
  1899.     PortInfoRec        info;        /* Just one, please. */
  1900.     LocationNameRec    loc;
  1901.     short            indx, reqCount, actCount;
  1902.     TargetID        theID;
  1903.  
  1904.     retDesc->dataHandle = nil;        /* So caller can dispose always. */
  1905.  
  1906.     hstate = LockHandleHigh((Handle)frHndl);
  1907.     loc.locationKindSelector = ppcNBPLocation;        /* Using an NBP construct. */
  1908.     pcpy(loc.u.nbpEntity.objStr,  (*frHndl)->doc.reconnectMachine);
  1909.     pcpy(loc.u.nbpEntity.zoneStr, (*frHndl)->doc.reconnectZone);
  1910.     pcpy(loc.u.nbpEntity.typeStr, "\pPPCToolBox");
  1911.     HSetState((Handle)frHndl, hstate);
  1912.  
  1913.     indx     = 0;
  1914.     reqCount = 1;
  1915.     actCount = 0;
  1916.     err = DoIPCListPorts(&indx, &reqCount, &actCount, &loc, &info, proc);
  1917.     if (err) return(err);
  1918.  
  1919.     if (actCount) {
  1920.         theID.name = info.name;
  1921.         theID.location = loc;
  1922.         err = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), retDesc);
  1923.     }
  1924.  
  1925.     return(err);
  1926. }
  1927.  
  1928.  
  1929.  
  1930.