1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/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 improvements 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.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#include "merc.h"

char map_chars[5] = "|-|-";
char map_chars_closed[5] = "I=I=";
char lcolor = 'x';
int depth = 0;

#define    MAXDEPTH  4
#define    MAPX     10
#define    MAPY      8
#define    BOUNDARY(x, y) (((x) < 0) || ((y) < 0) || \
((x) > (MAPX * 2)) || ((y) > (MAPY * 2))) \

struct map_type
{

  char symbol;
  int depth;
  RoomIndex *pRoom;
};

typedef struct map_type MAP_DATA;

MAP_DATA map[(MAPX * 2) + 1][(MAPY * 2) + 1];

void
get_exit_dir (int dir, int *x, int *y, int xorig, int yorig)
{
  switch (dir)
    {
    case 0:
      *x = xorig;
      *y = yorig - 1;
      break;
    case 1:
      *x = xorig + 1;
      *y = yorig;
      break;
    case 2:
      *x = xorig;
      *y = yorig + 1;
      break;
    case 3:
      *x = xorig - 1;
      *y = yorig;
      break;
    default:
      *x = -1;
      *y = -1;
      break;
    }
}

void
clear_coord (int x, int y)
{
  map[x][y].symbol = ' ';
  map[x][y].depth = 0;
  map[x][y].pRoom = NULL;
}

struct sector_color_type
{
  sector_t bit;
  const char *display_color;
  char display_symbol;
};

const struct sector_color_type sector_color_table[SECT_MAX] = {
  {
   SECT_INSIDE, "{w", 'o'},
  {SECT_CITY, "{W", 'o'},
  {SECT_FIELD, "{G", '*'},
  {SECT_FOREST, "{g", '*'},
  {SECT_HILLS, "{y", '!'},
  {SECT_MOUNTAIN, "{w", '@'},
  {SECT_WATER_SWIM, "{B", '='},
  {SECT_WATER_NOSWIM, "{b", '='},
  {SECT_ICE, "{C", 'O'},
  {SECT_AIR, "{C", '~'},
  {SECT_DESERT, "{y", '+'},
  {SECT_ROAD, "{m", ':'},
  {SECT_PATH, "{M", ':'},
  {SECT_SWAMP, "{G", '&'},
  {SECT_CAVE, "{w", '#'},
  {SECT_NONE, "{w", '?'}
};

const char *
get_sector_color (sector_t sector)
{
  int looper;

  for (looper = 0; looper < SECT_MAX; looper++)
    if (sector_color_table[looper].bit == sector)
      return (sector_color_table[looper].display_color);

  return "";
}

char
get_sector_symbol (sector_t sector)
{
  int looper;

  for (looper = 0; looper < SECT_MAX; looper++)
    if (sector_color_table[looper].bit == sector)
      return (sector_color_table[looper].display_symbol);

  return '?';
}

void
map_exits (CharData * ch, RoomIndex * pRoom, int x, int y)
{
  int door;
  int exitx = 0, exity = 0;
  int roomx = 0, roomy = 0;
  ExitData *pExit;

  if (!can_see_room (ch, pRoom))
    return;

  map[x][y].symbol = get_sector_symbol (pRoom->sector_type);
  map[x][y].depth = depth;
  map[x][y].pRoom = pRoom;

  if (depth >= MAXDEPTH)
    return;

  for (door = DIR_NORTH; door <= DIR_DOWN; door++)
    {
      if ((pExit = pRoom->exit[door]) == NULL)
	continue;

      if (IsSet (pExit->exit_info, EX_CLOSED))
	continue;

      if (pExit->u1.to_room == NULL)
	continue;

      if (!can_see_room (ch, pExit->u1.to_room))
	continue;

      get_exit_dir (door, &exitx, &exity, x, y);
      get_exit_dir (door, &roomx, &roomy, exitx, exity);

      if (BOUNDARY (exitx, exity) || BOUNDARY (roomx, roomy))
	continue;

      if (depth == MAXDEPTH)
	continue;

      map[exitx][exity].depth = depth;
      if (IsSet (pExit->exit_info, EX_CLOSED))
	map[exitx][exity].symbol = map_chars_closed[door];
      else
	map[exitx][exity].symbol = map_chars[door];
      map[exitx][exity].pRoom = pExit->u1.to_room;

      if ((depth < MAXDEPTH)
	  && ((map[roomx][roomy].pRoom == pExit->u1.to_room)
	      || (map[roomx][roomy].pRoom == NULL)))
	{
	  depth++;
	  map_exits (ch, pExit->u1.to_room, roomx, roomy);
	  depth--;
	}
    }
}

char *
reformat_desc (char *desc)
{
  size_t l, m;
  static char buf[MPL];

  l = 0;
  m = 0;
  buf[0] = '\0';

  if (NullStr (desc))
    return "";


  for (m = 0; m <= strlen (desc); m++)
    if (desc[m] == '\n' || desc[m] == '\r')
      desc[m] = '\x20';


  for (m = 0; desc[m] != '\0'; m++)
    {
      if (desc[m] == '\x20' && desc[m + 1] == '\x20')
	{
	  buf[l++] = ' ';
	  do
	    {
	      m++;
	    }
	  while (desc[m] == '\x20');
	}
      buf[l++] = desc[m];
    }
  buf[l] = '\0';

  return buf;
}

size_t
get_line_len (char *desc, size_t max_len)
{
  size_t m, l;
  char buf[MSL];

  if (strlen (desc) <= max_len)
    return 0;

  buf[0] = '\0';
  l = 0;

  for (m = 0; m <= strlen (desc); m++)
    {
      if (desc[m] == COLORCODE)
	{
	  int k = ansi_skip (&desc[m]);

	  m += k;
	  if (k == 1)
	    lcolor = desc[m];
	}
      else if (desc[m] == CUSTOMSTART)
	{
	  do
	    {
	      m++;
	    }
	  while (desc[m] != CUSTOMEND);
	}
      else if (desc[m] == MXP_BEGc)
	{
	  do
	    {
	      m++;
	    }
	  while (desc[m] != MXP_ENDc);
	}
      else
	{
	  if (++l > max_len)
	    break;
	}
    }

  for (l = m; l > 0; l--)
    if (desc[l] == ' ')
      break;

  return l + 1;
}

void
show_map (CharData * ch, char *text, bool fSmall)
{
  char buf[MSL * 2];
  size_t x, y, m, n, pos;
  char *p;
  bool alldesc = false;
  double rcnt = (double) (areacount (ch, ch->in_room->area));
  double rooms = (double) (arearooms (ch->in_room->area));
  int maxlen = get_scr_cols (ch);
  int maplen = maxlen - 15;

  if (fSmall)
    {
      m = 4;
      n = 5;
    }
  else
    {
      m = 0;
      n = 0;
    }
  pos = 0;
  p = text;
  buf[0] = '\0';
  lcolor = 'x';

  if (fSmall)
    {

      if (IsNPC (ch) || IsSet (ch->in_room->room_flags, ROOM_NOEXPLORE))
	sprintf (buf, "{R+------------+{%c ", lcolor);
      else
	sprintf (buf, "{R+-----[{x%3.0f%%{R]+{%c ",
		 Percent (rcnt, rooms), lcolor);

      if (!alldesc)
	{
	  pos = get_line_len (p, maplen);
	  if (pos > 0)
	    {
	      strncat (buf, p, pos);
	      p += pos;
	    }
	  else
	    {
	      strcat (buf, p);
	      alldesc = true;
	    }
	}
      strcat (buf, NEWLINE);
    }

  for (y = m; y <= (MAPY * 2) - m; y++)
    {
      if (fSmall)
	strcat (buf, "{R|");
      else
	strcat (buf, "{D");

      for (x = n; x <= (MAPX * 2) - n; x++)
	{
	  if (map[x][y].pRoom)
	    {
	      if (map[x][y].symbol ==
		  get_sector_symbol (map[x][y].pRoom->sector_type)
		  && !IsNPC (ch)
		  && StrIsSet (ch->pcdata->explored, map[x][y].pRoom->vnum))
		{
		  if (map[x][y].pRoom->exit[DIR_UP]
		      && map[x][y].pRoom->exit[DIR_DOWN])
		    map[x][y].symbol = 'B';
		  else if (!map[x][y].pRoom->exit[DIR_UP]
			   && map[x][y].pRoom->exit[DIR_DOWN])
		    map[x][y].symbol = 'D';
		  else if (map[x][y].pRoom->exit[DIR_UP]
			   && !map[x][y].pRoom->exit[DIR_DOWN])
		    map[x][y].symbol = 'U';
		}
	      if (!fSmall)
		sprintf (buf + strlen (buf), " %s%c{D",
			 get_sector_color (map[x][y].pRoom->sector_type),
			 map[x][y].symbol);
	      else
		sprintf (buf + strlen (buf), "%s%c",
			 get_sector_color (map[x][y].pRoom->sector_type),
			 map[x][y].symbol);
	    }
	  else
	    {
	      if (!fSmall)
		strcat (buf, " {D.");
	      else
		strcat (buf, " ");
	    }
	}
      if (!fSmall)
	{
	  switch (y)
	    {
	    case 0:
	      strcat (buf, "   {xX   You are here");
	      break;
	    case 2:
	      strcat (buf, "   {xo   Normal Rooms");
	      break;
	    case 3:
	      strcat (buf, "   {xU   Room with exit up");
	      break;
	    case 4:
	      strcat (buf, "   {xD   Room with exit down");
	      break;
	    case 5:
	      strcat (buf, "   {xB   Room with exits up & down");
	      break;
	    case 6:
	      strcat (buf, "   {x|-  Exits");
	      break;
	    case 7:
	      strcat (buf, "   {x>I< Closed Doors");
	      break;
	    case 8:
	      strcat (buf, "   {x*   Field/Forest");
	      break;
	    case 9:
	      strcat (buf, "   {x!   Hills");
	      break;
	    case 10:
	      strcat (buf, "   {x@   Mountain");
	      break;
	    case 11:
	      strcat (buf, "   {x=   Water");
	      break;
	    case 12:
	      strcat (buf, "   {x~   Air");
	      break;
	    case 13:
	      strcat (buf, "   {x+   Desert");
	      break;
	    case 14:
	      strcat (buf, "   {x:   Road/Path");
	      break;
	    case 15:
	      strcat (buf, "   {x&   Swamp");
	      break;
	    case 16:
	      strcat (buf, "   {x#   Cave");
	      break;
	    case 17:
	      strcat (buf, "   {x?   Unknown");
	      break;
	    default:
	      strcat (buf, "   {x");
	      break;
	    }
	  strcat (buf, NEWLINE);
	}
      else
	{
	  sprintf (buf + strlen (buf), "{R| {%c", lcolor);

	  if (!alldesc)
	    {
	      pos = get_line_len (p, maplen);
	      if (pos > 0)
		{
		  strncat (buf, p, pos);
		  p += pos;
		}
	      else
		{
		  strcat (buf, p);
		  alldesc = true;
		}
	    }
	  strcat (buf, NEWLINE);
	}
    }

  if (!fSmall)
    chprintlnf (ch, "%s" NEWLINE "%s{x%s", draw_line (ch, NULL, 0), buf,
		draw_line (ch, NULL, 0));
  else
    {
      sprintf (buf + strlen (buf), "{R+-----------+{%c ", lcolor);

      if (!alldesc)
	{
	  pos = get_line_len (p, maplen);
	  if (pos > 0)
	    {
	      strncat (buf, p, pos);
	      p += pos;
	    }
	  else
	    {
	      strcat (buf, p);
	      alldesc = true;
	    }
	}

      if (!alldesc)
	{
	  do
	    {
	      pos = get_line_len (p, maxlen);
	      if (pos > 0)
		{
		  strncat (buf, p, pos);
		  p += pos;
		}
	      else
		{
		  strcat (buf, p);
		  alldesc = true;
		}
	    }
	  while (!alldesc);
	}
      strcat (buf, "{x");
      chprint (ch, buf);
    }
}

void
draw_map (CharData * ch, const char *desc)
{
  int x, y;
  char *buf;
  bool fSmall;

  if (NullStr (desc))
    {
      buf = (char *) desc;
      fSmall = false;
    }
  else
    {
      buf = reformat_desc ((char *) desc);
      fSmall = true;
    }

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

  x = MAPX;
  y = MAPY;

  depth = (fSmall) ? 2 : 0;

  map_exits (ch, ch->in_room, x, y);

  map[x][y].symbol = 'X';
  show_map (ch, buf, fSmall);
}

Do_Fun (do_automap)
{
  if (IsNPC (ch))
    return;

  set_on_off (ch, &ch->act, PLR_AUTOMAP,
	      "You now see an automap in room descriptions.",
	      "You no longer see automap room descriptions.");
}

Do_Fun (do_map)
{
  if (IsNPC (ch))
    return;
  if (!ch->in_room)
    return;
  if (!check_blind (ch))
    return;

  draw_map (ch, NULL);

  return;
}