Checkpoint: converting parlor stuff to actionscript.

git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@30 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Ray Greenwell
2006-07-28 02:47:21 +00:00
parent b82ab59b1d
commit 7ee319bb2b
33 changed files with 3870 additions and 0 deletions
@@ -0,0 +1,77 @@
//
// $Id: GameConfigurator.java 3590 2005-06-08 23:20:18Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.client;
import mx.core.Container;
import mx.core.UIComponent;
import mx.containers.Grid;
import mx.containers.GridItem;
import mx.containers.GridRow;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.parlor.util.ParlorContext;
/**
* Provides the base from which interfaces can be built to configure games
* prior to starting them. Derived classes would extend the base
* configurator adding interface elements and wiring them up properly to
* allow the user to configure an instance of their game.
*
* <p> Clients that use the game configurator will want to instantiate one
* based on the class returned from the {@link GameConfig} and then
* initialize it with a call to {@link #init}.
*/
public /*abstract*/ class FlexGameConfigurator extends GameConfigurator
{
/**
* Get the Container that contains the UI elements for this configurator.
*/
public function getContainer () :Container
{
return _grid;
}
/**
* Add a control to the interface. This should be the standard way
* that configurator controls are added, but note also that external
* entities may add their own controls that are related to the game,
* but do not directly alter the game config, so that all the controls
* are added in a uniform manner and are well aligned.
*/
public function addControl (
label :UIComponent, control :UIComponent) :void
{
var row :GridRow = new GridRow();
var labelItem :GridItem = new GridItem();
var controlItem :GridItem = new GridItem();
labelItem.addChild(label);
controlItem.addChild(control);
row.addChild(labelItem);
row.addChild(controlItem);
_grid.addChild(row);
}
/** The grid on which the config options are placed. */
protected var _grid :Grid = new Grid();
}
@@ -0,0 +1,104 @@
//
// $Id: GameConfigurator.java 3590 2005-06-08 23:20:18Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.client {
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.parlor.util.ParlorContext;
/**
* Provides the base from which interfaces can be built to configure games
* prior to starting them. Derived classes would extend the base
* configurator adding interface elements and wiring them up properly to
* allow the user to configure an instance of their game.
*
* <p> Clients that use the game configurator will want to instantiate one
* based on the class returned from the {@link GameConfig} and then
* initialize it with a call to {@link #init}.
*/
public /*abstract*/ class GameConfigurator
{
/**
* Initializes this game configurator, creates its user interface
* elements and prepares it for display.
*/
public function init (ctx :ParlorContext) :void
{
// save this for later
_ctx = ctx;
// create our interface elements
createConfigInterface();
}
/**
* The default implementation creates nothing.
*/
protected function createConfigInterface () :void
{
}
/**
* Provides this configurator with its configuration. It should set up
* all of its user interface elements to reflect the configuration.
*/
public function setGameConfig (config :GameConfig) :void
{
_config = config;
// set up the user interface
gotGameConfig();
}
/**
* Derived classes will likely want to override this method and
* configure their user interface elements accordingly.
*/
protected function gotGameConfig () :void
{
}
/**
* Obtains a configured game configuration.
*/
public function getGameConfig () :GameConfig
{
// flush our changes to the config object
flushGameConfig();
return _config;
}
/**
* Derived classes will want to override this method, flushing values
* from the user interface to the game config object so that it is
* properly configured prior to being returned to the {@link
* #getGameConfig} caller.
*/
protected function flushGameConfig () :void
{
}
/** Provides access to client services. */
protected var _ctx :ParlorContext;
/** Our game configuration. */
protected var _config :GameConfig;
}
}
@@ -0,0 +1,337 @@
//
// $Id: GameController.java 3804 2006-01-13 01:52:36Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.client {
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.presents.dobj.AttributeChangedEvent;
import com.threerings.crowd.client.PlaceController;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;
import com.threerings.parlor.Log;
import com.threerings.parlor.game.data.GameCodes;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.parlor.game.data.GameObject;
import com.threerings.parlor.game.data.PartyGameConfig;
import com.threerings.parlor.util.ParlorContext;
/**
* The game controller manages the flow and control of a game on the
* client side. This class serves as the root of a hierarchy of controller
* classes that aim to provide functionality shared between various
* similar games. The base controller provides functionality for starting
* and ending the game and for calculating ratings adjustements when a
* game ends normally. It also handles the basic house keeping like
* subscription to the game object and dispatch of commands and
* distributed object events.
*/
public /*abstract*/ class GameController extends PlaceController
implements AttributeChangeListener
{
protected static const log :Log = Log.getLog(GameController);
/**
* Initializes this game controller with the game configuration that
* was established during the match making process. Derived classes
* may want to override this method to initialize themselves with
* game-specific configuration parameters but they should be sure to
* call <code>super.init</code> in such cases.
*
* @param ctx the client context.
* @param config the configuration of the game we are intended to
* control.
*/
override public function init (ctx :CrowdContext, config :PlaceConfig) :void
{
// cast our references before we call super.init() so that when
// super.init() calls createPlaceView(), we have our casted
// references already in place
_ctx = (ctx as ParlorContext);
_config = (config as GameConfig);
super.init(ctx, config);
}
/**
* Adds this controller as a listener to the game object (thus derived
* classes need not do so) and lets the game manager know that we are
* now ready to go.
*/
override public function willEnterPlace (plobj :PlaceObject) :void
{
super.willEnterPlace(plobj);
// obtain a casted reference
_gobj = (plobj as GameObject);
// if this place object is not our current location we'll need to
// add it as an auxiliary chat source
var bobj :BodyObject =
(_ctx.getClient().getClientObject() as BodyObject);
if (bobj.location != plobj.getOid()) {
_ctx.getChatDirector().addAuxiliarySource(
_gobj, GameCodes.GAME_CHAT_TYPE);
}
// and add ourselves as a listener
_gobj.addListener(this);
// we don't want to claim to be finished until any derived classes
// that overrode this method have executed, so we'll queue up a
// runnable here that will let the game manager know that we're
// ready on the next pass through the distributed event loop
log.info("Entering game " + _gobj.which() + ".");
if (_gobj.getPlayerIndex(bobj.getVisibleName()) != -1) {
// finally let the game manager know that we're ready
// to roll
_ctx.getClient().callLater(playerReady);
}
}
/**
* Removes our listener registration from the game object and cleans
* house.
*/
override public function didLeavePlace (plobj :PlaceObject) :void
{
super.didLeavePlace(plobj);
_ctx.getChatDirector().removeAuxiliarySource(_gobj);
// unlisten to the game object
_gobj.removeListener(this);
_gobj = null;
}
/**
* Returns whether the game is over.
*/
public function isGameOver () :Boolean
{
var gameOver :Boolean = (_gobj == null) ||
(_gobj.state != GameObject.IN_PLAY);
return (_gameOver || gameOver);
}
/**
* Sets the client game over override. This is used in situations
* where we determine that the game is over before the server has
* informed us of such.
*/
public function setGameOver (gameOver :Boolean) :void
{
_gameOver = gameOver;
}
/**
* Calls {@link #gameWillReset}, ends the current game (locally, it
* does not tell the server to end the game), and waits to receive a
* reset notification (which is simply an event setting the game state
* to <code>IN_PLAY</code> even though it's already set to
* <code>IN_PLAY</code>) from the server which will start up a new
* game. Derived classes should override {@link #gameWillReset} to
* perform any game-specific animations.
*/
public function resetGame () :void
{
// let derived classes do their thing
gameWillReset();
// end the game until we receive a new board
setGameOver(true);
}
/**
* Returns the unique round identifier for the current round.
*/
public function getRoundId () :int
{
return (_gobj == null) ? -1 : _gobj.roundId;
}
/**
* Handles basic game controller action events. Derived classes should
* be sure to call <code>super.handleAction</code> for events they
* don't specifically handle.
*/
override public function handleAction (cmd :String, arg :Object) :Boolean
{
return super.handleAction(cmd, arg);
}
/**
* A way for controllers to display a game-related system message.
*/
public function systemMessage (bundle :String, msg :String) :void
{
_ctx.getChatDirector().displayInfo(
bundle, msg, GameCodes.GAME_CHAT_TYPE);
}
// from interface AttributeChangeListener
public function attributeChanged (event :AttributeChangedEvent) :void
{
// deal with game state changes
var name :String = event.getName();
if (GameObject.STATE.equals(name)) {
var newState :int = int(event.getValue());
if (!stateDidChange(newState)) {
log.warning("Game transitioned to unknown state " +
"[gobj=" + _gobj + ", state=" + newState + "].");
}
}
}
/**
* Derived classes can override this method if they add additional game
* states and should handle transitions to those states, returning true to
* indicate they were handled and calling super for the normal game states.
*/
protected function stateDidChange (state :int) :Boolean
{
switch (state) {
case GameObject.IN_PLAY:
gameDidStart();
return true;
case GameObject.GAME_OVER:
gameDidEnd();
return true;
case GameObject.CANCELLED:
gameWasCancelled();
return true;
}
return false;
}
/**
* Called after we've entered the game and everything has initialized
* to notify the server that we, as a player, are ready to play.
*/
protected function playerReady () :void
{
log.info("Reporting ready " + _gobj.which() + ".");
_gobj.gameService.playerReady(_ctx.getClient());
}
/**
* Called when the game transitions to the <code>IN_PLAY</code>
* state. This happens when all of the players have arrived and the
* server starts the game.
*/
protected function gameDidStart () :void
{
if (_gobj == null) {
log.info("Received gameDidStart() after leaving game room.");
return;
}
// clear out our game over flag
setGameOver(false);
/* TODO
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameDidStart();
}
});
*/
}
/**
* Called when the game transitions to the <code>GAME_OVER</code>
* state. This happens when the game reaches some end condition by
* normal means (is not cancelled or aborted).
*/
protected function gameDidEnd () :void
{
/* TODO
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameDidEnd();
}
});
*/
}
/**
* Called when the game was cancelled for some reason.
*/
protected function gameWasCancelled () :void
{
/*
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameWasCancelled();
}
});
*/
}
/**
* Called to give derived classes a chance to display animations, send
* a final packet, or do any other business they care to do when the
* game is about to reset.
*/
protected function gameWillReset () :void
{
/* TODO
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameWillReset();
}
});
*/
}
/**
* Used to determine if this game is a party game.
*/
protected function isPartyGame () :Boolean
{
return (_config is PartyGameConfig) &&
(PartyGameConfig(_config).getPartyGameType() !=
PartyGameConfig.NOT_PARTY_GAME);
}
/** A reference to the active parlor context. */
protected var _pctx :ParlorContext;
/** Our game configuration information. */
protected var _config :GameConfig;
/** A reference to the game object for the game that we're
* controlling. */
protected var _gobj :GameObject;
/** A local flag overriding the game over state for situations where
* the client knows the game is over before the server has
* transitioned the game object accordingly. */
protected var _gameOver :Boolean;
}
}
@@ -0,0 +1,39 @@
//
// $Id: GameService.java 3600 2005-06-15 23:46:31Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.client {
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
/**
* Provides services used by game clients to request that actions be taken
* by the game manager.
*/
public interface GameService extends InvocationService
{
/**
* Lets the game manager know that the calling player is in the game
* room and ready to play.
*/
function playerReady (client :Client) :void;
}
}
@@ -0,0 +1,47 @@
//
// $Id: GameAI.java 3399 2005-03-12 07:37:34Z mdb $
package com.threerings.parlor.game.data {
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamable;
/**
* Represents attributes of an AI player.
*/
public class GameAI
implements Streamable
{
/** The "personality" of the AI, which can be interpreted by
* each puzzle. */
public var personality :int;
/** The skill level of the AI. */
public var skill :int;
/**
* Constructs an AI with the specified (game-interpreted) skill and
* personality.
*/
public function GameAI (personality :int = 0, skill :int = 0)
{
this.personality = personality;
this.skill = skill;
}
// from Streamable
public function writeObject (out :ObjectOutputStream) :void
{
out.writeInt(personality);
out.writeInt(skill);
}
// from Streamable
public function readObject (ins :ObjectInputStream) :void
{
personality = ins.readInt();
skill = ins.readInt();
}
}
}
@@ -0,0 +1,45 @@
//
// $Id: PuzzleCodes.java 3184 2004-10-28 19:20:27Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.data {
import com.threerings.presents.data.InvocationCodes;
/**
* Constants relating to the game services.
*/
public class GameCodes extends InvocationCodes
{
/** The message bundle identifier for general game messages. */
public static const GAME_MESSAGE_BUNDLE :String = "game.general";
/** The name of the message event to a placeObject that a player
* was knocked out of a puzzle. */
public static const PLAYER_KNOCKED_OUT :String = "playerKnocked";
/** The name of the message event to a placeObject that reports
* the winners and losers of a game. */
public static const WINNERS_AND_LOSERS :String = "winnersAndLosers";
/** A chat type for chatting on the game object. */
public static const GAME_CHAT_TYPE :String = "gameChat";
}
}
@@ -0,0 +1,162 @@
//
// $Id: GameConfig.java 4026 2006-04-18 01:32:41Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.data {
import com.threerings.util.ClassUtil;
import com.threerings.util.Cloneable;
import com.threerings.util.Hashable;
import com.threerings.util.Name;
import com.threerings.io.TypedArray;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.parlor.client.TableConfigurator;
import com.threerings.parlor.game.client.GameConfigurator;
/**
* The game config class encapsulates the configuration information for a
* particular type of game. The hierarchy of game config objects mimics the
* hierarchy of game managers and controllers. Both the game manager and game
* controller are provided with the game config object when the game is
* created.
*
* <p> The game config object is also the mechanism used to instantiate the
* appropriate game manager and controller. Every game must have an associated
* game config derived class that overrides {@link #createController} and
* {@link #getManagerClassName}, returning the appropriate game controller and
* manager class for that game. Thus the entire chain of events that causes a
* particular game to be created is the construction of the appropriate game
* config instance which is provided to the server as part of an invitation or
* via some other matchmaking mechanism.
*/
public /*abstract*/ class GameConfig extends PlaceConfig
implements Cloneable, Hashable
{
/** The usernames of the players involved in this game, or an empty
* array if such information is not needed by this particular game. */
public var players :TypedArray = TypedArray.create(Name);
/** Indicates whether or not this game is rated. */
public var rated :Boolean = true;
/** Configurations for AIs to be used in this game. Slots with real
* players should be null and slots with AIs should contain
* configuration for those AIs. A null array indicates no use of AIs
* at all. */
public var ais :TypedArray = TypedArray.create(GameAI);
/**
* Returns the message bundle identifier for the bundle that should be
* used to translate the translatable strings used to describe the
* game config parameters.
*/
public function getBundleName () :String
{
Log.getLog(this).warning("this method is actually abstract.");
}
/**
* Creates a configurator that can be used to create a user interface
* for configuring this instance prior to starting the game. If no
* configuration is necessary, this method should return null.
*/
public function createConfigurator () :GameConfigurator
/**
* Creates a table configurator for initializing 'table' properties
* of the game. The default implementation returns null.
*/
public function createTableConfigurator () :TableConfigurator
{
return null;
}
/**
* Returns a translatable label describing this game.
*/
public function getGameName () :String
{
// the whole getRatingTypeId(), getGameName(), getBundleName()
// business should be cleaned up. we should have getGameIdent()
// and everything should have a default implementation using that
return "m." + getBundleName();
}
/**
* Returns the game rating type, if the system uses such things.
*/
public function getRatingTypeId () :int
{
return -1;
}
/**
* Returns an Array of strings that describe the configuration of this
* game. Default implementation returns an empty array.
*/
public function getDescription () :Array
{
return new Array(); // nothing by default
}
/**
* Returns true if this game config object is equal to the supplied
* object (meaning it is also a game config object and its
* configuration settings are the same as ours).
*/
public function equals (other :Object) :Boolean
{
// make sure they're of the same class
if (ClassUtil.getClassName(other) == ClassUtil.getClassName(this)) {
var that :GameConfig = GameConfig(other);
return this.rated == that.rated;
} else {
return false;
}
}
/**
* Computes a hashcode for this game config object that supports our
* {@link #equals} implementation. Objects that are equal should have
* the same hashcode.
*/
public function hashCode () :int
{
// look ma, it's so sophisticated!
return StringUtil.hashCode(ClassUtil.getClassName(this)) +
(rated ? 1 : 0);
}
// from Cloneable
public function clone () :Object
{
var copy :GameConfig = ClassUtil.newInstance(this);
copy.players = this.players;
copy.rated = this.rated;
copy.ais = this.ais;
return copy;
}
}
}
@@ -0,0 +1,49 @@
//
// $Id: GameMarshaller.java 4145 2006-05-24 01:24:24Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.data {
import com.threerings.parlor.game.client.GameService;
import com.threerings.presents.client.Client;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
/**
* Provides the implementation of the {@link GameService} interface
* that marshalls the arguments and delivers the request to the provider
* 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.
*/
public class GameMarshaller extends InvocationMarshaller
implements GameService
{
/** The method id used to dispatch {@link #playerReady} requests. */
public static const PLAYER_READY :int = 1;
// documentation inherited from interface
public function playerReady (arg1 :Client) :void
{
sendRequest(arg1, PLAYER_READY, [ ]);
}
}
}
@@ -0,0 +1,442 @@
//
// $Id: GameObject.java 4191 2006-06-13 22:42:20Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.data {
import com.threerings.util.Integer;
import com.threerings.util.langBoolean;
import com.threerings.util.Name;
import com.threerings.io.TypedArray;
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
{
// AUTO-GENERATED: FIELDS START
/** The field name of the <code>gameService</code> field. */
public static const GAME_SERVICE :String = "gameService";
/** The field name of the <code>state</code> field. */
public static const STATE :String = "state";
/** The field name of the <code>isRated</code> field. */
public static const IS_RATED :String = "isRated";
/** The field name of the <code>isPrivate</code> field. */
public static const IS_PRIVATE :String = "isPrivate";
/** The field name of the <code>players</code> field. */
public static const PLAYERS :String = "players";
/** The field name of the <code>winners</code> field. */
public static const WINNERS :String = "winners";
/** The field name of the <code>roundId</code> field. */
public static const ROUND_ID :String = "roundId";
/** The field name of the <code>playerStatus</code> field. */
public static const PLAYER_STATUS :String = "playerStatus";
// AUTO-GENERATED: FIELDS END
/** 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 const PRE_GAME :int = 0;
/** A game state constant indicating that the game is in play. */
public static const IN_PLAY :int = 1;
/** A game state constant indicating that the game ended normally. */
public static const GAME_OVER :int = 2;
/** A game state constant indicating that the game was cancelled. */
public static const CANCELLED :int = 3;
/** The player status constant for a player whose game is in play. */
public static const PLAYER_IN_PLAY :int = 0;
/** The player status constant for a player whose has been knocked out
* of the game. NOTE: This can include a player choosing to leave a
* game prematurely. */
public static const PLAYER_LEFT_GAME :int = 1;
/** Provides general game invocation services. */
public var gameService :GameMarshaller;
/** The game state, one of {@link #PRE_GAME}, {@link #IN_PLAY},
* {@link #GAME_OVER}, or {@link #CANCELLED}. */
public var state :int = PRE_GAME;
/** Indicates whether or not this game is rated. */
public var isRated :Boolean;
/** Indicates whether the game is "private". */
public var isPrivate :Boolean;
/** The usernames of the players involved in this game. */
public var players :TypedArray; /* of Name */
/** Whether each player in the game is a winner, or <code>null</code>
* if the game is not yet over. */
public var winners :TypedArray; /* of Boolean */
/** The unique round identifier for the current round. */
public var roundId :int;
/** If null, indicates that all present players are active, or for
* more complex games can be non-null to indicate the current status
* of each player in the game. The status value is one of
* {@link #PLAYER_LEFT_GAME} or {@link #PLAYER_IN_PLAY}. */
public var playerStatus :TypedArray; /* of int */
/**
* Returns the number of players in the game.
*/
public function getPlayerCount () :int
{
var count :int = 0;
var size :int = players.length;
for (var ii :int = 0; ii < size; ii++) {
if (players[ii] != null) {
count++;
}
}
return count;
}
/**
* Returns the number of active players in the game.
*/
public function getActivePlayerCount () :int
{
var count :int = 0;
var size :int = players.length;
for (var ii :int = 0; ii < size; ii++) {
if (isActivePlayer(ii)) {
count++;
}
}
return count;
}
/**
* Returns whether the given player is still an active player in
* the game. (Ie. whether or not they are still participating.)
*/
public function isActivePlayer (pidx :int) :Boolean
{
return isOccupiedPlayer(pidx) &&
(playerStatus == null || isActivePlayerStatus(playerStatus[pidx]));
}
/**
* Returns the player index of the given user in the game, or
* <code>-1</code> if the player is not involved in the game.
*/
public function getPlayerIndex (username :Name) :int
{
return ArrayUtil.indexOf(players, username);
}
/**
* Returns whether the game is in play. A game that is not in play
* could either be awaiting players, ended, or cancelled.
*/
public function isInPlay () :Boolean
{
return (state == IN_PLAY);
}
/**
* Returns whether the given player index in the game is occupied.
*/
public function isOccupiedPlayer (pidx :int) :Boolean
{
return (pidx >= 0 && pidx < players.length) && (players[pidx] != null);
}
/**
* Returns whether the given player index is a winner, or false if the
* winners are not yet assigned.
*/
public function isWinner (pidx :int) :Boolean
{
return (winners != null) && winners[pidx];
}
/**
* Returns the number of winners for this game, or <code>0</code> if
* the winners array is not populated, e.g., the game is not yet over.
*/
public function getWinnerCount () :int
{
int count = 0;
if (winners != null) {
for (var ii :int = 0; ii < winners.length; ii++) {
if (winners[ii]) {
count++;
}
}
}
return count;
}
/**
* Returns true if the game is ended in a draw.
*/
public function isDraw () :Boolean
{
return getWinnerCount() == getPlayerCount();
}
/**
* Returns the winner index of the first winning player for this game,
* or <code>-1</code> 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 function getWinnerIndex () :int
{
return ArrayUtil.indexOf(winners, true);
}
/**
* Returns the type of party game being played or NOT_PARTY_GAME.
* {@link PartyGameConfig}.
*/
public function getPartyGameType () :int
{
return PartyGameConfig.NOT_PARTY_GAME;
}
/**
* Used by {@link #isActivePlayer} to determine if the supplied status is
* associated with an active player (one that has not resigned from the
* game and/or left the game room).
*/
protected function isActivePlayerStatus (playerStatus :int) :Boolean
{
return playerStatus == PLAYER_IN_PLAY;
}
override protected function whichBuf (buf :StringBuilder) :void
{
super.whichBuf(buf);
buf.append(players.join());
buf.append(":").append(state);
}
// AUTO-GENERATED: METHODS START
/**
* Requests that the <code>gameService</code> 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 function setGameService (value :GameMarshaller) :void
{
var ovalue :GameMarshaller = this.gameService;
requestAttributeChange(
GAME_SERVICE, value, ovalue);
this.gameService = value;
}
/**
* Requests that the <code>state</code> 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 function setState (value :int) :void
{
var ovalue :int = this.state;
requestAttributeChange(
STATE, Integer.valueOf(value), Integer.valueOf(ovalue));
this.state = value;
}
/**
* Requests that the <code>isRated</code> 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 function setIsRated (value :Boolean) :void
{
var ovalue :Boolean = this.isRated;
requestAttributeChange(
IS_RATED, langBoolean.valueOf(value), langBoolean.valueOf(ovalue));
this.isRated = value;
}
/**
* Requests that the <code>isPrivate</code> 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 function setIsPrivate (value :Boolean) :void
{
var ovalue :Boolean = this.isPrivate;
requestAttributeChange(
IS_PRIVATE, langBoolean.valueOf(value),
langBoolean.valueOf(ovalue));
this.isPrivate = value;
}
/**
* Requests that the <code>players</code> 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 function setPlayers (value :TypedArray) :void
{
var ovalue :TypedArray = this.players;
requestAttributeChange(
PLAYERS, value, ovalue);
this.players = (value == null) ? null : (value.clone() as TypedArray);
}
/**
* Requests that the <code>index</code>th element of
* <code>players</code> 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 function setPlayersAt (value :Name, index :int) :void
{
var ovalue :Name = (this.players[index] as Name);
requestElementUpdate(
PLAYERS, index, value, ovalue);
this.players[index] = value;
}
/**
* Requests that the <code>winners</code> 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 function setWinners (value :TypedArray) :void
{
var ovalue :TypedArray = this.winners;
requestAttributeChange(
WINNERS, value, ovalue);
this.winners = (value == null) ? null : (value.clone() as TypedArray);
}
/**
* Requests that the <code>index</code>th element of
* <code>winners</code> 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 function setWinnersAt (value :Boolean, index :int) :void
{
var ovalue :Boolean = (this.winners[index] as Boolean);
requestElementUpdate(
WINNERS, index, langBoolean.valueOf(value),
langBoolean.valueOf(ovalue));
this.winners[index] = value;
}
/**
* Requests that the <code>roundId</code> 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 function setRoundId (value :int) :void
{
var ovalue :int = this.roundId;
requestAttributeChange(
ROUND_ID, Integer.valueOf(value), Integer.valueOf(ovalue));
this.roundId = value;
}
/**
* Requests that the <code>playerStatus</code> 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 function setPlayerStatus (value :TypedArray) :void
{
var ovalue :TypedArray = this.playerStatus;
requestAttributeChange(
PLAYER_STATUS, value, ovalue);
this.playerStatus = (value == null) ? null
: (value.clone() as TypedArray);
}
/**
* Requests that the <code>index</code>th element of
* <code>playerStatus</code> 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 function setPlayerStatusAt (value :int, index :int) :void
{
var ovalue :int = (this.playerStatus[index] as int);
requestElementUpdate(
PLAYER_STATUS, index, Integer.valueOf(value),
Integer.valueOf(ovalue));
this.playerStatus[index] = value;
}
// AUTO-GENERATED: METHODS END
}
}
@@ -0,0 +1,51 @@
//
// $Id: PartyGameConfig.java 3804 2006-01-13 01:52:36Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.game.data {
/**
* Provides additional information for party games.
* A party game is a game in which the players are not set prior to starting,
* but players can come and go at will during the normal progression of
* the game.
*/
public interface PartyGameConfig
{
/** Party game constant indicating that this game, while it does
* implement PartyGameConfig, is not currently being played in party
* mode. */
public static const NOT_PARTY_GAME :int = 0;
/** Party game constant indicating that we're in a party game in which
* players must sit at an available seat to play, otherwise they're
* an observer. */
public static const SEATED_PARTY_GAME :int = 1;
/** Party game constant indicating that everyone in the game place is
* a "player", meaning that they do not need to claim a seat to play. */
public static const FREE_FOR_ALL_PARTY_GAME :int = 2;
/**
* Get the type of party game being played.
*/
function getPartyGameType () :int;
}
}