/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik Strfeldt, 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.                                               *
 *                                                                         *
 *  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.                                                  *
 ***************************************************************************/

/***************************************************************************
*    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                         *
****************************************************************************/

/***************************************************************************
* MapMaker originally created by
* Wendigo of Oblivionmud.static.net port 9000
* If you use this code, enjoy it, have bug fixes or simply want to
* chat, please feel free to email me at  kcaffet@hotmail.com (msn as well)
****************************************************************************/

/*
 * Installation of this snippet should be rather easy.  Simply put the file
 * in with the rest of your source code, edit your Makefile and add the
 * appropriate $.o file (where $ is the name of this file)
 * Declare a do_map in interp.h and add the command into interp.c
 *
 * This is a stand-alone file.  However, it is recommended that you move
 * many of these functions into their appropriate files (All the recycle
 * info into recycle.c and wnatnot.
 */

/* Commands for do_map are as follows:
 * (Note: Commands do not need to be issued in any order)
 * 
 * world: 	Area boundaries do not apply. It will go out as far as it
 * 			can into the world.  Not specifying world leaves it at the
 * 			default of area only
 * 			
 * tight:	Do not show room links(Not specifying will show links)
 * 
 * # > 0:	Ex: 4, 6, 30  Will show that many spaces away
 * 			from you, forming a box(not specifying will go until finished)
 * 			
 * # < 0:	Ex: -1, -5, -20  Will limit the map to that depth (positive)
 * 			(not specifying will go until finished)
 * 			
 * doors:	Will not go past closed doors.(Not Specified will go through
 * 			all doors)
 *
 * mob:		Will highlight squares with mobs in them (colour coded) (Not
 * 			specified will not show mob colours)
 *
 * terrain:	Will toggle terrain mode (rooms shown with terrain symbols)
 * 			(not specified will show regular area rooms)
 *
 * fog:		Enables fog mode (Will not go past certain terrain types)
 * 			(Not specified will go through all terrain types)
 *
 * border:	Adds a pretty border around the map. (not specified, no border)
 * 
 * Ex: 	map tight 8    	Will stay in the area, not show room links and only
 * 						go 8 spaces away from the user
 *
 * 		map 20 world	Area boundaries ignored, shows room links, goes 20
 * 						spaces away from the user
 *
 * 		map world tight mob terrain fog border doors
 * 						Yah..  Look at all the above options, apply them
 *
 * 	As a side note, colour code had to be reduced to a bare minimum due
 * 	to a resource limit on how much can be displayed at one time.
 * 	One line of 80 characters can take up a lot of space if every 
 * 	spot is used and has an extra 4-8 colour code characters in it.
 * 	
 * 	If you begin to experience disconnections when using the map at it's
 * 	maximum grid size, simply reduce the grid size.
 *
 * Here are the keys to generated maps:
 * - and |  are regular 2 way links
 * <, >, ^, v   are one way links
 * ), (, ",", `  are links that go e, w, n, s  but do not go to the room shown
 * =, /   is  1<->2   1 goes east, 2 goes west, but they do not go each other
 *
 * Bright blue *(room) has a down  BMagenta * has an up  BRed * has both
 * BGreen Link is a door   Green Link is not a door
 * '*' is a regular room  'S'  room has a shopkeeper  'P'  room has a pet store
 *
 */


#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h> 
#include <time.h> 
#include "merc.h"


#define MAX_MAP 77 // Shows 1/2 the given rooms (links) Always odd
#define MAP_MID 38 // Always 2x+1 to get MAX_MAP (makes the middle
#define MAX_MAP_HASH 16

// -1 is already taken, all positives are taken, so start lower
#define NS_2WAY		-2
#define NS_1WAYN	-3
#define NS_1WAYS	-4
#define NS_HIT		-5
#define EW_2WAY		-6
#define EW_1WAYE	-7
#define EW_1WAYW	-8
#define EW_HIT		-9
#define NS_2WAYD	-10
#define NS_1WAYND	-11
#define NS_1WAYSD	-12
#define NS_HITD		-13
#define EW_2WAYD	-14
#define EW_1WAYED	-15
#define EW_1WAYWD	-16
#define EW_HITD		-17
#define NS_UNN		-18
#define NS_UNS		-19
#define EW_UNE		-20
#define EW_UNW		-21
#define NS_UNND		-22
#define NS_UNSD		-23
#define EW_UNED		-24
#define EW_UNWD		-25

// Structures that are used.
typedef struct	map_qd		MAP_QD;
typedef struct	map_visit	MAP_VISIT;
typedef struct	map_param	MAP_PARAM;

// External information, used by many things.
extern MAP_QD *map_qd_free;
extern MAP_QD *map_queue;
extern MAP_VISIT *map_visit[MAX_MAP_HASH];
extern MAP_VISIT *map_visit_free;
extern int map[][];
extern MAP_PARAM *mp;

// Function definitions
void make_map			args ( (CHAR_DATA *ch, int x, int y) );
void add_to_map			args ( (CHAR_DATA *ch, ROOM_INDEX_DATA *room, int x, int y, int depth) );
void free_map_qd		args ( (MAP_QD *map_qd) );
MAP_QD *new_map_qd		args ( (void) );
void add_map_qd			args ( (MAP_QD *map_qd) );
MAP_QD *next_map_qd		args ( (void) );
void init_map			args ( (void) );
void init_mp			args ( (void) );
void show_map			args ( (CHAR_DATA *ch, int x, int y) );
MAP_VISIT *new_map_visit	args ( (void) );
void free_map_visit		args ( (MAP_VISIT *mapv) );
void add_visited		args ( (int room) );
bool has_visited		args ( (int room) );
void free_all_visits	args ( (void) );
int get_y_to			args ( (void) );
int get_x_to			args ( (void) );
int get_y_start			args ( (void) );
int get_x_start			args ( (void) );
int put_link			args ( (ROOM_INDEX_DATA *room, int other, int dir) );
char *get_link			args ( (int link_type) );
char *get_linkc			args ( (int link_type) );
char *get_mroom			args ( (CHAR_DATA *ch, int room) );
char *get_mroomc		args ( (CHAR_DATA *ch, int room) );
		
MAP_VISIT *map_visit[MAX_MAP_HASH];
MAP_VISIT *map_visit_free;
MAP_QD	*map_qd_free;
MAP_QD	*map_queue;
MAP_PARAM *mp;
int map[MAX_MAP][MAX_MAP];

// Map parameters  Saved here to avoid many arguments being used in map function
struct map_param
{
	bool area;
	bool tight;
	bool fog;
	int size;
	bool border;
	bool doors;
	int depth;
	bool col; // Used to add the default colour back if needed
	bool mobs;
	bool ter; // Switches to terrain mode.
};
	

// visited room
struct map_visit
{
	MAP_VISIT *next;
	int room;
	bool valid;
};

// Map queue data
struct map_qd
{
	MAP_QD *next;
	int room;
	int x;
	int y;
	int depth;
	bool valid;
};

// Free's all visited rooms from the map_visit hash table
void free_all_visits (void)
{
	MAP_VISIT *map, *map_next;
	int hash;

	for (hash = 0; hash < MAX_MAP_HASH; hash++)
	{
		for (map = map_visit[hash]; map != NULL; map = map_next)
		{
			map_next = map->next;
			free_map_visit(map);
		}
		map_visit[hash] = NULL;
	}
	return;
}

// Adds a room as visited
void add_visited (int room)
{
	MAP_VISIT *mv;
	int hash;

	hash = room % MAX_MAP_HASH;
	mv = new_map_visit();
	mv->room = room;

	mv->next = map_visit[hash];
	map_visit[hash] = mv;	
	
	return;
}

// Returns T/F if room was visited
bool has_visited (int room)
{
	MAP_VISIT *map;
	int hash;
	bool visited = FALSE;
	
	hash = room % MAX_MAP_HASH;

	for (map = map_visit[hash]; map != NULL; map = map->next)
	{
		if (map->room == room)
		{
			visited = TRUE;
			break;
		}
	}
	
	return visited;
}

// Initialized the map, sets all values in grid to -1
// As well it free's all previously visited rooms
void init_map (void)
{
	int x, y;

	for (x = 0; x < MAX_MAP; x++)	
		for (y = 0; y < MAX_MAP; y++)
			map[x][y] = -1;
	
	free_all_visits();
	
	return;
}

void init_mp (void)
{
	if (mp == NULL)
		mp = alloc_perm (sizeof(*mp));
	
	mp->area = FALSE;
	mp->tight = FALSE;
	mp->fog = FALSE;
	mp->size = MAP_MID;
	mp->border = FALSE;
	mp->doors = TRUE;
	mp->depth = -1;
	mp->col = FALSE;
	mp->mobs = FALSE;
	mp->ter = FALSE;
	return;
}

// Returns the colour of the link
char *get_linkc (int link)
{
	switch (link)
	{
		case NS_2WAYD:
		case NS_1WAYND:
		case NS_1WAYSD:
		case NS_HITD:
		case EW_2WAYD:
		case EW_1WAYED:
		case EW_1WAYWD:
		case EW_HITD:
		case NS_UNND:
		case NS_UNSD:
		case EW_UNED:
		case EW_UNWD:
			mp->col = TRUE;
			return "{w{G";		
		default:
			if (mp->col == TRUE)
			{
				mp->col = FALSE;
				return "{g";
			}
			else
				return "";
	}
	// Somethin goofed
	return "{g";
}

// Returns the character of the link
char *get_link (int link)
{
	switch (link)
	{
		case NS_2WAY:
		case NS_2WAYD:
			return "|";
		case NS_1WAYN:
		case NS_1WAYND:
			return "^";
		case NS_1WAYS:
		case NS_1WAYSD:
			return "v";
		case NS_HIT:
		case NS_HITD:
			return "/";
		case EW_2WAY:
		case EW_2WAYD:
			return "-";
		case EW_1WAYE:
		case EW_1WAYED:
			return ">";
		case EW_1WAYW:
		case EW_1WAYWD:
			return "<";
		case EW_HIT:
		case EW_HITD:
			return "=";
		case NS_UNN:
		case NS_UNND:
			return ",";
		case NS_UNS:
		case NS_UNSD:
			return "`";
		case EW_UNE:
		case EW_UNED:
			return ")";
		case EW_UNW:
		case EW_UNWD:
			return "(";
			
		default:
			return "?";
	}
	return "?";
}
// Returns the character of the room.
// Change as you like
char *get_mroom (CHAR_DATA *ch, int room)
{
	ROOM_INDEX_DATA *rm;
	CHAR_DATA *keeper;
	SHOP_DATA *shop;

	rm = get_room_index(room);
	shop = NULL;
	
	// Check for a shop. 
	for (keeper = rm->people; keeper; keeper = keeper->next_in_room)
	{
		if (IS_NPC(keeper) && (shop = keeper->pIndexData->pShop) != NULL)
			break;
	}

	if (mp->ter) // Terrain mode
	{
		switch (rm->sector_type)
		{
			case SECT_INSIDE:
				return "*";
			case SECT_CITY:
				return "+";
			case SECT_FIELD:
				return "o";
			case SECT_FOREST:
				return "f";
			case SECT_HILLS:
				return "z";
			case SECT_MOUNTAIN:
				return "x";
			case SECT_WATER_SWIM:
				return "~";
			case SECT_WATER_NOSWIM:
				return "~";
//			case SECT_UNUSED:
//				return "*";
			case SECT_AIR:
				return ".";
			case SECT_DESERT:
				return "!";
			default:
				return "*";
		}
	}
	// End Terrain mode
	
	if (shop != NULL) // Do we have a shop??
		return "S";
	else if (IS_SET (rm->room_flags, ROOM_PET_SHOP)) // How about a pet shop?
		return "P";

	// Default.
	return "*";
}
/* Returns the colour code of the room */
char *get_mroomc (CHAR_DATA *ch, int room)
{
	ROOM_INDEX_DATA *rm;
	CHAR_DATA *mob;
	int mtype = 0;

	rm = get_room_index(room);

	for (mob = rm->people; mob; mob = mob->next_in_room)
	{
		if (IS_NPC(mob))
		{
			if (IS_SET(mob->act, ACT_AGGRESSIVE))
			{
				mtype = 2;
				break;
			}
			else
				mtype = 1;
		}
	}

	if (mp->ter) // Terrain mode colour, if needed.  This will override exit and mob colours
	{
	}

	
	// Does it have an up and a down? Can they get there?
	if (	(rm->exit[DIR_UP] != NULL
				&& can_see_room(ch, rm->exit[DIR_UP]->u1.to_room))
			&& (rm->exit[DIR_DOWN] != NULL
				&& can_see_room(ch, rm->exit[DIR_DOWN]->u1.to_room))
			&& (mp->doors || (!IS_SET(rm->exit[DIR_UP]->exit_info, EX_CLOSED) || !IS_SET(rm->exit[DIR_DOWN]->exit_info, EX_CLOSED))))
	{
		mp->col = TRUE;
		if (mp->mobs && mtype == 1)
			return "\e[0;44m{R";
		else if (mp->mobs && mtype == 2)
			return "\e[0;41m{R";
		else
			return "{R";
	}
	else if (rm->exit[DIR_UP] != NULL
				&& can_see_room(ch, rm->exit[DIR_UP]->u1.to_room)
				&& (mp->doors || !IS_SET(rm->exit[DIR_UP]->exit_info, EX_CLOSED))) // Going up?
	{
		mp->col = TRUE;
		if (mp->mobs && mtype == 1)
			return "\e[0;44m{M";
		else if(mp->mobs && mtype == 2)
			return "\e[0;41m{M";
		else
			return "{M";
	}
	else if (rm->exit[DIR_DOWN] != NULL
				&& can_see_room(ch, rm->exit[DIR_DOWN]->u1.to_room)
				&& (mp->doors || !IS_SET(rm->exit[DIR_DOWN]->exit_info, EX_CLOSED))) // Going down..
	{
		mp->col = TRUE;
		if (mp->mobs && mtype == 1)
			return "\e[0;44m{B";
		else if (mp->mobs && mtype == 2)
			return "\e[0;41m{B";
		else
			return "{B";
	}	
	// Default.
	if (mp->col == TRUE)
	{
		if (mp->mobs && mtype == 1)
			return "\e[0;44;32m";
		else if (mp->mobs && mtype == 2)
			return "\e[0;41;32m";
		else
		{
			mp->col = FALSE;
			return "{g";
		}
	}
	else if (mp->mobs && mtype == 1)
	{
		mp->col = TRUE;
		return "\e[0;44;32m";
	}
	else if (mp->mobs && mtype == 2)
	{
		mp->col = TRUE;
		return "\e[0;41;32m";
	}
	else
		return "";
}

	

// Finds out what type of link to put between rooms
// returns the link number
int put_link (ROOM_INDEX_DATA *room, int next, int dir)
{
	ROOM_INDEX_DATA *other;
	EXIT_DATA  *exit, *org;
	int dir2;

	// Get the reverse dir
	dir2 = dir == 0 ? 2 : dir == 1 ? 3 : dir == 2 ? 0 : 1;

	if (next > 0) // Do we have a room there already?
	{
		other = get_room_index(next);
		exit = other->exit[dir2];
	}
	else
	{
		exit = room->exit[dir]->u1.to_room->exit[dir2];
		other = room->exit[dir]->u1.to_room;
	}
	
	org = room->exit[dir];

	if  (dir == DIR_NORTH) // I'm going north
	{
		if (exit == NULL) // 1 way?
		{
			if (other != NULL && org->u1.to_room == other) // Is the link to that room?
				return IS_SET(org->exit_info, EX_ISDOOR) ? NS_1WAYND : NS_1WAYN;
			else // Goes that way but not to that room
				return IS_SET(org->exit_info, EX_ISDOOR) ? NS_UNND : NS_UNN;
		}		
		else if (exit->u1.to_room == room) // 2 way?		
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_2WAYD : NS_2WAY;
		else if (exit->u1.to_room != room) // 2 way collide?
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_HITD : NS_HIT;
		else
			return -1;
	}
	else if (dir == DIR_SOUTH) // I'm going south
	{
		if (exit == NULL) // 1 way?
		{
			if (org->u1.to_room == other) // Is the link to that room?
				return IS_SET(org->exit_info, EX_ISDOOR) ? NS_1WAYSD : NS_1WAYS;
			else // Goes that way but not to that room
				return IS_SET(org->exit_info, EX_ISDOOR) ? NS_UNSD : NS_UNS;
		}
		else if (exit->u1.to_room == room) // 2 way?
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_2WAYD : NS_2WAY;
		else if (exit->u1.to_room != room) // 2 way collide?
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_HITD : NS_HIT;
		else
			return -1;
	}
	else if (dir == DIR_EAST) // I'm going east
	{
		if (exit == NULL) // 1 way?
		{
			if (org->u1.to_room == other) // Is the link to that room?
				return IS_SET(org->exit_info, EX_ISDOOR) ? EW_1WAYED : EW_1WAYE;
			else // Goes that way but no to that room
				return IS_SET(org->exit_info, EX_ISDOOR) ? EW_UNED : EW_UNE;
		}
		else if (exit->u1.to_room == room) // 2 way?
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_2WAYD : EW_2WAY;
		else if (exit->u1.to_room != room) // 2 way collide?
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_HITD : EW_HIT;
		else
			return -1;
	}
	else if(dir == DIR_WEST) // I'm going west
	{
		if (exit == NULL) // 1 way?
		{
			if (org->u1.to_room == other) // Is the link to that room?
				return IS_SET(org->exit_info, EX_ISDOOR) ? EW_1WAYWD : EW_1WAYW;
			else
				return IS_SET(org->exit_info, EX_ISDOOR) ? EW_UNWD : EW_UNW;
		}
		else if (exit->u1.to_room == room)
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_2WAYD : EW_2WAY;
		else if (exit->u1.to_room != room)
			return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_HITD : EW_HIT;
		else
			return -1;
	}
	else
		return -1;	
}

// Returns a new, clean map_visit
MAP_VISIT *new_map_visit (void)
{
	static MAP_VISIT mapv_zero;
	MAP_VISIT *mapv;

	if (map_visit_free == NULL)	
		mapv = alloc_perm (sizeof (*mapv));	
	else
	{
		mapv = map_visit_free;
		map_visit_free = map_visit_free->next;
	}

	*mapv = mapv_zero;

	mapv->next = NULL;
	mapv->room = -1;

	VALIDATE (mapv);
	return mapv;
}

// free's the map visit for future use
void free_map_visit (MAP_VISIT *mapv)
{
	if (!IS_VALID(mapv))
		return;
	INVALIDATE (mapv);
	mapv->next = map_visit_free;
	map_visit_free = mapv;
	return;
}

// Returns a new map queue data
MAP_QD *new_map_qd (void)
{
	static MAP_QD map_zero;
	MAP_QD *map;

	if (map_qd_free == NULL)	
		map = alloc_perm (sizeof (*map));	
	else
	{
		map = map_qd_free;
		map_qd_free = map_qd_free->next;
	}

	*map = map_zero;

	map->next = NULL;
	map->room = -1;
	map->x = -1;
	map->y = -1;

	VALIDATE (map);
	return map;
}
	
// Free map queue data
void free_map_qd (MAP_QD *mqd)
{
	if (!IS_VALID(mqd))
		return;
	INVALIDATE (mqd);
	mqd->next = map_qd_free;
	map_qd_free = mqd;
	return;
}

// Add an MQD to the queue
void add_map_qd (MAP_QD *mqd)
{
	MAP_QD *map;

	// Mark the room as visited
	add_visited(mqd->room);

	// Is there a mqd in the queue?  If not lets start it off
	if (map_queue == NULL)
	{
		map_queue = mqd;
		return;
	}

	// Lets add it at the end.  It has to wait in line..
	for (map = map_queue; map != NULL; map = map->next)
	{
		if (map->next == NULL)
		{
			map->next = mqd;
			break;
		}
	}
	return;	
}

// Returns the next queue waiting in line
MAP_QD *next_map_qd (void)
{
	MAP_QD *map;

	if (map_queue == NULL)
		return NULL;
	
	map = map_queue;
	map_queue = map_queue->next;
	return map;
}

// Command to start it all.  arguments are world, tight - lack of either defaults to area -, # (any number)
// all in any order you want
void do_map (CHAR_DATA *ch, char *argument)
{
	int x = MAP_MID, y = MAP_MID, size = -1;
	char arg[MSL];
	init_mp();

	for (argument = one_argument(argument, arg); arg[0] != '\0'; )
	{ // For every argument given..
		if (is_number(arg))
		{
			size = atoi(arg);
			if (size >= MAP_MID)
				mp->size = MAP_MID;
			else if (size > 0)
				mp->size = size;
			else if (size < 0)
				mp->depth = size * -1;
		}
		else if(!str_prefix(arg, "world"))
			mp->area = TRUE;
		else if(!str_prefix(arg, "tight"))
			mp->tight = TRUE;
		else if (!str_prefix(arg, "fog"))
			mp->fog = TRUE;
		else if (!str_prefix(arg, "border"))
			mp->border = TRUE;
		else if (!str_prefix(arg, "doors"))
			mp->doors = FALSE;
		else if (!str_prefix(arg, "mobs"))
			mp->mobs = TRUE;
		else if (!str_prefix(arg, "terrain"))
			mp->ter = TRUE;
		
		arg[0] = '\0';
		argument = one_argument (argument, arg);
	}
	if (!mp->tight && mp->size > 0) // It's not a tight map, so we double it's size to make up for the extra links
		mp->size *= 2;
	
	make_map (ch, x, y); // Create your map - most important part
	show_map (ch, x, y); // Use the show_map routine to display it - can create different routines to suit taste or need
	return;
}

// make the map.  Meat of the whole thing
void make_map (CHAR_DATA *ch, int x, int y)
{
	// Lets start out with a fresh grid and hash table
	init_map();

	// Add your startin point
	map[x][y] = ch->in_room->vnum;
	// Say you've visited your startin point
	add_visited(ch->in_room->vnum);
	
	// Use your starting point to begin the graphing process, with you in the middle
	add_to_map (ch, ch->in_room, x, y, 0);
	return;	
}

// get_?_start and get_?_to  functions are used to trim the map down so only the smallet, visible map is displayed
// returns their appropriate boundaries
int get_x_start (void)
{
	int y, x, size = mp->size;
	
	if (size < MAP_MID)
		return MAP_MID - size;
	else	
	{
		for (x = 0; x < MAX_MAP; x++)
		{
			for (y = 0; y < MAX_MAP; y++)
			{
				if (map[x][y] != -1)
					return x;
			}
		}
	}
/*		for (x = MAP_MID - size; x < MAX_MAP; x++)
		{
			for (y = 0; y < MAX_MAP; y++)
			{
				if (map[x][y] != -1)
					return x;
			}
		}
*/
	return MAX_MAP - 1;
}
// See above
int get_y_start (void)
{
	int y, x, size = mp->size;

	if (size < MAP_MID)
		return MAP_MID - size;
	else
	{
		for (y = 0; y < MAX_MAP; y++)
		{
			for (x = 0; x < MAX_MAP; x++)
			{
				if (map[x][y] != -1)
					return y;
			}
		}	
	}

/*		for (y = MAP_MID - size; y < MAX_MAP; y++)
		{
			for (x = 0; x < MAX_MAP; x++)
			{
				if (map[x][y] != -1)
					return y;
			}
		}
*/
	return MAX_MAP - 1;
}
// See above
int get_x_to (void)
{
	int y, x, size = mp->size;

	if (size < MAP_MID)
		return MAX_MAP - MAP_MID + size - 1;
	else
	{
		for (x = MAX_MAP - 1; x >= 0; x--)
		{
			for (y = 0; y < MAX_MAP; y++)
			{
				if (map[x][y] != -1)
					return x;
			}
		}
	}
/*	for (x = MAP_MID + size; x >= 0; x--)
		{
			for (y = 0; y < MAX_MAP; y++)
			{
				if (map[x][y] != -1)
					return x;
			}
		}
*/
	return 0;	
}
// See above
int get_y_to (void)
{
	int y, x, size = mp->size;

	if (size < MAP_MID)
		return MAX_MAP - MAP_MID + size - 1;
	else
	{
		for (y = MAX_MAP - 1; y >= 0; y--)
		{
			for (x = 0; x < MAX_MAP; x++)
			{
				if (map[x][y] != -1)
					return y;
			}
		}
	}
	
/*		for (y = MAP_MID + size; y >= 0; y--)
		{
			for (x = 0; x < MAX_MAP; x++)
			{
				if (map[x][y] != -1)
					return y;
			}
		}
*/
	return 0;
}

// The map display function
// Can be easily redone into a different show function to display mobs, terrain..  Anything you want
// After all, you know the room numbers for each room in the map and new links can be defined if needed
// Create as many different shows as you need.  show_map_mobs, show_map_terrain    for instance
void show_map (CHAR_DATA *ch, int xx, int yy)
{
	int x, x_to, x_from, y, y_to, y_from;
	char buf[MSL];
	
	// Get our trimming threashholds
	y_from = get_y_start();
	y_to = get_y_to();
	x_from = get_x_start();
	x_to = get_x_to();
	
	// Start out our buffer
	sprintf (buf, "%c", '\0');

	mp->col = TRUE;
	if (mp->border)
	{
		send_to_char ("{Y+", ch);
		for (x = x_from; x <= x_to; x++)
			send_to_char ("-", ch);
		send_to_char ("+\n\r", ch);
	}
	for (y = y_from; y <= y_to; y++)		
	{
		for (x = x_from; x <= x_to; x++)
		{
			if (map[x][y] != -1) // Is there something here?
			{
				if (map[x][y] < -1) // ? < -1 means a link type.  Lets buffer it
					sprintf (buf, "%s%s%s", buf, get_linkc(map[x][y]), get_link(map[x][y]));
				else if (xx == x && yy == y) // This is where we started.  Make sure to mark it with a special character
				{
					if (mp->col == TRUE)
						sprintf (buf, "%s{w{R@", buf);
					else
					{
						mp->col = TRUE;
						sprintf (buf, "%s{R@", buf);
					}
				}
				else // Must be a room
				{
					sprintf (buf, "%s%s%s", buf, get_mroomc(ch, map[x][y]), get_mroom(ch, map[x][y]));
				}
			}
			else // Nothing's here..  Make a blank space
			{
				if (mp->col == TRUE)
				{
					mp->col = FALSE;
					sprintf (buf, "%s{g ", buf);
				}
				else
					sprintf (buf, "%s ", buf);
			}
		}
		if (mp->border)
		{
			if (mp->col == TRUE)
				printf_to_char (ch, "{Y|%s{w{Y|\n\r", buf);
			else
				printf_to_char (ch, "{Y|%s{Y|\n\r", buf);

			mp->col = TRUE;
		}
		else
			printf_to_char (ch, "%s\n\r", buf); // Send a line out and start again
		sprintf (buf, "%c", '\0');
	}
	if (mp->border)
	{
		send_to_char ("{Y+", ch);
		for (x = x_from; x <= x_to; x++)
			send_to_char ("-", ch);
		send_to_char ("+{w\n\r", ch);
	}
	// We're done, so free the visits ( I know, it's done twice, but it's safer this way )
	free_all_visits();
	return;			
}

// Uses a combination of a queue and recursion.  Takes you, does all the rooms around you
// After that, it does all those rooms, then the rooms those generated..  until it stops
void add_to_map (CHAR_DATA *ch, ROOM_INDEX_DATA *room, int x, int y, int depth)
{
	EXIT_DATA *exit;
	MAP_QD *qd, *next_qd;
	int dir, num;
	bool fog, tight, aarea;
	int qroom, qx, qy, qdepth; // better memory management

	fog = mp->fog;
	tight = mp->tight;
	aarea = mp->area;
	
	
	// Go in all 4 directions NESW, add the lines then add to map the next room
	for (dir = 0; dir < 4; dir++)
	{
		if ((exit = room->exit[dir]) != NULL)
		{// We have an exit room to search!

			// Add your conditions for not mapping that room here.
			if (!can_see_room (ch, exit->u1.to_room) // Can they get there normally?
				|| (fog && exit->u1.to_room->sector_type == SECT_MOUNTAIN) // Is fog mod on?

				|| (mp->depth >= 0 && depth == mp->depth)
				|| (mp->doors == FALSE && IS_SET(exit->exit_info, EX_CLOSED)))
				continue;
			
			switch (dir)
			{
				case DIR_NORTH: // y - 1
					if (!tight) // Do we want our room links?
					{
						// Num is used to control if we do every second point as a room, or every point
						num = 2;
						if (y - 2 < 0) // Will we oversteap our bounds if we put try to put in this link?
							break;
						else
							map[x][y-1] = put_link (room, map[x][y-2], dir);
					}
					else
						num = 1;
					
					// Cases where we WON'T add this room, and thereby search it
					if (y - num < 0
						|| map[x][y-num] != -1
						|| (room->area != exit->u1.to_room->area && !aarea)
						|| has_visited(exit->u1.to_room->vnum))
						break;
					// It's passed the test, lets add it
					map[x][y-num] = exit->u1.to_room->vnum;
					qd = new_map_qd();
					qd->x = x;
					qd->y = y - num;
					qd->room = exit->u1.to_room->vnum;
					qd->depth = depth + 1;
					add_map_qd(qd);					
					break;
					
				case DIR_EAST: // x + 1
					if (!tight) // See all comments above.
					{
						num = 2;
						if (x + 2 > MAX_MAP - 1)
							break;
						else
							map[x+1][y] = put_link (room, map[x+2][y],  dir);
					}
					else
						num = 1;

					if (x + num > MAX_MAP - 1
						|| map[x+num][y] != -1
						|| (room->area != exit->u1.to_room->area && !aarea)
						|| has_visited(exit->u1.to_room->vnum))
						break;
					map[x+num][y] = exit->u1.to_room->vnum;
					qd = new_map_qd();
					qd->x = x + num;
					qd->y = y;
					qd->room = exit->u1.to_room->vnum;
					qd->depth = depth + 1;
					add_map_qd(qd);					
					break;
					
				case DIR_SOUTH: // y + 1
					if (!tight)
					{
						num = 2;
						if (y + 2 > MAX_MAP - 1)
							break;
						else
							map[x][y+1] = put_link (room, map[x][y+2], dir);
					}
					else
						num = 1;
					
					if (y + num > MAX_MAP - 1
						|| map[x][y+num] != -1
						|| (room->area != exit->u1.to_room->area && !aarea)
						|| has_visited(exit->u1.to_room->vnum))
						break;
					map[x][y+num] = exit->u1.to_room->vnum;
					qd = new_map_qd();
					qd->x = x;
					qd->y = y + num;
					qd->room = exit->u1.to_room->vnum;
					qd->depth = depth + 1;
					add_map_qd(qd);					
					break;
					
				case DIR_WEST: // x - 1
					if (!tight)
					{
						num = 2;
						if (x - 2 < 0)
							break;
						else
							map[x-1][y] = put_link (room, map[x-2][y], dir);
					}
					else
						num = 1;
					
					if (x - num < 0
						|| map[x-num][y] != -1
						|| (room->area != exit->u1.to_room->area && !aarea)
						|| has_visited(exit->u1.to_room->vnum))
						break;
					map[x-num][y] = exit->u1.to_room->vnum;
					qd = new_map_qd();
					qd->x = x - num;
					qd->y = y;
					qd->room = exit->u1.to_room->vnum;
					qd->depth = depth + 1;
					add_map_qd(qd);
					break;
				default:
					break;
			} // End of dir switch
		} // End of exit existing
	} // end of searching NESW from our point
	
	next_qd = next_map_qd(); // But wait!  Is there another room in the queue to search?

	if (next_qd != NULL)
	{ // Looks like it.  Lets search this point just like we did when we first started this whole thing
		qroom = next_qd->room;
		qx = next_qd->x;
		qy = next_qd->y;
		qdepth = next_qd->depth;
		// In this way I cn free the qdata before the recursive call, meaning it's available right away instead of after all the recursion is done.
		
		free_map_qd (next_qd);
		
		add_to_map (ch, get_room_index(qroom), qx, qy, qdepth);
	}
	return;
}