eldhamud/boards/
eldhamud/clans/
eldhamud/classes/
eldhamud/councils/
eldhamud/deity/
eldhamud/doc/
eldhamud/doc/DIKU/
eldhamud/doc/MERC/
eldhamud/doc/mudprogs/
eldhamud/houses/
eldhamud/src/o/CVS/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefitting.  We hope that you share your changes too.  What goes      *
*  around, comes around.                                                  *
***************************************************************************
*  Converted for AFKMud 1.64 by Zarius (jeff@mindcloud.com)               *
*  Downloaded from http://www.mindcloud.com                               *
*  If you like the snippet let me know                                    *
***************************************************************************/
/**************************************************************************
 * 	                       Version History                                *
 **************************************************************************
 *  (v1.0) - Converted Automapper to AFKMud 1.64 and added additional     *
 *           directions and removed room desc code into a sep func        *
 **************************************************************************/

/*
	 TO DO
   1. Add a way of displaying up and down directions effectively
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "mud.h"
#include "mapper.h"
//#include "mxp.h"
void show_char_to_char( CHAR_DATA *list, CHAR_DATA *ch );
void display_imm_toggle(CHAR_DATA *ch);

/* The map itself */
struct map_type map[MAPX + 1][MAPY + 1];

size_t mudstrlcat( char *dst, const char *src, size_t siz )
{
  register char *d = dst;
  register const char *s = src;
  register size_t n = siz;
  size_t dlen;

  /*
   * Find the end of dst and adjust bytes left but don't go past end 
   */
  while( n-- != 0 && *d != '\0' )
    d++;
  dlen = d - dst;
  n = siz - dlen;

  if( n == 0 )
    return ( dlen + strlen( s ) );
  while( *s != '\0' )
  {
    if( n != 1 )
    {
      *d++ = *s;
      n--;
    }
    s++;
  }
  *d = '\0';
  return ( dlen + ( s - src ) );   /* count does not include NUL */
}


char * roomdesc( CHAR_DATA *ch )
{
  static char outbuf[MAX_STRING_LENGTH];
  /* Build a room desc moved here -- Zarius */
  outbuf[0] = '\0';

  mudstrlcat( outbuf, color_str(AT_RMDESC, ch ), MAX_STRING_LENGTH); /* Set the color */
  mudstrlcat( outbuf, ch->in_room->description, MAX_STRING_LENGTH );


  return outbuf;
}


void do_showmap( CHAR_DATA *ch, char *argument )
{
  draw_map(ch, roomdesc( ch ));
  return;
}

/* Take care of some repetitive code for later */
void get_exit_dir( int dir, int *x, int *y, int xorig, int yorig )
{
  /* Get the next coord based on direction */
  switch( dir )
  {
  case 0: /* North */
    *x = xorig;
    *y = yorig - 1;
    break;
  case 1: /* East */
    *x = xorig + 1;
    *y = yorig;
    break;
  case 2: /* South */
    *x = xorig;
    *y = yorig + 1;
    break;
  case 3: /* West */
    *x = xorig - 1;
    *y = yorig;
    break;
  case 4: /* UP */
    break;
  case 5: /* DOWN */
    break;
  case 6: /* NE */
    *x = xorig + 1;
    *y = yorig - 1;
    break;
  case 7: /* NW */
    *x = xorig - 1;
    *y = yorig - 1;
    break;
  case 8: /* SE */
    *x = xorig + 1;
    *y = yorig + 1;
    break;
  case 9: /* SW */
    *x = xorig - 1;
    *y = yorig + 1;
    break;
  default:
    *x = -1;
    *y = -1;
    break;
  }
}

char *get_exits(CHAR_DATA *ch)
{
  static char buf[MAX_STRING_LENGTH];
  EXIT_DATA *pexit;
  bool found;

  buf[0] = '\0';

  if( !check_blind(ch) )
    return buf;

  set_char_color( AT_EXITS, ch );

  mudstrlcpy( buf, "&R[&DExits:", MAX_STRING_LENGTH );

  found = FALSE;
  for( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
  {
    if( IS_IMMORTAL(ch) )
      /* Immortals see all exits, even secret ones */
    {
      if( pexit->to_room )
      {
        found = TRUE;
        mudstrlcat( buf, " ", MAX_STRING_LENGTH );
        mudstrlcat( buf, capitalize( dir_name[pexit->vdir] ), MAX_STRING_LENGTH );
        if( IS_EXIT_FLAG(pexit, EX_OVERLAND) )
          mudstrlcat( buf, "&w->&R(&WOverland&R)&D", MAX_STRING_LENGTH );
        /* New code added to display closed, or otherwise invisible exits to immortals */
        /* Installed by Samson 1-25-98 */
        if( IS_EXIT_FLAG( pexit, EX_LOCKED ) && IS_EXIT_FLAG( pexit, EX_CLOSED ) )
          mudstrlcat( buf, "&w->&R(&WClosed & Locked&R)&D", MAX_STRING_LENGTH );
        else if( IS_EXIT_FLAG( pexit, EX_CLOSED ) )
          mudstrlcat( buf, "&w->&R(&WClosed&R)&D", MAX_STRING_LENGTH );
        if( IS_EXIT_FLAG( pexit, EX_WINDOW ) )
          mudstrlcat( buf, "&w->(Window)", MAX_STRING_LENGTH );
        if( IS_EXIT_FLAG( pexit, EX_HIDDEN ) )
          mudstrlcat( buf, "&w->&R(&WHidden&R)&D", MAX_STRING_LENGTH );
      }
    }
    else
    {
      if( pexit->to_room && !IS_EXIT_FLAG( pexit, EX_SECRET ) && ( !IS_EXIT_FLAG( pexit, EX_WINDOW )
          || IS_EXIT_FLAG( pexit, EX_ISDOOR ) ) && !IS_EXIT_FLAG( pexit, EX_HIDDEN ))
      {
        found = TRUE;
        mudstrlcat( buf, " ", MAX_STRING_LENGTH );
        mudstrlcat( buf, capitalize( dir_name[pexit->vdir] ), MAX_STRING_LENGTH );
        if( IS_EXIT_FLAG(pexit, EX_OVERLAND) )
          mudstrlcat( buf, "&w->&R(&WOverland&R)&D", MAX_STRING_LENGTH );
        if( IS_EXIT_FLAG( pexit, EX_LOCKED ) && IS_EXIT_FLAG( pexit, EX_CLOSED ) )
          mudstrlcat( buf, "&w->&R(&WClosed & Locked&R)&D", MAX_STRING_LENGTH );
        else if( IS_EXIT_FLAG( pexit, EX_CLOSED ) )
          mudstrlcat( buf, "&w->&R(&WClosed&R)&D", MAX_STRING_LENGTH );
      }
    }
  }

  if( !found )
  {
    mudstrlcat( buf, " none&R]&D", MAX_STRING_LENGTH );
  }
  else
  {
    mudstrlcat( buf, "&R]&D", MAX_STRING_LENGTH );
  }

  mudstrlcat( buf, "\n\r", MAX_STRING_LENGTH );
  return buf;
}


/* Clear one map coord */
void clear_coord( int x, int y )
{
  map[x][y].tegn = ' ';
  map[x][y].vnum = 0;
  map[x][y].depth = 0;
  xCLEAR_BITS( map[x][y].info );
  map[x][y].can_see = TRUE;
}

/* Clear all exits for one room */
void clear_room( int x, int y )
{
  int dir, exitx, exity;

  /* Cycle through the four directions */
  for( dir = 0; dir < 4; dir++ )
  {
    /* Find next coord in this direction */
    get_exit_dir( dir, &exitx, &exity, x, y );

    /* If coord is valid, clear it */
    if ( !BOUNDARY( exitx, exity ) ) clear_coord( exitx, exity );
  }
}

/* This function is recursive, ie it calls itself */
void map_exits(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoom, int x, int y, int depth)
{
  static char map_chars [11] = "|-|-UD/\\\\/";
  int door;
  int exitx = 0, exity = 0;
  int roomx = 0, roomy = 0;
  char buf[200]; // bugs
  EXIT_DATA *pExit;

  /* Setup this coord as a room */
  switch(pRoom->sector_type)
  {
  case SECT_CITY:
  case SECT_INSIDE:
    map[x][y].tegn = 'O';
    break;
  case SECT_FIELD:
  case SECT_FOREST:
  case SECT_HILLS:
    map[x][y].tegn = '*';
    break;
  case SECT_MOUNTAIN:
    map[x][y].tegn = '@';
    break;
  case SECT_WATER_SWIM:
  case SECT_WATER_NOSWIM:
    map[x][y].tegn = '=';
    break;
  case SECT_AIR:
    map[x][y].tegn = '~';
    break;
  case SECT_DESERT:
    map[x][y].tegn = '+';
    break;
  default:
    map[x][y].tegn = 'O';
    sprintf(buf, "Map_exits: Bad sector type (%d) in room %d.",
            pRoom->sector_type, pRoom->vnum);
    bug(buf, 0);
    break;
  }
  map[x][y].vnum = pRoom->vnum;
  map[x][y].depth = depth;
  map[x][y].info = pRoom->room_flags;
  map[x][y].can_see = room_is_dark( pRoom );

  /* Limit recursion */
  if ( depth > MAXDEPTH ) return;

  /* This room is done, deal with it's exits */
  for( door = 0; door < 10; door++ )
  {
    /* Skip if there is no exit in this direction */
    if ( ( pExit = get_exit( pRoom, door ) ) == NULL )
      continue;

    /* Skip up and down until I can figure out a good way to display it */
    if (door == 4 || door == 5)
      continue;

    /* Get the coords for the next exit and room in this direction */
    get_exit_dir( door, &exitx, &exity, x, y );
    get_exit_dir( door, &roomx, &roomy, exitx, exity );

    /* Skip if coords fall outside map */
    if ( BOUNDARY( exitx, exity ) || BOUNDARY( roomx, roomy )) continue;

    /* Skip if there is no room beyond this exit */
    if ( pExit->to_room == NULL ) continue;

    /* Ensure there are no clashes with previously defined rooms */
    if ( ( map[roomx][roomy].vnum != 0 ) &&
         ( map[roomx][roomy].vnum != pExit->to_room->vnum ))
    {
      /* Use the new room if the depth is higher */
      if ( map[roomx][roomy].depth <= depth ) continue;

      /* It is so clear the old room */
      clear_room( roomx, roomy );
    }

    /* No exits at MAXDEPTH */
    if ( depth == MAXDEPTH ) continue;

    /* No need for exits that are already mapped */
    if ( map[exitx][exity].depth > 0 ) continue;

    /* Fill in exit */
    map[exitx][exity].depth = depth;
    map[exitx][exity].vnum = pExit->to_room->vnum;
    //		map[exitx][exity].info = pExit->exit_info;
    map[exitx][exity].tegn = map_chars[door];

    /* More to do? If so we recurse */
    if ( ( depth < MAXDEPTH ) &&
         ( ( map[roomx][roomy].vnum == pExit->to_room->vnum ) ||
           ( map[roomx][roomy].vnum == 0 ) ) )
    {
      /* Depth increases by one each time */
      map_exits( ch, pExit->to_room, roomx, roomy, depth + 1 );
    }
  }
}

/* Reformat room descriptions to exclude undesirable characters */
void reformat_desc( char *desc )
{
  /* Index variables to keep track of array/pointer elements */
  unsigned int i;
  int j;
  char buf[MAX_STRING_LENGTH], *p;

  i = 0;
  j = 0;
  buf[0] = '\0';

  if ( !desc  ) return;

  /* Replace all "\n" and "\r" with spaces */
  for( i = 0; i <= strlen( desc ); i++ )
  {
    if ( ( desc[i] == '\n' ) || ( desc[i] == '\r' ) ) desc[i] = ' ';
  }

  /* Remove multiple spaces */
  for( p = desc; *p != '\0'; p++ )
  {
    buf[j] = *p;
    j++;

    /* Two or more consecutive spaces? */
    if ( ( *p == ' ' ) && ( *( p + 1 ) == ' ' ) )
    {
      do
      {
        p++;
      }
      while( *(p + 1) == ' ' );
    }
  }

  buf[j] = '\0';

  /* Copy to desc */
  mudstrlcpy( desc, buf, MAX_INPUT_LENGTH );
}

int get_line( char *desc, int max_len )
{
  int i, j = 0;

  /* Return if it's short enough for one line */
  if ( (int)strlen( desc ) <= max_len ) return 0;

  /* Calculate end point in string without color */
  for( i = 0; i <= (int)strlen( desc ); i++ )
  {
    /* Here you need to skip your color sequences */
    j++;

    if ( j > max_len ) break;
  }

  /* End point is now in i, find the nearest space */
  for( j = i; j > 0; j-- )
  {
    if ( desc[j] == ' ' ) break;
  }

  /* There could be a problem if there are no spaces on the line */
  return j + 1;
}

/* Display the map to the player */
void show_map( CHAR_DATA *ch, char *text )
{
  char buf[MAX_STRING_LENGTH * 2];
  int x, y, pos;
  char *p;
  bool alldesc = FALSE; /* Has desc been fully displayed? */

  if ( !text ) alldesc = TRUE;

  pos = 0;
  p = text;
  buf[0] = '\0';

  //if (y == 0 && IS_PLR_FLAG( ch, PLR_AUTOEXIT))  /* the autoexits */
  //{
  //  sprintf(buf + strlen( buf ), "%s", get_exits(ch));
  //  continue;
  //}


  /* Top of map frame */
  if (IS_PLR_FLAG( ch, PLR_AUTOEXIT )) /* Show exits */
    sprintf( buf, "&z+-----------+&w %s%s", color_str( AT_EXITS, ch ), get_exits(ch) );
  else
    sprintf( buf, "&z+-----------+&w\n\r" );

  /* Write out the main map area with text */
  for( y = 0; y <= MAPY; y++ )
  {
    mudstrlcat( buf, "&z|&D", MAX_STRING_LENGTH );

    for( x = 0; x <= MAPX; x++ )
    {
      switch(map[x][y].tegn)
      {
      case '-':
      case '|':
      case '\\':
      case '/':
        sprintf(buf + strlen(buf), "&O%c&D", map[x][y].tegn);
        break;
      case 'X':
        sprintf(buf + strlen(buf), "&R%c&d", map[x][y].tegn);
        break;
      case '*':
        sprintf(buf + strlen(buf), "&g%c&d", map[x][y].tegn);
        break;
      case '@':
        sprintf(buf + strlen(buf), "&r%c&d", map[x][y].tegn);
        break;
      case '=':
        sprintf(buf + strlen(buf), "&B%c&d", map[x][y].tegn);
        break;
      case '~':
        sprintf(buf + strlen(buf), "&C%c&d", map[x][y].tegn);
        break;
      case '+':
        sprintf(buf + strlen(buf), "&Y%c&d", map[x][y].tegn);
        break;
      case 'O':
        sprintf(buf + strlen(buf), "&w%c&d", map[x][y].tegn);
        break;
      default:
        sprintf( buf + strlen( buf ), "%c", map[x][y].tegn );
      }
    }
    mudstrlcat( buf, "&z|&D ", MAX_STRING_LENGTH );

    //if (y == 0 && IS_PLR_FLAG( ch, PLR_AUTOEXIT))  /* the autoexits */
    //{
    //	sprintf(buf + strlen( buf ), "%s", get_exits(ch));
    //	continue;
    //}

    /* Add the text, if necessary */
    if ( !alldesc )
    {
      pos = get_line( p, 63 );
      if ( pos > 0 )
      {
        mudstrlcat( buf, color_str(AT_RMDESC, ch), MAX_STRING_LENGTH);
        strncat( buf, p, pos );
        p += pos;
      }
      else
      {
        mudstrlcat( buf, color_str(AT_RMDESC, ch), MAX_STRING_LENGTH);
        mudstrlcat( buf, p, MAX_STRING_LENGTH );
        alldesc = TRUE;
      }
    }
    mudstrlcat( buf, "\n\r", MAX_STRING_LENGTH );
  }

  /* Finish off map area */
  mudstrlcat( buf, "&z+-----------+&D ", MAX_STRING_LENGTH );
  if ( !alldesc )
  {
    pos = get_line( p, 63 );
    if ( pos > 0 )
    {
      mudstrlcat( buf, color_str(AT_RMDESC, ch), MAX_STRING_LENGTH);
      strncat( buf, p, pos );
      p += pos;
    }
    else
    {
      mudstrlcat( buf, color_str(AT_RMDESC, ch), MAX_STRING_LENGTH);
      mudstrlcat( buf, p, MAX_STRING_LENGTH );
      alldesc = TRUE;
    }
  }

  /* Deal with any leftover text */
  if ( !alldesc )
  {
    do
    {
      /* Note the number - no map to detract from width */
      pos = get_line( p, 78 );
      if ( pos > 0 )
      {
        mudstrlcat( buf, color_str(AT_RMDESC, ch), MAX_STRING_LENGTH);
        strncat( buf, p, pos );
        p += pos;
      }
      else
      {
        mudstrlcat( buf, color_str(AT_RMDESC, ch), MAX_STRING_LENGTH);
        mudstrlcat( buf, p, MAX_STRING_LENGTH );
        alldesc = TRUE;
      }
    }
    while( !alldesc );
  }
  mudstrlcat(buf, "&D\n\r", MAX_STRING_LENGTH);
  send_to_char(buf, ch);
  display_imm_toggle(ch);

}

/* Clear, generate and display the map */
void draw_map( CHAR_DATA *ch, const char *desc )
{
  int x, y;
  static char buf[MAX_STRING_LENGTH];

  mudstrlcpy( buf, desc, MAX_INPUT_LENGTH );
  /* Remove undesirable characters */
  reformat_desc( buf );

  /* Clear map */
  for( y = 0; y <= MAPY; y++ )
  {
    for( x = 0; x <= MAPX; x++ )
    {
      clear_coord( x, y );
    }
  }

  /* Start with players pos at centre of map */
  x = MAPX / 2;
  y = MAPY / 2;

  map[x][y].vnum = ch->in_room->vnum;
  map[x][y].depth = 0;

  /* Generate the map */
  map_exits( ch, ch->in_room, x, y, 0 );

  /* Current position should be a "X" */
  map[x][y].tegn = 'X';
  /* Send the map */
  show_map( ch, buf );

  show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE );
  show_char_to_char( ch->in_room->first_person,  ch );
}