/*
* 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;
}