1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  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 *erase_new_lines(const char *desc)
{
	unsigned int l, m, sz;
	static char buf[MSL * 7];
	char temp[MSL * 7];

	if (NullStr(desc))
		return "";

	l = 0;
	m = 0;
	buf[0] = NUL;
	temp[0] = NUL;
	sz = strlen(desc);

	for (m = 0; m <= sz; m++)
	{
		if (desc[m] == '\n' || desc[m] == '\r')
			temp[m] = '\x20';
		else
			temp[m] = desc[m];
	}
	temp[m] = NUL;

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

		buf[l++] = temp[m];
	}
	buf[l] = NUL;
	return buf;

}

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

	if (NullStr(desc) || (sz = strlen(desc)) <= max_len)
		return 0;

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

	for (m = 0; m <= sz; 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);
		}

		if (++l > max_len)
			break;
	}

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

	return l + 1;
}

void show_map(CharData * ch, const char *text, bool fSmall)
{
	char buf[MSL * 2];
	size_t x, y, m, n, pos;
	const 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';

	if (fSmall)
	{

		if (IsNPC(ch) || IsSet(ch->in_room->room_flags, ROOM_NOEXPLORE))
			sprintf(buf, CTAG(_AUTOMAP) "+------------+{%c ", lcolor);
		else
			sprintf(buf,
					CTAG(_AUTOMAP) "+-----[{x%3.0f%%" CTAG(_AUTOMAP) "]+{%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, CTAG(_AUTOMAP) "|");
		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), CTAG(_AUTOMAP) "| {%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), CTAG(_AUTOMAP) "+-----------+{%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;
	const char *buf;
	bool fSmall;

	lcolor = 'x';

	if (NullStr(desc))
	{
		buf = desc;
		fSmall = false;
	}
	else
	{
		buf = erase_new_lines(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;
}