LOP/area/
LOP/boards/
LOP/channels/
LOP/clans/
LOP/color/
LOP/councils/
LOP/deity/
LOP/src/specials/
/*****************************************************************************
 * DikuMUD (C) 1990, 1991 by:                                                *
 *   Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen,   *
 *   and Katja Nyboe.                                                        *
 *---------------------------------------------------------------------------*
 * MERC 2.1 (C) 1992, 1993 by:                                               *
 *   Michael Chastain, Michael Quan, and Mitchell Tse.                       *
 *---------------------------------------------------------------------------*
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider.                    *
 *   Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
 *         gorog, Grishnakh, Nivek, Tricops, and Fireblade.                  *
 *---------------------------------------------------------------------------*
 * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community.              *
 *                    Their contributions are greatly appreciated.           *
 *---------------------------------------------------------------------------*
 * LoP (C) 2006 - 2012 by: the LoP team.                                     *
 *---------------------------------------------------------------------------*
 *                         Wilderness Code                                   *
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "h/mud.h"

bool loc_in_wilderness; /* Used to know if they should enter the wilderness */
int loc_cords[2]; /* Used to get the cords for goto etc... */
extern int desccount;
extern int desccheck;
extern char showdescription[MSL];

bool should_follow_wilderness( CHAR_DATA *ch, CHAR_DATA *rch );

void put_in_wilderness( CHAR_DATA *ch, short x, short y )
{
   if( !ch )
      return;
   if( is_npc( ch ) )
      xSET_BIT( ch->act, ACT_WILDERNESS );
   else
      xSET_BIT( ch->act, PLR_WILDERNESS );
   ch->cords[0] = x;
   ch->cords[1] = y;
}

/* Allow them to move around the wilderness */
void move_around_wilderness( CHAR_DATA *ch, short dir, char *str )
{
   CHAR_DATA *fch, *nextinroom, *master;
   int x = 0, y = 0, chx = 0, chy = 0, moveloss = 0, sector = 0, oldchx, oldchy;

   if( !ch || !str || str[0] == '\0' )
      return;

   desccount = 0;
   desccheck = 0;

   chx = ch->cords[0];
   oldchx = ch->cords[0];
   chy = ch->cords[1];
   oldchy = ch->cords[1];

   if( dir == 0 ) /* North */
      chy--; /* Line before */
   else if( dir == 1 ) /* South */
      chy++; /* Line below */
   else if( dir == 2 ) /* East */
      chx++; /* Next character */
   else if( dir == 3 ) /* West */
      chx--; /* Previous character */
   else if( dir == 4 ) /* NE */
   {
      chy--; /* Line before */
      chx++; /* Next character */
   }
   else if( dir == 5 ) /* NW */
   {
      chy--; /* Line before */
      chx--; /* Previous character */
   }
   else if( dir == 6 ) /* SE */
   {
      chy++; /* Line below */
      chx++; /* Next character */
   }
   else if( dir == 7 ) /* SW */
   {
      chy++; /* Line below */
      chx--; /* Previous character */
   }

   if( chy < 0 || chx < 0 )
   {
      send_to_char( "You can't go that way.\r\n", ch );
      return;
   }

   /* Parse the description and add in color etc... for where they are */
   for( ; *str != '\0'; )
   {
      if( *str != '\r' && *str != '\n' && x == chx && y == chy ) /* Ok so it is there and valid */
      {
         /* These you can't go to */
         if( *str == ' ' )
         {
            send_to_char( "You can't go that way.\r\n", ch );
            return;
         }

         /* Since we have the character now lets set up the movement loss */
         /* Only loose movement if not on a mount */
         if( *str == '^' ) /* Mountain */
            sector = SECT_MOUNTAIN;
         else if( *str == '*' ) /* Field */
            sector = SECT_FIELD;
         else if( *str == '~' )
            sector = SECT_WATER_SWIM;
         else /* Default of the Inside */
            sector = SECT_INSIDE;

         moveloss = 1;

         if( ( ch->mount && ( !should_follow_wilderness( ch, ch->mount ) || !is_floating( ch->mount ) ) ) || !is_floating( ch ) )
            moveloss = movement_loss[ URANGE( 0, sector, SECT_MAX - 1 ) ];;

         if( ch->mount && should_follow_wilderness( ch, ch->mount ) )
         {
            if( ch->mount->move < moveloss )
            {
               send_to_char( "Your mount is to exhausted.\r\n", ch );
               return;
            }
            move_around_wilderness( ch->mount, dir, ch->in_room->description );
         }
         else /* Only take movement if no mount since mount will loose when it is done */
         {
            if( ch->move < moveloss )
            {
               send_to_char( "Your to exhausted.\r\n", ch );
               return;
            }
            ch->move -= moveloss;
         }

         ch->cords[0] = chx;
         ch->cords[1] = chy;
         do_look( ch, (char *)"auto" );
         ch->cords[0] = oldchx;
         ch->cords[1] = oldchy;

         for( fch = ch->in_room->first_person; fch; fch = nextinroom )
         {
            nextinroom = fch->next_in_room;

            if( fch == ch || !fch->master )
               continue;

            master = fch->master;
            while( master->master )
               master = master->master;

            if( master != ch || xIS_SET( ch->act, PLR_SOLO ) || xIS_SET( fch->act, PLR_SOLO ) )
               continue;

            if( fch->position != POS_STANDING && fch->position != POS_MOUNTED )
               continue;

            if( !should_follow_wilderness( ch, fch ) )
               continue;

            act( AT_ACTION, "You follow $N.", fch, NULL, master, TO_CHAR );
            move_around_wilderness( fch, dir, fch->in_room->description );
         }

         ch->cords[0] = chx;
         ch->cords[1] = chy;

         return;
      }

      /* Should do this after the other checks */
      if( *str != '\r' && *str != '\n' )
         x++;
      if( *str == '\n' )
      {
         x = 0;
         y++;
      }

      str++;
   }

   send_to_char( "You can't go that way.\r\n", ch );
}

void parse_wilderness_description( CHAR_DATA *ch, char *str )
{
   int x = 0, y = 0;

   if( !ch || !str || str[0] == '\0' )
      return;

   desccount = 0;
   desccheck = 0;

   /* Parse the description and add in color etc... for where they are */
   for( ; *str != '\0'; )
   {
      if( x == ch->cords[0] && y == ch->cords[1] && is_in_wilderness( ch ) )
      {
         showdescription[desccount++] = '&';
         showdescription[desccount++] = 'r';
         if( *str == '&' || *str == '^' || *str == '}' )
            showdescription[desccount++] = *str;
         showdescription[desccount++] = *str;
         showdescription[desccount++] = '&';
         showdescription[desccount++] = 'D';
      }
      else
      {
         if( *str == '&' || *str == '^' || *str == '}' )
            showdescription[desccount++] = *str;
         showdescription[desccount++] = *str;
      }

      if( *str != '\n' && *str != '\r' )
         x++;
      if( *str == '\n' )
      {
         x = 0;
         y++;
      }

      str++;
   }
   showdescription[desccount] = '\0';

   send_to_char( showdescription, ch );
}

bool is_same_cords( OBJ_DATA *obj, CHAR_DATA *ch )
{
   if( !obj || !ch )
      return false;
   if( !xIS_SET( obj->extra_flags, ITEM_WILDERNESS ) && !is_in_wilderness( ch ) )
      return true;
   if( xIS_SET( obj->extra_flags, ITEM_WILDERNESS ) && is_in_wilderness( ch )
   && obj->cords[0] == ch->cords[0] && obj->cords[1] == ch->cords[1] )
      return true;
   return false;
}

bool should_follow_wilderness( CHAR_DATA *ch, CHAR_DATA *rch )
{
   if( !ch || !rch )
      return false;

   if( is_in_wilderness( ch ) )
   {
      if( is_in_wilderness( rch ) && ch->cords[0] == rch->cords[0] && ch->cords[1] == rch->cords[1] )
         return true;
   }

   if( !is_in_wilderness( ch ) )
   {
      if( !is_in_wilderness( rch ) )
         return true;
   }

   return false;
}

CMDF( do_wilderness )
{
   CHAR_DATA *fch, *nextinroom, *master;

   if( !ch || !ch->in_room )
      return;

   if( !xIS_SET( ch->in_room->room_flags, ROOM_WILDERNESS ) )
   {
      /* Just incase for some reason not in the room any more */
      if( is_npc( ch ) )
         xREMOVE_BIT( ch->act, ACT_WILDERNESS );
      else
         xREMOVE_BIT( ch->act, PLR_WILDERNESS );
      ch->cords[0] = 0;
      ch->cords[1] = 0;
      send_to_char( "You aren't currently in a wilderness room.\r\n", ch );
      return;
   }

   if( ch->mount && should_follow_wilderness( ch, ch->mount ) )
      do_wilderness( ch->mount, (char *)"" );

   for( fch = ch->in_room->first_person; fch; fch = nextinroom )
   {
      nextinroom = fch->next_in_room;
 
      if( fch == ch || !fch->master )
         continue;

      master = fch->master;
      while( master->master )
         master = master->master;

      if( master != ch || xIS_SET( ch->act, PLR_SOLO ) || xIS_SET( fch->act, PLR_SOLO ) )
         continue;

      if( fch->position != POS_STANDING && fch->position != POS_MOUNTED )
         continue;

      if( !should_follow_wilderness( ch, fch ) )
         continue;

      do_wilderness( fch, (char *)"" );
   }

   ch->cords[0] = 0;
   ch->cords[1] = 0;

   if( is_npc( ch ) )
   {
      xTOGGLE_BIT( ch->act, ACT_WILDERNESS );
      if( xIS_SET( ch->act, ACT_WILDERNESS ) )
         send_to_char( "You enter the wilderness.\r\n", ch );
      else
         send_to_char( "You emerge from the wilderness.\r\n", ch );
   }
   else
   {
      xTOGGLE_BIT( ch->act, PLR_WILDERNESS );
      if( xIS_SET( ch->act, PLR_WILDERNESS ) )
         send_to_char( "You enter the wilderness.\r\n", ch );
      else
         send_to_char( "You emerge from the wilderness.\r\n", ch );
   }
}

void obj_to_char_cords( OBJ_DATA *obj, CHAR_DATA *ch )
{
   if( !obj || !ch || !ch->in_room )
      return;
   if( !xIS_SET( ch->in_room->room_flags, ROOM_WILDERNESS ) )
      return;
   if( !is_in_wilderness( ch ) )
      return;
   /* Should be good to set it now */
   xSET_BIT( obj->extra_flags, ITEM_WILDERNESS );
   obj->cords[0] = ch->cords[0];
   obj->cords[1] = ch->cords[1];
}

bool can_see_character( CHAR_DATA *ch, CHAR_DATA *rch )
{
   if( !ch || !rch || !ch->in_room || !rch->in_room )
      return false;

   if( !xIS_SET( ch->in_room->room_flags, ROOM_WILDERNESS ) )
      return true;

   /* If not set to wilderness */
   if( !is_in_wilderness( ch ) )
   {
      /* This one is so just skip them */
      if( is_in_wilderness( rch ) )
         return false;
   }

   /* Is set to wilderness */
   if( is_in_wilderness( ch ) )
   {
      /* This one isn't so just skip them */
      if( !is_in_wilderness( rch ) )
         return false;

      /* If not in the same spot continue */
      if( ch->cords[0] != rch->cords[0] || ch->cords[1] != rch->cords[1] )
         return false;
   }

   return true;
}

bool is_in_wilderness( CHAR_DATA *ch )
{
   if( !ch )
   {
      bug( "%s: NULL ch", __FUNCTION__ );
      return false;
   }
   if( !ch->in_room || !xIS_SET( ch->in_room->room_flags, ROOM_WILDERNESS ) )
      return false;
   if( is_npc( ch ) && xIS_SET( ch->act, ACT_WILDERNESS ) )
      return true;
   if( !is_npc( ch ) && xIS_SET( ch->act, PLR_WILDERNESS ) )
      return true;
   return false;
}

/* Lets set them to the cords if we need to */
void set_loc_cords( CHAR_DATA *ch )
{
   if( !loc_in_wilderness || !ch )
      return;
   if( is_npc( ch ) )
      xSET_BIT( ch->act, ACT_WILDERNESS );
   else
      xSET_BIT( ch->act, PLR_WILDERNESS );
   ch->cords[0] = loc_cords[0];
   ch->cords[1] = loc_cords[1];
}

void char_to_char_cords( CHAR_DATA *ch, CHAR_DATA *victim )
{
   if( !ch || !victim )
      return;
   if( !is_in_wilderness( ch ) )
      return;
   if( is_npc( ch ) )
      xSET_BIT( victim->act, ACT_WILDERNESS );
   else
      xSET_BIT( victim->act, PLR_WILDERNESS );
   victim->cords[0] = ch->cords[0];
   victim->cords[1] = ch->cords[1];
}