contest/
contest/Merc21/
contest/Merc21/log/
contest/Merc21/player/
******************************************************************************
File Name : installation.txt
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.

Note new card games can be added fairly easily by adding a new enum to game.h 
and entering the new game into the GameRulesTable in game.c - you can easily 
adjust the existing games as well if you wish.

******************************************************************************
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 char_data struct, after this:

    char *		long_descr;
    char *		description;

Add:

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

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_double       );
    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_start        );
    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 },
    { "double",         do_double,      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 },
    { "start",          do_start,       POS_RESTING,     0,  LOG_NORMAL },
    { "stick",          do_stick,       POS_RESTING,     0,  LOG_NORMAL },

******************************************************************************
Changes to be made to db.c
******************************************************************************

In the clear_char() function, after this:

    ch->max_mana		= 100;
    ch->move			= 100;
    ch->max_move		= 100;

Add:

    ch->deck                    = NULL;
    ch->hand                    = NULL;
    ch->prev_card_player        = NULL;
    ch->next_card_player        = NULL;
    ch->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:

    if ( ch->deck != NULL )
    {
	CHAR_DATA *prev = ch->prev_card_player;
	CHAR_DATA *next = ch->next_card_player;

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

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

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

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

******************************************************************************
Changes to be made to special.c
******************************************************************************

Declare the following special functions:

    DECLARE_SPEC_FUN(	spec_poker_player	);
    DECLARE_SPEC_FUN(	spec_texas_player	);
    DECLARE_SPEC_FUN(	spec_blackjack_player	);

Add them to the spec_lookup() function as follows:

    if ( !str_cmp( name, "spec_poker_player"	  ) ) return spec_poker_player;
    if ( !str_cmp( name, "spec_texas_player"	  ) ) return spec_texas_player;
    if ( !str_cmp( name, "spec_blackjack_player"  ) ) return spec_blackjack_player;

Create the definitions as follows:



bool spec_poker_player( CHAR_DATA *ch )
{
    if ( ch->position != POS_STANDING )
	return FALSE;

    if ( ch->deck == NULL )
    {
	/* Start a game of draw poker */
	do_start( ch, "Draw Poker" );
    }
    else if ( ch->deck->Instances == 1 )
    {
	/* They've not started the game yet */
	do_say( ch, "Who wants to play Draw Poker?  Use the 'play' command." );
    }
    else if ( ch->deck->Playing == eFalse )
    {
	do_say( ch, "Let's play!" );
	do_deal( ch, "" );
    }
    else if ( ch->play_turn == TRUE )
    {
	/* The game is underway! */
	combination_t Combination = eCombinationMax;
	char arg[MAX_INPUT_LENGTH];
	char *pActions = NULL;

	switch ( ch->deck->Turn )
	{
	    case 1: /* Turn 1: deal, and place the initial bet */
		/* Make sure they have enough gold to match the bet */
		if ( ch->deck->Bet > 0 )
		{
		    if ( ch->gold < ch->deck->Bet )
			ch->gold = ch->deck->Bet;
		    do_bet( ch, "call" );
		}
		else /* There's no bet yet, so make one */
		{
		    /* Make sure they have enough gold, or the AI will get stuck */
		    if ( ch->gold < 10 )
			ch->gold = 10;
		    do_bet( ch, "10" );
		}
		break;
	    case 2: /* Turn 2: discard some cards if appropriate */
		pActions = GameAdvice(ch->deck->Game, ch->hand);
		if ( pActions != NULL && pActions[0] != '\0' )
		{
		    pActions = one_argument( pActions, arg );
		    if ( !str_cmp( arg, "discard" ) )
		    {
			while ( pActions[0] != '\0' )
			{
			    pActions = one_argument( pActions, arg );
			    if ( arg[0] != '\0' && strlen(arg) == 2 )
				do_discard( ch, arg );
			}
			do_draw( ch, "" );
		    }
		    else /* Their only other option is to stick. */
		    {
			do_stick( ch, "" );
		    }
		}
		break;
	    case 3: /* Turn 3: place another bet, or call */
		(void)ScorePoker(ch->hand, &Combination);

		/* Maybe he'll give up */
		if ( Combination == eCombinationHighCard && number_range(1,10) <= 4 )
		{
		    do_fold( ch, "" );
		}
		else if ( number_range(1,10) <= Combination+1 )
		{
		    int Bet = ch->deck->Bet * number_range(2,3);
		    
		    /* Make sure they have enough gold to make the bet */
		    if ( ch->gold < Bet )
			ch->gold = Bet;

		    /* Place the bet */
		    sprintf( arg, "%d", Bet );
		    do_bet( ch, arg );
		}
		else /* Just make them match the bet */
		{
		    /* Make sure they have enough gold to match the bet */
		    if ( ch->gold < ch->deck->Bet )
			ch->gold = ch->deck->Bet;
		    do_bet( ch, "call" );
		}
		break;
	    default: /* Should never reach this point */
		break;
	}
    }

    return TRUE;
}



bool spec_texas_player( CHAR_DATA *ch )
{
    if ( ch->position != POS_STANDING )
	return FALSE;

    if ( ch->deck == NULL )
    {
	/* Start a game of Texas hold 'em poker */
	do_start( ch, "Texas Hold 'em" );
    }
    else if ( ch->deck->Instances == 1 )
    {
	/* They've not started the game yet */
	do_say( ch, "Who wants to play Texas Hold 'em?  Use the 'play' command." );
    }
    else if ( ch->deck->Playing == eFalse )
    {
	do_say( ch, "Let's play!" );
	do_deal( ch, "" );
    }
    else if ( ch->play_turn == TRUE )
    {
	/* The game is underway! */
	combination_t Combination = eCombinationMax;
	(void)ScorePoker(ch->hand, &Combination);

	if ( ch->deck->Bet < 10 )
	{
	    /* Make sure they have enough gold for the initial bet */
	    if ( ch->gold < 10 )
		ch->gold = 10;

	    /* Start the initial bet */
	    do_bet( ch, "10" );
	}
	else if ( number_range(1,10) <= Combination+1 )
	{
	    char buf[MAX_INPUT_LENGTH];
	    int Bet = ch->deck->Bet * number_range(2,3);
		    
	    /* Make sure they have enough gold to make the bet */
	    if ( ch->gold < Bet )
		ch->gold = Bet;

	    /* Place the bet */
	    sprintf( buf, "%d", Bet );
	    do_bet( ch, buf );
	}
	else /* Just make them match it */
	{
	    /* Make sure they have enough gold to match any bets */
	    if ( ch->gold < ch->deck->Bet )
		ch->gold = ch->deck->Bet;

	    /* Match the bet */
	    do_bet( ch, "call" );
	}
    }

    return TRUE;
}



bool spec_blackjack_player( CHAR_DATA *ch )
{
    if ( ch->position != POS_STANDING )
	return FALSE;

    if ( ch->deck == NULL )
    {
	/* Start a game of blackacjk */
	do_start( ch, "Blackjack" );
    }
    else if ( ch->deck->Bet == 0 )
    {
	/* Make sure they have enough gold for the initial bet */
	if ( ch->gold < 10 )
	    ch->gold = 10;

	/* Start the initial bet */
	do_bet( ch, "10" );
    }
    else if ( ch->deck->Instances == 1 )
    {
	/* They've not started the game yet */
	do_say( ch, "Who wants to play Blackjack?  Use the 'play' command." );
    }
    else if ( ch->deck->Playing == eFalse )
    {
	do_say( ch, "Let's play!" );
	do_deal( ch, "" );
    }
    else if ( ch->play_turn == TRUE )
    {
	/* The game is underway! */
	if ( ch->deck->Turn == 1 )
	{
	    /* Make sure they have enough gold, or the AI will get stuck */
	    if ( ch->gold < ch->deck->Bet )
		ch->gold = ch->deck->Bet;
	    do_bet( ch, "call" );
	}
	else /* It's turn 2 */
	{
	    char *pActions = GameAdvice(ch->deck->Game, ch->hand);
	    if ( !str_cmp( pActions, "draw") )
		do_draw( ch, "" );
	    else /* The only other option is to stick */
		do_stick( ch, "" );
	}
    }

    return TRUE;
}

******************************************************************************
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 double draw fold play shuffle start stick
~

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 double draw fold play shuffle start stick
~

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 double draw fold hand play shuffle start stick
~

0 DOUBLE~
Syntax: double

This command causes you to double your bet, draw a card, and end your turn.

See also: bet deal discard draw fold hand play shuffle start stick
~

0 STICK~
Syntax: stick

This command causes you to stick with your current hand.

See also: bet deal discard double draw fold hand play shuffle start
~

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 double fold hand play shuffle start stick
~

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 double draw hand play shuffle start stick
~

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 double draw fold play shuffle start stick
~

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 double draw fold hand shuffle start stick
~

0 SHUFFLE~
Syntax: shuffle

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

See also: bet deal discard double draw fold hand play start stick
~

0 START~
Syntax: start

This command allows you to start a new game of cards.  Type 'start' on its 
own to bring up a list of the available games.

See also: bet deal discard double draw fold hand play shuffle stick
~

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

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

#include "game.h"
#include "deck.h"
#include "hand.h"
#include "score.h"
#include "merc.h"

void ShowValidCommands( CHAR_DATA *ch )
{
    static char buf[MAX_STRING_LENGTH];
    static char commands[MAX_STRING_LENGTH];
    commands[0] = '\0';

    if ( ch->deck != NULL && ch->hand != NULL )
    {
	if ( GameViewHand(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " hand" );
	if ( GameCanBet(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " bet" );
	if ( GameCanFold(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " fold" );
	if ( GameCanDiscard(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " discard" );
	if ( GameCanDraw(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " draw" );
	if ( GameCanStick(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " stick" );
	if ( GameCanDouble(ch->deck->Game, ch->deck->Turn) )
	   strcat( commands, " double" );
    }

    if ( commands[0] == '\0' )
	strcpy( commands, " none" );

    sprintf( buf, "Card commands for turn %d:", ch->deck->Turn );
    strcat( buf, commands );
    strcat( buf, "\n\r" );
    send_to_char( buf, ch );
}

void FlushPlayers( CHAR_DATA *ch )
{
    if ( ch->deck != NULL && ch->hand != NULL )
    {
	CHAR_DATA *current, *next = NULL;

	for ( current = ch; current != NULL; current = next )
	{
	    CHAR_DATA *prev = current->prev_card_player;
	    next = current->next_card_player;

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

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

void RevealScore( CHAR_DATA *ch )
{
    if ( ch->deck != NULL && ch->hand != NULL )
    {
        char buf[MAX_STRING_LENGTH];

	CHAR_DATA *current, *winner = ch;
	combination_t HighCombination = eCombinationHighCard;
        int TopScore = -1;
        int WinnerCount = 0;
        char HighScore[16] = {'\0'};
	int gold = ch->deck->Pot;

	for ( current = ch; current != NULL; current = current->next_card_player )
	{
	    /* Calculate score */
	    sprintf( buf, "You reveal your hand: %s\n\r", 
		HandShow(current->hand, eFalse) );
	    send_to_char( buf, current );
	    sprintf( buf, "$n reveals $s hand: %s", 
		HandShow(current->hand, eFalse) );
	    act( buf, current, NULL, NULL, TO_ROOM );

	    if ( GameScoring(ch->deck->Game) == eScorePoker )
	    {
		combination_t Combination = eCombinationMax;

		strncpy( buf, ScorePoker(current->hand, &Combination), 15 );

		if ( Combination > HighCombination )
		{
		    /* We've a new high score */
		    HighCombination = Combination;
		    strcpy( HighScore, buf );
		    winner = current;
		}
		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 = current;
			}
		    }
		}
	    }
	    else if ( GameScoring(ch->deck->Game) == eScoreBlackjack )
	    {
		int Score = ScoreBlackjack(current->hand);

		if ( Score > TopScore )
		{
		    /* We've a new high score */
		    TopScore = Score;
		    winner = current;
		    WinnerCount = 1;
		}
		else if ( Score == TopScore )
		{
		    /* We've more than one winner */
		    WinnerCount++;
		}
	    }
	    else /* Add support for your other scoring systems here */
	    {
		bug( "RevealScore: Function called with unsupported scoring system.\n", 0 );
	    }
	}

	if ( GameSoloBet(ch->deck->Game) )
	{
	    /* Find the dealer */
	    CHAR_DATA *dealer = NULL;
	    for ( current = ch; current != NULL; current = current->next_card_player )
	    {
		if ( current->hand->bDealer )
		    dealer = current;
	    }

	    if ( dealer != NULL )
	    {
		int DealerScore = ScoreBlackjack(dealer->hand);
		for ( current = ch; current != NULL; current = current->next_card_player )
		{
		    if ( current != dealer )
		    {
			int Score = ScoreBlackjack(current->hand);
			if ( Score == 21 && current->hand->Size == 2 )
			{
			    int Winnings = (current->hand->Bet*5)/2; /* 3:2 payout */

			    sprintf( buf, "\n\rBlackjack!  You collect %d gold.\n\r", Winnings );
			    send_to_char( buf, current );
			    sprintf( buf, "\n\rBLACKJACK!  $n collects %d gold.", Winnings );
			    act( buf, current, NULL, NULL, TO_ROOM );

			    /* You get twice your bet back */
			    current->gold += Winnings;
			    current->deck->Pot -= Winnings;
			}
			else if ( Score > 0 && (Score > DealerScore || Score == 21) )
			{
			    int Winnings = current->hand->Bet*2; /* 1:1 payout */

			    sprintf( buf, "\n\rYou win!  You collect %d gold.\n\r", Winnings );
			    send_to_char( buf, current );
			    sprintf( buf, "\n\rWINNER!  $n collects %d gold.", Winnings );
			    act( buf, current, NULL, NULL, TO_ROOM );

			    /* You get twice your bet back */
			    current->gold += Winnings;
			    current->deck->Pot -= Winnings;
			}
			else if ( Score == DealerScore )
			{
			    sprintf( buf, "\n\rYou match the house.  You recover your %d gold bet.\n\r", current->hand->Bet );
			    send_to_char( buf, current );
			    sprintf( buf, "\n\r$n matches the house, and recovers $s %d gold bet.", current->hand->Bet );
			    act( buf, current, NULL, NULL, TO_ROOM );

			    /* You get twice your bet back */
			    current->gold += current->hand->Bet;
			    current->deck->Pot -= current->hand->Bet;
			}
			else /* The player loses */
			{
			    send_to_char( "\n\rYou lose to the house.\n\r", current );
			}
		    }
		}

		/* The dealer empties the pot */
		if ( dealer->deck->Pot > 0 )
		{
		    dealer->gold += dealer->deck->Pot;

		    sprintf( buf, "\n\rYou empty the remaining %d gold from the pot.\n\r", dealer->deck->Pot );
		    send_to_char( buf, dealer );
		    sprintf( buf, "\n\r$n collects the remaining %d gold from the pot.\n\r", dealer->deck->Pot );
		    act( buf, dealer, NULL, NULL, TO_ROOM );
		}
		else if ( dealer->deck->Pot < 0 )
		{
		    dealer->deck->Pot = abs(dealer->deck->Pot);
		    dealer->gold -= dealer->deck->Pot;

		    sprintf( buf, "\n\rYou had to add an extra %d gold to the pot.\n\r", dealer->deck->Pot );
		    send_to_char( buf, dealer );
		}
	    }
	}
	else if ( WinnerCount > 1 )
	{
	    for ( current = ch; current != NULL; current = current->next_card_player )
	    {
		int Score = ScoreBlackjack(current->hand);
		if ( Score > 0 && Score == TopScore )
		{
		    sprintf( buf, "\n\rYou're one of %d winners!  You collect %d gold from the pot.\n\r", WinnerCount, gold/WinnerCount );
		    send_to_char( buf, current );
		    sprintf( buf, "\n\rJOINT WIN!  $n collects %d gold from the pot.\n\r", gold/WinnerCount );
		    act( buf, current, NULL, NULL, TO_ROOM );
		    winner->gold += (gold/WinnerCount);
		}
	    }
	}
	else /* There was a clear winner */
	{
	    sprintf( buf, "\n\rYou win!  You collect %d gold from the pot.\n\r", gold );
	    send_to_char( buf, winner );

	    sprintf( buf, "\n\rWINNER!  $n collects %d gold from the pot.\n\r", gold );
	    act( buf, winner, NULL, NULL, TO_ROOM );
	    winner->gold += gold;
	}

	/* Flush the players out of the game */
	FlushPlayers(ch);
    }
}

void ShareCard( CHAR_DATA *ch, card_t card, boolean_t show )
{
    if ( ch->deck != NULL && ch->hand != NULL )
    {
        CHAR_DATA *next;
        for ( next = ch; next != NULL; next = next->next_card_player )
        {
	    /* Give each player a copy of the card */
            (void)HandAddCard(next->hand, card);

	    /* Show the player their new hand, if required */
	    if ( show )
	    {
		char buf[MAX_STRING_LENGTH];

		sprintf( buf, "Including shared cards, you now have the following hand: %s\n\r\n\r", 
		    HandShow(next->hand, eFalse) );
		send_to_char( buf, next );
		send_to_char( HandShow(next->hand, eTrue), next );
	    }
	}
    }
}

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

	if ( GameSoloBet(ch->deck->Game) )
	{
	    sprintf( buf, "It's now your turn (current bet: %dgp).\n\r\n\r", 
		ch->hand->Bet );
	}
	else /* Its a shared bet */
	{
	    sprintf( buf, "It's now your turn (pot: %dgp, current bet: %dgp).\n\r\n\r", 
		ch->deck->Pot, ch->deck->Bet );
	}

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

	    next->play_turn = TRUE;

	    /* If there are two players and one just lost, the other wins */
	    if ( bCheckWin && next->deck->Instances == 2 )
	    {
		/* Reveal the scores */
		RevealScore( next );
	    }
	    else /* There are still other players */
	    {
		send_to_char( buf, next );
		ShowValidCommands( 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->prev_card_player;
	    if ( prev == NULL )
	    {
		/* There's only one player, so make them win */
		ch->play_turn = TRUE;
		ch->deck->Turn = GameLastTurn(ch->deck->Game);
		RevealScore( ch );
	    }
	    else /* Keep going back until we reach the start */
	    {
		while ( prev->prev_card_player != NULL )
		    prev = prev->prev_card_player;

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

		/* If there are two players and one just lost, the other wins */
		if ( bCheckWin && prev->deck->Instances == 2 )
		{
		    /* Reveal the scores */
		    RevealScore( prev );
		}
		else if ( ++prev->deck->Turn > GameLastTurn(prev->deck->Game) )
		{
		    /* Reveal the scores */
		    RevealScore( prev );
		}
		else /* The game is not yet finished */
		{
		    int BurnedCards = GameBurnCards(prev->deck->Game, 
			prev->deck->Turn);
		    int SharedCards = GameSharedDraw(prev->deck->Game, 
			prev->deck->Turn);

		    send_to_char( buf, prev );
		    ShowValidCommands( prev );
		    act( "It is now $n's turn.", prev, NULL, NULL, TO_ROOM );

		    /* Any card burning should be done now */
		    if ( BurnedCards > 0 )
		    {
			sprintf( buf, "You burn %d card%s from the top of the deck.\n\r", 
			    BurnedCards, BurnedCards == 1 ? "" : "s" );
			send_to_char( buf, prev );
			sprintf( buf, "$n burns %d card%s from the top of the deck.", 
			    BurnedCards, BurnedCards == 1 ? "" : "s" );
			act( buf, prev, NULL, NULL, TO_ROOM );

			for ( ; BurnedCards > 0; --BurnedCards )
			{
			    /* Draw a card and cast it into the void */
			    (void)DeckDrawCard(prev->deck);
			}
		    }

		    /* If there are any shared cards to be placed, do so now */
		    if ( SharedCards > 0 )
		    {
			sprintf( buf, "You draw %d new card%s from the deck and place %s face-up on the table.\n\r", 
			    SharedCards, SharedCards == 1 ? "" : "s", SharedCards == 1 ? "it" : "them" );
			send_to_char( buf, prev );
			sprintf( buf, "$n draws %d new card%s from the deck and places %s face-up on the table.", 
			    SharedCards, SharedCards == 1 ? "" : "s", SharedCards == 1 ? "it" : "them" );
			act( buf, prev, NULL, NULL, TO_ROOM );

			for ( ; SharedCards > 0; --SharedCards )
			{
			    /* Draw a card and give each player a copy */
			    card_t card = DeckDrawCard(prev->deck);
			    ShareCard( prev, card, SharedCards == 1 );
			}
		    }
		}
	    }
	}
    }
}

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

    if ( ch->deck == NULL || ch->hand == NULL )
    {
	send_to_char( "You need to start a game before you can bet.\n\r", ch );
    }
    else if ( ch->deck->Turn > GameLastTurn(ch->deck->Game) )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( !GameCanBet(ch->deck->Game, 0) )
    {
	sprintf( buf, "You cannot place bets in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( !GameCanBet(ch->deck->Game, ch->deck->Turn) )
    {
	sprintf( buf, "You cannot place bets in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( ch->deck->Turn > 0 && ch->deck->Playing == eFalse )
    {
	send_to_char( "You cannot bet until the first hand has been dealt.\n\r", ch );
    }
    else if ( ch->play_turn == FALSE )
    {
	send_to_char( "You can only bet on your turn.\n\r", ch );
    }
    else if ( argument[0] == '\0' )
    {
	if ( ch->deck->Turn == 0 )
	{
	    send_to_char( "How much do you want to set the minimum bet to?\n\r", ch );
	}
	else if ( GameSoloBet(ch->deck->Game) )
	{
	    sprintf( buf, "How much do you wish to bet?  Your current bet is %d gold.\n\r", 
		ch->hand->Bet );
	    send_to_char( buf, ch );
	}
	else /* Its a shared bet */
	{
	    sprintf( buf, "How much do you wish to bet?  The current bet is %d gold.\n\r", 
		ch->deck->Bet );
	    send_to_char( buf, ch );
	}
    }
    else if ( !strcmp( argument, "call" ) )
    {
	if ( ch->deck->Turn == 0 )
	{
	    send_to_char( "You cannot 'bet call' for the minimum bet.\n\r", ch );
	}
	else if ( ch->gold < ch->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->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->hand->Bet = ch->deck->Bet;
		ch->deck->Pot += ch->deck->Bet;
		ch->gold -= ch->deck->Bet;

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

	    /* Turn over - next player */
	    NextPlayer(ch, FALSE);
	}
    }
    else if ( !is_number(argument) )
    {
	if ( GameSoloBet(ch->deck->Game) )
	{
	    sprintf( buf, "Please specify a number of gold pieces to bet.  The current bet is %d gold.\n\r", 
		ch->deck->Bet );
	    send_to_char( buf, ch );
	}
	else /* Its a shared bet */
	{
	    sprintf( buf, "Please specify a number of gold pieces to bet.  Your current bet is %d gold.\n\r", 
		ch->hand->Bet );
	    send_to_char( buf, ch );
	}
    }
    else if ( ch->deck->Turn == 0 )
    {
	int gold = atoi(argument);
	if ( ch->deck->Bet > 0 )
	{
	    sprintf( buf, "You've already set a minimum bet of %d gold.  You should now 'deal'.\n\r", 
		ch->deck->Bet );
	    send_to_char( buf, ch );
	}
	else if ( gold <= 0 )
	{
	    send_to_char( "You must set a minimum bet of at least 1 gold.\n\r", 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 */
	{
	    /* Set the bet - but don't remove gold at this point */
	    ch->hand->Bet = gold;
	    ch->deck->Bet = gold;

	    if ( GameMinimumBet(ch->deck->Game) ) 
	    {
		sprintf( buf, "Minimum bet is set to %d gold.  Type 'deal' to start the game.\n\r", gold );
		send_to_char( buf, ch );
		sprintf( buf, "$n begins a game of %s with a minimum bet of %d gold.  Type 'play' to join.", GameName(ch->deck->Game), gold );
		act( buf, ch, NULL, NULL, TO_ROOM );
	    }
	    else /* A minimum bet wasn't required */
	    {
		sprintf( buf, "You set the minimum bet to %d gold.  You should now 'deal'.\n\r", ch->deck->Bet );
		send_to_char( buf, ch );
		sprintf( buf, "$n sets the minimum bet to %d gold.", ch->deck->Bet );
		act( buf, ch, NULL, NULL, TO_ROOM );
	    }
	}
    }
    else if ( GameSoloBet(ch->deck->Game) ) 
    {
	int gold = atoi(argument);
	if ( gold < ch->deck->Bet )
	{
	    sprintf( buf, "You must at least match the minimum bet of %d gold.\n\r", 
		ch->deck->Bet );
	    send_to_char( buf, ch );
	}
	else if ( gold <= ch->hand->Bet )
	{
	    sprintf( buf, "You must exceed your current bet of %d gold.\n\r", 
		ch->hand->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 */
	{
	    /* Remove their old bet, so that it can be replaced */
	    ch->deck->Pot -= ch->hand->Bet;
	    ch->gold += ch->hand->Bet;

	    /* Apply the new bet, update the pot, and the characters gold */
	    ch->hand->Bet = gold;
	    ch->deck->Bet = gold;
	    ch->deck->Pot += gold;
	    ch->gold -= gold;

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

	    /* Turn over - next player */
	    NextPlayer(ch, FALSE);
	}
    }
    else /* We've got a numeric value of gold */
    {
	int gold = atoi(argument);
	if ( gold <= ch->deck->Bet )
	{
	    sprintf( buf, "You must exceed the current bet of %d gold, or 'bet call' to match it.\n\r", 
		ch->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 */
	{
	    /* Remove their old bet, so that it can be replaced */
	    ch->deck->Pot -= ch->hand->Bet;
	    ch->gold += ch->hand->Bet;

	    /* Update the bet, the pot, and the characters gold */
	    ch->hand->Bet = gold;
	    ch->deck->Bet = gold;
	    ch->deck->Pot += gold;
	    ch->gold -= gold;

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

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

void do_deal( CHAR_DATA *ch, char *argument )
{
    if ( ch->deck == NULL || ch->hand == NULL )
    {
	send_to_char( "You need to start a game before you can deal.\n\r", ch );
    }
    else if ( ch->deck->Playing == eTrue )
    {
	send_to_char( "You can only deal at the start of a game.\n\r", ch );
    }
    else if ( ch->play_turn == FALSE )
    {
	send_to_char( "You're not the dealer.\n\r", ch );
    }
    else if ( GameMinimumBet(ch->deck->Game) && ch->deck->Bet <= 0 ) 
    {
	send_to_char( "You must first set the minimum bet (eg 'bet 10').\n\r", ch );
    }
    else if ( ch->deck->Instances < 2 )
    {
	send_to_char( "You need at least 2 players for a game of cards.\n\r", ch );
    }
    else /* Go ahead and deal the cards */
    {
	int Deal = GameInitialDraw(ch->deck->Game);

	/* Indicate that the game has begun */
	ch->deck->Playing = eTrue;

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

		if ( HandCountCards(prev->hand) == Deal )
		{
		    char buf[MAX_STRING_LENGTH];

		    /* Check explicitly for turn 1 (we're in turn 0) */
		    if ( GameViewHand(ch->deck->Game, 1) )
		    {
			if ( ch == prev )
			{
			    sprintf( buf, "You deal yourself %d cards: %s\n\r\n\r", 
				Deal, HandShow(prev->hand, eFalse) );
			    send_to_char( buf, ch );
			}
			else /* Dealt to someone else */
			{
			    sprintf( buf, "$n deals you %d cards: %s\n\r", 
				Deal, HandShow(prev->hand, eFalse) );
			    act( buf, ch, NULL, prev, TO_VICT );
			}
			send_to_char( HandShow(prev->hand, eTrue), prev );
		    }
		    else /* We're not allowed to show them the cards */
		    {
			if ( ch == prev )
			{
			    sprintf( buf, "You deal yourself %d cards face-down on the table.\n\r", Deal );
			    send_to_char( buf, ch );

			    if ( ch->deck->Game == eGameBlackjack )
			    {
				sprintf( buf, "You flip one of the cards over to reveal the %s.\n\r", CardName(card) );
				send_to_char( buf, ch );
				sprintf( buf, "$n deals $mself %d cards, one of which he reveals as the %s.", 
				    Deal, CardName(card) );
				act( buf, ch, NULL, NULL, TO_ROOM );
			    }
			}
			else /* Dealt to someone else */
			{
			    sprintf( buf, "$n deals you %d cards face-down on the table.", Deal );
			    act( buf, ch, NULL, prev, TO_VICT );
			}
		    }
		}
	    }
	}

	/* Now we begin turn 1 */
	NextPlayer(ch, FALSE);
    }
}

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

    if ( ch->deck == NULL || ch->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->deck->Turn > GameLastTurn(ch->deck->Game) )
    {
	send_to_char( "The game is already over.\n\r", ch );
	return;
    }

    if ( !GameCanDiscard(ch->deck->Game, 0) )
    {
	sprintf( buf, "You cannot discard cards in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
	return;
    }

    /* You can only discard on your turn */
    if ( ch->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->deck->Playing == eFalse )
    {
	send_to_char( "You cannot discard any cards until the dealer has dealt the first hand.\n\r", ch );
	return;
    }

    if ( !GameCanDiscard(ch->deck->Game, ch->deck->Turn) )
    {
	sprintf( buf, "You cannot discard cards in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
	return;
    }

    /* Can you discard that many cards? */
    if ( HandCountCards(ch->hand) <= GameInitialDraw(ch->deck->Game) - 
	GameCanDiscard(ch->deck->Game, ch->deck->Turn) )
    {
	sprintf( buf, "You may only discard up to %d cards in turn %d of %s.\n\r", 
	    GameCanDiscard(ch->deck->Game, ch->deck->Turn), ch->deck->Turn, 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	return;
    }

    if ( argument[0] == '\0' || strlen(argument) != 2 )
    {
	send_to_char( "Please specify which card 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 )
    {
	/* Swap them around, in case the player did them the wrong way */
	suit = CardSuit( UPPER(argument[1]) );
	rank = CardRank( UPPER(argument[0]) );

	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->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->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 )
{
    char buf[MAX_STRING_LENGTH];

    if ( ch->deck == NULL || ch->hand == NULL )
    {
	send_to_char( "You need to start playing before you can draw a card.\n\r", ch );
    }
    else if ( ch->deck->Turn > GameLastTurn(ch->deck->Game) )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( !GameCanDraw(ch->deck->Game, 0) )
    {
	sprintf( buf, "You cannot draw cards in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( !GameCanDraw(ch->deck->Game, ch->deck->Turn) )
    {
	sprintf( buf, "You cannot draw cards in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( ch->play_turn == FALSE )
    {
	send_to_char( "You can only draw a card on your own turn.\n\r", ch );
    }
    else if ( ch->deck->Playing == eFalse )
    {
	send_to_char( "You cannot draw any cards until the dealer has dealt the first hand.\n\r", ch );
    }
    else if ( GameCanDraw(ch->deck->Game, ch->deck->Turn) == 1 )
    {
	/* Draw a card from the deck and put it in their hand */
	card_t card = DeckDrawCard(ch->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 );
	}
	else if ( HandAddCard(ch->hand, card) == eFalse )
	{
	    bug( "do_draw: Duplicate card found in hand.", 0 );
	    send_to_char( "You were unable to draw the card.\n\r", ch );
	}
	else /* They drew the card fine */
	{
	    int Score = ScoreBlackjack(ch->hand);
	    if ( Score > 0 && Score <= 21 )
	    {
		sprintf( buf, "You draw the %s from the deck.\n\r", CardName(card) );
		send_to_char( buf, ch );
		sprintf( buf, "$n draws a new card from the deck." );
		act( buf, ch, NULL, NULL, TO_ROOM );
	    }
	    else /* They've bone bust */
	    {
		CHAR_DATA *prev = ch->prev_card_player;
		CHAR_DATA *next = ch->next_card_player;

		sprintf( buf, "You draw the %s from the deck, going bust!\n\r", CardName(card) );
		send_to_char( buf, ch );
		sprintf( buf, "$n draws a new card from the deck, and goes bust!" );
		act( buf, ch, NULL, NULL, TO_ROOM );

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

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

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

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

		    ch->deck = NULL;
		}
	    }
	}
    }
    else if ( HandCountCards(ch->hand) == GameFullHand(ch->deck->Game) )
    {
	sprintf( buf, "You've already got a full hand of %d cards.\n\r", 
	    GameFullHand(ch->deck->Game) );
	send_to_char( buf, ch );
    }
    else /* They're playing, so draw a card */
    {
	int CardsDrawn = 0;
	int FullHand = GameFullHand(ch->deck->Game);

        while ( HandCountCards(ch->hand) < FullHand )
	{
	    /* Draw a card from the deck and put it in their hand */
	    card_t card = DeckDrawCard(ch->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->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, FALSE);
    }
}

void do_fold( CHAR_DATA *ch, char *argument )
{
    if ( ch->deck == NULL || ch->hand == NULL )
    {
	send_to_char( "You need to be playing before you can fold.\n\r", ch );
    }
    else if ( !GameCanFold(ch->deck->Game, 0) )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "You cannot fold in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( !GameCanFold(ch->deck->Game, ch->deck->Turn) )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "You cannot fold in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( ch->play_turn == FALSE )
    {
	send_to_char( "You can only fold on your own turn.\n\r", ch );
    }
    else if ( ch->deck->Playing == eFalse )
    {
	send_to_char( "You cannot fold until the first hand has been dealt.\n\r", ch );
    }
    else /* Show the hand (if any) and then discard it */
    {
	CHAR_DATA *prev = ch->prev_card_player;
	CHAR_DATA *next = ch->next_card_player;

	if ( HandCountCards(ch->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->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 && HandRemoveCard(ch->hand, card) )
                {
		    /* Make sure the card isn't already in the deck */
		    if ( DeckReturnCard(ch->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, TRUE);

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

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

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

	    ch->deck = NULL;
	}
    }
}

void do_hand( CHAR_DATA *ch, char *argument )
{
    if ( ch->deck == NULL || ch->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->hand) == 0 )
    {
	send_to_char( "Your hand is currently empty - you need to draw a card.\n\r", ch );
    }
    else if ( !GameViewHand(ch->deck->Game, 0) )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "You cannot view your hand in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( !GameViewHand(ch->deck->Game, ch->deck->Turn) )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "You cannot view your hand in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( 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->hand, eFalse) );
	send_to_char( buf, ch );

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

	send_to_char( "\n\r", ch );
	ShowValidCommands( ch );
    }
}

void do_stick( CHAR_DATA *ch, char *argument )
{
    if ( ch->deck == NULL || ch->hand == NULL )
    {
	send_to_char( "You need to start a game before you can stick with your hand.\n\r", ch );
    }
    else if ( ch->deck->Turn > GameLastTurn(ch->deck->Game) )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( !GameCanStick(ch->deck->Game, 0) )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "You cannot stick in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( !GameCanStick(ch->deck->Game, ch->deck->Turn) )
    {
	char buf[MAX_STRING_LENGTH];
	sprintf( buf, "You cannot stick in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( ch->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 to stick with your current hand.\n\r", ch );
	act( "$n chooses to stick with $s current hand.", ch, NULL, NULL, TO_ROOM );

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

void do_start( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    game_t Game = eGameNone;

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

    if ( argument[0] != '0' && is_number(argument) )
	Game = atoi(argument)-1;
    else /* They specified a string, not a number, so look it up */
	Game = GameIndex(argument);

    if ( Game <= eGameNone || Game >= eGameMax )
    {
        int i; /* Loop counter */

	send_to_char( "Please specify the game to play from the following:\n\r", ch );

	for ( i = eGameNone+1; i < eGameMax; ++i )
	{
	    sprintf( buf, "%d) %s\n\r", i+1, GameName(i) );
	    send_to_char( buf, ch );
	}

	return;
    }
    else if ( GameMinimumBet(Game) ) 
    {
	sprintf( buf, "You begin a game of %s.  You must now set a minimum bet (eg 'bet 10').\n\r", 
	    GameName(Game) );
	send_to_char( buf, ch );
    }
    else /* It's a valid game */
    {
	sprintf( buf, "You begin a game of %s (type 'deal' when ready).\n\r", 
	    GameName(Game) );
	send_to_char( buf, ch );
	sprintf( buf, "$n begins a game of %s (use the 'play' command to join).", 
	    GameName(Game) );
	act( buf, ch, NULL, NULL, TO_ROOM );
    }

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

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

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

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

    /* Shouldn't be necessary, but better safe than sorry */
    ch->next_card_player = NULL;
    ch->prev_card_player = NULL;
}

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 the character is not already playing a game */
    if ( ch->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->deck != NULL )
    {
        int MaxPlayers = GameMaxPlayers(victim->deck->Game);

	if ( victim->deck->Instances >= MaxPlayers )
	{
	    char buf[MAX_STRING_LENGTH];
	    sprintf( buf, "That game is already full (it has %d player%s).\n\r", 
		victim->deck->Instances, 
		victim->deck->Instances == 1 ? "" : "s" );
	    send_to_char( buf, ch );
	    return;
	}
	else if ( victim->deck->Playing == eTrue )
	{
	    send_to_char( "You cannot join a game which is already under way.\n\r", ch );
	    return;
	}
	else if ( GameMinimumBet(victim->deck->Game) && victim->deck->Bet <= 0 ) 
	{
	    send_to_char( "You must first wait until the minimum bet has been set.\n\r", ch );
	    return;
	}
    }
    else /* victim->deck == NULL */
    {
	act( "$N is not currently playing any card game.", ch, NULL, victim, TO_CHAR );
	return;
    }

    if ( ch == victim )
    {
	send_to_char( "Use the 'start' game to begin a new card game.\n\r", ch );
    }
    else /* The other person is already playing, so join their game */
    {
	/* Set ch to use the same deck as victim */
	ch->deck = victim->deck;
	ch->deck->Instances++;

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

	/* Store the minimum bet, if any */
	ch->hand->Bet = ch->deck->Bet;

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

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

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

	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->deck == NULL )
    {
	send_to_char( "You need to start playing before you can shuffle the deck.\n\r", ch );
    }
    else if ( DeckCountCards(ch->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->deck);

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

void do_double( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];

    if ( ch->deck == NULL || ch->hand == NULL )
    {
	send_to_char( "You need to start a game before you can double down.\n\r", ch );
    }
    else if ( ch->deck->Turn > GameLastTurn(ch->deck->Game) )
    {
	send_to_char( "The game is already over.\n\r", ch );
    }
    else if ( !GameCanDouble(ch->deck->Game, 0) )
    {
	sprintf( buf, "You cannot double down in %s.\n\r", 
	    GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( !GameCanDouble(ch->deck->Game, ch->deck->Turn) )
    {
	sprintf( buf, "You cannot double down in turn %d of %s.\n\r", 
	    ch->deck->Turn, GameName(ch->deck->Game) );
	send_to_char( buf, ch );
	ShowValidCommands( ch );
    }
    else if ( ch->deck->Turn > 0 && ch->deck->Playing == eFalse )
    {
	send_to_char( "You cannot double down until the first hand has been dealt.\n\r", ch );
    }
    else if ( ch->play_turn == FALSE )
    {
	send_to_char( "You can only double down on your turn.\n\r", ch );
    }
    else /* Double their current bet and draw a card */
    {
	if ( ch->gold < ch->hand->Bet*2 )
	{
	    send_to_char( "You don't have enough gold to double down.\n\r", ch );
	}
	else /* It's a valid bet */
	{
	    /* Draw a card from the deck and put it in their hand */
	    card_t card = DeckDrawCard(ch->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 );
	    }
	    else if ( HandAddCard(ch->hand, card) == eFalse )
	    {
		bug( "do_draw: Duplicate card found in hand.", 0 );
		send_to_char( "You were unable to draw the card.\n\r", ch );
	    }
	    else /* They drew the card fine */
	    {
		/* Apply the new bet, pot and gold */
		ch->gold -= ch->hand->Bet;
		ch->deck->Pot += ch->hand->Bet;
		ch->hand->Bet *= 2;
		ch->deck->Bet = ch->hand->Bet;

		int Score = ScoreBlackjack(ch->hand);
		if ( Score > 0 && Score <= 21 )
		{
		    sprintf( buf, "Your double your bet to %d gold and draw the %s.\n\r", 
			ch->hand->Bet, CardName(card) );
		    send_to_char( buf, ch );
		    sprintf( buf, "$n doubles $s bet to %d gold and draws a card.", ch->hand->Bet );
		    act( buf, ch, NULL, NULL, TO_ROOM );

		    /* Turn over - next player */
		    NextPlayer(ch, FALSE);
		}
		else /* They've bone bust */
		{
		    CHAR_DATA *prev = ch->prev_card_player;
		    CHAR_DATA *next = ch->next_card_player;

		    sprintf( buf, "Your double your bet to %d gold and draw the %s, going bust!\n\r", 
			ch->hand->Bet, CardName(card) );
		    send_to_char( buf, ch );
		    sprintf( buf, "$n doubles $s bet to %d gold, draws a card, and goes bust!", ch->hand->Bet );
		    act( buf, ch, NULL, NULL, TO_ROOM );

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

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

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

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

			ch->deck = NULL;
		    }
		}
	    }
	}
    }
}


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