diff --git a/src/as/com/threerings/ezgame/AbstractControl.as b/src/as/com/threerings/ezgame/AbstractControl.as new file mode 100644 index 00000000..72b7fcfe --- /dev/null +++ b/src/as/com/threerings/ezgame/AbstractControl.as @@ -0,0 +1,142 @@ +// +// $Id: BaseControl.as 414 2007-08-23 00:32:36Z mdb $ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +import flash.errors.IllegalOperationError; + +import flash.events.Event; +import flash.events.EventDispatcher; + +/** + * The abstract base class for EZ controls. + */ +public class AbstractControl extends EventDispatcher +{ + public function AbstractControl () + { + if (Object(this).constructor == AbstractControl) { + throw new IllegalOperationError("Abstract"); + } + } + + /** + * Are we connected and running inside the EZGame environment, or has someone just + * loaded up our SWF by itself? + */ + public function isConnected () :Boolean + { + return false; + } + + /** + * Execute the specified function as a batch of commands that will be sent to the server + * together. This is no different from executing the commands outside of a batch, but + * may result in better use of the network and should be used if setting a number of things + * at once. + * + * Example: + * _ctrl.doBatch(function () :void { + * _ctrl.set("board", new Array()); + * _ctrl.set("scores", new Array()); + * _ctrl.set("captures", 0); + * }); + */ + public function doBatch (fn :Function) :void + { + callHostCode("startTransaction"); + try { + fn(); + } finally { + callHostCode("commitTransaction"); + } + } + + /** + * Populate any properties or functions we want to expose to the host code. + */ + protected function populateProperties (o :Object) :void + { + // nothing by default + } + + /** + * Grab any properties needed from our host code. + */ + protected function setHostProps (o :Object) :void + { + // nothing by default + } + + /** + * Your own events may not be dispatched here. + */ + override public function dispatchEvent (event :Event) :Boolean + { + // Ideally we want to not be an EventDispatcher so that people + // won't try to do this on us, but if we do that, then some other + // object will be the target during dispatch, and that's confusing. + throw new IllegalOperationError(); + } + + /** + * Secret function to dispatch property changed events. + */ + protected function dispatch (event :Event) :void + { + try { + super.dispatchEvent(event); + } catch (err :Error) { + trace("Error dispatching event to user game."); + trace(err.getStackTrace()); + } + } + + /** + * Call a method exposed by the host code. + */ + protected function callHostCode (name :String, ... args) :* + { + return undefined; // no-op by default + } + + /** + * Exposed to sub controls. + */ + internal function callHostCodeFriend (name :String, args :Array) :* + { + args.unshift(name); + return callHostCode.apply(this, args); + } + + /** + * Helper method to throw an error if we're not connected. + */ + protected function checkIsConnected () :void + { + if (!isConnected()) { + throw new IllegalOperationError( + "The game is not connected to the host framework, please check isConnected(). " + + "If false, your game is being viewed standalone and should adjust."); + } + } +} +} diff --git a/src/as/com/threerings/ezgame/AbstractGameControl.as b/src/as/com/threerings/ezgame/AbstractGameControl.as new file mode 100644 index 00000000..d93abe99 --- /dev/null +++ b/src/as/com/threerings/ezgame/AbstractGameControl.as @@ -0,0 +1,244 @@ +// +// $Id: EZGameControl.as 526 2007-12-13 01:42:10Z ray $ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +import flash.display.DisplayObject; + +import flash.errors.IllegalOperationError; + +import flash.events.Event; +import flash.events.EventDispatcher; +import flash.events.KeyboardEvent; +import flash.events.MouseEvent; + +import flash.geom.Point; + +/** + * Dispatched when the game client is unloaded and you should clean up any Timers or + * other bits left hanging. + * + * @eventType flash.events.Event.UNLOAD + */ +[Event(name="unload", type="flash.events.Event")] + +/** + * The single point of control for each client in your multiplayer EZGame. + */ +public class AbstractGameControl extends AbstractControl +{ + /** + * Create an EZGameControl object using some display object currently on the hierarchy. + * + * @param disp the display object that is the game's UI. + * @param autoReady if true, the game will automatically be started when initialization is + * complete, if false, the game will not start until all clients call {@link #playerReady}. + */ + public function AbstractGameControl (disp :DisplayObject, autoReady :Boolean) + { + createSubControls(); + + var event :DynEvent = new DynEvent(); + event.userProps = new Object(); + populateProperties(event.userProps); + event.userProps["autoReady_v1"] = autoReady; + disp.root.loaderInfo.sharedEvents.dispatchEvent(event); + if ("ezProps" in event) { + setHostProps(event.ezProps); + } + + // set up our focusing click handler + disp.root.addEventListener(MouseEvent.CLICK, handleRootClick); + + // set up the unload event to propagate + disp.root.loaderInfo.addEventListener(Event.UNLOAD, dispatch); + } + + override public function isConnected () :Boolean + { + return _connected; + } + + /** + * Create any subcontrols used by this game. + */ + protected function createSubControls () :void + { + _subControls.push( + _localCtrl = createLocalControl(), + _netCtrl = createNetControl(), + _playerCtrl = createPlayerControl(), + _gameCtrl = createGameControl(), + _servicesCtrl = createServicesControl() + ); + } + + /** + * Create the 'local' subcontrol. + */ + protected function createLocalControl () :EZLocalSubControl + { + return new EZLocalSubControl(this); + } + + /** + * Create the 'net' subcontrol. + */ + protected function createNetControl () :EZNetSubControl + { + return new EZNetSubControl(this); + } + + /** + * Create the 'player' subcontrol. + */ + protected function createPlayerControl () :EZPlayerSubControl + { + return new EZPlayerSubControl(this); + } + + /** + * Create the 'game' subcontrol. + */ + protected function createGameControl () :EZGameSubControl + { + return new EZGameSubControl(this); + } + + /** + * Create the 'services' subcontrol. + */ + protected function createServicesControl () :EZServicesSubControl + { + return new EZServicesSubControl(this); + } + + /** + * Populate any properties or functions we want to expose to the other side of the ezgame + * security boundary. + */ + override protected function populateProperties (o :Object) :void + { + super.populateProperties(o); + + o["connectionClosed_v1"] = connectionClosed_v1; + + for each (var ctrl :AbstractSubControl in _subControls) { + ctrl.populatePropertiesFriend(o); + } + } + + /** + * Sets the properties we received from the host framework on the other side of the security + * boundary. + */ + override protected function setHostProps (o :Object) :void + { + super.setHostProps(o); + + // see if we're connected + _connected = (o.gameData != null); + + for each (var ctrl :AbstractSubControl in _subControls) { + ctrl.setHostPropsFriend(o); + } + + // and assign our functions + _funcs = o; + } + + override protected function callHostCode (name :String, ... args) :* + { + if (_funcs != null) { + try { + var func :Function = (_funcs[name] as Function); + if (func != null) { + return func.apply(null, args); + } + } catch (err :Error) { + trace(err.getStackTrace()); + trace("--"); + throw new Error("Unable to call host code: " + err.message); + } + + } else { + // if _funcs is null, this will almost certainly throw an error.. + checkIsConnected(); + } + } + + /** + * Internal method that is called whenever the mouse clicks our root. + */ + protected function handleRootClick (evt :MouseEvent) :void + { + if (!isConnected()) { + return; + } + try { + if (evt.target.stage == null || evt.target.stage.focus != null) { + return; + } + } catch (err :SecurityError) { + } + callHostCode("focusContainer_v1"); + } + + /** + * Private method called when the backend disconnects from us. + */ + private function connectionClosed_v1 () :void + { + _connected = false; + } + + /** Are we connected? */ + protected var _connected :Boolean; + + /** Contains functions exposed to us from the EZGame host. */ + protected var _funcs :Object; + + /** Holds all our sub-controls. */ + protected var _subControls :Array = []; + + /** Specific sub-controls. */ + protected var _localCtrl :EZLocalSubControl; + protected var _netCtrl :EZNetSubControl; + protected var _playerCtrl :EZPlayerSubControl; + protected var _gameCtrl :EZGameSubControl; + protected var _servicesCtrl :EZServicesSubControl; +} +} + +import flash.events.Event; + +dynamic class DynEvent extends Event +{ + public function DynEvent () + { + super("ezgameQuery", true, false); + } + + override public function clone () :Event + { + return new DynEvent(); + } +} diff --git a/src/as/com/threerings/ezgame/SubControl.as b/src/as/com/threerings/ezgame/AbstractSubControl.as similarity index 56% rename from src/as/com/threerings/ezgame/SubControl.as rename to src/as/com/threerings/ezgame/AbstractSubControl.as index a3b4cd1f..a148e718 100644 --- a/src/as/com/threerings/ezgame/SubControl.as +++ b/src/as/com/threerings/ezgame/AbstractSubControl.as @@ -1,5 +1,5 @@ // -// $Id$ +// $Id: SubControl.as 271 2007-04-07 00:25:58Z dhoover $ // // Vilya library - tools for developing networked games // Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved @@ -26,18 +26,43 @@ import flash.errors.IllegalOperationError; /** * Abstract base class. Do not instantiate. */ -public class SubControl extends BaseControl +public class AbstractSubControl extends AbstractControl { - public function SubControl (ctrl :EZGameControl) + public function AbstractSubControl (parent :AbstractControl) { super(); - if (ctrl == null || Object(this).constructor == SubControl) { + if (parent == null || Object(this).constructor == AbstractSubControl) { throw new IllegalOperationError("Abstract"); } - _ctrl = ctrl; + _parent = parent; } - protected var _ctrl :EZGameControl; + override public function isConnected () :Boolean + { + return _parent.isConnected(); + } + + override public function doBatch (fn :Function) :void + { + return _parent.doBatch(fn); + } + + override protected function callHostCode (name :String, ... args) :* + { + return _parent.callHostCodeFriend(name, args); + } + + internal function populatePropertiesFriend (o :Object) :void + { + populateProperties(o); + } + + internal function setHostPropsFriend (o :Object) :void + { + setHostProps(o); + } + + protected var _parent :AbstractControl; } } diff --git a/src/as/com/threerings/ezgame/BaseControl.as b/src/as/com/threerings/ezgame/BaseControl.as deleted file mode 100644 index e7c9758f..00000000 --- a/src/as/com/threerings/ezgame/BaseControl.as +++ /dev/null @@ -1,65 +0,0 @@ -// -// $Id$ -// -// Vilya library - tools for developing networked games -// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved -// http://www.threerings.net/code/vilya/ -// -// 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.ezgame { - -import flash.errors.IllegalOperationError; - -import flash.events.Event; -import flash.events.EventDispatcher; - -/** - * The abstract base class for EZ controls. - */ -public class BaseControl extends EventDispatcher -{ - public function BaseControl () - { - if (Object(this).constructor == BaseControl) { - throw new IllegalOperationError("Abstract"); - } - } - - /** - * Your own events may not be dispatched here. - */ - override public function dispatchEvent (event :Event) :Boolean - { - // Ideally we want to not be an EventDispatcher so that people - // won't try to do this on us, but if we do that, then some other - // object will be the target during dispatch, and that's confusing. - throw new IllegalOperationError(); - } - - /** - * Secret function to dispatch property changed events. - */ - protected function dispatch (event :Event) :void - { - try { - super.dispatchEvent(event); - } catch (err :Error) { - trace("Error dispatching event to user game."); - trace(err.getStackTrace()); - } - } -} -} diff --git a/src/as/com/threerings/ezgame/CardDeck.as b/src/as/com/threerings/ezgame/CardDeck.as index 78fdaae6..9db788e8 100644 --- a/src/as/com/threerings/ezgame/CardDeck.as +++ b/src/as/com/threerings/ezgame/CardDeck.as @@ -40,19 +40,19 @@ public class CardDeck } } - _gameCtrl.collections.create(_deckName, deck); + _gameCtrl.services.bags.create(_deckName, deck); } public function dealToPlayer ( playerId :int, count :int, msgName :String) :void { // TODO: support the callback - _gameCtrl.collections.deal(_deckName, count, msgName, null, playerId); + _gameCtrl.services.bags.deal(_deckName, count, msgName, null, playerId); } public function dealToData (count :int, propName :String) :void { - _gameCtrl.collections.deal(_deckName, count, propName, null); + _gameCtrl.services.bags.deal(_deckName, count, propName, null); } /** The game control. */ diff --git a/src/as/com/threerings/ezgame/CollectionsControl.as b/src/as/com/threerings/ezgame/EZBagsSubControl.as similarity index 61% rename from src/as/com/threerings/ezgame/CollectionsControl.as rename to src/as/com/threerings/ezgame/EZBagsSubControl.as index 23e5a3db..b89ef6a6 100644 --- a/src/as/com/threerings/ezgame/CollectionsControl.as +++ b/src/as/com/threerings/ezgame/EZBagsSubControl.as @@ -22,51 +22,50 @@ package com.threerings.ezgame { /** - * Contains EZ methods related to collections. + * Contains 'bags' game services. */ -public class CollectionsControl extends SubControl +public class EZBagsSubControl extends AbstractSubControl { - public function CollectionsControl (ctrl :EZGameControl) + public function EZBagsSubControl (parent :AbstractControl) { - super(ctrl); + super(parent); } /** - * Create a collection containing the specified values, - * clearing any previous collection with the same name. + * Create a bag containing the specified values, + * clearing any previous bag with the same name. */ - public function create (collName :String, values :Array) :void + public function create (bagName :String, values :Array) :void { - populate(collName, values, true); + populate(bagName, values, true); } /** - * Add to an existing collection. If it doesn't exist, it will - * be created. The new values will be inserted randomly into the - * collection. + * Add to an existing bag. If it doesn't exist, it will + * be created. */ - public function addTo (collName :String, values :Array) :void + public function addTo (bagName :String, values :Array) :void { - populate(collName, values, false); + populate(bagName, values, false); } /** - * Merge the specified collection into the other collection. - * The source collection will be destroyed. The elements from - * The source collection will be shuffled and appended to the end - * of the destination collection. + * Merge the specified bag into the other bag. + * The source bag will be destroyed. The elements from + * the source bag will be shuffled and appended to the end + * of the destination bag. */ - public function merge (srcColl :String, intoColl :String) :void + public function merge (srcBag :String, intoBag :String) :void { - _ctrl.callEZCodeFriend("mergeCollection_v1", srcColl, intoColl); + callHostCode("mergeCollection_v1", srcBag, intoBag); } /** - * Pick (do not remove) the specified number of elements from a collection, + * Pick (do not remove) the specified number of elements from a bag, * and distribute them to a specific player or set them as a property * in the game data. * - * @param collName the collection name. + * @param bagName the collection name. * @param count the number of elements to pick * @param msgOrPropName the name of the message or property * that will contain the picked elements. @@ -77,18 +76,18 @@ public class CollectionsControl extends SubControl */ // TODO: a way to specify exclusive picks vs. duplicate-OK picks? public function pick ( - collName :String, count :int, msgOrPropName :String, + bagName :String, count :int, msgOrPropName :String, playerId :int = 0) :void { - getFrom(collName, count, msgOrPropName, playerId, false, null); + getFrom(bagName, count, msgOrPropName, playerId, false, null); } /** - * Deal (remove) the specified number of elements from a collection, + * Deal (remove) the specified number of elements from a bag, * and distribute them to a specific player or set them as a property * in the game data. * - * @param collName the collection name. + * @param bagName the collection name. * @param count the number of elements to pick * @param msgOrPropName the name of the message or property * that will contain the picked elements. @@ -99,10 +98,10 @@ public class CollectionsControl extends SubControl */ // TODO: figure out the method signature of the callback public function deal ( - collName :String, count :int, msgOrPropName :String, + bagName :String, count :int, msgOrPropName :String, callback :Function = null, playerId :int = 0) :void { - getFrom(collName, count, msgOrPropName, playerId, true, callback); + getFrom(bagName, count, msgOrPropName, playerId, true, callback); } @@ -112,19 +111,19 @@ public class CollectionsControl extends SubControl * Helper method for create and addTo. */ protected function populate ( - collName :String, values :Array, clearExisting :Boolean) :void + bagName :String, values :Array, clearExisting :Boolean) :void { - _ctrl.callEZCodeFriend("populateCollection_v1", collName, values, clearExisting); + callHostCode("populateCollection_v1", bagName, values, clearExisting); } /** * Helper method for pick and deal. */ protected function getFrom ( - collName :String, count :int, msgOrPropName :String, playerId :int, + bagName :String, count :int, msgOrPropName :String, playerId :int, consume :Boolean, callback :Function) :void { - _ctrl.callEZCodeFriend("getFromCollection_v2", collName, count, msgOrPropName, + callHostCode("getFromCollection_v2", bagName, count, msgOrPropName, playerId, consume, callback); } } diff --git a/src/as/com/threerings/ezgame/EZEvent.as b/src/as/com/threerings/ezgame/EZEvent.as index dde95fd1..90880a26 100644 --- a/src/as/com/threerings/ezgame/EZEvent.as +++ b/src/as/com/threerings/ezgame/EZEvent.as @@ -30,19 +30,20 @@ public /*abstract*/ class EZEvent extends Event { /** * Access the game control to which this event applies. + * Note: you will need to cast this to the appropriate GameControl type. */ - public function get gameControl () :EZGameControl + public function get gameControl () :AbstractGameControl { - return _ezgame; + return _gameCtrl; } - public function EZEvent (type :String, ezgame :EZGameControl) + public function EZEvent (type :String, gameCtrl :Object) { super(type); - _ezgame = ezgame; + _gameCtrl = gameCtrl as AbstractGameControl; } /** The game control for this event. */ - protected var _ezgame :EZGameControl; + protected var _gameCtrl :AbstractGameControl; } } diff --git a/src/as/com/threerings/ezgame/EZGameControl.as b/src/as/com/threerings/ezgame/EZGameControl.as index a1ac3591..2bb67c77 100644 --- a/src/as/com/threerings/ezgame/EZGameControl.as +++ b/src/as/com/threerings/ezgame/EZGameControl.as @@ -23,113 +23,12 @@ package com.threerings.ezgame { import flash.display.DisplayObject; -import flash.errors.IllegalOperationError; - -import flash.events.Event; -import flash.events.EventDispatcher; -import flash.events.KeyboardEvent; -import flash.events.MouseEvent; - -import flash.geom.Point; - -/** - * Dispatched when a key is pressed when the game has focus. - * - * @eventType flash.events.KeyboardEvent.KEY_DOWN - */ -[Event(name="keyDown", type="flash.events.KeyboardEvent")] - -/** - * Dispatched when a key is released when the game has focus. - * - * @eventType flash.events.KeyboardEvent.KEY_UP - */ -[Event(name="keyUp", type="flash.events.KeyboardEvent")] - -/** - * Dispatched when the size of the game area changes. - * - * @eventType com.threerings.ezgame.SizeChangedEvent.TYPE - */ -[Event(name="SizeChanged", type="com.threerings.ezgame.SizeChangedEvent")] - -/** - * Dispatched when the controller changes for the game. - * - * @eventType com.threerings.ezgame.StateChangedEvent.CONTROL_CHANGED - */ -[Event(name="ControlChanged", type="com.threerings.ezgame.StateChangedEvent")] - -/** - * Dispatched when the game starts, usually after all players are present. - * - * @eventType com.threerings.ezgame.StateChangedEvent.GAME_STARTED - */ -[Event(name="GameStarted", type="com.threerings.ezgame.StateChangedEvent")] - -/** - * Dispatched when a round starts. - * - * @eventType com.threerings.ezgame.StateChangedEvent.ROUND_STARTED - */ -[Event(name="RoundStarted", type="com.threerings.ezgame.StateChangedEvent")] - -/** - * Dispatched when the turn changes in a turn-based game. - * - * @eventType com.threerings.ezgame.StateChangedEvent.TURN_CHANGED - */ -[Event(name="TurnChanged", type="com.threerings.ezgame.StateChangedEvent")] - -/** - * Dispatched when a round ends. - * - * @eventType com.threerings.ezgame.StateChangedEvent.ROUND_ENDED - */ -[Event(name="RoundEnded", type="com.threerings.ezgame.StateChangedEvent")] - -/** - * Dispatched when the game ends. - * - * @eventType com.threerings.ezgame.StateChangedEvent.GAME_ENDED - */ -[Event(name="GameEnded", type="com.threerings.ezgame.StateChangedEvent")] - -/** - * Dispatched when the game client is unloaded and you should clean up any Timers or - * other bits left hanging. - * - * @eventType flash.events.Event.UNLOAD - */ -[Event(name="unload", type="flash.events.Event")] - -/** - * Dispatched when a property has changed in the shared game state. - * - * @eventType com.threerings.ezgame.PropertyChangedEvent.TYPE - */ -[Event(name="PropChanged", type="com.threerings.ezgame.PropertyChangedEvent")] - -/** - * Dispatched when a message arrives with information that is not part of the shared game state. - * - * @eventType com.threerings.ezgame.MessageReceivedEvent.TYPE - */ -[Event(name="msgReceived", type="com.threerings.ezgame.MessageReceivedEvent")] - -/** - * Dispatched when a user chats. - * - * @eventType com.threerings.ezgame.UserChatEvent.TYPE - */ -[Event(name="UserChat", type="com.threerings.ezgame.UserChatEvent")] - /** * The single point of control for each client in your multiplayer EZGame. * * TODO: lots of documentation. */ -public class EZGameControl extends BaseControl +public class EZGameControl extends AbstractGameControl { /** * Create an EZGameControl object using some display object currently on the hierarchy. @@ -138,720 +37,49 @@ public class EZGameControl extends BaseControl * @param autoReady if true, the game will automatically be started when initialization is * complete, if false, the game will not start until all clients call {@link #playerReady}. */ - public function EZGameControl (disp :DisplayObject, autoReady :Boolean) + public function EZGameControl (disp :DisplayObject, autoReady :Boolean = true) { - var event :DynEvent = new DynEvent(); - event.userProps = new Object(); - populateProperties(event.userProps); - event.userProps["autoReady_v1"] = autoReady; - disp.root.loaderInfo.sharedEvents.dispatchEvent(event); - if ("ezProps" in event) { - setEZProps(event.ezProps); - } - - // set up our focusing click handler - disp.root.addEventListener(MouseEvent.CLICK, handleRootClick); - - // set up the unload event to propagate - disp.root.loaderInfo.addEventListener(Event.UNLOAD, dispatch); - - // TODO: this should only be available if the game uses it - _seating = new SeatingControl(this); - } - - // documentation inherited - override public function addEventListener ( - type :String, listener :Function, useCapture :Boolean = false, - priority :int = 0, useWeakReference :Boolean = false) :void - { - super.addEventListener(type, listener, useCapture, priority, useWeakReference); - - switch (type) { - case KeyboardEvent.KEY_UP: - case KeyboardEvent.KEY_DOWN: - if (hasEventListener(type)) { // ensure it was added - callEZCode("alterKeyEvents_v1", type, true); - } - break; - } - } - - // documentation inherited - override public function removeEventListener ( - type :String, listener :Function, useCapture :Boolean = false) :void - { - super.removeEventListener(type, listener, useCapture); - - switch (type) { - case KeyboardEvent.KEY_UP: - case KeyboardEvent.KEY_DOWN: - if (!hasEventListener(type)) { // once it's no longer needed - callEZCode("alterKeyEvents_v1", type, false); - } - break; - } + super(disp, autoReady); } /** - * Are we connected and running inside the EZGame environment, or has someone just loaded up - * this swf by itself? + * Access the 'local' services. */ - public function isConnected () :Boolean + public function get local () :EZLocalSubControl { - return (_gameData != null); + return _localCtrl; } /** - * Get any game-specific configurations that were set up in the lobby. + * Access the 'net' services. */ - public function getConfig () :Object + public function get net () :EZNetSubControl { - return _gameConfig; + return _netCtrl; } /** - * Get the size of the game area, expressed as a Point - * (x = width, y = height). + * Access the 'player' services. */ - public function getSize () :Point + public function get player () :EZPlayerSubControl { - return callEZCode("getSize_v1") as Point; + return _playerCtrl; } /** - * Get the CollectionsControl, which contains methods for utilizing the server to dispatch - * private information. + * Access the 'game' services. */ - public function get collections () :CollectionsControl + public function get game () :EZGameSubControl { - if (_collections == null) { - _collections = new CollectionsControl(this); - } - return _collections; + return _gameCtrl; } /** - * Get the SeatingControl, which contains methods for checking and assigning player seating - * positions. + * Access the 'services' services. */ - public function get seating () :SeatingControl + public function get services () :EZServicesSubControl { - return _seating; + return _servicesCtrl; } - - /** - * Get a property from data. - */ - public function get (propName :String, index :int = -1) :Object - { - checkIsConnected(); - - var value :Object = _gameData[propName]; - if (index >= 0) { - if (value is Array) { - return (value as Array)[index]; - - } else { - throw new ArgumentError("Property " + propName + " is not an array."); - } - } - return value; - } - - /** - * Set a property that will be distributed. - */ - public function set (propName :String, value :Object, index :int = -1) :void - { - callEZCode("setProperty_v1", propName, value, index, false); - } - - /** - * Set a property, but have this client immediately set the value so that it can be - * re-read. The property change event will still arrive and will be your clue as to when the - * other clients will see the newly set value. Be careful with this method, as it can allow - * data inconsistency: two clients may see different values for a property if one of them - * recently set it immediately, and the resultant PropertyChangedEvent's oldValue also may not - * be consistent. - */ - public function setImmediate (propName :String, value :Object, index :int = -1) :void - { - callEZCode("setProperty_v1", propName, value, index, true); - } - - /** - * Set a property that will be distributed, but only if it's equal to the specified test value. - * - *

Please note that, unlike in the standard set() function, the property will not be - * updated right away, but will require a request to the server and a response back. For this - * reason, there may be a considerable delay between calling testAndSet, and seeing the result - * of the update. - * - *

The operation is 'atomic', in the sense that testing and setting take place during the - * same server event. In comparison, a separate 'get' followed by a 'set' operation would - * involve two events with two network round-trips, and no guarantee that the value won't - * change between the events. - */ - public function testAndSet ( - propName :String, newValue :Object, testValue :Object, index :int = -1) :void - { - callEZCode("testAndSetProperty_v1", propName, newValue, testValue, index); - } - - /** - * Execute the specified function as a batch of commands that will be sent to the server - * together. This is no different from executing the commands outside of a batch, but - * may result in better use of the network and should be used if setting a number of things - * at once. - * - * Example: - * _ctrl.doBatch(function () :void { - * _ctrl.set("board", new Array()); - * _ctrl.set("scores", new Array()); - * _ctrl.set("captures", 0); - * }); - */ - public function doBatch (fn :Function) :void - { - callEZCode("startTransaction"); - try { - fn(); - } finally { - callEZCode("commitTransaction"); - } - } - - /** - * Get the names of all currently-set properties that begin with the specified prefix. - */ - public function getPropertyNames (prefix :String = "") :Array - { - var props :Array = []; - for (var s :String in _gameData) { - if (s.lastIndexOf(prefix, 0) == 0) { - props.push(s); - } - } - return props; - } - - /** - * Register an object to receive whatever events it should receive, based on which event - * listeners it implements. - */ - public function registerListener (obj :Object) :void - { - if (obj is MessageReceivedListener) { - var mrl :MessageReceivedListener = (obj as MessageReceivedListener); - addEventListener(MessageReceivedEvent.TYPE, mrl.messageReceived, false, 0, true); - } - if (obj is PropertyChangedListener) { - var pcl :PropertyChangedListener = (obj as PropertyChangedListener); - addEventListener(PropertyChangedEvent.TYPE, pcl.propertyChanged, false, 0, true); - } - if (obj is StateChangedListener) { - var scl :StateChangedListener = (obj as StateChangedListener); - addEventListener(StateChangedEvent.CONTROL_CHANGED, scl.stateChanged, false, 0, true); - addEventListener(StateChangedEvent.GAME_STARTED, scl.stateChanged, false, 0, true); - addEventListener(StateChangedEvent.ROUND_STARTED, scl.stateChanged, false, 0, true); - addEventListener(StateChangedEvent.TURN_CHANGED, scl.stateChanged, false, 0, true); - addEventListener(StateChangedEvent.ROUND_ENDED, scl.stateChanged, false, 0, true); - addEventListener(StateChangedEvent.GAME_ENDED, scl.stateChanged, false, 0, true); - } - if (obj is OccupantChangedListener) { - var ocl :OccupantChangedListener = (obj as OccupantChangedListener); - addEventListener(OccupantChangedEvent.OCCUPANT_ENTERED, ocl.occupantEntered, - false, 0, true); - addEventListener(OccupantChangedEvent.OCCUPANT_LEFT, ocl.occupantLeft, false, 0, true); - } - } - - /** - * Unregister the specified object from receiving events. - */ - public function unregisterListener (obj :Object) :void - { - if (obj is MessageReceivedListener) { - var mrl :MessageReceivedListener = (obj as MessageReceivedListener); - removeEventListener( - MessageReceivedEvent.TYPE, mrl.messageReceived); - } - if (obj is PropertyChangedListener) { - var pcl :PropertyChangedListener = (obj as PropertyChangedListener); - removeEventListener( - PropertyChangedEvent.TYPE, pcl.propertyChanged); - } - if (obj is StateChangedListener) { - var scl :StateChangedListener = (obj as StateChangedListener); - removeEventListener(StateChangedEvent.GAME_STARTED, scl.stateChanged); - removeEventListener(StateChangedEvent.ROUND_STARTED, scl.stateChanged); - removeEventListener(StateChangedEvent.TURN_CHANGED, scl.stateChanged); - removeEventListener(StateChangedEvent.ROUND_ENDED, scl.stateChanged); - removeEventListener(StateChangedEvent.GAME_ENDED, scl.stateChanged); - } - if (obj is OccupantChangedListener) { - var ocl :OccupantChangedListener = (obj as OccupantChangedListener); - removeEventListener(OccupantChangedEvent.OCCUPANT_ENTERED, ocl.occupantEntered); - removeEventListener(OccupantChangedEvent.OCCUPANT_LEFT, ocl.occupantLeft); - } - } - - /** - * If the game was not configured to auto-start, all clients must call this function to let the - * server know that they are ready, at which point the game will be started. Once a game is - * over, all clients can call this function again to start a new game. - */ - public function playerReady () :void - { - callEZCode("playerReady_v1"); - } - - /** - * Requests a set of random letters from the dictionary service. The letters will arrive in a - * separate message with the specified key, as an array of strings. - * - * @param locale RFC 3066 string that represents language settings - * @param dictionary the dictionary to use, or null for the default. - * TODO: document possible parameters. - * @param count the number of letters to be produced - * @param callback the function that will process the results, of the form: - *

function (letters :Array) :void
- * where letters is an array of strings containing letters for the given language settings - * (potentially empty). - */ - public function getDictionaryLetterSet ( - locale :String, dictionary :String, count :int, callback :Function) :void - { - callEZCode("getDictionaryLetterSet_v2", locale, dictionary, count, callback); - } - - /** - * Checks to see if the dictionary for the given locale contains the given word. - * - * @param locale RFC 3066 string that represents language settings - * @param dictionary the dictionary to use, or null for the default. - * TODO: document possible parameters. - * @param word the string contains the word to be checked - * @param callback the function that will process the results, of the form: - *
function (word :String, result :Boolean) :void
- * where word is a copy of the word that was requested, and result specifies whether the word - * is valid given language settings - */ - public function checkDictionaryWord ( - locale :String, dictionary :String, word :String, callback :Function) :void - { - callEZCode("checkDictionaryWord_v2", locale, dictionary, word, callback); - } - - /** - * Send a "message" to other clients subscribed to the game. These is similar to setting a - * property, except that the value will not be saved- it will merely end up coming out as a - * MessageReceivedEvent. - * - * @param messageName The message to send. - * @param value The value to attach to the message. - * @param playerId if 0 (or unset), sends to all players, otherwise the message will be private - * to just one player - */ - public function sendMessage (messageName :String, value :Object, playerId :int = 0) :void - { - callEZCode("sendMessage_v2", messageName, value, playerId); - } - - /** - * Start the ticker with the specified name. The ticker will deliver messages to all connected - * clients at the specified delay. The value of each message is a single integer, - * starting with 0 and increasing by 1 with each messsage. - */ - public function startTicker (tickerName :String, msOfDelay :int) :void - { - callEZCode("setTicker_v1", tickerName, msOfDelay); - } - - /** - * Stop the specified ticker. - */ - public function stopTicker (tickerName :String) :void - { - startTicker(tickerName, 0); - } - - /** - * Send a message that will be heard by everyone in the game room, even observers. - */ - public function sendChat (msg :String) :void - { - callEZCode("sendChat_v1", msg); - } - - /** - * Display the specified message immediately locally: not sent to any other players or - * observers in the game room. - */ - public function localChat (msg :String) :void - { - callEZCode("localChat_v1", msg); - } - - /** - * Run the specified text through the user's chat filter. This is not necessary for sendChat, - * but may be desirable for other user-entered text. - * - * @return the filtered text, or null if it was so bad it's gone. - */ - public function filter (text :String) :String - { - return (callEZCode("filter_v1", text) as String); - } - - /** - * Returns the player ids of all occupants in the game room. - */ - public function getOccupantIds () :Array /* of playerId */ - { - return (callEZCode("getOccupants_v1") as Array); - } - - /** - * Get the display name of the specified occupant. Two players may have the same name: always - * use playerId to purposes of identification and comparison. The name is for display - * only. Will be null is the specified playerId is not in the game. - */ - public function getOccupantName (playerId :int) :String - { - return String(callEZCode("getOccupantName_v1", playerId)); - } - - /** - * Returns this client's player id. - */ - public function getMyId () :int - { - return int(callEZCode("getMyId_v1")); - } - - /** - * Returns true if we are in control of this game. False if another client is in control. - */ - public function amInControl () :Boolean - { - return getControllerId() == getMyId(); - } - - /** - * Returns the player id of the client that is in control of this game. - */ - public function getControllerId () :int - { - return int(callEZCode("getControllerId_v1")); - } - - /** - * Returns the player id of the current turn holder, or 0 if it's nobody's turn. - */ - public function getTurnHolder () :int - { - return int(callEZCode("getTurnHolder_v1")); - } - - /** - * Returns the current round number. Rounds start at 1 and increase if the game calls {@link - * #endRound} with a next round timeout. Between rounds, it returns a negative number, - * corresponding to the negation of the round that just ended. - */ - public function getRound () :int - { - return int(callEZCode("getRound_v1")); - } - - /** - * Get the user-specific game data for the specified user. The first time this is requested per - * game instance it will be retrieved from the database. After that, it will be returned from - * memory. - */ - public function getUserCookie (occupantId :int, callback :Function) :void - { - callEZCode("getUserCookie_v2", occupantId, callback); - } - - /** - * Store persistent data that can later be retrieved by an instance of this game. The maximum - * size of this data is 4096 bytes AFTER AMF3 encoding. Note: there is no playerId parameter - * because a cookie may only be stored for the current player. - * - * @return false if the cookie could not be encoded to 4096 bytes or less; true if the cookie - * is going to try to be saved. There is no guarantee it will be saved and no way to find out - * if it failed, but if it fails it will be because the shit hit the fan so hard that there's - * nothing you can do anyway. - */ - public function setUserCookie (cookie :Object) :Boolean - { - return Boolean(callEZCode("setUserCookie_v1", cookie)); - } - - /** - * A convenience method to just check if it's our turn. - */ - public function isMyTurn () :Boolean - { - return Boolean(callEZCode("isMyTurn_v1")); - } - - /** - * Is the game currently in play? - */ - public function isInPlay () :Boolean - { - return Boolean(callEZCode("isInPlay_v1")); - } - - /** - * Start the next player's turn. If a playerId is specified, that player's turn will be - * next. Otherwise the turn will progress to the next natural turn holder (following - * seating order) or be assigned randomly if the game is just starting. - */ - public function startNextTurn (nextPlayerId :int = 0) :void - { - callEZCode("startNextTurn_v1", nextPlayerId); - } - - /** - * Ends the current round. If nextRoundDelay is greater than zero, the next round will be - * started in the specified number of seconds, otherwise no next round will be started. This - * method should not be called at the end of the last round, instead endGame() - * should be called. - */ - public function endRound (nextRoundDelay :int = 0) :void - { - callEZCode("endRound_v1", nextRoundDelay); - } - - /** - * End the game. The specified player ids are winners! - */ - public function endGame (winnerIds :Array) :void - { - callEZCode("endGame_v2", winnerIds); - } - - /** - * Requests to start the game again in the specified number of seconds. This should only be - * used for party games. Seated table games should have each player report that they are ready - * again and the game will automatically start. - */ - public function restartGameIn (seconds :int) :void - { - callEZCode("restartGameIn_v1", seconds); - } - - /** - * Populate any properties or functions we want to expose to the other side of the ezgame - * security boundary. - */ - protected function populateProperties (o :Object) :void - { - o["connectionClosed_v1"] = connectionClosed_v1; - o["propertyWasSet_v1"] = propertyWasSet_v1; - o["controlDidChange_v1"] = controlDidChange_v1; - o["turnDidChange_v1"] = turnDidChange_v1; - o["messageReceived_v1"] = messageReceived_v1; - o["gameStateChanged_v1"] = gameStateChanged_v1; - o["roundStateChanged_v1"] = roundStateChanged_v1; - o["dispatchEvent_v1"] = dispatch; - o["occupantChanged_v1"] = occupantChanged_v1; - o["userChat_v1"] = userChat_v1; - o["sizeChanged_v1"] = sizeChanged_v1; - } - - /** - * Private method called when the backend disconnects from us. - */ - private function connectionClosed_v1 () :void - { - _gameData = null; - } - - /** - * Private method to post a PropertyChangedEvent. - */ - private function propertyWasSet_v1 ( - name :String, newValue :Object, oldValue :Object, index :int) :void - { - dispatch(new PropertyChangedEvent(this, name, newValue, oldValue, index)); - } - - /** - * Private method to post a StateChangedEvent. - */ - private function controlDidChange_v1 () :void - { - dispatch(new StateChangedEvent(StateChangedEvent.CONTROL_CHANGED, this)); - } - - /** - * Private method to post a StateChangedEvent. - */ - private function turnDidChange_v1 () :void - { - dispatch(new StateChangedEvent(StateChangedEvent.TURN_CHANGED, this)); - } - - /** - * Private method to post a MessageReceivedEvent. - */ - private function messageReceived_v1 (name :String, value :Object) :void - { - dispatch(new MessageReceivedEvent(this, name, value)); - } - - /** - * Private method to post a StateChangedEvent. - */ - private function gameStateChanged_v1 (started :Boolean) :void - { - dispatch(new StateChangedEvent(started ? StateChangedEvent.GAME_STARTED : - StateChangedEvent.GAME_ENDED, this)); - } - - /** - * Private method to post a StateChangedEvent. - */ - private function roundStateChanged_v1 (started :Boolean) :void - { - dispatch(new StateChangedEvent(started ? StateChangedEvent.ROUND_STARTED : - StateChangedEvent.ROUND_ENDED, this)); - } - - /** - * Private method to post a OccupantEvent. - */ - private function occupantChanged_v1 (occupantId :int, player :Boolean, enter :Boolean) :void - { - dispatch(new OccupantChangedEvent( - enter ? OccupantChangedEvent.OCCUPANT_ENTERED : - OccupantChangedEvent.OCCUPANT_LEFT, this, occupantId, player)); - } - - /** - * Private method to post a UserChatEvent. - */ - private function userChat_v1 (speaker :int, message :String) :void - { - dispatch(new UserChatEvent(this, speaker, message)); - } - - /** - * Private method to generate a SizeChangedEvent. - */ - private function sizeChanged_v1 (size :Point) :void - { - dispatch(new SizeChangedEvent(this, size)); - } - - /** - * Sets the properties we received from the EZ game framework on the other side of the security - * boundary. - */ - protected function setEZProps (o :Object) :void - { - // get our gamedata - _gameData = o.gameData; - if (o.gameConfig != null) { - _gameConfig = o.gameConfig; - } - - // and functions - _funcs = o; - } - - /** - * Call a method across the security boundary. - */ - protected function callEZCode (name :String, ... args) :* - { - if (_funcs != null) { - try { - var func :Function = (_funcs[name] as Function); - if (func != null) { - return func.apply(null, args); - } - } catch (err :Error) { - trace(err.getStackTrace()); - trace("--"); - throw new Error("Unable to call host code: " + err.message); - } - - } else { - // if _funcs is null, this will almost certainly throw an error.. - checkIsConnected(); - } - } - - /** - * A "friend" version of callEZCode for subControls. - */ - internal function callEZCodeFriend (name :String, ... args) :* - { - // var args - args.unshift(name); - return callEZCode.apply(this, args); - } - - /** - * Throw an error if we're not connected. - */ - protected function checkIsConnected () :void - { - if (!isConnected()) { - throw new IllegalOperationError( - "The game is not connected to The Whirled, please check isConnected(). " + - "If false, your game is being viewed standalone and should adjust."); - } - } - - /** - * Internal method that is called whenever the mouse clicks our root. - */ - protected function handleRootClick (evt :MouseEvent) :void - { - if (!isConnected()) { - return; - } - try { - if (evt.target.stage == null || evt.target.stage.focus != null) { - return; - } - } catch (err :SecurityError) { - } - callEZCode("focusContainer_v1"); - } - - /** Contains the data properties shared by all players in the game. */ - protected var _gameData :Object; - - /** Contains any custom game configuration data. */ - protected var _gameConfig :Object = {}; - - /** Contains functions exposed to us from the EZGame host. */ - protected var _funcs :Object; - - /** Sub-controls. */ - protected var _collections :CollectionsControl; - protected var _seating :SeatingControl; } } - -import flash.events.Event; - -dynamic class DynEvent extends Event -{ - public function DynEvent () - { - super("ezgameQuery", true, false); - } - - override public function clone () :Event - { - return new DynEvent(); - } -} diff --git a/src/as/com/threerings/ezgame/EZGameSubControl.as b/src/as/com/threerings/ezgame/EZGameSubControl.as new file mode 100644 index 00000000..af9bebf8 --- /dev/null +++ b/src/as/com/threerings/ezgame/EZGameSubControl.as @@ -0,0 +1,339 @@ +// +// $Id: SeatingControl.as 271 2007-04-07 00:25:58Z dhoover $ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +/** + * Dispatched when the controller changes for the game. + * + * @eventType com.threerings.ezgame.StateChangedEvent.CONTROL_CHANGED + */ +[Event(name="ControlChanged", type="com.threerings.ezgame.StateChangedEvent")] + +/** + * Dispatched when the game starts, usually after all players are present. + * + * @eventType com.threerings.ezgame.StateChangedEvent.GAME_STARTED + */ +[Event(name="GameStarted", type="com.threerings.ezgame.StateChangedEvent")] + +/** + * Dispatched when a round starts. + * + * @eventType com.threerings.ezgame.StateChangedEvent.ROUND_STARTED + */ +[Event(name="RoundStarted", type="com.threerings.ezgame.StateChangedEvent")] + +/** + * Dispatched when the turn changes in a turn-based game. + * + * @eventType com.threerings.ezgame.StateChangedEvent.TURN_CHANGED + */ +[Event(name="TurnChanged", type="com.threerings.ezgame.StateChangedEvent")] + +/** + * Dispatched when a round ends. + * + * @eventType com.threerings.ezgame.StateChangedEvent.ROUND_ENDED + */ +[Event(name="RoundEnded", type="com.threerings.ezgame.StateChangedEvent")] + +/** + * Dispatched when the game ends. + * + * @eventType com.threerings.ezgame.StateChangedEvent.GAME_ENDED + */ +[Event(name="GameEnded", type="com.threerings.ezgame.StateChangedEvent")] + +/** + * Dispatched when an occupant enters the game. + * + * @eventType com.threerings.ezgame.OccupantChangedEvent.OCCUPANT_ENTERED + */ +[Event(name="OccupantEntered", type="com.threerings.ezgame.OccupantChangedEvent")] + +/** + * Dispatched when an occupant leaves the game. + * + * @eventType com.threerings.ezgame.OccupantChangedEvent.OCCUPANT_LEFT + */ +[Event(name="OccupantLeft", type="com.threerings.ezgame.OccupantChangedEvent")] + +/** + * Dispatched when a user chats. + * + * @eventType com.threerings.ezgame.UserChatEvent.TYPE + */ +[Event(name="UserChat", type="com.threerings.ezgame.UserChatEvent")] + +/** + * Access game-specific controls. + */ +public class EZGameSubControl extends AbstractSubControl +{ + public function EZGameSubControl (parent :AbstractGameControl) + { + super(parent); + + _seatingCtrl = createSeatingControl(); + } + + /** + * Access the 'seating' subcontrol. + */ + public function get seating () :EZSeatingSubControl + { + // TODO: this should return null for PARTY games + return _seatingCtrl; + } + + /** + * Get any game-specific configurations that were set up in the lobby. + */ + public function getConfig () :Object + { + return _gameConfig; + } + + /** + * Send a system chat message that will be seen by everyone in the game room, + * even observers. + */ + public function systemMessage (msg :String) :void + { + callHostCode("sendChat_v1", msg); + } + + /** + * If the game was not configured to auto-start, all clients must call this function to let the + * server know that they are ready, at which point the game will be started. Once a game is + * over, all clients can call this function again to start a new game. + */ + public function playerReady () :void + { + callHostCode("playerReady_v1"); + } + + /** + * Returns the player ids of all occupants in the game room. + */ + public function getOccupantIds () :Array /* of playerId */ + { + return (callHostCode("getOccupants_v1") as Array); + } + + /** + * Get the display name of the specified occupant. Two players may have the same name: always + * use playerId to purposes of identification and comparison. The name is for display + * only. Will be null is the specified playerId is not in the game. + */ + public function getOccupantName (playerId :int) :String + { + return String(callHostCode("getOccupantName_v1", playerId)); + } + + /** + * Returns this client's player id. + */ + public function getMyId () :int + { + return int(callHostCode("getMyId_v1")); + } + + /** + * Returns true if we are in control of this game. False if another client is in control. + */ + public function amInControl () :Boolean + { + return getControllerId() == getMyId(); + } + + /** + * Returns the player id of the client that is in control of this game. + */ + public function getControllerId () :int + { + return int(callHostCode("getControllerId_v1")); + } + + /** + * Returns the player id of the current turn holder, or 0 if it's nobody's turn. + */ + public function getTurnHolder () :int + { + return int(callHostCode("getTurnHolder_v1")); + } + + /** + * Returns the current round number. Rounds start at 1 and increase if the game calls {@link + * #endRound} with a next round timeout. Between rounds, it returns a negative number, + * corresponding to the negation of the round that just ended. + */ + public function getRound () :int + { + return int(callHostCode("getRound_v1")); + } + + /** + * A convenience method to just check if it's our turn. + */ + public function isMyTurn () :Boolean + { + return Boolean(callHostCode("isMyTurn_v1")); + } + + /** + * Is the game currently in play? + */ + public function isInPlay () :Boolean + { + return Boolean(callHostCode("isInPlay_v1")); + } + + /** + * Start the next player's turn. If a playerId is specified, that player's turn will be + * next. Otherwise the turn will progress to the next natural turn holder (following + * seating order) or be assigned randomly if the game is just starting. + */ + public function startNextTurn (nextPlayerId :int = 0) :void + { + callHostCode("startNextTurn_v1", nextPlayerId); + } + + /** + * Ends the current round. If nextRoundDelay is greater than zero, the next round will be + * started in the specified number of seconds, otherwise no next round will be started. This + * method should not be called at the end of the last round, instead endGame() + * should be called. + */ + public function endRound (nextRoundDelay :int = 0) :void + { + callHostCode("endRound_v1", nextRoundDelay); + } + + /** + * End the game. The specified player ids are winners! + */ + public function endGame (winnerIds :Array) :void + { + callHostCode("endGame_v2", winnerIds); + } + + /** + * Requests to start the game again in the specified number of seconds. This should only be + * used for party games. Seated table games should have each player report that they are ready + * again and the game will automatically start. + */ + public function restartGameIn (seconds :int) :void + { + callHostCode("restartGameIn_v1", seconds); + } + + /** + * Create the 'seating' subcontrol. + */ + protected function createSeatingControl () :EZSeatingSubControl + { + return new EZSeatingSubControl(_parent, this); + } + + override protected function populateProperties (o :Object) :void + { + super.populateProperties(o); + + o["controlDidChange_v1"] = controlDidChange_v1; + o["turnDidChange_v1"] = turnDidChange_v1; + o["gameStateChanged_v1"] = gameStateChanged_v1; + o["roundStateChanged_v1"] = roundStateChanged_v1; + o["occupantChanged_v1"] = occupantChanged_v1; + o["userChat_v1"] = userChat_v1; + + _seatingCtrl.populatePropertiesFriend(o); + } + + override protected function setHostProps (o :Object) :void + { + super.setHostProps(o); + + _gameConfig = o.gameConfig; + + _seatingCtrl.setHostPropsFriend(o); + } + + /** + * Private method to post a StateChangedEvent. + */ + private function controlDidChange_v1 () :void + { + dispatch(new StateChangedEvent(StateChangedEvent.CONTROL_CHANGED, _parent)); + } + + /** + * Private method to post a StateChangedEvent. + */ + private function turnDidChange_v1 () :void + { + dispatch(new StateChangedEvent(StateChangedEvent.TURN_CHANGED, _parent)); + } + + /** + * Private method to post a StateChangedEvent. + */ + private function gameStateChanged_v1 (started :Boolean) :void + { + dispatch(new StateChangedEvent(started ? StateChangedEvent.GAME_STARTED : + StateChangedEvent.GAME_ENDED, _parent)); + } + + /** + * Private method to post a StateChangedEvent. + */ + private function roundStateChanged_v1 (started :Boolean) :void + { + dispatch(new StateChangedEvent(started ? StateChangedEvent.ROUND_STARTED : + StateChangedEvent.ROUND_ENDED, _parent)); + } + + /** + * Private method to post a OccupantEvent. + */ + private function occupantChanged_v1 (occupantId :int, player :Boolean, enter :Boolean) :void + { + dispatch(new OccupantChangedEvent( + enter ? OccupantChangedEvent.OCCUPANT_ENTERED : + OccupantChangedEvent.OCCUPANT_LEFT, _parent, occupantId, player)); + } + + /** + * Private method to post a UserChatEvent. + */ + private function userChat_v1 (speaker :int, message :String) :void + { + dispatch(new UserChatEvent(_parent, speaker, message)); + } + + /** Contains any custom game configuration data. */ + protected var _gameConfig :Object = {}; + + /** The seating sub-control. */ + protected var _seatingCtrl :EZSeatingSubControl; +} +} diff --git a/src/as/com/threerings/ezgame/EZLocalSubControl.as b/src/as/com/threerings/ezgame/EZLocalSubControl.as new file mode 100644 index 00000000..f2bbaec3 --- /dev/null +++ b/src/as/com/threerings/ezgame/EZLocalSubControl.as @@ -0,0 +1,138 @@ +// +// $Id$ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +/** + * Dispatched when a key is pressed when the game has focus. + * + * @eventType flash.events.KeyboardEvent.KEY_DOWN + */ +[Event(name="keyDown", type="flash.events.KeyboardEvent")] + +/** + * Dispatched when a key is released when the game has focus. + * + * @eventType flash.events.KeyboardEvent.KEY_UP + */ +[Event(name="keyUp", type="flash.events.KeyboardEvent")] + +/** + * Dispatched when the size of the game area changes. + * + * @eventType com.threerings.ezgame.SizeChangedEvent.TYPE + */ +[Event(name="SizeChanged", type="com.threerings.ezgame.SizeChangedEvent")] + + +import flash.events.KeyboardEvent; + +import flash.geom.Point; + +/** + * Access local properties of the game. + */ +public class EZLocalSubControl extends AbstractSubControl +{ + public function EZLocalSubControl (parent :AbstractGameControl) + { + super(parent); + } + + // documentation inherited + override public function addEventListener ( + type :String, listener :Function, useCapture :Boolean = false, + priority :int = 0, useWeakReference :Boolean = false) :void + { + super.addEventListener(type, listener, useCapture, priority, useWeakReference); + + switch (type) { + case KeyboardEvent.KEY_UP: + case KeyboardEvent.KEY_DOWN: + if (hasEventListener(type)) { // ensure it was added + callHostCode("alterKeyEvents_v1", type, true); + } + break; + } + } + + // documentation inherited + override public function removeEventListener ( + type :String, listener :Function, useCapture :Boolean = false) :void + { + super.removeEventListener(type, listener, useCapture); + + switch (type) { + case KeyboardEvent.KEY_UP: + case KeyboardEvent.KEY_DOWN: + if (!hasEventListener(type)) { // once it's no longer needed + callHostCode("alterKeyEvents_v1", type, false); + } + break; + } + } + + /** + * Get the size of the game area, expressed as a Point + * (x = width, y = height). + */ + public function getSize () :Point + { + return callHostCode("getSize_v1") as Point; + } + + /** + * Display a feedback system chat message for the local player only, no other players + * or observers will see it. + */ + public function feedback (msg :String) :void + { + callHostCode("localChat_v1", msg); + } + + /** + * Run the specified text through the user's chat filter. This is optional, you can use + * it to clean up user-entered text. + * + * @return the filtered text, or null if it was so bad it's gone. + */ + public function filter (text :String) :String + { + return (callHostCode("filter_v1", text) as String); + } + + override protected function populateProperties (o :Object) :void + { + super.populateProperties(o); + + o["dispatchEvent_v1"] = dispatch; // for re-dispatching key events + o["sizeChanged_v1"] = sizeChanged_v1; + } + + /** + * Private method to generate a SizeChangedEvent. + */ + private function sizeChanged_v1 (size :Point) :void + { + dispatch(new SizeChangedEvent(_parent, size)); + } +} +} diff --git a/src/as/com/threerings/ezgame/EZNetSubControl.as b/src/as/com/threerings/ezgame/EZNetSubControl.as new file mode 100644 index 00000000..43ab5ea6 --- /dev/null +++ b/src/as/com/threerings/ezgame/EZNetSubControl.as @@ -0,0 +1,171 @@ +// +// $Id$ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +/** + * Dispatched when a property has changed in the shared game state. + * + * @eventType com.threerings.ezgame.PropertyChangedEvent.TYPE + */ +[Event(name="PropChanged", type="com.threerings.ezgame.PropertyChangedEvent")] + +/** + * Dispatched when a message arrives with information that is not part of the shared game state. + * + * @eventType com.threerings.ezgame.MessageReceivedEvent.TYPE + */ +[Event(name="msgReceived", type="com.threerings.ezgame.MessageReceivedEvent")] + +/** + * Provides access to 'net' game services. + */ +public class EZNetSubControl extends AbstractSubControl +{ + public function EZNetSubControl (parent :AbstractGameControl) + { + super(parent); + } + + /** + * Get a property from data. + */ + public function get (propName :String, index :int = -1) :Object + { + checkIsConnected(); + + var value :Object = _gameData[propName]; + if (index >= 0) { + if (value is Array) { + return (value as Array)[index]; + + } else { + throw new ArgumentError("Property " + propName + " is not an array."); + } + } + return value; + } + + /** + * Set a property that will be distributed. + */ + public function set (propName :String, value :Object, index :int = -1) :void + { + callHostCode("setProperty_v1", propName, value, index, false); + } + + /** + * Set a property, but have this client immediately set the value so that it can be + * re-read. The property change event will still arrive and will be your clue as to when the + * other clients will see the newly set value. Be careful with this method, as it can allow + * data inconsistency: two clients may see different values for a property if one of them + * recently set it immediately, and the resultant PropertyChangedEvent's oldValue also may not + * be consistent. + */ + public function setImmediate (propName :String, value :Object, index :int = -1) :void + { + callHostCode("setProperty_v1", propName, value, index, true); + } + + /** + * Set a property that will be distributed, but only if it's equal to the specified test value. + * + *

Please note that, unlike in the standard set() function, the property will not be + * updated right away, but will require a request to the server and a response back. For this + * reason, there may be a considerable delay between calling testAndSet, and seeing the result + * of the update. + * + *

The operation is 'atomic', in the sense that testing and setting take place during the + * same server event. In comparison, a separate 'get' followed by a 'set' operation would + * involve two events with two network round-trips, and no guarantee that the value won't + * change between the events. + */ + public function testAndSet ( + propName :String, newValue :Object, testValue :Object, index :int = -1) :void + { + callHostCode("testAndSetProperty_v1", propName, newValue, testValue, index); + } + + /** + * Get the names of all currently-set properties that begin with the specified prefix. + */ + public function getPropertyNames (prefix :String = "") :Array + { + var props :Array = []; + for (var s :String in _gameData) { + if (s.lastIndexOf(prefix, 0) == 0) { + props.push(s); + } + } + return props; + } + + /** + * Send a "message" to other clients subscribed to the game. These is similar to setting a + * property, except that the value will not be saved- it will merely end up coming out as a + * MessageReceivedEvent. + * + * @param messageName The message to send. + * @param value The value to attach to the message. + * @param playerId if 0 (or unset), sends to all players, otherwise the message will be private + * to just one player + */ + public function sendMessage (messageName :String, value :Object, playerId :int = 0) :void + { + callHostCode("sendMessage_v2", messageName, value, playerId); + } + + override protected function populateProperties (o :Object) :void + { + super.populateProperties(o); + + o["propertyWasSet_v1"] = propertyWasSet_v1; + o["messageReceived_v1"] = messageReceived_v1; + } + + override protected function setHostProps (o :Object) :void + { + super.setHostProps(o); + + _gameData = o.gameData; + } + + /** + * Private method to post a PropertyChangedEvent. + */ + private function propertyWasSet_v1 ( + name :String, newValue :Object, oldValue :Object, index :int) :void + { + dispatch(new PropertyChangedEvent(_parent, name, newValue, oldValue, index)); + } + + /** + * Private method to post a MessageReceivedEvent. + */ + private function messageReceived_v1 (name :String, value :Object) :void + { + dispatch(new MessageReceivedEvent(_parent, name, value)); + } + + /** Game properties. */ + protected var _gameData :Object; +} +} diff --git a/src/as/com/threerings/ezgame/EZPlayerSubControl.as b/src/as/com/threerings/ezgame/EZPlayerSubControl.as new file mode 100644 index 00000000..48074d6d --- /dev/null +++ b/src/as/com/threerings/ezgame/EZPlayerSubControl.as @@ -0,0 +1,59 @@ +// +// $Id$ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +/** + * Provides access to 'player' game services. + */ +public class EZPlayerSubControl extends AbstractSubControl +{ + public function EZPlayerSubControl (parent :AbstractGameControl) + { + super(parent); + } + + /** + * Get the user-specific game data for the specified user. The first time this is requested per + * game instance it will be retrieved from the database. After that, it will be returned from + * memory. + */ + public function getUserCookie (occupantId :int, callback :Function) :void + { + callHostCode("getUserCookie_v2", occupantId, callback); + } + + /** + * Store persistent data that can later be retrieved by an instance of this game. The maximum + * size of this data is 4096 bytes AFTER AMF3 encoding. Note: there is no playerId parameter + * because a cookie may only be stored for the current player. + * + * @return false if the cookie could not be encoded to 4096 bytes or less; true if the cookie + * is going to try to be saved. There is no guarantee it will be saved and no way to find out + * if it failed, but if it fails it will be because the shit hit the fan so hard that there's + * nothing you can do anyway. + */ + public function setUserCookie (cookie :Object) :Boolean + { + return Boolean(callHostCode("setUserCookie_v1", cookie)); + } +} +} diff --git a/src/as/com/threerings/ezgame/SeatingControl.as b/src/as/com/threerings/ezgame/EZSeatingSubControl.as similarity index 71% rename from src/as/com/threerings/ezgame/SeatingControl.as rename to src/as/com/threerings/ezgame/EZSeatingSubControl.as index c962ebef..e480b3a5 100644 --- a/src/as/com/threerings/ezgame/SeatingControl.as +++ b/src/as/com/threerings/ezgame/EZSeatingSubControl.as @@ -1,5 +1,5 @@ // -// $Id$ +// $Id: SeatingControl.as 271 2007-04-07 00:25:58Z dhoover $ // // Vilya library - tools for developing networked games // Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved @@ -21,11 +21,17 @@ package com.threerings.ezgame { -public class SeatingControl extends SubControl + +/** + * Access seating information for a seated game. + */ +// TODO: methods for allowing a player to pick a seat in SEATED_CONTINUOUS games. +public class EZSeatingSubControl extends AbstractSubControl { - public function SeatingControl (ctrl :EZGameControl) + public function EZSeatingSubControl (parent :AbstractControl, game :EZGameSubControl) { - super(ctrl); + super(parent); + _game = game; } /** @@ -33,7 +39,7 @@ public class SeatingControl extends SubControl */ public function getPlayerPosition (playerId :int) :int { - return int(_ctrl.callEZCodeFriend("getPlayerPosition_v1", playerId)); + return int(callHostCode("getPlayerPosition_v1", playerId)); } /** @@ -42,7 +48,7 @@ public class SeatingControl extends SubControl */ public function getMyPosition () :int { - return int(_ctrl.callEZCodeFriend("getMyPosition_v1")); + return int(callHostCode("getMyPosition_v1")); } /** @@ -51,7 +57,7 @@ public class SeatingControl extends SubControl */ public function getPlayerIds () :Array /* of playerId (int) */ { - return (_ctrl.callEZCodeFriend("getPlayers_v1") as Array); + return (callHostCode("getPlayers_v1") as Array); } /** @@ -62,11 +68,12 @@ public class SeatingControl extends SubControl return getPlayerIds().map( function (playerId :int, o2:*, o3:*) :String { - return _ctrl.getOccupantName(playerId); + return _game.getOccupantName(playerId); } ); } - // TODO: methods for allowing a player to pick a seat + /** Our direct parent. */ + protected var _game :EZGameSubControl; } } diff --git a/src/as/com/threerings/ezgame/EZServicesSubControl.as b/src/as/com/threerings/ezgame/EZServicesSubControl.as new file mode 100644 index 00000000..a60064ab --- /dev/null +++ b/src/as/com/threerings/ezgame/EZServicesSubControl.as @@ -0,0 +1,124 @@ +// +// $Id$ +// +// Vilya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/vilya/ +// +// 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.ezgame { + +/** + * Provides access to 'services' game services. + */ +public class EZServicesSubControl extends AbstractSubControl +{ + public function EZServicesSubControl (parent :AbstractGameControl) + { + super(parent); + + _bagsCtrl = createBagsControl(); + } + + /** + * Access the 'bags' subcontrol. + */ + public function get bags () :EZBagsSubControl + { + return _bagsCtrl; + } + + /** + * Requests a set of random letters from the dictionary service. The letters will arrive in a + * separate message with the specified key, as an array of strings. + * + * @param locale RFC 3066 string that represents language settings + * @param dictionary the dictionary to use, or null for the default. + * TODO: document possible parameters. + * @param count the number of letters to be produced + * @param callback the function that will process the results, of the form: + *

function (letters :Array) :void
+ * where letters is an array of strings containing letters for the given language settings + * (potentially empty). + */ + public function getDictionaryLetterSet ( + locale :String, dictionary :String, count :int, callback :Function) :void + { + callHostCode("getDictionaryLetterSet_v2", locale, dictionary, count, callback); + } + + /** + * Checks to see if the dictionary for the given locale contains the given word. + * + * @param locale RFC 3066 string that represents language settings + * @param dictionary the dictionary to use, or null for the default. + * TODO: document possible parameters. + * @param word the string contains the word to be checked + * @param callback the function that will process the results, of the form: + *
function (word :String, result :Boolean) :void
+ * where word is a copy of the word that was requested, and result specifies whether the word + * is valid given language settings + */ + public function checkDictionaryWord ( + locale :String, dictionary :String, word :String, callback :Function) :void + { + callHostCode("checkDictionaryWord_v2", locale, dictionary, word, callback); + } + + /** + * Start the ticker with the specified name. The ticker will deliver messages to all connected + * clients at the specified delay. The value of each message is a single integer, + * starting with 0 and increasing by 1 with each messsage. + */ + public function startTicker (tickerName :String, msOfDelay :int) :void + { + callHostCode("setTicker_v1", tickerName, msOfDelay); + } + + /** + * Stop the specified ticker. + */ + public function stopTicker (tickerName :String) :void + { + startTicker(tickerName, 0); + } + + /** + * Create the 'bags' subcontrol. + */ + protected function createBagsControl () :EZBagsSubControl + { + return new EZBagsSubControl(_parent); + } + + override protected function populateProperties (o :Object) :void + { + super.populateProperties(o); + + _bagsCtrl.populatePropertiesFriend(o); + } + + override protected function setHostProps (o :Object) :void + { + super.setHostProps(o); + + _bagsCtrl.setHostPropsFriend(o); + } + + /** The bags sub-control. */ + protected var _bagsCtrl :EZBagsSubControl; +} +} diff --git a/src/as/com/threerings/ezgame/MessageReceivedEvent.as b/src/as/com/threerings/ezgame/MessageReceivedEvent.as index bc71a8ee..b55e5870 100644 --- a/src/as/com/threerings/ezgame/MessageReceivedEvent.as +++ b/src/as/com/threerings/ezgame/MessageReceivedEvent.as @@ -45,9 +45,9 @@ public class MessageReceivedEvent extends EZEvent } public function MessageReceivedEvent ( - ezgame :EZGameControl, messageName :String, value :Object) + gameCtrl :Object, messageName :String, value :Object) { - super(TYPE, ezgame); + super(TYPE, gameCtrl); _name = messageName; _value = value; } @@ -60,7 +60,7 @@ public class MessageReceivedEvent extends EZEvent override public function clone () :Event { - return new MessageReceivedEvent(_ezgame, _name, _value); + return new MessageReceivedEvent(_gameCtrl, _name, _value); } protected var _name :String; diff --git a/src/as/com/threerings/ezgame/MessageReceivedListener.as b/src/as/com/threerings/ezgame/MessageReceivedListener.as deleted file mode 100644 index b932ef6e..00000000 --- a/src/as/com/threerings/ezgame/MessageReceivedListener.as +++ /dev/null @@ -1,35 +0,0 @@ -// -// $Id$ -// -// Vilya library - tools for developing networked games -// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved -// http://www.threerings.net/code/vilya/ -// -// 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.ezgame { - -/** - * Implement this interface to automagically be registered to received - * MessageReceivedEvents. - */ -public interface MessageReceivedListener -{ - /** - * Handle a MessageReceivedEvent. - */ - function messageReceived (event :MessageReceivedEvent) :void; -} -} diff --git a/src/as/com/threerings/ezgame/OccupantChangedEvent.as b/src/as/com/threerings/ezgame/OccupantChangedEvent.as index 5c422b7b..7025ff4b 100644 --- a/src/as/com/threerings/ezgame/OccupantChangedEvent.as +++ b/src/as/com/threerings/ezgame/OccupantChangedEvent.as @@ -41,9 +41,9 @@ public class OccupantChangedEvent extends EZEvent } public function OccupantChangedEvent ( - type :String, ezgame :EZGameControl, occupantId :int, player :Boolean) + type :String, gameCtrl :Object, occupantId :int, player :Boolean) { - super(type, ezgame); + super(type, gameCtrl); _occupantId = occupantId; _player = player; } @@ -57,7 +57,7 @@ public class OccupantChangedEvent extends EZEvent override public function clone () :Event { - return new OccupantChangedEvent(type, _ezgame, _occupantId, _player); + return new OccupantChangedEvent(type, _gameCtrl, _occupantId, _player); } protected var _occupantId :int; diff --git a/src/as/com/threerings/ezgame/OccupantChangedListener.as b/src/as/com/threerings/ezgame/OccupantChangedListener.as deleted file mode 100644 index 0c35f84e..00000000 --- a/src/as/com/threerings/ezgame/OccupantChangedListener.as +++ /dev/null @@ -1,30 +0,0 @@ -// -// $Id$ -// -// Vilya library - tools for developing networked games -// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved -// http://www.threerings.net/code/vilya/ -// -// 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.ezgame { - -public interface OccupantChangedListener -{ - function occupantEntered (event :OccupantChangedEvent) :void; - - function occupantLeft (event :OccupantChangedEvent) :void; -} -} diff --git a/src/as/com/threerings/ezgame/PlayersDisplay.as b/src/as/com/threerings/ezgame/PlayersDisplay.as index 13f9f238..a085a25d 100644 --- a/src/as/com/threerings/ezgame/PlayersDisplay.as +++ b/src/as/com/threerings/ezgame/PlayersDisplay.as @@ -40,7 +40,6 @@ import flash.text.TextFieldAutoSize; * extend this class. */ public class PlayersDisplay extends Sprite - implements StateChangedListener { /** * Set the game control that will be used with this display. @@ -48,7 +47,9 @@ public class PlayersDisplay extends Sprite public function setGameControl (gameCtrl :EZGameControl) :void { _gameCtrl = gameCtrl; - _gameCtrl.registerListener(this); + _gameCtrl.game.addEventListener(StateChangedEvent.GAME_STARTED, stateChanged); + _gameCtrl.game.addEventListener(StateChangedEvent.GAME_ENDED, stateChanged); + _gameCtrl.game.addEventListener(StateChangedEvent.TURN_CHANGED, stateChanged); configureInterface(); } @@ -85,11 +86,11 @@ public class PlayersDisplay extends Sprite return; // nothing to do } - var players :Array = _gameCtrl.seating.getPlayerIds(); + var players :Array = _gameCtrl.game.seating.getPlayerIds(); // create a label for each player for each (var playerId :int in players) { - var name :String = _gameCtrl.getOccupantName(playerId); + var name :String = _gameCtrl.game.getOccupantName(playerId); label = createPlayerLabel(playerId, name); icon = createPlayerIcon(playerId, name); var iconW :int = 0; @@ -187,8 +188,8 @@ public class PlayersDisplay extends Sprite */ protected function displayCurrentTurn () :void { - var idx :int = _gameCtrl.isInPlay() ? - _gameCtrl.seating.getPlayerPosition(_gameCtrl.getTurnHolder()) : -1; + var idx :int = _gameCtrl.game.isInPlay() ? + _gameCtrl.game.seating.getPlayerPosition(_gameCtrl.game.getTurnHolder()) : -1; for (var ii :int = 0; ii < _playerLabels.length; ii++) { var label :TextField = (_playerLabels[ii] as TextField); label.backgroundColor = getBackground(ii == idx); diff --git a/src/as/com/threerings/ezgame/PropertyChangedEvent.as b/src/as/com/threerings/ezgame/PropertyChangedEvent.as index 20e07f35..b55c5104 100644 --- a/src/as/com/threerings/ezgame/PropertyChangedEvent.as +++ b/src/as/com/threerings/ezgame/PropertyChangedEvent.as @@ -68,10 +68,10 @@ public class PropertyChangedEvent extends EZEvent * Constructor. */ public function PropertyChangedEvent ( - ezgame :EZGameControl, propName :String, newValue :Object, + gameCtrl :Object, propName :String, newValue :Object, oldValue :Object, index :int = -1) { - super(TYPE, ezgame); + super(TYPE, gameCtrl); _name = propName; _newValue = newValue; _oldValue = oldValue; @@ -86,8 +86,7 @@ public class PropertyChangedEvent extends EZEvent override public function clone () :Event { - return new PropertyChangedEvent( - _ezgame, _name, _newValue, _oldValue, _index); + return new PropertyChangedEvent(_gameCtrl, _name, _newValue, _oldValue, _index); } /** Our implementation details. */ diff --git a/src/as/com/threerings/ezgame/PropertyChangedListener.as b/src/as/com/threerings/ezgame/PropertyChangedListener.as deleted file mode 100644 index e805991b..00000000 --- a/src/as/com/threerings/ezgame/PropertyChangedListener.as +++ /dev/null @@ -1,35 +0,0 @@ -// -// $Id$ -// -// Vilya library - tools for developing networked games -// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved -// http://www.threerings.net/code/vilya/ -// -// 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.ezgame { - -/** - * Implement this interface to automagically be registered to received - * PropertyChangedEvents. - */ -public interface PropertyChangedListener -{ - /** - * Handle a PropertyChangedEvent. - */ - function propertyChanged (event :PropertyChangedEvent) :void; -} -} diff --git a/src/as/com/threerings/ezgame/SizeChangedEvent.as b/src/as/com/threerings/ezgame/SizeChangedEvent.as index 25ce9b7e..4f621d13 100644 --- a/src/as/com/threerings/ezgame/SizeChangedEvent.as +++ b/src/as/com/threerings/ezgame/SizeChangedEvent.as @@ -46,9 +46,9 @@ public class SizeChangedEvent extends EZEvent /** * Constructor. */ - public function SizeChangedEvent (ezgame :EZGameControl, size :Point) + public function SizeChangedEvent (gameCtrl :Object, size :Point) { - super(TYPE, ezgame); + super(TYPE, gameCtrl); _size = size; } @@ -59,7 +59,7 @@ public class SizeChangedEvent extends EZEvent override public function clone () :Event { - return new SizeChangedEvent(_ezgame, _size.clone()); + return new SizeChangedEvent(_gameCtrl, _size.clone()); } /** Our implementation details. */ diff --git a/src/as/com/threerings/ezgame/StateChangedEvent.as b/src/as/com/threerings/ezgame/StateChangedEvent.as index a8d0beeb..13054874 100644 --- a/src/as/com/threerings/ezgame/StateChangedEvent.as +++ b/src/as/com/threerings/ezgame/StateChangedEvent.as @@ -48,9 +48,9 @@ public class StateChangedEvent extends EZEvent // TODO: move to own event? public static const TURN_CHANGED :String = "TurnChanged"; - public function StateChangedEvent (type :String, ezgame :EZGameControl) + public function StateChangedEvent (type :String, gameCtrl :Object) { - super(type, ezgame); + super(type, gameCtrl); } override public function toString () :String @@ -60,7 +60,7 @@ public class StateChangedEvent extends EZEvent override public function clone () :Event { - return new StateChangedEvent(type, _ezgame); + return new StateChangedEvent(type, _gameCtrl); } } } diff --git a/src/as/com/threerings/ezgame/StateChangedListener.as b/src/as/com/threerings/ezgame/StateChangedListener.as deleted file mode 100644 index 82d84dc7..00000000 --- a/src/as/com/threerings/ezgame/StateChangedListener.as +++ /dev/null @@ -1,35 +0,0 @@ -// -// $Id$ -// -// Vilya library - tools for developing networked games -// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved -// http://www.threerings.net/code/vilya/ -// -// 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.ezgame { - -/** - * Implement this interface to automagically be registered to received - * StateChangedEvents. - */ -public interface StateChangedListener -{ - /** - * Handle a StateChangedEvent. - */ - function stateChanged (event :StateChangedEvent) :void; -} -} diff --git a/src/as/com/threerings/ezgame/UserChatEvent.as b/src/as/com/threerings/ezgame/UserChatEvent.as index ad34934e..c816e277 100644 --- a/src/as/com/threerings/ezgame/UserChatEvent.as +++ b/src/as/com/threerings/ezgame/UserChatEvent.as @@ -50,9 +50,9 @@ public class UserChatEvent extends EZEvent /** * Constructor. */ - public function UserChatEvent (ezgame :EZGameControl, speaker :int, message :String) + public function UserChatEvent (gameCtrl :Object, speaker :int, message :String) { - super(TYPE, ezgame); + super(TYPE, gameCtrl); _speaker = speaker; _message = message; } @@ -64,7 +64,7 @@ public class UserChatEvent extends EZEvent override public function clone () :Event { - return new UserChatEvent(_ezgame, _speaker, _message); + return new UserChatEvent(_gameCtrl, _speaker, _message); } /** Our implementation details. */