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/
#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 );
    }
}