/**************************************************************************** * ResortMUD Version 5.0 was mainly programmed by Ntanel, Garinan, Josh, * * Badastaz, Digifuzz, Senir, Kratas, Scion, Shogar and Tagith. * * ------------------------------------------------------------------------ * * Copyright (C) 1996 - 2001 Haslage Net Electronics: MudWorld of Lorain, * * Ohio. ALL RIGHTS RESERVED See /doc/RMLicense.txt for more details. * ****************************************************************************/ /* * Roulette code * Author: Cronel (cronel_kal@hotmail.com) * of FrozenMUD (empire.digiunix.net 4000) * * Permission to use and distribute this code is granted provided * this header is retained and unaltered, and the distribution * package contains all the original files unmodified. * If you modify this code and use/distribute modified versions * you must give credit to the original author(s). * * Written in 29/1/98. */ #include "mud.h" /* * DATA DEFINITIONS */ typedef enum { ROULETTE_IDLE, /* Roulette is idle. No bets recieved. */ ROULETTE_BETTING, /* Someone has bet.. */ ROULETTE_END_BETTING, /* Players have time till next update to bet. In next update the ball will be rolled */ ROULETTE_ROLLING /* Ball is rolling. In next update, the rolling will be over and bets will be resolved; roulette will go back to idle */ } roulete_states; /* bet types */ typedef enum { BET_NONE, /* from 1 to 36 the bet_type is the number.. */ BET_RED = 37, BET_BLACK, BET_ODD, BET_EVEN, BET_1STCOL, BET_2NDCOL, BET_3RDCOL, BET_1STDOZEN, BET_2NDDOZEN, BET_3RDDOZEN } BET_TYPE; /* keywords for betting in each of the non-numeric types */ char * const bet_names[] = { "red", "black", "odd", "even", "col1", "col2", "col3", "doz1", "doz2", "doz3", NULL /* null acts as array terminator, dont remove */ }; /* descriptive names for non numeric bet types */ char * const desc_bet_names[] = { "red", "black", "odds", "evens", "first column", "second column", "third column", "first dozen", "second dozen", "third dozen" }; typedef struct bet_data BET_DATA; struct bet_data { BET_DATA * next_bet; BET_DATA * prev_bet; char * player_name; /* Name of the gambler */ int amount; /* Amount of money in the bet */ short bet_type; /* On what did they bet? */ }; /* * MODULE DATA */ short roulette_state = ROULETTE_IDLE; BET_DATA * first_bet = NULL; BET_DATA * last_bet = NULL; char * roulette_extra_descr; extern short top_ed ; /* from db.c */ /* * LOCAL FUNCTIONS */ OBJ_DATA *get_roulette_obj(); CHAR_DATA *get_croupier( ROOM_INDEX_DATA *room ); EXTRA_DESCR_DATA *get_roulette_extra( OBJ_DATA * roulette ); EXTRA_DESCR_DATA *get_extra_from_list( EXTRA_DESCR_DATA *extra_list, char *name ); void clean_bets(); void resolve_bets(CHAR_DATA *croupier, int number ); bool has_won( short type, short number ); int calc_gain( short type, int amount ); char *get_bet_name( short type ); short get_bet_type( char *str ); int advatoi ( char *s ); /* from bet.h (included in act_obj.c). used in auctions. god knows why it's in an *.h .. */ void do_bet( CHAR_DATA *ch, char *argument ) { char arg1[ MAX_INPUT_LENGTH ]; char arg2[ MAX_INPUT_LENGTH ]; char buf[ MAX_STRING_LENGTH ]; int amount; BET_TYPE bet_type; OBJ_DATA *roulette; ROOM_INDEX_DATA *room; CHAR_DATA *croupier; BET_DATA *bet; EXTRA_DESCR_DATA *extra; if( (roulette = get_roulette_obj()) == NULL || (room = roulette->in_room) == NULL || (croupier = get_croupier(room)) == NULL ) { send_to_char("Sorry but the roulette hasn't been set up properly yet.\r\n", ch ); return; } if( !str_cmp( argument, "stop") && IS_IMMORTAL(ch) ) { if( roulette_state != ROULETTE_IDLE ) { act( AT_SAY, "$n says '$N wants us to finish this right now, so...", croupier, NULL, ch, TO_ROOM ); roulette_state = ROULETTE_ROLLING; bet_update(); send_to_char( "Ok. The roulette round is now over", ch ); } else send_to_char( "The roulette is idle right now. No need to do that.\r\n", ch ); return; } if( ch->in_room != room ) { send_to_char("You can't bet here. Go to the roulette!\r\n", ch ); return; } if( IS_NPC(ch) ) { send_to_char( "Sorry, mobs can't bet.\r\n", ch ); return; } if( !can_see( croupier, ch ) ) { send_to_char( "You can't bet while being invisible.\r\n", ch ); return; } if( roulette_state == ROULETTE_ROLLING ) { sprintf(buf, "%s You can't bet now! Wait till it stops rolling, please.", ch->name ); do_tell(croupier, buf ); return; } argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); /* munch optional words */ if( !str_cmp( arg2, "coins") || !str_cmp( arg2, "coin") || !str_cmp( arg2, "gold") ) argument = one_argument( argument, arg2 ); if( !str_cmp( arg2, "on" ) ) argument = one_argument( argument, arg2 ); if( arg1[0] == '\0' || arg2[0] == '\0' ) { send_to_char( "Syntax: bet <amount> coins on <something>\r\n", ch ); return; } amount = advatoi( arg1 ); if( amount <= 0 ) { send_to_char( "Illegal amount.\r\n", ch ); return; } if( ch->gold < amount ) { send_to_char( "You don't have that much money.\r\n", ch ); return; } bet_type = get_bet_type( arg2 ); if( bet_type == BET_NONE ) { send_to_char( "Illegal bet. Legal bets are numbers 1-36 and either \"red\" or \"black\".\r\n", ch ); return; } extra = get_roulette_extra( roulette ); if( roulette_state == ROULETTE_IDLE ) { if( extra != NULL ) { roulette_extra_descr = extra->description; sprintf(buf, "%s\r\nOn the table you see:\r\n", roulette_extra_descr ); extra->description = STRALLOC( buf ); } roulette_state = ROULETTE_BETTING; } if( extra != NULL ) { sprintf(buf, "%s%s has %d coins on %s.\r\n", extra->description, ch->name, amount, get_bet_name( bet_type) ); STRFREE( extra->description ); extra->description = STRALLOC( buf ); } ch->gold -= amount; CREATE( bet, BET_DATA, 1 ); bet->player_name = QUICKLINK( ch->name ); bet->amount = amount; bet->bet_type = bet_type; LINK( bet, first_bet, last_bet, next_bet, prev_bet ); act( AT_GOLD, "$n places a bet in the roulette table.", ch, NULL, NULL, TO_ROOM ); sprintf(buf, "%s Your bet of %d coins on %s has been placed, %s.", ch->name, amount, get_bet_name( bet_type), ch->name ); do_tell( croupier, buf ); } /* look for an extra with the same keyword as the roulette's object name. */ EXTRA_DESCR_DATA *get_roulette_extra( OBJ_DATA * roulette ) { EXTRA_DESCR_DATA *extra, *new_extra; extra = get_extra_from_list( roulette->first_extradesc, "roulette" ); if( extra == NULL ) { extra = get_extra_from_list( roulette->pIndexData->first_extradesc, "roulette" ); if( extra != NULL ) { CREATE(new_extra, EXTRA_DESCR_DATA, 1); new_extra->keyword = STRALLOC( "roulette" ); new_extra->description = QUICKLINK( extra->description ); LINK( new_extra, roulette->first_extradesc, roulette->last_extradesc, next, prev ); top_ed ++; return new_extra; } } return extra; } EXTRA_DESCR_DATA *get_extra_from_list( EXTRA_DESCR_DATA *extra, char *name ) { for ( ; extra ; extra = extra->next ) { if( nifty_is_name( name, extra->keyword) ) return extra; } return NULL; } /* return a descriptive name for that type of bet .. static string */ char *get_bet_name( short type ) { static char buf[ MAX_STRING_LENGTH ]; if( type <= 0 ) { bug( "get_bet_name: invalid type passed" ); return "(invalid bet)"; } if( type > 0 && type < 37 ) { sprintf( buf, "%d", type ); return buf; } else return desc_bet_names[ type - BET_RED ]; } /* return the type of bet for a given keyword string */ short get_bet_type( char *s ) { short number, i; number = atoi(s); if( number > 0 && number < 37 ) return number; else { for( i=0 ; bet_names[i] ; i++ ) { if( !str_cmp(bet_names[i], s) ) return i + BET_RED; } return BET_NONE; } } void bet_update(void) { OBJ_DATA *roulette; ROOM_INDEX_DATA *room; CHAR_DATA *croupier; char buf [MAX_STRING_LENGTH]; short result; EXTRA_DESCR_DATA *extra; if( (roulette = get_roulette_obj()) == NULL || (room = roulette->in_room) == NULL || (croupier = get_croupier(room)) == NULL ) return; switch( roulette_state ) { case ROULETTE_IDLE: do_say( croupier, "Place your bets... Place your bets..." ); act( AT_ACTION, "$n is waiting for someone to bet...", croupier, NULL, NULL, TO_ROOM ); return; case ROULETTE_BETTING: do_say( croupier, "That's right! Keep betting, keep betting please..."); roulette_state = ROULETTE_END_BETTING; return; case ROULETTE_END_BETTING: act( AT_ACTION, "With a movement of $s hand, $n starts spinning the roulette. After a second, $e throws the ball in.", croupier, NULL, NULL, TO_ROOM ); do_say( croupier, "No more bets! The ball is rolling! Woohoo!" ); roulette_state = ROULETTE_ROLLING; return; case ROULETTE_ROLLING: /* The big moment! */ act( AT_ACTION, "The roulette stops spinning.", croupier, NULL, NULL, TO_ROOM ); result = (short) number_range( 0, 36 ); if( result == 0 ) sprintf( buf, "The roulette has stopped! It's the zero! Everyone loses. I love these moments, he he he..."); else sprintf( buf, "The roulette has stopped! It's the %d!", result ); do_say( croupier, buf ); if ( result != 0 ) resolve_bets( croupier, result ); clean_bets(); roulette_state = ROULETTE_IDLE; extra = get_roulette_extra( roulette ); if( extra != NULL && roulette_extra_descr != NULL ) { STRFREE( extra->description ); extra->description = roulette_extra_descr; } return; } } /* wipe all bets */ void clean_bets() { BET_DATA *bet, *next_bet; for( bet = first_bet ; bet ; bet = next_bet ) { next_bet = bet->next_bet; STRFREE( bet->player_name ); DISPOSE( bet ); } first_bet = NULL; last_bet = NULL; } /* given the result number, resolve each of the outstanding bets, giving money to the winners, and informing the losers */ void resolve_bets(CHAR_DATA *croupier, int number) { BET_DATA *bet; char buf[ MAX_STRING_LENGTH ]; int gain; bool is_in_room; CHAR_DATA *ch; int bet_count; for( bet = first_bet, bet_count = 0 ; bet ; bet = bet->next_bet, bet_count++ ) { is_in_room = TRUE; ch = get_char_room( croupier, bet->player_name ); if( !ch ) { ch = get_char_world( croupier, bet->player_name ); is_in_room = FALSE; } if( !ch ) /* the player left the game... lost his money */ continue; if( has_won(bet->bet_type, number) ) { if( is_in_room ) { act( AT_SAY, "$n says '$N has won!'", croupier, NULL, ch, TO_ROOM ); gain = calc_gain( bet->bet_type, bet->amount ); sprintf(buf, "%s You won on %s. Here's your %d coins", bet->player_name, get_bet_name( bet->bet_type), gain); do_tell( croupier, buf ); ch->gold += gain; act( AT_GOLD, "$n gives you the money.", croupier, NULL, ch, TO_VICT ); } else { act( AT_SAY, "$n says '$N has won! But since $E left, I keep the money.'", croupier, NULL, ch, TO_ROOM ); } } else { if( is_in_room ) { sprintf(buf, "%s Sorry, you have lost your %d coins on %s", bet->player_name, bet->amount, get_bet_name( bet->bet_type) ); do_tell( croupier, buf ); } } } } int calc_gain( short type, int amount ) { if( type > 0 && type < 37 ) return amount * 36; else { switch( type ) { case BET_EVEN: case BET_ODD: case BET_RED: case BET_BLACK: return amount * 2; case BET_1STCOL: case BET_2NDCOL: case BET_3RDCOL: case BET_1STDOZEN: case BET_2NDDOZEN: case BET_3RDDOZEN: return amount * 3; default: bug( "calc_gain: unknown bet type "); return 0; } } } /* return true if the bet_type has won for that given number */ bool has_won( short type, short number ) { if ( type > 0 && type < 37 ) { return (type == number); } else { switch( type ) { case BET_EVEN: return ((number % 2) == 0); case BET_ODD: return ((number % 2) != 0); case BET_RED: case BET_BLACK: case BET_1STCOL: case BET_2NDCOL: case BET_3RDCOL: return FALSE; case BET_1STDOZEN: return (number >= 1 && number <= 12); case BET_2NDDOZEN: return (number >= 13 && number <= 24); case BET_3RDDOZEN: return (number >= 25 && number <= 36); return FALSE; default: bug( "has_won; unknown bet type" ); return FALSE; } } } OBJ_DATA *get_roulette_obj() { OBJ_DATA *obj; for( obj = first_object ; obj ; obj = obj->next ) { if( obj->pIndexData->vnum == OBJ_VNUM_ROULETTE ) return obj; } return NULL; } CHAR_DATA *get_croupier( ROOM_INDEX_DATA *room ) { CHAR_DATA *ch; if( !room ) { bug( "get_croupier: null room "); return NULL; } for( ch = room->first_person ; ch ; ch = ch->next_in_room ) { if( IS_NPC(ch) ) return ch; } return NULL; }