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