Behold Vilya, Ring of Air and repository for our game and virtual worldly

extensions to the distributed environment provided by Narya.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@1 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Michael Bayne
2006-06-23 17:58:11 +00:00
commit a4df87e52f
317 changed files with 45818 additions and 0 deletions
@@ -0,0 +1,56 @@
//
// $Id: Log.java 4191 2006-06-13 22:42:20Z ray $
//
// 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;
/**
* A placeholder class that contains a reference to the log object used by
* the Card services.
*/
public class Log
{
public static com.samskivert.util.Log log =
new com.samskivert.util.Log("card");
/** Convenience function. */
public static void debug (String message)
{
log.debug(message);
}
/** Convenience function. */
public static void info (String message)
{
log.info(message);
}
/** Convenience function. */
public static void warning (String message)
{
log.warning(message);
}
/** Convenience function. */
public static void logStackTrace (Throwable t)
{
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
}
}
@@ -0,0 +1,122 @@
//
// $Id: CardGameController.java 4053 2006-04-25 00:49:58Z mthomas $
//
// 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.client;
import com.threerings.util.Name;
import com.threerings.crowd.data.PlaceObject;
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.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 TurnGameController, CardCodes, CardGameReceiver
{
// Documentation inherited.
public void willEnterPlace (PlaceObject plobj)
{
super.willEnterPlace(plobj);
if (_ctx.getClient().getClientObject().receivers.containsKey(
CardGameDecoder.RECEIVER_CODE)) {
Log.warning("Yuh oh, we already have a card game receiver " +
"registered and are trying for another...!");
Thread.dumpStack();
}
_ctx.getClient().getInvocationDirector().registerReceiver(
new CardGameDecoder(this));
}
// Documentation inherited.
public void didLeavePlace (PlaceObject plobj)
{
super.didLeavePlace(plobj);
_ctx.getClient().getInvocationDirector().unregisterReceiver(
CardGameDecoder.RECEIVER_CODE);
}
// Documentation inherited.
public void turnDidChange (Name turnHolder)
{}
/**
* Called by our sender to notify us of a received hand.
*/
public final void receivedHand (int oid, Hand hand)
{
if (oid == _gobj.getOid()) {
receivedHand(hand);
}
}
/**
* Called when the server deals the client a new hand of cards. Default
* implementation does nothing.
*
* @param hand the hand dealt to the user
*/
public void receivedHand (Hand hand)
{}
/**
* Dispatched to the client when it has received a set of cards
* from another player. Default implementation does nothing.
*
* @param plidx the index of the player providing the cards
* @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. 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)
{}
}
@@ -0,0 +1,101 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 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.client;
import com.threerings.parlor.card.client.CardGameReceiver;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.Hand;
import com.threerings.presents.client.InvocationDecoder;
/**
* Dispatches calls to a {@link CardGameReceiver} instance.
*/
public class CardGameDecoder extends InvocationDecoder
{
/** The generated hash code used to identify this receiver class. */
public static final String RECEIVER_CODE = "0718199d459e31d8d673744c71b0e788";
/** The method id used to dispatch {@link CardGameReceiver#cardsTransferredBetweenPlayers}
* notifications. */
public static final int CARDS_TRANSFERRED_BETWEEN_PLAYERS = 1;
/** The method id used to dispatch {@link CardGameReceiver#receivedCardsFromPlayer}
* notifications. */
public static final int RECEIVED_CARDS_FROM_PLAYER = 2;
/** The method id used to dispatch {@link CardGameReceiver#receivedHand}
* notifications. */
public static final int RECEIVED_HAND = 3;
/** The method id used to dispatch {@link CardGameReceiver#sentCardsToPlayer}
* notifications. */
public static final int SENT_CARDS_TO_PLAYER = 4;
/**
* Creates a decoder that may be registered to dispatch invocation
* service notifications to the specified receiver.
*/
public CardGameDecoder (CardGameReceiver receiver)
{
this.receiver = receiver;
}
// documentation inherited
public String getReceiverCode ()
{
return RECEIVER_CODE;
}
// documentation inherited
public void dispatchNotification (int methodId, Object[] args)
{
switch (methodId) {
case CARDS_TRANSFERRED_BETWEEN_PLAYERS:
((CardGameReceiver)receiver).cardsTransferredBetweenPlayers(
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), ((Integer)args[2]).intValue()
);
return;
case RECEIVED_CARDS_FROM_PLAYER:
((CardGameReceiver)receiver).receivedCardsFromPlayer(
((Integer)args[0]).intValue(), (Card[])args[1]
);
return;
case RECEIVED_HAND:
((CardGameReceiver)receiver).receivedHand(
((Integer)args[0]).intValue(), (Hand)args[1]
);
return;
case SENT_CARDS_TO_PLAYER:
((CardGameReceiver)receiver).sentCardsToPlayer(
((Integer)args[0]).intValue(), (Card[])args[1]
);
return;
default:
super.dispatchNotification(methodId, args);
return;
}
}
}
@@ -0,0 +1,71 @@
//
// $Id: ParlorReceiver.java 3099 2004-08-27 02:21:06Z 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.client;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.Hand;
import com.threerings.presents.client.InvocationReceiver;
/**
* Defines, for the card game services, a set of notifications delivered
* asynchronously by the server to the client.
*/
public interface CardGameReceiver extends InvocationReceiver
{
/**
* Dispatched to the client when it has received a hand of cards.
*
* @param oid the oid of the game for which this hand applies
* @param hand the received hand
*/
public void receivedHand (int oid, Hand hand);
/**
* Dispatched to the client when it has received a set of cards
* from another player.
*
* @param plidx the index of the player providing the cards
* @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);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,252 @@
//
// $Id: CardSprite.java 3819 2006-01-24 19:46:34Z mthomas $
//
// 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.client;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import com.threerings.media.image.Mirage;
import com.threerings.media.sprite.FadableImageSprite;
import com.threerings.media.util.Path;
import com.threerings.parlor.card.data.Card;
/**
* A sprite representing a playing card.
*/
public class CardSprite extends FadableImageSprite
implements Comparable
{
/**
* Creates a new upward-facing card sprite.
*
* @param panel the panel responsible for the sprite
* @param card the card to depict (can be null, in which case the
* card back will be shown)
*/
public CardSprite (CardPanel panel, Card card)
{
_panel = panel;
_card = card;
_facingUp = true;
updateMirage();
}
/**
* Creates a new card sprite.
*
* @param panel the panel responsible for the sprite
* @param card the card to depict
* @param facingUp whether or not the card should be facing up
*/
public CardSprite (CardPanel panel, Card card, boolean facingUp)
{
_panel = panel;
_card = card;
_facingUp = facingUp;
updateMirage();
}
/**
* Sets the card to depict.
*
* @param card the new card
*/
public void setCard (Card card)
{
_card = card;
updateMirage();
}
/**
* Returns the card being depicted.
*
* @return the current card
*/
public Card getCard ()
{
return _card;
}
/**
* Turns this card up or down.
*
* @param facingUp whether or not the card should be facing up
*/
public void setFacingUp (boolean facingUp)
{
_facingUp = facingUp;
updateMirage();
}
/**
* Checks whether this card is facing up or down.
*
* @return true if the card is facing up, false if facing down
*/
public boolean isFacingUp ()
{
return _facingUp;
}
/**
* Sets whether or not the user can drag this card around the board.
*
* @param draggable whether or not the user can drag the card
*/
public void setDraggable (boolean draggable)
{
_draggable = draggable;
}
/**
* Checks whether or not the user can drag this card.
*
* @return true if the user can drag the card, false if not
*/
public boolean isDraggable ()
{
return _draggable;
}
/**
* Flip the card from its current displayed card to the specified card.
*/
public void flip (Card newCard, long duration)
{
_flipStamp = 0;
_flipDuration = duration;
_flipCard = newCard;
_scaleFactor = 1.0;
}
// Documentation inherited.
public void tick (long tickStamp)
{
super.tick(tickStamp);
// Take care of any flipping we might be doing.
if (_flipDuration != -1) {
if (_flipStamp == 0) {
_flipStamp = tickStamp;
}
long diff = tickStamp - _flipStamp;
// Set the new scale while we're flipping
if (diff < _flipDuration/2) {
_scaleFactor = 1.0 - ((float)diff*2)/_flipDuration;
} else {
// Switch the image to the card we're flipping to.
if (_flipCard != null) {
setCard(_flipCard);
_flipCard = null;
}
_scaleFactor = ((float)diff*2)/_flipDuration - 1.0;
}
// If we're done, stop flipping.
if (_scaleFactor > 1.0) {
_scaleFactor = 1.0;
_flipDuration = -1;
}
// Make sure we flag our location as needing redrawing
if (_mgr != null) {
_mgr.getRegionManager().invalidateRegion(_bounds);
}
}
}
// Documentation inherited.
public void paint (Graphics2D gfx)
{
if (_scaleFactor <= 0) {
return;
}
// If we are flipping the card, scale it horizontally.
AffineTransform otrans = gfx.getTransform();
if (_scaleFactor < 1.0) {
int xtrans = getX() + getWidth()/2;
gfx.translate(xtrans, 0);
gfx.scale(_scaleFactor, 1.0);
gfx.translate(-xtrans, 0);
}
super.paint(gfx);
gfx.setTransform(otrans);
}
/**
* 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((_card != null && _facingUp ) ?
_panel.getCardImage(_card) : _panel.getCardBackImage());
}
/** The panel responsible for the sprite. */
protected CardPanel _panel;
/** The depicted card. */
protected Card _card;
/** Whether or not the card is facing up. */
protected boolean _facingUp;
/** Whether or not the user can drag the card around the board. */
protected boolean _draggable;
/** The horizontal scale factor used while flipping the card. */
protected double _scaleFactor = 1.0;
/** If flipping, how long the current flip should take (otherwise -1). */
protected long _flipDuration;
/** The timestamp for when we started flipping the card. */
protected long _flipStamp;
/** The card which will be revealed when we're done flipping. */
protected Card _flipCard;
}
@@ -0,0 +1,65 @@
//
// $Id: CardSpriteObserver.java 4191 2006-06-13 22:42:20Z ray $
//
// 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.client;
import java.awt.event.MouseEvent;
/**
* Observer interface for (draggable) card sprites.
*/
public interface CardSpriteObserver
{
/**
* Notifies the observer that the user clicked a card sprite.
*
* @param sprite the dragged sprite
* @param me the mouse event associated with the drag
*/
public void cardSpriteClicked (CardSprite sprite, MouseEvent me);
/**
* Notifies the observer that the user moved the mouse pointer onto
* a card sprite.
*
* @param sprite the entered sprite
* @param me the mouse event associated with the entrance
*/
public void cardSpriteEntered (CardSprite sprite, MouseEvent me);
/**
* Notifies the observer that the user moved the mouse pointer off of
* a card sprite.
*
* @param sprite the exited the sprite
* @param me the mouse event associated with the exit
*/
public void cardSpriteExited (CardSprite sprite, MouseEvent me);
/**
* Notifies the observer that the user dragged a card sprite to a new
* location.
*
* @param sprite the dragged sprite
* @param me the mouse event associated with the drag
*/
public void cardSpriteDragged (CardSprite sprite, MouseEvent me);
}
@@ -0,0 +1,59 @@
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 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.client;
import com.threerings.parlor.card.data.Card;
public class MicroCardSprite extends CardSprite
{
/**
* Creates a new upward-facing micro-card sprite.
*
* @param panel the panel responsible for the sprite
* @param card the card to depict (can be null, in which case the
* card back will be shown)
*/
public MicroCardSprite (CardPanel panel, Card card)
{
super(panel, card);
}
/**
* Creates a new micro-card sprite.
*
* @param panel the panel responsible for the sprite
* @param card the card to depict
* @param facingUp whether or not the card should be facing up
*/
public MicroCardSprite (CardPanel panel, Card card, boolean facingUp)
{
super(panel, card, facingUp);
}
/**
* Updates the mirage according to the current state.
*/
protected void updateMirage ()
{
setMirage((_card != null && _facingUp ) ?
_panel.getMicroCardImage(_card) : _panel.getMicroCardBackImage());
}
}
@@ -0,0 +1,244 @@
//
// $Id: Card.java 4191 2006-06-13 22:42:20Z ray $
//
// 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.data;
import java.io.IOException;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.presents.dobj.DSet;
/**
* Instances of this class represent individual playing cards.
*/
public class Card implements DSet.Entry, Comparable, CardCodes
{
/**
* No-arg constructor for deserialization.
*/
public Card ()
{}
/**
* Creates a new card.
*
* @param number the number of the card
* @param suit the suit of the card
*/
public Card (int number, int suit)
{
_value = (byte)((suit << 5) | number);
}
/**
* Returns the value of the card, either from 2 to 11 or
* KING, QUEEN, JACK, ACE, RED_JOKER, or BLACK_JOKER.
*
* @return the value of the card
*/
public int getNumber ()
{
return (_value & 0x1F);
}
/**
* Returns the suit of the card: SPADES, HEARTS, DIAMONDS, or
* CLUBS. If the card is the joker, the suit is undefined.
*
* @return the suit of the card
*/
public int getSuit ()
{
return (_value >> 5);
}
/**
* Checks whether the card is a number card (2 to 10).
*
* @return true if the card is a number card, false otherwise
*/
public boolean isNumber ()
{
int number = getNumber();
return number >= 2 && number <= 10;
}
/**
* Checks whether the card is a face card (KING, QUEEN, or JACK).
*
* @return true if the card is a face card, false otherwise
*/
public boolean isFace ()
{
int number = getNumber();
return number == KING || number == QUEEN || number == JACK;
}
/**
* Checks whether the card is an ace.
*
* @return true if the card is an ace, false otherwise
*/
public boolean isAce ()
{
return getNumber() == ACE;
}
/**
* Checks whether the card is a joker.
*
* @return true if the card is a joker, false otherwise
*/
public boolean isJoker ()
{
int number = getNumber();
return number == RED_JOKER || number == BLACK_JOKER;
}
/**
* Checks whether or not this card is valid. The no-arg public
* constructor for deserialization creates an invalid card.
*
* @return true if this card is valid, false if not
*/
public boolean isValid ()
{
int number = getNumber(), suit = getSuit();
return number == RED_JOKER || number == BLACK_JOKER ||
(number >= 2 && number <= ACE &&
suit >= SPADES && suit <= DIAMONDS);
}
// Documentation inherited.
public Comparable getKey ()
{
if (_key == null) {
_key = Byte.valueOf(_value);
}
return _key;
}
/**
* Returns a hash code for this card.
*
* @return this card's hash code
*/
public int hashCode ()
{
return _value;
}
/**
* Checks this card for equality with another.
*
* @param other the other card to compare
* @return true if the cards are equal, false otherwise
*/
public boolean equals (Object other)
{
if (other instanceof Card) {
return _value == ((Card)other)._value;
}
else {
return false;
}
}
/**
* Compares this card to another. The card order is the same as the
* initial deck ordering: two through ten, jack, queen, king, ace for
* spades, hearts, clubs, and diamonds, then the red joker and the
* black joker.
*
* @param other the other card to compare this to
* @return -1, 0, or +1, depending on whether this card is less than,
* equal to, or greater than the other card
*/
public int compareTo (Object other)
{
int otherValue = ((Card)other)._value;
if (_value > otherValue) {
return +1;
} else if(_value < otherValue) {
return -1;
} else {
return 0;
}
}
/**
* Returns a string representation of this card.
*
* @return a description of this card
*/
public String toString ()
{
int number = getNumber();
if (number == RED_JOKER) {
return "RJ";
}
else if (number == BLACK_JOKER) {
return "BJ";
}
else {
StringBuilder sb = new StringBuilder();
if (number >= 2 && number <= 9) {
sb.append(Integer.toString(number));
}
else {
switch (number) {
case 10: sb.append('T'); break;
case JACK: sb.append('J'); break;
case QUEEN: sb.append('Q'); break;
case KING: sb.append('K'); break;
case ACE: sb.append('A'); break;
default: sb.append('?'); break;
}
}
switch (getSuit()) {
case SPADES: sb.append('s'); break;
case HEARTS: sb.append('h'); break;
case CLUBS: sb.append('c'); break;
case DIAMONDS: sb.append('d'); break;
default: sb.append('?'); break;
}
return sb.toString();
}
}
/** The number of the card. */
protected byte _value;
/** The comparison key. */
protected transient Byte _key;
}
@@ -0,0 +1,60 @@
//
// $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
// 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.data;
import com.threerings.presents.data.InvocationCodes;
/**
* Constants relating to the card services.
*/
public interface CardCodes extends InvocationCodes
{
/** The suit of spades. */
public static final int SPADES = 0;
/** The suit of hearts. */
public static final int HEARTS = 1;
/** The suit of clubs. */
public static final int CLUBS = 2;
/** The suit of diamonds. */
public static final int DIAMONDS = 3;
/** The number of the jack. */
public static final int JACK = 11;
/** The number of the queen. */
public static final int QUEEN = 12;
/** The number of the king. */
public static final int KING = 13;
/** The number of the ace. */
public static final int ACE = 14;
/** The number of the red joker. */
public static final int RED_JOKER = 15;
/** The number of the black joker. */
public static final int BLACK_JOKER = 16;
}
@@ -0,0 +1,31 @@
//
// $Id: TurnGameObject.java 3099 2004-08-27 02:21:06Z 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.data;
import com.threerings.parlor.game.data.GameObject;
/**
* Game object class for card games.
*/
public class CardGameObject extends GameObject
{
}
@@ -0,0 +1,121 @@
//
// $Id: Deck.java 3713 2005-09-27 21:58:10Z andrzej $
//
// 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.data;
import java.util.Collections;
import java.util.List;
import com.threerings.util.StreamableArrayList;
/**
* Instances of this class represent decks of cards.
*/
public class Deck extends StreamableArrayList
implements CardCodes
{
/**
* Default constructor creates an unshuffled deck of cards without
* jokers.
*/
public Deck ()
{
reset(false);
}
/**
* Constructor.
*
* @param includeJokers whether or not to include the two jokers
* in the deck
*/
public Deck (boolean includeJokers)
{
reset(includeJokers);
}
/**
* Resets the deck to its initial state: an unshuffled deck of
* 52 or 54 cards, depending on whether the jokers are included.
*
* @param includeJokers whether or not to include the two jokers
* in the deck
*/
public void reset (boolean includeJokers)
{
clear();
for (int i = SPADES; i <= DIAMONDS; i++) {
for (int j = 2; j <= ACE; j++) {
add(new Card(j, i));
}
}
if (includeJokers) {
add(new Card(RED_JOKER, 3));
add(new Card(BLACK_JOKER, 3));
}
}
/**
* Shuffles the deck.
*/
public void shuffle ()
{
Collections.shuffle(this);
}
/**
* Deals a hand of cards from the deck.
*
* @param size the size of the hand to deal
* @return the newly created and populated hand, or null
* if there are not enough cards in the deck to deal the hand
*/
public Hand dealHand (int size)
{
int dsize = size();
if (dsize < size) {
return null;
} else {
Hand hand = new Hand();
// use a sublist view to manipulate the top of the deck
List sublist = subList(dsize - size, dsize);
hand.addAll(sublist);
sublist.clear();
return hand;
}
}
/**
* Returns a hand of cards to the deck.
*
* @param hand the hand of cards to return
*/
public void returnHand (Hand hand)
{
addAll(hand);
hand.clear();
}
}
@@ -0,0 +1,90 @@
//
// $Id: Hand.java 3813 2006-01-19 21:50:53Z ray $
//
// 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.data;
import com.threerings.util.StreamableArrayList;
/**
* Instances of this class represent hands of cards.
*/
public class Hand extends StreamableArrayList
{
/**
* 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]);
}
}
/**
* Removes all of the specified cards from this hand.
*/
public void removeAll (Card[] cards)
{
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;
}
/**
* Counts the members of a particular suit within this hand.
*
* @param suit the suit of interest
* @return the number of cards in the specified suit
*/
public int getSuitMemberCount (int suit)
{
int len = size(), members = 0;
for (int i = 0; i < len; i++) {
if (((Card)get(i)).getSuit() == suit) {
members++;
}
}
return members;
}
/**
* Get an array of the cards in this hand.
*/
public Card[] getCards ()
{
Card[] cards = new Card[size()];
toArray(cards);
return cards;
}
}
@@ -0,0 +1,54 @@
//
// $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.data;
import com.threerings.io.Streamable;
/**
* Pairs a player index with the card that the player played in the trick.
*/
public class PlayerCard implements Streamable
{
/** The index of the player. */
public int pidx;
/** The card that the player played. */
public Card card;
/**
* No-argument constructor for deserialization.
*/
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;
}
}
@@ -0,0 +1,268 @@
//
// $Id: CardGameManager.java 3829 2006-02-03 19:11:20Z ray $
//
// 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.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.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;
import com.threerings.presents.dobj.MessageEvent;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.PresentsServer;
/**
* A manager class for card games. Handles common functions like dealing
* hands of cards to all players.
*/
public class CardGameManager extends GameManager
implements TurnGameManager, CardCodes
{
// Documentation inherited.
protected void didStartup ()
{
super.didStartup();
_cardgameobj = (CardGameObject)_gameobj;
}
// Documentation inherited.
public void turnWillStart ()
{}
// Documentation inherited.
public void turnDidStart ()
{}
// Documentation inherited.
public void turnDidEnd ()
{}
/**
* This should be called to start a rematched game. It just starts the
* current game anew, but provides a mechanism for derived classes to
* do special things when there is a rematch.
*/
public void rematchGame ()
{
if (gameWillRematch()) {
startGame();
}
}
/**
* Derived classes can override this method and take any action needed
* prior to a game rematch. If the rematch needs to be vetoed for any
* reason, they can return false from this method and the rematch will
* be aborted.
*/
protected boolean gameWillRematch ()
{
return true;
}
/**
* Deals a hand of cards to the player at the specified index from
* the given Deck.
*
* @param deck the deck from which to deal
* @param size the size of the hand to deal
* @param playerIndex the index of the target player
* @return the hand dealt to the player, or null if the deal
* was canceled because the deck did not contain enough cards
*/
public Hand dealHand (Deck deck, int size, int playerIndex)
{
if (deck.size() < size) {
return null;
} else {
Hand hand = deck.dealHand(size);
if (!isAI(playerIndex)) {
ClientObject clobj = (ClientObject)
PresentsServer.omgr.getObject(_playerOids[playerIndex]);
if (clobj != null) {
CardGameSender.sendHand(clobj, _cardgameobj.getOid(), hand);
}
}
return hand;
}
}
/**
* Deals a hand of cards to each player from the specified
* Deck.
*
* @param deck the deck from which to deal
* @param size the size of the hands to deal
* @return the array of hands dealt to each player, or null if
* the deal was canceled because the deck did not contain enough
* cards
*/
public Hand[] dealHands (Deck deck, int size)
{
if (deck.size() < size * _playerCount) {
return null;
} else {
Hand[] hands = new Hand[_playerCount];
for (int i=0;i<_playerCount;i++) {
hands[i] = dealHand(deck, size, i);
}
return hands;
}
}
/**
* Gets the player index of the specified client object, or -1
* if the client object does not represent a player.
*/
public int getPlayerIndex (ClientObject client)
{
int oid = client.getOid();
for (int i=0;i<_playerOids.length;i++) {
if (_playerOids[i] == oid) {
return i;
}
}
return -1;
}
/**
* Returns the client object corresponding to the specified player index,
* or null if the position is not occupied by a player.
*/
public ClientObject getClientObject (int pidx)
{
if (_playerOids[pidx] != 0) {
return (ClientObject)PresentsServer.omgr.getObject(
_playerOids[pidx]);
} else {
return null;
}
}
/**
* Sends a set of cards from one player to another.
*
* @param fromPlayerIdx the index of the player sending the cards
* @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)
{
// Notify the sender that the cards have been taken
ClientObject fromClient = getClientObject(fromPlayerIdx);
if (fromClient != null) {
CardGameSender.sentCardsToPlayer(fromClient, toPlayerIdx, cards);
}
// Notify the receiver with the cards
ClientObject toClient = getClientObject(toPlayerIdx);
if (toClient != null) {
CardGameSender.sendCardsFromPlayer(toClient, fromPlayerIdx,
cards);
}
// and everybody else in the room other than the sender and the
// receiver with the number of cards sent
notifyCardsTransferred(fromPlayerIdx, toPlayerIdx, cards.length);
}
/**
* Sends sets of cards between players simultaneously. Each player is
* guaranteed to receive the notification of cards received after the
* notification of cards sent. The length of the arrays passed must
* be equal to the player count.
*
* @param toPlayerIndices for each player, the index of the player to
* transfer cards to
* @param cards for each player, the cards to transfer
*/
public void transferCardsBetweenPlayers (int[] toPlayerIndices,
Card[][] cards)
{
// Send all removal notices
for (int i = 0; i < _playerCount; i++) {
ClientObject fromClient = getClientObject(i);
if (fromClient != null) {
CardGameSender.sentCardsToPlayer(fromClient,
toPlayerIndices[i], cards[i]);
}
}
// Send all addition notices and notify everyone else
for (int i = 0; i < _playerCount; i++) {
ClientObject toClient = getClientObject(toPlayerIndices[i]);
if (toClient != null) {
CardGameSender.sendCardsFromPlayer(toClient, i, cards[i]);
}
notifyCardsTransferred(i, toPlayerIndices[i], cards[i].length);
}
}
/**
* Notifies everyone in the room (other than the sender and the receiver)
* that a set of cards have been transferred.
*
* @param fromPlayerIdx the index of the player sending the cards
* @param toPlayerIdx the index of the player receiving the cards
* @param cards the number of cards sent
*/
protected void notifyCardsTransferred (final int fromPlayerIdx,
final int toPlayerIdx, final int cards)
{
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) {
ClientObject client =
(ClientObject)PresentsServer.omgr.getObject(oid);
if (client != null) {
CardGameSender.cardsTransferredBetweenPlayers(client,
fromPlayerIdx, toPlayerIdx, cards);
}
}
}
};
applyToOccupants(op);
}
/** The card game object. */
protected CardGameObject _cardgameobj;
}
@@ -0,0 +1,85 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 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.server;
import com.threerings.parlor.card.client.CardGameDecoder;
import com.threerings.parlor.card.client.CardGameReceiver;
import com.threerings.parlor.card.data.Card;
import com.threerings.parlor.card.data.Hand;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationSender;
/**
* Used to issue notifications to a {@link CardGameReceiver} instance on a
* client.
*/
public class CardGameSender extends InvocationSender
{
/**
* 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[] { Integer.valueOf(arg1), Integer.valueOf(arg2), Integer.valueOf(arg3) });
}
/**
* Issues a notification that will result in a call to {@link
* CardGameReceiver#receivedCardsFromPlayer} on a client.
*/
public static void sendCardsFromPlayer (
ClientObject target, int arg1, Card[] arg2)
{
sendNotification(
target, CardGameDecoder.RECEIVER_CODE, CardGameDecoder.RECEIVED_CARDS_FROM_PLAYER,
new Object[] { Integer.valueOf(arg1), arg2 });
}
/**
* Issues a notification that will result in a call to {@link
* CardGameReceiver#receivedHand} on a client.
*/
public static void sendHand (
ClientObject target, int arg1, Hand arg2)
{
sendNotification(
target, CardGameDecoder.RECEIVER_CODE, CardGameDecoder.RECEIVED_HAND,
new Object[] { Integer.valueOf(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[] { Integer.valueOf(arg1), arg2 });
}
}
@@ -0,0 +1,49 @@
//
// $Id: TrickCardGameControllerDelegate.java 3465 2005-04-12 02:50:17Z andrzej $
//
// 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.client;
import com.threerings.parlor.turn.client.TurnGameControllerDelegate;
import com.threerings.parlor.card.client.CardGameController;
/**
* A card game controller delegate for trick-based card games, such as
* Spades and Hearts.
*/
public class TrickCardGameControllerDelegate
extends TurnGameControllerDelegate
{
/**
* Constructor.
*
* @param controller the game controller
*/
public TrickCardGameControllerDelegate (CardGameController
controller)
{
super(controller);
_cgctrl = controller;
}
/** The card game controller. */
protected CardGameController _cgctrl;
}
@@ -0,0 +1,41 @@
//
// $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
* @param handSize the size of the player's hand, which is used to verify
* that the request is for the current trick
*/
public void playCard (Client client, Card card, int handSize);
/**
* A request for a rematch.
*
* @param client the client object
*/
public void requestRematch (Client client);
}
@@ -0,0 +1,42 @@
//
// $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
// 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.data;
import com.threerings.parlor.card.data.CardCodes;
/**
* Constants relating to trick-based card games.
*/
public interface TrickCardCodes extends CardCodes
{
/** For four-player games, the bottom (own) player. */
public static final int BOTTOM = 0;
/** For four-player games, the player on the left. */
public static final int LEFT = 1;
/** For four-player games, the top (opposite) player. */
public static final int TOP = 2;
/** For four-player games, the player on the right. */
public static final int RIGHT = 3;
}
@@ -0,0 +1,73 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 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.data;
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.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
/**
* 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 TrickCardGameMarshaller extends InvocationMarshaller
implements TrickCardGameService
{
/** The method id used to dispatch {@link #playCard} requests. */
public static final int PLAY_CARD = 1;
// documentation inherited from interface
public void playCard (Client arg1, Card arg2, int arg3)
{
sendRequest(arg1, PLAY_CARD, new Object[] {
arg2, Integer.valueOf(arg3)
});
}
/** The method id used to dispatch {@link #requestRematch} requests. */
public static final int REQUEST_REMATCH = 2;
// documentation inherited from interface
public void requestRematch (Client arg1)
{
sendRequest(arg1, REQUEST_REMATCH, new Object[] {
});
}
/** The method id used to dispatch {@link #sendCardsToPlayer} requests. */
public static final int SEND_CARDS_TO_PLAYER = 3;
// documentation inherited from interface
public void sendCardsToPlayer (Client arg1, int arg2, Card[] arg3)
{
sendRequest(arg1, SEND_CARDS_TO_PLAYER, new Object[] {
Integer.valueOf(arg2), arg3
});
}
}
@@ -0,0 +1,210 @@
//
// $Id: TrickCardGameObject.java 3516 2005-04-21 00:47:17Z andrzej $
//
// 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.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;
/**
* Game objects for trick-based card games must implement this interface.
*/
public interface TrickCardGameObject extends TurnGameObject
{
/** 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;
/** Indicates that the player has not requested or accepted a rematch. */
public static final int NO_REQUEST = 0;
/** Indicates that the player has requested a rematch. */
public static final int REQUESTS_REMATCH = 1;
/** Indicates that the player has accepted the rematch request. */
public static final int ACCEPTS_REMATCH = 2;
/**
* Returns a reference to the trick card game service used to make
* requests to the server.
*
* @return a reference to the trick card game service
*/
public TrickCardGameMarshaller getTrickCardGameService ();
/**
* Sets the reference to the trick card game service.
*
* @param trickCardGameService the trick card game service
*/
public void setTrickCardGameService (TrickCardGameMarshaller
trickCardGameService);
/**
* 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 trickState field
*/
public String getTrickStateFieldName ();
/**
* Returns the trick state: between hands, playing a hand, or playing a
* trick.
*
* @return the trick state
*/
public int getTrickState ();
/**
* Sets the trick state.
*
* @param trickState the trick state
*/
public void setTrickState (int trickState);
/**
* Returns an array containing the turn duration scales for each player.
* Turn duration scales decrease each time players time out.
*
* @return the array of turn duration scales
*/
public float[] getTurnDurationScales ();
/**
* Sets the array of turn duration scales.
*
* @param turnDurationScales the array of turn duration scales
*/
public void setTurnDurationScales (float[] turnDurationScales);
/**
* Sets an element of the array of turn duration scales.
*
* @param turnDurationScale the turn duration scale
* @param index the index of the turn duration scale
*/
public void setTurnDurationScalesAt (float turnDurationScale, int index);
/**
* Returns the duration of the current turn, which may depend on the state
* of the game as well as the duration scale of the active player.
*/
public long getTurnDuration ();
/**
* Returns the name of the field that contains the history of the trick
* in terms of the cards played by each player.
*
* @return the name of the cardsPlayed field
*/
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);
/**
* Returns the name of the field that contains the rematch requests.
*
* @return the name of the rematchRequests field
*/
public String getRematchRequestsFieldName ();
/**
* Returns the array of rematch requests.
*
* @return the array of rematch requests
*/
public int[] getRematchRequests ();
/**
* Sets the array of rematch requests.
*
* @param rematchRequests the array of rematch requests
*/
public void setRematchRequests (int[] rematchRequests);
/**
* Sets an element of the rematch request array.
*
* @param rematchRequest the rematch request value
* @param index the index at which to set the value
*/
public void setRematchRequestsAt (int rematchRequest, int index);
/**
* 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 ();
}
@@ -0,0 +1,84 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 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.server;
import com.threerings.parlor.card.data.Card;
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.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 TrickCardGameProvider}.
*/
public class TrickCardGameDispatcher extends InvocationDispatcher
{
/**
* Creates a dispatcher that may be registered to dispatch invocation
* service requests for the specified provider.
*/
public TrickCardGameDispatcher (TrickCardGameProvider provider)
{
this.provider = provider;
}
// documentation inherited
public InvocationMarshaller createMarshaller ()
{
return new TrickCardGameMarshaller();
}
// documentation inherited
public void dispatchRequest (
ClientObject source, int methodId, Object[] args)
throws InvocationException
{
switch (methodId) {
case TrickCardGameMarshaller.PLAY_CARD:
((TrickCardGameProvider)provider).playCard(
source,
(Card)args[0], ((Integer)args[1]).intValue()
);
return;
case TrickCardGameMarshaller.REQUEST_REMATCH:
((TrickCardGameProvider)provider).requestRematch(
source
);
return;
case TrickCardGameMarshaller.SEND_CARDS_TO_PLAYER:
((TrickCardGameProvider)provider).sendCardsToPlayer(
source,
((Integer)args[0]).intValue(), (Card[])args[1]
);
return;
default:
super.dispatchRequest(source, methodId, args);
return;
}
}
}
@@ -0,0 +1,643 @@
//
// $Id: TrickCardGameManagerDelegate.java 4188 2006-06-13 18:03:48Z 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.server;
import java.util.ArrayList;
import java.util.Arrays;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.Interval;
import com.samskivert.util.RandomUtil;
import com.samskivert.util.StringUtil;
import com.threerings.util.Name;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.dobj.DObject;
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;
/**
* A card game manager delegate for trick-based card games, such as
* Spades and Hearts.
*/
public class TrickCardGameManagerDelegate extends TurnGameManagerDelegate
implements TrickCardGameProvider
{
/**
* Constructor.
*
* @param manager the game manager
*/
public TrickCardGameManagerDelegate (CardGameManager manager)
{
super(manager);
_cgmgr = manager;
_deck = new Deck();
}
// Documentation inherited.
public void didStartup (PlaceObject plobj)
{
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());
}
// Documentation inherited.
public void gameWillStart ()
{
super.gameWillStart();
// clear out the last cards played
_trickCardGame.setLastCardsPlayed(null);
// initialize the turn duration scales
float[] scales = new float[_cardGame.getPlayerCount()];
Arrays.fill(scales, 1.0f);
_trickCardGame.setTurnDurationScales(scales);
}
/**
* 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 gameDidEnd ()
{
super.gameDidEnd();
// 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);
}
// initialize the array of rematch requests
_trickCardGame.setRematchRequests(
new int[_cardGame.getPlayerCount()]);
}
// Documentation inherited.
public void startTurn ()
{
super.startTurn();
// initialize the timeout flag and schedule the timeout interval
_turnTimedOut = false;
_turnTimeoutInterval.schedule(_trickCardGame.getTurnDuration());
}
// Documentation inherited.
public void endTurn ()
{
// cancel the timeout interval
_turnTimeoutInterval.cancel();
// reduce or increase the turn duration scale
if (_turnTimedOut) {
reduceTurnDurationScale(_turnIdx);
} else {
increaseTurnDurationScale(_turnIdx);
}
super.endTurn();
}
/**
* Starts a hand of cards. Calls {@link #handWillStart}, sets the trick
* state to PLAYING_HAND, and calls {@link #handDidStart}.
*/
public void startHand ()
{
handWillStart();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_HAND);
handDidStart();
}
/**
* Ends the hand of cards. Calls {@link #handWillEnd}, sets the trick
* state to BETWEEN_HANDS, and calls {@link #handDidEnd}.
*/
public void endHand ()
{
handWillEnd();
_trickCardGame.setTrickState(TrickCardGameObject.BETWEEN_HANDS);
handDidEnd();
}
/**
* Starts a trick. Calls {@link #trickWillStart}, sets the trick
* state to PLAYING_TRICK, and calls {@link #trickDidStart}.
*/
public void startTrick ()
{
trickWillStart();
_trickCardGame.setTrickState(TrickCardGameObject.PLAYING_TRICK);
trickDidStart();
}
/**
* Ends the trick. Calls {@link #trickWillEnd}, sets the trick
* state to PLAYING_HAND, and calls {@link #trickDidEnd}.
*/
public void endTrick ()
{
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 calls {@link #sendCardsToPlayer(int, int,
* Card[])}.
*/
public void sendCardsToPlayer (ClientObject client, int toidx,
Card[] cards)
{
// make sure they're actually a player
int fromidx = _cgmgr.getPlayerIndex(client);
if (fromidx == -1) {
Log.warning("Send request from non-player [username=" +
((BodyObject)client).who() + ", cards=" +
StringUtil.toString(cards) + "].");
return;
}
// make sure they have the cards
if (!_hands[fromidx].containsAll(cards)) {
Log.warning("Tried to send cards not held [username=" +
((BodyObject)client).who() + ", cards=" +
StringUtil.toString(cards) + "].");
return;
}
// send the cards
sendCardsToPlayer(fromidx, toidx, cards);
}
/**
* Sends cards between players without error checking. Default
* implementation transfers the cards between hands and notifies
* everyone of the transfer using {@link
* CardGameManager#transferCardsBetweenPlayers(int, int, Card[])}.
*/
protected void sendCardsToPlayer (int fromidx, int toidx, Card[] cards)
{
// 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);
}
// Documentation inherited.
public void playCard (ClientObject client, Card card, int handSize)
{
// make sure we're playing a trick
if (_trickCardGame.getTrickState() !=
TrickCardGameObject.PLAYING_TRICK) {
return; // silently ignore play attempts after timeouts
}
// make sure it's their turn
Name username = ((BodyObject)client).getVisibleName();
if (!username.equals(_trickCardGame.getTurnHolder())) {
return;
}
// make sure they're on the right trick
int pidx = _cardGame.getPlayerIndex(username);
if (_hands[pidx].size() != handSize) {
return;
}
// make sure their hand contains the specified card
if (!_hands[pidx].contains(card)) {
Log.warning("Tried to play card not held [username=" + username +
", card=" + card + "].");
return;
}
// make sure the card is legal to play
if (!_trickCardGame.isCardPlayable(_hands[pidx], card)) {
Log.warning("Tried to play illegal card [username=" + username +
", card=" + card + "].");
return;
}
// play the card
playCard(pidx, card);
}
/**
* Plays a card for a player without error checking.
*/
protected void playCard (int pidx, Card card)
{
((DObject) _trickCardGame).startTransaction();
try {
// 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);
}
}
} finally {
((DObject) _trickCardGame).commitTransaction();
}
}
// Documentation inherited.
public void requestRematch (ClientObject client)
{
// make sure the game is over
if (_cardGame.state != CardGameObject.GAME_OVER) {
Log.warning("Tried to request rematch when game wasn't over " +
"[username=" + ((BodyObject)client).who() + "].");
return;
}
// make sure the requester is one of the players
int pidx = _cgmgr.getPlayerIndex(client);
if (pidx == -1) {
Log.warning("Rematch request from non-player [username=" +
((BodyObject)client).who() + "].");
return;
}
// make sure the player hasn't already requested
if (_trickCardGame.getRematchRequests()[pidx] !=
TrickCardGameObject.NO_REQUEST) {
Log.warning("Repeated rematch request [username=" +
((BodyObject)client).who() + "].");
return;
}
// if player is first requesting, set to request; else set
// to accept
int req = (getRematchRequestCount() == 0 ?
TrickCardGameObject.REQUESTS_REMATCH :
TrickCardGameObject.ACCEPTS_REMATCH);
_trickCardGame.setRematchRequestsAt(req, pidx);
// if all players accept the rematch, restart the game
if (getRematchRequestCount() == _cardGame.getPlayerCount()) {
_cgmgr.rematchGame();
}
}
/**
* Returns the number of players currently requesting or accepting
* a rematch.
*/
protected int getRematchRequestCount ()
{
int[] rematchRequests = _trickCardGame.getRematchRequests();
int count = 0;
for (int i = 0; i < rematchRequests.length; i++) {
if (rematchRequests[i] != TrickCardGameObject.NO_REQUEST) {
count++;
}
}
return count;
}
/**
* Checks whether the trick is complete--that is, whether each player has
* played a card.
*/
protected boolean isTrickComplete ()
{
return _trickCardGame.getCardsPlayed().length ==
_cardGame.getPlayerCount();
}
// 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;
}
}
/**
* 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) {
playCard(_turnIdx, pickRandomPlayableCard(_hands[_turnIdx]));
}
}
/**
* Reduces the specified player's turn duration due to a time-out.
*/
protected void reduceTurnDurationScale (int pidx)
{
float oldScale = _trickCardGame.getTurnDurationScales()[pidx],
newScale = Math.max(oldScale - TURN_DURATION_SCALE_REDUCTION,
MINIMUM_TURN_DURATION_SCALE);
if (newScale != oldScale) {
_trickCardGame.setTurnDurationScalesAt(newScale, pidx);
}
}
/**
* Increases the specified player's turn duration due to avoiding a
* time-out.
*/
protected void increaseTurnDurationScale (int pidx)
{
float oldScale = _trickCardGame.getTurnDurationScales()[pidx],
newScale = Math.min(oldScale + TURN_DURATION_SCALE_INCREASE,
1.0f);
if (newScale != oldScale) {
_trickCardGame.setTurnDurationScalesAt(newScale, pidx);
}
}
/**
* 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());
// clear out the cards played in the trick
_trickCardGame.setCardsPlayed(null);
// 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;
/** Whether or not the turn timed out. */
protected boolean _turnTimedOut;
/** The all-purpose turn timeout interval. */
protected Interval _turnTimeoutInterval =
new Interval(PresentsServer.omgr) {
public void expired () {
_turnTimedOut = true;
turnTimedOut();
}
};
/** Calls {@link #endTrick} upon expiration. */
protected Interval _endTrickInterval = new Interval(PresentsServer.omgr) {
public void expired () {
endTrick();
}
};
/** Reduce turn duration scales by this amount each time the player times
* out. */
protected static final float TURN_DURATION_SCALE_REDUCTION = 0.25f;
/**
* Increase turn duration scales by this amount each time the player
* manages not to time out. */
protected static final float TURN_DURATION_SCALE_INCREASE = 0.5f;
/** Don't let turn duration scales get below this level. */
protected static final float MINIMUM_TURN_DURATION_SCALE = 0.1f;
}
@@ -0,0 +1,50 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 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.server;
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.data.ClientObject;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.InvocationProvider;
/**
* Defines the server-side of the {@link TrickCardGameService}.
*/
public interface TrickCardGameProvider extends InvocationProvider
{
/**
* Handles a {@link TrickCardGameService#playCard} request.
*/
public void playCard (ClientObject caller, Card arg1, int arg2);
/**
* Handles a {@link TrickCardGameService#requestRematch} request.
*/
public void requestRematch (ClientObject caller);
/**
* Handles a {@link TrickCardGameService#sendCardsToPlayer} request.
*/
public void sendCardsToPlayer (ClientObject caller, int arg1, Card[] arg2);
}
@@ -0,0 +1,195 @@
//
// $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 pidx the player index
*/
public static int getTeamIndex (int pidx)
{
return pidx & 1;
}
/**
* 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 tidx ^ 1;
}
/**
* For four-player games with fixed partnerships, this returns the index
* of the player's partner.
*/
public static int getPartnerIndex (int pidx)
{
return pidx ^ 2;
}
/**
* 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 (midx << 1) | tidx;
}
/**
* For four-player games, this returns the index of the player after the
* specified player going clockwise around the table.
*/
public static int getNextInClockwiseSequence (int pidx)
{
// 2
// 1 3
// 0
return (pidx + 1) & 3;
}
/**
* 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 (pidx2 - pidx1) & 3;
}
/**
* For four-player games, returns the index of the player to the left of
* the specified player.
*/
public static int getLeftIndex (int pidx)
{
return (pidx + 1) & 3;
}
/**
* For four-player games, returns the index of the player to the right of
* the specified player.
*/
public static int getRightIndex (int pidx)
{
return (pidx + 3) & 3;
}
/**
* For four-player games, returns the index of the player across from the
* specified player.
*/
public static int getOppositeIndex (int pidx)
{
return pidx ^ 2;
}
/**
* 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;
}
/**
* Checks whether the specified array contains the given card.
*/
public static boolean containsCard (PlayerCard[] cards, Card card)
{
for (int i = 0; i < cards.length; i++) {
if (cards[i].card.equals(card)) {
return true;
}
}
return false;
}
/**
* 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;
}
}