diff --git a/src/java/com/threerings/parlor/game/GameConfig.java b/src/java/com/threerings/parlor/game/GameConfig.java index fe236fdaf..8ed41911b 100644 --- a/src/java/com/threerings/parlor/game/GameConfig.java +++ b/src/java/com/threerings/parlor/game/GameConfig.java @@ -1,5 +1,5 @@ // -// $Id: GameConfig.java,v 1.11 2002/07/25 23:20:22 mdb Exp $ +// $Id: GameConfig.java,v 1.12 2002/09/06 22:52:27 shaper Exp $ package com.threerings.parlor.game; @@ -36,6 +36,15 @@ public abstract class GameConfig extends PlaceConfig */ public abstract Class getConfiguratorClass (); + /** + * Returns whether this game is a party game. The default + * implementation returns false. + */ + public boolean isPartyGame () + { + return false; + } + /** * Returns true if this game config object is equal to the supplied * object (meaning it is also a game config object and its diff --git a/src/java/com/threerings/parlor/game/GameDispatcher.java b/src/java/com/threerings/parlor/game/GameDispatcher.java index bbc3c8fb1..3ccd8a282 100644 --- a/src/java/com/threerings/parlor/game/GameDispatcher.java +++ b/src/java/com/threerings/parlor/game/GameDispatcher.java @@ -1,5 +1,5 @@ // -// $Id: GameDispatcher.java,v 1.2 2002/08/20 19:38:14 mdb Exp $ +// $Id: GameDispatcher.java,v 1.3 2002/09/06 22:52:27 shaper Exp $ package com.threerings.parlor.game; @@ -13,10 +13,6 @@ import com.threerings.presents.server.InvocationException; /** * Dispatches requests to the {@link GameProvider}. - * - *
Generated from
- * $Id: GameDispatcher.java,v 1.2 2002/08/20 19:38:14 mdb Exp $
- *
*/
public class GameDispatcher extends InvocationDispatcher
{
@@ -48,8 +44,17 @@ public class GameDispatcher extends InvocationDispatcher
);
return;
+ case GameMarshaller.START_PARTY_GAME:
+ ((GameProvider)provider).startPartyGame(
+ source
+
+ );
+ return;
+
default:
super.dispatchRequest(source, methodId, args);
}
}
+
+ // Generated on 12:49:14 09/06/02.
}
diff --git a/src/java/com/threerings/parlor/game/GameManager.java b/src/java/com/threerings/parlor/game/GameManager.java
index 4f83b30cb..5d8fe869b 100644
--- a/src/java/com/threerings/parlor/game/GameManager.java
+++ b/src/java/com/threerings/parlor/game/GameManager.java
@@ -1,5 +1,5 @@
//
-// $Id: GameManager.java,v 1.39 2002/08/21 05:22:41 mdb Exp $
+// $Id: GameManager.java,v 1.40 2002/09/06 22:52:27 shaper Exp $
package com.threerings.parlor.game;
@@ -7,6 +7,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
+import com.samskivert.util.ArrayUtil;
+import com.samskivert.util.ListUtil;
+
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.presents.dobj.AttributeChangedEvent;
@@ -38,10 +41,125 @@ import com.threerings.parlor.server.ParlorSender;
public class GameManager extends PlaceManager
implements ParlorCodes, GameProvider, AttributeChangeListener
{
+ // documentation inherited
+ protected void didInit ()
+ {
+ super.didInit();
+
+ // save off a casted reference to our config
+ _gameconfig = (GameConfig)_config;
+ }
+
+ /**
+ * Adds the given player to the game. This should only be called
+ * before the game is started, and is most likely to be used to add
+ * players to party games.
+ *
+ * @param player the username of the player to add to this game.
+ */
+ public void addPlayer (String player)
+ {
+ // append the player to the player list
+ int pcount = _players.length;
+ int npcount = pcount + 1;
+ String[] nplayers = new String[npcount];
+ System.arraycopy(_players, 0, nplayers, 0, pcount);
+ nplayers[pcount] = player;
+ _players = nplayers;
+
+ // expand the player oids list
+ int[] nplayerOids = new int[npcount];
+ System.arraycopy(_playerOids, 0, nplayerOids, 0, pcount);
+ _playerOids = nplayerOids;
+
+ if (_AIs != null) {
+ // expand the AI list
+ byte[] nAIs = new byte[npcount];
+ System.arraycopy(_AIs, 0, nAIs, 0, pcount);
+ _AIs = nAIs;
+ }
+
+ // set the new players list in the game object
+ _gameobj.setPlayers(_players);
+
+ // deliver a game ready notification to the player
+ BodyObject bobj = CrowdServer.lookupBody(player);
+ ParlorSender.gameIsReady(bobj, _gameobj.getOid());
+
+ // let derived classes do what they like
+ playerWasAdded(player, pcount);
+ }
+
+ /**
+ * Called when a player was added to the game. Derived classes may
+ * override this method to perform any game-specific actions they
+ * desire, but should be sure to call
+ * super.playerWasAdded().
+ *
+ * @param player the username of the player added to the game.
+ * @param pidx the player index of the player added to the game.
+ */
+ protected void playerWasAdded (String player, int pidx)
+ {
+ }
+
+ /**
+ * Removes the given player from the game. This is most likely to be
+ * used to allow players involved in a party game to leave the game
+ * early-on if they realize they'd rather not play for some reason.
+ *
+ * @param player the username of the player to remove from this game.
+ */
+ public void removePlayer (String player)
+ {
+ // get the player's index in the player list
+ int pidx = ListUtil.indexOfEqual(_players, player);
+ if (pidx == -1) {
+ Log.warning("Attempt to remove non-player from players list " +
+ "[gameOid=" + _gameobj.getOid() +
+ ", player=" + player + "].");
+ return;
+ }
+
+ // remove the player from the players list
+ _players = ArrayUtil.splice(_players, pidx, 1);
+
+ // remove the player slot from the player oid list
+ _playerOids = ArrayUtil.splice(_playerOids, pidx, 1);
+
+ if (_AIs != null) {
+ // remove the player slot from the AI list
+ _AIs = ArrayUtil.splice(_AIs, pidx, 1);
+ }
+
+ // set the new players list in the game object
+ _gameobj.setPlayers(_players);
+
+ // let derived classes do what they like
+ playerWasRemoved(player, pidx);
+ }
+
+ /**
+ * Called when a player was removed from the game. Derived classes
+ * may override this method to perform any game-specific actions they
+ * desire, but should be sure to call
+ * super.playerWasRemoved().
+ *
+ * @param player the username of the player removed from the game.
+ * @param pidx the player index of the player before they were removed
+ * from the game.
+ */
+ protected void playerWasRemoved (String player, int pidx)
+ {
+ }
+
/**
* Provides the game manager with a list of the usernames of all
- * players in the game. This happens before startup and before the
- * game object has been created.
+ * players in the game. This happens before startup and before the
+ * game object has been created. Note that party games may
+ * subsequently add or remove players via {@link #addPlayer} and
+ * {@link #removePlayer}, and so should be sure to handle a changing
+ * player list gracefully.
*
* @param players the usernames of all of the players in this game or
* a zero-length array if the game has no specific set of players.
@@ -192,13 +310,14 @@ public class GameManager extends PlaceManager
// we have a specific set of players)
if (_players != null) {
int gameOid = _gameobj.getOid();
- for (int i = 0; i < _players.length; i++) {
- BodyObject bobj = CrowdServer.lookupBody(_players[i]);
+ int pcount = _players.length;
+ for (int ii = 0; ii < pcount; ii++) {
+ BodyObject bobj = CrowdServer.lookupBody(_players[ii]);
if (bobj == null) {
Log.warning("Unable to deliver game ready to " +
"non-existent player " +
"[gameOid=" + gameOid +
- ", player=" + _players[i] + "].");
+ ", player=" + _players[ii] + "].");
continue;
}
@@ -242,8 +361,10 @@ public class GameManager extends PlaceManager
*/
protected void playersAllHere ()
{
- // start up the game (if we haven't already)
- if (_gameobj.state == GameObject.AWAITING_PLAYERS) {
+ // start up the game if we're not a party game and if we haven't
+ // already done so
+ if (!_gameconfig.isPartyGame() &&
+ _gameobj.state == GameObject.AWAITING_PLAYERS) {
startGame();
}
}
@@ -308,7 +429,7 @@ public class GameManager extends PlaceManager
* Called after the game start notification was dispatched. Derived
* classes can override this to put whatever wheels they might need
* into motion now that the game is started (if anything other than
- * transitioning the game to IN_PLAY is necessary).
+ * transitioning the game to {@link GameObject#IN_PLAY} is necessary).
*/
protected void gameDidStart ()
{
@@ -335,11 +456,12 @@ public class GameManager extends PlaceManager
}
/**
- * Called by the AIGameTicker if we're registered as an AI game.
+ * Called by the {@link AIGameTicker} if we're registered as an AI
+ * game.
*/
protected void tickAIs ()
{
- for (int ii=0; ii < _AIs.length; ii++) {
+ for (int ii = 0; ii < _AIs.length; ii++) {
byte level = _AIs[ii];
if (level != -1) {
tickAI(ii, level);
@@ -359,7 +481,7 @@ public class GameManager extends PlaceManager
/**
* Called when the game is known to be over. This will call some
* calldown functions to determine the winner of the game and then
- * transition the game to the GAME_OVER state.
+ * transition the game to the {@link GameObject#GAME_OVER} state.
*/
public void endGame ()
{
@@ -375,13 +497,13 @@ public class GameManager extends PlaceManager
}
/**
- * Called after the game has transitioned to the
- * GAME_OVER state. Derived classes should override this
+ * Called after the game has transitioned to the {@link
+ * GameObject#GAME_OVER} state. Derived classes should override this
* to perform any post-game activities.
*/
protected void gameDidEnd ()
{
- // remove ourselves from the AIticker, if applicable
+ // remove ourselves from the AI ticker, if applicable
if (_AIs != null) {
AIGameTicker.unregisterAIGame(this);
}
@@ -489,6 +611,49 @@ public class GameManager extends PlaceManager
return true;
}
+ // documentation inherited from interface
+ public void startPartyGame (ClientObject caller)
+ {
+ // make sure this is a party game
+ if (!_gameconfig.isPartyGame()) {
+ Log.warning("Attempt to player-start a non-party game " +
+ "[gameOid=" + _gameobj.getOid() +
+ ", caller=" + caller + "].");
+ return;
+ }
+
+ // make sure the caller is the creating player
+ BodyObject plobj = (BodyObject)caller;
+ if (!plobj.username.equals(_players[0])) {
+ Log.warning("Attempt to start party game by non-creating player " +
+ "[gameOid=" + _gameobj.getOid() +
+ ", caller=" + caller + "].");
+ return;
+ }
+
+ // make sure the game is ready to go
+ if (!canStartPartyGame()) {
+ Log.warning("Attempt to start party game that can't yet begin " +
+ "[gameOid=" + _gameobj.getOid() +
+ ", caller=" + caller + "].");
+ return;
+ }
+
+ // start things up
+ startGame();
+ }
+
+ /**
+ * Returns whether this party game is all set to begin. The default
+ * implementation returns true. Derived classes that implement a
+ * party game should override this method to enforce any prerequisites
+ * (such as a minimum number of players) as appropriate.
+ */
+ protected boolean canStartPartyGame ()
+ {
+ return true;
+ }
+
// documentation inherited
public void attributeChanged (AttributeChangedEvent event)
{
@@ -523,6 +688,9 @@ public class GameManager extends PlaceManager
protected byte _level;
}
+ /** A reference to our game config. */
+ protected GameConfig _gameconfig;
+
/** A reference to our game object. */
protected GameObject _gameobj;
@@ -536,8 +704,8 @@ public class GameManager extends PlaceManager
* player indexes. */
protected byte[] _AIs;
- /** If non-null, contains bundles and messages that should be sent
- * as system messages once the game has started. */
+ /** If non-null, contains bundles and messages that should be sent as
+ * system messages once the game has started. */
protected ArrayList _startmsgs;
/** Our delegate operator to tick AIs. */
diff --git a/src/java/com/threerings/parlor/game/GameMarshaller.java b/src/java/com/threerings/parlor/game/GameMarshaller.java
index 0cb5cecc7..e4218ac58 100644
--- a/src/java/com/threerings/parlor/game/GameMarshaller.java
+++ b/src/java/com/threerings/parlor/game/GameMarshaller.java
@@ -1,5 +1,5 @@
//
-// $Id: GameMarshaller.java,v 1.2 2002/08/20 19:38:14 mdb Exp $
+// $Id: GameMarshaller.java,v 1.3 2002/09/06 22:52:27 shaper Exp $
package com.threerings.parlor.game;
@@ -14,10 +14,6 @@ import com.threerings.presents.dobj.InvocationResponseEvent;
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
- *
- *
Generated from
- * $Id: GameMarshaller.java,v 1.2 2002/08/20 19:38:14 mdb Exp $
- *
*/
public class GameMarshaller extends InvocationMarshaller
implements GameService
@@ -33,5 +29,16 @@ public class GameMarshaller extends InvocationMarshaller
});
}
- // Class file generated on 12:33:04 08/20/02.
+ /** The method id used to dispatch {@link #startPartyGame} requests. */
+ public static final int START_PARTY_GAME = 2;
+
+ // documentation inherited from interface
+ public void startPartyGame (Client arg1)
+ {
+ sendRequest(arg1, START_PARTY_GAME, new Object[] {
+
+ });
+ }
+
+ // Generated on 12:49:14 09/06/02.
}
diff --git a/src/java/com/threerings/parlor/game/GameProvider.java b/src/java/com/threerings/parlor/game/GameProvider.java
index c4d635293..de3ec2b30 100644
--- a/src/java/com/threerings/parlor/game/GameProvider.java
+++ b/src/java/com/threerings/parlor/game/GameProvider.java
@@ -1,5 +1,5 @@
//
-// $Id: GameProvider.java,v 1.1 2002/08/14 19:07:53 mdb Exp $
+// $Id: GameProvider.java,v 1.2 2002/09/06 22:52:27 shaper Exp $
package com.threerings.parlor.game;
@@ -17,4 +17,10 @@ public interface GameProvider extends InvocationProvider
* service request.
*/
public void playerReady (ClientObject caller);
+
+ /**
+ * Called when the client has sent a {@link
+ * GameService#startPartyGame} service request.
+ */
+ public void startPartyGame (ClientObject caller);
}
diff --git a/src/java/com/threerings/parlor/game/GameService.java b/src/java/com/threerings/parlor/game/GameService.java
index f51938055..33d9f0292 100644
--- a/src/java/com/threerings/parlor/game/GameService.java
+++ b/src/java/com/threerings/parlor/game/GameService.java
@@ -1,5 +1,5 @@
//
-// $Id: GameService.java,v 1.1 2002/08/14 19:07:53 mdb Exp $
+// $Id: GameService.java,v 1.2 2002/09/06 22:52:27 shaper Exp $
package com.threerings.parlor.game;
@@ -17,4 +17,12 @@ public interface GameService extends InvocationService
* room and ready to play.
*/
public void playerReady (Client client);
+
+ /**
+ * Asks the game manager to start the party game. This should only be
+ * called for party games, and then only by the creating player after
+ * any other game-specific starting prerequisites (e.g., a required
+ * number of players) have been fulfilled.
+ */
+ public void startPartyGame (Client client);
}