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; package com.threerings.parlor.card.client;
import com.threerings.util.Name;
import com.threerings.crowd.data.PlaceObject; import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.card.data.Card; import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.CardCodes; import com.threerings.parlor.card.data.CardCodes;
import com.threerings.parlor.card.data.Hand; import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.game.client.GameController; import com.threerings.parlor.game.client.GameController;
import com.threerings.parlor.turn.client.TurnGameController;
/** /**
* A controller class for card games. Handles common functions like * A controller class for card games. Handles common functions like
* accepting dealt hands. * accepting dealt hands.
*/ */
public abstract class CardGameController extends GameController public abstract class CardGameController extends GameController
implements CardCodes, CardGameReceiver implements TurnGameController, CardCodes, CardGameReceiver
{ {
// Documentation inherited. // Documentation inherited.
public void willEnterPlace (PlaceObject plobj) public void willEnterPlace (PlaceObject plobj)
@@ -54,6 +56,10 @@ public abstract class CardGameController extends GameController
CardGameDecoder.RECEIVER_CODE); CardGameDecoder.RECEIVER_CODE);
} }
// Documentation inherited.
public void turnDidChange (Name turnHolder)
{}
/** /**
* Called when the server deals the client a new hand of cards. Default * Called when the server deals the client a new hand of cards. Default
* implementation does nothing. * implementation does nothing.
@@ -72,4 +78,27 @@ public abstract class CardGameController extends GameController
*/ */
public void receivedCardsFromPlayer (int plidx, Card[] cards) 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. */ * notifications. */
public static final int RECEIVED_CARDS_FROM_PLAYER = 2; 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 * Creates a decoder that may be registered to dispatch invocation
* service notifications to the specified receiver. * service notifications to the specified receiver.
@@ -55,6 +63,18 @@ public class CardGameDecoder extends InvocationDecoder
); );
return; 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: default:
super.dispatchNotification(methodId, args); super.dispatchNotification(methodId, args);
} }
@@ -47,4 +47,24 @@ public interface CardGameReceiver extends InvocationReceiver
* @param cards the cards received * @param cards the cards received
*/ */
public void receivedCardsFromPlayer (int plidx, Card[] cards); 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; 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.sprite.OrientableImageSprite;
import com.threerings.media.util.Path;
import com.threerings.parlor.card.data.Card; import com.threerings.parlor.card.data.Card;
@@ -31,12 +35,14 @@ import com.threerings.parlor.card.data.Card;
* A sprite representing a playing card. * A sprite representing a playing card.
*/ */
public class CardSprite extends OrientableImageSprite public class CardSprite extends OrientableImageSprite
implements Comparable
{ {
/** /**
* Creates a new upward-facing card sprite. * Creates a new upward-facing card sprite.
* *
* @param panel the panel responsible for the 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) public CardSprite (CardPanel panel, Card card)
{ {
@@ -127,13 +133,199 @@ public class CardSprite extends OrientableImageSprite
return _draggable; 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. * Updates the mirage according to the current state.
*/ */
protected void updateMirage () protected void updateMirage ()
{ {
setMirage(_facingUp ? _panel.getCardImage(_card) : setMirage((_card != null && _facingUp ) ?
_panel.getCardBackImage()); _panel.getCardImage(_card) : _panel.getCardBackImage());
} }
/** The panel responsible for the sprite. */ /** 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. */ /** Whether or not the user can drag the card around the board. */
protected boolean _draggable; 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 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 java.util.Collections;
import com.threerings.io.Streamable;
import com.threerings.util.StreamableArrayList; import com.threerings.util.StreamableArrayList;
/** /**
* Instances of this class represent decks of cards. * Instances of this class represent decks of cards.
*/ */
public class Deck implements CardCodes, public class Deck extends StreamableArrayList
Streamable implements CardCodes
{ {
/** The cards in the deck. */
public StreamableArrayList cards;
/** /**
* Default constructor creates an unshuffled deck of cards without * Default constructor creates an unshuffled deck of cards without
* jokers. * jokers.
*/ */
public Deck () public Deck ()
{ {
cards = new StreamableArrayList();
reset(false); reset(false);
} }
@@ -56,8 +48,6 @@ public class Deck implements CardCodes,
*/ */
public Deck (boolean includeJokers) public Deck (boolean includeJokers)
{ {
cards = new StreamableArrayList();
reset(includeJokers); reset(includeJokers);
} }
@@ -70,17 +60,17 @@ public class Deck implements CardCodes,
*/ */
public void reset (boolean includeJokers) public void reset (boolean includeJokers)
{ {
cards.clear(); clear();
for (int i=SPADES;i<=DIAMONDS;i++) { for (int i = SPADES; i <= DIAMONDS; i++) {
for (int j=2;j<=ACE;j++) { for (int j = 2; j <= ACE; j++) {
cards.add(new Card(j, i)); add(new Card(j, i));
} }
} }
if (includeJokers) { if (includeJokers) {
cards.add(new Card(RED_JOKER, 3)); add(new Card(RED_JOKER, 3));
cards.add(new Card(BLACK_JOKER, 3)); add(new Card(BLACK_JOKER, 3));
} }
} }
@@ -89,7 +79,7 @@ public class Deck implements CardCodes,
*/ */
public void shuffle () public void shuffle ()
{ {
Collections.shuffle(cards); Collections.shuffle(this);
} }
/** /**
@@ -101,15 +91,15 @@ public class Deck implements CardCodes,
*/ */
public Hand dealHand (int size) public Hand dealHand (int size)
{ {
if (cards.size() < size) { if (size() < size) {
return null; return null;
}
else { } else {
Hand hand = new Hand(); Hand hand = new Hand();
int cardsLeft = cards.size(); int cardsLeft = size();
for (int i=0;i<size;i++) { for (int i = 0; i < size; i++) {
hand.cards.add(cards.remove(--cardsLeft)); hand.add(remove(--cardsLeft));
} }
return hand; return hand;
@@ -123,17 +113,7 @@ public class Deck implements CardCodes,
*/ */
public void returnHand (Hand hand) public void returnHand (Hand hand)
{ {
cards.addAll(hand.cards); addAll(hand);
hand.cards.clear(); hand.clear();
}
/**
* Returns a string representation of this deck.
*
* @return a description of this deck
*/
public String toString ()
{
return "[cards=" + cards.toString() + "]";
} }
} }
@@ -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 // 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
@@ -21,28 +21,44 @@
package com.threerings.parlor.card.data; package com.threerings.parlor.card.data;
import java.util.Iterator;
import com.threerings.io.Streamable;
import com.threerings.util.StreamableArrayList; import com.threerings.util.StreamableArrayList;
/** /**
* Instances of this class represent hands of cards. * Instances of this class represent hands of cards.
*/ */
public class Hand implements CardCodes, public class Hand extends StreamableArrayList
Streamable
{ {
/** 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) public int getSuitMemberCount (int suit)
{ {
int members = 0; int len = size(), members = 0;
for (int i = 0; i < len; i++) {
Iterator it = cards.iterator(); if (((Card)get(i)).getSuit() == suit) {
members++;
while (it.hasNext()) {
if (((Card)it.next()).getSuit() == suit) {
members++;
} }
} }
return 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 // 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
@@ -19,29 +19,36 @@
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // 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 * Pairs a player index with the card that the player played in the trick.
* Spades and Hearts.
*/ */
public interface TrickCardGameController extends TurnGameController public class PlayerCard implements Streamable
{ {
/** /** The index of the player. */
* Notifies the controller that the gameplay entered or left a hand. public int pidx;
*
* @param playingHand true if the gameplay entered a hand, false if /** The card that the player played. */
* it left one public Card card;
*/
public void playingHandDidChange (boolean playingHand);
/** /**
* Notifies the controller that the gameplay entered or left a trick. * No-argument constructor for deserialization.
*
* @param playingTrick true if the gameplay entered a trick, false if
* it left one
*/ */
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; package com.threerings.parlor.card.server;
import com.threerings.crowd.data.BodyObject; 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.Log;
import com.threerings.parlor.card.data.Card; import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.CardCodes; 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.CardGameObject;
import com.threerings.parlor.card.data.Deck; import com.threerings.parlor.card.data.Deck;
import com.threerings.parlor.card.data.Hand; import com.threerings.parlor.card.data.Hand;
import com.threerings.parlor.game.server.GameManager; 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.client.InvocationService.ConfirmListener;
import com.threerings.presents.data.ClientObject; import com.threerings.presents.data.ClientObject;
@@ -45,27 +46,26 @@ import com.threerings.presents.server.PresentsServer;
* hands of cards to all players. * hands of cards to all players.
*/ */
public class CardGameManager extends GameManager public class CardGameManager extends GameManager
implements CardCodes, CardGameProvider implements TurnGameManager, CardCodes
{ {
// Documentation inherited. // Documentation inherited.
protected void didStartup () protected void didStartup ()
{ {
super.didStartup(); super.didStartup();
_cardgameobj = (CardGameObject)_gameobj; _cardgameobj = (CardGameObject)_gameobj;
_cardgameobj.setCardGameService(
(CardGameMarshaller)PresentsServer.invmgr.registerDispatcher(
new CardGameDispatcher(this), false));
} }
// Documentation inherited. // Documentation inherited.
protected void didShutdown () public void turnWillStart ()
{ {}
super.didShutdown();
// Documentation inherited.
PresentsServer.invmgr.clearDispatcher(_cardgameobj.cardGameService); public void turnDidStart ()
} {}
// Documentation inherited.
public void turnDidEnd ()
{}
/** /**
* Deals a hand of cards to the player at the specified index from * 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) public Hand dealHand (Deck deck, int size, int playerIndex)
{ {
if (deck.cards.size() < size) { if (deck.size() < size) {
return null; return null;
} }
else { else {
@@ -105,7 +105,7 @@ public class CardGameManager extends GameManager
*/ */
public Hand[] dealHands (Deck deck, int size) public Hand[] dealHands (Deck deck, int size)
{ {
if (deck.cards.size() < size * _playerCount) { if (deck.size() < size * _playerCount) {
return null; return null;
} }
else { else {
@@ -135,47 +135,11 @@ public class CardGameManager extends GameManager
} }
/** /**
* Checks whether or not it is acceptable to transfer the given set of * Returns the client object corresponding to the specified player index.
* 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
*/ */
protected boolean acceptTransferBetweenPlayers(int fromPlayerIdx, public ClientObject getClientObject (int pidx)
int toPlayerIdx, Card[] cards)
{ {
return true; return (ClientObject)PresentsServer.omgr.getObject(_playerOids[pidx]);
}
/**
* 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");
}
} }
/** /**
@@ -185,14 +149,34 @@ public class CardGameManager extends GameManager
* @param toPlayerIdx the index of the player receiving the cards * @param toPlayerIdx the index of the player receiving the cards
* @param cards the cards to be exchanged * @param cards the cards to be exchanged
*/ */
public void transferCardsBetweenPlayers (int fromPlayerIdx, public void transferCardsBetweenPlayers (final int fromPlayerIdx,
int toPlayerIdx, Card[] cards) final int toPlayerIdx, final Card[] cards)
{ {
CardGameSender.sendCardsFromPlayer( // Notify the sender that the cards have been taken
(ClientObject)PresentsServer.omgr.getObject( CardGameSender.sentCardsToPlayer(getClientObject(fromPlayerIdx),
_playerOids[toPlayerIdx]), fromPlayerIdx, cards); 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. */ /** The card game object. */
protected CardGameObject _cardgameobj; 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 }); 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; package com.threerings.parlor.card.trick.client;
import com.threerings.presents.dobj.AttributeChangedEvent;
import com.threerings.parlor.turn.client.TurnGameControllerDelegate; 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 * A card game controller delegate for trick-based card games, such as
@@ -39,30 +37,13 @@ public class TrickCardGameControllerDelegate
* *
* @param controller the game controller * @param controller the game controller
*/ */
public TrickCardGameControllerDelegate (TrickCardGameController public TrickCardGameControllerDelegate (CardGameController
controller) controller)
{ {
super(controller); super(controller);
_cgctrl = controller;
_tcgctrl = controller;
} }
// Documentation inherited /** The card game controller. */
public void attributeChanged (AttributeChangedEvent ace) protected CardGameController _cgctrl;
{
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;
} }
@@ -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 // 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
@@ -19,43 +19,24 @@
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // 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 * Constants relating to trick-based card games.
* Spades and Hearts.
*/ */
public interface TrickCardGameManager extends TurnGameManager public interface TrickCardCodes extends CardCodes
{ {
/** /** For four-player games, the top (opposite) player. */
* Notifies the manager that a hand is about to start. public static final int TOP = 0;
*/
public void handWillStart ();
/** /** For four-player games, the bottom (own) player. */
* Notifies the manager that a hand just started. public static final int BOTTOM = 1;
*/
public void handDidStart ();
/** /** For four-player games, the player on the left. */
* Notifies the manager that a hand has ended. public static final int LEFT = 2;
*/
public void handDidEnd ();
/** /** For four-player games, the player on the right. */
* Notifies the manager that a trick is about to start. public static final int RIGHT = 3;
*/
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 ();
} }
@@ -19,35 +19,43 @@
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // 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.data.Card;
import com.threerings.parlor.card.trick.client.TrickCardGameService;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.presents.data.InvocationMarshaller; import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent; 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 * that marshalls the arguments and delivers the request to the provider
* on the server. Also provides an implementation of the response listener * on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back * interfaces that marshall the response arguments and deliver them back
* to the requesting client. * to the requesting client.
*/ */
public class CardGameMarshaller extends InvocationMarshaller public class TrickCardGameMarshaller extends InvocationMarshaller
implements CardGameService implements TrickCardGameService
{ {
/** The method id used to dispatch {@link #sendCardsToPlayer} requests. */ /** The method id used to dispatch {@link #playCard} requests. */
public static final int SEND_CARDS_TO_PLAYER = 1; public static final int PLAY_CARD = 1;
// documentation inherited from interface // 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[] { 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; 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; import com.threerings.parlor.turn.data.TurnGameObject;
/** /**
@@ -28,47 +31,113 @@ import com.threerings.parlor.turn.data.TurnGameObject;
*/ */
public interface TrickCardGameObject extends TurnGameObject public interface TrickCardGameObject extends TurnGameObject
{ {
/** /** The state that indicates the game is currently between hands. */
* Returns the name of the field that signals whether or not the users public static final int BETWEEN_HANDS = 0;
* are currently playing a hand.
* /** The state that indicates the game is currently playing a hand. */
* @return the name of the playingHand field public static final int PLAYING_HAND = 1;
*/
public String getPlayingHandFieldName (); /** 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 * Returns the name of the field that contains the trick state: between
* are currently playing a trick. * 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 // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // 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.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.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.presents.data.ClientObject; import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationMarshaller; import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.server.InvocationDispatcher; import com.threerings.presents.server.InvocationDispatcher;
import com.threerings.presents.server.InvocationException; 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 * Creates a dispatcher that may be registered to dispatch invocation
* service requests for the specified provider. * service requests for the specified provider.
*/ */
public CardGameDispatcher (CardGameProvider provider) public TrickCardGameDispatcher (TrickCardGameProvider provider)
{ {
this.provider = provider; this.provider = provider;
} }
@@ -48,7 +47,7 @@ public class CardGameDispatcher extends InvocationDispatcher
// documentation inherited // documentation inherited
public InvocationMarshaller createMarshaller () public InvocationMarshaller createMarshaller ()
{ {
return new CardGameMarshaller(); return new TrickCardGameMarshaller();
} }
// documentation inherited // documentation inherited
@@ -57,10 +56,17 @@ public class CardGameDispatcher extends InvocationDispatcher
throws InvocationException throws InvocationException
{ {
switch (methodId) { switch (methodId) {
case CardGameMarshaller.SEND_CARDS_TO_PLAYER: case TrickCardGameMarshaller.PLAY_CARD:
((CardGameProvider)provider).sendCardsToPlayer( ((TrickCardGameProvider)provider).playCard(
source, 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; return;
@@ -21,10 +21,31 @@
package com.threerings.parlor.card.trick.server; 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.crowd.data.PlaceObject;
import com.threerings.parlor.game.server.GameManager; import com.threerings.parlor.game.server.GameManager;
import com.threerings.parlor.turn.server.TurnGameManagerDelegate; 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; import com.threerings.parlor.card.trick.data.TrickCardGameObject;
/** /**
@@ -32,41 +53,19 @@ import com.threerings.parlor.card.trick.data.TrickCardGameObject;
* Spades and Hearts. * Spades and Hearts.
*/ */
public class TrickCardGameManagerDelegate extends TurnGameManagerDelegate public class TrickCardGameManagerDelegate extends TurnGameManagerDelegate
implements TrickCardGameProvider
{ {
/** /**
* Constructor. * Constructor.
* *
* @param manager the game manager * @param manager the game manager
*/ */
public TrickCardGameManagerDelegate (TrickCardGameManager manager) public TrickCardGameManagerDelegate (CardGameManager manager)
{ {
super(manager); super(manager);
_tcgmgr = manager; _cgmgr = manager;
} _deck = new Deck();
// 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;
}
} }
// Documentation inherited. // Documentation inherited.
@@ -75,56 +74,431 @@ public class TrickCardGameManagerDelegate extends TurnGameManagerDelegate
super.didStartup(plobj); super.didStartup(plobj);
_trickCardGame = (TrickCardGameObject)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 () public void startHand ()
{ {
_tcgmgr.handWillStart(); handWillStart();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_HAND);
_trickCardGame.setPlayingHand(true); handDidStart();
_tcgmgr.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 () public void endHand ()
{ {
_trickCardGame.setPlayingHand(false); handWillEnd();
_trickCardGame.setTrickState(TrickCardGameObject.BETWEEN_HANDS);
_tcgmgr.handDidEnd(); handDidEnd();
} }
/** /**
* Starts a trick. * Starts a trick. Calls {@link #trickWillStart}, sets the trick
* state to PLAYING_TRICK, and calls {@link #trickDidStart}.
*/ */
public void startTrick () public void startTrick ()
{ {
_tcgmgr.trickWillStart(); trickWillStart();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_TRICK);
_trickCardGame.setPlayingTrick(true); trickDidStart();
_tcgmgr.trickDidStart();
} }
/** /**
* Ends a trick. * Ends the trick. Calls {@link #trickWillEnd}, sets the trick
* state to PLAYING_HAND, and calls {@link #trickDidEnd}.
*/ */
public void endTrick () public void endTrick ()
{ {
_trickCardGame.setPlayingTrick(false); trickWillEnd();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_HAND);
_tcgmgr.trickDidEnd(); 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. */ // Documentation inherited.
protected TrickCardGameManager _tcgmgr; 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; 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} };
}