contest/
contest/Merc21/
contest/Merc21/log/
contest/Merc21/player/
contest/doc/
contest/example/Merc21/
contest/example/Merc21/log/
contest/example/Merc21/player/
contest/example/doc/
contest/example/standalone/
contest/standalone/
******************************************************************************
File Name : installation.txt
Date      : 27th October 2005
Author    : Richard Woolcock
******************************************************************************

The following changes are required in order to install the snippet into a 
stock copy of Merc2.1.  As many other codebases are also derived from Merc, 
it shouldn't take much effort to apply the same instructions to them - ROM, 
Smaug, GodWars, etc.

******************************************************************************
Changes to be made to Merc.h
******************************************************************************

At the top of the file, right under the copyright notice, add:

    #include "deck.h"
    #include "hand.h"

In the pc_data struct, after this:

    char *              bamfin;
    char *              bamfout;
    char *              title;

Add:

    deck_t *            deck;
    hand_t *            hand;
    CHAR_DATA *		prev_card_player;
    CHAR_DATA *		next_card_player;
    bool		play_turn;

If you later add support for mobs playing card games, you'll probably want to 
move the above into char_data, but for now it's assumed that only players can 
play card games.

In the "Command functions" section, add the following:

    DECLARE_DO_FUN( do_bet          );
    DECLARE_DO_FUN( do_deal         );
    DECLARE_DO_FUN( do_discard      );
    DECLARE_DO_FUN( do_draw         );
    DECLARE_DO_FUN( do_fold         );
    DECLARE_DO_FUN( do_hand         );
    DECLARE_DO_FUN( do_play         );
    DECLARE_DO_FUN( do_shuffle      );
    DECLARE_DO_FUN( do_stick        );

You'll probably want to insert them in alphabetical order, for readability.

******************************************************************************
Changes to be made to interp.c
******************************************************************************

Add the following to the end of the command table (cmd_table):

    /*
     * Card game commands.
     */
    { "bet",            do_bet,         POS_RESTING,     0,  LOG_NORMAL },
    { "deal",           do_deal,        POS_RESTING,     0,  LOG_NORMAL },
    { "discard",        do_discard,     POS_RESTING,     0,  LOG_NORMAL },
    { "draw",           do_draw,        POS_RESTING,     0,  LOG_NORMAL },
    { "fold",           do_fold,        POS_RESTING,     0,  LOG_NORMAL },
    { "hand",           do_hand,        POS_RESTING,     0,  LOG_NORMAL },
    { "play",           do_play,        POS_RESTING,     0,  LOG_NORMAL },
    { "shuffle",        do_shuffle,     POS_RESTING,     0,  LOG_NORMAL },
    { "stick",          do_stick,       POS_RESTING,     0,  LOG_NORMAL },

******************************************************************************
Changes to be made to save.c
******************************************************************************

In the load_char_obj() function, after this:

    ch->pcdata->bamfin                  = str_dup( "" );
    ch->pcdata->bamfout                 = str_dup( "" );
    ch->pcdata->title                   = str_dup( "" );

Add:

    ch->pcdata->deck                    = NULL;
    ch->pcdata->hand                    = NULL;
    ch->pcdata->prev_card_player        = NULL;
    ch->pcdata->next_card_player        = NULL;
    ch->pcdata->play_turn               = FALSE;

This ensures that the deck and hand are cleared upon initialisation.

******************************************************************************
Changes to be made to handler.c
******************************************************************************

At the top, after the following headers:

    #include <ctype.h>
    #include <stdio.h>

Add one more header file:

    #include <stdlib.h>

It's needed for the call to free(), which comes next.

In the extract_char() function, after this:

    if ( IS_NPC(ch) )
        --ch->pIndexData->count;

Add this:

    else // They're a PC.
    {
	if ( ch->pcdata->deck != NULL )
	{
	    CHAR_DATA *prev = ch->pcdata->prev_card_player;
	    CHAR_DATA *next = ch->pcdata->next_card_player;

	    /* Strip the character from the player list */
	    if ( prev != NULL )
		prev->pcdata->next_card_player = next;
	    if ( next != NULL )
		next->pcdata->prev_card_player = prev;

	    /* Destroy the deck if nobody else is using it */
	    if ( --ch->pcdata->deck->Instances <= 0 )
		free( ch->pcdata->deck );
	}

        /* Free and clear their hand */
        free( ch->pcdata->hand );
    }

This will destroy their deck if nobody else is using it, and will also 
destroy their hand.

******************************************************************************
Help files to add to help.are
******************************************************************************

0 BET~
Syntax: bet <gold>
Syntax: bet call

This command allows you to bet a number of gold pieces.  The amount you bet 
must be greater than the previous bet, and other players will then have to 
call it (equal the bet made), raise it (bet higher) or fold.

You may also chose to call the current bet, if you have enough gold.  If you 
cannot even match the bet, you will have to fold.  It is possible to have a 
bid of 0gp, if nobody else has opened the betting.  The dealer always goes 
first, and may therefore set the ante as his or her opening bet.

See also: deal discard draw fold play shuffle
~

0 DEAL~
Syntax: deal

This command allows you to deal a hand of 5 cards to every player, and thus 
start the game.  Only the dealer (who first created the game) may use this 
command.

See also: bet discard draw fold play shuffle
~

0 DISCARD~
Syntax: discard <card>

This command allows you to discard a card from your hand.  You must specify the
card by using its value - for example 'discard C2' to discard the Two of Clubs.

See also: bet deal draw fold hand play shuffle
~

0 DRAW~
Syntax: draw

This command allows you to draw the top card from the deck.  The card you have
drawn will also be revealed to you, although nobody else will see it.

See also: bet deal discard fold hand play shuffle
~

0 FOLD~
Syntax: fold

This command causes you to fold, quitting from whichever card game you are 
currently playing.  This will also reveal your hand.

See also: bet deal discard draw hand play shuffle
~

0 HAND~
Syntax: hand
Syntax: hand table

This command allows you to look at the cards in your hand.  You may also type 
'hand table' to show a table of which cards you have.

See also: bet deal discard draw fold play shuffle
~

0 PLAY~
Syntax: play <person>

This command allows you to begin a game of cards.  You may choose to join an 
existing game, or start a new one - either with yourself or with someone else.

See also: bet deal discard draw fold hand shuffle
~

0 SHUFFLE~
Syntax: shuffle

This command allows you to shuffle the deck you're currently playing with.

See also: bet deal discard draw fold hand play
~

******************************************************************************
Create a new file called card_commands.c
******************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "deck.h"
#include "hand.h"
#include "poker.h"
#include "merc.h"

void RevealScore( CHAR_DATA *ch )
{
    if ( ch->pcdata->deck != NULL && ch->pcdata->hand != NULL )
    {
	CHAR_DATA *next, *winner = ch;
	combination_t HighCombination = eCombinationHighCard;
        char HighScore[16] = {'\0'};
	int gold = ch->pcdata->deck->Pot;

	for ( next = ch; next != NULL; next = next->pcdata->next_card_player )
	{
	    /* Calculate score */
	    combination_t Combination = eCombinationMax;
            char buf[MAX_STRING_LENGTH];

	    sprintf( buf, "You reveal your hand: %s\n\r", 
		HandShow(next->pcdata->hand, eFalse) );
	    send_to_char( buf, next );
	    sprintf( buf, "$n reveals $s hand: %s", 
		HandShow(next->pcdata->hand, eFalse) );
	    act( buf, next, NULL, NULL, TO_ROOM );

	    strncpy( buf, PokerScore(next->pcdata->hand, &Combination), 15 );

	    if ( Combination > HighCombination )
	    {
		/* We've a new high score */
		HighCombination = Combination;
		strcpy( HighScore, buf );
		winner = next;
	    }
	    else if ( Combination == HighCombination )
	    {
		int i; /* Loop counter */

		for ( i = 0; HighScore[i] != '\0' && buf[i] != '\0'; ++i )
		{
		    if ( HighScore[i] > buf[i] )
		    {
			/* We've a new high score */
			HighCombination = Combination;
			strcpy( HighScore, buf );
			winner = next;
		    }
		}
	    }

	    /* Dispose of their hand and deck */
	    if ( --next->pcdata->deck->Instances <= 0 )
		free( next->pcdata->deck );
	    next->pcdata->deck = NULL;
	    free( next->pcdata->hand );
	    next->pcdata->hand = NULL;
	}

	send_to_char( "\n\rYou win!  You collect the gold from the pot.\n\r", winner );
	act( "\n\rWINNER!  $n collects the gold from the pot.", winner, NULL, NULL, TO_ROOM );
	winner->gold += gold;
    }
}

void NextPlayer( CHAR_DATA *ch )
{
    char buf[MAX_STRING_LENGTH];
    if ( ch->pcdata->deck != NULL && ch->pcdata->hand != NULL )
    {
	/* You've drawn one or more cards, so your turn is over */
	ch->pcdata->play_turn = FALSE;

	sprintf( buf, "It's now your turn (pot: %dgp, current bet: %dgp).\n\r", 
	    ch->pcdata->deck->Pot, ch->pcdata->deck->Bet );

	if ( ch->pcdata->next_card_player != NULL )
	{
	    /* It's now the next players turn */
	    CHAR_DATA *next = ch->pcdata->next_card_player;

	    next->pcdata->play_turn = TRUE;
	    send_to_char( buf, next );
	    act( "It is now $n's turn.", next, NULL, NULL, TO_ROOM );
	}
	else /* We've reached the last player, so go back to the first one */
	{
	    CHAR_DATA *prev = ch->pcdata->prev_card_player;
	    if ( prev == NULL )
	    {
		/* There's only one player, so make them win */
		ch->pcdata->play_turn = TRUE;
		ch->pcdata->deck->Turn = 3;
		RevealScore( ch );
	    }
	    else /* Keep going back until we reach the start */
	    {
		while ( prev->pcdata->prev_card_player != NULL )
		    prev = prev->pcdata->prev_card_player;

		/* The first player has a turn again */
		prev->pcdata->play_turn = TRUE;

		if ( ++prev->pcdata->deck->Turn > 3 )
		{
		    /* Reveal the scores */
		    RevealScore( prev );
		}
		else /* The game is not yet finished */
		{
		    send_to_char( buf, prev );
		    act( "It is now $n's turn.", prev, NULL, NULL, TO_ROOM );
		}
	    }
	}
    }
}

void do_bet( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    int gold = 0;

    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to start a game before you can bet.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Turn > 3 )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Playing == eFalse )
    {
	send_to_char( "You cannot bet until the first hand has been dealt.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Turn == 2 )
    {
	send_to_char( "You cannot bet on the second turn - either discard/draw, or stick.\n\r", ch );
    }
    else if ( ch->pcdata->play_turn == FALSE )
    {
	send_to_char( "You can only bet on your turn.\n\r", ch );
    }
    else if ( argument[0] == '\0' )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "How much do you wish to bet?  The current bet is %d gold.\n\r", 
	    ch->pcdata->deck->Bet );
	send_to_char( buf, ch );
    }
    else if ( !strcmp( argument, "call" ) )
    {
	if ( ch->gold < ch->pcdata->deck->Bet )
	{
	    send_to_char( "You don't have enough gold to call the current bet.  You'll have to fold.\n\r", ch );
	}
	else /* They can call the current bet */
	{
	    if ( ch->pcdata->deck->Bet == 0 )
	    {
		send_to_char( "You defer to the next player.\n\r", ch );
		act( "$n defers, chosing not to place a bet.", ch, NULL, NULL, TO_ROOM );
	    }
	    else /* It's a proper bet */
	    {
		/* Update the pot and the characters gold */
		ch->pcdata->deck->Pot += ch->pcdata->deck->Bet;
		ch->gold -= ch->pcdata->deck->Bet;

		sprintf( buf, "Your call the current bet of %d gold.\n\r", ch->pcdata->deck->Bet );
		send_to_char( buf, ch );
		sprintf( buf, "$n calls the current bet of %d gold.", ch->pcdata->deck->Bet );
		act( buf, ch, NULL, NULL, TO_ROOM );
	    }

	    /* Turn over - next player */
	    NextPlayer(ch);
	}
    }
    else if ( !is_number(argument) )
    {
	sprintf( buf, "Please specify a number of gold pieces to bet.  The current bet is %d gold.\n\r", 
	    ch->pcdata->deck->Bet );
	send_to_char( buf, ch );
    }
    else if ( (gold = atoi(argument)) <= ch->pcdata->deck->Bet )
    {
	sprintf( buf, "You must exceed the current bet of %d gold.\n\r", 
	    ch->pcdata->deck->Bet );
	send_to_char( buf, ch );
    }
    else if ( gold > ch->gold )
    {
	send_to_char( "You don't have enough gold to bet that much.\n\r", ch );
    }
    else /* It's a valid bet */
    {
	/* Update the bet, the pot, and the characters gold */
	ch->pcdata->deck->Bet = gold;
	ch->pcdata->deck->Pot += gold;
	ch->gold -= gold;

	sprintf( buf, "Your raise the bet to %d gold.\n\r", ch->pcdata->deck->Bet );
	send_to_char( buf, ch );
	sprintf( buf, "$n raises the bet to %d gold.", ch->pcdata->deck->Bet );
	act( buf, ch, NULL, NULL, TO_ROOM );

	/* Turn over - next player */
	NextPlayer(ch);
    }
}

void do_deal( CHAR_DATA *ch, char *argument )
{
    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to start a game before you can deal.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Playing == eTrue )
    {
	send_to_char( "You can only deal at the start of a game.\n\r", ch );
    }
    else if ( ch->pcdata->play_turn == FALSE )
    {
	send_to_char( "You're not the dealer.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Instances < 2 )
    {
	send_to_char( "You need at least 2 players for a game of poker.\n\r", ch );
    }
    else /* Go ahead and deal the cards */
    {
	/* Indicate that the game has begun */
	ch->pcdata->deck->Playing = eTrue;

	/* Set the turn to turn 1 */
	ch->pcdata->deck->Turn = 1;

        while ( HandCountCards(ch->pcdata->hand) < 5 )
        {
	    CHAR_DATA *next;
            
	    for ( next = ch; next != NULL; next = next->pcdata->next_card_player )
	    {
		/* Draw a card from the deck and put it in their hand */
		card_t card = DeckDrawCard(next->pcdata->deck);
		(void)HandAddCard(next->pcdata->hand, card);

		if ( HandCountCards(next->pcdata->hand) == 5 )
		{
		    char buf[MAX_STRING_LENGTH];
		    if ( ch == next )
		    {
			sprintf( buf, "You deal yourself 5 cards: %s\n\r\n\r", 
			    HandShow(next->pcdata->hand, eFalse) );
			send_to_char( buf, ch );
		    }
		    else /* Dealt to someone else */
		    {
			sprintf( buf, "$n deals you 5 cards: %s\n\r", 
			    HandShow(next->pcdata->hand, eFalse) );
			act( buf, ch, NULL, next, TO_VICT );
		    }
		    send_to_char( HandShow(next->pcdata->hand, eTrue), next );
		}
	    }
	}
    }
}

void do_discard( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    card_t card;
    suit_t suit;
    rank_t rank;

    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to start playing before you can discard a card.\n\r", ch );
	return;
    }

    /* The game is over */
    if ( ch->pcdata->deck->Turn > 3 )
    {
	send_to_char( "The game is already over.\n\r", ch );
	return;
    }

    /* You can only discard on your turn */
    if ( ch->pcdata->play_turn == FALSE )
    {
	send_to_char( "You can only discard on your own turn.\n\r", ch );
	return;
    }

    /* You can only discard on once the game has started */
    if ( ch->pcdata->deck->Playing == eFalse )
    {
	send_to_char( "You cannot discard any cards until the dealer has dealt the first hand.\n\r", ch );
	return;
    }

    /* You can only discard on the second turn of the game */
    if ( ch->pcdata->deck->Turn != 2 )
    {
	send_to_char( "You can only discard on your second turn.\n\r", ch );
	return;
    }

    /* You can only discard up to 4 cards */
    if ( HandCountCards(ch->pcdata->hand) < 2 )
    {
	send_to_char( "You may only discard up to 4 cards.\n\r", ch );
	return;
    }

    if ( argument[0] == '\0' || strlen(argument) != 2 )
    {
	send_to_char( "Please specify which card do you wish to discard (eg 'discard H5').\n\r", ch );
	return;
    }

    /* Find the suit and rank of the card they're trying to discard */
    suit = CardSuit( UPPER(argument[0]) );
    rank = CardRank( UPPER(argument[1]) );

    if ( suit == eSuitMax || rank == eRankMax )
    {
	sprintf( buf, "There is no such card as '%s'.\n\r", argument );
	send_to_char( buf, ch );
	return;
    }

    /* Find the card type, based on its suit and rank */
    card = CardType( suit, rank );

    /* Try to remove the card from their hand */
    if ( HandRemoveCard(ch->pcdata->hand, card) == eFalse )
    {
	sprintf( buf, "You're not even holding the %s (%s)!\n\r", 
	   CardName(card), CardValue(card) );
	send_to_char( buf, ch );
	return;
    }

    /* Try to put the card back onto the bottom of the deck */
    if ( DeckReturnCard(ch->pcdata->deck, card) == eFalse )
    {
	sprintf( buf, "do_discard: Tried to return '%s' to deck, but it was already there!", CardValue(card) );
	bug( buf, 0 );
    }

    sprintf( buf, "You discard the %s (%s) from your hand.\n\r", 
	CardName(card), CardValue(card) );
    send_to_char( buf, ch );
    act( "$n discards a card from $s hand.", ch, NULL, NULL, TO_ROOM );
}

void do_draw( CHAR_DATA *ch, char *argument )
{
    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to start playing before you can draw a card.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Turn > 3 )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( ch->pcdata->play_turn == FALSE )
    {
	send_to_char( "You can only draw a card on your own turn.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Playing == eFalse )
    {
	send_to_char( "You cannot draw any cards until the dealer has dealt the first hand.\n\r", ch );
    }
    else if ( HandCountCards(ch->pcdata->hand) == 5 )
    {
	send_to_char( "You've already got a full hand of 5 cards.\n\r", ch );
    }
    else /* They're playing, so draw a card */
    {
	char buf[MAX_STRING_LENGTH];
        int CardsDrawn = 0;

        while ( HandCountCards(ch->pcdata->hand) < 5 )
	{
	    /* Draw a card from the deck and put it in their hand */
	    card_t card = DeckDrawCard(ch->pcdata->deck);

	    if ( card == eCardMax )
            {
		bug( "do_draw: Managed to end up with an empty deck.", 0 );
		send_to_char( "The deck is empty!\n\r", ch );
		break;
            }
            else if ( HandAddCard(ch->pcdata->hand, card) == eTrue )
            {
		CardsDrawn++;
	    }
	    else /* They were unable to add the card to their hand */
	    {
		bug( "do_draw: Duplicate card found in hand.", 0 );
		send_to_char( "You were unable to draw the card.\n\r", ch );
		break;
	    }
	}

	sprintf( buf, "You draw %d new card%s from the deck.\n\r", 
	    CardsDrawn, CardsDrawn == 1 ? "" : "s" );
	send_to_char( buf, ch );
	sprintf( buf, "$n draws %d new card%s from the deck.", 
	    CardsDrawn, CardsDrawn == 1 ? "" : "s" );
	act( buf, ch, NULL, NULL, TO_ROOM );

	/* Turn over - next player */
	NextPlayer(ch);
    }
}

void do_fold( CHAR_DATA *ch, char *argument )
{
    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to be playing before you can fold.\n\r", ch );
    }
    else if ( ch->pcdata->play_turn == FALSE )
    {
	send_to_char( "You can only fold on your own turn.\n\r", ch );
    }
    else /* Show the hand (if any) and then discard it */
    {
	CHAR_DATA *prev = ch->pcdata->prev_card_player;
	CHAR_DATA *next = ch->pcdata->next_card_player;

	if ( HandCountCards(ch->pcdata->hand) == 0 )
	{
	    send_to_char( "You fold.\n\r", ch );
	    act( "$n folds ($s hand is already empty).", ch, NULL, NULL, TO_ROOM );
	}
	else /* Show their hand, then put the cards back into the deck */
	{
	    char buf[MAX_STRING_LENGTH];
	    int i; /* Loop counter */
            const char *pCards = HandShow(ch->pcdata->hand, eFalse);
	    int Max = strlen(pCards);

	    sprintf( buf, "You fold, throwing down your hand: %s\n\r", pCards );
	    send_to_char( buf, ch );
	    sprintf( buf, "Placing $s cards down, $n folds, revealing: %s", pCards );
	    act( buf, ch, NULL, NULL, TO_ROOM );

	    for ( i = 0; i < Max; i += 3 )
            {
		/* Put all the cards in their hand back into the deck */
		card_t card = CardType(CardSuit(pCards[i]), CardRank(pCards[i+1]));
		if ( card != eCardMax )
                {
		    /* Make sure the card isn't already in the deck */
		    if ( DeckReturnCard(ch->pcdata->deck, card) == eFalse )
		    {
			sprintf( buf, "do_discard: Tried to return '%s' to deck, but it was already there!\n\r", 
			   CardValue(card) );
			bug( buf, 0 );
		    }
		}
            }
	}

	/* Turn over - next player */
	NextPlayer(ch);

	/* Destroy the hand (no need to remove the cards beforehand) */
	free(ch->pcdata->hand);
        ch->pcdata->hand = NULL;

	/* Strip the character from the player list */
	if ( prev != NULL )
	    prev->pcdata->next_card_player = next;
	if ( next != NULL )
	    next->pcdata->prev_card_player = prev;

	/* If they're the last person using that deck, destroy it */
        if ( --ch->pcdata->deck->Instances == 0 )
           free(ch->pcdata->deck);
        ch->pcdata->deck = NULL;
    }
}

void do_hand( CHAR_DATA *ch, char *argument )
{
    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to start playing in order to get a hand of cards.\n\r", ch );
    }
    else if ( HandCountCards(ch->pcdata->hand) == 0 )
    {
	send_to_char( "Your hand is currently empty - you need to draw a card.\n\r", ch );
    }
    else /* Just show the hand to its owner */
    {
	char buf[MAX_STRING_LENGTH];

	sprintf( buf, "You glance at your hand: %s\n\r\n\r", 
	    HandShow(ch->pcdata->hand, eFalse) );
	send_to_char( buf, ch );

	if ( !strcmp(argument, "table") )
	    send_to_char( PokerScore(ch->pcdata->hand, NULL), ch );
	else /* Show the graphical layout */
	    send_to_char( HandShow(ch->pcdata->hand, eTrue), ch );
    }
}

void do_stick( CHAR_DATA *ch, char *argument )
{
    if ( ch->pcdata->deck == NULL || ch->pcdata->hand == NULL )
    {
	send_to_char( "You need to start a game before you can stick with your hand.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Turn > 3 )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( ch->pcdata->deck->Turn != 2 )
    {
	send_to_char( "You can only stick (choose not to discard) on the second turn.\n\r", ch );
    }
    else if ( ch->pcdata->play_turn == FALSE )
    {
	send_to_char( "You can only stick on your own turn.\n\r", ch );
    }
    else /* They choose to do nothing this turn */
    {
	send_to_char( "You choose not to discard any cards.\n\r", ch );
	act( "$n chooses not to discard any cards.", ch, NULL, NULL, TO_ROOM );

	/* Turn over - next player */
	NextPlayer(ch);
    }
}

void do_play( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;

    if ( argument[0] == '\0' )
    {
	send_to_char( "Who do you wish to play with?\n\r", ch );
	return;
    }

    /* Make sure the target exists, and is in the same room as ch */
    if ( ( victim = get_char_world( ch, argument ) ) == NULL
    || ( victim->in_room != ch->in_room ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    /* Make sure that neither ch or victim are NPCs */
    if ( IS_NPC(ch) || IS_NPC(victim) )
    {
	send_to_char( "Only players can play cards.\n\r", ch );
	return;
    }

    /* Make sure the character is not already playing a game */
    if ( ch->pcdata->deck != NULL )
    {
	send_to_char( "You're already playing a game.\n\r", ch );
	return;
    }

    /* Make sure the game isn't already full or under way */
    if ( victim->pcdata->deck != NULL )
    {
	if ( victim->pcdata->deck->Instances >= 6 )
	{
	    send_to_char( "That game is already full (it has 6 players).\n\r", ch );
	    return;
	}
	else if ( victim->pcdata->deck->Playing == eTrue )
	{
	    send_to_char( "You cannot join a game which is already under way.\n\r", ch );
	    return;
	}
    }

    if ( ch == victim )
    {
	/* Create a new deck of cards for solo play */
	ch->pcdata->deck = DeckCreate();
	ch->pcdata->deck->Instances = 1;

	/* Shuffle the deck */
	DeckShuffle(ch->pcdata->deck);

	/* Create an empty hand for the character */
	ch->pcdata->hand = HandCreate();

	/* Indicate that it's this characters turn */
	ch->pcdata->play_turn = TRUE;

	send_to_char( "You begin a game of cards (type 'deal' to start).\n\r", ch );
	act( "$n begins a game of cards.", ch, NULL, NULL, TO_ROOM );
    }
    else if ( victim->pcdata->deck == NULL )
    {
	/* Create a new deck of cards, used by both characters */
	victim->pcdata->deck = DeckCreate();
	ch->pcdata->deck = victim->pcdata->deck;
	ch->pcdata->deck->Instances = 2;

	/* Shuffle the deck */
	DeckShuffle(ch->pcdata->deck);

	/* Create an empty hand for both characters */
	victim->pcdata->hand = HandCreate();
	ch->pcdata->hand = HandCreate();

	/* Indicate who's turn it is */
	ch->pcdata->play_turn = TRUE;
	victim->pcdata->play_turn = FALSE;

	/* Add both characters into the same player list */
	ch->pcdata->next_card_player = victim;
	victim->pcdata->prev_card_player = ch;

	act( "You begin a game of cards with $N (type 'deal' to start).", ch, NULL, victim, TO_CHAR );
	act( "$n begins a game of cards with you.", ch, NULL, victim, TO_VICT );
	act( "$n begins a game of cards with $N.", ch, NULL, victim, TO_NOTVICT );
    }
    else /* The other person is already playing, so join their game */
    {
	/* Set ch to use the same deck as victim */
	ch->pcdata->deck = victim->pcdata->deck;
	ch->pcdata->deck->Instances++;

	/* Create an empty hand for ch */
	ch->pcdata->hand = HandCreate();

	/* Indicate that it's not this characters turn */
	ch->pcdata->play_turn = FALSE;

	/* Add yourself to the end of their player list */
	if ( victim->pcdata->next_card_player == NULL )
	{
	    victim->pcdata->next_card_player = ch;
	    ch->pcdata->prev_card_player = victim;
	}
	else /* There are already other players, so join at the end */
	{
	    CHAR_DATA *next = victim;

	    while ( next->pcdata->next_card_player != NULL )
		next = next->pcdata->next_card_player;
	    next->pcdata->next_card_player = ch;
	    ch->pcdata->prev_card_player = next;
	}

	act( "You join $N's game of cards.", ch, NULL, victim, TO_CHAR );
	act( "$n joins your game of cards.", ch, NULL, victim, TO_VICT );
	act( "$n joins $N's game of cards.", ch, NULL, victim, TO_NOTVICT );
    }
}

void do_shuffle( CHAR_DATA *ch, char *argument )
{
    if ( ch->pcdata->deck == NULL )
    {
	send_to_char( "You need to start playing before you can shuffle the deck.\n\r", ch );
    }
    else if ( DeckCountCards(ch->pcdata->deck) == 0 )
    {
	send_to_char( "You can't shuffle the deck, there's no cards left in it!.\n\r", ch );
    }
    else /* Shuffle the deck */
    {
	DeckShuffle(ch->pcdata->deck);

	send_to_char( "You shuffle the deck.\n\r", ch );
	act( "$n shuffles the deck.", ch, NULL, NULL, TO_ROOM );
    }
}

******************************************************************************
End of installation.txt
******************************************************************************