1stMUD/corefiles/
1stMUD/gods/
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 lcolor = 'x';

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

struct map_type
{
	char symbol;
	vnum_t vnum;
	int depth;
	flag_t info;
	bool up;
	bool dn;
};

typedef struct map_type MAP_DATA;

MAP_DATA map[MAPX + 1][MAPY + 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].up = FALSE;
	map[x][y].dn = FALSE;
	map[x][y].info = 0;
}

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 depth)
{
	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(ch->in_room->sector_type);
	map[x][y].vnum = pRoom->vnum;
	map[x][y].depth = depth;
	map[x][y].dn = FALSE;
	map[x][y].up = FALSE;

	if (!IS_NPC(ch) && getbit(ch->pcdata->explored, pRoom->vnum))
	{
		map[x][y].info = pRoom->room_flags;

		if (pRoom->exit[DIR_DOWN] != NULL)
			map[x][y].dn = TRUE;
		if (pRoom->exit[DIR_UP] != NULL)
			map[x][y].up = TRUE;
	}

	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;
		map[exitx][exity].symbol = map_chars[door];
		map[exitx][exity].info = pExit->exit_info;

		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 + 1);
			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 += 2;
		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] == ANSI_KEY)
		{
			lcolor = desc[l + 1];
			break;
		}
	}
	for (l = m; l > 0; l--)
		if (desc[l] == ' ')
			break;

	return l + 1;
}

void show_map(CHAR_DATA * ch, char *text)
{
	char buf[MSL * 2];
	int x, y, pos;
	char *p;
	bool alldesc = FALSE;
	int rcnt = areacount(ch);
	double rooms = (double) (arearooms(ch));
	double percent = (double) rcnt / (rooms / 100);
	int maxlen = (ch->desc
				  && ch->desc->scr_width > 0) ? ch->desc->scr_width - 2 : 78;
	int maplen = maxlen - 15;

	if (IS_NULLSTR(text))
		alldesc = TRUE;

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

	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 = 0; y <= MAPY; y++)
	{
		strcat(buf, "{R|{x");

		for (x = 0; x <= MAPX; x++)
		{
			if (map[x][y].symbol == 'o')
			{
				if (map[x][y].up && map[x][y].dn)
					map[x][y].symbol = 'O';
				if (!map[x][y].up && map[x][y].dn)
					map[x][y].symbol = 'D';
				if (map[x][y].up && !map[x][y].dn)
					map[x][y].symbol = 'U';
			}
			sprintf(buf + strlen(buf), "%s%c",
					get_sector_color(ch->in_room->sector_type),
					map[x][y].symbol);
		}

		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");
	}
	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];

	sprintf(buf, desc);

	reformat_desc(buf);

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

	x = MAPX / 2;
	y = MAPY / 2;

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

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

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

CH_CMD(do_automap)
{
	if (IS_NPC(ch))
		return;

	if (IS_SET(ch->act, PLR_AUTOMAP))
	{
		chprintln(ch, "Automap removed.");
		REMOVE_BIT(ch->act, PLR_AUTOMAP);
	}
	else
	{
		chprintln(ch, "Automap on.");
		SET_BIT(ch->act, PLR_AUTOMAP);
	}
}