74665f1663
git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@416 c613c5cb-e716-0410-b11b-feb51c14d237
799 lines
26 KiB
ActionScript
799 lines
26 KiB
ActionScript
//
|
|
// $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;
|
|
import flash.events.KeyboardEvent;
|
|
import flash.events.MouseEvent;
|
|
|
|
import flash.display.DisplayObject;
|
|
|
|
/**
|
|
* 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 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 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
|
|
{
|
|
/**
|
|
* 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 EZGameControl (disp :DisplayObject, autoReady :Boolean)
|
|
{
|
|
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);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Are we connected and running inside the EZGame environment, or has someone just loaded up
|
|
* this swf by itself?
|
|
*/
|
|
public function isConnected () :Boolean
|
|
{
|
|
return (_gameData != null);
|
|
}
|
|
|
|
/**
|
|
* Get any game-specific configurations that were set up in the lobby.
|
|
*/
|
|
public function getConfig () :Object
|
|
{
|
|
return _gameConfig;
|
|
}
|
|
|
|
/**
|
|
* Get the CollectionsControl, which contains methods for utilizing the server to dispatch
|
|
* private information.
|
|
*/
|
|
public function get collections () :CollectionsControl
|
|
{
|
|
if (_collections == null) {
|
|
_collections = new CollectionsControl(this);
|
|
}
|
|
return _collections;
|
|
}
|
|
|
|
/**
|
|
* Get the SeatingControl, which contains methods for checking and assigning player seating
|
|
* positions.
|
|
*/
|
|
public function get seating () :SeatingControl
|
|
{
|
|
return _seating;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* <p> 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.
|
|
*
|
|
* <p> 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 count the number of letters to be produced
|
|
* @param callback the function that will process the results, of the form:
|
|
* <pre>function (letters :Array) :void</pre>
|
|
* where letters is an array of strings containing letters for the given language settings
|
|
* (potentially empty).
|
|
*/
|
|
public function getDictionaryLetterSet (locale :String, count :int, callback :Function) :void
|
|
{
|
|
callEZCode("getDictionaryLetterSet_v1", locale, count, callback);
|
|
}
|
|
|
|
/**
|
|
* 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 RFC 3066 string that represents language settings
|
|
* @param word the string contains the word to be checked
|
|
* @param callback the function that will process the results, of the form:
|
|
* <pre>function (word :String, result :Boolean) :void</pre>
|
|
* 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, word :String, callback :Function) :void
|
|
{
|
|
callEZCode("checkDictionaryWord_v1", locale, 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 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. It will deliver messages to the game object at the
|
|
* specified delay, the value of each message being a single integer, starting with 0 and
|
|
* increasing by one 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 getOccupants () :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.
|
|
*/
|
|
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"));
|
|
}
|
|
|
|
/**
|
|
* End the current turn. If no next player id is specified, then the next player after the
|
|
* current one is used.
|
|
*/
|
|
public function endTurn (nextPlayerId :int = 0) :void
|
|
{
|
|
callEZCode("endTurn_v2", 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.
|
|
*/
|
|
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["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;
|
|
}
|
|
|
|
/**
|
|
* 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));
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
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();
|
|
}
|
|
}
|