Holy crap Batman! It's the beginnings of refactoring the basic puzzle

stuff into Narya.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2876 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2003-11-26 01:42:34 +00:00
parent 0601c94e42
commit 54eaddb27d
53 changed files with 9395 additions and 0 deletions
@@ -0,0 +1,101 @@
//
// $Id: PlayerStatusView.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import javax.swing.JPanel;
import com.threerings.parlor.game.GameObject;
import com.threerings.puzzle.Log;
import com.threerings.puzzle.data.BoardSummary;
import com.threerings.puzzle.data.PuzzleConfig;
import com.threerings.puzzle.data.PuzzleObject;
/**
* The player status view displays a player's current status in the game.
*/
public class PlayerStatusView extends JPanel
{
/**
* Constructs a player status view.
*/
public PlayerStatusView (GameObject gameobj, int pidx)
{
// save off references
_gameobj = gameobj;
_username = _gameobj.players[pidx];
_pidx = pidx;
// configure the panel
setOpaque(false);
}
/**
* Initializes the player status view with the puzzle config.
*/
public void init (PuzzleConfig config)
{
// nothing for now
}
/**
* Get the player index of the player represented by this view.
*/
public int getPlayerIndex ()
{
return _pidx;
}
/**
* Sets the player board summary.
*/
public void setBoardSummary (BoardSummary summary)
{
_summary = summary;
repaint();
}
/**
* Sets the player status.
*/
public void setStatus (int status)
{
_status = status;
repaint();
}
/**
* Sets whether to highlight the player status display when rendered.
*/
public void setHighlighted (boolean highlight)
{
_highlight = highlight;
repaint();
}
/** Returns a string representation of this instance. */
public String toString ()
{
return "[user=" + _username + ", pidx=" + _pidx +
", status=" + _status + "]";
}
/** The game object associated with this view. */
protected GameObject _gameobj;
/** The player name. */
protected String _username;
/** The player index. */
protected int _pidx;
/** Whether this display is highlighted. */
protected boolean _highlight;
/** The player board summary. */
protected BoardSummary _summary;
/** The player game status. */
protected int _status = PuzzleObject.PLAYER_IN_PLAY;
}
@@ -0,0 +1,57 @@
//
// $Id: PuzzleAnimationWaiter.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import com.threerings.media.animation.AnimationWaiter;
import com.threerings.puzzle.Log;
import com.threerings.puzzle.data.PuzzleObject;
/**
* An animation waiter to be used with puzzles that want to modify the
* game object or board in some way after the animations end, and would
* like to do so in a safe fashion such that their changes aren't
* unwittingly performed on game data for a subsequent round of the
* puzzle.
*/
public abstract class PuzzleAnimationWaiter extends AnimationWaiter
{
/**
* Constructs a puzzle animation waiter.
*/
public PuzzleAnimationWaiter (PuzzleObject puzobj)
{
_puzobj = puzobj;
_roundId = puzobj.roundId;
}
/**
* Returns whether the puzzle associated with this puzzle animation
* waiter is still valid.
*/
public boolean puzzleStillValid ()
{
return (_puzobj.isInPlay() && (_roundId == _puzobj.roundId));
}
// documentation inherited
protected final void allAnimationsFinished ()
{
allAnimationsFinished(puzzleStillValid());
}
/**
* Replacement for {@link AnimationWaiter#allAnimationsFinished} that
* also reports whether the puzzle associated with this animation
* waiter is still valid.
*/
protected abstract void allAnimationsFinished (boolean puzStillValid);
/** The initial round id. */
protected int _roundId;
/** The puzzle object that the animations we're observering want to
* modify. */
protected PuzzleObject _puzobj;
}
@@ -0,0 +1,461 @@
//
// $Id: PuzzleBoardView.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import javax.swing.UIManager;
import com.samskivert.swing.Label;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.util.StringUtil;
import com.threerings.media.VirtualMediaPanel;
import com.threerings.media.animation.Animation;
import com.threerings.media.animation.AnimationAdapter;
import com.threerings.media.image.Mirage;
import com.threerings.media.sprite.Sprite;
import com.threerings.media.sprite.SpriteManager;
import com.threerings.yohoho.client.YoUI;
import com.threerings.puzzle.Log;
import com.threerings.puzzle.client.ScoreAnimation;
import com.threerings.puzzle.data.Board;
import com.threerings.puzzle.data.PuzzleConfig;
import com.threerings.puzzle.util.PuzzleContext;
/**
* The puzzle board view displays a view of a puzzle game.
*/
public abstract class PuzzleBoardView extends VirtualMediaPanel
{
/**
* Constructs a puzzle board view.
*/
public PuzzleBoardView (PuzzleContext ctx)
{
super(ctx.getFrameManager());
// keep this for later
_ctx = ctx;
}
/**
* Initializes the board with the board dimensions.
*/
public void init (PuzzleConfig config)
{
// save off our bounds
Dimension bounds = getPreferredSize();
_bounds = new Rectangle(0, 0, bounds.width, bounds.height);
}
/**
* Sets the board to be displayed.
*/
public void setBoard (Board board)
{
_board = board;
}
/**
* Provides the board view with a reference to its controller so that
* it may communicate directly rather than by posting actions up the
* interface hierarchy which sometimes fails if the puzzle board view
* is hidden before we get a chance to post our actions.
*/
public void setController (PuzzleController pctrl)
{
_pctrl = pctrl;
}
/**
* Sets the background image displayed by the board view.
*/
public void setBackgroundImage (Mirage image)
{
_background = image;
}
/**
* Set whether this puzzle is paused or not.
*/
public void setPaused (boolean paused)
{
if (paused) {
_pauseLabel = new Label(
YoUI.puzzle.getBundle().get(_pctrl.getPauseString()),
Label.BOLD | Label.OUTLINE, Color.WHITE, Color.BLACK,
_fonts[_fonts.length - 2]);
_pauseLabel.setTargetWidth(_bounds.width);
_pauseLabel.layout(this);
} else {
_pauseLabel = null;
}
repaint();
}
/**
* Adds the given animation to the set of animations currently present
* on the board. The animation will be added to a list of action
* animations whose count can be queried with {@link
* #getActionAnimationCount}. The animation will automatically be
* removed from the action list when it completes.
*/
public void addActionAnimation (Animation anim)
{
super.addAnimation(anim);
// remember the animation's existence
_actionAnims.add(anim);
// and listen for it to finish so that we can clear it out
anim.addAnimationObserver(_actionAnimObs);
}
// documentation inherited
public void abortAnimation (Animation anim)
{
super.abortAnimation(anim);
// always check to see if it was action-y
animationFinished(anim);
}
/**
* Called when a potential action animation is finished.
*/
protected void animationFinished (Animation anim)
{
if (DEBUG_ACTION) {
Log.info("Animation cleared " + StringUtil.shortClassName(anim) +
":" + _actionAnims.contains(anim));
}
// if it WAS an action animation, check for a clear
if (_actionAnims.remove(anim)) {
maybeFireCleared();
}
}
/**
* Adds the given sprite to the set of sprites currently present on
* the board. The sprite will be added to a list of action sprites
* whose count can be queried with {@link #getActionSpriteCount}. Callers
* should be sure to remove the sprite when their work with it is done
* via {@link #removeSprite}.
*/
public void addActionSprite (Sprite sprite)
{
// add the piece to the sprite manager
addSprite(sprite);
// note that this piece is interesting
_actionSprites.add(sprite);
}
/**
* Removes the given sprite from the board.
*/
public void removeSprite (Sprite sprite)
{
super.removeSprite(sprite);
if (DEBUG_ACTION) {
Log.info("Sprite cleared " + StringUtil.shortClassName(sprite) +
":" + _actionSprites.contains(sprite));
}
// we just always check to see if it was action-y
if (_actionSprites.remove(sprite)) {
maybeFireCleared();
}
}
/**
* Returns the number of action animations on the board.
*/
public int getActionAnimationCount ()
{
return _actionAnims.size();
}
/**
* Returns the number of action sprites on the board.
*/
public int getActionSpriteCount ()
{
return _actionSprites.size();
}
/**
* Returns the count of action sprites and animations on the board.
*/
public int getActionCount ()
{
return _actionSprites.size() + _actionAnims.size();
}
/**
* Dumps to the logs, a list of interesting sprites and animations
* currently active on the puzzle board.
*/
public void dumpActors ()
{
StringUtil.Formatter fmt = new StringUtil.Formatter() {
public String toString (Object obj) {
return StringUtil.shortClassName(obj);
}
};
Log.info("Board contents [board=" + StringUtil.shortClassName(this) +
", sprites=" + StringUtil.listToString(_actionSprites, fmt) +
", anims=" + StringUtil.listToString(_actionAnims, fmt) +
"].");
}
/**
* Creates and returns an animation displaying the given string with
* the specified parameters, floating it a short distance up the view.
*
* @param score the score text to display.
* @param color the color of the text.
* @param fontSize the size of the text; a value between 0 and {@link
* #getPuzzleFontCount} - 1.
* @param x the x-position at which the score is to be placed.
* @param y the y-position at which the score is to be placed.
*/
public ScoreAnimation createScoreAnimation (
String score, Color color, int fontSize, int x, int y)
{
// create and configure the label
Label label = new Label(score);
label.setTargetWidth(_bounds.width);
label.setStyle(Label.OUTLINE);
label.setTextColor(color);
label.setAlternateColor(Color.black);
label.setFont(getPuzzleFont(fontSize));
label.setAlignment(Label.CENTER);
label.layout(this);
// create the score animation
ScoreAnimation anim = new ScoreAnimation(label, x, y);
anim.setRenderOrder(getScoreRenderOrder());
return anim;
}
/**
* Returns the render order to be assigned to score animations by
* default. Derived classes may wish to override this method to
* change the default render order.
*
* @see #createScoreAnimation
*/
protected int getScoreRenderOrder ()
{
return 1;
}
/**
* Returns the puzzle font to be used for the specified score.
*/
public int getFont (String why, int score, int maxScore)
{
int fontSize = (int)(score*getPuzzleFontCount()/maxScore);
fontSize = Math.min(FONT_SIZES.length-1, fontSize);
// Log.info("Font for " + why + " (" + score + " of " + maxScore +
// ") => " + fontSize + ".");
return fontSize;
}
/**
* Returns the number of different puzzle font sizes so that those who
* care to choose a font size out of the range of possible sizes can
* do so gracefully.
*/
public int getPuzzleFontCount ()
{
return FONT_SIZES.length;
}
/**
* Positions the supplied animation so as to avoid any active
* animations previously registered with this method, and adds the
* animation to the list of animations to be avoided by any future
* avoid animations.
*/
public void trackAvoidAnimation (Animation anim)
{
// reposition the animation as appropriate
Rectangle abounds = new Rectangle(anim.getBounds());
ArrayList avoidables = (ArrayList)_avoidAnims.clone();
if (SwingUtil.positionRect(abounds, _bounds, avoidables)) {
anim.setLocation(abounds.x, abounds.y);
}
// add the animation to the list of avoidables
_avoidAnims.add(anim);
// keep an eye on it so that we can remove it when it's finished
anim.addAnimationObserver(_avoidAnimObs);
}
// documentation inherited
public void paintBehind (Graphics2D gfx, Rectangle dirty)
{
super.paintBehind(gfx, dirty);
// render the background
renderBackground(gfx, dirty);
}
/**
* Fills the background of the board with the background color.
*/
protected void renderBackground (Graphics2D gfx, Rectangle dirty)
{
gfx.setColor(getBackground());
gfx.fill(dirty);
}
// documentation inherited
public void paintBetween (Graphics2D gfx, Rectangle dirty)
{
super.paintBetween(gfx, dirty);
// PerformanceMonitor.tick(this, "paint");
renderBoard(gfx, dirty);
}
// documentation inherited
protected void paintInFront (Graphics2D gfx, Rectangle dirty)
{
super.paintInFront(gfx, dirty);
// if the action is paused, indicate as much
if (_pauseLabel != null) {
Dimension d = _pauseLabel.getSize();
_pauseLabel.render(gfx, (_bounds.width - d.width) / 2,
(_bounds.height - d.height) / 2);
}
}
/**
* Fires a {@link #ACTION_CLEARED} command iff we have no remaining
* interesting sprites or animations.
*/
protected void maybeFireCleared ()
{
if (DEBUG_ACTION) {
Log.info("Maybe firing cleared " +
getActionCount() + ":" + isShowing());
}
if (getActionCount() == 0) {
_pctrl.boardActionCleared();
}
}
/**
* Renders the board contents to the given graphics context.
* Sub-classes should implement this method to draw all of their
* game-specific business.
*/
protected abstract void renderBoard (Graphics2D gfx, Rectangle dirty);
/**
* Returns the puzzle font of the specified size.
*
* @param size the desired font size; a value between 0 and {@link
* #getPuzzleFontCount} - 1.
*/
protected static Font getPuzzleFont (int size)
{
return _fonts[size];
}
/** Our client context. */
protected PuzzleContext _ctx;
/** Our puzzle controller. */
protected PuzzleController _pctrl;
/** The board data to be displayed. */
protected Board _board;
/** The board's bounding rectangle. */
protected Rectangle _bounds;
/** The action animations on the board. */
protected ArrayList _actionAnims = new ArrayList();
/** The action sprites on the board. */
protected ArrayList _actionSprites = new ArrayList();
/** The animations that other animations may wish to avoid. */
protected ArrayList _avoidAnims = new ArrayList();
/** Our background image. */
protected Mirage _background;
/** A label to show when the puzzle is paused. */
protected Label _pauseLabel;
/** The distance in pixels that score animations float. */
protected int _scoreDist = DEFAULT_SCORE_DISTANCE;
/** Listens to our action animations and clears them when they're done. */
protected AnimationAdapter _actionAnimObs = new AnimationAdapter() {
public void animationCompleted (Animation anim, long when) {
animationFinished(anim);
}
};
/** Automatically removes avoid animations when they're done. */
protected AnimationAdapter _avoidAnimObs = new AnimationAdapter() {
public void animationCompleted (Animation anim, long when) {
if (!_avoidAnims.remove(anim)) {
Log.warning("Couldn't remove avoid animation?! " + anim + ".");
}
}
};
/** The puzzle fonts. */
protected static Font[] _fonts;
/** Temporary action debugging. */
protected static boolean DEBUG_ACTION = false;
// action state constants
protected static final int ACTION_GOING = 0;
protected static final int CLEAR_PENDING = 1;
protected static final int ACTION_CLEARED = 2;
/** The default vertical distance to float score animations. */
protected static final int DEFAULT_SCORE_DISTANCE = 30;
/** The mid-sized font used as the default size for score
* animations. */
protected static final int MEDIUM_FONT_SIZE = 1;
/** The puzzle font sizes. */
protected static final double[] FONT_SIZES = {
24d, 30d, 36d, 42d, 52d, 68d };
static {
// create the puzzle fonts
Font ofont = UIManager.getFont("Label.serifFont");
ofont = ofont.deriveFont((float)FONT_SIZES[0]);
_fonts = new Font[FONT_SIZES.length];
for (int ii = 0; ii < _fonts.length; ii++) {
double scale = FONT_SIZES[ii]/FONT_SIZES[0];
_fonts[ii] = ofont.deriveFont(
AffineTransform.getScaleInstance(scale * 1.1d, scale));
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,162 @@
//
// $Id: PuzzleControllerDelegate.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.game.GameControllerDelegate;
import com.threerings.puzzle.data.Board;
import com.threerings.puzzle.data.BoardSummary;
import com.threerings.puzzle.data.PuzzleCodes;
import com.threerings.puzzle.data.PuzzleGameCodes;
import com.threerings.puzzle.data.PuzzleObject;
/**
* A base class for puzzle controller delegates. Provides access to some
* delegated puzzle controller methods ({@link #startAction}, {@link
* #clearAction}, etc.) and provides a casted reference to the puzzle
* object.
*/
public class PuzzleControllerDelegate extends GameControllerDelegate
implements PuzzleCodes, PuzzleGameCodes
{
/**
* Constructs a puzzle controller delegate.
*/
public PuzzleControllerDelegate (PuzzleController ctrl)
{
super(ctrl);
// keep around a casted reference to our controller
_ctrl = ctrl;
}
// documentation inherited
public void willEnterPlace (PlaceObject plobj)
{
super.willEnterPlace(plobj);
// get a casted reference to our game object
_puzobj = (PuzzleObject)plobj;
}
// documentation inherited
public void didLeavePlace (PlaceObject plobj)
{
super.didLeavePlace(plobj);
_puzobj = null;
}
/**
* Called when a player is knocked out of the game.
*/
public void playerKnockedOut (int pidx)
{
}
/**
* Called when the user toggles chatting mode.
*/
public void setChatting (boolean chatting)
{
}
/**
* Can we start chatting at the instant that this method is called?
*/
protected boolean canStartChatting ()
{
return true;
}
/**
* Derived classes should override this method and do whatever is
* necessary to start up the action for their puzzle. This could be
* called when the user is already in the "room" and the game starts,
* or immediately upon entering the room if the game is already
* started (for example if they disconnected and reconnected to a game
* already in progress).
*/
protected void startAction ()
{
}
/**
* Delegates that wish to postpone action clearing can override this
* method to return false until such time as the action can be
* cleared. They must, however, call {@link #maybeClearAction} when
* conditions become such that they would once again allow action to
* be cleared.
*/
protected boolean canClearAction ()
{
return true;
}
/**
* Calls {@link PuzzleController#maybeClearAction}, preserving its
* protected access but making the method available to all
* PuzzleControllerDelegate derivations.
*/
protected void maybeClearAction ()
{
_ctrl.maybeClearAction();
}
/**
* Puzzles should override this method and clear out any action on the
* board and generally clean up anything that was going on because the
* game was in play. This is called when the game has ended or when it
* is going to reset and when the client leaves the game "room".
* Anything that is cleared out here should be recreated in {@link
* #startAction}.
*/
protected void clearAction ()
{
}
/**
* Called when the puzzle controller sets up a new board for the
* player.
*
* @param board the newly initialized and ready-to-go board.
*/
public void setBoard (Board board)
{
}
/**
* Called when the game is suspended while we wait for a new piece
* packet from the server.
*/
public void didSuspend ()
{
}
/**
* Called when the game is resumed once a new piece packet arrives
* from the server while we were suspended awaiting its arrival.
*
* @param delta the time elapsed in milliseconds while we were
* suspended.
*/
public void didResume (long delta)
{
}
/**
* Called when the puzzle difficulty level is changed.
*/
public void difficultyChanged (int level)
{
}
/** Our puzzle controller. */
protected PuzzleController _ctrl;
/** The puzzle distributed object. */
protected PuzzleObject _puzobj;
}
@@ -0,0 +1,31 @@
//
// $Id: PuzzleGameService.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.puzzle.data.Board;
import com.threerings.puzzle.data.PuzzleCodes;
/**
* Provides services used by puzzle game clients to request that actions
* be taken by the puzzle manager.
*/
public interface PuzzleGameService extends InvocationService, PuzzleCodes
{
/**
* Asks the puzzle manager to apply the supplied progress events for
* the specified puzzle round to the player's state.
*/
public void updateProgress (Client client, int roundId, int[] events);
/**
* Debug variant of {@link #updateProgress} that is only used when
* {@link #SYNC_BOARD_STATE} is true and which includes the board
* states associated with each event.
*/
public void updateProgressSync (
Client client, int roundId, int[] events, Board[] states);
}
@@ -0,0 +1,244 @@
//
// $Id: PuzzlePanel.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.io.IOException;
import javax.swing.JPanel;
import com.samskivert.swing.Controller;
import com.samskivert.swing.ControllerProvider;
import com.samskivert.swing.util.SwingUtil;
import com.threerings.media.image.Mirage;
import com.threerings.util.KeyTranslator;
import com.threerings.util.RobotPlayer;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.puzzle.Log;
import com.threerings.puzzle.data.BoardSummary;
import com.threerings.puzzle.data.PuzzleCodes;
import com.threerings.puzzle.data.PuzzleConfig;
import com.threerings.puzzle.data.PuzzleGameCodes;
import com.threerings.puzzle.data.PuzzleObject;
import com.threerings.puzzle.util.PuzzleContext;
/**
* The puzzle panel class should be extended by classes that provide a
* view for a puzzle game. The {@link PuzzleController} calls these
* methods as necessary to perform its duties in managing the logical
* actions of a puzzle game.
*/
public abstract class PuzzlePanel extends JPanel
implements PlaceView, ControllerProvider, PuzzleCodes, PuzzleGameCodes
{
/**
* Constructs a puzzle panel.
*/
public PuzzlePanel (PuzzleContext ctx, PuzzleController controller)
{
_ctx = ctx;
_controller = controller;
// set up the keyboard manager
_xlate = getKeyTranslator();
_ctx.getKeyboardManager().setTarget(this, _xlate);
// leave the keyboard manager disabled to start, and set things up
// for chatting
setPuzzleGrabsKeys(false);
// configure the puzzle panel
setLayout(new BorderLayout());
// create the puzzle board view
_bview = createBoardView(ctx);
// create the puzzle board panel
_bpanel = createBoardPanel();
// add the board panel
add(_bpanel, BorderLayout.CENTER);
}
/**
* Temporarily replaces the puzzle board display with the supplied
* overlay panel. The panel can be removed and the board display
* restored by calling {@link #popOverlayPanel}.
*
* @return true if the specified panel will be displayed, false if it
* was not able to be pushed because another overlay panel is already
* pushed onto the primary panel.
*/
public boolean pushOverlayPanel (JPanel opanel)
{
// bail if we've already got an overlay
if (_opanel != null) {
Log.info("Refusing to push overlay panel, we've already got one " +
"[opanel=" + _opanel + ", npanel=" + opanel + "].");
return false;
}
// swap in the overlay panel
_opanel = opanel;
remove(_bpanel);
add(_opanel);
// make sure the UI updates
SwingUtil.refresh(this);
return true;
}
/**
* Pops the overlay panel off of the main puzzle board display.
*/
public void popOverlayPanel ()
{
if (_opanel != null) {
remove(_opanel);
_opanel = null;
add(_bpanel);
// make sure the UI updates
SwingUtil.refresh(this);
}
}
/**
* Initializes the puzzle panel with the puzzle config of the puzzle
* whose user interface is being displayed by the panel
*/
public void init (PuzzleConfig config)
{
_config = config;
_bview.init(config);
}
/**
* Sets whether this panel receives events periodically from a robot
* player.
*/
public void setRobotPlayer (boolean isrobot)
{
// create a robot player if necessary
if (_robot == null) {
_robot = new RobotPlayer(this, _xlate);
}
setPuzzleGrabsKeys(!isrobot);
_robot.setRobotDelay(200L);
_robot.setActive(isrobot);
}
/**
* Sets whether the puzzle grabs keys or if they should go to the chat
* window.
*/
public void setPuzzleGrabsKeys (boolean puzgrabs)
{
// enable or disable the key manager appropriately
_ctx.getKeyboardManager().setEnabled(puzgrabs);
if (puzgrabs) {
getBoardView().requestFocus();
}
}
/**
* Called by the controller when the action starts.
*/
public void startAction ()
{
// make the first player a robot player
if (ROBOT_TEST && _controller.getPlayerIndex() == 0) {
setRobotPlayer(true);
}
}
/**
* Called by the controller when the action stops.
*/
public void clearAction ()
{
// deactivate the robot player
if (ROBOT_TEST && _controller.getPlayerIndex() == 0) {
setRobotPlayer(false);
}
}
/**
* Creates the puzzle board view that will be used to display the main
* puzzle interface. This is called when the puzzle panel is
* constructed. The derived panel will still be responsible for adding
* the board to the interface hierarchy.
*/
protected abstract PuzzleBoardView createBoardView (PuzzleContext ctx);
/**
* Creates the main panel used to display the puzzle and its various
* in-game accoutrements (next block views, player status displays,
* etc.) This is called when the puzzle panel is constructed. The
* derived panel is responsible for making sure that the board view is
* present in the board panel.
*/
protected abstract JPanel createBoardPanel ();
/**
* Returns a key translator with the desired key to controller command
* mappings desired for this puzzle.
*/
protected abstract KeyTranslator getKeyTranslator ();
// documentation inherited from interface
public void willEnterPlace (PlaceObject plobj)
{
}
// documentation inherited from interface
public void didLeavePlace (PlaceObject plobj)
{
// disable the keyboard manager when we leave
_ctx.getKeyboardManager().reset();
}
/**
* Returns a reference to the {@link PuzzleBoardView} in use.
*/
public PuzzleBoardView getBoardView ()
{
return _bview;
}
// documentation inherited
public Controller getController ()
{
return _controller;
}
/** Our puzzle context. */
protected PuzzleContext _ctx;
/** The board view on which the primary puzzle interface is displayed. */
protected PuzzleBoardView _bview;
/** The board panel displayed while the puzzle is in progress. */
protected JPanel _bpanel;
/** The board overlay panel displayed as requested. */
protected JPanel _opanel;
/** The puzzle config. */
protected PuzzleConfig _config;
/** The robot player. */
protected RobotPlayer _robot;
/** Our key translations. */
protected KeyTranslator _xlate;
/** The puzzle game controller. */
protected PuzzleController _controller;
}
@@ -0,0 +1,52 @@
//
// $Id: PuzzleService.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.puzzle.data.SolitairePuzzleConfig;
/**
* The puzzle services provide a mechanism by which the client can enter
* and leave puzzles. These services should not be used directly, but
* instead should be accessed via the {@link PuzzleDirector}.
*/
public interface PuzzleService extends InvocationService
{
/** Used to communicate responses to {@link #enterPuzzle} requests. */
public static interface EnterPuzzleListener extends InvocationListener
{
/**
* Indicates that a {@link #enterPuzzle} request was successful
* and provides the place config for the puzzle room.
*/
public void puzzleEntered (PlaceConfig config);
}
/**
* Requests that this client start up the specified single-player
* puzzle.
*/
public void startPuzzle (Client client, SolitairePuzzleConfig config,
InvocationListener listener);
/**
* Requests that this client enter the specified puzzle.
*/
public void enterPuzzle (
Client client, int puzzleOid, EnterPuzzleListener listener);
/**
* Requests that this client depart whatever puzzle they occupy.
*/
public void leavePuzzle (Client client);
/**
* Requests that the difficulty level of the puzzle this client is
* currently occupying be changed to the specified difficulty level.
*/
public void changeDifficulty (Client client, int level);
}
@@ -0,0 +1,226 @@
//
// $Id: ScoreAnimation.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.client;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import com.samskivert.swing.Label;
import com.threerings.media.animation.Animation;
import com.threerings.puzzle.Log;
public class ScoreAnimation extends Animation
{
/**
* Constructs a score animation for the given score value centered at
* the given coordinates.
*/
public ScoreAnimation (Label label, int x, int y)
{
this(label, x, y, DEFAULT_FLOAT_PERIOD);
}
/**
* Constructs a score animation for the given score value centered at
* the given coordinates. The animation will float up the screen for
* 30 pixels.
*/
public ScoreAnimation (Label label, int x, int y, long floatPeriod)
{
this(label, x, y, x, y - DELTA_Y, floatPeriod);
}
/**
* Constructs a score animation for the given score value starting at
* the given coordinates and floating toward the specified
* coordinates.
*/
public ScoreAnimation (Label label, int sx, int sy,
int destx, int desty, long floatPeriod)
{
super(new Rectangle(sx, sy, label.getSize().width,
label.getSize().height));
// save things off
_label = label;
_startX = _x = sx;
_startY = _y = sy;
_destx = destx;
_desty = desty;
_floatPeriod = floatPeriod;
// calculate our deltas
_dx = (destx - sx);
_dy = (desty - sy);
// initialize our starting alpha
_alpha = 1.0f;
}
/**
* Called to change the direction 180 degrees.
*/
public void flipDirection ()
{
_dx = -_dx;
_dy = -_dy;
}
/**
* Returns the label used to render this score animation.
*/
public Label getLabel ()
{
return _label;
}
// documentation inherited
public void setLocation (int x, int y)
{
super.setLocation(x, y);
// update our destination coordinates
_destx += (x - _startX);
_desty += (y - _startY);
// update our initial coordinates
_startX = _x = x;
_startY = _y = y;
// recalculate our deltas
_dx = (_destx - x);
_dy = (_desty - y);
}
/**
* Sets the duration of this score animation to the specified time in
* milliseconds. This should be called before the animation is added
* to the animation manager.
*/
public void setFloatPeriod (long floatPeriod)
{
_floatPeriod = floatPeriod;
}
// documentation inherited
public void tick (long timestamp)
{
boolean invalid = false;
if (_start == 0) {
// initialize our starting time
_start = timestamp;
// we need to make sure to invalidate ourselves initially
invalid = true;
}
long fadeDelay = _floatPeriod/2;
long fadePeriod = _floatPeriod - fadeDelay;
// figure out the current alpha
long msecs = timestamp - _start;
float oalpha = _alpha;
if (msecs > fadeDelay) {
long rmsecs = msecs - fadeDelay;
_alpha = Math.max(1.0f - (rmsecs / (float)fadePeriod), 0.0f);
_alpha = Math.min(_alpha, 1.0f);
}
// get the alpha composite
_comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, _alpha);
// determine the new y-position of the score
float pctdone = (float)msecs / _floatPeriod;
int ox = _x, oy = _y;
_x = _startX + (int)(_dx * pctdone);
_y = _startY + (int)(_dy * pctdone);
// only update our location and dirty ourselves if we actually
// moved or our alpha changed
if (ox != _x || oy != _y) {
// dirty our old location
invalidate();
_bounds.setLocation(_x, _y);
invalid = true;
} else if (oalpha != _alpha) {
invalid = true;
}
if (invalid) {
// dirty our current location
invalidate();
}
// note whether we're done
_finished = (msecs >= _floatPeriod);
}
// documentation inherited
public void fastForward (long timeDelta)
{
if (_start > 0) {
_start += timeDelta;
}
}
// documentation inherited
public void paint (Graphics2D gfx)
{
Composite ocomp = gfx.getComposite();
if (_comp != null) {
gfx.setComposite(_comp);
}
_label.render(gfx, _x, _y);
gfx.setComposite(ocomp);
}
// documentation inherited
protected void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", x=").append(_x);
buf.append(", y=").append(_y);
buf.append(", alpha=").append(_alpha);
}
/** The starting animation time. */
protected long _start;
/** The label we're animating. */
protected Label _label;
/** The starting coordinates of the score. */
protected int _startX, _startY;
/** The current coordinates of the score. */
protected int _x, _y;
/** The destination coordinates towards which the animation travels. */
protected int _destx, _desty;
/** The distance to be traveled by the score animation. */
protected int _dx, _dy;
/** The duration for which we float up the screen. */
protected long _floatPeriod;
/** The current alpha level used to render the score. */
protected float _alpha;
/** The composite used to render the score. */
protected Composite _comp;
/** The time in milliseconds during which the score is visible. */
protected static final long DEFAULT_FLOAT_PERIOD = 1500L;
/** The total vertical distance the score travels. */
protected static final int DELTA_Y = 30;
}