1stMUD/corefiles/
1stMUD/gods/
1stMUD/notes/
1stMUD/player/
1stMUD/win32/
1stMUD/win32/ROM/
/**************************************************************************
*  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-2002 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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;
	vnum_t vnum;
	int depth;
	ROOM_INDEX_DATA *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].vnum = 0;
	map[x][y].depth = 0;
	map[x][y].pRoom = NULL;
}

void clear_room(int x, int y)
{
	int dir, exitx, exity;

	for (dir = DIR_NORTH; dir <= DIR_WEST; dir++)
	{
		get_exit_dir(dir, &exitx, &exity, x, y);
		if (!BOUNDARY(exitx, exity))
			clear_coord(exitx, exity);
	}
}

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

const struct sector_color_type sector_color_table[] = {
	{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_UNUSED, "{w", 'o'},
	{SECT_AIR, "{C", '~'},
	{SECT_DESERT, "{y", '+'},
	{SECT_MAX, "{w", 'o'}
};

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

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

char get_sector_symbol(int sector)
{
	int looper;

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

void map_exits(CHAR_DATA * ch, ROOM_INDEX_DATA * pRoom, int x, int y)
{
	int door;
	int exitx = 0, exity = 0;
	int roomx = 0, roomy = 0;
	EXIT_DATA *pExit;

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

	map[x][y].symbol = get_sector_symbol(pRoom->sector_type);
	map[x][y].vnum = pRoom->vnum;
	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 (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 ((map[roomx][roomy].vnum != 0)
			&& (map[roomx][roomy].vnum != pExit->u1.to_room->vnum)
			/* only clear exits and rooms of higher depth */
			&& map[roomx][roomy].depth > depth && depth < MAXDEPTH)
		{
			clear_room(roomx, roomy);
		}

		if (depth == MAXDEPTH)
			continue;

		map[exitx][exity].depth = depth;
		map[exitx][exity].vnum = pExit->u1.to_room->vnum;
		if (IS_SET(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].vnum == pExit->u1.to_room->vnum)
				|| (map[roomx][roomy].vnum == 0)))
		{
			depth++;
			map_exits(ch, pExit->u1.to_room, roomx, roomy);
			depth--;
		}
	}
}

void reformat_desc(char *desc)
{
	char *p;
	unsigned int l, m;
	char buf[MSL * 2];

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

	if (desc[0] == '\0')
		return;

	/* remove all \n & \r */
	for (m = 0; m <= strlen(desc); m++)
		if (desc[m] == '\n' || desc[m] == '\r')
			desc[m] = ' ';

	/* remove multiple spaces */
	for (p = desc; *p != '\0'; p++)
	{
		if (*p == ' ' && *(p + 1) == ' ')
		{
			buf[l] = *p;
			l++;
			do
			{
				p++;
			}
			while (*p == ' ');
		}
		buf[l] = *p;
		l++;
	}
	buf[l] = '\0';
	sprintf(desc, buf);

	return;
}

unsigned int get_line(char *desc, unsigned int max_len)
{
	unsigned int m;
	unsigned int 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] == ANSI_KEY)
		{
			m++;
			lcolor = desc[m];
			m++;
		}
		else if (desc[m] == ANSI_CUSTOM)
		{
			while (desc[m] != ANSI_END)
				m++;
			m++;
		}
		l++;

		if (l > max_len)
			break;
	}

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

	return l + 1;
}

void show_map(CHAR_DATA * ch, char *text, bool fSmall)
{
	char buf[MSL * 2];
	int x, y, m, n, pos;
	char *p;
	bool alldesc = FALSE;
	int rcnt = areacount(ch, ch->in_room->area);
	double rooms = (double) (arearooms(ch->in_room->area));
	double percent = UMIN((double) rcnt / (rooms / 100), 100);
	int maxlen = (ch->desc
				  && ch->desc->scr_width > 0) ? ch->desc->scr_width - 2 : 78;
	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 (IS_NPC(ch) || IS_SET(ch->in_room->room_flags, ROOM_NOEXPLORE))
			sprintf(buf, "{R+------------+{%c ", lcolor);
		else
			sprintf(buf, "{R+-----[{x%3.0f%%{R]+{%c ", percent, lcolor);

		if (!alldesc)
		{
			pos = get_line(p, maplen);
			if (pos > 0)
			{
				strncat(buf, p, pos);
				p += pos;
			}
			else
			{
				strcat(buf, p);
				alldesc = TRUE;
			}
		}
		strcat(buf, "\n\r");
	}

	for (y = m; y <= (MAPY * 2) - m; y++)
	{
		if (fSmall)
			strcat(buf, "{R|{x");
		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)
					&& !IS_NPC(ch)
					&& STR_IS_SET(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 != '.' ? map[x][y].symbol : ' ');
			}
			else
			{
				if (!fSmall)
				{
					strcat(buf, " ");
					strcat(buf, &map[x][y].symbol);
				}
				else
					strcat(buf,
						   map[x][y].symbol != '.' ? &map[x][y].symbol : " ");
			}
		}
		if (!fSmall)
		{
			switch (y)
			{
			case 0:
				strcat(buf, "   {xX   You are here\n\r");
				break;
			case 2:
				strcat(buf, "   {xo   Normal Rooms\n\r");
				break;
			case 3:
				strcat(buf, "   {xU   Room with exit up\n\r");
				break;
			case 4:
				strcat(buf, "   {xD   Room with exit down\n\r");
				break;
			case 5:
				strcat(buf, "   {xB   Room with exits up & down\n\r");
				break;
			case 6:
				strcat(buf, "   {x|-  Exits\n\r");
				break;
			case 7:
				strcat(buf, "   {x>I< Closed Doors\n\r");
				break;
			case 8:
				strcat(buf, "   {x*   Field/Forest/Hills\n\r");
				break;
			case 9:
				strcat(buf, "   {x@   Mountain\n\r");
				break;
			case 10:
				strcat(buf, "   {x=   Water\n\r");
				break;
			case 11:
				strcat(buf, "   {x~   Air\n\r");
				break;
			case 12:
				strcat(buf, "   {x+   Desert\n\r");
				break;
			default:
				strcat(buf, "   {x\n\r");
				break;
			}
		}
		else
		{
			strcat(buf, "{R| {");
			strcat(buf, &lcolor);
			if (!alldesc)
			{
				pos = get_line(p, maplen);
				if (pos > 0)
				{
					strncat(buf, p, pos);
					p += pos;
				}
				else
				{
					strcat(buf, p);
					alldesc = TRUE;
				}
			}
			strcat(buf, "\n\r");
		}
	}

	if (!fSmall)
		chprintlnf(ch, "%s\n\r%s%s", draw_line(ch, NULL, 0), buf,
				   draw_line(ch, NULL, 0));
	else
	{
		strcat(buf, "{R+-----------+{");
		strcat(buf, &lcolor);
		strcat(buf, " ");

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

		if (!alldesc)
		{
			do
			{
				pos = get_line(p, maxlen);
				if (pos > 0)
				{
					strncat(buf, p, pos);
					p += pos;
				}
				else
				{
					strcat(buf, p);
					alldesc = TRUE;
				}
			}
			while (!alldesc);
		}
		chprintln(ch, buf);
	}
}

void draw_map(CHAR_DATA * ch, const char *desc)
{
	int x, y;
	static char buf[MSL];
	bool fSmall;

	if (IS_NULLSTR(desc))
		fSmall = FALSE;
	else
	{
		fSmall = TRUE;
		sprintf(buf, desc);

		reformat_desc(buf);
	}

	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[x][y].vnum = ch->in_room->vnum;
	map[x][y].depth = depth;

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

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

CH_CMD(do_automap)
{
	if (IS_NPC(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.");
}

bool check_blind args((CHAR_DATA * ch));

CH_CMD(do_map)
{
	if (IS_NPC(ch))
		return;
	if (!ch->in_room)
		return;
	if (!check_blind(ch))
		return;

	draw_map(ch, NULL);

	return;
}