home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Abalone 1.4.2 / src / Connection.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-21  |  10.2 KB  |  544 lines  |  [TEXT/MPS ]

  1. #define CONNECTION_C
  2. #include "Connection.h"
  3. #include "Abalone.h"
  4.  
  5.  
  6. #if defined(__MWERKS__)
  7. #pragma segment __%Main
  8. #else
  9. #pragma segment Main
  10. #endif
  11.  
  12.  
  13. static    AEAddressDesc    address[kPlayers+1];
  14.  
  15.  
  16. Boolean
  17. Connected (void)
  18. {
  19.     return gSet.Connected [blak] || gSet.Connected [whit] || gSet.Connected [grin];
  20. }
  21.  
  22.  
  23.  
  24. PPCFilterUPP portFilterUPP = 0;
  25.     
  26.  
  27. void
  28. InitConnection(void)
  29. {
  30.     short    p;
  31.     Boolean    netPlayerSelected = false;
  32.     
  33.     if (!portFilterUPP) portFilterUPP = NewPPCFilterProc (AbalonePortFilter);
  34.  
  35. //    In principal, we could try to restore the old connections.
  36. //    Because I don't, the connect state must be reset.
  37.  
  38.     for (p = blak; p <= gSet.Players; p++)
  39.     {
  40.         gSet.Connected[p] = false;
  41.     }
  42.     
  43. //    Check to see if we have network players at all.
  44. //    If not, don't bother establishing any kind of connection.
  45.  
  46.     for (p = blak; p <= gSet.Players; p++)
  47.     {
  48.         if (gSet.PlayerKind[p] == networkPlayer)
  49.         {
  50.             netPlayerSelected = true;
  51.             break;
  52.         }
  53.     }
  54.  
  55.     if (! netPlayerSelected)
  56.         return;
  57.         
  58. //    There are net players selected.
  59. //    Give the user a chance to determine what to do now.
  60.  
  61.     portFilterUPP = NewPPCFilterProc (AbalonePortFilter);
  62.  
  63.     CurrentCursor (arrowCursor);
  64.     switch (Alert (rConnection, nil))
  65.     {
  66.         case 1:    //    Establish Connection
  67.             ConnectionProtocol();
  68.         break;
  69.         
  70.         case 2:    //    Wait for other
  71.         
  72.             ;
  73.             
  74.         break;
  75.         
  76.         case 3:    //    Cancel net play
  77.         
  78.         //    Cancelling is done by replacing all net players by mac players.
  79.         
  80.             for (p = blak; p <= gSet.Players; p++)
  81.             {
  82.                 if (gSet.PlayerKind[p] == networkPlayer)
  83.                 {
  84.                     ClearNetAddress (p);
  85.                     gSet.PlayerKind[p] = macPlayer;
  86.                 }
  87.             }
  88.         break;
  89.     }
  90. }
  91.  
  92.  
  93.  
  94. AEAddressDesc    *
  95. GetNetAddress (short player)
  96. {
  97.     Assert (IsConnected(player), INTERNAL_ERROR);
  98.     return & address[player];
  99. }
  100.  
  101.  
  102.  
  103. void
  104. SetNetAddress (AEAddressDesc *newAddress, short player)
  105. {
  106.     if (IsConnected(player))
  107.         AEDisposeDesc (& address[player]);
  108.     
  109.     gSet.Connected[player] = (AEDuplicateDesc (newAddress, & address[player]) == noErr);
  110. }
  111.  
  112.  
  113.  
  114. void
  115. ClearNetAddress (short player)
  116. {    
  117.     if (IsConnected(player))
  118.         AEDisposeDesc (& address[player]);
  119.         
  120.     gSet.Connected[player] = false;
  121. }
  122.  
  123.  
  124.  
  125. Boolean
  126. IsConnected (short player)
  127. {
  128.     return gSet.Connected[player];
  129. }
  130.  
  131.  
  132.  
  133. Boolean    
  134. ConnectState (SettingsPtr settings, short player)
  135. {
  136.     return settings->Connected[player];
  137. }
  138.  
  139.  
  140.  
  141. void
  142. BreakConnections (void)
  143. {
  144.     short            p, q;
  145.     OSErr            error;
  146.     
  147.     for (p = blak; p <= gSet.Players; p++)
  148.     {
  149.         if (! IsNetPlayer (& gSet, p) || ! IsConnected (p))
  150.             continue;
  151.             
  152.         for (q = blak; q <= gSet.Players; q++)
  153.         {
  154.             if (gSet.PlayerKind[q] != networkPlayer)
  155.             {
  156.                 error = SendAEStop (GetNetAddress(p), q);
  157.             }
  158.         }
  159.         ClearNetAddress(p);
  160.     }
  161. }
  162.  
  163.  
  164.  
  165. void
  166. ReSyncProtocol (void)
  167. {
  168.     short    p;
  169.     
  170.     for (p = blak; p <= gSet.Players; p++)
  171.     {
  172.         if (! IsNetPlayer (& gSet, p) || ! IsConnected (p))
  173.             continue;
  174.             
  175.         SynchronisationProtocol (p);
  176.     }
  177. }
  178.  
  179.  
  180.  
  181. void
  182. SynchronisationProtocol (short p)
  183. {
  184.     Game            serverGame;
  185.     Board            serverBoard;
  186.     
  187.     if (SendAEGame (& address[p], & gTheGame, CurrentBoard(), & serverGame, & serverBoard) != noErr)
  188.         return;
  189.         
  190.     if (CheckSum (& serverBoard) != CheckSum (CurrentBoard()))
  191.     {
  192.         if (serverGame.CurrentMove <= gTheGame.CurrentMove)
  193.         {
  194.             Warning (OUT_OF_SYNC);
  195.             
  196.             gTheGame = serverGame;
  197.             CopyBoard (& serverBoard, CurrentBoard());
  198.             gTheGame.Board = CurrentBoard();
  199.             InvalBoard();
  200.         }
  201.     //    else: the other side handles this
  202.     }
  203. }
  204.  
  205.  
  206.  
  207. OSErr
  208. ConnectionProtocol (void)
  209. {
  210.     Str255            prompt, label;
  211.     OSErr            error = noErr;
  212.     short            p, q;
  213.     Settings        wantedSet;
  214.     Settings        serverSet;
  215.     long            serverCheckSum;
  216.     AEAddressDesc    netAddress;
  217.     Boolean            protocolDone = false;
  218.     
  219.     for (p = blak; ! protocolDone && p <= gSet.Players; p++)
  220.     {
  221.         if (! IsNetPlayer (& gSet, p))
  222.             continue;
  223.             
  224.         if (IsConnected (p))
  225.             break;
  226.         
  227.         GetIndString (prompt, rPPCStrings, 1);
  228.         GetIndString (label, rPPCStrings, 2);
  229.     
  230.         error = MakeTarget (    & netAddress,
  231.                                 false,
  232.                                 kAEWaitReply,
  233.                                 prompt,
  234.                                 label,
  235.                                 portFilterUPP
  236.                             );
  237.         
  238.         if (error == noErr)
  239.         {
  240.         //    We have a valid net address to establish a connection with.
  241.         //    Show the other side our current settings, and get the requested settings.
  242.         
  243.             wantedSet = gSet;
  244.             error = SendAEInit (& netAddress, & wantedSet, & serverSet, & serverCheckSum);
  245.         }
  246.         if (error == noErr)
  247.         {
  248.         //    We have a valid reply from the server as well.
  249.         //    We should set our settings as requested.
  250.         
  251.             gSet = wantedSet;
  252.         
  253.         //    If we have a valid reply, we now have the other sides settings,
  254.         //    which means we know which address to use for all players the server handles!
  255.         
  256.             for (q = blak; q <= serverSet.Players; q++)
  257.                 if    (! IsNetPlayer (& serverSet, q))
  258.                     SetNetAddress (& netAddress, q);
  259.             
  260.         //    The net address has been copied by all who need it;
  261.         //    it can and should be disposed.
  262.         
  263.             AEDisposeDesc (& netAddress);
  264.             
  265.         //    Handle out-of-sync problems.
  266.         //    We have a valid connection, so if we have an out-of-sync,
  267.         //    we should be able to ask for the right board.
  268.         
  269.         
  270.             if ( serverCheckSum != CheckSum (CurrentBoard()))
  271.             {
  272.                 SynchronisationProtocol (p);
  273.             }
  274.         
  275.         //    Request the server a broadcast of net addresses (my own, among others).    
  276.             
  277.             error = SendAENew1 (& netAddress, & gSet);
  278.  
  279.         //    Because we broadcast the addresses, we don't need more than 1 good connection.
  280.         
  281.             protocolDone = true;
  282.         }
  283.         else switch (error)
  284.         {
  285.             case missingDataErr:
  286.                 Warning (PPC);
  287.             case noConnectionErr:
  288.             default:
  289.                 CurrentCursor (arrowCursor);
  290.                 switch (Alert (403, nil))
  291.                 {
  292.                     case 1:    //    Retry connecting
  293.                         --p;
  294.                     break;
  295.                     case 2:    //    Wait for other
  296.                         protocolDone = true;
  297.                     break;
  298.                     case 3:    //    Cancel net play
  299.                         CancelNetPlay();
  300.                         protocolDone = true;
  301.                     break;
  302.                 }
  303.             break;
  304.         }
  305.     }
  306.     return error;
  307. }
  308.  
  309.  
  310.  
  311. OSErr
  312. BroadcastMove (MovePtr move, short player, long checksum)
  313. {
  314.     short            p;
  315.     OSErr            error = noErr;
  316.     
  317.     //    Send this game to all known network players
  318.     
  319.     for (p = blak; p <= gSet.Players; p++)
  320.     {
  321.         if (gSet.PlayerKind[p] != networkPlayer)
  322.             continue;
  323.             
  324.         if (! IsConnected(p))                            //    try to restore connection
  325.             ConnectionProtocol();
  326.  
  327.         if (! IsConnected(p))                        //    connection not restored
  328.             continue;
  329.  
  330.         error = SendAEMove (GetNetAddress(p), move, player, checksum);
  331.         
  332.         switch (error)
  333.         {
  334.             case noErr:
  335.             default:
  336.             break;
  337.             
  338.             case outOfSyncErr:
  339.                 SynchronisationProtocol (p);
  340.             break;
  341.             
  342.             case illegalMoveErr:
  343.             case duplicateMoveErr:
  344.                 error = noErr;
  345.             break;
  346.         }
  347.     }
  348.     return error;
  349. }
  350.  
  351.  
  352.  
  353. // Don't allow PPCBrowser to show any applications other than Abalone.
  354.  
  355. pascal Boolean    AbalonePortFilter (LocationNamePtr locationName, PortInfoPtr thePortInfo)
  356. {
  357. #if ! defined(__MWERKS__) && ! defined (__SC__)
  358. #pragma unused(locationName)
  359. #endif
  360.  
  361.     long    type;
  362.  
  363.     if (thePortInfo->name.portKindSelector == ppcByString)
  364.     {
  365.         BlockMove (thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  366.         if (type == 'A•1e')
  367.             return true;
  368.     }
  369.     return false;
  370. }
  371.  
  372.  
  373.  
  374.  
  375.  
  376. #ifdef NETDEBUG
  377. void
  378. DoNetTestMenu (short menuItem)
  379. {
  380.     static AEAddressDesc    gOpponent;
  381.     OSErr                    error;
  382.     
  383.     switch (menuItem)
  384.     {
  385.         case NETTEST_CONNECT:
  386.             gSet.Connected[0] = gSet.Connected[1] = gSet.Connected[2] = gSet.Connected[3] = false;
  387.             error = ConnectionProtocol();
  388.         break;
  389.         case NETTEST_MOVE:
  390.         //    The last move made is stored in a global gLastMove.
  391.         //    This can be sent to a different Abalone process.
  392.             BroadcastMove (gLastMove, PriorPlayer (CurrentPlayer()), CheckSum (RecentBoard()));
  393.         break;
  394.         case NETTEST_GAME:
  395.         //    For testing, the current game is sent to the other side.
  396.         
  397.             SendAEGame (GetNetAddress(NextPlayer(gTheGame.CurrentPlayer)), & gTheGame);
  398.         
  399.         break;
  400.         case NETTEST_UNDO:
  401.         break;
  402.         default:
  403.             Assert (false, DEFAULT_IN_CASE);
  404.     }
  405. }
  406. #endif
  407.  
  408.  
  409.  
  410. void
  411. MatchSettings (SettingsPtr smpl, SettingsPtr sets)
  412. {
  413.     short        p;
  414.     
  415.     Assert (sets->Version == smpl->Version, DIFFERENT_VERSION_ERROR);
  416.     
  417. //    Match the number of players
  418.     sets->Players = smpl->Players;
  419.  
  420. //    Don't care about personal preferences over there:
  421. //    Leave stuff like FieldWidth and SounOn alone.
  422.  
  423. //    Match the player types.
  424. //    This is the hard part, when we assume the settings need not be complementary.
  425.  
  426.     for (p = 1; p <= smpl->Players; p++)
  427.     {
  428.         if (IsMacPlayer (smpl, p))
  429.         {
  430.             if (IsMacPlayer (sets, p))
  431.             {
  432.                 SetPlayerKind (sets, p, networkPlayer);
  433.             }
  434.             else if (IsHumanPlayer (sets, p))
  435.             {
  436.                 SetPlayerKind (smpl, p, networkPlayer);
  437.             }
  438.             else //    IsNetPlayer (sets, p)
  439.             {
  440.                 Boolean    forceHuman =     ! ConnectState (sets, p)
  441.                                     &&    (CountHumanPlayers (sets) == 0);
  442.  
  443.                 if (forceHuman)
  444.                 {
  445.                     SetPlayerKind (sets, p, humanPlayer);
  446.                     SetPlayerKind (smpl, p, networkPlayer);
  447.                 }
  448.             }
  449.         }
  450.         else if (IsHumanPlayer (smpl, p))
  451.         {
  452.             if (IsMacPlayer (sets, p))
  453.             {
  454.                 SetPlayerKind (sets, p, networkPlayer);
  455.             }
  456.             else if (IsHumanPlayer (sets, p))
  457.             {
  458.                 SetPlayerKind (sets, p, networkPlayer);
  459.             }
  460.             else //    IsNetPlayer (sets, p)
  461.             {
  462.                 ;
  463.             }
  464.         }
  465.         else //    IsNetPlayer (smpl, p)
  466.         {
  467.             if (IsMacPlayer (sets, p))
  468.             {
  469.                 ;
  470.             }
  471.             else if (IsHumanPlayer (sets, p))
  472.             {
  473.                 ;
  474.             }
  475.             else //    IsNetPlayer (sets, p)
  476.             {
  477.                 Boolean    forceHuman =    smpl->Players == 2
  478.                                     ||    (! ConnectState (smpl, p) && ! ConnectState (sets, p));
  479.                 if (forceHuman)    
  480.                     SetPlayerKind (sets, p, humanPlayer);
  481.                 
  482.             }
  483.         }
  484.     }
  485.     
  486.     if (CountHumanPlayers (sets) == 0)
  487.     {
  488.     //    After making the changes above, the other side doesnt' have a human player left,
  489.     //    we can see if we have a slot left we can assign to him.
  490.     
  491.         for (p = 1; p <= smpl->Players; p++)
  492.         {
  493.             if    (IsMacPlayer (smpl, p))
  494.             {
  495.             //    So we do. Assign it to him.
  496.             
  497.                 SetPlayerKind (sets, p, humanPlayer);
  498.                 break;    //    one will do; others should have a chance as well.
  499.             }
  500.         }
  501.     }
  502.  
  503. //    Over here, the settings are as good as they will be, so assume them OK.
  504.     
  505. //    Match the names
  506.  
  507.     for (p = 1; p <= smpl->Players; p++)
  508.     {
  509.         if (smpl->PlayerKind[p] == humanPlayer)
  510.         {
  511.         //    Tell the other side our name
  512.         
  513.             strcpy (sets->PlayerName[p], smpl->PlayerName[p]);
  514.         }
  515.         if (sets->PlayerKind[p] == humanPlayer)
  516.         {
  517.         //    Be so polite as to use his own name
  518.         
  519.             strcpy (smpl->PlayerName[p], sets->PlayerName[p]);
  520.         }
  521.     }
  522. }
  523.  
  524.  
  525.  
  526. void
  527. CancelNetPlay (void)
  528. {
  529.     short    p;
  530.  
  531.     BreakConnections();    //    just to be sure
  532.  
  533. //    Cancelling is done by replacing all net players by mac players.
  534.  
  535.     for (p = blak; p <= gSet.Players; p++)
  536.     {
  537.         if (IsNetPlayer (& gSet, p))
  538.         {
  539.             ClearNetAddress (p);
  540.             SetPlayerKind (& gSet, p, macPlayer);
  541.         }
  542.     }
  543. }
  544.