/*
 *
 * Battle code to allow players
 * to fight one another without
 * the loss of experience or items.
 * Origianlly coded for Age of Infinity MUD
 * by Theodryck.  C 1999.
 *
 * You may use and distribute this code
 * freely as long you leave unaltered
 * the documention within.
 *
 */

 /* In merc.h we need to make the declarations */

 /* Add this after PLR_PAGER */
 #define PLR_BATTLE                 BV30

 /* Add this in the channel declarations part of merc.h */
 #define CHANNEL_BATTLE             BV10

/* In the DECLARE_DO_FUN section add the following: */

/*Battle stuff by Theodryck*/
DECLARE_DO_FUN(   do_battle  );
DECLARE_DO_FUN(   do_bopen   );
DECLARE_DO_FUN(   do_bclose  );
DECLARE_DO_FUN(   do_bstop   );
DECLARE_DO_FUN(   do_bchat   );
DECLARE_DO_FUN(   do_badd    );
DECLARE_DO_FUN(   do_bremove );

/*
 * Set up all the parts used
 */

typedef struct         battle_data       BATTLE_DATA; /*battle struct*/

extern                 BATTLE_DATA *  battle;

/*Here's the main battle struct */
struct   battle_data
  {
  int  level1;
  int   level2;
  bool  open;
  bool running;
  };
void talk_battle      args( (char *argument) );
void do_battle          args( (CHAR_DATA *ch, char * argument ) );
void do_bopen          args( (CHAR_DATA *ch, char * argument ) );
void do_bclose          args( (CHAR_DATA *ch, char * argument ) );
void do_bstop          args( (CHAR_DATA *ch, char * argument ) );
void do_bchat          args( (CHAR_DATA *ch, char * argument ) );

/* In act_wiz.c we add the actual functions for the immortal commands */

void do_bopen(CHAR_DATA *ch, char* argument )
 {

        int   upper;
        int   lower;
        char  buf[MAX_STRING_LENGTH];
        int   number;

  //  battle = (BATTLE_DATA *) malloc (sizeof(BATTLE_DATA));

      if(IS_NPC( ch ) ) /*mobs can't open battles */
       return;

     lower = 0;
     upper = 0;
     number = 0;

     for ( ;; )
       {
      char  arg[MAX_STRING_LENGTH];
      argument = one_argument(argument, arg);

       if(arg[0] == '\0')
        break;


         if (is_number( arg ) )
          {
           switch (++number)
            {
             case 1: lower = atoi( arg ) ; break;
             case 2: upper = atoi( arg ) ; break;
             default :
              send_to_char("Only two level numbers please.", ch );
              return;
            }
          }
         else
          {
          send_to_char ("Syntax is: bopen <level 1> <level 2>.", ch );
          return;
          }
        }

      battle->open = TRUE;
      battle->level1 = lower;
      battle->level2 = upper;
      sprintf( buf,"{o{wNow open for levels {m<{r%d - %d{m>{w!{x\n\r",lower,upper);
      talk_battle( buf );

    return;
   }

/*Now that we've opened a battle , we need a way to close it */
void do_bclose (CHAR_DATA *ch, char *argument)
 {


        char            buf[MAX_STRING_LENGTH];
        ROOM_INDEX_DATA *location;
        int             place;

       if(IS_NPC( ch ) ) /*Since mobs can't open battles, let's not let them close battles*/
        return;

   /*actual closing of battle and scattering of players */

       battle->open = FALSE;
       sprintf(buf,"Is now closed!\n\r");
       talk_battle( buf );

       for(ch = char_list; ch; ch = ch->next)
        {
         if (IS_SET( ch->act, PLR_BATTLE ) )
          {
           place = number_range(24001, 24048);
           location = get_room_index( place );
           char_from_room( ch );                   /*Randomly drop players about*/
           char_to_room( ch, location );           /*the battle field, the numbers*/
          }                                        /*can be changed to suit your*/
        }                                          /*battle area.*/

     battle->running = TRUE;
   return;
 }

/*Just in case we need it*/
void do_bstop(CHAR_DATA *ch, char * argument)
 {

    char            buf[MAX_STRING_LENGTH];
    ROOM_INDEX_DATA *location;
    int             place;

    if(IS_NPC( ch ) )
     return;
    place = 3001;
    location = get_room_index( place );

    if( !battle->running && !battle->open )
     {
      send_to_char( "There is no battle going on that you can stop", ch );
      return;
     }

    sprintf( buf,"{o{wHas been stopped!{x\n\r" );
    talk_battle( buf );

    for(ch = char_list; ch; ch = ch->next )
     {
      if(IS_SET( ch->act, PLR_BATTLE ) )
       {
        /* Ahapin - added this check to stop fights in progress */
	if ( ch->fighting )
	    stop_fighting( ch, TRUE );

	REMOVE_BIT( ch->act, PLR_BATTLE );
        char_from_room( ch );
        char_to_room( ch, location );
       }
     }
   battle->running = FALSE;
   battle->open = FALSE;
   return;
 }
/*Here's a little tidbit just for fun
 *Add players to battle regardless of level */
void do_badd( CHAR_DATA * ch, char * argument )
 {
   CHAR_DATA        *victim;
   CHAR_DATA        *rch;
   ROOM_INDEX_DATA  *location;
   int               place;
   char              arg1[MAX_INPUT_LENGTH];
   char              buf[MAX_STRING_LENGTH];


   argument = one_argument(argument, arg1 );

    rch = get_char( ch );

    if ( !authorized( rch, "badd" ) )
        return;

  if(!battle->running && !battle->open )
    {
    send_to_char( "There is no battle going on at the moment", ch );
    return;
    }

  if (arg1[0] == '\0')
    {
    send_to_char( "Add who to the battle?", ch );
    return;
    }

      if ( !( victim = get_char_world( ch, arg1 ) ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

  place = ROOM_VNUM_PREP;
  location = get_room_index( place );

    if ( IS_NPC( victim ) )
    {
	send_to_char( "Not on mobs.\n\r", ch );
	return;
    }
    else
     {
     act( "$n has gone to seek glory on the battlefield.", victim, NULL, NULL, TO_ROOM );
      char_from_room( victim );
      char_to_room( victim, location );
      act( "$n has arrived on the battlefield.", victim, NULL, NULL, TO_ROOM );
      do_look( victim, "auto" );
      SET_BIT ( victim->act, PLR_BATTLE );
      victim->battles++;
      sprintf( buf,"{o{w%s {rhas joined the battle!.{x\n\r",victim->name );
      talk_battle( buf );
      victim->mana = victim->max_mana;
      victim->hit = victim->max_hit;
      victim->move = victim->max_move;
      sprintf( buf, "%s added to the battle.\n\r", victim->name );
      send_to_char( buf, ch );
     }
  return;
}
/*Since we can add players...let's be able to remove them
  as well. */
void do_bremove( CHAR_DATA * ch, char * argument )
  {
     CHAR_DATA         *victim;
     CHAR_DATA         *rch;
     ROOM_INDEX_DATA   *location;
     int                place;
     char               buf[MAX_STRING_LENGTH];
     char               arg1[MAX_STRING_LENGTH];


    argument = one_argument( argument, arg1 );

    rch = get_char( ch );

    if ( !authorized( rch, "bremove" ) )
        return;

    if(!battle->running && !battle->open )
    {
    send_to_char( "There is no battle going on at the moment", ch );
    return;
    }

     if (arg1[0] == '\0')
    {
    send_to_char( "Remove who from the battle?", ch );
    return;
    }

      if ( !( victim = get_char_world( ch, arg1 ) ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

   if (IS_NPC( victim ) )
    {
    send_to_char( "Not on mobs.\n\r", ch );
    return;
    }
  else
  {
  REMOVE_BIT( victim->act, PLR_BATTLE );
  place = victim->pcdata->temple;
  location = get_room_index( place );
  sprintf( buf, "%s has removed you from battle.\n\r", ch->name );
  send_to_char( buf, victim );
  char_from_room( victim );
  char_to_room( victim, location );
  do_look( victim, "auto" );
  sprintf( buf, "%s has been removed from battle.\n\r", victim->name );
  send_to_char( buf, ch );
 }
  return;
 }

 /*
  * In act_move.c we add the function that allows
  * players to actually join the battles
  */

/*Battle code stuff by Theodryck */
 void do_battle (CHAR_DATA *ch, char * argument)
 {

     ROOM_INDEX_DATA             *location;
     char            buf[MAX_STRING_LENGTH];
     int             place;

   /*can't let mobs in battles :P*/
     if (IS_NPC( ch ) )
      return;

   /*There's no battle going on dummy */
     if(!battle->open)
      {
       send_to_char("There is no battle currently open",ch );
       return;
      }

     if( IS_SET( ch->act, PLR_BATTLE ) )

       return;

     place = ROOM_VNUM_PREP;
     location = get_room_index( place );
  /*
   *Here we check to see if the player is in the
   *proper level range
   */
     if(battle->open && (ch->level >= battle->level1 && ch->level <= battle->level2) )
      {
      act( "$n has gone to seek glory on the battlefield.", ch, NULL, NULL, TO_ROOM );
      char_from_room( ch);
      char_to_room( ch, location );
      act( "$n has arrived on the battlefield.", ch, NULL, NULL, TO_ROOM );
      do_look(ch, "auto" );
      SET_BIT (ch->act, PLR_BATTLE );
      ch->battles++;
      sprintf(buf,"{o{w%s {rhas joined the battle!.{x\n\r",ch->name);
      talk_battle( buf );
      ch->mana = ch->max_mana;
      ch->hit = ch->max_hit;
      ch->move = ch->max_move;
      }

     else
      {
      send_to_char("You are not in the correct level range", ch);
      return;
      }

    return;
    }

 /* in db.c we add the following */

 /*In the globals section */
 BATTLE_DATA   *         battle;
 bool                    check_battle;

 /* Add this after the weather initialization in boot_db */

                battle = (BATTLE_DATA *) malloc (sizeof(BATTLE_DATA)); /* DOH!!! */
                if (battle == NULL)
                {
                        bug ("malloc'ing BATTLE_DATA didn't give %d bytes",sizeof(BATTLE_DATA));
                        exit (1);
                }

        battle->open = FALSE;
        battle->running = FALSE;


/* In fight.c we need to add this */

 /*Add this in one_hit, right after the declarations are made */
   if ( IS_SET( ch->act, PLR_BATTLE )
         && !IS_NPC( victim )
         && !IS_SET( victim->act, PLR_BATTLE ) )
        return;

 /*A little further down we need to change the check for immortals so that it looks like this */
 if ( !IS_NPC( victim )
	&& victim->level >= LEVEL_IMMORTAL
add this--->&& !IS_SET( ch->act, PLR_BATTLE )
	&& victim->hit < 1 )
	victim->hit = 1;

 /* In damage() we need to add this in case POS_DEAD */
  if ( !IS_NPC( victim ) && IS_SET( victim->act, PLR_BATTLE ) )
        {
        sprintf( buf, "{o{m %s{r has been slain by{w %s!{x\n\r",victim->name,
        ( IS_NPC( ch ) ? ch->short_descr : ch->name ) );
        talk_battle( buf );
        break;
        }

 /*
  * Make sure to add && !IS_SET( victim->act, PLR_BATTLE )
  * to the if statement just before the call to gain_exp ()
  *
  */

 /* In is_safe() add this */
  if ( !IS_NPC( victim ) && IS_SET( victim->act, PLR_BATTLE ) )
       return FALSE;

 /*change the statment just after to look like this */
    if ( !IS_NPC( victim )
	&& !IS_NPC( ch )
	&& victim != ch
	&& !IS_SET( victim->act, PLR_BATTLE )
	&& !IS_SET( ch->act, PLR_BATTLE ) )
        return TRUE;

/* Also be sure to add a check for PLR_BATTLE in check_killer() */

/*
 * In raw_kill
 * change the call to make corpse to look like this
 */
if ( !IS_SET( victim->act, PLR_BATTLE ) )
    make_corpse( victim );

/* Just before the call to extract_char in raw_kill add the following */
if (!IS_NPC( victim ) && IS_SET(victim->act, PLR_BATTLE) )
     {
       ROOM_INDEX_DATA     *location;
       int                 place;

      place = victim->pcdata->temple;
      location = get_room_index( place);
      REMOVE_BIT( victim->act, PLR_BATTLE );
      do_recall(victim, "");
      do_look(victim, "auto");
      victim->position   = POS_RESTING;
      victim->hit = victim->max_hit;
      victim->mana = victim->max_mana;
      victim->move = victim->max_move;
      return;
     }

/* In group_gain add this right after the declarations */
if ( victim == ch
        || IS_SET(victim->act, PLR_BATTLE )  )
	return;

/* A little further down, after the check for in_arena( victim ) */
 if( IS_SET( ch->act, PLR_BATTLE ) )
         continue;

 /*In do_kill change the following if statement to look like this */
 if ( !IS_NPC( victim ) )
    {
	if (   !IS_SET( victim->act, PLR_KILLER )
	    && !IS_SET( victim->act, PLR_THIEF  )
   add this--->&& !IS_SET(ch->act, PLR_BATTLE)  )
	{
	    send_to_char( "You can not kill another player.\n\r", ch );
	    return;
	}
    }
    else
    {
	if ( IS_AFFECTED( victim, AFF_CHARM ) && victim->master )
	{
	    send_to_char( "You must MURDER a charmed creature.\n\r", ch );
	    return;
	}

/* In do_flee add an if check for PLR_BATTLE to prevent loss of exp */

/* In interp.c we need to add this to the command table */

  /*In the immortal commands section add this:*/
    { "battle",		do_battle,	POS_DEAD,	 0,  LOG_NORMAL, 1 },
    { "bonus",          do_bonus,       POS_DEAD,    L_ARC,  LOG_NORMAL, 1 },
    { "bopen",          do_bopen,       POS_DEAD,    L_HER,  LOG_NORMAL, 1 },
    { "bclose",         do_bclose,      POS_DEAD,    L_HER,  LOG_NORMAL, 1 },
    { "bstop",          do_bstop,       POS_DEAD,    L_HER,  LOG_NORMAL, 1 },
    { "bchat",          do_bchat,       POS_DEAD,    L_HER,  LOG_NORMAL, 1 },
    { "badd",           do_badd,        POS_DEAD,    L_HER,  LOG_NORMAL, 1 },
    { "bremove",        do_bremove,     POS_DEAD,    L_HER,  LOG_NORMAL, 1 },

/* In update.c add this */

/*add this after weather_update*/
void battle_update ( void )
 {

       CHAR_DATA   * ch;
       CHAR_DATA   * winner;
       ROOM_INDEX_DATA *location;
       int          place;
       int          count;
       char         buf[MAX_STRING_LENGTH];

     count = 0;

     if( battle->running == FALSE || battle->open == TRUE )
       return;


     place = 3001;
     location = get_room_index( place );

     for(ch = char_list; ch; ch = ch->next)
      {
       if(IS_SET( ch->act, PLR_BATTLE ) )
        {
         ++count;
         winner = ch;
        }
      }

    if( count == 1 )
     {
      sprintf( buf,"{o{w%s {rhas won the battle!{x\n\r",winner->name);
      talk_battle( buf );
       winner->bwins++;
      REMOVE_BIT(winner->act, PLR_BATTLE);
      winner->hit = winner->max_hit;
      winner->mana = winner->max_mana;
      winner->move = winner->max_move;
      char_from_room( winner );
      char_to_room( winner, location );
      do_look( winner, "auto" );
      battle->running = FALSE;
     }
   battle->running = TRUE;
   return;
  }

 /* Add this right after the call to violence_update() */
 if ( battle->running == TRUE && battle->open == FALSE )
        battle_update   ( );

/* And lastly we need to set up the channels in act_comm.c */

/* In the first part of chanoff add this */
 SET_BIT( ch->deaf, CHANNEL_BATTLE );

 /* Add this to do_quit */
 if( IS_SET( ch->act, PLR_BATTLE ) )
     {
      send_to_char( "But your in a battle!", ch );
      return;
     }

 /*In act_comm.c we need to set up a channel for battle */
void talk_battle (char *argument)
{
    DESCRIPTOR_DATA *d;
    char buf[MAX_STRING_LENGTH];
    CHAR_DATA *original;

    sprintf (buf,"{o{rBATTLE: %s{x\n\r", argument);

    for (d = descriptor_list; d != NULL; d = d->next)
    {
        original = d->original ? d->original : d->character; /* if switched */
        if ( (d->connected == CON_PLAYING) )
        //act (buf, original , NULL, NULL, TO_CHAR);
          send_to_char( buf , original );

    }
}

/*Now we need a way to let imms talk on it */
void do_bchat( CHAR_DATA *ch, char *argument )
{
    talk_battle( argument );
    return;
}


/*
 * And that should be it.  If you have any troubles implementing this code or
 * have any comments on it email me at theo@envy.com.
 */