/* * ResortMUD Arena Code * Author: Scion (Scion@usa.net) * of ResortMUD (ucmm.dhs.org: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). */ #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include "mud.h" void arena_add(int number, bool money); int arena_death(CHAR_DATA *ch, CHAR_DATA *victim); void arena_update(void); /* called by comm.c */ extern void save_sysdata args( ( SYSTEM_DATA sys ) ); /* act_wiz.c in ShogTag */ const int MAX_ARENA_FEE=3000000; /* Set this to something reasonable */ const int ARENA_DEFAULT_PRIZE = 10000; const int MIN_BET = 100; int arena_players=0; /* This keeps track of the number of players left in the arena */ int arena_total_players=0; int arena_prize; /* This is always 500 coins, set it to be balanced on your MUD */ int arena_fee=0; /* This is the entrance fee to get in, which can be set with arena start */ int low_level=0; /* Lowest level allowed in arena */ int hi_level=0; /* Highest level allowes in arena */ int arena_total_bets=0; /* Total number of bets. Individual amounts are stored on the players */ int arena_bet_time=1; /* Time for betting in 30 second increments */ int arena_update_mode=0; /* Update is called once per minute, but we don't want to do something every minute. */ void do_arena( CHAR_DATA *ch, char *argument ) { char cmd[ MAX_INPUT_LENGTH ]; char cmd2[ MAX_INPUT_LENGTH ]; char cmd3[ MAX_INPUT_LENGTH ]; char buf[ MAX_STRING_LENGTH ]; CHAR_DATA *victim; AREA_DATA *arena; int hi_vnum; int lo_vnum; int real_vnum; int i; argument = one_argument( argument, cmd ); set_char_color( AT_IMMORT, ch ); if (IS_IMMORTAL(ch)) { if( !str_cmp( cmd, "start" ) ) { if (sysdata.arena >= 1) { send_to_char("There is already a battle in the arena!\r\n",ch); return; } argument = one_argument(argument, cmd); /* entrance fee */ argument = one_argument(argument, cmd2); /* low level */ argument = one_argument(argument, cmd3); /* high level */ arena_prize=ARENA_DEFAULT_PRIZE; if (cmd[0] == '\0') arena_fee=0; else arena_fee=atoi(cmd); if (arena_fee < 0) /* Free matches are, of course, allowed and encouraged! */ arena_fee = 0; if (arena_fee >= MAX_ARENA_FEE) arena_fee = MAX_ARENA_FEE; if (cmd2[0] == '\0') low_level=-1; /* Ignore level settings if not specified */ else { low_level=atoi(cmd2); if (low_level>MAX_LEVEL) low_level=MAX_LEVEL; if (low_level<=0) low_level=-1; } if (cmd3[0] == '\0') hi_level=-1; /* Ignore level settings if not specified */ else { hi_level=atoi(cmd3); if (hi_level>MAX_LEVEL) hi_level=MAX_LEVEL; if (hi_level<=0) hi_level=-1; } if (hi_level < low_level) { /* If they're backward, reverse them */ i=hi_level; hi_level=low_level; low_level=i; } sysdata.arena = 1; /* move on to betting stage */ save_sysdata( sysdata ); /* Clear everyone's bets */ arena_total_bets=0; for( victim = first_char; victim ; victim = victim->next ) { if (IS_NPC(victim)) continue; victim->arenabet=-1; victim->arena_bet_on=NULL; victim->num_bets=0; } arena_players=0; arena_total_players=0; /* Display the appropriate start messages */ if (hi_level>0 && low_level==-1) sprintf(buf, "%s has ^zOPENED^x the arena with a MAX level of %d!",ch->name, hi_level); else if (low_level>0 && hi_level==-1) sprintf(buf, "%s has ^zOPENED^x the arena with a MIN level of %d!",ch->name, low_level); else if (low_level == -1 && hi_level == -1) sprintf(buf, "%s has ^zOPENED^x the arena!", ch->name); else sprintf(buf,"%s has ^zOPENED^x the arena for levels %d through %d!", ch->name, low_level, hi_level); do_info(ch, buf); if (arena_fee) { sprintf(buf,"The entrance fee is %d coins!", arena_fee); do_info(ch, buf); } do_info(ch, "Type \'arena join\' to join, or \'arena bet <amount> <player>\' to bet!"); set_char_color( AT_IMMORT, ch ); send_to_char( "Ready.\n\r", ch ); return; } else if ( !str_cmp( cmd, "end" ) ) { if( sysdata.arena == 0) { send_to_char( "There is not currently an arena battle to end.\n\r", ch ); return; } if (sysdata.arena==1) { sprintf(buf, "%s has closed betting. Let the games begin!", ch->name); do_info(ch, buf); sysdata.arena=2; return; } sprintf(buf, "%s has canceled the arena match!",ch->name); do_info(ch, buf); do_info(ch, "The arena is ^zCLOSED^x."); for( victim = first_char; victim ; victim = victim->next ) { if( IS_NPC(victim) ) continue; if( victim->arena==1 ) { send_to_char("Your bet has been returned to you.\n",ch); ch->gold+=ch->arenabet; ch->arena_bet_on=NULL; ch->arenabet=-1; ch->num_bets=0; continue; } if( victim->arena!=2 ) continue; /* remove recent fight timer */ if( get_timer( victim, TIMER_RECENTFIGHT ) ) remove_timer( victim, TIMER_RECENTFIGHT); /* make everyone STANDING (for all peace, etc) */ stop_fighting( victim, TRUE ); victim->position = POS_STANDING; if (arena_fee) { send_to_char("Your entrance fee has been returned to you.\r\n",victim); victim->gold+=arena_fee; } act( AT_MAGIC, "$n disappears in blinding flash of light.", victim, NULL, NULL, TO_ROOM ); char_from_room( victim ); char_to_room( victim, get_room_index(victim->retran) ); act( AT_MAGIC, "$n arrives in a blinding flash of light.", victim, NULL, NULL, TO_ROOM ); do_look( victim, "auto" ); victim->arena=0; } sysdata.arena = 0; save_sysdata( sysdata ); set_char_color( AT_IMMORT, ch ); send_to_char( "Done.\n\r", ch ); return; } else if (!str_cmp(cmd, "who")) { send_to_char("\r\nWho is in the arena:\r\n",ch); for( victim = first_char; victim ; victim = victim->next ) { if( IS_NPC(victim) ) continue; if( victim->arena==0 ) continue; switch (victim->arena) { case 1: sprintf(cmd, "Betting"); break; case 2: sprintf(cmd, "Fighting"); break; case 3: sprintf(cmd, "Defeated"); break; case 4: sprintf(cmd, "Spectator"); break; default: sprintf(cmd, "Unknown"); break; } sprintf(buf, "%15s: %s\r\n", victim->name, cmd); send_to_char(buf, ch); } return; } } /* if IS_IMMORTAL(ch) */ if ((!IS_IMMORTAL(ch)) || (sysdata.imm_arena==TRUE)) { /******* JOIN *******/ if ( !str_cmp( cmd, "join" ) ) { if (ch->arena==2) { send_to_char( "You are already in the arena!\r\n", ch); return; } if (sysdata.arena==2) { send_to_char( "You\'re too late! The betting stage is over!\r\n",ch); return; } if (sysdata.arena==0) { send_to_char( "The arena is currently closed. Ask an immortal to open it!\r\n", ch); return; } if ((ch->gold < arena_fee) && !IS_IMMORTAL(ch)) { sprintf(buf, "You do not have the %d coins to join this arena match!\r\n",arena_fee); send_to_char(buf,ch); return; } if (ch->arena==3) { send_to_char("You were already defeated in this round!\r\n",ch); return; } if (ch->arena==1) { send_to_char("You have bet on this round, you cannot participate!\r\n",ch); return; } if (ch->arena==4) { send_to_char("You are watching a player in this round, you cannot participate.\r\n",ch); return; } if (ch->level<low_level && low_level != -1) { send_to_char("You are not of a high enough level to compete in this match!\r\n",ch); return; } if (ch->level>hi_level && hi_level != -1) { send_to_char("Leave those low level players to bicker amongst themselves.\r\n",ch); return; } if (ch->fighting) { send_to_char("You had better stop fighting before entering the arena!\r\n",ch); return; } /* Put them in a random room inside arena.are */ for ( arena = first_area; arena; arena = arena->next ) { if ( !str_cmp( arena->filename, "arena.are" ) ) { lo_vnum=arena->low_r_vnum; hi_vnum=arena->hi_r_vnum; break; } else { lo_vnum=2; hi_vnum=2; } } if ((lo_vnum==2) && (hi_vnum==2)) { bug("Could not find arena.are!",0); send_to_char("An error ocurred while moving you to the arena.\r\nThe administrators have been notified of the error.\r\n",ch); return; } i=0; while (!get_room_index(real_vnum=number_range(lo_vnum, hi_vnum))) { if (i++ >= 50) { bug("Cannot find a room in the arena for %s!", ch->name); send_to_char("An error ocurred while moving you to the arena.\r\nThe administrators have been notified of the error.\r\n",ch); return; } } stop_fighting( ch, TRUE ); ch->position = POS_STANDING; act( AT_MAGIC, "$n disappears in a blinding flash of light.", ch, NULL, NULL, TO_ROOM ); ch->retran = ch->in_room->vnum; char_from_room( ch ); char_to_room( ch, get_room_index(real_vnum)); /* Take their money and put it in the pot */ if (arena_fee) { if (IS_IMMORTAL(ch)) { sprintf(buf, "Bill Gates donates %d coins for %s\'s entrance fee!",arena_fee, ch->name); do_info(ch, buf); } else ch->gold-=arena_fee; arena_prize+=arena_fee; } act( AT_MAGIC, "$n arrives in a blinding flash of light.", ch, NULL, NULL, TO_ROOM ); do_look( ch, "auto" ); send_to_char("You have entered the arena!\r\n",ch); sprintf(buf, "%s has joined the arena match!", ch->name); do_info(ch, buf); ch->arena=2; arena_add(1,FALSE); return; } /******** WIMPOUT ********/ else if ( !str_cmp( cmd, "wimpout" ) ) { if (ch->arena!=2) { send_to_char( "You are not in the arena!\r\n", ch); return; } if (ch->fighting) { send_to_char("You had better stop fighting before you do that!\r\n", ch); return; } if (arena_fee>0) send_to_char("By wimping out, you forfeit your entrance fee!\r\n",ch); stop_fighting(ch, TRUE); ch->position = POS_STANDING; act( AT_MAGIC, "$n disappears in a blinding flash of light.", ch, NULL, NULL, TO_ROOM ); char_from_room( ch ); char_to_room( ch, get_room_index(ch->retran) ); act( AT_MAGIC, "$n arrives in a blinding flash of light.", ch, NULL, NULL, TO_ROOM ); do_look( ch, "auto" ); sprintf(buf, "%s has wimped out of the arena match!", ch->name); do_info(ch, buf); ch->arena=0; arena_add(-1,FALSE); return; } /******** BET ********/ else if ( !str_cmp( cmd, "bet" ) ) { argument = one_argument(argument, cmd); /* amount */ argument = one_argument(argument, cmd2); /* character */ if (IS_IMMORTAL(ch) && sysdata.arena==0 && !str_cmp(cmd, "time")) { arena_bet_time=atoi(cmd2); sprintf(buf, "The arena will now allow %d minutes for betting.\r\n", arena_bet_time); send_to_char(buf, ch); return; } else if (IS_IMMORTAL(ch) && sysdata.arena!=0 && !str_cmp(cmd, "time")) { send_to_char("You may only set the bet time when the arena is not in use.\r\n",ch); send_to_char("Betting may be ended using \'arena end\' while betting is in progress.\r\n",ch); return; } if (sysdata.arena != 1) { send_to_char("The arena is not accepting bets at this time.\r\n",ch); return; } if (ch->arena!=0) { send_to_char("You cannot bet on this match.\r\n",ch); return; } if (cmd[0] == '\0') { send_to_char("You must specify an amount to bid, as well as a player to bid on.\r\n",ch); return; } if (cmd2[0] == '\0') { send_to_char("You must specify a player to bid on, after the amount you wish to bid.\r\n",ch); return; } ch->arenabet=atoi(cmd); if (ch->gold < ch->arenabet) { send_to_char("You do not have that much money!\r\n",ch); ch->arenabet=-1; return; } if (ch->arenabet<MIN_BET) { sprintf(buf, "You must bid more than %d.\r\n", MIN_BET); send_to_char(buf, ch); ch->arenabet=-1; return; } if (!(victim=get_char_world(ch, cmd2))) { send_to_char("There is no such player available to bid on.\r\n",ch); ch->arenabet=-1; return; } if (victim==ch) { send_to_char("You cannot bet on yourself!\r\n",ch); return; } if (victim->arena!=2) { send_to_char("That player is not fighting in the arena at this time.\r\n",ch); victim=NULL; ch->arenabet=-1; return; } /* Ok, now we know ch has enough money and has picked a valid victim */ sprintf(buf, "A bid of %d coins has been placed on %s to win!", ch->arenabet, victim->name); do_info(victim, buf); /* in case these infos are logged */ ch->gold-=ch->arenabet; ch->arena_bet_on=victim; ch->arena_bet_on->num_bets++; arena_total_bets+=ch->arenabet; ch->arena=1; return; } /****** NO VALID COMMAND ******/ else { /* If we got no valid arguments */ send_to_char( "Syntax:\r\n", ch); if (!IS_IMMORTAL(ch) || (sysdata.imm_arena==TRUE)) { if (sysdata.arena > 0) send_to_char( "arena join\r\n",ch); if (ch->arena==2) send_to_char( "arena wimpout\r\n",ch); if (sysdata.arena==1 && ch->arena == 0) send_to_char( "arena bet <amount> <player>\r\n",ch); } if (IS_IMMORTAL(ch)) { if (sysdata.arena==0) { send_to_char( "\r\narena start [fee] [low] [high]\r\n", ch); send_to_char( "arena bet time [minutes]\r\n",ch); } if (sysdata.arena > 0) send_to_char( "arena end\r\n", ch); send_to_char( "arena who\r\n",ch); } switch (sysdata.arena) { case 0: send_to_char("\r\nThe arena is closed.\r\n",ch); break; case 1: sprintf(buf, "\r\nThe arena has %d minutes left in the betting stage.\r\n",(arena_bet_time - arena_update_mode)); send_to_char("\r\nThe arena is in the betting stage.\r\n", ch); break; case 2: sprintf(buf, "\r\nThere are %d combatants in the arena.\r\n", arena_players); send_to_char(buf,ch); break; } /* switch */ } /* else */ } /* if !IS_IMMORTAL(ch) */ } /* function */ void arena_update(void) { char buf[MAX_STRING_LENGTH]; switch(sysdata.arena) { case 0: /* arena is off */ arena_update_mode=0; return; break; case 1: /* arena is in betting mode */ if (arena_update_mode >= arena_bet_time) { do_info(first_char, "All betting has come to an end! Let the games begin!"); sysdata.arena=2; return; } do_info(first_char, "Place your bets! Use \'arena bet <amount> <player>\' to bet on your favorite combatant!"); arena_update_mode++; break; case 2: /* arena is in free for all mode */ if (arena_fee > 0) sprintf(buf, "Now in the arena: levels %d to %d, entry fee only %d coins!",((low_level>0) ? low_level : 1), ((hi_level>0) ? hi_level : MAX_LEVEL), arena_fee); else sprintf(buf, "Now in the arena: Free for All, levels %d to %d!", ((low_level>0) ? low_level : 1), ((hi_level>0) ? hi_level : MAX_LEVEL)); do_info(first_char, buf); break; default: sysdata.arena=0; bug("Default case reached in arena_update!",0); break; } } void arena_add(int number, bool money) { /* This adds "number" players to arena_players and checks win conditions. */ char buf[ MAX_STRING_LENGTH ]; CHAR_DATA *ch; int percent=0; int g=0; arena_players+=number; if (arena_players>arena_total_players) arena_total_players=arena_players; if ((sysdata.arena == 2) && (arena_players <= 1) && (number <= 0)) { /* someone won */ for( ch = first_char; ch ; ch = ch->next ) { /* if number is positive, we've just added */ if( IS_NPC(ch) ) /* a player. How could they have just won? */ continue; switch( ch->arena ) { case 0: /* Character's not in, and hasn't been in the arena */ continue; break; case 1: /* Character has bet on a participant */ if (ch->arena_bet_on->num_bets <= 0) ch->arena_bet_on->num_bets=1; percent=ch->arenabet/arena_total_bets; g=ch->arenabet+ch->arenabet*percent; ch->gold += g; sprintf(buf, "You won %d coins!\r\n",g); send_to_char(buf, ch); ch->arena=0; break; case 2: /* Character has won, being the last one left alive in arena */ if (money==TRUE) { sprintf(buf, "%s has ^zWON^x the arena match, and ^z%d^x coins!", ch->name, arena_prize); do_info(ch, buf); ch->gold+=arena_prize; ch->arena_wins++; adjust_hiscore("arena_pkill", ch, ch->arena_wins); } else do_info(ch, "The arena match has been closed without a winner."); stop_fighting(ch, TRUE); ch->position=POS_STANDING; act( AT_MAGIC, "$n disappears in a golden beam of light.", ch, NULL, NULL, TO_ROOM); ch->hit = ch->max_hit; ch->mana = ch->max_mana; ch->move = ch->max_move; ch->pcdata->condition[COND_BLOODTHIRST] = (10 + ch->level); update_pos(ch); send_to_char("You have been fully restored!\r\n",ch); char_from_room( ch ); char_to_room( ch, get_room_index(ch->retran)); act( AT_MAGIC, "$n appears in a golden beam of light.", ch, NULL, NULL, TO_ROOM); do_look( ch, "auto" ); ch->arena=0; break; case 3: /* Character died in arena */ ch->arena=0; break; case 4: /* Character is watching a participant */ ch->arena=0; break; } } arena_prize=ARENA_DEFAULT_PRIZE; sysdata.arena=0; save_sysdata( sysdata ); arena_players=0; } } int arena_death(CHAR_DATA *ch, CHAR_DATA *victim) { char buf[MAX_STRING_LENGTH]; /* If they were in the arena, override death! */ if (victim->arena==2) { act(AT_DEAD, "$n has been DEFEATED!!", victim, 0, 0, TO_ROOM); act(AT_DEAD, "You have been DEFEATED!", victim, 0, 0, TO_CHAR); sprintf( buf, "%s has been defeated by %s in the arena!", victim->name, ch->name); do_info( victim, buf ); sprintf( buf, "%s (%d) killed by %s in arena at %d", victim->name, victim->level, (IS_NPC(ch) ? ch->short_descr : ch->name), victim->in_room->vnum ); log_string( buf ); to_channel( buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL ); ch->arena_kills++; victim->arena_deaths++; /* Now that that fiasco is over, retran and restore the victim */ stop_fighting(victim, TRUE); victim->position=POS_STANDING; act( AT_MAGIC, "$n disappears in a beam of holy light.", victim, NULL, NULL, TO_ROOM); victim->hit = victim->max_hit; victim->mana = victim->max_mana; victim->move = victim->max_move; victim->pcdata->condition[COND_BLOODTHIRST] = (10 + victim->level); update_pos(victim); send_to_char("You have been fully restored!\r\n",victim); char_from_room( victim ); char_to_room( victim, get_room_index(victim->retran)); act( AT_MAGIC, "$n falls delicately out of the sky.", victim, NULL, NULL, TO_ROOM); do_look( victim, "auto" ); victim->arena=3; /* 0==no arena, 1==betting, 2==fighting, 3==dead, 4==watching */ arena_add(-1,TRUE); /* Reduce the player count by one */ return 0; } return 1; }