First checkin for the great Spades refactor.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3465 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Andrzej Kapolka
2005-04-12 02:50:17 +00:00
parent bc30a3f389
commit 7fd9b51cab
22 changed files with 2197 additions and 497 deletions
@@ -21,20 +21,22 @@
package com.threerings.parlor.card.client;
import com.threerings.util.Name;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.CardCodes;
import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.game.client.GameController;
import com.threerings.parlor.turn.client.TurnGameController;
/**
* A controller class for card games. Handles common functions like
* accepting dealt hands.
*/
public abstract class CardGameController extends GameController
implements CardCodes, CardGameReceiver
implements TurnGameController, CardCodes, CardGameReceiver
{
// Documentation inherited.
public void willEnterPlace (PlaceObject plobj)
@@ -54,6 +56,10 @@ public abstract class CardGameController extends GameController
CardGameDecoder.RECEIVER_CODE);
}
// Documentation inherited.
public void turnDidChange (Name turnHolder)
{}
/**
* Called when the server deals the client a new hand of cards. Default
* implementation does nothing.
@@ -72,4 +78,27 @@ public abstract class CardGameController extends GameController
*/
public void receivedCardsFromPlayer (int plidx, Card[] cards)
{}
/**
* Dispatched to the client when the server has forced it to send
* a set of cards to another player. Default implementation does
* nothing.
*
* @param plidx the index of the player to which the cards were sent
* @param cards the cards sent
*/
public void sentCardsToPlayer (int plidx, Card[] cards)
{}
/**
* Dispatched to the client when a set of cards is transferred between
* two other players in the game. Default implementation does nothing.
*
* @param fromidx the index of the player sending the cards
* @param toidx the index of the player receiving the cards
* @param cards the number of cards transferred
*/
public void cardsTransferredBetweenPlayers (int fromidx, int toidx,
int cards)
{}
}
@@ -24,6 +24,14 @@ public class CardGameDecoder extends InvocationDecoder
* notifications. */
public static final int RECEIVED_CARDS_FROM_PLAYER = 2;
/** The method id used to dispatch {@link CardGameReceiver#sentCardsToPlayer}
* notifications. */
public static final int SENT_CARDS_TO_PLAYER = 3;
/** The method id used to dispatch {@link CardGameReceiver#cardsTransferredBetweenPlayers}
* notifications. */
public static final int CARDS_TRANSFERRED_BETWEEN_PLAYERS = 4;
/**
* Creates a decoder that may be registered to dispatch invocation
* service notifications to the specified receiver.
@@ -55,6 +63,18 @@ public class CardGameDecoder extends InvocationDecoder
);
return;
case SENT_CARDS_TO_PLAYER:
((CardGameReceiver)receiver).sentCardsToPlayer(
((Integer)args[0]).intValue(), (Card[])args[1]
);
return;
case CARDS_TRANSFERRED_BETWEEN_PLAYERS:
((CardGameReceiver)receiver).cardsTransferredBetweenPlayers(
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), ((Integer)args[2]).intValue()
);
return;
default:
super.dispatchNotification(methodId, args);
}
@@ -47,4 +47,24 @@ public interface CardGameReceiver extends InvocationReceiver
* @param cards the cards received
*/
public void receivedCardsFromPlayer (int plidx, Card[] cards);
/**
* Dispatched to the client when the server has forced it to send
* a set of cards to another player.
*
* @param plidx the index of the player to which the cards were sent
* @param cards the cards sent
*/
public void sentCardsToPlayer (int plidx, Card[] cards);
/**
* Dispatched to the client when a set of cards is transferred between
* two other players in the game.
*
* @param fromidx the index of the player sending the cards
* @param toidx the index of the player receiving the cards
* @param cards the number of cards transferred
*/
public void cardsTransferredBetweenPlayers (int fromidx, int toidx,
int cards);
}
@@ -1,26 +0,0 @@
//
// $Id: RoisterService.java 17829 2004-11-12 20:24:43Z mdb $
package com.threerings.parlor.card.client;
import com.threerings.parlor.card.data.Card;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
/**
* Service calls related to card games.
*/
public interface CardGameService extends InvocationService
{
/**
* Sends a set of cards to another player.
*
* @param client the client object
* @param playerIndex the index of the player to receive the cards
* @param cards the cards to send
* @param cl a listener to notify on success/failure
*/
public void sendCardsToPlayer (Client client, int playerIndex, Card[] cards,
ConfirmListener cl);
}
File diff suppressed because it is too large Load Diff
@@ -21,9 +21,13 @@
package com.threerings.parlor.card.client;
import com.threerings.media.image.Mirage;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import com.threerings.media.image.Mirage;
import com.threerings.media.sprite.OrientableImageSprite;
import com.threerings.media.util.Path;
import com.threerings.parlor.card.data.Card;
@@ -31,12 +35,14 @@ import com.threerings.parlor.card.data.Card;
* A sprite representing a playing card.
*/
public class CardSprite extends OrientableImageSprite
implements Comparable
{
/**
* Creates a new upward-facing card sprite.
*
* @param panel the panel responsible for the sprite
* @param card the card to depict
* @param card the card to depict (can be null, in which case the
* card back will be shown)
*/
public CardSprite (CardPanel panel, Card card)
{
@@ -127,13 +133,199 @@ public class CardSprite extends OrientableImageSprite
return _draggable;
}
/**
* Sets the alpha value of this sprite.
*/
public void setAlpha (float alpha)
{
if (alpha < 0.0f) {
alpha = 0.0f;
} else if (alpha > 1.0f) {
alpha = 1.0f;
}
if (alpha != _alphaComposite.getAlpha()) {
_alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
alpha);
if (_mgr != null) {
_mgr.getRegionManager().invalidateRegion(_bounds);
}
}
}
/**
* Returns the alpha value of this sprite.
*/
public float getAlpha ()
{
return _alphaComposite.getAlpha();
}
/**
* Fades this sprite in over the specified duration after
* waiting for the specified delay.
*/
public void fadeIn (long delay, long duration)
{
setAlpha(0.0f);
_fadeStamp = 0;
_fadeDelay = delay;
_fadeInDuration = duration;
}
/**
* Puts this sprite on the specified path and fades it in over
* the specified duration.
*
* @param path the path to move along
* @param fadePortion the portion of time to spend fading in, from 0.0f (no time)
* to 1.0f (the entire time)
*/
public void moveAndFadeIn (Path path, long pathDuration, float fadePortion)
{
move(path);
setAlpha(0.0f);
_fadeInDuration = (long)(pathDuration*fadePortion);
}
/**
* Puts this sprite on the specified path and fades it out over
* the specified duration.
*
* @param path the path to move along
* @param pathDuration the duration of the path
* @param fadePortion the portion of time to spend fading out, from 0.0f (no time)
* to 1.0f (the entire time)
*/
public void moveAndFadeOut (Path path, long pathDuration, float fadePortion)
{
move(path);
setAlpha(1.0f);
_pathDuration = pathDuration;
_fadeOutDuration = (long)(pathDuration*fadePortion);
}
/**
* Puts this sprite on the specified path, fading it in over the specified
* duration at the beginning and fading it out at the end.
*
* @param path the path to move along
* @param pathDuration the duration of the path
* @param fadePortion the portion of time to spend fading in/out, from
* 0.0f (no time) to 1.0f (the entire time)
*/
public void moveAndFadeInAndOut (Path path, long pathDuration,
float fadePortion)
{
move(path);
setAlpha(0.0f);
_pathDuration = pathDuration;
_fadeInDuration = _fadeOutDuration = (long)(pathDuration*fadePortion);
}
// Documentation inherited.
public void tick (long tickStamp)
{
super.tick(tickStamp);
if (_fadeInDuration != -1) {
if (_path != null && (tickStamp-_pathStamp) <= _fadeInDuration) {
// fading in while moving
float alpha = (float)(tickStamp-_pathStamp)/_fadeInDuration;
if (alpha >= 1.0f) {
// fade-in complete
setAlpha(1.0f);
_fadeInDuration = -1;
} else {
setAlpha(alpha);
}
} else {
// fading in while stationary
if (_fadeStamp == 0) {
// store the time at which fade started
_fadeStamp = tickStamp;
}
if (tickStamp > _fadeStamp + _fadeDelay) {
// initial delay has passed
float alpha = (float)(tickStamp-_fadeStamp-_fadeDelay)/_fadeInDuration;
if (alpha >= 1.0f) {
// fade-in complete
setAlpha(1.0f);
_fadeInDuration = -1;
} else {
setAlpha(alpha);
}
}
}
} else if(_fadeOutDuration != -1 && _pathStamp+_pathDuration-tickStamp
<= _fadeOutDuration) {
// fading out while moving
float alpha = (float)(_pathStamp+_pathDuration-tickStamp)/_fadeOutDuration;
setAlpha(alpha);
}
}
// Documentation inherited.
public void pathCompleted (long timestamp)
{
super.pathCompleted(timestamp);
if (_fadeInDuration != -1) {
setAlpha(1.0f);
_fadeInDuration = -1;
} else if(_fadeOutDuration != -1) {
setAlpha(0.0f);
_fadeOutDuration = -1;
}
}
// Documentation inherited.
public void paint (Graphics2D gfx)
{
if (_alphaComposite.getAlpha() < 1.0f) {
Composite ocomp = gfx.getComposite();
gfx.setComposite(_alphaComposite);
super.paint(gfx);
gfx.setComposite(ocomp);
} else {
super.paint(gfx);
}
}
/**
* Compares this to another card sprite based on their cards.
*/
public int compareTo (Object other)
{
CardSprite cs = (CardSprite)other;
if (_card == null || cs._card == null) {
return 0;
} else {
return _card.compareTo(cs._card);
}
}
/**
* Updates the mirage according to the current state.
*/
protected void updateMirage ()
{
setMirage(_facingUp ? _panel.getCardImage(_card) :
_panel.getCardBackImage());
setMirage((_card != null && _facingUp ) ?
_panel.getCardImage(_card) : _panel.getCardBackImage());
}
/** The panel responsible for the sprite. */
@@ -147,4 +339,23 @@ public class CardSprite extends OrientableImageSprite
/** Whether or not the user can drag the card around the board. */
protected boolean _draggable;
/** The alpha composite. */
protected AlphaComposite _alphaComposite =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
/** If fading in, the fade-in duration (otherwise -1). */
protected long _fadeInDuration = -1;
/** If fading in without moving, the fade-in delay. */
protected long _fadeDelay;
/** The time at which fading started. */
protected long _fadeStamp = -1;
/** If fading out, the fade-out duration (otherwise -1). */
protected long _fadeOutDuration = -1;
/** If fading out, the path duration. */
protected long _pathDuration;
}
@@ -28,29 +28,4 @@ import com.threerings.parlor.game.data.GameObject;
*/
public class CardGameObject extends GameObject
{
// AUTO-GENERATED: FIELDS START
/** The field name of the <code>cardGameService</code> field. */
public static final String CARD_GAME_SERVICE = "cardGameService";
// AUTO-GENERATED: FIELDS END
/** The card game service interface. */
public CardGameMarshaller cardGameService;
// AUTO-GENERATED: METHODS START
/**
* Requests that the <code>cardGameService</code> field be set to the
* specified value. The local value will be updated immediately and an
* event will be propagated through the system to notify all listeners
* that the attribute did change. Proxied copies of this object (on
* clients) will apply the value change when they received the
* attribute changed notification.
*/
public void setCardGameService (CardGameMarshaller value)
{
CardGameMarshaller ovalue = this.cardGameService;
requestAttributeChange(
CARD_GAME_SERVICE, value, ovalue);
this.cardGameService = value;
}
// AUTO-GENERATED: METHODS END
}
@@ -23,28 +23,20 @@ package com.threerings.parlor.card.data;
import java.util.Collections;
import com.threerings.io.Streamable;
import com.threerings.util.StreamableArrayList;
/**
* Instances of this class represent decks of cards.
*/
public class Deck implements CardCodes,
Streamable
public class Deck extends StreamableArrayList
implements CardCodes
{
/** The cards in the deck. */
public StreamableArrayList cards;
/**
* Default constructor creates an unshuffled deck of cards without
* jokers.
*/
public Deck ()
{
cards = new StreamableArrayList();
reset(false);
}
@@ -56,8 +48,6 @@ public class Deck implements CardCodes,
*/
public Deck (boolean includeJokers)
{
cards = new StreamableArrayList();
reset(includeJokers);
}
@@ -70,17 +60,17 @@ public class Deck implements CardCodes,
*/
public void reset (boolean includeJokers)
{
cards.clear();
clear();
for (int i=SPADES;i<=DIAMONDS;i++) {
for (int j=2;j<=ACE;j++) {
cards.add(new Card(j, i));
for (int i = SPADES; i <= DIAMONDS; i++) {
for (int j = 2; j <= ACE; j++) {
add(new Card(j, i));
}
}
if (includeJokers) {
cards.add(new Card(RED_JOKER, 3));
cards.add(new Card(BLACK_JOKER, 3));
add(new Card(RED_JOKER, 3));
add(new Card(BLACK_JOKER, 3));
}
}
@@ -89,7 +79,7 @@ public class Deck implements CardCodes,
*/
public void shuffle ()
{
Collections.shuffle(cards);
Collections.shuffle(this);
}
/**
@@ -101,15 +91,15 @@ public class Deck implements CardCodes,
*/
public Hand dealHand (int size)
{
if (cards.size() < size) {
if (size() < size) {
return null;
}
else {
} else {
Hand hand = new Hand();
int cardsLeft = cards.size();
for (int i=0;i<size;i++) {
hand.cards.add(cards.remove(--cardsLeft));
int cardsLeft = size();
for (int i = 0; i < size; i++) {
hand.add(remove(--cardsLeft));
}
return hand;
@@ -123,17 +113,7 @@ public class Deck implements CardCodes,
*/
public void returnHand (Hand hand)
{
cards.addAll(hand.cards);
hand.cards.clear();
}
/**
* Returns a string representation of this deck.
*
* @return a description of this deck
*/
public String toString ()
{
return "[cards=" + cards.toString() + "]";
addAll(hand);
hand.clear();
}
}
@@ -1,5 +1,5 @@
//
// $Id: Hand.java,v 1.4 2004/10/15 18:20:28 andrzej Exp $
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
@@ -21,28 +21,44 @@
package com.threerings.parlor.card.data;
import java.util.Iterator;
import com.threerings.io.Streamable;
import com.threerings.util.StreamableArrayList;
/**
* Instances of this class represent hands of cards.
*/
public class Hand implements CardCodes,
Streamable
public class Hand extends StreamableArrayList
{
/** The cards in the hand. */
public StreamableArrayList cards;
/**
* Adds all of the specified cards to this hand.
*/
public void addAll (Card[] cards)
{
for (int i = 0; i < cards.length; i++) {
add(cards[i]);
}
}
/**
* Default constructor creates an empty hand.
* Removes all of the specified cards from this hand.
*/
public Hand ()
public void removeAll (Card[] cards)
{
cards = new StreamableArrayList();
for (int i = 0; i < cards.length; i++) {
remove(cards[i]);
}
}
/**
* Checks whether this hand contains all of the specified cards.
*/
public boolean containsAll (Card[] cards)
{
for (int i = 0; i < cards.length; i++) {
if (!contains(cards[i])) {
return false;
}
}
return true;
}
/**
@@ -53,26 +69,12 @@ public class Hand implements CardCodes,
*/
public int getSuitMemberCount (int suit)
{
int members = 0;
Iterator it = cards.iterator();
while (it.hasNext()) {
if (((Card)it.next()).getSuit() == suit) {
members++;
int len = size(), members = 0;
for (int i = 0; i < len; i++) {
if (((Card)get(i)).getSuit() == suit) {
members++;
}
}
return members;
}
/**
* Returns a string representation of this hand.
*
* @return a description of this hand
*/
public String toString ()
{
return "[cards=" + cards.toString() + "]";
}
}
@@ -1,5 +1,5 @@
//
// $Id$
// $Id: TrickCardGameObject.java 3382 2005-03-03 19:55:35Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
@@ -19,29 +19,36 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.card.trick.client;
package com.threerings.parlor.card.data;
import com.threerings.parlor.turn.client.TurnGameController;
import com.threerings.io.Streamable;
/**
* A card game controller interface for trick-based card games, such as
* Spades and Hearts.
* Pairs a player index with the card that the player played in the trick.
*/
public interface TrickCardGameController extends TurnGameController
public class PlayerCard implements Streamable
{
/**
* Notifies the controller that the gameplay entered or left a hand.
*
* @param playingHand true if the gameplay entered a hand, false if
* it left one
*/
public void playingHandDidChange (boolean playingHand);
/** The index of the player. */
public int pidx;
/** The card that the player played. */
public Card card;
/**
* Notifies the controller that the gameplay entered or left a trick.
*
* @param playingTrick true if the gameplay entered a trick, false if
* it left one
* No-argument constructor for deserialization.
*/
public void playingTrickDidChange (boolean playingTrick);
public PlayerCard ()
{}
/**
* Creates a new player card.
*
* @param pidx the index of the player
* @param card the card played
*/
public PlayerCard (int pidx, Card card)
{
this.pidx = pidx;
this.card = card;
}
}
@@ -22,17 +22,18 @@
package com.threerings.parlor.card.server;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.OccupantInfo;
import com.threerings.crowd.server.OccupantOp;
import com.threerings.parlor.card.Log;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.CardCodes;
import com.threerings.parlor.card.data.CardGameMarshaller;
import com.threerings.parlor.card.data.CardGameObject;
import com.threerings.parlor.card.data.Deck;
import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.game.server.GameManager;
import com.threerings.parlor.turn.server.TurnGameManager;
import com.threerings.presents.client.InvocationService.ConfirmListener;
import com.threerings.presents.data.ClientObject;
@@ -45,27 +46,26 @@ import com.threerings.presents.server.PresentsServer;
* hands of cards to all players.
*/
public class CardGameManager extends GameManager
implements CardCodes, CardGameProvider
implements TurnGameManager, CardCodes
{
// Documentation inherited.
protected void didStartup ()
{
super.didStartup();
_cardgameobj = (CardGameObject)_gameobj;
_cardgameobj.setCardGameService(
(CardGameMarshaller)PresentsServer.invmgr.registerDispatcher(
new CardGameDispatcher(this), false));
}
// Documentation inherited.
protected void didShutdown ()
{
super.didShutdown();
PresentsServer.invmgr.clearDispatcher(_cardgameobj.cardGameService);
}
public void turnWillStart ()
{}
// Documentation inherited.
public void turnDidStart ()
{}
// Documentation inherited.
public void turnDidEnd ()
{}
/**
* Deals a hand of cards to the player at the specified index from
@@ -79,7 +79,7 @@ public class CardGameManager extends GameManager
*/
public Hand dealHand (Deck deck, int size, int playerIndex)
{
if (deck.cards.size() < size) {
if (deck.size() < size) {
return null;
}
else {
@@ -105,7 +105,7 @@ public class CardGameManager extends GameManager
*/
public Hand[] dealHands (Deck deck, int size)
{
if (deck.cards.size() < size * _playerCount) {
if (deck.size() < size * _playerCount) {
return null;
}
else {
@@ -135,47 +135,11 @@ public class CardGameManager extends GameManager
}
/**
* Checks whether or not it is acceptable to transfer the given set of
* cards from the first player to the second. Default implementation
* simply returns true.
*
* @param fromPlayerIdx the index of the sending player
* @param toPlayerIdx the index of the receiving player
* @param cards the cards to send
* @return true if the transfer is should proceed, false otherwise
* Returns the client object corresponding to the specified player index.
*/
protected boolean acceptTransferBetweenPlayers(int fromPlayerIdx,
int toPlayerIdx, Card[] cards)
public ClientObject getClientObject (int pidx)
{
return true;
}
/**
* Processes a request to send a set of cards from one player to another.
* Calls {@link #acceptTransferBetweenPlayers
* acceptTransferBetweenPlayers} to determine whether or not
* to process the transfer, and {@link #transferCardsBetweenPlayers
* transferCardsBetweenPlayers} to
* perform the transfer if accepted.
*
* @param client the client object
* @param playerIndex the index of the player to receive the cards
* @param cards the cards to send
* @param cl a listener to notify on success/failure
*/
public void sendCardsToPlayer (ClientObject client, int playerIndex,
Card[] cards, ConfirmListener cl)
throws InvocationException
{
int fromPlayerIdx = getPlayerIndex(client);
if (acceptTransferBetweenPlayers(fromPlayerIdx, playerIndex, cards)) {
transferCardsBetweenPlayers(getPlayerIndex(client), playerIndex,
cards);
cl.requestProcessed();
} else {
throw new InvocationException("m.transfer_rejected");
}
return (ClientObject)PresentsServer.omgr.getObject(_playerOids[pidx]);
}
/**
@@ -185,14 +149,34 @@ public class CardGameManager extends GameManager
* @param toPlayerIdx the index of the player receiving the cards
* @param cards the cards to be exchanged
*/
public void transferCardsBetweenPlayers (int fromPlayerIdx,
int toPlayerIdx, Card[] cards)
public void transferCardsBetweenPlayers (final int fromPlayerIdx,
final int toPlayerIdx, final Card[] cards)
{
CardGameSender.sendCardsFromPlayer(
(ClientObject)PresentsServer.omgr.getObject(
_playerOids[toPlayerIdx]), fromPlayerIdx, cards);
// Notify the sender that the cards have been taken
CardGameSender.sentCardsToPlayer(getClientObject(fromPlayerIdx),
toPlayerIdx, cards);
// Notify the receiver with the cards
CardGameSender.sendCardsFromPlayer(getClientObject(toPlayerIdx),
fromPlayerIdx, cards);
// and everybody else in the room other than the sender and the
// receiver with the number of cards sent
final int senderOid = _playerOids[fromPlayerIdx],
receiverOid = _playerOids[toPlayerIdx];
OccupantOp op = new OccupantOp() {
public void apply (OccupantInfo info) {
int oid = info.getBodyOid();
if (oid != senderOid && oid != receiverOid) {
CardGameSender.cardsTransferredBetweenPlayers(
(ClientObject)PresentsServer.omgr.getObject(
oid), fromPlayerIdx, toPlayerIdx, cards.length);
}
}
};
applyToOccupants(op);
}
/** The card game object. */
protected CardGameObject _cardgameobj;
}
@@ -1,30 +0,0 @@
//
// $Id: RoisterService.java 17829 2004-11-12 20:24:43Z mdb $
package com.threerings.parlor.card.server;
import com.threerings.parlor.card.data.Card;
import com.threerings.presents.client.InvocationService.ConfirmListener;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.InvocationProvider;
/**
* Service calls related to card games.
*/
public interface CardGameProvider extends InvocationProvider
{
/**
* Sends a set of cards to another player.
*
* @param client the client object
* @param playerIndex the index of the player to receive the cards
* @param cards the cards to send
* @param cl a listener to notify on success/failure
* @exception InvocationException if an error occurs
*/
public void sendCardsToPlayer (ClientObject client, int playerIndex,
Card[] cards, ConfirmListener cl)
throws InvocationException;
}
@@ -40,4 +40,28 @@ public class CardGameSender extends InvocationSender
new Object[] { new Integer(arg1), arg2 });
}
/**
* Issues a notification that will result in a call to {@link
* CardGameReceiver#sentCardsToPlayer} on a client.
*/
public static void sentCardsToPlayer (
ClientObject target, int arg1, Card[] arg2)
{
sendNotification(
target, CardGameDecoder.RECEIVER_CODE, CardGameDecoder.SENT_CARDS_TO_PLAYER,
new Object[] { new Integer(arg1), arg2 });
}
/**
* Issues a notification that will result in a call to {@link
* CardGameReceiver#cardsTransferredBetweenPlayers} on a client.
*/
public static void cardsTransferredBetweenPlayers (
ClientObject target, int arg1, int arg2, int arg3)
{
sendNotification(
target, CardGameDecoder.RECEIVER_CODE, CardGameDecoder.CARDS_TRANSFERRED_BETWEEN_PLAYERS,
new Object[] { new Integer(arg1), new Integer(arg2), new Integer(arg3) });
}
}
@@ -21,11 +21,9 @@
package com.threerings.parlor.card.trick.client;
import com.threerings.presents.dobj.AttributeChangedEvent;
import com.threerings.parlor.turn.client.TurnGameControllerDelegate;
import com.threerings.parlor.card.trick.data.TrickCardGameObject;
import com.threerings.parlor.card.client.CardGameController;
/**
* A card game controller delegate for trick-based card games, such as
@@ -39,30 +37,13 @@ public class TrickCardGameControllerDelegate
*
* @param controller the game controller
*/
public TrickCardGameControllerDelegate (TrickCardGameController
public TrickCardGameControllerDelegate (CardGameController
controller)
{
super(controller);
_tcgctrl = controller;
_cgctrl = controller;
}
// Documentation inherited
public void attributeChanged (AttributeChangedEvent ace)
{
super.attributeChanged(ace);
TrickCardGameObject tcgObj = (TrickCardGameObject)_gameObj;
if (ace.getName().equals(tcgObj.getPlayingHandFieldName())) {
_tcgctrl.playingHandDidChange(tcgObj.getPlayingHand());
}
else if (ace.getName().equals(tcgObj.getPlayingTrickFieldName())) {
_tcgctrl.playingTrickDidChange(tcgObj.getPlayingTrick());
}
}
/** The trick card game controller. */
protected TrickCardGameController _tcgctrl;
/** The card game controller. */
protected CardGameController _cgctrl;
}
@@ -0,0 +1,32 @@
//
// $Id: RoisterService.java 17829 2004-11-12 20:24:43Z mdb $
package com.threerings.parlor.card.trick.client;
import com.threerings.parlor.card.data.Card;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
/**
* Service calls related to trick card games.
*/
public interface TrickCardGameService extends InvocationService
{
/**
* Sends a group of cards to the player at the specified index.
*
* @param client the client object
* @param toidx the index of the player to send the cards to
* @param cards the cards to send
*/
public void sendCardsToPlayer (Client client, int toidx, Card[] cards);
/**
* Plays a card in the trick.
*
* @param client the client object
* @param card the card to play
*/
public void playCard (Client client, Card card);
}
@@ -1,5 +1,5 @@
//
// $Id$
// $Id: CardCodes.java 3224 2004-11-19 19:04:56Z andrzej $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
@@ -19,43 +19,24 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.card.trick.server;
package com.threerings.parlor.card.trick.data;
import com.threerings.parlor.turn.server.TurnGameManager;
import com.threerings.parlor.card.data.CardCodes;
/**
* A card game manager interface for trick-based card games, such as
* Spades and Hearts.
* Constants relating to trick-based card games.
*/
public interface TrickCardGameManager extends TurnGameManager
public interface TrickCardCodes extends CardCodes
{
/**
* Notifies the manager that a hand is about to start.
*/
public void handWillStart ();
/** For four-player games, the top (opposite) player. */
public static final int TOP = 0;
/**
* Notifies the manager that a hand just started.
*/
public void handDidStart ();
/** For four-player games, the bottom (own) player. */
public static final int BOTTOM = 1;
/**
* Notifies the manager that a hand has ended.
*/
public void handDidEnd ();
/** For four-player games, the player on the left. */
public static final int LEFT = 2;
/**
* Notifies the manager that a trick is about to start.
*/
public void trickWillStart ();
/**
* Notifies the manager that a trick just started.
*/
public void trickDidStart ();
/**
* Notifies the manager that a trick has ended.
*/
public void trickDidEnd ();
/** For four-player games, the player on the right. */
public static final int RIGHT = 3;
}
@@ -19,35 +19,43 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.card.data;
package com.threerings.parlor.card.trick.data;
import com.threerings.parlor.card.client.CardGameService;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.trick.client.TrickCardGameService;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
/**
* Provides the implementation of the {@link CardGameService} interface
* Provides the implementation of the {@link TrickCardGameService} interface
* that marshalls the arguments and delivers the request to the provider
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*/
public class CardGameMarshaller extends InvocationMarshaller
implements CardGameService
public class TrickCardGameMarshaller extends InvocationMarshaller
implements TrickCardGameService
{
/** The method id used to dispatch {@link #sendCardsToPlayer} requests. */
public static final int SEND_CARDS_TO_PLAYER = 1;
/** The method id used to dispatch {@link #playCard} requests. */
public static final int PLAY_CARD = 1;
// documentation inherited from interface
public void sendCardsToPlayer (Client arg1, int arg2, Card[] arg3, InvocationService.ConfirmListener arg4)
public void playCard (Client arg1, Card arg2)
{
sendRequest(arg1, PLAY_CARD, new Object[] {
arg2
});
}
/** The method id used to dispatch {@link #sendCardsToPlayer} requests. */
public static final int SEND_CARDS_TO_PLAYER = 2;
// documentation inherited from interface
public void sendCardsToPlayer (Client arg1, int arg2, Card[] arg3)
{
InvocationMarshaller.ConfirmMarshaller listener4 = new InvocationMarshaller.ConfirmMarshaller();
listener4.listener = arg4;
sendRequest(arg1, SEND_CARDS_TO_PLAYER, new Object[] {
new Integer(arg2), arg3, listener4
new Integer(arg2), arg3
});
}
@@ -21,6 +21,9 @@
package com.threerings.parlor.card.trick.data;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.card.data.PlayerCard;
import com.threerings.parlor.turn.data.TurnGameObject;
/**
@@ -28,47 +31,113 @@ import com.threerings.parlor.turn.data.TurnGameObject;
*/
public interface TrickCardGameObject extends TurnGameObject
{
/**
* Returns the name of the field that signals whether or not the users
* are currently playing a hand.
*
* @return the name of the playingHand field
*/
public String getPlayingHandFieldName ();
/** The state that indicates the game is currently between hands. */
public static final int BETWEEN_HANDS = 0;
/** The state that indicates the game is currently playing a hand. */
public static final int PLAYING_HAND = 1;
/** The state that indicates the game is currently playing a trick. */
public static final int PLAYING_TRICK = 2;
/** The number of states defined for the base trick card game object. */
public static final int TRICK_STATE_COUNT = 3;
/**
* Checks whether the users are currently playing a hand.
* Returns a reference to the trick card game service used to make
* requests to the server.
*
* @return true if the users are playing a hand, false otherwise
* @return a reference to the trick card game service
*/
public boolean getPlayingHand ();
public TrickCardGameMarshaller getTrickCardGameService ();
/**
* Brings the gameplay in or out of a hand.
* Sets the reference to the trick card game service.
*
* @param playingHand true to enter a hand, false to leave one
* @param trickCardGameService the trick card game service
*/
public void setPlayingHand (boolean playingHand);
public void setTrickCardGameService (TrickCardGameMarshaller
trickCardGameService);
/**
* Returns the name of the field that signals whether or not the users
* are currently playing a trick.
* Returns the name of the field that contains the trick state: between
* hands, playing a hand, or playing a trick.
*
* @return the name of the playingTrick field
* @return the name of the trickState field
*/
public String getPlayingTrickFieldName ();
public String getTrickStateFieldName ();
/**
* Checks whether the users are currently playing a trick.
* Returns the trick state: between hands, playing a hand, or playing a
* trick.
*
* @return true if the users are playing a trick, false otherwise
* @return the trick state
*/
public boolean getPlayingTrick ();
public int getTrickState ();
/**
* Sets the trick state.
*
* @param trickState the trick state
*/
public void setTrickState (int trickState);
/**
* Brings the gameplay in or out of a trick.
* Returns the name of the field that contains the history of the trick
* in terms of the cards played by each player.
*
* @param playingTrick true to enter a trick, false to leave one
* @return the name of the cardsPlayed field
*/
public void setPlayingTrick (boolean playingTrick);
public String getCardsPlayedFieldName ();
/**
* Returns an array containing the history of the trick in terms of the
* cards played by each player.
*
* @return the cards played so far in the trick
*/
public PlayerCard[] getCardsPlayed ();
/**
* Sets the array of cards played by each player.
*
* @param cardsPlayed the array of cards played
*/
public void setCardsPlayed (PlayerCard[] cardsPlayed);
/**
* Returns the name of the field that contains the history of the last
* trick in terms of the cards played by each player.
*
* @return the name of the lastCardsPlayed field
*/
public String getLastCardsPlayedFieldName ();
/**
* Returns an array containing the history of the last trick in terms of
* the cards played by each player.
*
* @return the cards played in the last trick
*/
public PlayerCard[] getLastCardsPlayed ();
/**
* Sets the last array of cards played by each player.
*
* @param lastCardsPlayed the last array of cards played
*/
public void setLastCardsPlayed (PlayerCard[] lastCardsPlayed);
/**
* Checks whether a user can play the specified card at this time.
*
* @param hand the player's hand
* @param card the card that the user would like to play
*/
public boolean isCardPlayable (Hand hand, Card card);
/**
* Returns the card of the player who took the current trick.
*/
public PlayerCard getTrickTaker ();
}
@@ -19,28 +19,27 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.card.server;
package com.threerings.parlor.card.trick.server;
import com.threerings.parlor.card.client.CardGameService;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.CardGameMarshaller;
import com.threerings.parlor.card.trick.client.TrickCardGameService;
import com.threerings.parlor.card.trick.data.TrickCardGameMarshaller;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.server.InvocationDispatcher;
import com.threerings.presents.server.InvocationException;
/**
* Dispatches requests to the {@link CardGameProvider}.
* Dispatches requests to the {@link TrickCardGameProvider}.
*/
public class CardGameDispatcher extends InvocationDispatcher
public class TrickCardGameDispatcher extends InvocationDispatcher
{
/**
* Creates a dispatcher that may be registered to dispatch invocation
* service requests for the specified provider.
*/
public CardGameDispatcher (CardGameProvider provider)
public TrickCardGameDispatcher (TrickCardGameProvider provider)
{
this.provider = provider;
}
@@ -48,7 +47,7 @@ public class CardGameDispatcher extends InvocationDispatcher
// documentation inherited
public InvocationMarshaller createMarshaller ()
{
return new CardGameMarshaller();
return new TrickCardGameMarshaller();
}
// documentation inherited
@@ -57,10 +56,17 @@ public class CardGameDispatcher extends InvocationDispatcher
throws InvocationException
{
switch (methodId) {
case CardGameMarshaller.SEND_CARDS_TO_PLAYER:
((CardGameProvider)provider).sendCardsToPlayer(
case TrickCardGameMarshaller.PLAY_CARD:
((TrickCardGameProvider)provider).playCard(
source,
((Integer)args[0]).intValue(), (Card[])args[1], (InvocationService.ConfirmListener)args[2]
(Card)args[0]
);
return;
case TrickCardGameMarshaller.SEND_CARDS_TO_PLAYER:
((TrickCardGameProvider)provider).sendCardsToPlayer(
source,
((Integer)args[0]).intValue(), (Card[])args[1]
);
return;
@@ -21,10 +21,31 @@
package com.threerings.parlor.card.trick.server;
import java.util.ArrayList;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.Interval;
import com.threerings.util.Name;
import com.threerings.util.RandomUtil;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.PresentsServer;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.game.server.GameManager;
import com.threerings.parlor.turn.server.TurnGameManagerDelegate;
import com.threerings.parlor.card.Log;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.CardGameObject;
import com.threerings.parlor.card.data.Deck;
import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.card.data.PlayerCard;
import com.threerings.parlor.card.server.CardGameManager;
import com.threerings.parlor.card.trick.data.TrickCardGameMarshaller;
import com.threerings.parlor.card.trick.data.TrickCardGameObject;
/**
@@ -32,41 +53,19 @@ import com.threerings.parlor.card.trick.data.TrickCardGameObject;
* Spades and Hearts.
*/
public class TrickCardGameManagerDelegate extends TurnGameManagerDelegate
implements TrickCardGameProvider
{
/**
* Constructor.
*
* @param manager the game manager
*/
public TrickCardGameManagerDelegate (TrickCardGameManager manager)
public TrickCardGameManagerDelegate (CardGameManager manager)
{
super(manager);
_tcgmgr = manager;
}
// Documentation inherited.
public void setFirstTurnHolder ()
{
if (_trickCardGame.getPlayingHand() &&
_trickCardGame.getPlayingTrick()) {
super.setFirstTurnHolder();
}
else {
_turnIdx = -1;
}
}
// Documentation inherited.
public void setNextTurnHolder ()
{
if (_trickCardGame.getPlayingHand() &&
_trickCardGame.getPlayingTrick()) {
super.setNextTurnHolder();
}
else {
_turnIdx = -1;
}
_cgmgr = manager;
_deck = new Deck();
}
// Documentation inherited.
@@ -75,56 +74,431 @@ public class TrickCardGameManagerDelegate extends TurnGameManagerDelegate
super.didStartup(plobj);
_trickCardGame = (TrickCardGameObject)plobj;
_cardGame = (CardGameObject)plobj;
_trickCardGame.setTrickCardGameService(
(TrickCardGameMarshaller)PresentsServer.invmgr.registerDispatcher(
new TrickCardGameDispatcher(this), false));
}
// Documentation inherited.
public void didShutdown ()
{
super.didShutdown();
PresentsServer.invmgr.clearDispatcher(
_trickCardGame.getTrickCardGameService());
}
/**
* Starts a hand of cards.
* Called when the game has started. Default implementation starts the
* first hand.
*/
public void gameDidStart ()
{
super.gameDidStart();
// start the first hand
startHand();
}
// Documentation inherited.
public void gameWillEnd ()
{
// make sure all intervals are cancelled
_turnTimeoutInterval.cancel();
_endTrickInterval.cancel();
// make sure trick state is back to between hands
if (_trickCardGame.getTrickState() !=
TrickCardGameObject.BETWEEN_HANDS) {
_trickCardGame.setTrickState(TrickCardGameObject.BETWEEN_HANDS);
}
super.gameDidEnd();
}
// Documentation inherited.
public void startTurn ()
{
super.startTurn();
// schedule the timeout interval
_turnTimeoutInterval.schedule(getTurnTimeoutDelay());
}
// Documentation inherited.
public void endTurn ()
{
// cancel the timeout interval
_turnTimeoutInterval.cancel();
super.endTurn();
}
/**
* Starts a hand of cards. Calls {@link #handWillStart}, sets the trick
* state to PLAYING_HAND, and calls {@link #handDidStart}.
*/
public void startHand ()
{
_tcgmgr.handWillStart();
_trickCardGame.setPlayingHand(true);
_tcgmgr.handDidStart();
handWillStart();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_HAND);
handDidStart();
}
/**
* Ends a hand of cards.
* Ends the hand of cards. Calls {@link #handWillEnd}, sets the trick
* state to BETWEEN_HANDS, and calls {@link #handDidEnd}.
*/
public void endHand ()
{
_trickCardGame.setPlayingHand(false);
_tcgmgr.handDidEnd();
handWillEnd();
_trickCardGame.setTrickState(TrickCardGameObject.BETWEEN_HANDS);
handDidEnd();
}
/**
* Starts a trick.
* Starts a trick. Calls {@link #trickWillStart}, sets the trick
* state to PLAYING_TRICK, and calls {@link #trickDidStart}.
*/
public void startTrick ()
{
_tcgmgr.trickWillStart();
_trickCardGame.setPlayingTrick(true);
_tcgmgr.trickDidStart();
trickWillStart();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_TRICK);
trickDidStart();
}
/**
* Ends a trick.
* Ends the trick. Calls {@link #trickWillEnd}, sets the trick
* state to PLAYING_HAND, and calls {@link #trickDidEnd}.
*/
public void endTrick ()
{
_trickCardGame.setPlayingTrick(false);
_tcgmgr.trickDidEnd();
trickWillEnd();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_HAND);
trickDidEnd();
}
/**
* Processes a request to transfer a group of cards between players.
* Default implementation verifies that the user's hand contains the
* specified cards, then transfers the cards (letting everyone know
* that the transfer has taken place).
*/
public void sendCardsToPlayer (ClientObject client, int toidx,
Card[] cards)
throws InvocationException
{
// make sure they're actually a player
int fromidx = _cgmgr.getPlayerIndex(client);
if (fromidx == -1) {
throw new InvocationException("m.not_playing");
}
// make sure they have the cards
if (!_hands[fromidx].containsAll(cards)) {
throw new InvocationException("m.not_holding_card");
}
// remove from sending player's hand
_hands[fromidx].removeAll(cards);
// add to receiving player's hand
_hands[toidx].addAll(cards);
// notify everyone of the transfer
_cgmgr.transferCardsBetweenPlayers(fromidx, toidx, cards);
}
/** The trick card game manager. */
protected TrickCardGameManager _tcgmgr;
// Documentation inherited.
public void playCard (ClientObject client, Card card)
throws InvocationException
{
// make sure we're playing a trick
if (_trickCardGame.getTrickState() !=
TrickCardGameObject.PLAYING_TRICK) {
throw new InvocationException("not_playing_trick");
}
// make sure it's their turn
Name username = ((BodyObject)client).username;
verifyPlayersTurn(username);
// make sure their hand contains the specified card
int pidx = _cardGame.getPlayerIndex(username);
if (!_hands[pidx].contains(card)) {
throw new InvocationException("m.not_holding_card");
}
// make sure the card is legal to play
if (!_trickCardGame.isCardPlayable(_hands[pidx], card)) {
throw new InvocationException("m.card_not_playable");
}
// play the card by removing it from the hand and adding it to the end
// of the cards played array
_hands[pidx].remove(card);
PlayerCard[] cards = (PlayerCard[])ArrayUtil.append(
_trickCardGame.getCardsPlayed(), new PlayerCard(pidx, card));
_trickCardGame.setCardsPlayed(cards);
// end the user's turn
endTurn();
// end the trick if everyone has played a card
if (_turnIdx == -1) {
if (_endTrickDelay == 0) {
endTrick();
} else {
_endTrickInterval.schedule(_endTrickDelay);
}
}
}
/** The game object. */
/**
* Checks whether the trick is complete--that is, whether each player has
* played a card.
*/
protected boolean isTrickComplete ()
{
return _trickCardGame.getCardsPlayed().length ==
_cardGame.getPlayerCount();
}
/**
* Throws an {@link InvocationException} if it is not the specified
* user's turn.
*/
protected void verifyPlayersTurn (Name username)
throws InvocationException
{
if (!_trickCardGame.getTurnHolder().equals(username)) {
throw new InvocationException("m.not_your_turn");
}
}
// Documentation inherited.
protected void setFirstTurnHolder ()
{
if (_trickCardGame.getTrickState() ==
TrickCardGameObject.PLAYING_TRICK) {
super.setFirstTurnHolder();
} else {
_turnIdx = -1;
}
}
// Documentation inherited.
protected void setNextTurnHolder ()
{
if (_trickCardGame.getTrickState() ==
TrickCardGameObject.PLAYING_TRICK &&
!isTrickComplete()) {
super.setNextTurnHolder();
} else {
_turnIdx = -1;
}
}
/**
* Returns the amount of time to allow before timing out the turn
* by calling {@link #turnTimedOut}. Default implementation returns
* a minute.
*/
protected long getTurnTimeoutDelay ()
{
return 60 * 1000L;
}
/**
* Called when the current turn times out. Default implementation
* plays a random playable card if in the trick-playing state.
*/
protected void turnTimedOut ()
{
if (_trickCardGame.getTrickState() ==
TrickCardGameObject.PLAYING_TRICK) {
int pidx = _cardGame.getPlayerIndex(
_trickCardGame.getTurnHolder());
Card card = pickRandomPlayableCard(_hands[pidx]);
try {
playCard(_cgmgr.getClientObject(pidx), card);
} catch (InvocationException ie) {
Log.warning("Couldn't play card [card=" + card + ", hand=" +
_hands[pidx] + "].");
Log.logStackTrace(ie);
}
}
}
/**
* Returns a random playable card from the specified hand.
*/
protected Card pickRandomPlayableCard (Hand hand)
{
ArrayList playableCards = new ArrayList();
for (int i = 0; i < hand.size(); i++) {
Card card = (Card)hand.get(i);
if (_trickCardGame.isCardPlayable(hand, card)) {
playableCards.add(card);
}
}
return (Card)RandomUtil.pickRandom(playableCards);
}
/**
* Notifies the object that a new hand is about to start.
*/
protected void handWillStart ()
{}
/**
* Notifies the object that a new hand has just started. Default
* implementation prepares the deck, deals the hands, and starts the
* first trick.
*/
protected void handDidStart ()
{
// prepare the deck
prepareDeck();
// deal cards to players
dealHands();
// start the first trick
startTrick();
}
/**
* Prepares the deck for a new hand of cards. Default implementation
* resets to a full deck without jokers and shuffles.
*/
protected void prepareDeck ()
{
_deck.reset(false);
_deck.shuffle();
}
/**
* Deals hands to the players. Default implementation deals the entire
* deck to the players in equal-sized hands.
*/
protected void dealHands ()
{
_hands = _cgmgr.dealHands(_deck, _deck.size() /
_cardGame.getPlayerCount());
}
/**
* Notifies the object that the hand is about to end.
*/
protected void handWillEnd ()
{}
/**
* Notifies the object that the hand has ended. Default implementation
* starts the next hand.
*/
protected void handDidEnd ()
{
startHand();
}
/**
* Notifies the object that a new trick is about to start. Default
* implementation resets the array of cards played.
*/
protected void trickWillStart ()
{
_trickCardGame.setCardsPlayed(new PlayerCard[0]);
}
/**
* Notifies the object that a new trick has started. Default
* implementation sets the first turn holder and starts the
* turn.
*/
protected void trickDidStart ()
{
setFirstTurnHolder();
startTurn();
}
/**
* Notifies the object that the trick is about to end.
*/
protected void trickWillEnd ()
{}
/**
* Notifies the object that the trick has ended. Default implementation
* records the last cards played and starts the next trick, unless a
* player has run out of cards, in which case it ends the hand.
*/
protected void trickDidEnd ()
{
// store the trick results for late-joiners
_trickCardGame.setLastCardsPlayed(_trickCardGame.getCardsPlayed());
// verify that each player has at least one card
if (anyHandsEmpty()) {
endHand();
return;
}
// everyone has cards; let's play another trick
startTrick();
}
/**
* Checks whether any hands are empty.
*/
protected boolean anyHandsEmpty ()
{
for (int i = 0; i < _hands.length; i++) {
if (_hands[i].isEmpty()) {
return true;
}
}
return false;
}
/** The card game manager. */
protected CardGameManager _cgmgr;
/** The game object as trick card game. */
protected TrickCardGameObject _trickCardGame;
/** The game object as card game. */
protected CardGameObject _cardGame;
/** The amount of time to wait before ending the trick. */
protected long _endTrickDelay;
/** The deck from which cards are dealt. */
protected Deck _deck;
/** The hands of each player. */
protected Hand[] _hands;
/** The all-purpose turn timeout interval. */
protected Interval _turnTimeoutInterval =
new Interval(PresentsServer.omgr) {
public void expired () {
turnTimedOut();
}
};
/** Calls {@link #endTrick} upon expiration. */
protected Interval _endTrickInterval = new Interval(PresentsServer.omgr) {
public void expired () {
endTrick();
}
};
}
@@ -0,0 +1,36 @@
//
// $Id: RoisterService.java 17829 2004-11-12 20:24:43Z mdb $
package com.threerings.parlor.card.trick.server;
import com.threerings.parlor.card.data.Card;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.InvocationProvider;
/**
* Service calls related to trick card games.
*/
public interface TrickCardGameProvider extends InvocationProvider
{
/**
* Sends a group of cards to the player at the specified index.
*
* @param client the client object
* @param toidx the index of the player to send the cards to
* @param cards the cards to send
*/
public void sendCardsToPlayer (ClientObject client, int toidx,
Card[] cards)
throws InvocationException;
/**
* Plays a card in the trick.
*
* @param client the client object
* @param card the card to play
*/
public void playCard (ClientObject client, Card card)
throws InvocationException;
}
@@ -0,0 +1,167 @@
//
// $Id: TrickCardGameObject.java 3382 2005-03-03 19:55:35Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.parlor.card.trick.util;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.card.data.PlayerCard;
import com.threerings.parlor.card.trick.data.TrickCardCodes;
/**
* Methods of general utility to trick-taking card games.
*/
public class TrickCardGameUtil
implements TrickCardCodes
{
/**
* For four-player games with fixed partnerships, this returns the index
* of the player's team.
*
* @param plidx the player index
*/
public static int getTeamIndex (int plidx)
{
return plidx / 2;
}
/**
* For four-player games with fixed partnerships, this returns the index
* of the other team.
*
* @param tidx the index of the team
*/
public static int getOtherTeamIndex (int tidx)
{
return 1 - tidx;
}
/**
* For four-player games with fixed partnerships, this returns the index
* of the player's partner.
*/
public static int getPartnerIndex (int plidx)
{
return plidx ^ 1;
}
/**
* For four-player games with fixed partnerships, this returns the index
* of one of the members of a team.
*
* @param tidx the index of the team
* @param midx the index of the player within the team
*/
public static int getTeamMemberIndex (int tidx, int midx)
{
return tidx * 2 + midx;
}
/**
* For four-player games with fixed partnerships, this returns the index
* of the player after the specified player going clockwise around the
* table.
*/
public static int getNextInClockwiseSequence (int plidx)
{
// 0
// 2 3
// 1
switch (plidx) {
case 0: return 3;
case 1: return 2;
case 2: return 0;
case 3: return 1;
default: return -1;
}
}
/**
* For four-player games with fixed partnerships, this returns the
* relative location of one player from the point of view of another.
*
* @param pidx1 the index of the player to whom the location is relative
* @param pidx2 the index of the player whose location is desired
* @return the relative location (TOP, BOTTOM, LEFT, or RIGHT)
*/
public static int getRelativeLocation (int pidx1, int pidx2)
{
return RELATIVE_LOCATIONS[pidx1][pidx2];
}
/**
* Checks whether the player can follow the suit lead with the hand given.
*/
public static boolean canFollowSuit (PlayerCard[] cardsPlayed, Hand hand)
{
return hand.getSuitMemberCount(cardsPlayed[0].card.getSuit()) > 0;
}
/**
* Determines the number of cards that belong to the specified suit within
* the array given.
*/
public static int countSuitMembers (PlayerCard[] cards, int suit)
{
int count = 0;
for (int i = 0; i < cards.length; i++) {
if (cards[i].card.getSuit() == suit) {
count++;
}
}
return count;
}
/**
* Checks whether the proposed card follows the suit lead.
*/
public static boolean followsSuit (PlayerCard[] cardsPlayed, Card card)
{
return cardsPlayed[0].card.getSuit() == card.getSuit();
}
/**
* Returns the highest card (according to the standard A,K,...,2 ordering)
* in the suit lead, with an optional trump suit.
*
* @param trumpSuit the trump suit, or -1 for none
*/
public static PlayerCard getHighestInLeadSuit (PlayerCard[] cardsPlayed,
int trumpSuit)
{
PlayerCard highest = cardsPlayed[0];
for (int i = 1; i < cardsPlayed.length; i++) {
PlayerCard other = cardsPlayed[i];
if ((other.card.getSuit() == highest.card.getSuit() &&
other.card.compareTo(highest.card) > 0) ||
(other.card.getSuit() == trumpSuit &&
highest.card.getSuit() != trumpSuit)) {
highest = other;
}
}
return highest;
}
/** The locations of the other players for each player index. */
protected static final int[][] RELATIVE_LOCATIONS = {
{BOTTOM, TOP, RIGHT, LEFT}, {TOP, BOTTOM, LEFT, RIGHT},
{LEFT, RIGHT, BOTTOM, TOP}, {RIGHT, LEFT, TOP, BOTTOM} };
}