// // $Id: GameObject.java,v 1.18 2004/03/06 11:29:19 mdb Exp $ package com.threerings.parlor.game; import com.samskivert.util.ListUtil; import com.samskivert.util.StringUtil; import com.threerings.util.Name; import com.threerings.crowd.data.PlaceObject; /** * A game object hosts the shared data associated with a game played by * one or more players. The game object extends the place object so that * the game can act as a place where players actually go when playing the * game. Only very basic information is maintained in the base game * object. It serves as the base for a hierarchy of game object * derivatives that handle basic gameplay for a suite of different game * types (ie. turn based games, party games, board games, card games, * etc.). */ public class GameObject extends PlaceObject { /** The field name of the gameService field. */ public static final String GAME_SERVICE = "gameService"; /** The field name of the state field. */ public static final String STATE = "state"; /** The field name of the isRated field. */ public static final String IS_RATED = "isRated"; /** The field name of the players field. */ public static final String PLAYERS = "players"; /** The field name of the winners field. */ public static final String WINNERS = "winners"; /** The field name of the roundId field. */ public static final String ROUND_ID = "roundId"; /** The field name of the creator field. */ public static final String CREATOR = "creator"; /** A game state constant indicating that the game has not yet started * and is still awaiting the arrival of all of the players. */ public static final int AWAITING_PLAYERS = 0; /** A game state constant indicating that the game is in play. */ public static final int IN_PLAY = 1; /** A game state constant indicating that the game ended normally. */ public static final int GAME_OVER = 2; /** A game state constant indicating that the game was cancelled. */ public static final int CANCELLED = 3; /** Provides general game invocation services. */ public GameMarshaller gameService; /** The game state, one of {@link #AWAITING_PLAYERS}, {@link #IN_PLAY}, * {@link #GAME_OVER}, or {@link #CANCELLED}. */ public int state; /** Indicates whether or not this game is rated. */ public boolean isRated; /** The usernames of the players involved in this game. */ public Name[] players; /** Whether each player in the game is a winner, or null * if the game is not yet over. */ public boolean[] winners; /** The unique round identifier for the current round. */ public int roundId; /** The player index of the creating player if this is a party game. */ public int creator; /** * Returns the number of players in the game. */ public int getPlayerCount () { int count = 0; int size = players.length; for (int ii = 0; ii < size; ii++) { if (players[ii] != null) { count++; } } return count; } /** * Returns the player index of the given user in the game, or * -1 if the player is not involved in the game. */ public int getPlayerIndex (Name username) { int size = (players == null) ? 0 : players.length; for (int ii = 0; ii < size; ii++) { if (players[ii] != null && players[ii].equals(username)) { return ii; } } return -1; } /** * Returns whether the game is in play. A game that is not in play * could either be awaiting players, ended, or cancelled. */ public boolean isInPlay () { return (state == IN_PLAY); } /** * Returns whether the given player index in the game is occupied. */ public boolean isOccupiedPlayer (int pidx) { return (players[pidx] != null); } /** * Returns whether the given player index is a winner, or false if the * winners are not yet assigned. */ public boolean isWinner (int pidx) { return (winners == null) ? false : winners[pidx]; } /** * Returns the number of winners for this game, or 0 if * the winners array is not populated, e.g., the game is not yet over. */ public int getWinnerCount () { int count = 0; int size = (winners == null) ? 0 : winners.length; for (int ii = 0; ii < size; ii++) { if (winners[ii]) { count++; } } return count; } /** * Returns the winner index of the first winning player for this game, * or -1 if there are no winners or the winners array is * not yet assigned. This is only likely to be useful for games that * are known to have a single winner. */ public int getWinnerIndex () { int size = (winners == null) ? 0 : winners.length; for (int ii = 0; ii < size; ii++) { if (winners[ii]) { return ii; } } return -1; } // documentation inherited protected void which (StringBuffer buf) { super.which(buf); StringUtil.toString(buf, players); buf.append(":").append(state); } /** * Requests that the gameService field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setGameService (GameMarshaller gameService) { requestAttributeChange(GAME_SERVICE, gameService); this.gameService = gameService; } /** * Requests that the state field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setState (int state) { requestAttributeChange(STATE, new Integer(state)); this.state = state; } /** * Requests that the isRated field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setIsRated (boolean isRated) { requestAttributeChange(IS_RATED, new Boolean(isRated)); this.isRated = isRated; } /** * Requests that the players field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setPlayers (Name[] players) { requestAttributeChange(PLAYERS, players); this.players = players; } /** * Requests that the indexth element of * players field be set to the specified value. The local * value will be updated immediately and an event will be propagated * through the system to notify all listeners that the attribute did * change. Proxied copies of this object (on clients) will apply the * value change when they received the attribute changed notification. */ public void setPlayersAt (Name value, int index) { requestElementUpdate(PLAYERS, value, index); this.players[index] = value; } /** * Requests that the winners field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setWinners (boolean[] winners) { requestAttributeChange(WINNERS, winners); this.winners = winners; } /** * Requests that the indexth element of * winners field be set to the specified value. The local * value will be updated immediately and an event will be propagated * through the system to notify all listeners that the attribute did * change. Proxied copies of this object (on clients) will apply the * value change when they received the attribute changed notification. */ public void setWinnersAt (boolean value, int index) { requestElementUpdate(WINNERS, new Boolean(value), index); this.winners[index] = value; } /** * Requests that the roundId field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setRoundId (int roundId) { requestAttributeChange(ROUND_ID, new Integer(roundId)); this.roundId = roundId; } /** * Requests that the creator field be set to the specified * value. The local value will be updated immediately and an event * will be propagated through the system to notify all listeners that * the attribute did change. Proxied copies of this object (on * clients) will apply the value change when they received the * attribute changed notification. */ public void setCreator (int creator) { requestAttributeChange(CREATOR, new Integer(creator)); this.creator = creator; } }