Revamped drop puzzle framework to use sprites for pieces instead of
rendering the board from the board state and doing all manner of jockeying to prevent that from wigging out when the board state changes before the display is ready to change. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3108 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: DropBoardView.java,v 1.4 2004/08/27 02:20:29 mdb Exp $
|
// $Id: DropBoardView.java,v 1.5 2004/08/29 06:50:47 mdb Exp $
|
||||||
//
|
//
|
||||||
// Narya library - tools for developing networked games
|
// Narya library - tools for developing networked games
|
||||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||||
@@ -30,8 +30,13 @@ import java.awt.Rectangle;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import com.threerings.media.image.Mirage;
|
import com.threerings.media.image.Mirage;
|
||||||
|
import com.threerings.media.sprite.ImageSprite;
|
||||||
|
import com.threerings.media.sprite.PathAdapter;
|
||||||
import com.threerings.media.sprite.Sprite;
|
import com.threerings.media.sprite.Sprite;
|
||||||
|
import com.threerings.media.util.LinePath;
|
||||||
|
import com.threerings.media.util.Path;
|
||||||
|
|
||||||
|
import com.threerings.puzzle.Log;
|
||||||
import com.threerings.puzzle.client.PuzzleBoardView;
|
import com.threerings.puzzle.client.PuzzleBoardView;
|
||||||
import com.threerings.puzzle.client.ScoreAnimation;
|
import com.threerings.puzzle.client.ScoreAnimation;
|
||||||
import com.threerings.puzzle.data.Board;
|
import com.threerings.puzzle.data.Board;
|
||||||
@@ -128,34 +133,152 @@ public abstract class DropBoardView extends PuzzleBoardView
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dirties the rectangle encompassing the piece segment with the given
|
* Creates a new piece sprite and places it directly in it's correct
|
||||||
* direction and length whose bottom-leftmost corner is at <code>(col,
|
* position.
|
||||||
* row)</code>.
|
|
||||||
*/
|
*/
|
||||||
public void dirtySegment (int dir, int col, int row, int len)
|
public void createPiece (int piece, int sx, int sy)
|
||||||
{
|
{
|
||||||
int x = _pwid * col, y = (_phei * row) - _roff;
|
if (sx < 0 || sy < 0 || sx >= _bwid || sy >= _bhei) {
|
||||||
int wid = (dir == VERTICAL) ? _pwid : len * _pwid;
|
Log.warning("Requested to create piece in invalid location " +
|
||||||
int hei = (dir == VERTICAL) ? _phei * len : _phei;
|
"[sx=" + sx + ", sy=" + sy + "].");
|
||||||
_remgr.invalidateRegion(x, y, wid, hei);
|
Thread.dumpStack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createPiece(piece, sx, sy, sx, sy, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dirties the rectangle encompassing the specified piece in the
|
* Refreshes the piece sprite at the specified location, if no sprite
|
||||||
* board.
|
* exists at the location, one will be created. <em>Note:</em> this
|
||||||
|
* method assumes the default {@link ImageSprite} is being used to
|
||||||
|
* display pieces. If {@link #createPieceSprite} is overridden to
|
||||||
|
* return a non-ImageSprite, this method must also be customized.
|
||||||
*/
|
*/
|
||||||
public void dirtyPiece (int col, int row)
|
public void updatePiece (int sx, int sy)
|
||||||
{
|
{
|
||||||
_remgr.invalidateRegion(_pwid * col, (_phei * row) - _roff,
|
updatePiece(_dboard.getPiece(sx, sy), sx, sy);
|
||||||
_pwid, _phei);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dirties a rectangular region of pieces.
|
* Updates the piece sprite at the specified location, if no sprite
|
||||||
|
* exists at the location, one will be created. <em>Note:</em> this
|
||||||
|
* method assumes the default {@link ImageSprite} is being used to
|
||||||
|
* display pieces. If {@link #createPieceSprite} is overridden to
|
||||||
|
* return a non-ImageSprite, this method must also be customized.
|
||||||
*/
|
*/
|
||||||
public void dirtyPieces (int xx, int yy, int width, int height)
|
public void updatePiece (int piece, int sx, int sy)
|
||||||
|
{
|
||||||
|
if (sx < 0 || sy < 0 || sx >= _bwid || sy >= _bhei) {
|
||||||
|
Log.warning("Requested to update piece in invalid location " +
|
||||||
|
"[sx=" + sx + ", sy=" + sy + "].");
|
||||||
|
Thread.dumpStack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int spos = sy * _bwid + sx;
|
||||||
|
if (_pieces[spos] != null) {
|
||||||
|
((ImageSprite)_pieces[spos]).setMirage(getPieceImage(piece));
|
||||||
|
} else {
|
||||||
|
createPiece(piece, sx, sy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new piece sprite and moves it into position on the board.
|
||||||
|
*/
|
||||||
|
public void createPiece (int piece, int sx, int sy, int tx, int ty,
|
||||||
|
long duration)
|
||||||
|
{
|
||||||
|
if (tx < 0 || ty < 0 || tx >= _bwid || ty >= _bhei) {
|
||||||
|
Log.warning("Requested to create and move piece to invalid " +
|
||||||
|
"location [tx=" + tx + ", ty=" + ty + "].");
|
||||||
|
Thread.dumpStack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Sprite sprite = createPieceSprite(piece);
|
||||||
|
addSprite(sprite);
|
||||||
|
movePiece(sprite, sx, sy, tx, ty, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the view to move the piece at the specified starting
|
||||||
|
* position to the specified destination position. There must be a
|
||||||
|
* sprite at the starting position, if there is a sprite at the
|
||||||
|
* destination position, it must also be moved immediately following
|
||||||
|
* this call (as in the case of a swap) to avoid badness.
|
||||||
|
*
|
||||||
|
* @return the piece sprite that is being moved.
|
||||||
|
*/
|
||||||
|
public Sprite movePiece (int sx, int sy, int tx, int ty, long duration)
|
||||||
|
{
|
||||||
|
int spos = sy * _bwid + sx;
|
||||||
|
Sprite piece = _pieces[spos];
|
||||||
|
if (piece == null) {
|
||||||
|
Log.warning("Missing source sprite for drop [sx=" + sx +
|
||||||
|
", sy=" + sy + ", tx=" + tx + ", ty=" + ty + "].");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
_pieces[spos] = null;
|
||||||
|
movePiece(piece, sx, sy, tx, ty, duration);
|
||||||
|
return piece;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper function for moving pieces into place.
|
||||||
|
*/
|
||||||
|
protected void movePiece (Sprite piece, final int sx, final int sy,
|
||||||
|
final int tx, final int ty, long duration)
|
||||||
|
{
|
||||||
|
final Exception where = new Exception();
|
||||||
|
|
||||||
|
// if the sprite needn't move, then just position it and be done
|
||||||
|
Point start = new Point();
|
||||||
|
getPiecePosition(sx, sy, start);
|
||||||
|
if (sx == tx && sy == ty) {
|
||||||
|
int tpos = ty * _bwid + tx;
|
||||||
|
if (_pieces[tpos] != null) {
|
||||||
|
Log.warning("Zoiks! Asked to add a piece where we already " +
|
||||||
|
"have one [sx=" + sx + ", sy=" + sy +
|
||||||
|
", tx=" + tx + ", ty=" + ty + "].");
|
||||||
|
Log.logStackTrace(where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_pieces[tpos] = piece;
|
||||||
|
piece.setLocation(start.x, start.y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise create a path and do some bits
|
||||||
|
Point end = new Point();
|
||||||
|
getPiecePosition(tx, ty, end);
|
||||||
|
piece.addSpriteObserver(new PathAdapter() {
|
||||||
|
public void pathCompleted (Sprite sprite, Path path, long when) {
|
||||||
|
sprite.removeSpriteObserver(this);
|
||||||
|
int tpos = ty * _bwid + tx;
|
||||||
|
if (_pieces[tpos] != null) {
|
||||||
|
Log.warning("Oh god, we're dropping onto another piece " +
|
||||||
|
"[sx=" + sx + ", sy=" + sy +
|
||||||
|
", tx=" + tx + ", ty=" + ty + "].");
|
||||||
|
Log.logStackTrace(where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_pieces[tpos] = sprite;
|
||||||
|
if (_actionSprites.remove(sprite)) {
|
||||||
|
maybeFireCleared();
|
||||||
|
}
|
||||||
|
pieceArrived(when, sprite, tx, ty);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_actionSprites.add(piece);
|
||||||
|
piece.move(new LinePath(start, end, duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a piece is finished moving into its requested position.
|
||||||
|
* Derived classes may wish to take this opportunity to play a sound
|
||||||
|
* or whatnot.
|
||||||
|
*/
|
||||||
|
protected void pieceArrived (long tickStamp, Sprite sprite, int px, int py)
|
||||||
{
|
{
|
||||||
_remgr.invalidateRegion(xx*_pwid, yy*_phei, width*_pwid, height*_phei);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,9 +315,63 @@ public abstract class DropBoardView extends PuzzleBoardView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove all of this board's piece sprites
|
||||||
|
int pcount = (_pieces == null) ? 0 : _pieces.length;
|
||||||
|
for (int ii = 0; ii < pcount; ii++) {
|
||||||
|
if (_pieces[ii] != null) {
|
||||||
|
removeSprite(_pieces[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.setBoard(board);
|
super.setBoard(board);
|
||||||
|
|
||||||
_dboard = (DropBoard)board;
|
_dboard = (DropBoard)board;
|
||||||
|
|
||||||
|
// create the pieces for the new board
|
||||||
|
Point spos = new Point();
|
||||||
|
int width = _dboard.getWidth(), height = _dboard.getHeight();
|
||||||
|
_pieces = new Sprite[width * height];
|
||||||
|
for (int yy = 0; yy < height; yy++) {
|
||||||
|
for (int xx = 0; xx < width; xx++) {
|
||||||
|
Sprite piece = createPieceSprite(_dboard.getPiece(xx, yy));
|
||||||
|
if (piece != null) {
|
||||||
|
int ppos = yy * width + xx;
|
||||||
|
getPiecePosition(xx, yy, spos);
|
||||||
|
piece.setLocation(spos.x, spos.y);
|
||||||
|
addSprite(piece);
|
||||||
|
_pieces[ppos] = piece;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the piece sprite at the specified location.
|
||||||
|
*/
|
||||||
|
public Sprite getPieceSprite (int xx, int yy)
|
||||||
|
{
|
||||||
|
return _pieces[yy * _dboard.getWidth() + xx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the specified piece from the board.
|
||||||
|
*/
|
||||||
|
public void clearPieceSprite (int xx, int yy)
|
||||||
|
{
|
||||||
|
int ppos = yy * _dboard.getWidth() + xx;
|
||||||
|
if (_pieces[ppos] != null) {
|
||||||
|
removeSprite(_pieces[ppos]);
|
||||||
|
_pieces[ppos] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears out a piece from the board along with its piece sprite.
|
||||||
|
*/
|
||||||
|
public void clearPiece (int xx, int yy)
|
||||||
|
{
|
||||||
|
_dboard.setPiece(xx, yy, PIECE_NONE);
|
||||||
|
clearPieceSprite(xx, yy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -206,6 +383,19 @@ public abstract class DropBoardView extends PuzzleBoardView
|
|||||||
return new DropSprite(this, col, row, pieces, dist);
|
return new DropSprite(this, col, row, pieces, dist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dirties the rectangle encompassing the segment with the given
|
||||||
|
* direction and length whose bottom-leftmost corner is at <code>(col,
|
||||||
|
* row)</code>.
|
||||||
|
*/
|
||||||
|
public void dirtySegment (int dir, int col, int row, int len)
|
||||||
|
{
|
||||||
|
int x = _pwid * col, y = (_phei * row) - _roff;
|
||||||
|
int wid = (dir == VERTICAL) ? _pwid : len * _pwid;
|
||||||
|
int hei = (dir == VERTICAL) ? _phei * len : _phei;
|
||||||
|
_remgr.invalidateRegion(x, y, wid, hei);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns an animation which makes use of a label sprite
|
* Creates and returns an animation which makes use of a label sprite
|
||||||
* that is assigned a path that floats it a short distance up the
|
* that is assigned a path that floats it a short distance up the
|
||||||
@@ -294,6 +484,20 @@ public abstract class DropBoardView extends PuzzleBoardView
|
|||||||
return anim;
|
return anim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the sprite that is used to display the specified piece. If
|
||||||
|
* the piece represents no piece, this method should return null.
|
||||||
|
*/
|
||||||
|
protected Sprite createPieceSprite (int piece)
|
||||||
|
{
|
||||||
|
if (piece == PIECE_NONE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ImageSprite sprite = new ImageSprite(getPieceImage(piece));
|
||||||
|
sprite.setRenderOrder(-1);
|
||||||
|
return sprite;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates <code>pos</code> with the most appropriate screen
|
* Populates <code>pos</code> with the most appropriate screen
|
||||||
* coordinates to center a rectangle of the given width and height (in
|
* coordinates to center a rectangle of the given width and height (in
|
||||||
@@ -371,6 +575,9 @@ public abstract class DropBoardView extends PuzzleBoardView
|
|||||||
/** The drop board. */
|
/** The drop board. */
|
||||||
protected DropBoard _dboard;
|
protected DropBoard _dboard;
|
||||||
|
|
||||||
|
/** A sprite for every piece displayed in the drop board. */
|
||||||
|
protected Sprite[] _pieces;
|
||||||
|
|
||||||
/** The piece dimensions in pixels. */
|
/** The piece dimensions in pixels. */
|
||||||
protected int _pwid, _phei;
|
protected int _pwid, _phei;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: DropControllerDelegate.java,v 1.5 2004/08/27 02:20:29 mdb Exp $
|
// $Id: DropControllerDelegate.java,v 1.6 2004/08/29 06:50:47 mdb Exp $
|
||||||
//
|
//
|
||||||
// Narya library - tools for developing networked games
|
// Narya library - tools for developing networked games
|
||||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||||
@@ -51,7 +51,6 @@ import com.threerings.puzzle.drop.data.DropCodes;
|
|||||||
import com.threerings.puzzle.drop.data.DropConfig;
|
import com.threerings.puzzle.drop.data.DropConfig;
|
||||||
import com.threerings.puzzle.drop.data.DropLogic;
|
import com.threerings.puzzle.drop.data.DropLogic;
|
||||||
import com.threerings.puzzle.drop.data.DropPieceCodes;
|
import com.threerings.puzzle.drop.data.DropPieceCodes;
|
||||||
import com.threerings.puzzle.drop.util.DropPieceProvider;
|
|
||||||
import com.threerings.puzzle.drop.util.PieceDropLogic;
|
import com.threerings.puzzle.drop.util.PieceDropLogic;
|
||||||
import com.threerings.puzzle.drop.util.PieceDropper.PieceDropInfo;
|
import com.threerings.puzzle.drop.util.PieceDropper.PieceDropInfo;
|
||||||
import com.threerings.puzzle.drop.util.PieceDropper;
|
import com.threerings.puzzle.drop.util.PieceDropper;
|
||||||
@@ -149,15 +148,6 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the DropPieceProvider for this puzzle. This is currently
|
|
||||||
* only needed if you are using the alwaysfilled property of dropboards.
|
|
||||||
*/
|
|
||||||
protected DropPieceProvider getDropPieceProvider ()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the speed with which the next board row should rise into
|
* Returns the speed with which the next board row should rise into
|
||||||
* place, in pixels per millisecond.
|
* place, in pixels per millisecond.
|
||||||
@@ -217,14 +207,14 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// evolve the board to kick-start the game into action
|
// evolve the board to kick-start the game into action
|
||||||
tryEvolveBoard();
|
unstabilizeBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
protected boolean canClearAction ()
|
protected boolean canClearAction ()
|
||||||
{
|
{
|
||||||
// Log.info("Drop can clear " + _evolving);
|
// Log.info("Drop can clear " + _stable);
|
||||||
return !_evolving && super.canClearAction();
|
return _stable && super.canClearAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -534,21 +524,21 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
}
|
}
|
||||||
// keep dropping the drop block
|
// keep dropping the drop block
|
||||||
sprite.drop();
|
sprite.drop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sprite.getDistance() > 0) {
|
||||||
|
sprite.drop();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (sprite.getDistance() > 0) {
|
// remove the sprite
|
||||||
sprite.drop();
|
_dview.removeSprite(sprite);
|
||||||
|
|
||||||
} else {
|
// apply the pieces to the board
|
||||||
// remove the sprite
|
applyDropSprite(sprite, col, row);
|
||||||
_dview.removeSprite(sprite);
|
|
||||||
|
|
||||||
// apply the pieces to the board
|
// perform any new destruction and falling
|
||||||
applyDropSprite(sprite, col, row);
|
unstabilizeBoard();
|
||||||
|
|
||||||
// perform any new destruction and falling
|
|
||||||
tryEvolveBoard();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,62 +552,13 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
// set the pieces in the board
|
// set the pieces in the board
|
||||||
int[] pieces = sprite.getPieces();
|
int[] pieces = sprite.getPieces();
|
||||||
_dboard.setSegment(VERTICAL, col, row, pieces);
|
_dboard.setSegment(VERTICAL, col, row, pieces);
|
||||||
// dirty the updated board pieces
|
// create the updated board pieces
|
||||||
_dview.dirtySegment(VERTICAL, col, row, pieces.length);
|
for (int dy = 0; dy < pieces.length; dy++) {
|
||||||
}
|
// pieces outside the board are discarded
|
||||||
|
if (row - dy >= 0) {
|
||||||
/**
|
// note: vertical segments are applied counting downwards
|
||||||
* Calls {@link #tryEvolveBoard(boolean)} with debugging deactivated.
|
// from the starting row toward row zero
|
||||||
*/
|
_dview.createPiece(pieces[dy], col, row - dy);
|
||||||
protected void tryEvolveBoard ()
|
|
||||||
{
|
|
||||||
tryEvolveBoard(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to evolve the board. This involves first calling {@link
|
|
||||||
* #canEvolveBoard} and only calling {@link #evolveBoard} if the
|
|
||||||
* former returned true. If the board is fully stabilized, {@link
|
|
||||||
* #boardDidStabilize} will be called to reinstate the puzzle action.
|
|
||||||
*/
|
|
||||||
protected void tryEvolveBoard (boolean debug)
|
|
||||||
{
|
|
||||||
// if we can't evolve the board because things are going on, we
|
|
||||||
// bail out immediately
|
|
||||||
if (!canEvolveBoard()) {
|
|
||||||
if (debug) {
|
|
||||||
Log.info("Can't evolve board " +
|
|
||||||
"[acount=" + _dview.getActionCount() + "].");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we do not evolve the board in any way, let the derived class
|
|
||||||
// know that the board stabilized so that they can drop in a new
|
|
||||||
// piece if they like or take whatever other action is appropriate
|
|
||||||
_evolving = evolveBoard();
|
|
||||||
if (debug) {
|
|
||||||
Log.info("Evolved board [evolving=" + _evolving + "].");
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're no longer evolving and the action has not ended, go
|
|
||||||
// ahead and let our derived class know that the board has
|
|
||||||
// stabilized so that it can drop in the next piece or somesuch
|
|
||||||
if (!_evolving) {
|
|
||||||
if (_ctrl.hasAction()) {
|
|
||||||
// this will trigger further puzzle activity
|
|
||||||
if (debug) {
|
|
||||||
Log.info("Board did stabilize");
|
|
||||||
}
|
|
||||||
boardDidStabilize();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (debug) {
|
|
||||||
Log.info("Maybe clearing action.");
|
|
||||||
}
|
|
||||||
// this will ensure that if we have been postponing action
|
|
||||||
// due to board evolution, that it will now be cleared
|
|
||||||
maybeClearAction();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -629,7 +570,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
*/
|
*/
|
||||||
protected boolean canEvolveBoard ()
|
protected boolean canEvolveBoard ()
|
||||||
{
|
{
|
||||||
return (_dview.getActionCount() == 0);
|
return (!_ctrl.isWaiting() && _dview.getActionCount() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -647,6 +588,16 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
*/
|
*/
|
||||||
protected abstract boolean evolveBoard ();
|
protected abstract boolean evolveBoard ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived classes should call this method whenever they change some
|
||||||
|
* board state that will require board evolution to restabilize the
|
||||||
|
* board.
|
||||||
|
*/
|
||||||
|
protected void unstabilizeBoard ()
|
||||||
|
{
|
||||||
|
_stable = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the board has been fully evolved and is once again
|
* Called when the board has been fully evolved and is once again
|
||||||
* stable. The default implementation updates the player's local board
|
* stable. The default implementation updates the player's local board
|
||||||
@@ -683,7 +634,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
*/
|
*/
|
||||||
protected void animationDidFinish (Animation anim)
|
protected void animationDidFinish (Animation anim)
|
||||||
{
|
{
|
||||||
tryEvolveBoard();
|
unstabilizeBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -766,7 +717,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
if (!error) {
|
if (!error) {
|
||||||
// stuff the piece into the board
|
// stuff the piece into the board
|
||||||
_dboard.setPiece(col, row, pieces[ii]);
|
_dboard.setPiece(col, row, pieces[ii]);
|
||||||
_dview.dirtyPiece(col, row);
|
_dview.createPiece(pieces[ii], col, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,7 +778,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
// forcibly land the block if we bounce twice at the same row
|
// forcibly land the block if we bounce twice at the same row
|
||||||
if (_bounceStamp == 0 && _bounceRow == bounceRow) {
|
if (_bounceStamp == 0 && _bounceRow == bounceRow) {
|
||||||
if (checkBlockLanded("double-bounced", true, true)) {
|
if (checkBlockLanded("double-bounced", true, true)) {
|
||||||
tryEvolveBoard();
|
unstabilizeBoard();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -878,7 +829,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
// make sure we weren't cancelled for some reason
|
// make sure we weren't cancelled for some reason
|
||||||
if (_bounceStamp != 0) {
|
if (_bounceStamp != 0) {
|
||||||
if (checkBlockLanded("bounced", true, true)) {
|
if (checkBlockLanded("bounced", true, true)) {
|
||||||
tryEvolveBoard();
|
unstabilizeBoard();
|
||||||
|
|
||||||
} else if (_blocksprite != null) {
|
} else if (_blocksprite != null) {
|
||||||
// take the block sprite out of bouncing mode
|
// take the block sprite out of bouncing mode
|
||||||
@@ -897,31 +848,20 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
*/
|
*/
|
||||||
protected boolean dropPieces ()
|
protected boolean dropPieces ()
|
||||||
{
|
{
|
||||||
// get a list of the piece columns to be dropped
|
PieceDropper.DropObserver drobs = new PieceDropper.DropObserver() {
|
||||||
List drops = _dropper.getDroppedPieces(_dboard, getDropPieceProvider());
|
public void pieceDropped (
|
||||||
int size = drops.size();
|
int piece, int sx, int sy, int dx, int dy) {
|
||||||
if (size == 0) {
|
float vel = getPieceVelocity(true) * 1.5f;
|
||||||
return false;
|
long duration = (long)(_dview.getPieceHeight() *
|
||||||
}
|
Math.abs(dy-sy) / vel);
|
||||||
|
if (sy < 0) {
|
||||||
// drop each column
|
_dview.createPiece(piece, sx, sy, dx, dy, duration);
|
||||||
for (int ii = 0; ii < size; ii++) {
|
} else {
|
||||||
PieceDropInfo pdi = (PieceDropInfo)drops.get(ii);
|
_dview.movePiece(sx, sy, dx, dy, duration);
|
||||||
// Log.info("Dropping column segment [pdi=" + pdi + "].");
|
}
|
||||||
|
}
|
||||||
// clear the dropping pieces from the board
|
};
|
||||||
_dboard.setSegment(
|
return (_dropper.dropPieces(_dboard, drobs) > 0);
|
||||||
VERTICAL, pdi.col, pdi.row, pdi.pieces.length, PIECE_NONE);
|
|
||||||
|
|
||||||
// create a piece sprite animating the pieces falling
|
|
||||||
DropSprite sprite = _dview.createPieces(
|
|
||||||
pdi.col, pdi.row, pdi.pieces, pdi.dist);
|
|
||||||
sprite.setVelocity(1.5f * getPieceVelocity(true));
|
|
||||||
sprite.addSpriteObserver(_dropMovedHandler);
|
|
||||||
_dview.addActionSprite(sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -948,6 +888,45 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
((tickStamp - _bounceStamp) >= _bounceInterval)) {
|
((tickStamp - _bounceStamp) >= _bounceInterval)) {
|
||||||
bounceTimerExpired();
|
bounceTimerExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we can't evolve the board because it doesn't need evolving
|
||||||
|
// or things are going on, we stop here
|
||||||
|
if (_stable || !canEvolveBoard()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we do not evolve the board in any way, let the derived class
|
||||||
|
// know that the board stabilized so that they can drop in a new
|
||||||
|
// piece if they like or take whatever other action is appropriate
|
||||||
|
boolean evolving = evolveBoard();
|
||||||
|
boolean debug = false;
|
||||||
|
if (debug) {
|
||||||
|
Log.info("Evolved board [evolving=" + evolving + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're no longer evolving and the action has not ended, go
|
||||||
|
// ahead and let our derived class know that the board has
|
||||||
|
// stabilized so that it can drop in the next piece or somesuch
|
||||||
|
if (!evolving) {
|
||||||
|
// no evolving again until someone destabilizes the board
|
||||||
|
_stable = true;
|
||||||
|
|
||||||
|
if (_ctrl.hasAction()) {
|
||||||
|
// this will trigger further puzzle activity
|
||||||
|
if (debug) {
|
||||||
|
Log.info("Board did stabilize");
|
||||||
|
}
|
||||||
|
boardDidStabilize();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (debug) {
|
||||||
|
Log.info("Maybe clearing action.");
|
||||||
|
}
|
||||||
|
// this will ensure that if we have been postponing action
|
||||||
|
// due to board evolution, that it will now be cleared
|
||||||
|
maybeClearAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
@@ -989,7 +968,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
|
|
||||||
// we're un-paused, so we should try evolving the board to start
|
// we're un-paused, so we should try evolving the board to start
|
||||||
// things up again
|
// things up again
|
||||||
tryEvolveBoard(true);
|
unstabilizeBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1107,7 +1086,7 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
|
|
||||||
if (canRise) {
|
if (canRise) {
|
||||||
// evolve the board
|
// evolve the board
|
||||||
tryEvolveBoard();
|
unstabilizeBoard();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.debug("Sticking fork in it [risers=" +
|
Log.debug("Sticking fork in it [risers=" +
|
||||||
@@ -1170,15 +1149,15 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
/** The drop board. */
|
/** The drop board. */
|
||||||
protected DropBoard _dboard;
|
protected DropBoard _dboard;
|
||||||
|
|
||||||
/** Whether or not we are in the middle of board evolution. */
|
|
||||||
protected boolean _evolving;
|
|
||||||
|
|
||||||
/** Whether the game is using drop block functionality. */
|
/** Whether the game is using drop block functionality. */
|
||||||
protected boolean _usedrop;
|
protected boolean _usedrop;
|
||||||
|
|
||||||
/** Whether the game is using board rising functionality. */
|
/** Whether the game is using board rising functionality. */
|
||||||
protected boolean _userise;
|
protected boolean _userise;
|
||||||
|
|
||||||
|
/** Whether or not the board is currently stable. */
|
||||||
|
protected boolean _stable;
|
||||||
|
|
||||||
/** The board dimensions in pieces. */
|
/** The board dimensions in pieces. */
|
||||||
protected int _bwid, _bhei;
|
protected int _bwid, _bhei;
|
||||||
|
|
||||||
@@ -1241,6 +1220,16 @@ public abstract class DropControllerDelegate extends PuzzleControllerDelegate
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** A piece operation that will update piece sprites as board
|
||||||
|
* positions are updated. */
|
||||||
|
protected DropBoard.PieceOperation _updateBoardOp =
|
||||||
|
new DropBoard.PieceOperation() {
|
||||||
|
public boolean execute (DropBoard board, int col, int row) {
|
||||||
|
_dview.updatePiece(col, row);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** The default board row rising velocity. */
|
/** The default board row rising velocity. */
|
||||||
protected static final float DEFAULT_RISE_VELOCITY = 100f / 1000f;
|
protected static final float DEFAULT_RISE_VELOCITY = 100f / 1000f;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: DropBoard.java,v 1.7 2004/08/27 02:20:30 mdb Exp $
|
// $Id: DropBoard.java,v 1.8 2004/08/29 06:50:47 mdb Exp $
|
||||||
//
|
//
|
||||||
// Narya library - tools for developing networked games
|
// Narya library - tools for developing networked games
|
||||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||||
@@ -145,6 +145,15 @@ public class DropBoard extends Board
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For boards that are always filled, this method is called to obtain
|
||||||
|
* pieces to fill the board.
|
||||||
|
*/
|
||||||
|
public int getNextPiece ()
|
||||||
|
{
|
||||||
|
return PIECE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the distance the piece at the given column and row can drop
|
* Returns the distance the piece at the given column and row can drop
|
||||||
* until it hits a non-empty piece (defined as {@link #PIECE_NONE}).
|
* until it hits a non-empty piece (defined as {@link #PIECE_NONE}).
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: DropManagerDelegate.java,v 1.4 2004/08/27 02:20:30 mdb Exp $
|
// $Id: DropManagerDelegate.java,v 1.5 2004/08/29 06:50:47 mdb Exp $
|
||||||
//
|
//
|
||||||
// Narya library - tools for developing networked games
|
// Narya library - tools for developing networked games
|
||||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||||
@@ -129,7 +129,7 @@ public abstract class DropManagerDelegate extends PuzzleManagerDelegate
|
|||||||
*/
|
*/
|
||||||
protected boolean dropPieces (DropBoard board)
|
protected boolean dropPieces (DropBoard board)
|
||||||
{
|
{
|
||||||
return (_dropper.dropPieces(board, null).size() > 0);
|
return (_dropper.dropPieces(board, null) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// $Id: DropPieceProvider.java,v 1.2 2004/08/27 02:20:31 mdb Exp $
|
|
||||||
//
|
|
||||||
// Narya library - tools for developing networked games
|
|
||||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
|
||||||
// http://www.threerings.net/code/narya/
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Lesser General Public License as published
|
|
||||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
package com.threerings.puzzle.drop.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does something extraordinary.
|
|
||||||
*/
|
|
||||||
public interface DropPieceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the next piece to add to the drop board.
|
|
||||||
*/
|
|
||||||
public int getNextPiece ()
|
|
||||||
throws OutOfPiecesException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I lost my touch.
|
|
||||||
*/
|
|
||||||
public static class OutOfPiecesException extends Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: PieceDropper.java,v 1.3 2004/08/27 02:20:31 mdb Exp $
|
// $Id: PieceDropper.java,v 1.4 2004/08/29 06:50:47 mdb Exp $
|
||||||
//
|
//
|
||||||
// Narya library - tools for developing networked games
|
// Narya library - tools for developing networked games
|
||||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
package com.threerings.puzzle.drop.util;
|
package com.threerings.puzzle.drop.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
@@ -71,6 +72,15 @@ public class PieceDropper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to inform a drop observer that a piece has been dropped.
|
||||||
|
*/
|
||||||
|
public static interface DropObserver
|
||||||
|
{
|
||||||
|
/** Indicates that the specified piece was dropped. */
|
||||||
|
public void pieceDropped (int piece, int sx, int sy, int dx, int dy);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a piece dropper that uses the supplied piece drop logic
|
* Constructs a piece dropper that uses the supplied piece drop logic
|
||||||
* to specialise itself for a particular puzzle.
|
* to specialise itself for a particular puzzle.
|
||||||
@@ -81,83 +91,63 @@ public class PieceDropper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructively modifies the supplied board to contain pieces dropped
|
* Effects any drops possible on the supplied board (modifying the
|
||||||
* in the first of potentially multiple drop positions and returns a
|
* board in the progress) and notifying the supplied drop observer of
|
||||||
* list of {@link PieceDropInfo} objects detailing all column segments
|
* those drops.
|
||||||
* to be dropped. Note that a single list is used internally to store
|
|
||||||
* the drop info objects, and so callers that care to do anything
|
|
||||||
* long-term with the drop info should create their own copy of the
|
|
||||||
* list or somesuch.
|
|
||||||
*
|
*
|
||||||
* @param DropPieceProvider if the board should always be filled
|
* @return the number of pieces dropped.
|
||||||
* (as specified by the PieceDropLogic) this will provide
|
|
||||||
* information on the newly filled in pieces.
|
|
||||||
*/
|
*/
|
||||||
public List dropPieces (DropBoard board, DropPieceProvider provider)
|
public int dropPieces (DropBoard board, DropObserver drobs)
|
||||||
{
|
{
|
||||||
int bhei = board.getHeight(), bwid = board.getWidth();
|
int dropped = 0, bhei = board.getHeight(), bwid = board.getWidth();
|
||||||
_drops.clear();
|
|
||||||
for (int yy = bhei - 1; yy >= 0; yy--) {
|
for (int yy = bhei - 1; yy >= 0; yy--) {
|
||||||
for (int xx = 0; xx < bwid; xx++) {
|
for (int xx = 0; xx < bwid; xx++) {
|
||||||
// find all drops in this column
|
dropped += dropPieces(board, xx, yy, drobs);
|
||||||
getColumnDrops(board, _drops, xx, yy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the board wants pieces to be dropped in to fill the gaps, do
|
||||||
|
// that now
|
||||||
if (_logic.boardAlwaysFilled()) {
|
if (_logic.boardAlwaysFilled()) {
|
||||||
addFillingDrops(board, provider, _drops);
|
for (int xx = 0; xx < bwid; xx++) {
|
||||||
|
int dist = board.getDropDistance(xx, -1);
|
||||||
|
for (int ii = 0; ii < dist; ii++) {
|
||||||
|
int yy = (-1 - ii);
|
||||||
|
int piece = board.getNextPiece();
|
||||||
|
if (piece != PIECE_NONE) {
|
||||||
|
drop(board, piece, xx, yy, yy + dist, drobs);
|
||||||
|
dropped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _drops;
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes but does not modify the supplied board and returns a list
|
* Computes and effects the drop for the specified piece and any
|
||||||
* of {@link PieceDropInfo} objects detailing all column segments to
|
* associated attached pieces. The supplied observer is notified of
|
||||||
* be dropped. Note that a single list is used internally to store
|
* all drops.
|
||||||
* the drop info objects, and so callers that care to do anything
|
|
||||||
* long-term with the drop info should create their own copy of the
|
|
||||||
* list or somesuch.
|
|
||||||
*
|
|
||||||
* @param DropPieceProvider if the board should always be filled
|
|
||||||
* (as specified by the PieceDropLogic) this will provide
|
|
||||||
* information on the newly filled in pieces.
|
|
||||||
*/
|
*/
|
||||||
public List getDroppedPieces (DropBoard board, DropPieceProvider provider)
|
protected int dropPieces (
|
||||||
{
|
DropBoard board, int xx, int yy, DropObserver drobs)
|
||||||
// grab a snapshot of the board within which we're dropping
|
|
||||||
// pieces to avoid modifying the source board directly while we're
|
|
||||||
// figuring out what to drop where
|
|
||||||
if (_board == null) {
|
|
||||||
_board = (DropBoard)board.clone();
|
|
||||||
} else {
|
|
||||||
board.copyInto(_board);
|
|
||||||
}
|
|
||||||
return dropPieces(_board, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populates the <code>drops</code> list with {@link PieceDropInfo}
|
|
||||||
* objects detailing the column segments to be dropped per empty space
|
|
||||||
* below. Destructively modifies the given board to reflect the final
|
|
||||||
* positions of the column segments once dropped.
|
|
||||||
*/
|
|
||||||
protected void getColumnDrops (DropBoard board, List drops, int x, int y)
|
|
||||||
{
|
{
|
||||||
// skip empty or fixed pieces
|
// skip empty or fixed pieces
|
||||||
int piece = board.getPiece(x, y);
|
int piece = board.getPiece(xx, yy);
|
||||||
if (!_logic.isDroppablePiece(piece)) {
|
if (!_logic.isDroppablePiece(piece)) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dropped = 0;
|
||||||
if (_logic.isConstrainedPiece(piece)) {
|
if (_logic.isConstrainedPiece(piece)) {
|
||||||
// find out where this constrained block starts and ends
|
// find out where this constrained block starts and ends
|
||||||
int start = _logic.getConstrainedEdge(board, x, y, LEFT);
|
int start = _logic.getConstrainedEdge(board, xx, yy, LEFT);
|
||||||
int end = _logic.getConstrainedEdge(board, x, y, RIGHT);
|
int end = _logic.getConstrainedEdge(board, xx, yy, RIGHT);
|
||||||
int bwid = board.getWidth();
|
int bwid = board.getWidth();
|
||||||
if (start < 0 || end >= bwid) {
|
if (start < 0 || end >= bwid) {
|
||||||
Log.warning("Board reported bogus constrained edge " +
|
Log.warning("Board reported bogus constrained edge " +
|
||||||
"[x=" + x + ", y=" + y +
|
"[x=" + xx + ", y=" + yy +
|
||||||
", start=" + start + ", end=" + end + "].");
|
", start=" + start + ", end=" + end + "].");
|
||||||
board.dump();
|
board.dump();
|
||||||
start = Math.max(start, 0);
|
start = Math.max(start, 0);
|
||||||
@@ -167,182 +157,47 @@ public class PieceDropper
|
|||||||
// get the smallest drop distance across all of the block columns
|
// get the smallest drop distance across all of the block columns
|
||||||
int dist = board.getHeight() - 1;
|
int dist = board.getHeight() - 1;
|
||||||
for (int xpos = start; xpos <= end; xpos++) {
|
for (int xpos = start; xpos <= end; xpos++) {
|
||||||
dist = Math.min(dist, board.getDropDistance(xpos, y));
|
dist = Math.min(dist, board.getDropDistance(xpos, yy));
|
||||||
}
|
}
|
||||||
if (dist == 0) {
|
if (dist == 0) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scoot along the bottom edge of the block dropping each column
|
// scoot along the bottom edge of the block, noting the drop
|
||||||
|
// for each column
|
||||||
for (int xpos = start; xpos <= end; xpos++) {
|
for (int xpos = start; xpos <= end; xpos++) {
|
||||||
addDropInfo(board, drops, true, xpos, y, dist);
|
piece = board.getPiece(xpos, yy);
|
||||||
|
drop(board, piece, xpos, yy, yy + dist, drobs);
|
||||||
|
dropped++;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// get the distance to drop the pieces
|
// get the distance to drop the pieces
|
||||||
int dist = board.getDropDistance(x, y);
|
int dist = board.getDropDistance(xx, yy);
|
||||||
if (dist == 0) {
|
if (dist == 0) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
drop(board, piece, xx, yy, yy + dist, drobs);
|
||||||
// add the column segment to the list of drops
|
dropped++;
|
||||||
addDropInfo(board, drops, false, x, y, dist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Helpy helper function. */
|
||||||
* Adds a {@link PieceDropInfo} object to the drop list detailing
|
protected final void drop (DropBoard board, int piece,
|
||||||
* dropping of the column segment at the specified location.
|
int xx, int yy, int ty, DropObserver drobs)
|
||||||
*
|
|
||||||
* @param board the working board.
|
|
||||||
* @param allowConst whether to allow dropping constrained pieces in
|
|
||||||
* the specified column segment.
|
|
||||||
* @param x the column x-coordinate.
|
|
||||||
* @param y the column segment bottom y-coordinate.
|
|
||||||
* @param dist the distance to drop the pieces.
|
|
||||||
*/
|
|
||||||
protected void addDropInfo (DropBoard board, List drops,
|
|
||||||
boolean allowConst, int x, int y, int dist)
|
|
||||||
{
|
{
|
||||||
// sanity check our column
|
// don't try to clear things out if we're filling in from off-board
|
||||||
if (x < 0 || x >= board.getWidth()) {
|
if (yy >= 0) {
|
||||||
Log.warning("Requested to add bogus drop info [board=" + board +
|
board.setPiece(xx, yy, PIECE_NONE);
|
||||||
", drops=" + StringUtil.toString(drops) +
|
|
||||||
", allowConst=" + allowConst +
|
|
||||||
", x=" + x + ", y=" + y + ", dist=" + dist + "].");
|
|
||||||
Thread.dumpStack();
|
|
||||||
}
|
}
|
||||||
|
board.setPiece(xx, ty, piece);
|
||||||
// traverse up the column looking for an empty or block piece
|
if (drobs != null) {
|
||||||
// that will terminate this column segment
|
drobs.pieceDropped(piece, xx, yy, xx, ty);
|
||||||
int height = getDropHeight(board, allowConst, x, y, dist);
|
|
||||||
|
|
||||||
// create the piece drop info object
|
|
||||||
PieceDropInfo pdi = new PieceDropInfo(x, y, dist);
|
|
||||||
|
|
||||||
// copy in the relevant pieces
|
|
||||||
pdi.pieces = new int[height];
|
|
||||||
int idx = 0;
|
|
||||||
for (int yy = y; yy > (y - height); yy--) {
|
|
||||||
pdi.pieces[idx++] = board.getPiece(x, yy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the working copy of the board with the eventual
|
|
||||||
// piece locations
|
|
||||||
dropPieces(board, pdi);
|
|
||||||
|
|
||||||
// add the column segment to the pot
|
|
||||||
drops.add(pdi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we want to keep the board filled at all times,
|
|
||||||
* this method will be called to create drop objects for the
|
|
||||||
* newly-filled in pieces.
|
|
||||||
*/
|
|
||||||
protected void addFillingDrops (
|
|
||||||
DropBoard board, DropPieceProvider provider, List drops)
|
|
||||||
{
|
|
||||||
boolean out = false;
|
|
||||||
// drop in new pieces for empty spaces at the top
|
|
||||||
for (int xx=0, bwid=board.getWidth(); xx < bwid; xx++) {
|
|
||||||
// get the distance to drop the pieces
|
|
||||||
int dist = board.getDropDistance(xx, -1);
|
|
||||||
if (dist != 0) {
|
|
||||||
PieceDropInfo pdi = new PieceDropInfo(xx, -1, dist);
|
|
||||||
pdi.pieces = new int[dist];
|
|
||||||
for (int ii=0; ii < dist; ii++) {
|
|
||||||
try {
|
|
||||||
pdi.pieces[ii] = provider.getNextPiece();
|
|
||||||
} catch (DropPieceProvider.OutOfPiecesException oop) {
|
|
||||||
// well, how far did we get?
|
|
||||||
int[] something = new int[ii];
|
|
||||||
System.arraycopy(pdi.pieces, 0, something, 0, ii);
|
|
||||||
pdi.pieces = something;
|
|
||||||
out = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dropPieces(board, pdi);
|
|
||||||
drops.add(pdi);
|
|
||||||
|
|
||||||
// if we're outta pieces, bail.
|
|
||||||
if (out) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Allows puzzle-specific customizations. */
|
||||||
* Returns the height of the piece segment to be dropped at the
|
|
||||||
* given coordinates.
|
|
||||||
*/
|
|
||||||
protected int getDropHeight (
|
|
||||||
DropBoard board, boolean allowConst, int x, int y, int dist)
|
|
||||||
{
|
|
||||||
int height = 0;
|
|
||||||
for (int yy = y; yy >= 0; yy--) {
|
|
||||||
int curpiece = board.getPiece(x, yy);
|
|
||||||
if (!_logic.isClimbablePiece(allowConst, curpiece, true)) {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
height++;
|
|
||||||
|
|
||||||
if (!_logic.isClimbablePiece(allowConst, curpiece, false)) {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the given board to reflect the eventual destination of the
|
|
||||||
* given pieces.
|
|
||||||
*/
|
|
||||||
protected void dropPieces (DropBoard board, PieceDropInfo pdi)
|
|
||||||
{
|
|
||||||
// clear out the original piece positions
|
|
||||||
if (!board.setSegment(
|
|
||||||
VERTICAL, pdi.col, pdi.row, pdi.pieces.length, PIECE_NONE)) {
|
|
||||||
Log.warning("Bogosity encountered when clearing pieces for drop " +
|
|
||||||
"[bwid=" + board.getWidth() +
|
|
||||||
", bhei=" + board.getHeight() + ", pdi=" + pdi + "].");
|
|
||||||
}
|
|
||||||
// place the pieces in their destination positions
|
|
||||||
applyPieces(board, pdi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies the pieces in the given piece drop info object to the given
|
|
||||||
* board at their eventual destination positions.
|
|
||||||
*/
|
|
||||||
protected void applyPieces (DropBoard board, PieceDropInfo pdi)
|
|
||||||
{
|
|
||||||
int start = pdi.row, end = (pdi.row - pdi.pieces.length);
|
|
||||||
int idx = 0;
|
|
||||||
boolean error = false;
|
|
||||||
for (int yy = (start + pdi.dist); yy > (end + pdi.dist); yy--) {
|
|
||||||
error = !board.setPiece(pdi.col, yy, pdi.pieces[idx++]) || error;
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
Log.warning("Bogosity encountered while applying dropped " +
|
|
||||||
"pieces to board [bwid=" + board.getWidth() +
|
|
||||||
", bhei=" + board.getHeight() + ", pdi=" + pdi + "].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The piece drop logic used to allow puzzle-specific piece dropping
|
|
||||||
* hooks. */
|
|
||||||
protected PieceDropLogic _logic;
|
protected PieceDropLogic _logic;
|
||||||
|
|
||||||
/** The list of piece drop info objects detailing the piece drops
|
|
||||||
* resulting from the last call to {@link #getDroppedPieces}. */
|
|
||||||
protected ArrayList _drops = new ArrayList();
|
|
||||||
|
|
||||||
/** The board on which pieces are being dropped. */
|
|
||||||
protected DropBoard _board;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user