home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / OPENSTEP / Games / Empire-0.6-MIS / DistributedGameManager.m < prev    next >
Encoding:
Text File  |  1997-10-31  |  48.4 KB  |  1,712 lines

  1. //
  2. // $Id: DistributedGameManager.m,v 1.12 1997/10/31 05:44:20 nygard Exp $
  3. //
  4.  
  5. //
  6. //  This file is a part of Empire, a game of exploration and conquest.
  7. //  Copyright (C) 1996  Steve Nygard
  8. //
  9. //  This program is free software; you can redistribute it and/or modify
  10. //  it under the terms of the GNU General Public License as published by
  11. //  the Free Software Foundation; either version 2 of the License, or
  12. //  (at your option) any later version.
  13. //
  14. //  This program is distributed in the hope that it will be useful,
  15. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. //  GNU General Public License for more details.
  18. //
  19. //  You should have received a copy of the GNU General Public License
  20. //  along with this program; if not, write to the Free Software
  21. //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. //
  23. //  You may contact the author by:
  24. //     e-mail:  nygard@telusplanet.net
  25. //
  26.  
  27. #import "Empire.h"
  28.  
  29. RCSID ("$Id: DistributedGameManager.m,v 1.12 1997/10/31 05:44:20 nygard Exp $");
  30.  
  31. #import "DistributedGameManager.h"
  32. #import "GameManager.h"
  33. #import "City.h"
  34. #import "EmPlayer.h"
  35. #import "EmpireProtocols.h"
  36. #import "Map.h"
  37. #import "SNRandom.h"
  38. #import "Unit.h"
  39. #import "World.h"
  40.  
  41. //======================================================================
  42. // This class is somewhat disorganized.  It adds functionality to
  43. // handle distributed games.
  44. //
  45. // I've annotated some of the methods:
  46. //   Client -> Server: The message is initiated from the client, and
  47. //                     goes to the server.
  48. //   Server -> Client: The message always originates in the server,
  49. //                     and queries the client.
  50. //   Client -> Server -> Client: The message is for a particular client,
  51. //                     and is forwarded to the propre client by the
  52. //                     server.
  53. //
  54. // Generally, when the server gets a message for a client it manages,
  55. // it calls the implementation in its superclass.
  56. //
  57. // You have to be really careful, otherwise you can get unlimited
  58. // recursion happening between separate processes.  However, the
  59. // methods tend to fall into the above three patterns.
  60. //======================================================================
  61.  
  62. #define DistributedGameManager_VERSION 1
  63.  
  64. @implementation DistributedGameManager
  65.  
  66. + (void) initialize
  67. {
  68.     if (self == [DistributedGameManager class])
  69.     {
  70.         [self setVersion:DistributedGameManager_VERSION];
  71.     }
  72. }
  73.  
  74. //----------------------------------------------------------------------
  75.  
  76. - init
  77. {
  78.     [super init];
  79.  
  80.     master = nil;
  81.     masterConnection = nil;
  82.     clientPlayer = p_neutral;
  83.     
  84.     playerManagers[0] = nil;
  85.     playerManagers[1] = nil;
  86.     playerManagers[2] = nil;
  87.     playerManagers[3] = nil;
  88.  
  89.     clientConnections[0] = nil;
  90.     clientConnections[1] = nil;
  91.     clientConnections[2] = nil;
  92.     clientConnections[3] = nil;
  93.  
  94.     unreadyRemotePlayers = 0;
  95.  
  96.     cachedMaps[0] = nil;
  97.     cachedMaps[1] = nil;
  98.     cachedMaps[2] = nil;
  99.     cachedMaps[3] = nil;
  100.  
  101.     return self;
  102. }
  103.  
  104. //----------------------------------------------------------------------
  105.  
  106. - (void) dealloc
  107. {
  108.     Player p;
  109.  
  110.     for (p = p_neutral; p <= p_player3; p++)
  111.     {
  112.         SNRelease (cachedMaps[p]);
  113.     }
  114.     
  115.     [super dealloc];
  116. }
  117.  
  118. //======================================================================
  119. // EmpireGameManagerProtocol
  120. //======================================================================
  121.  
  122. - (void) ping
  123. {
  124. }
  125.  
  126. //----------------------------------------------------------------------
  127.  
  128. - (void) aboutToDisconnect:sender
  129. {
  130. }
  131.  
  132. //----------------------------------------------------------------------
  133.  
  134. - (void) peer:clientGameManager forPlayer:(Player)number
  135. {
  136.     NSAssert (playerManagers[number] == nil, @"Player manager already set.");
  137.     NSAssert (clientConnections[number] == nil, @"Client connection already set.");
  138.     
  139.     playerManagers[number] = [clientGameManager retain];
  140.     clientConnections[number] = [clientGameManager connectionForProxy];
  141.  
  142.     [[NSNotificationCenter defaultCenter] addObserver:self
  143.                                           selector:@selector (connectionDidDie:)
  144.                                           name:NSConnectionDidDieNotification
  145.                                           object:clientConnections[number]];
  146.  
  147.     //[playerManagers[number] setProtocolForProxy:@protocol (EmpireGameManagerProtocol)];
  148.  
  149.     // Accessed by different threads?
  150.     unreadyRemotePlayers--;
  151.     playersActive[number] = YES;
  152.     activePlayerCount++;
  153.  
  154.     [[NSNotificationCenter defaultCenter] postNotificationName:EMPlayerStateChangedNotification
  155.                                           object:self];
  156.  
  157.     [self tryToStart];
  158. }
  159.  
  160. //----------------------------------------------------------------------
  161.  
  162. - (Map *) remoteFetchMapForPlayer:(Player)number
  163. {
  164.     return [self fetchMapForPlayer:number];
  165. }
  166.  
  167. //----------------------------------------------------------------------
  168.  
  169. // Run by client, so this client hasn't run -distribute maps...
  170. // Server -> Client
  171. - (void) otherMaps:(Map *)map1:(Map *)map2 forPlayer:(Player)number
  172. {
  173.     Player p1, p2;
  174.  
  175.     //NSLog (@"map1: %@, map2: %@", map1, map2);
  176.  
  177.     // ? constantly increasing retain count?
  178.     cachedMaps[number] = [[players[number] map] retain];
  179.  
  180.     p1 = (number == p_player1) ? p_player2 : p_player1;
  181.     p2 = (number == p_player3) ? p_player2 : p_player3;
  182.  
  183.     SNRelease (cachedMaps[p1]);
  184.     cachedMaps[p1] = [map1 retain];
  185.  
  186.     SNRelease (cachedMaps[p2]);
  187.     cachedMaps[p2] = [map2 retain];
  188.  
  189.     //NSLog (@"cachedMaps[%d]: %@, cachedMaps[%d]: %@", p1, cachedMaps[p1], p2, cachedMaps[p2]);
  190. }
  191.  
  192. //----------------------------------------------------------------------
  193.  
  194. - (void) remoteTurn:(int)turn withCookie:(NSNumber *)aCookie forPlayer:(Player)number
  195. {
  196.     NSAssert1 (players[number] != nil, @"Player %d is nil.", number);
  197.  
  198.     [players[number] yourTurn:turn withCookie:aCookie];
  199. }
  200.  
  201. //----------------------------------------------------------------------
  202.  
  203. - (void) remoteTurnDone:(NSNumber *)aCookie forPlayer:(Player)number updatedMap:(Map *)newMap
  204. {
  205.     SNRelease (cachedMaps[number]);
  206.  
  207.     cachedMaps[number] = [newMap retain];
  208.  
  209.     [self turnDone:aCookie];
  210. }
  211.  
  212. //======================================================================
  213. // EstablishGame
  214. //======================================================================
  215.  
  216. - (void) startGameWithMapNamed:(NSString *)mapName
  217. {
  218.     [super startGameWithMapNamed:mapName];
  219.  
  220.     unreadyRemotePlayers = 0;
  221. }
  222.  
  223. //----------------------------------------------------------------------
  224.  
  225. - (void) tryToStart
  226. {
  227.     AssertGameState (gs_establishing_game);
  228.  
  229.     if (unreadyRemotePlayers == 0)
  230.     {
  231.         [self distributeMaps];
  232.         [super tryToStart];
  233.     }
  234. }
  235.  
  236. //----------------------------------------------------------------------
  237. #if 0
  238. - (void) stopGame
  239. {
  240.     [super stopGame];
  241.     
  242.     SNRelease (master);
  243. }
  244. #endif
  245. //----------------------------------------------------------------------
  246.  
  247. //- (void) startGameWithMap:(Map *)worldMap master:(GameManager *)masterGameManager
  248. - (void) startGameWithMap:(Map *)worldMap master:masterGameManager
  249. {
  250.     // Check whether there is a game in progress
  251.     if (gameState != gs_no_game)
  252.     {
  253.         if (NSRunAlertPanel (@"New Client", @"There is already a game in progress or starting.", @"Cancel", @"Start new game", nil) == NSAlertDefaultReturn)
  254.             return;
  255.         
  256.         [self stopGame];
  257.     }
  258.  
  259.     AssertGameState (gs_no_game);
  260.     NSAssert (world == nil, @"There is already an active world.");
  261.  
  262.     NSAssert (master == nil, @"Master game manager already set.");
  263.     NSAssert (masterConnection == nil, @"Master connection alread set.");
  264.  
  265.     world = [[World alloc] initWithMap:worldMap];
  266.     NSAssert (world != nil, @"Could not create world.");
  267.  
  268.     [self setGameState:gs_establishing_game];
  269.     unreadyRemotePlayers = 0;
  270.     master = [masterGameManager retain];
  271.     masterConnection = [masterGameManager connectionForProxy];
  272.  
  273.     [[NSNotificationCenter defaultCenter] addObserver:self
  274.                                           selector:@selector (connectionDidDie:)
  275.                                           name:NSConnectionDidDieNotification
  276.                                           object:masterConnection];
  277. }
  278.  
  279. //----------------------------------------------------------------------
  280.  
  281. - (void) addRemotePlayer:(Player)number forClient:remoteClient
  282. {
  283.     NSProtocolChecker *protocolChecker;
  284.  
  285.     NSAssert (world != nil, @"No active world.");
  286.  
  287.     unreadyRemotePlayers++;
  288.  
  289.     protocolChecker = [NSProtocolChecker protocolCheckerWithTarget:self
  290.                                          protocol:@protocol (EmpireGameManagerProtocol)];
  291.  
  292.     NSAssert (protocolChecker != nil, @"A protocol checker could not be allocated.");
  293.  
  294.     NS_DURING
  295.         {
  296.             [remoteClient ping];
  297.             [remoteClient choosePlayer:number forMap:[world worldMap] master:protocolChecker];
  298.         }
  299.     NS_HANDLER
  300.         {
  301.             EHAND;
  302.         }
  303.     NS_ENDHANDLER;
  304. }
  305.  
  306. //----------------------------------------------------------------------
  307.  
  308. - (void) notifyMasterForPlayer:(Player)number
  309. {
  310.     NSProtocolChecker *protocolChecker;
  311.  
  312.     AssertGameState (gs_establishing_game);
  313.     NSAssert (master != nil, @"No master game manager.");
  314.  
  315.     protocolChecker = [NSProtocolChecker protocolCheckerWithTarget:self
  316.                                          protocol:@protocol (EmpireGameManagerProtocol)];
  317.  
  318.     NSAssert (protocolChecker != nil, @"A protocol checker could not be allocated.");
  319.  
  320.     clientPlayer = number;
  321.     [self setGameState:gs_client_active];
  322.  
  323.     NS_DURING
  324.         {
  325.             // Pass protocol checker.
  326.             [master peer:protocolChecker forPlayer:number];
  327.         }
  328.     NS_HANDLER
  329.         {
  330.             EHAND;
  331.         }
  332.     NS_ENDHANDLER;
  333. }
  334.  
  335. //----------------------------------------------------------------------
  336.  
  337. // This initializes the server map cache, which then fills each client
  338. // map cache.  Each client then synchronizes their initial map by
  339. // updating around all of their cities.  This is only needed at startup.
  340. //
  341. // At this time, all non-nil players/player managers should be active.
  342. //
  343. - (void) distributeMaps
  344. {
  345.     Player p;
  346.  
  347.     for (p = p_player1; p <= p_player3; p++)
  348.     {
  349.         if (playersActive[p] == YES)
  350.         {
  351.             // Problem retaining nil here?
  352.             cachedMaps[p] = [[self fetchMapForPlayer:p] retain];
  353.         }
  354.         else
  355.         {
  356.             cachedMaps[p] = nil;
  357.         }
  358.     }
  359.  
  360.     // Distribute maps to active remote players.
  361.     for (p = p_player1; p <= p_player3; p++)
  362.     {
  363.         if (playerManagers[p] != nil)
  364.         {
  365.             NSAssert1 (playersActive[p] == YES, @"Player %d should be active.", p);
  366.             [self distributeMapsToRemotePlayer:p];
  367.         }
  368.     }
  369.  
  370.     for (p = p_player1; p <= p_player3; p++)
  371.     {
  372.         if (playersActive[p] == YES)
  373.         {
  374.             [self updateMapAroundCitiesForPlayer:p];
  375.         }
  376.     }
  377. }
  378.  
  379. //======================================================================
  380. // TurnHandling
  381. //======================================================================
  382.  
  383. // Client -> Server
  384.  
  385. // I can't figure out a way of calling the super's implementation to
  386. // accomplish the default behaviour...
  387. - (void) turnDone:(NSNumber *)aCookie
  388. {
  389.     Player nextPlayer;
  390.     int limit = 3;
  391.     
  392.     if (master != nil)
  393.     {
  394.         NS_DURING
  395.             {
  396.                 [master remoteTurnDone:aCookie forPlayer:clientPlayer updatedMap:cachedMaps[clientPlayer]];
  397.             }
  398.         NS_HANDLER
  399.             {
  400.                 EHAND;
  401.             }
  402.         NS_ENDHANDLER;
  403.         
  404.         return;
  405.     }
  406.  
  407.     if ([awaitingCookie isEqual:aCookie] == NO)
  408.     {
  409.         //NSLog (@"awaiting: %@, got: %@", awaitingCookie, aCookie);
  410.         NSLog (@"[2] Invalid cookie!");
  411.         return;
  412.     }
  413.  
  414.     if (activePlayerCount <= 0)
  415.     {
  416.         NSLog (@"No active players.");
  417.         return;
  418.     }
  419.  
  420.     SNRelease (awaitingCookie);
  421.     awaitingCookie = [[NSNumber numberWithUnsignedLong:[[SNRandom instance] randomNumber]] retain];
  422.  
  423.     do
  424.     {
  425.         nextPlayer = [self nextPlayerTurn];
  426.     }
  427.     while (limit-- > 0 && (playersActive[nextPlayer] == NO
  428.                            || (players[nextPlayer] == nil && playerManagers[nextPlayer] == nil)));
  429.  
  430.     if (playersActive[nextPlayer] == YES && players[nextPlayer] != nil)
  431.     {
  432.         [players[nextPlayer] yourTurn:currentTurn withCookie:awaitingCookie];
  433.     }
  434.     else if (playersActive[nextPlayer] == YES && playerManagers[nextPlayer] != nil)
  435.     {
  436.         [self distributeMapsToRemotePlayer:nextPlayer];
  437.         NS_DURING
  438.             {
  439.                 [playerManagers[nextPlayer] remoteTurn:currentTurn withCookie:awaitingCookie forPlayer:nextPlayer];
  440.             }
  441.         NS_HANDLER
  442.             {
  443.                 EHAND;
  444.             }
  445.         NS_ENDHANDLER;
  446.     }
  447.     else
  448.     {
  449.         NSLog (@"No active players.");
  450.     }
  451. }
  452.  
  453. //----------------------------------------------------------------------
  454.  
  455. // This distributes the server's current map cache to a client.  It
  456. // should have no idea of active players.  When a player becomes
  457. // inactive, the map in the cache should become nil.?
  458.  
  459. // Server -> Client
  460. - (void) distributeMapsToRemotePlayer:(Player)number
  461. {
  462.     Player p1, p2;
  463.     Map *map1, *map2;
  464.         
  465.     NSAssert1 (playerManagers[number] != nil, @"No remote manager for player: %d", number);
  466.  
  467.     p1 = (number == p_player1) ? p_player2 : p_player1;
  468.     p2 = (number == p_player3) ? p_player2 : p_player3;
  469.     //NSLog (@"Distributing maps(%d,%d) to player manager: %d", p1, p2, number);
  470.  
  471.     NS_DURING
  472.         {
  473.             map1 = playersActive[p1] == YES ? cachedMaps[p1] : nil;
  474.             map2 = playersActive[p2] == YES ? cachedMaps[p2] : nil;
  475. #if 0
  476.             NSLog (@"Player %d active? %@, Player %d active? %@",
  477.                    p1, playersActive[p1] ? @"Yes" : @"No",
  478.                    p2, playersActive[p2] ? @"Yes" : @"No");
  479.             NSLog (@"Maps are %@, %@", map1, map2);
  480. #endif
  481.             [playerManagers[number] otherMaps:map1:map2 forPlayer:number];
  482.             //[playerManagers[number] otherMaps:cachedMaps[p1]:cachedMaps[p2] forPlayer:number];
  483.         }
  484.     NS_HANDLER
  485.         {
  486.             EHAND;
  487.         }
  488.     NS_ENDHANDLER;
  489. }
  490.  
  491. //======================================================================
  492. // Empire Game Manager Protocol:
  493. //======================================================================
  494.  
  495. //----------------------------------------------------------------------
  496. // The -remote* methods may be a bit redundant, but they helped me
  497. // distinguish between remote and local methods.
  498. //----------------------------------------------------------------------
  499.  
  500. //----------------------------------------------------------------------
  501. // Game Initialization / Termination
  502. //----------------------------------------------------------------------
  503.  
  504. - (City *) remoteRandomNeutralCity
  505. {
  506.     return [self randomNeutralCity];
  507. }
  508.  
  509. //----------------------------------------------------------------------
  510.  
  511. - (void) remoteGameHasStopped:(Player)number activePlayers:(int)activePlayers
  512. {
  513.     [self gameHasStopped:number activePlayers:activePlayers];
  514. }
  515.  
  516. //----------------------------------------------------------------------
  517. // Combat Support
  518. //----------------------------------------------------------------------
  519.  
  520. - (void) remoteSet3x3Tokens:(struct NineTokens)tokens aroundLocation:(EMMapLocation)target forPlayer:(Player)number
  521. {
  522.     [self set3x3Tokens:tokens.tokens aroundLocation:target forPlayer:number];
  523. }
  524.  
  525. //----------------------------------------------------------------------
  526.  
  527. - (void) remoteSetToken:(MapToken)token atLocation:(EMMapLocation)target forPlayer:(Player)number;
  528. {
  529.     [self setToken:token atLocation:target forPlayer:number];
  530. }
  531.  
  532. //----------------------------------------------------------------------
  533. // I trying very hard with these methods to avoid referencing remote
  534. // units and cities for combat.
  535. //----------------------------------------------------------------------
  536.  
  537. - (MoveResult) remoteUnitWithCombatProfile:(CombatProfile)attackerProfile
  538.                              attacksPlayer:(Player)cityPlayer
  539.                             cityAtLocation:(EMMapLocation)target
  540.                  playersAdjacentToDefender:(int)adjacentPlayers
  541. {
  542.     //NSLog (@"master: %@, cityPlayer: %d, cityLocation: %d,%d patd: %d", master, cityPlayer, target.row, target.column, adjacentPlayers);
  543.  
  544.     return [self unitWithCombatProfile:attackerProfile
  545.                  attacksPlayer:cityPlayer
  546.                  cityAtLocation:target
  547.                  playersAdjacentToDefender:adjacentPlayers];
  548. }
  549.  
  550. //----------------------------------------------------------------------
  551.  
  552. - (MoveResult) remoteUnitWithCombatProfile:(CombatProfile)attackerProfile
  553.                              attacksPlayer:(Player)defender
  554.                             unitAtLocation:(EMMapLocation)target
  555.                            withBombardment:(BOOL)bombarding
  556.                  playersAdjacentToDefender:(int)adjacentPlayers
  557. {
  558.     //NSLog (@"master: %@, defender: %d, cityLocation: %d,%d patd: %d", master, defender, target.row, target.column, adjacentPlayers);
  559.  
  560.     return [self unitWithCombatProfile:attackerProfile
  561.                  attacksPlayer:defender
  562.                  unitAtLocation:target
  563.                  withBombardment:bombarding
  564.                  playersAdjacentToDefender:adjacentPlayers];
  565. }
  566.  
  567. //----------------------------------------------------------------------
  568.  
  569. - (CombatProfile) remoteReadyDefendingCityAtLocation:(EMMapLocation)target forPlayer:(Player)number
  570. {
  571.     return [self readyDefendingCityAtLocation:target forPlayer:number];
  572. }
  573.  
  574. //----------------------------------------------------------------------
  575.  
  576. - (CombatProfile) remoteReadyDefendingUnitAtLocation:(EMMapLocation)target
  577.                                            forPlayer:(Player)number
  578.                                   againstBombardment:(BOOL)bombarding
  579. {
  580.     return [self readyDefendingUnitAtLocation:target forPlayer:number againstBombardment:bombarding];
  581. }
  582.  
  583. //----------------------------------------------------------------------
  584.  
  585. - (void) remoteShowExplosions:(int)count forPlayer:(Player)number atLocation:(EMMapLocation)target
  586. {
  587.     [self showExplosions:count forPlayer:number atLocation:target];
  588. }
  589.  
  590. //----------------------------------------------------------------------
  591.  
  592. - (void) remoteHitDefendingUnit:(Player)number withDamage:(int)damage
  593. {
  594.     [self hitDefendingUnit:number withDamage:damage];
  595. }
  596.  
  597. //----------------------------------------------------------------------
  598.  
  599. - (City *) remoteLostDefendingCityOfPlayer:(Player)number
  600. {
  601.     return [self lostDefendingCityOfPlayer:number];
  602. }
  603.  
  604. //----------------------------------------------------------------------
  605.  
  606. - (void) remoteHitAttacker:(Player)number withDamage:(int)damage
  607. {
  608.     [self hitAttacker:number withDamage:damage];
  609. }
  610.  
  611. //----------------------------------------------------------------------
  612.  
  613. - (void) remotePlayer:(Player)number hasCapturedCity:(City *)capturedCity
  614. {
  615.     [self player:number hasCapturedCity:capturedCity];
  616. }
  617.  
  618. //----------------------------------------------------------------------
  619.  
  620. - (void) remoteFinishedCombatForPlayer:(Player)number
  621. {
  622.     [self finishedCombatForPlayer:number];
  623. }
  624.  
  625. //----------------------------------------------------------------------
  626.  
  627. // Client -> Server
  628. - (BOOL) remoteCheckForEndOfPlayer:(Player)number
  629. {
  630.     return [self checkForEndOfPlayer:number];
  631. }
  632.  
  633. //----------------------------------------------------------------------
  634.  
  635. - (BOOL) remoteHasPlayerLost:(Player)number
  636. {
  637.     return [self hasPlayerLost:number];
  638. }
  639.  
  640. //----------------------------------------------------------------------
  641.  
  642. - (void) remotePlayerHasLost:(Player)number activePlayers:(int)activePlayers
  643. {
  644.     [self playerHasLost:number activePlayers:activePlayers];
  645. }
  646.  
  647. //----------------------------------------------------------------------
  648.  
  649. - (BOOL) remotePlayerHasWon:(Player)number activePlayers:(int)activePlayers
  650. {
  651.     return [self playerHasWon:number activePlayers:activePlayers];
  652. }
  653.  
  654. //----------------------------------------------------------------------
  655. // Methods that may communicate with remote game managers:
  656. //----------------------------------------------------------------------
  657.  
  658. //----------------------------------------------------------------------
  659. // Server -> Client...
  660. - (void) gameHasStopped:(Player)number activePlayers:(int)activePlayers
  661. {
  662.     if (playerManagers[number] != nil)
  663.     {
  664.         NS_DURING
  665.             {
  666.                 [playerManagers[number] remoteGameHasStopped:number activePlayers:activePlayers];
  667.             }
  668.         NS_HANDLER
  669.             {
  670.                 EHAND;
  671.             }
  672.         NS_ENDHANDLER;
  673.  
  674.         [self deactivatePlayer:number];
  675.     }
  676.     else
  677.     {
  678.         [super gameHasStopped:number activePlayers:activePlayers];
  679.     }
  680. }    
  681.  
  682. //----------------------------------------------------------------------
  683. // The central game manager maintains the list of neutral cities.
  684. //----------------------------------------------------------------------
  685.  
  686. // Client -> Server
  687. - (City *) randomNeutralCity
  688. {
  689.     City *city = nil;
  690.     
  691.     if (master != nil)
  692.     {
  693.         NS_DURING
  694.             {
  695.                 city = [master remoteRandomNeutralCity];
  696.             }
  697.         NS_HANDLER
  698.             {
  699.                 EHAND;
  700.             }
  701.         NS_ENDHANDLER;
  702.     }
  703.     else
  704.     {
  705.         city = [world randomNeutralCity];
  706.     }
  707.  
  708.     return city;
  709. }
  710.  
  711. //----------------------------------------------------------------------
  712.  
  713. // Client -> Server
  714. - (MoveResult) unitWithCombatProfile:(CombatProfile)attackerProfile
  715.                        attacksPlayer:(Player)cityPlayer
  716.                       cityAtLocation:(EMMapLocation)target
  717.            playersAdjacentToDefender:(int)adjacentPlayers
  718. {
  719.     MoveResult moveResult;
  720.     
  721.     if (master != nil)
  722.     {
  723.         NS_DURING
  724.             {
  725.                 moveResult = [master remoteUnitWithCombatProfile:attackerProfile
  726.                                      attacksPlayer:cityPlayer
  727.                                      cityAtLocation:target
  728.                                      playersAdjacentToDefender:adjacentPlayers];
  729.             }
  730.         NS_HANDLER
  731.             {
  732.                 EHAND;
  733.             }
  734.         NS_ENDHANDLER;
  735.     }
  736.     else
  737.     {
  738.         moveResult = [super unitWithCombatProfile:attackerProfile
  739.                             attacksPlayer:cityPlayer
  740.                             cityAtLocation:target
  741.                             playersAdjacentToDefender:adjacentPlayers];
  742.     }
  743.  
  744.     return moveResult;
  745. }
  746.  
  747. //----------------------------------------------------------------------
  748.  
  749. - (MoveResult) unitWithCombatProfile:(CombatProfile)attackerProfile
  750.                        attacksPlayer:(Player)defender
  751.                       unitAtLocation:(EMMapLocation)target
  752.                      withBombardment:(BOOL)bombarding
  753.            playersAdjacentToDefender:(int)adjacentPlayers
  754. {
  755.     MoveResult moveResult;
  756.     
  757.     if (master != nil)
  758.     {
  759.         NS_DURING
  760.             {
  761.                 moveResult = [master remoteUnitWithCombatProfile:attackerProfile
  762.                                      attacksPlayer:defender
  763.                                      unitAtLocation:target
  764.                                      withBombardment:bombarding
  765.                                      playersAdjacentToDefender:adjacentPlayers];
  766.             }
  767.         NS_HANDLER
  768.             {
  769.                 EHAND;
  770.             }
  771.         NS_ENDHANDLER;
  772.     }
  773.     else
  774.     {
  775.         moveResult = [super unitWithCombatProfile:attackerProfile
  776.                             attacksPlayer:defender
  777.                             unitAtLocation:target
  778.                             withBombardment:bombarding
  779.                             playersAdjacentToDefender:adjacentPlayers];
  780.     }
  781.  
  782.     return moveResult;
  783. }
  784.  
  785. //----------------------------------------------------------------------
  786.  
  787. // Server -> Client
  788. - (CombatProfile) readyDefendingCityAtLocation:(EMMapLocation)target forPlayer:(Player)number
  789. {
  790.     CombatProfile cityProfile;
  791.  
  792.     NSAssert1 (number == p_neutral || playersActive[number] == YES, @"Player %d is not active", number);
  793.     if (playerManagers[number] != nil)
  794.     {
  795.         NS_DURING
  796.             {
  797.                 cityProfile = [playerManagers[number] remoteReadyDefendingCityAtLocation:target forPlayer:number];
  798.             }
  799.         NS_HANDLER
  800.             {
  801.                 EHAND;
  802.             }
  803.         NS_ENDHANDLER;
  804.     }
  805.     else
  806.     {
  807.         cityProfile = [super readyDefendingCityAtLocation:target forPlayer:number];
  808.     }
  809.  
  810.     return cityProfile;
  811. }
  812.  
  813. //----------------------------------------------------------------------
  814.  
  815. // Server -> Client
  816. - (CombatProfile) readyDefendingUnitAtLocation:(EMMapLocation)target forPlayer:(Player)number againstBombardment:(BOOL)bombarding
  817. {
  818.     CombatProfile unitProfile;
  819.  
  820.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  821.     if (playerManagers[number] != nil)
  822.     {
  823.         NS_DURING
  824.             {
  825.                 unitProfile = [playerManagers[number] remoteReadyDefendingUnitAtLocation:target
  826.                                               forPlayer:number
  827.                                               againstBombardment:bombarding];
  828.             }
  829.         NS_HANDLER
  830.             {
  831.                 EHAND;
  832.             }
  833.         NS_ENDHANDLER;
  834.     }
  835.     else
  836.     {
  837.         unitProfile = [super readyDefendingUnitAtLocation:target forPlayer:number againstBombardment:bombarding];
  838.     }
  839.  
  840.     return unitProfile;
  841. }
  842.  
  843. //----------------------------------------------------------------------
  844.  
  845. // Server -> Client
  846. - (void) showExplosions:(int)count forPlayer:(Player)number atLocation:(EMMapLocation)target
  847. {
  848.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  849.     if (playerManagers[number] != nil)
  850.     {
  851.         NS_DURING
  852.             {
  853.                 [playerManagers[number] remoteShowExplosions:count forPlayer:number atLocation:target];
  854.             }
  855.         NS_HANDLER
  856.             {
  857.                 EHAND;
  858.             }
  859.         NS_ENDHANDLER;
  860.     }
  861.     else
  862.     {
  863.         [super showExplosions:count forPlayer:number atLocation:target];
  864.     }
  865. }
  866.  
  867. //----------------------------------------------------------------------
  868.  
  869. // Server -> Client
  870. - (void) hitDefendingUnit:(Player)number withDamage:(int)damage
  871. {
  872.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  873.     if (playerManagers[number] != nil)
  874.     {
  875.         NS_DURING
  876.             {
  877.                 [playerManagers[number] remoteHitDefendingUnit:number withDamage:damage];
  878.             }
  879.         NS_HANDLER
  880.             {
  881.                 EHAND;
  882.             }
  883.         NS_ENDHANDLER;
  884.     }
  885.     else
  886.     {
  887.         [super hitDefendingUnit:number withDamage:damage];
  888.     }
  889. }
  890.  
  891. //----------------------------------------------------------------------
  892.  
  893. // Server -> Client
  894. //- (void) hitDefendingCity:(Player)number withDamage:(int)damage
  895. - (City *) lostDefendingCityOfPlayer:(Player)number
  896. {
  897.     City *city = nil;
  898.     
  899.     NSAssert1 (number == p_neutral || playersActive[number] == YES, @"Player %d is not active", number);
  900.     if (playerManagers[number] != nil)
  901.     {
  902.         NS_DURING
  903.             {
  904.                 city = [playerManagers[number] remoteLostDefendingCityOfPlayer:number];
  905.             }
  906.         NS_HANDLER
  907.             {
  908.                 EHAND;
  909.             }
  910.         NS_ENDHANDLER;
  911.     }
  912.     else
  913.     {
  914.         city = [super lostDefendingCityOfPlayer:number];
  915.     }
  916.  
  917.     return city;
  918. }
  919.  
  920. //----------------------------------------------------------------------
  921.  
  922. // Server -> Client
  923. - (void) hitAttacker:(Player)number withDamage:(int)damage
  924. {
  925.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  926.     if (playerManagers[number] != nil)
  927.     {
  928.         NS_DURING
  929.             {
  930.                 [playerManagers[number] remoteHitAttacker:number withDamage:damage];
  931.             }
  932.         NS_HANDLER
  933.             {
  934.                 EHAND;
  935.             }
  936.         NS_ENDHANDLER;
  937.     }
  938.     else
  939.     {
  940.         [super hitAttacker:number withDamage:damage];
  941.     }
  942. }
  943.  
  944. //----------------------------------------------------------------------
  945.  
  946. // Server -> Client
  947. - (void) player:(Player)number hasCapturedCity:(City *)capturedCity
  948. {
  949.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  950.     if (playerManagers[number] != nil)
  951.     {
  952.         NS_DURING
  953.             {
  954.                 [playerManagers[number] remotePlayer:number hasCapturedCity:capturedCity];
  955.             }
  956.         NS_HANDLER
  957.             {
  958.                 EHAND;
  959.             }
  960.         NS_ENDHANDLER;
  961.     }
  962.     else
  963.     {
  964.         [super player:number hasCapturedCity:capturedCity];
  965.     }
  966. }
  967.  
  968. //----------------------------------------------------------------------
  969.  
  970. // Server -> Client
  971. - (void) finishedCombatForPlayer:(Player)number
  972. {
  973.     NSAssert1 (number == p_neutral || playersActive[number] == YES, @"Player %d is not active", number);
  974.     if (playerManagers[number] != nil)
  975.     {
  976.         NS_DURING
  977.             {
  978.                 [playerManagers[number] remoteFinishedCombatForPlayer:number];
  979.             }
  980.         NS_HANDLER
  981.             {
  982.                 EHAND;
  983.             }
  984.         NS_ENDHANDLER;
  985.     }
  986.     else
  987.     {
  988.         [super finishedCombatForPlayer:number];
  989.     }
  990. }
  991.  
  992. //----------------------------------------------------------------------
  993.  
  994. // Client -> Server
  995. - (BOOL) checkForEndOfPlayer:(Player)number
  996. {
  997.     BOOL result;
  998.  
  999.     if (master != nil)
  1000.     {
  1001.         NS_DURING
  1002.             {
  1003.                 result = [master remoteCheckForEndOfPlayer:number];
  1004.             }
  1005.         NS_HANDLER
  1006.             {
  1007.                 EHAND;
  1008.             }
  1009.         NS_ENDHANDLER;
  1010.     }
  1011.     else
  1012.     {
  1013.         NSAssert1 (number == p_neutral || playersActive[number] == YES, @"Player %d is not active", number);
  1014.         result = [super checkForEndOfPlayer:number];
  1015.     }
  1016.  
  1017.     //[self logStatus];
  1018.  
  1019.     return result;
  1020. }
  1021.  
  1022. //----------------------------------------------------------------------
  1023.  
  1024. // Server -> Client
  1025. - (BOOL) hasPlayerLost:(Player)number
  1026. {
  1027.     BOOL result;
  1028.     
  1029.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  1030.     if (playerManagers[number] != nil)
  1031.     {
  1032.         NS_DURING
  1033.             {
  1034.                 result = [playerManagers[number] remoteHasPlayerLost:number];
  1035.             }
  1036.         NS_HANDLER
  1037.             {
  1038.                 EHAND;
  1039.             }
  1040.         NS_ENDHANDLER;
  1041.     }
  1042.     else
  1043.     {
  1044.         result = [super hasPlayerLost:number];
  1045.     }
  1046.  
  1047.     return result;
  1048. }
  1049.  
  1050. //----------------------------------------------------------------------
  1051.  
  1052. // Server -> Client
  1053. - (void) playerHasLost:(Player)number activePlayers:(int)activePlayers
  1054. {
  1055.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  1056.  
  1057.     if (playerManagers[number] != nil)
  1058.     {
  1059.         NS_DURING
  1060.             {
  1061.                 [playerManagers[number] remotePlayerHasLost:number activePlayers:activePlayers];
  1062.             }
  1063.         NS_HANDLER
  1064.             {
  1065.                 EHAND;
  1066.             }
  1067.         NS_ENDHANDLER;
  1068.  
  1069.         [self deactivatePlayer:number]; //?
  1070.     }
  1071.     else
  1072.     {
  1073.         //NSAssert (gameState == gs_client_active, @"Expected to be in client active state.");
  1074.         
  1075.         [super playerHasLost:number activePlayers:activePlayers];
  1076.     }
  1077. }
  1078.  
  1079. //----------------------------------------------------------------------
  1080.  
  1081. // Server -> Client
  1082. - (BOOL) playerHasWon:(Player)number activePlayers:(int)activePlayers
  1083. {
  1084.     BOOL keepPlaying;
  1085.  
  1086.     NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  1087.  
  1088.     if (playerManagers[number] != nil)
  1089.     {
  1090.         NS_DURING
  1091.             {
  1092.                 keepPlaying = [playerManagers[number] remotePlayerHasWon:number activePlayers:activePlayers];
  1093.             }
  1094.         NS_HANDLER
  1095.             {
  1096.                 EHAND;
  1097.             }
  1098.         NS_ENDHANDLER;
  1099.  
  1100.         if (keepPlaying == NO)
  1101.         {
  1102.             [self deactivatePlayer:number];
  1103.         }
  1104.     }
  1105.     else
  1106.     {
  1107.         // Only if master != nil...
  1108.         //NSAssert (gameState == gs_client_active, @"Expected to be in client active state."); 
  1109.         
  1110.         keepPlaying = [super playerHasWon:number activePlayers:activePlayers];
  1111.     }
  1112.  
  1113.     //[self logStatus];
  1114.  
  1115.     return keepPlaying;
  1116. }
  1117.  
  1118. //======================================================================
  1119.  
  1120. // Get's our cached version.
  1121. - (Map *) mapForPlayer:(Player)number
  1122. {
  1123.     Map *map = nil;
  1124.     
  1125.     //NSLog (@"player %d active? %@", playersActive[number] == YES ? @"Yes" : @"No");
  1126.  
  1127.     if (master == nil)
  1128.     {
  1129.         map = playersActive[number] == YES ? cachedMaps[number] : nil;
  1130.     }
  1131.     else
  1132.     {
  1133.         map = cachedMaps[number];
  1134.     }
  1135.  
  1136.     //NSLog (@"DGM - mapForPlayer:%d is %@", number, map);
  1137.  
  1138.     return map;
  1139. }
  1140.  
  1141. //----------------------------------------------------------------------
  1142.  
  1143. // Get's the original, current version from player.
  1144. // Client -> Server -> Client
  1145. - (Map *) fetchMapForPlayer:(Player)number
  1146. {
  1147.     Map *map = nil;
  1148.     
  1149.     //NSLog (@"DGM-Player: %d", number);
  1150.  
  1151.     if (players[number] != nil)
  1152.     {
  1153.         //NSLog (@"Calling super.");
  1154.         //NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number); // only server knows...
  1155.         map = [super mapForPlayer:number];
  1156.     }
  1157.     else if (playerManagers[number] != nil && playersActive[number] == YES)
  1158.     {
  1159.         //NSLog (@"Server -> Client");
  1160.         //NSLog (@"player %d active? %@", number, playersActive[number] ? @"Yes" : @"No");
  1161.         //NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number); // only server knows...
  1162.         NS_DURING
  1163.             {
  1164.                 map = [playerManagers[number] remoteFetchMapForPlayer:number];
  1165.             }
  1166.         NS_HANDLER
  1167.             {
  1168.                 EHAND;
  1169.             }
  1170.         NS_ENDHANDLER;
  1171.     }
  1172.     else if (master != nil)
  1173.     {
  1174.         //NSLog (@"Client -> Server");
  1175.         NS_DURING
  1176.             {
  1177.                 map = [master remoteFetchMapForPlayer:number];
  1178.             }
  1179.         NS_HANDLER
  1180.             {
  1181.                 EHAND;
  1182.             }
  1183.         NS_ENDHANDLER;
  1184.     }
  1185. #if 0
  1186.     else
  1187.     {
  1188.         // playerManagers[number] != nil, playersActive[number] == NO, cachedMaps[number]...
  1189.         map = cachedMaps[number];
  1190.         //NSLog (@"Returning final map for player %d: %@", number, map);
  1191.     }
  1192. #endif
  1193.     return map;
  1194. }
  1195.  
  1196. //----------------------------------------------------------------------
  1197. // Client -> Server -> Client?
  1198. - (void) set3x3Tokens:(MapToken *)tokens aroundLocation:(EMMapLocation)target forPlayer:(Player)number
  1199. {
  1200.     struct NineTokens nineTokens;
  1201.     int l;
  1202.     
  1203.     //NSLog (@"target: %d,%d, player: %d", target.row, target.column, number);
  1204.  
  1205.     // Modify our local map
  1206.     [super set3x3Tokens:tokens aroundLocation:target forPlayer:number];
  1207.  
  1208.     if (players[number] == nil)
  1209.     {
  1210.         if (master != nil)
  1211.         {
  1212.             for (l = 0; l < 9; l++)
  1213.                 nineTokens.tokens[l] = tokens[l];
  1214.  
  1215.             NS_DURING
  1216.                 {
  1217.                     [master remoteSet3x3Tokens:nineTokens aroundLocation:target forPlayer:number];
  1218.                 }
  1219.             NS_HANDLER
  1220.                 {
  1221.                     EHAND;
  1222.                 }
  1223.             NS_ENDHANDLER;
  1224.         }
  1225.         else if (playerManagers[number] != nil)
  1226.         {
  1227.             NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  1228.             for (l = 0; l < 9; l++)
  1229.                 nineTokens.tokens[l] = tokens[l];
  1230.  
  1231.             NS_DURING
  1232.                 {
  1233.                     [playerManagers[number] remoteSet3x3Tokens:nineTokens aroundLocation:target forPlayer:number];
  1234.                 }
  1235.             NS_HANDLER
  1236.                 {
  1237.                     EHAND;
  1238.                 }
  1239.             NS_ENDHANDLER;
  1240.         }
  1241.     }
  1242. }
  1243.  
  1244. //----------------------------------------------------------------------
  1245.  
  1246. // setToken: works differently from set3x3Tokens... It doens't set the local
  1247. // map, since we're cheating and taking the updated token from the local map...
  1248.  
  1249. - (void) setToken:(MapToken)token atLocation:(EMMapLocation)target forPlayer:(Player)number
  1250. {
  1251.     //NSLog (@"(%d,%d): %@", target.row, target.column, EMFormatComponents (token));
  1252.  
  1253.     if (players[number] == nil)
  1254.     {
  1255.         //NSLog (@"players[%d] not nil", number);
  1256.         
  1257.         if (master != nil)
  1258.         {
  1259.             //NSLog (@"master not nil");
  1260.             NS_DURING
  1261.                 {
  1262.                     [master remoteSetToken:token atLocation:target forPlayer:number];
  1263.                 }
  1264.             NS_HANDLER
  1265.                 {
  1266.                     EHAND;
  1267.                 }
  1268.             NS_ENDHANDLER;
  1269.         }
  1270.         else if (playerManagers[number] != nil && playersActive[number] == YES)
  1271.         {
  1272.             NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  1273.             //NSLog (@"playerManagers[%d] not nil", number);
  1274.             NS_DURING
  1275.                 {
  1276.                     [playerManagers[number] remoteSetToken:token atLocation:target forPlayer:number];
  1277.                 }
  1278.             NS_HANDLER
  1279.                 {
  1280.                     EHAND;
  1281.                 }
  1282.             NS_ENDHANDLER;
  1283.         }
  1284.     }
  1285.     else
  1286.     {
  1287.         NSAssert1 (playersActive[number] == YES, @"Player %d is not active", number);
  1288.         [[players[number] map] setToken:token atLocation:target];
  1289.     }
  1290. }
  1291.  
  1292. //----------------------------------------------------------------------
  1293.  
  1294. - (void) remove:(Icon)icon atLocation:(EMMapLocation)target forPlayer:(Player)number
  1295. {
  1296.     [super remove:icon atLocation:target forPlayer:number];
  1297.     [self setToken:[[self mapForPlayer:number] tokenAtLocation:target] atLocation:target forPlayer:number];
  1298. }
  1299.  
  1300. //----------------------------------------------------------------------
  1301.  
  1302. - (void) put:(Icon)icon atLocation:(EMMapLocation)target forPlayer:(Player)number
  1303. {
  1304.     [super put:icon atLocation:target forPlayer:number];
  1305.     [self setToken:[[self mapForPlayer:number] tokenAtLocation:target] atLocation:target forPlayer:number];
  1306. }
  1307.  
  1308. //----------------------------------------------------------------------
  1309.  
  1310. - (void) setCityAtLocation:(EMMapLocation)target toPlayer:(Player)newCityPlayer forPlayer:(Player)number
  1311. {
  1312.     //NSLog (@"target: (%d,%d), toPlayer: %d, forPlayer: %d", target.row, target.column, newCityPlayer, number);
  1313.     [super setCityAtLocation:target toPlayer:newCityPlayer forPlayer:number];
  1314.     [self setToken:[[self mapForPlayer:number] tokenAtLocation:target] atLocation:target forPlayer:number];
  1315. }
  1316.  
  1317. //======================================================================
  1318. //======================================================================
  1319.  
  1320. - (void) remoteUpdateMapAroundCitiesForPlayer:(Player)number
  1321. {
  1322.     [self updateMapAroundCitiesForPlayer:number];
  1323. }
  1324.  
  1325. //----------------------------------------------------------------------
  1326.  
  1327. // Server -> Client
  1328. - (void) updateMapAroundCitiesForPlayer:(Player)number
  1329. {
  1330.     //NSLog (@"Player %d active? %@", number, playersActive[number] ? @"Yes" : @"No");
  1331.  
  1332.     if (players[number] != nil)
  1333.     {
  1334.         [players[number] updateMapAroundCities];
  1335.     }
  1336.     else if (playerManagers[number] != nil)
  1337.     {
  1338.         NS_DURING
  1339.             {
  1340.                 [playerManagers[number] remoteUpdateMapAroundCitiesForPlayer:number];
  1341.             }
  1342.         NS_HANDLER
  1343.             {
  1344.                 EHAND;
  1345.             }
  1346.         NS_ENDHANDLER;
  1347.     }
  1348. }
  1349.  
  1350. //----------------------------------------------------------------------
  1351.  
  1352. - (void) connectionDidDie:(NSNotification *)notification
  1353. {
  1354.     id object = [notification object];
  1355.     Player p;
  1356.     
  1357.     //NSLog (@"notification: %@", notification);
  1358.  
  1359.     //[self logStatus];
  1360.  
  1361.     NSLog (@"master connection: %@", masterConnection);
  1362.     for (p = p_player1; p <= p_player3; p++)
  1363.         NSLog (@"clientConnections[%d]: %@", p, clientConnections[p]);
  1364.     
  1365.     if (object == nil)
  1366.     {
  1367.     }
  1368.     else if (object == masterConnection)
  1369.     {
  1370.         NSRunAlertPanel (@"Game Interrupted", @"The connection to the server was lost.", nil, nil, nil);
  1371.     }
  1372.     else
  1373.     {
  1374.         for (p = p_player1; p <= p_player3; p++)
  1375.         {
  1376.             if (object == clientConnections[p])
  1377.             {
  1378.                 NSRunAlertPanel (@"Game Interrupted", @"The connection to client %d was lost.", nil, nil, nil, p);
  1379.             }
  1380.         }
  1381.     }
  1382. }
  1383.  
  1384. //----------------------------------------------------------------------
  1385.  
  1386. - (void) remoteResignPlayerFromGame:(Player)number
  1387. {
  1388.     [self resignPlayerFromGame:number];
  1389. }
  1390.  
  1391. //----------------------------------------------------------------------
  1392.  
  1393. // Client -> Server
  1394. - (void) resignPlayerFromGame:(Player)number
  1395. {
  1396.     if (master != nil)
  1397.     {
  1398.         NS_DURING
  1399.             {
  1400.                 [master remoteResignPlayerFromGame:number];
  1401.             }
  1402.         NS_HANDLER
  1403.             {
  1404.                 EHAND;
  1405.             }
  1406.         NS_ENDHANDLER;
  1407.  
  1408.         [self deactivatePlayer:number];
  1409.     }
  1410.     else
  1411.     {
  1412.         [super resignPlayerFromGame:number];
  1413.     }
  1414. }
  1415.  
  1416. //----------------------------------------------------------------------
  1417.  
  1418. - (NSArray *) remoteRemainingCitiesForPlayer:(Player)number
  1419. {
  1420.     return [self remainingCitiesForPlayer:number];
  1421. }
  1422.  
  1423. //----------------------------------------------------------------------
  1424.  
  1425. // Server -> Client
  1426. - (NSArray *) remainingCitiesForPlayer:(Player)number
  1427. {
  1428.     NSArray *remainingCities = nil;
  1429.  
  1430.     if (playerManagers[number] != nil)
  1431.     {
  1432.         NS_DURING
  1433.             {
  1434.                 remainingCities = [playerManagers[number] remoteRemainingCitiesForPlayer:number];
  1435.             }
  1436.         NS_HANDLER
  1437.             {
  1438.                 EHAND;
  1439.             }
  1440.         NS_ENDHANDLER;
  1441.     }
  1442.     else
  1443.     {
  1444.         remainingCities = [super remainingCitiesForPlayer:number];
  1445.     }
  1446.  
  1447.     return remainingCities;
  1448. }
  1449.  
  1450. //----------------------------------------------------------------------
  1451. // Frees up either client or server game manager for another game...
  1452. //----------------------------------------------------------------------
  1453.  
  1454. - (void) stopGame
  1455. {
  1456.     [super stopGame];
  1457.  
  1458.     //[self logStatus];
  1459. }
  1460.  
  1461. //----------------------------------------------------------------------
  1462.  
  1463. - (void) deactivatePlayer:(Player)number
  1464. {
  1465.     [super deactivatePlayer:number];
  1466.  
  1467.     SNRelease (playerManagers[number]);
  1468.     SNRelease (cachedMaps[number]);
  1469.  
  1470.     if (clientConnections[number] != nil)
  1471.     {
  1472.         [[NSNotificationCenter defaultCenter] removeObserver:self
  1473.                                               name:nil
  1474.                                               object:clientConnections[number]];
  1475.         clientConnections[number] = nil;
  1476.     }
  1477.  
  1478.     // Maybe this should be the thing to terminate when activePlayerCount == 0?
  1479.     //NSLog (@"active player count: %d", activePlayerCount);
  1480. }
  1481.  
  1482. //----------------------------------------------------------------------
  1483.  
  1484. - (void) remotePlayerHasResigned:(Player)number activePlayers:(int)activePlayers
  1485. {
  1486.     [self playerHasResigned:number activePlayers:activePlayers];
  1487. }
  1488.  
  1489. //----------------------------------------------------------------------
  1490.  
  1491. // Server -> Client
  1492. - (void) playerHasResigned:(Player)number activePlayers:(int)activePlayers
  1493. {
  1494.     NSAssert1 (number == p_neutral || playersActive[number] == YES, @"Player %d is not active", number);
  1495.  
  1496.     if (playerManagers[number] != nil)
  1497.     {
  1498.         NS_DURING
  1499.             {
  1500.                 [playerManagers[number] remotePlayerHasResigned:number activePlayers:activePlayers];
  1501.             }
  1502.         NS_HANDLER
  1503.             {
  1504.                 EHAND;
  1505.             }
  1506.         NS_ENDHANDLER;
  1507.     }
  1508.     else
  1509.     {
  1510.         [super playerHasResigned:number activePlayers:activePlayers];
  1511.     }
  1512.  
  1513.     //[self logStatus];
  1514. }
  1515.  
  1516. //----------------------------------------------------------------------
  1517.  
  1518. - (Map *) remoteFinalMapForPlayer:(Player)number
  1519. {
  1520.     return [self finalMapForPlayer:number];
  1521. }
  1522.  
  1523. //----------------------------------------------------------------------
  1524.  
  1525. // Client -> Server
  1526. - (Map *) finalMapForPlayer:(Player)number
  1527. {
  1528.     Map *map;
  1529.  
  1530.     //NSLog (@"DGM-player: %d", number);
  1531.  
  1532.     if (master != nil)
  1533.     {
  1534.         NS_DURING
  1535.             {
  1536.                 map = [master remoteFinalMapForPlayer:number];
  1537.             }
  1538.         NS_HANDLER
  1539.             {
  1540.                 EHAND;
  1541.             }
  1542.         NS_ENDHANDLER;
  1543.     }
  1544.     else
  1545.     {
  1546.         map = [super finalMapForPlayer:number];
  1547.     }
  1548.  
  1549.     return map;
  1550. }
  1551.  
  1552. //----------------------------------------------------------------------
  1553.  
  1554. - (void) remoteNotifyPlayer:(Player)number aPlayerHasResigned:(Player)resignedPlayer
  1555. {
  1556.     [self notifyPlayer:number aPlayerHasResigned:resignedPlayer];
  1557. }
  1558.  
  1559. //----------------------------------------------------------------------
  1560.  
  1561. // Server -> Client
  1562. - (void) notifyPlayer:(Player)number aPlayerHasResigned:(Player)resignedPlayer
  1563. {
  1564.     if (playerManagers[number] != nil)
  1565.     {
  1566.         NS_DURING
  1567.             {
  1568.                 [playerManagers[number] remoteNotifyPlayer:number aPlayerHasResigned:resignedPlayer];
  1569.             }
  1570.         NS_HANDLER
  1571.             {
  1572.                 EHAND;
  1573.             }
  1574.         NS_ENDHANDLER;
  1575.     }
  1576.     else
  1577.     {
  1578.         [super notifyPlayer:number aPlayerHasResigned:resignedPlayer];
  1579.     }
  1580. }
  1581.  
  1582. //----------------------------------------------------------------------
  1583.  
  1584. - (void) serverGameOver
  1585. {
  1586.     Player p;
  1587.  
  1588.     NSAssert (gameState == gs_player1_turn
  1589.               || gameState == gs_player2_turn
  1590.               || gameState == gs_player3_turn, @"Expected to be in a player turn state.");
  1591.     NSAssert (activePlayerCount == 0, @"Expected no active players.");
  1592.  
  1593.     SNRelease (awaitingCookie);
  1594.  
  1595.     attackingUnit = nil;
  1596.     defendingUnit = nil;
  1597.     defendingCity = nil;
  1598.  
  1599.     for (p = p_player1; p <= p_player3; p++)
  1600.     {
  1601.         SNRelease (cachedMaps[p]);
  1602.     }
  1603.  
  1604.     [self setGameState:gs_game_over];
  1605. }
  1606.  
  1607. //----------------------------------------------------------------------
  1608.  
  1609. - (void) clientGameOver
  1610. {
  1611.     Player p;
  1612.  
  1613.     AssertGameState (gs_client_active);
  1614.     NSAssert (activePlayerCount == 0, @"Expected no active players.");
  1615.     NSAssert (awaitingCookie == nil, @"Expected awaiting cookie to be nil.");
  1616.     NSAssert (master != nil, @"Expected master game manager to be set.");
  1617.     NSAssert (masterConnection != nil, @"Expected master game manager connection to be set.");
  1618.  
  1619.     [[NSNotificationCenter defaultCenter] removeObserver:self
  1620.                                           name:nil
  1621.                                           object:masterConnection];
  1622.     SNRelease (master);
  1623.     masterConnection = nil;
  1624.  
  1625.     attackingUnit = nil;
  1626.     defendingUnit = nil;
  1627.     defendingCity = nil;
  1628.  
  1629.     for (p = p_player1; p <= p_player3; p++)
  1630.     {
  1631.         SNRelease (cachedMaps[p]);
  1632.     }
  1633.  
  1634.     [self setGameState:gs_game_over];
  1635. }
  1636.  
  1637. //----------------------------------------------------------------------
  1638.  
  1639. - (void) theGameIsOver
  1640. {
  1641.     NSAssert (gameState == gs_client_active
  1642.               || gameState == gs_player1_turn
  1643.               || gameState == gs_player2_turn
  1644.               || gameState == gs_player3_turn, @"Invalid game state.");
  1645.  
  1646.     [super theGameIsOver];
  1647.  
  1648.     if (gameState == gs_client_active)
  1649.     {
  1650.         [self clientGameOver];
  1651.     }
  1652.     else
  1653.     {
  1654.         [self serverGameOver];
  1655.     }
  1656.     
  1657.     // The game manager sticks around until the last player releases it.  Then, *poof*.
  1658. }
  1659.  
  1660. //----------------------------------------------------------------------
  1661.  
  1662. - (void) logStatus
  1663. {
  1664.     NSLog (@"----------------------------------------");
  1665.     NSLog (@"Players active:     %@ %@ %@",
  1666.            playersActive[p_player1] == YES ? @"Yes" : @"No ",
  1667.            playersActive[p_player2] == YES ? @"Yes" : @"No ",
  1668.            playersActive[p_player3] == YES ? @"Yes" : @"No "
  1669.            );
  1670.     NSLog (@"Players:            %@ %@ %@",
  1671.            players[p_player1] == nil ? @"nil" : @"set",
  1672.            players[p_player2] == nil ? @"nil" : @"set",
  1673.            players[p_player3] == nil ? @"nil" : @"set"
  1674.            );
  1675.     NSLog (@"Player managers:    %@ %@ %@",
  1676.            playerManagers[p_player1] == nil ? @"nil" : @"set",
  1677.            playerManagers[p_player2] == nil ? @"nil" : @"set",
  1678.            playerManagers[p_player3] == nil ? @"nil" : @"set"
  1679.            );
  1680.     NSLog (@"Cached maps:        %@ %@ %@",
  1681.            cachedMaps[p_player1] == nil ? @"nil" : @"set",
  1682.            cachedMaps[p_player2] == nil ? @"nil" : @"set",
  1683.            cachedMaps[p_player3] == nil ? @"nil" : @"set"
  1684.            );
  1685.     NSLog (@"Final maps:         %@ %@ %@",
  1686.            finalMaps[p_player1] == nil ? @"nil" : @"set",
  1687.            finalMaps[p_player2] == nil ? @"nil" : @"set",
  1688.            finalMaps[p_player3] == nil ? @"nil" : @"set"
  1689.            );
  1690.     NSLog (@"active player count: %d", activePlayerCount);
  1691.     NSLog (@"awaiting cookie: %@", awaitingCookie);
  1692.     NSLog (@"attacking unit: %@", attackingUnit);
  1693.     NSLog (@"defending unit: %@", defendingUnit);
  1694.     NSLog (@"defending city: %@", defendingCity);
  1695.     NSLog (@"master: %@", master == nil ? @"nil" : @"set");
  1696.     NSLog (@"master connection: %@", masterConnection == nil ? @"nil" : @"set");
  1697.     NSLog (@"Client connections: %@ %@ %@",
  1698.            clientConnections[p_player1] == nil ? @"nil" : @"set",
  1699.            clientConnections[p_player2] == nil ? @"nil" : @"set",
  1700.            clientConnections[p_player3] == nil ? @"nil" : @"set"
  1701.            );
  1702.     NSLog (@"----------------------------------------");
  1703. }
  1704.  
  1705. @end
  1706.  
  1707. // Note: Client game manager ends up with a retain count of 1 when everything has
  1708. //       been resigned and closed.  Does the extra retain have anything to do with
  1709. //       the connection not being invalidated/released?
  1710.  
  1711. // Hmm. Third remote player's game manager is released when the server is quit.
  1712.