/******************************************************************************
*   TinTin++                                                                  *
*   Copyright (C) 2004 (See CREDITS file)                                     *
*                                                                             *
*   This program is protected under the GNU GPL (See COPYING)                 *
*                                                                             *
*   This program is free software; you can redistribute it and/or modify      *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   This program is distributed in the hope that it will be useful,           *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*   GNU General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with this program; if not, write to the Free Software               *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
******************************************************************************/

/******************************************************************************
*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
*                                                                             *
*                      coded by Igor van den Hoven 2004                       *
******************************************************************************/

#include "tintin.h"

/*
	todo:
*/

void create_legend(struct session *ses, char *arg);

int                 map_grid_x;
int                 map_grid_y;
int                 map_grid_z;

struct session    * map_search_ses;
struct exit_data  * map_search_exit_best;
struct exit_data  * map_search_exit_node;
int                 map_search_last_room;
int                 map_search_max_size;
int                 map_search_tar_room;

#define             MAP_SEARCH_SIZE 500

/*
	MUD font

	#map legend {128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 161}
	#map legend {144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 161}
*/

unsigned char	map_palet0[]	= { 42, 35, 35, 43, 35,124, 43, 43, 35, 43, 45, 43, 43, 43, 43, 43, 120};

unsigned char	map_palet1[]	= {126,247,247,109,247,120,108,116,247,106,113,118,107,117,119,110, 88};


DO_COMMAND(do_map)
{
	int cnt;
	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];

	arg = get_arg_in_braces(arg, arg1, FALSE);

	if (*arg1 == 0)
	{
		tintin_printf2(ses, "Available map options");
		tintin_printf2(ses, "");
		tintin_printf2(ses, "#map at       <location>  {command>    (execute command at given location)");
		tintin_printf2(ses, "#map color    <field>     <color>      (set the color for given field)");
		tintin_printf2(ses, "#map create   [size]                   (creates the initial map)");
		tintin_printf2(ses, "#map destroy                           (destroys the map)");
		tintin_printf2(ses, "#map delete   <direction>              (delete the room at given dir)");
		tintin_printf2(ses, "#map dig      <direction> [new] [vnum] (creates a new room)");
		tintin_printf2(ses, "#map exit     <direction>  <command>   (sets the exit command)");
		tintin_printf2(ses, "#map exitflag <direction> <exit flag>  (set the exit direction)");
		tintin_printf2(ses, "#map explore  <direction>              (saves path to #path)");
		tintin_printf2(ses, "#map info                              (info on map and current room)");
		tintin_printf2(ses, "#map insert   <direction>  [room flag] (insert a new room)");
		tintin_printf2(ses, "#map jump     <x> <y>                  (go to given coordinate)");
		tintin_printf2(ses, "#map find     <location> [exits]       (saves path to #path)");
		tintin_printf2(ses, "#map flag     <map flag>               (set map wide flags)");
		tintin_printf2(ses, "#map get      <option>     <variable>  (get various values)");
		tintin_printf2(ses, "#map goto     <location> [exits]       (moves you to given room)");
		tintin_printf2(ses, "#map leave                             (leave the map, return with goto)");
		tintin_printf2(ses, "#map legend   <symbols>                (sets the map legend)");
		tintin_printf2(ses, "#map link     <direction>  <room name> (links 2 rooms)");
		tintin_printf2(ses, "#map list     <location>               (shows list of matching rooms)");
		tintin_printf2(ses, "#map map      <radius>                 (shows an ascii map)");
		tintin_printf2(ses, "#map name     <room name>              (set the room's name)");
		tintin_printf2(ses, "#map read     <filename>               (load your map from a file)");
		tintin_printf2(ses, "#map resize   <size>                   (resize the maximum size)");
		tintin_printf2(ses, "#map roomflag <room flag>              (set room based flags)");
		tintin_printf2(ses, "#map set      <option>     <value>     (set various values)");
		tintin_printf2(ses, "#map return                            (return to last room.)");
		tintin_printf2(ses, "#map run      <location>  <delay>      (run to given room)");
		tintin_printf2(ses, "#map travel   <direction>  <delay>     (run in given direction)");
		tintin_printf2(ses, "#map undo                              (undo last move)");
		tintin_printf2(ses, "#map uninsert <direction>              (opposite of insert)");
		tintin_printf2(ses, "#map unlink   <direction> [both]       (deletes an exit)");
		tintin_printf2(ses, "#map write    <filename>               (save the map to a file)");

		return ses;
	}
	else
	{
		for (cnt = 0 ; *map_table[cnt].name ; cnt++)
		{
			if (is_abbrev(arg1, map_table[cnt].name))
			{
				if (map_table[cnt].check > 0 && ses->map == NULL)
				{
					tintin_printf2(ses, "#MAP: This session has no map data. Use #map create or #map read to create one.");

					return ses;
				}
				if (map_table[cnt].check > 1 && ses->map->room_list[ses->map->in_room] == NULL)
				{
					tintin_printf2(ses, "#MAP: You are not inside the map. Use #map goto to enter it.");

					return ses;
				}
				*arg1 = *arg2 = 0;

				map_table[cnt].map (ses, arg, arg1, arg2);
				break;
			}
		}

		if (*map_table[cnt].name == 0)
		{
			do_map(ses, "");

			return ses;
		}

		if (ses->map && HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
		{
			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
		}
	}
	return ses;
}

DO_MAP(map_at)
{
	int new_room, old_room;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_NONE);

	new_room = find_room(ses, arg1);

	if (new_room == -1)
	{
		show_message(ses, -1, "#MAP AT: Couldn't find room {%s}.", arg1);

		return;
	}

	old_room = ses->map->in_room;
	ses->map->in_room = new_room;

	script_driver(ses, -1, arg2);

	if (ses->map)
	{
		ses->map->in_room = old_room;
	}
}

DO_MAP(map_color)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg1 && is_abbrev(arg1, "ROOMS"))
	{
		RESTRING(ses->map->room_color, arg2);
	}
	else if (*arg1 && is_abbrev(arg1, "EXITS"))
	{
		RESTRING(ses->map->exit_color, arg2);
	}
	else if (*arg1 && is_abbrev(arg1, "PATHS"))
	{
		RESTRING(ses->map->path_color, arg2);
	}
	else
	{
		tintin_printf2(ses, "#SYNTAX: #MAP COLOR {EXIT|PATH|ROOM} {COLOR CODE}");
		return;
	}

	show_message(ses, -1, "#MAP: %s color set to: %s", arg1, arg2);
}

DO_MAP(map_create)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	create_map(ses, arg1);

	tintin_printf2(ses, "#MAP: %d room map created, use #map goto 1, to proceed", ses->map->size);
}

DO_MAP(map_delete)
{
	int room;
	struct exit_data *exit;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	if (is_number(arg1))
	{
		room = find_room(ses, arg1);

		if (room == -1)
		{
			tintin_printf2(ses, "#MAP: No room with that vnum found");
			return;
		}
	}
	else
	{
		exit = find_exit(ses, ses->map->in_room, arg1);

		if (exit)
		{
			room = exit->vnum;
		}

		if (exit == NULL)
		{
			tintin_printf2(ses, "#MAP: No exit with that name found");
			return;
		}

		room = exit->vnum;
	}

	if (room == ses->map->in_room)
	{
		tintin_printf2(ses, "#MAP: You must first leave the room you're trying to delete");
		return;
	}

	delete_room(ses, room, TRUE);

	show_message(ses, -1, "#MAP: Room {%d} deleted", room);
}

DO_MAP(map_destroy)
{
	delete_map(ses);

	tintin_printf2(ses, "#MAP: Map destroyed.");
}

DO_MAP(map_dig)
{
	int room;
	char temp[BUFFER_SIZE];
	struct exit_data *exit;
	struct listnode *node;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg1 == 0)
	{
		tintin_printf2(ses, "#SYNTAX: #MAP DIG {<DIRECTION>} {NEW|<VNUM>}");

		return;
	}

	for (room = 1 ; room < ses->map->size ; room++)
	{
		if (ses->map->room_list[room] == NULL)
		{
			break;
		}
	}

	exit = find_exit(ses, ses->map->in_room, arg1);

	if (exit)
	{
		show_message(ses, -1, "#MAP DIG: There is already a room in that direction.");
		return;
	}

	if (room == ses->map->size)
	{
		tintin_printf2(ses, "#MAP DIG: Maximum amount of rooms of %d reached.", ses->map->size);
		return;
	}

	if (is_number(arg2))
	{
		room = atoi(arg2);

		if (room <= 0 || room >= ses->map->size)
		{
			tintin_printf2(ses, "#MAP DIG: Invalid room vnum: %d.", room);
			return;
		}

		if (ses->map->room_list[room] == NULL)
		{
			sprintf(temp, "{%d} {0} {} {%d} { }", room, room);
			create_room(ses, temp);
		}
		sprintf(temp, "{%d} {%s} {%s}", room, arg1, arg1);
		create_exit(ses, ses->map->in_room, temp);

		return;
	}

	if (strcasecmp(arg2, "new") && find_coord(ses, arg1))
	{
		room = map_search_tar_room;
		show_message(ses, -1, "#MAP CREATE LINK %5d {%s}.", room, ses->map->room_list[room]->name);
	}
	else
	{
		sprintf(temp, "{%d} {0} {} {%d} { }", room, room);
		create_room(ses, temp);
	}

	sprintf(temp, "{%d} {%s} {%s}", room, arg1, arg1);
	create_exit(ses, ses->map->in_room, temp);

	if ((node = search_node_list(ses->list[LIST_PATHDIR], arg1)) != NULL)
	{
		if (find_exit(ses, room, node->right) == NULL)
		{
			sprintf(temp, "{%d} {%s} {%s}", ses->map->in_room, node->right, node->right);
			create_exit(ses, room, temp);
		}
	}
}

DO_MAP(map_exit)
{
	char arg3[BUFFER_SIZE];
	struct exit_data *exit;
	struct listnode *node;
	int room;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);

	exit = find_exit(ses, ses->map->in_room, arg1);

	if (exit == NULL)
	{
		tintin_printf2(ses, "#MAP: Exit {%s} not found.", arg1);

		return;
	}
	if (*arg2 == 0)
	{
		tintin_printf2(ses, "  command: %s", exit->cmd);
		tintin_printf2(ses, "direction: %d", exit->dir);
		tintin_printf2(ses, "    flags: %d", exit->flags);
		tintin_printf2(ses, "     name: %s", exit->name);
		tintin_printf2(ses, "     vnum: %d", exit->vnum);
	}
	else if (is_abbrev(arg2, "COMMAND"))
	{
		exit->cmd = restring(exit->cmd, arg3);

		show_message(ses, -1, "#MAP EXIT {%s} : COMMAND SET TO {%s}.", arg1, exit->cmd);
	}
	else if (is_abbrev(arg2, "DIRECTION"))
	{
		if ((node = search_node_list(ses->list[LIST_PATHDIR], arg3)) == NULL)
		{
			show_message(ses, -1, "#MAP EXIT {%s} : DIRECTION {%s} NOT FOUND.", arg1, arg3);

			return;
		}

		exit->dir = atoi(node->pr);

		show_message(ses, -1, "#MAP EXIT {%s} : DIRECTION SET TO {%s}.", arg1, arg3);
	}
	else if (is_abbrev(arg2, "FLAGS"))
	{
		exit->flags = atoi(arg3);

		show_message(ses, -1, "#MAP EXIT {%s} : FLAGS SET TO {%d}.", arg1, exit->flags);
	}
	else if (is_abbrev(arg2, "NAME"))
	{
		exit->name = restring(exit->name, arg3);

		show_message(ses, -1, "#MAP EXIT {%s} : NAME SET TO {%s}.", arg1, exit->name);
	}
	else if (is_abbrev(arg2, "VNUM"))
	{
		room = atoi(arg3);

		if (room <= 0 || room >= ses->map->size)
		{
			tintin_printf2(ses, "#MAP EXIT VNUM: Invalid room vnum: %d.", room);
			return;
		}

		if (ses->map->room_list[room] == NULL)
		{
			tintin_printf2(ses, "#MAP EXIT VNUM: Non existant room vnum: %d.", room);
			return;
		}
		exit->vnum = room;

		show_message(ses, -1, "#MAP EXIT {%s} : VNUM SET TO {%s}.", arg1, arg3);
	}
	else
	{
		tintin_printf2(ses, "Syntax: #MAP EXIT {<NAME>} {COMMAND|DIRECTION|NAME|FLAGS|VNUM} {<argument>}");
	}
}

DO_MAP(map_exitflag)
{
	struct exit_data *exit;
	char arg3[BUFFER_SIZE];
	int flag;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);

	exit = find_exit(ses, ses->map->in_room, arg1);

	if (exit == NULL)
	{
		tintin_printf2(ses, "#MAP: Exit {%s} not found.", arg1);

		return;
	}

	if (*arg2)
	{
		if (is_abbrev(arg2, "hide"))
		{
			flag = EXIT_FLAG_HIDE;
		}
		else
		{
			tintin_printf2(ses, "#MAP: Invalid exit flag {%s}.", arg2);

			return;
		}
	}
	else
	{
		tintin_printf2(ses, "#MAP: Hide flag is set to %s.", HAS_BIT(exit->flags, EXIT_FLAG_HIDE) ? "on" : "off");

		return;
	}

	if (is_abbrev("on", arg3))
	{
		SET_BIT(exit->flags, flag);
	}
	else if (is_abbrev("off", arg3))
	{
		DEL_BIT(exit->flags, flag);
	}
	else
	{
		TOG_BIT(exit->flags, flag);
	}	


	if (is_abbrev(arg2, "hide"))
	{
		show_message(ses, -1, "#MAP: Hide flag set to %s.", HAS_BIT(exit->flags, EXIT_FLAG_HIDE) ? "on" : "off");
	}
}

DO_MAP(map_explore)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	explore_path(ses, FALSE, arg1, "");
}

DO_MAP(map_find)
{
	shortest_path(ses, FALSE, arg1, arg);
}

DO_MAP(map_flag)
{
	int flag = 0, unflag = 0;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg1)
	{
		if (is_abbrev(arg1, "static"))
		{
			flag = MAP_FLAG_STATIC;
		}
		else if (is_abbrev(arg1, "vtgraphics"))
		{
			flag = MAP_FLAG_VTGRAPHICS;
			unflag = MAP_FLAG_MUDFONT|MAP_FLAG_ASCIIGRAPHICS;
		}
		else if (is_abbrev(arg1, "vtmap"))
		{
			flag = MAP_FLAG_VTMAP;
		}
		else if (is_abbrev(arg1, "asciigraphics"))
		{
			flag = MAP_FLAG_ASCIIGRAPHICS;
			unflag = MAP_FLAG_MUDFONT|MAP_FLAG_VTGRAPHICS;
		}
		else if (is_abbrev(arg1, "asciivnums"))
		{
			flag = MAP_FLAG_ASCIIVNUMS;
		}
		else if (is_abbrev(arg1, "mudfont"))
		{
			flag = MAP_FLAG_MUDFONT;
			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_VTGRAPHICS;
		}
		else if (is_abbrev(arg1, "nofollow"))
		{
			flag = MAP_FLAG_NOFOLLOW;
		}
		else
		{
			tintin_printf2(ses, "#MAP: Invalid flag {%s}.", arg1);

			return;
		}
	}
	else
	{
		tintin_printf2(ses, "#MAP: Static flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "on" : "off");
		tintin_printf2(ses, "#MAP: VTmap flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "on" : "off");
		tintin_printf2(ses, "#MAP: VTgraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTGRAPHICS) ? "on" : "off");
		tintin_printf2(ses, "#MAP: AsciiGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS) ? "on" : "off");
		tintin_printf2(ses, "#MAP: AsciiVnums flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) ? "on" : "off");
		tintin_printf2(ses, "#MAP: NoFollow flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "on" : "off");

		return;
	}

	if (is_abbrev("on", arg2))
	{
		SET_BIT(ses->map->flags, flag);
	}
	else if (is_abbrev("off", arg2))
	{
		DEL_BIT(ses->map->flags, flag);
	}
	else
	{
		TOG_BIT(ses->map->flags, flag);
	}

	if (unflag)
	{
		DEL_BIT(ses->map->flags, unflag);
	}

	if (is_abbrev(arg1, "static"))
	{
		show_message(ses, -1, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "vtgraphics"))
	{
		show_message(ses, -1, "#MAP: VTgraphics flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTGRAPHICS) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "vtmap"))
	{
		show_message(ses, -1, "#MAP: VTmap flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "on" : "off");

		show_vtmap(ses);
	}
	else if (is_abbrev(arg1, "asciigraphics"))
	{
		show_message(ses, -1, "#MAP: AsciiGraphics flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "asciivnums"))
	{
		show_message(ses, -1, "#MAP: AsciiVnums flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "mudfont"))
	{
		show_message(ses, -1, "#MAP: MudFont flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "on" : "off");
	}
	else if (is_abbrev(arg, "nofollow"))
	{
		show_message(ses, -1, "#MAP: NoFollow flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "on" : "off");

		ses->map->nofollow = HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? 1 : 0;
	}
}

DO_MAP(map_get)
{
	struct room_data *room = ses->map->room_list[ses->map->in_room];
	struct exit_data *exit;
	char buf[BUFFER_SIZE], arg3[BUFFER_SIZE];

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg3)
	{
		if (atoi(arg3) > 0 && atoi(arg3) < ses->map->size)
		{
			room = ses->map->room_list[atoi(arg3)];
		}
		else
		{
			room = NULL;
		}
	}

	if (room == NULL)
	{
		set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
	}
	else if (*arg1 == 0 || *arg2 == 0)
	{
		tintin_printf2(ses, "  roomvnum: %d", room->vnum);
		tintin_printf2(ses, "  roomarea: %s", room->area);
		tintin_printf2(ses, " roomcolor: %s", room->color);
		tintin_printf2(ses, "  roomdesc: %s", room->desc);
		tintin_printf2(ses, " roomexits: %d", get_map_exits(ses, room->vnum));
		tintin_printf2(ses, " roomflags: %d", room->flags);
		tintin_printf2(ses, "  roomname: %s", room->name);
		tintin_printf2(ses, "  roomnote: %s", room->note);
		tintin_printf2(ses, "roomsymbol: %s", room->symbol);
		tintin_printf2(ses, "worldflags: %d", ses->map->flags);
		tintin_printf2(ses, " worldsize: %d", ses->map->size);
	}
	else
	{
		if (is_abbrev(arg1, "roomarea"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->area);
		}
		else if (is_abbrev(arg1, "roomcolor"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->color);
		}
		else if (is_abbrev(arg1, "roomdesc"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->desc);
		}
		else if (is_abbrev(arg1, "roomflags"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", room->flags);
		}
		else if (is_abbrev(arg1, "roomname"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->name);
		}
		else if (is_abbrev(arg1, "roomnote"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->note);
		}
		else if (is_abbrev(arg1, "roomsymbol"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->symbol);
		}
		else if (is_abbrev(arg1, "roomvnum"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", room->vnum);
		}
		else if (is_abbrev(arg1, "roomexits"))
		{
			buf[0] = 0;

			for (exit = room->f_exit ; exit ; exit = exit->next)
			{
				cat_sprintf(buf, "{%s}{%d}", exit->name, exit->vnum);
			}
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", buf);
		}
		else if (is_abbrev(arg1, "worldflags"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->map->flags);
		}
		else if (is_abbrev(arg1, "worldsize"))
		{
			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->map->size);
		}
		else
		{
			show_message(ses, -1, "#MAP GET: unknown option: %s.", arg1);
		}
	}
}

DO_MAP(map_goto)
{
	int room;

	room = find_room(ses, arg);

	if (room != -1)
	{
		add_undo(ses, "%d %d %d", room, ses->map->in_room, 0);

		goto_room(ses, room);
		show_message(ses, -1, "#MAP: Location set to room {%s}.", ses->map->room_list[room]->name);
	}
	else
	{
		show_message(ses, -1, "#MAP: Couldn't find room {%s}.", arg);
	}
}

DO_MAP(map_info)
{
	int room, cnt, exits;
	struct exit_data *exit;

	for (room = cnt = exits = 0 ; room < ses->map->size ; room++)
	{
		if (ses->map->room_list[room])
		{
			cnt++;

			exits += get_map_exits(ses, room);
		}
	}

	tintin_printf2(ses, "%-20s %d/%d", "Total rooms:",    cnt, ses->map->size);
	tintin_printf2(ses, "%-20s %d", "Total exits:",    exits);
	tintin_printf2(ses, "%-20s %s", "Vtmap:",          HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "on" : "off");
	tintin_printf2(ses, "%-20s %s", "Static:",         HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "on" : "off");

	if (ses->map->in_room)
	{
		tintin_printf2(ses, "");
		tintin_printf2(ses, "%-20s %d", "Room vnum:",      ses->map->in_room);
		tintin_printf2(ses, "%-20s %s", "Room name:",      ses->map->room_list[ses->map->in_room]->name);
		tintin_printf2(ses, "%-20s %d", "Room size:",      ses->map->room_list[ses->map->in_room]->size);
		tintin_printf2(ses, "%-20s %s", "Avoid:",          HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "on" : "off");
		tintin_printf2(ses, "%-20s %s", "Hide:",           HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "on" : "off");		
		tintin_printf2(ses, "%-20s %s", "Leave:",          HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE) ? "on" : "off");
		tintin_printf2(ses, "%-20s %s", "Void:",           HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "on" : "off");

		for (exit = ses->map->room_list[ses->map->in_room]->f_exit ; exit ; exit = exit->next)
		{
			tintin_printf2(ses, "%-20s %03d %-3s (%s) to room: %-5d (%s)", "Exit:", exit->dir, exit->name, exit->cmd, exit->vnum, ses->map->room_list[exit->vnum]->name);
		}
	}
}

DO_MAP(map_insert)
{
	int room, in_room, to_room;
	char temp[BUFFER_SIZE];
	struct exit_data *exit;
	struct listnode *node;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	for (room = 1 ; room < ses->map->size ; room++)
	{
		if (ses->map->room_list[room] == NULL)
		{
			break;
		}
	}

	exit = find_exit(ses, ses->map->in_room, arg1);

	node = search_node_list(ses->list[LIST_PATHDIR], arg1);

	if (exit == NULL)
	{
		tintin_printf2(ses, "#MAP: There is no room in that direction.");

		return;
	}

	if (room == ses->map->size)
	{
		tintin_printf2(ses, "#MAP: Maximum amount of rooms of %d reached.", ses->map->size);
		return;
	}

	if (node == NULL)
	{
		tintin_printf2(ses, "#MAP: Given direction must be a pathdir.");
		return;
	}

	in_room = ses->map->in_room;
	to_room = exit->vnum;

	sprintf(temp, "{%d} {0} {} {%d} { }", room, room);
	create_room(ses, temp);

	sprintf(temp, "{%d} {%s} {%s}", to_room, node->left, node->left);
	create_exit(ses, room, temp);

	sprintf(temp, "{%d} {%s} {%s}", in_room, node->right, node->right);
	create_exit(ses, room, temp);

	exit->vnum = room;

	if ((exit = find_exit(ses, to_room, node->right)) != NULL)
	{
		exit->vnum = room;
	}

	if (*arg2)
	{
		char buf[BUFFER_SIZE];

		strcpy(buf, arg2);
		ses->map->in_room = room;
		map_roomflag(ses, buf, arg1, arg2);
		ses->map->in_room = in_room;
	}
	show_message(ses, -1, "#MAP: Inserted room {%d}.", room);
}

DO_MAP(map_jump)
{
	int vnum;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	map_grid_x = 0;
	map_grid_y = 0;
	map_grid_z = 0;

	map_search_ses       = ses;
	map_search_tar_room  = 0;

	map_grid_x += atoi(arg1);
	map_grid_y += atoi(arg2);

	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
	{
		if (ses->map->room_list[vnum])
		{
			ses->map->room_list[vnum]->size = MAP_SEARCH_SIZE;
		}
	}

	search_coord_bf(ses->map->in_room);

	if (map_search_tar_room)
	{
		add_undo(ses, "%d %d %d", map_search_tar_room, ses->map->in_room, 0);

		goto_room(ses, map_search_tar_room);

		show_message(ses, -1, "#MAP: Location set to room {%s}.", ses->map->room_list[map_search_tar_room]->name);
	}
	else
	{
		show_message(ses, -1, "#MAP: Couldn't find room at {%s} {%s}.", arg1, arg2);
	}
}

DO_MAP(map_leave)
{
	if (ses->map->in_room == 0)
	{
		tintin_printf2(ses, "#MAP: You're not currently inside the map.");
	}
	else
	{
		ses->map->last_room = ses->map->in_room;
		ses->map->in_room = 0;

		show_message(ses, -1, "#MAP: Leaving the map. Use goto or return to return.");

		check_all_events(ses, 0, 1, "MAP EXIT MAP", ntos(ses->map->in_room));
	}
}

DO_MAP(map_legend)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg1 == 0)
	{
		tintin_printf2(ses, "#MAP: Current legend: %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
			ses->map->legend[0],  ses->map->legend[1],  ses->map->legend[2],
			ses->map->legend[3],  ses->map->legend[4],  ses->map->legend[5],
			ses->map->legend[6],  ses->map->legend[7],  ses->map->legend[8],
			ses->map->legend[9],  ses->map->legend[10], ses->map->legend[11],
			ses->map->legend[12], ses->map->legend[13], ses->map->legend[14],
			ses->map->legend[15], ses->map->legend[16]);
	}
	else
	{
		create_legend(ses, arg1);
	}
}

DO_MAP(map_link)
{
	char arg3[BUFFER_SIZE];
	struct listnode *node;
	struct exit_data *exit;
	int room;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);

	if ((room = find_room(ses, arg)) == -1)
	{
		tintin_printf2(ses, "#MAP: Couldn't find room {%s}.", arg2);
		return;
	}

	exit = find_exit(ses, ses->map->in_room, arg1);

	if (exit)
	{
		delete_exit(ses, ses->map->in_room, exit);
	}

	sprintf(arg3, "{%d} {%s} {%s}", room, arg1, arg1);
	create_exit(ses, ses->map->in_room, arg3);

	if ((node = search_node_list(ses->list[LIST_PATHDIR], arg1)) != NULL)
	{
		if (find_exit(ses, room, node->right) == NULL)
		{
			sprintf(arg3, "{%d} {%s} {%s}", ses->map->in_room, node->right, node->right);
			create_exit(ses, room, arg3);
		}
	}
	show_message(ses, -1, "#MAP LINK: Connected room {%s} to {%s}.", ses->map->room_list[ses->map->in_room]->name, ses->map->room_list[room]->name);
}

DO_MAP(map_list)
{
	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE], arg5[BUFFER_SIZE];
	int room;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg5, GET_ALL, SUB_VAR|SUB_FUN);

	fill_map(ses);

	for (room = 0 ; room < ses->map->size ; room++)
	{
		if (match_room(ses, room, arg1, arg2, arg3, arg4, arg5))
		{
			tintin_printf2(ses, "vnum: %5d distance: %5d name: %s", ses->map->room_list[room]->vnum, ses->map->room_list[room]->size, ses->map->room_list[room]->name);
		}
	}
}

DO_MAP(map_map)
{
	char arg3[BUFFER_SIZE], buf[BUFFER_SIZE], out[BUFFER_SIZE];
	FILE *logfile = NULL;
	int x, y, line;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);

	push_call("map_map(%p,%p)",ses,arg);

	if (sscanf(arg1, "%dx%d", &map_grid_x, &map_grid_y) == 2)
	{
		if (*arg2)
		{
			if (tolower((int) *arg3) == 'a')
			{
				logfile = fopen(arg2, "a");
			}
			else
			{
				logfile = fopen(arg2, "w");
			}
		}

		if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
		{
			map_grid_y = map_grid_y / 3;
			map_grid_x = map_grid_x / 6;
		}
		else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
		{
			map_grid_x = map_grid_x / 2;
		}

		if (map_grid_x > ses->map->max_grid_x)
		{
			ses->map->max_grid_x = map_grid_x;

			ses->map->grid = (struct room_data **) realloc(ses->map->grid, ses->map->max_grid_x * ses->map->max_grid_y);
		}

		if (map_grid_y > ses->map->max_grid_y)
		{
			ses->map->max_grid_y = map_grid_y;

			ses->map->grid = (struct room_data **) realloc(ses->map->grid, ses->map->max_grid_x * ses->map->max_grid_y);
		}

	}
	else if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
	{
		map_grid_y = get_scroll_size(ses) / 3;
		map_grid_x = ses->cols / 6;

	}
	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
	{
		map_grid_y = get_scroll_size(ses);
		map_grid_x = ses->cols / 2;
	}
	else
	{
		map_grid_y = get_scroll_size(ses);
		map_grid_x = ses->cols;
	}

	create_map_grid(ses, ses->map->in_room, map_grid_x, map_grid_y);

	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
	{
		for (y = map_grid_y - 1 ; y >= 0 ; y--)
		{
			for (line = 1 ; line <= 3 ; line++)
			{
				strcpy(buf, "");

				for (x = 0 ; x < map_grid_x ; x++)
				{
					strcat(buf, draw_room(ses, ses->map->grid[x + map_grid_x * y], line));
				}

				substitute(ses, buf, out, SUB_COL);

				if (logfile)
				{
					fprintf(logfile, "%s\n", out);
				}
				else
				{
					tintin_puts2(ses, out);
				}
			}
		}
	}
	else
	{
		for (y = map_grid_y ; y >= 0 ; y--)
		{
			strcpy(buf, "");

			for (x = 0 ; x < map_grid_x ; x++)
			{
				strcat(buf, draw_room(ses, ses->map->grid[x + map_grid_x * y], 0));
			}

			for (x = strlen(buf) - 1 ; x > 0 ; x--)
			{
				if (buf[x] != ' ')
				{
					break;
				}
			}

			buf[x+1] = 0;

			substitute(ses, buf, out, SUB_COL);

			if (logfile)
			{
				fprintf(logfile, "%s\n", out);
			}
			else
			{
				tintin_puts2(ses, out);
			}
		}
	}

	if (logfile)
	{
		fclose(logfile);
	}

	pop_call();
	return;
}

DO_MAP(map_move)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	ses->map->nofollow++;

	follow_map(ses, arg1);

	ses->map->nofollow--;
}

DO_MAP(map_name)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	free(ses->map->room_list[ses->map->in_room]->name);
	ses->map->room_list[ses->map->in_room]->name = strdup(arg1);
}

DO_MAP(map_read)
{
	FILE *myfile;
	struct exit_data *exit;
	char buffer[BUFFER_SIZE], *cptr;
	int line = 0, room = 0;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	if ((myfile = fopen(arg1, "r")) == NULL)
	{
		tintin_printf2(ses, "#MAP: Map file {%s} not found.", arg1);

		return;
	}

	gtd->quiet++;

	if (ses->map == NULL)
	{
		ses->map = (struct map_data *) calloc(1, sizeof(struct map_data));
	}

	while (fgets(buffer, BUFFER_SIZE - 1, myfile))
	{
		line++;

		cptr = strchr(buffer, '\r'); /* For map files editor on Windows systems. */

		if (cptr)
		{
			*cptr = 0;
		}

		cptr = strchr(buffer, '\n');

		if (cptr)
		{
			*cptr = 0;
		}

		switch (buffer[0])
		{
			case 'C':
				switch (buffer[1])
				{
					case ' ':
						create_map(ses, buffer + 2);
						break;

					case 'E':
						ses->map->exit_color = strdup(buffer + 3);
						break;

					case 'P':
						ses->map->path_color = strdup(buffer + 3);
						break;

					case 'R':
						ses->map->room_color = strdup(buffer + 3);
						break;
				}
				break;

			case 'E':
				create_exit(ses, room, buffer + 2);
				break;

			case 'F':
				ses->map->flags = atoi(buffer + 2);

				if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
				{
					ses->map->nofollow = 1;
				}
				break;

			case 'I':
				ses->map->last_room = atoi(buffer + 2);
				break;

			case 'L':
				create_legend(ses, buffer + 2);
				break;

			case 'R':
				room = create_room(ses, buffer + 2);
				break;

			case '#':
				buffer[0] = gtd->tintin_char;
				ses = script_driver(ses, -1, buffer);
				break;

			case  0:
			case 13:
				break;

			default:
				gtd->quiet--;

				tintin_printf2(ses, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);

				fclose(myfile);

				delete_map(ses);

				return;				
		}
	}

	gtd->quiet--;

	fclose(myfile);

	for (room = 0 ; room < ses->map->size ; room++)
	{
		if (ses->map->room_list[room] == NULL)
		{
			continue;
		}

		for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
		{
			if (exit->vnum < 0 || exit->vnum >= ses->map->size || ses->map->room_list[exit->vnum] == NULL)
			{
				tintin_printf2(ses, "#MAP READ: Room %d - invalid exit '%s' to room %d.", room, exit->name, exit->vnum);

				delete_exit(ses, room, exit);

				if (ses->map->room_list[room]->f_exit)
				{
					exit = ses->map->room_list[room]->f_exit;
				}
				else
				{
					break;
				}
			}
		}
	}

	show_message(ses, -1, "#MAP READ: Map file {%s} loaded.", arg1);


}

DO_MAP(map_resize)
{
	int size;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	size = atoi(arg1);

	if (size <= ses->map->size)
	{
		tintin_printf2(ses, "#MAP RESIZE: NEW SIZE (%d) MUST BE GREATER THAN CURRENT SIZE (%d).", size, ses->map->size);
		return;
	}

	ses->map->size = size;

	ses->map->room_list = (struct room_data **) realloc(ses->map->room_list, ses->map->size * sizeof(struct room_data *));

	show_message(ses, -1, "#MAP RESIZE: MAP RESIZED TO %d ROOMS.", size);
}

DO_MAP(map_return)
{
	if (ses->map == NULL || ses->map->room_list[ses->map->last_room] == NULL)
	{
		tintin_printf2(ses, "#MAP RETURN: No known last room.");

		return;
	}

	if (ses->map->in_room)
	{
		tintin_printf2(ses, "#MAP RETURN: Already in the map.");
	}
	else
	{
		goto_room(ses, ses->map->last_room);
	}
}

DO_MAP(map_roomflag)
{
	int flag;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg1)
	{
		if (is_abbrev(arg1, "avoid"))
		{
			flag = ROOM_FLAG_AVOID;
		}
		else if (is_abbrev(arg1, "hide"))
		{
			flag = ROOM_FLAG_HIDE;
		}
		else if (is_abbrev(arg1, "leave"))
		{
			flag = ROOM_FLAG_LEAVE;
		}
		else if (is_abbrev(arg1, "void"))
		{
			flag = ROOM_FLAG_VOID;
		}
		else if (is_abbrev(arg1, "static"))
		{
			flag = ROOM_FLAG_STATIC;
		}
		else if (is_abbrev(arg1, "river"))
		{
			flag = ROOM_FLAG_RIVER;
		}
		else
		{
			tintin_printf2(ses, "#MAP: Invalid room flag {%s}.", arg1);

			return;
		}
	}
	else
	{
			tintin_printf2(ses, "#MAP: Avoid flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "on" : "off");
			tintin_printf2(ses, "#MAP: Hide flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "on" : "off");
			tintin_printf2(ses, "#MAP: Leave flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE) ? "on" : "off");
			tintin_printf2(ses, "#MAP: Void flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "on" : "off");
			tintin_printf2(ses, "#MAP: Static flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "on" : "off");

			return;
	}

	if (is_abbrev("on", arg2))
	{
		SET_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
	}
	else if (is_abbrev("off", arg2))
	{
		DEL_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
	}
	else
	{
		TOG_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
	}	


	if (is_abbrev(arg1, "avoid"))
	{
		show_message(ses, -1, "#MAP: Avoid flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "hide"))
	{
		show_message(ses, -1, "#MAP: Hide flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "leave"))
	{
		show_message(ses, -1, "#MAP: Leave flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "void"))
	{
		show_message(ses, -1, "#MAP: Void flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "static"))
	{
		show_message(ses, -1, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "on" : "off");
	}
	else if (is_abbrev(arg1, "river"))
	{
		show_message(ses, -1, "#MAP: River flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_RIVER) ? "on" : "off");
	}
}

DO_MAP(map_set)
{
	struct room_data *room = ses->map->room_list[ses->map->in_room];
	char arg3[BUFFER_SIZE];

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg3)
	{
		if (atoi(arg3) > 0 && atoi(arg3) < ses->map->size)
		{
			room = ses->map->room_list[atoi(arg3)];
		}
		else
		{
			room = NULL;
		}
	}

	if (room == NULL)
	{
		show_message(ses, -1, "#MAP SET: invalid room vnum: %s", arg3);
	}
	else if (*arg1 == 0)
	{
		tintin_printf2(ses, "  roomarea: %s", room->area);
		tintin_printf2(ses, " roomcolor: %s", room->color);
		tintin_printf2(ses, "  roomdesc: %s", room->desc);
		tintin_printf2(ses, " roomflags: %d", room->flags);
		tintin_printf2(ses, "  roomname: %s", room->name);
		tintin_printf2(ses, "  roomnote: %s", room->note);
		tintin_printf2(ses, "roomsymbol: %s", room->symbol);
	}
	else
	{
		if (is_abbrev(arg1, "roomarea"))
		{
			RESTRING(room->area, arg2);
			show_message(ses, -1, "#MAP SET: roomarea set to: %s", room->area);
		}
		else if (is_abbrev(arg1, "roomcolor"))
		{
			RESTRING(room->color, arg2);
			show_message(ses, -1, "#MAP SET: roomcolor set to: %s", arg2);
		}
		else if (is_abbrev(arg1, "roomdesc"))
		{
			RESTRING(room->desc, arg2);
			show_message(ses, -1, "#MAP SET: roomdesc set to: %s", arg2);
		}
		else if (is_abbrev(arg1, "roomflags"))
		{
			room->flags = (int) get_number(ses, arg2);

			show_message(ses, -1, "#MAP SET: roomflags set to: %d", room->flags);
		}
		else if (is_abbrev(arg1, "roomname"))
		{
			RESTRING(room->name, arg2);

			show_message(ses, -1, "#MAP SET: roomname set to: %s", room->name);
		}
		else if (is_abbrev(arg1, "roomnote"))
		{
			RESTRING(room->note, arg2);
			show_message(ses, -1, "#MAP SET: roomnote set to: %s", arg2);
		}
		else if (is_abbrev(arg1, "roomsymbol"))
		{
			RESTRING(room->symbol, arg2);

			show_message(ses, -1, "#MAP SET: roomsymbol set to: %s", room->symbol);
		}
		else
		{
			show_message(ses, -1, "#MAP SET: unknown option: %s", arg1);
		}
	}
}

DO_MAP(map_travel)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	explore_path(ses, TRUE, arg1, arg2);
}


DO_MAP(map_uninsert)
{
	int room1, room2, room3;
	struct exit_data *exit1, *exit2, *exit3;
	struct listnode *node;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);

	room1 = ses->map->in_room;
	exit1 = find_exit(ses, room1, arg1);

	node = search_node_list(ses->list[LIST_PATHDIR], arg1);

	if (exit1 == NULL)
	{
		tintin_printf2(ses, "#MAP UNINSERT: There is no room in that direction.");

		return;
	}

	if (node == NULL)
	{
		tintin_printf2(ses, "#MAP UNINSERT: Given direction must be a pathdir.");
		return;
	}

	room2 = exit1->vnum;
	exit2 = find_exit(ses, room2, node->left);

	if (exit2 == NULL)
	{
		tintin_printf2(ses, "#MAP UNINSERT: Unable to find backlink room.");
		return;
	}

	room3 = exit2->vnum;
	exit3 = find_exit(ses, room3, node->right);

	if (exit3 == NULL)
	{
		tintin_printf2(ses, "#MAP UNINSERT: Unable to find backlink exit.");

		return;
	}

	exit1->vnum = room3;
	exit3->vnum = room1;

	delete_room(ses, room2, TRUE);

	show_message(ses, -1, "#MAP UNINSERT: Uninserted room {%d}.", room2);
}

DO_MAP(map_undo)
{
	struct link_data *link;
	int undo_flag;
	struct exit_data *exit;

	link = ses->map->undo_tail;

	if (link == NULL)
	{
		tintin_printf2(ses, "#MAP UNDO: No known last move.");

		return;
	}

	if (ses->map->in_room != atoi(link->str1))
	{
		tintin_printf2(ses, "#MAP UNDO: Invalid last move.");

		return;
	}

	if (ses->map->room_list[atoi(link->str2)] == NULL)
	{
		tintin_printf2(ses, "#MAP UNDO: Invalid last move.");

		return;
	}

	undo_flag = atoi(link->str3);

	goto_room(ses, atoi(link->str2));

	if (HAS_BIT(undo_flag, MAP_UNDO_CREATE))
	{
		delete_room(ses, atoi(link->str1), TRUE);
	}
	else if (HAS_BIT(undo_flag, MAP_UNDO_LINK))
	{
		exit = find_exit(ses, atoi(link->str1), link->str2);

		if (exit)
		{
			delete_exit(ses, atoi(link->str1), exit);
		}

		exit = find_exit(ses, atoi(link->str2), link->str1);

		if (exit)
		{
			delete_exit(ses, atoi(link->str2), exit);
		}
	}
	del_undo(ses, link);
}

DO_MAP(map_unlink)
{
	struct exit_data *exit1;
	struct exit_data *exit2;
	struct listnode *node;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	node = search_node_list(ses->list[LIST_PATHDIR], arg1);

	exit1 = find_exit(ses, ses->map->in_room, arg1);

	if (exit1 == NULL)
	{
		tintin_printf2(ses, "#MAP UNLINK: No exit with that name found");

		return;
	}

	if (*arg2 == 'b')
	{
		if (node)
		{
			exit2 = find_exit(ses, exit1->vnum, node->right);

			if (exit2)
			{
				delete_exit(ses, exit1->vnum, exit2);
			}
		}
	}

	delete_exit(ses, ses->map->in_room, exit1);

	show_message(ses, -1, "#MAP UNLINK: Exit deleted.");
}

DO_MAP(map_run)
{
	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);

	shortest_path(ses, TRUE, arg2, arg1);
}

DO_MAP(map_write)
{
	FILE *file;
	struct exit_data *exit;
	int vnum;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);

	if (*arg1 == 0 || (file = fopen(arg1, "w")) == NULL)
	{
		tintin_printf2(ses, "#ERROR: #MAP WRITE {%s} - COULDN'T OPEN FILE TO WRITE.", arg1);

		return;
	}

	fprintf(file, "C %d\n\n", ses->map->size);

	fprintf(file, "CE %s\nCR %s\nCP %s\n\n", ses->map->exit_color, ses->map->room_color, ses->map->path_color);

	fprintf(file, "F %d\n\n", ses->map->flags);

	fprintf(file, "I %d\n\n", ses->map->in_room ? ses->map->in_room : ses->map->last_room);

	fprintf(file, "L %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n\n",
		ses->map->legend[0],  ses->map->legend[1],  ses->map->legend[2],
		ses->map->legend[3],  ses->map->legend[4],  ses->map->legend[5],
		ses->map->legend[6],  ses->map->legend[7],  ses->map->legend[8],
		ses->map->legend[9],  ses->map->legend[10], ses->map->legend[11],
		ses->map->legend[12], ses->map->legend[13], ses->map->legend[14],
		ses->map->legend[15], ses->map->legend[16]);

	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
	{
		if (ses->map->room_list[vnum])
		{
			fprintf(file, "\nR {%5d} {%d} {%s} {%s} {%s} {%s} {%s} {%s}\n",
				ses->map->room_list[vnum]->vnum,
				ses->map->room_list[vnum]->flags,
				ses->map->room_list[vnum]->color,
				ses->map->room_list[vnum]->name,
				ses->map->room_list[vnum]->symbol,
				ses->map->room_list[vnum]->desc,
				ses->map->room_list[vnum]->area,
				ses->map->room_list[vnum]->note);
                        
			for (exit = ses->map->room_list[vnum]->f_exit ; exit ; exit = exit->next)
			{
				fprintf(file, "E {%5d} {%s} {%s} {%d} {%d}\n",
					exit->vnum,
					exit->name,
					exit->cmd,
					exit->dir,
					exit->flags);
			}
		}
	}

	fclose(file);

	show_message(ses, -1, "#MAP: Map file written to {%s}.", arg1);
}

void create_map(struct session *ses, char *arg)
{
	int index;

	if (ses->map)
	{
		delete_map(ses);
	}

	ses->map = (struct map_data *) calloc(1, sizeof(struct map_data));
	ses->map->size = atoi(arg) > 0 ? atoi(arg) : 15000;

	ses->map->room_list = (struct room_data **) calloc(ses->map->size, sizeof(struct room_data *));

	ses->map->max_grid_x = 255;
	ses->map->max_grid_y = 101;

	ses->map->grid = (struct room_data **) calloc(ses->map->max_grid_x * ses->map->max_grid_y, sizeof(struct room_data *));

	ses->map->flags = MAP_FLAG_ASCIIGRAPHICS;

	ses->map->room_color = strdup("<178>");
	ses->map->exit_color = strdup("<078>");
	ses->map->path_color = strdup("<138>");

	create_room(ses, "{1} {0} {} {1} { }");

	for (index = 0 ; index < 17 ; index++)
	{
		sprintf(ses->map->legend[index], "%c", map_palet0[index]);
	}
}

void delete_map(struct session *ses)
{
	int index;

	for (index = 1 ; index < ses->map->size ; index++)
	{
		if (ses->map->room_list[index])
		{
			delete_room(ses, index, FALSE);
		}
	}
	free(ses->map->room_list);

	while (ses->map->undo_head)
	{
		del_undo(ses, ses->map->undo_head);
	}

	free(ses->map);

	ses->map = NULL;
}
		
void create_legend(struct session *ses, char *arg)
{
	int cnt;
	char buf[BUFFER_SIZE];

	for (cnt = 0 ; cnt < 17 ; cnt++)
	{
		arg = get_arg_in_braces(arg, buf, FALSE);

		substitute(ses, buf, buf, SUB_ESC);

		if (is_number(buf))
		{
			sprintf(ses->map->legend[cnt], "%c", atoi(buf));
		}
		else
		{
			sprintf(ses->map->legend[cnt], "%s", buf);
		}
	}
}


int create_room(struct session *ses, char *arg)
{
	char vnum[BUFFER_SIZE], flags[BUFFER_SIZE], color[BUFFER_SIZE], name[BUFFER_SIZE], symbol[BUFFER_SIZE], desc[BUFFER_SIZE], area[BUFFER_SIZE], note[BUFFER_SIZE];
	struct room_data *newroom;

	arg = get_arg_in_braces(arg, vnum,   FALSE);
	arg = get_arg_in_braces(arg, flags,  FALSE);
	arg = get_arg_in_braces(arg, color,  FALSE);
	arg = get_arg_in_braces(arg, name,   FALSE);
	arg = get_arg_in_braces(arg, symbol, FALSE);
	arg = get_arg_in_braces(arg, desc,   FALSE);
	arg = get_arg_in_braces(arg, area,   FALSE);
	arg = get_arg_in_braces(arg, note,   FALSE);

	/* Backward compatbility 1.96.5 */

	if (*symbol == 0) { strcpy(symbol, " "); }

	newroom         = (struct room_data *) calloc(1, sizeof(struct room_data));

	newroom->color  = strdup(color);
	newroom->name   = strdup(name);
	newroom->symbol = strdup(symbol);
	newroom->desc   = strdup(desc);
	newroom->area   = strdup(area);
	newroom->note   = strdup(note);

	newroom->flags  = atoi(flags);
	newroom->vnum   = atoi(vnum);

	ses->map->room_list[newroom->vnum] = newroom;

	show_message(ses, -1, "#MAP CREATE ROOM %5s {%s}.", vnum, name);

	return newroom->vnum;
}

void delete_room(struct session *ses, int room, int exits)
{
	struct exit_data *exit, *exit_next;
	int cnt;

	while (ses->map->room_list[room]->f_exit)
	{
		delete_exit(ses, room, ses->map->room_list[room]->f_exit);
	}

	free(ses->map->room_list[room]->name);
	free(ses->map->room_list[room]->color);
	free(ses->map->room_list[room]->symbol);
	free(ses->map->room_list[room]->desc);
	free(ses->map->room_list[room]->area);
	free(ses->map->room_list[room]->note);

	free(ses->map->room_list[room]);

	ses->map->room_list[room] = NULL;

	if (exits)
	{
		for (cnt = 0 ; cnt < ses->map->size ; cnt++)
		{
			if (ses->map->room_list[cnt])
			{
				for (exit = ses->map->room_list[cnt]->f_exit ; exit ; exit = exit_next)
				{
					exit_next = exit->next;

					if (exit->vnum == room)
					{
						delete_exit(ses, cnt, exit);
					}
				}
			}
		}
	}
}

void create_exit(struct session *ses, int room, char *arg)
{
	struct exit_data *newexit;
	struct listnode *node;

	char vnum[BUFFER_SIZE], name[BUFFER_SIZE], cmd[BUFFER_SIZE], dir[BUFFER_SIZE], flags[BUFFER_SIZE];

	arg = get_arg_in_braces(arg, vnum,  FALSE);
	arg = get_arg_in_braces(arg, name,  FALSE);
	arg = get_arg_in_braces(arg, cmd,   TRUE);
	arg = get_arg_in_braces(arg, dir,   FALSE);
	arg = get_arg_in_braces(arg, flags, FALSE);

	newexit        = (struct exit_data *) calloc(1, sizeof(struct exit_data));
	newexit->vnum  = atoi(vnum);
	newexit->name  = strdup(name);
	newexit->cmd   = strdup(cmd);
	newexit->dir   = atoi(dir);
	newexit->flags = atoi(flags);

	if (newexit->dir == 0)
	{
		if ((node = search_node_list(ses->list[LIST_PATHDIR], name)) != NULL)
		{
			newexit->dir = atoi(node->pr);
		}
	}

	LINK(newexit, ses->map->room_list[room]->f_exit, ses->map->room_list[room]->l_exit);

	show_message(ses, -1, "#MAP CREATE EXIT %5s {%s} {%s}.", vnum, name, cmd);
}

void delete_exit(struct session *ses, int room, struct exit_data *exit)
{
	free(exit->name);
	free(exit->cmd);

	UNLINK(exit, ses->map->room_list[room]->f_exit, ses->map->room_list[room]->l_exit)

	free(exit);
}

int get_map_exit(struct session *ses, char *arg)
{
	struct listnode *node;

	node = search_node_list(ses->list[LIST_PATHDIR], arg);

	if (node)
	{
		return atoi(node->pr);
	}
	else
	{
		return 0;
	}
}

int get_map_exits(struct session *ses, int room)
{
	struct exit_data *exit;

	int count = 0;

	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
	{
		count++;
	}

	return count;
}

int follow_map(struct session *ses, char *argument)
{
	struct exit_data *exit;
	int room;

	push_call("follow_map(%p,%p)",ses,argument);

	exit = find_exit(ses, ses->map->in_room, argument);

	if (exit)
	{
		room = ses->map->in_room;

		add_undo(ses, "%d %d %d", exit->vnum, room, 0);

		if (ses->map->nofollow == 0)
		{
			ses->map->nofollow++;

			script_driver(ses, -1, exit->cmd);

			ses->map->nofollow--;
		}
		goto_room(ses, exit->vnum);

		if (HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE))
		{
			show_message(ses, -1, "#MAP: LEAVE FLAG FOUND IN ROOM {%d}. LEAVING MAP.", ses->map->in_room);

			map_leave(ses, "", "", "");
		}
		else if (HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID))
		{
			exit = find_exit(ses, exit->vnum, argument);

			if (exit)
			{
				ses->map->nofollow++;

				follow_map(ses, exit->name);

				ses->map->nofollow--;

				pop_call();
				return 1;
			}

			for (exit = ses->map->room_list[ses->map->in_room]->f_exit ; exit ; exit = exit->next)
			{
				if (exit->vnum != room)
				{
					ses->map->nofollow++;

					follow_map(ses, exit->name);

					ses->map->nofollow--;

					pop_call();
					return 1;
				}
			}
		}

		show_vtmap(ses);

		pop_call();
		return 1;
	}

	if (!HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) && !HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC))
	{
		char temp[BUFFER_SIZE];
		struct listnode *node;

		if ((node = search_node_list(ses->list[LIST_PATHDIR], argument)) == NULL)
		{
			pop_call();
			return 0;
		}

		for (room = 1 ; room < ses->map->size ; room++)
		{
			if (ses->map->room_list[room] == NULL)
			{
				break;
			}
		}

		if (room == ses->map->size)
		{
			tintin_printf2(ses, "#MAP: Maximum amount of rooms of %d reached. Consider updating the C value in your map file.", ses->map->size);

			pop_call();
			return 1;
		}

		if (find_coord(ses, argument))
		{
			room = map_search_tar_room;

			show_message(ses, -1, "#MAP CREATE LINK %5d {%s}.", room, ses->map->room_list[room]->name);

			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_LINK);
		}
		else
		{
			sprintf(temp, "{%d} {0} {} {%d} { }", room, room);
			create_room(ses, temp);

			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE|MAP_UNDO_LINK);
		}
		sprintf(temp, "{%d} {%s} {%s}", room, node->left, node->left);
		create_exit(ses, ses->map->in_room, temp);

		if (find_exit(ses, room, node->right) == NULL)
		{
			sprintf(temp, "{%d} {%s} {%s}", ses->map->in_room, node->right, node->right);
			create_exit(ses, room, temp);
		}

		if (ses->map->nofollow == 0)
		{
			ses->map->nofollow++;

			script_driver(ses, -1, argument);

			ses->map->nofollow--;
		}
		goto_room(ses, room);

		show_vtmap(ses);

		pop_call();
		return 1;
	}
	pop_call();
	return 0;
}

void add_undo(struct session *ses, char *format, ...)
{
	struct link_data *link;
	char buf[BUFFER_SIZE], *arg, dir[BUFFER_SIZE], rev[BUFFER_SIZE], flag[BUFFER_SIZE];
	va_list args;

	push_call("add_undo(%s,%s)",ses->name, format);

	va_start(args, format);
	vsprintf(buf, format, args);
	va_end(args);

	arg = get_arg_in_braces(buf, dir, FALSE);
	arg = get_arg_in_braces(arg, rev, FALSE);
	arg = get_arg_in_braces(arg, flag, FALSE);

	link = (struct link_data *) calloc(1, sizeof(struct link_data));

	link->str1 = strdup(dir);
	link->str2 = strdup(rev);
	link->str3 = strdup(flag);

	LINK(link, ses->map->undo_head, ses->map->undo_tail);

	ses->map->undo_size++;

	if (ses->map->undo_size > 100)
	{
		del_undo(ses, ses->map->undo_head);
	}
	pop_call();
	return;
}

void del_undo(struct session *ses, struct link_data *link)
{
	UNLINK(link, ses->map->undo_head, ses->map->undo_tail);

	free(link->str1);
	free(link->str2);
	free(link->str3);

	free(link);

	ses->map->undo_size--;
}

/*
	Draws a map on a grid, breadth first improvements by Bryan Turner
*/

#define MAP_BF_SIZE 800

struct grid_node
{
	int vnum;
	int x;
	int y;
	int z;
	int size;
};

void build_map_grid_bf(int vnum, int x, int y, int z)
{
	int head, tail;
	struct grid_node *node, *temp, list[MAP_BF_SIZE];
	struct exit_data *exit;
	struct room_data *room;
	int xx, yy, zz;

	head = 0;
	tail = 1;

	node = &list[head];

	node->vnum = vnum;
	node->x    = x;
	node->y    = y;
	node->z    = z;
	node->size = 0;

	while (head != tail)
	{
		node = &list[head];

		head = (head + 1) % MAP_BF_SIZE;

		room = map_search_ses->map->room_list[node->vnum];

		if (room->size <= node->size)
		{
			continue;
		}

		room->size = node->size;

		if (node->x >= 0 && node->x < map_grid_x && node->y >= 0 && node->y < map_grid_y && node->z == 0)
		{
			if (map_search_ses->map->grid[node->x + map_grid_x * node->y] == NULL)
			{
				map_search_ses->map->grid[node->x + map_grid_x * node->y] = room;
			}
			else
			{
				continue;
			}
		}

		for (exit = room->f_exit ; exit ; exit = exit->next)
		{
			if (head == (tail + 1) % MAP_BF_SIZE)
			{
				break;
			}

			if (exit->dir == 0)
			{
				continue;
			}

			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE))
			{
				continue;
			}

			if (HAS_BIT(map_search_ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
			{
				continue;
			}

			xx = node->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
			yy = node->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
			zz = node->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);

			if (xx >= 0 && xx < map_grid_x && yy >= 0 && yy < map_grid_y && zz == 0)
			{
				if (map_search_ses->map->grid[xx + map_grid_x * yy] && map_search_ses->map->grid[xx + map_grid_x * yy]->size <= room->size + 1)
				{
					continue;
				}
			}

			temp = &list[tail];

			temp->vnum = exit->vnum;
			temp->x    = xx;
			temp->y    = yy;
			temp->z    = zz;
			temp->size = node->size + 1;

			tail = (tail + 1) % MAP_BF_SIZE;
		}
	}
}



void create_map_grid(struct session *ses, int room, int x, int y)
{
	int vnum;

	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
	{
		if (ses->map->room_list[vnum])
		{
			ses->map->room_list[vnum]->size = 500;
		}
	}

	for (vnum = 0 ; vnum < x * y ; vnum++)
	{
		ses->map->grid[vnum] = NULL;
	}

	map_search_ses = ses;

	map_grid_y = y;
	map_grid_x = x;

	if (ses->map->room_list[room])
	{
		build_map_grid_bf(room, x / 2, y / 2, 0);
	}
}



void show_vtmap(struct session *ses)
{
	char buf[BUFFER_SIZE], out[BUFFER_SIZE];
	int x, y, line;

	push_call("show_vtmap(%p)",ses);

	if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
	{
		pop_call();
		return;
	}

	if (ses->map->room_list[ses->map->in_room] == NULL)
	{
		pop_call();
		return;
	}

	if (ses != gtd->ses || HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD))
	{
		pop_call();
		return;
	}


	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
	{
		map_grid_y = (ses->top_row - 2) / 3;
		map_grid_x = (ses->cols    - 0) / 6;
	}
	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
	{
		map_grid_y = (ses->top_row - 2);
		map_grid_x = (ses->cols / 2);
	}
	else
	{
		map_grid_y = (ses->top_row - 2);
		map_grid_x = (ses->cols);
	}
	create_map_grid(ses, ses->map->in_room, map_grid_x, map_grid_y);

	save_pos(ses);
	goto_rowcol(ses, 1, 1);

	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
	{
		for (y = map_grid_y - 1 ; y >= 0 ; y--)
		{
			for (line = 1 ; line <= 3 ; line++)
			{
				strcpy(buf, "");

				for (x = 0 ; x < map_grid_x ; x++)
				{
					strcat(buf, draw_room(ses, ses->map->grid[x + map_grid_x * y], line));
				}
				substitute(ses, buf, out, SUB_COL);

				printf("%s\033[0K\n", out);
			}
		}
	}
	else
	{
		for (y = map_grid_y - 1 ; y >= 0 ; y--)
		{
			strcpy(buf, "");

			for (x = 0 ; x < map_grid_x ; x++)
			{
				strcat(buf, draw_room(ses, ses->map->grid[x + map_grid_x * y], 0));
			}
			substitute(ses, buf, out, SUB_COL);

			printf("%s\n", out);
		}
	}

	restore_pos(ses);

	pop_call();
	return;
}



char *draw_room(struct session *ses, struct room_data *room, int line)
{
	struct exit_data *exit;
	static char buf[101];
	int door, exits = 0, exit1 = 0, exit2 = 0;

	push_call("draw_room(%p,%p,%p)",ses,room,line);

	if (line)
	{
		if (room == NULL)
		{
			pop_call();
			return "      ";
		}

		sprintf(buf, "%s", ses->map->exit_color);

		for (exit = room->f_exit ; exit ; exit = exit->next)
		{
			door = exit->dir;

			switch (exit->dir)
			{
				case MAP_EXIT_N|MAP_EXIT_E:
					door = MAP_EXIT_NE;
					break;

				case MAP_EXIT_N|MAP_EXIT_W:
					door = MAP_EXIT_NW;
					break;

				case MAP_EXIT_S|MAP_EXIT_E:
					door = MAP_EXIT_SE;
					break;

				case MAP_EXIT_S|MAP_EXIT_W:
					door = MAP_EXIT_SW;
					break;

				case 0:
					continue;
			}

			SET_BIT(exits, door);
		}

		switch (line)
		{
			case 1:
				strcat(buf, HAS_BIT(exits, MAP_EXIT_NW) ? "\\ " : "  ");
				strcat(buf, HAS_BIT(exits, MAP_EXIT_N)  ? "|"   : " ");
				strcat(buf, HAS_BIT(exits, MAP_EXIT_U)  ? "+"   : " ");
				strcat(buf, HAS_BIT(exits, MAP_EXIT_NE) ? "/ "  : "  ");
				break;

			case 2:
				if (HAS_BIT(room->flags, ROOM_FLAG_VOID) || !HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
				{
					strcat(buf, HAS_BIT(exits, MAP_EXIT_W) ? "-" : " ");
				}

				if (room->vnum == ses->map->in_room)
				{
					if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
					{
						cat_sprintf(buf, "%s[<118>#%s]%s", *room->color ? room->color : ses->map->room_color, *room->color ? room->color : ses->map->room_color, ses->map->exit_color);
					}
					else
					{
						cat_sprintf(buf, "<118>%05d%s", room->vnum, ses->map->exit_color);
					}
				}
				else
				{
					if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
					{
						switch (exits)
						{
							case MAP_EXIT_N|MAP_EXIT_S:
								cat_sprintf(buf, " | ");
								break;
							case MAP_EXIT_E|MAP_EXIT_W:
								cat_sprintf(buf, "---");
								break;
							case MAP_EXIT_NE|MAP_EXIT_SW:
								cat_sprintf(buf, " / ");
								break;
							case MAP_EXIT_NW|MAP_EXIT_SE:
								cat_sprintf(buf, " \\ ");
								break;
							default:
								cat_sprintf(buf, " * ");
								break;
						}
					}
					else
					{
						if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
						{
							cat_sprintf(buf, "<128>%05d%s", room->vnum, ses->map->exit_color);
						}
						else if (strip_color_strlen(room->symbol) <= 1)
						{
							cat_sprintf(buf, "%s[%s%s]%s", HAS_BIT(room->flags, ROOM_FLAG_PATH) ? ses->map->path_color : *room->color ? room->color : ses->map->room_color, room->symbol, HAS_BIT(room->flags, ROOM_FLAG_PATH) ? ses->map->path_color : *room->color ? room->color : ses->map->room_color, ses->map->exit_color);
						}
						else
						{
							cat_sprintf(buf, "%s%-3s%s", HAS_BIT(room->flags, ROOM_FLAG_PATH) ? ses->map->path_color : *room->color ? room->color : ses->map->room_color, room->symbol, ses->map->exit_color);
						}
					}
				}

				if (HAS_BIT(room->flags, ROOM_FLAG_VOID) || !HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
				{
					strcat(buf, HAS_BIT(exits, MAP_EXIT_E) ? "--" : "  ");
				}
				else
				{
					strcat(buf, HAS_BIT(exits, MAP_EXIT_E) ? "-" : " ");
				}
				break;

			case 3:
				strcat(buf, HAS_BIT(exits, MAP_EXIT_SW) ? "/"   : " ");
				strcat(buf, HAS_BIT(exits, MAP_EXIT_D)  ? "-"   : " ");
				strcat(buf, HAS_BIT(exits, MAP_EXIT_S)  ? "| "  : "  ");
				strcat(buf, HAS_BIT(exits, MAP_EXIT_SE) ? "\\ " : "  ");
				break;
		}
		pop_call();
		return buf;
	}

	if (room == NULL)
	{
		if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
		{
			pop_call();
			return "  ";
		}
		else
		{
			pop_call();
			return " ";
		}
	}

	if (room->vnum == ses->map->in_room)
	{
		if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
		{
			sprintf(buf, "<118>%c%c", 199, 207);
		}
		else if (HAS_BIT(ses->map->flags, MAP_FLAG_VTGRAPHICS))
		{
			sprintf(buf, "<118>\033[12m%s\033[10m", ses->map->legend[16]);
		}
		else
		{
			sprintf(buf, "<118>%s", ses->map->legend[16]);
		}
		pop_call();
		return buf;
	}

	for (exit = room->f_exit ; exit ; exit = exit->next)
	{
		if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
		{
			switch (exit->dir)
			{
				case MAP_EXIT_N:
					SET_BIT(exit1, 1 << 0);
					SET_BIT(exit2, 1 << 0);
					SET_BIT(exits, MAP_EXIT_N);
					break;
				case MAP_EXIT_N|MAP_EXIT_W:
					SET_BIT(exit1, 1 << 1);
					SET_BIT(exits, MAP_EXIT_NW);
					break;
				case MAP_EXIT_N|MAP_EXIT_E:
					SET_BIT(exit2, 1 << 1);
					SET_BIT(exits, MAP_EXIT_NE);
					break;
				case MAP_EXIT_W:
					SET_BIT(exit1, 1 << 2);
					SET_BIT(exits, MAP_EXIT_W);
					break;
				case MAP_EXIT_E:
					SET_BIT(exit2, 1 << 2);
					SET_BIT(exits, MAP_EXIT_E);
					break;
				case MAP_EXIT_W|MAP_EXIT_S:
					SET_BIT(exit1, 1 << 3);
					SET_BIT(exits, MAP_EXIT_SW);
					break;
				case MAP_EXIT_E|MAP_EXIT_S:
					SET_BIT(exit2, 1 << 3);
					SET_BIT(exits, MAP_EXIT_SE);
					break;
				case MAP_EXIT_S:
					SET_BIT(exit1, 1 << 4);
					SET_BIT(exit2, 1 << 4);
					SET_BIT(exits, MAP_EXIT_S);
					break;
			}
			continue;
		}

		switch (exit->dir)
		{
			case MAP_EXIT_N|MAP_EXIT_E:
			case MAP_EXIT_N|MAP_EXIT_W:
			case MAP_EXIT_S|MAP_EXIT_E:
			case MAP_EXIT_S|MAP_EXIT_W:
				continue;
		}

		if (exit->dir >= MAP_EXIT_N && exit->dir <= MAP_EXIT_W)
		{
			SET_BIT(exits, exit->dir);
		}
	}

	if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
	{
		int room1 = exit1 + 128;
		int room2 = exit2 + 160;

		if (HAS_BIT(room->flags, ROOM_FLAG_RIVER))
		{
			switch (exits)
			{
				case 0:
					room1 = 192;
					room2 = 192 + 8;
					break;
				case MAP_EXIT_N:
					room1 = 192 + 1;
					room2 = 192 + 1 + 8;
					break;
				case MAP_EXIT_N|MAP_EXIT_W:
					room1 = 192 + 2;
					room2 = 192 + 1 + 8;
					break;
				case MAP_EXIT_S:
					room1 = 192 + 3;
					room2 = 192 + 3 + 8;
					break;
				case MAP_EXIT_W|MAP_EXIT_S:
					room1 = 192 + 5;
					room2 = 192 + 3 + 8;
					break;
				case MAP_EXIT_N|MAP_EXIT_W|MAP_EXIT_S:
					room1 = 192 + 6;
					room2 = 192 + 4 + 8;
					break;
				case MAP_EXIT_N|MAP_EXIT_E:
					room1 = 192 + 1;
					room2 = 192 + 2 + 8;
					break;
				case MAP_EXIT_N|MAP_EXIT_E|MAP_EXIT_W:
					room1 = 192 + 2;
					room2 = 192 + 2 + 8;
					break;
				case MAP_EXIT_E|MAP_EXIT_S:
					room1 = 192 + 3;
					room2 = 192 + 5 + 8;
					break;
				case MAP_EXIT_N|MAP_EXIT_E|MAP_EXIT_S:
					room1 = 192 + 4;
					room2 = 192 + 6 + 8;
					break;
				case MAP_EXIT_E|MAP_EXIT_S|MAP_EXIT_W:
					room1 = 192 + 5;
					room2 = 192 + 5 + 8;
					break;
			}
		}
		sprintf(buf, "%s%c%c", *room->color ? room->color : ses->map->room_color, room1, room2);
	}
	else if (HAS_BIT(ses->map->flags, MAP_FLAG_VTGRAPHICS))
	{
		sprintf(buf, "%s\033[12m%s\033[10m", *room->color ? room->color : ses->map->room_color, ses->map->legend[exits]);
	}
	else
	{
		sprintf(buf, "%s%s", *room->color ? room->color : ses->map->room_color, ses->map->legend[exits]);
	}
	pop_call();
	return buf;
}

int match_room(struct session *ses, int room, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5)
{
	if (ses->map->room_list[room] == NULL)
	{
		return 0;
	}

	if (*arg1)
	{
		if (!match(ses, ses->map->room_list[room]->name, arg1))
		{
			return 0;
		}
	}

	if (*arg2)
	{
		char exit[BUFFER_SIZE];
		int size = 0;
		char *arg = arg2;

		while (*arg)
		{
			arg = get_arg_in_braces(arg, exit, GET_ONE);

			size++;

			if (!find_exit(ses, room, exit))
			{
				size = -1;
				break;
			}

			if (*arg == COMMAND_SEPARATOR)
			{
				arg++;
			}
		}

		if (size != get_map_exits(ses, room))
		{
			return 0;
		}
	}

	if (*arg3)
	{
		if (!match(ses, ses->map->room_list[room]->desc, arg3))
		{
			return 0;
		}
	}

	if (*arg4)
	{
		if (!match(ses, ses->map->room_list[room]->area, arg4))
		{
			return 0;
		}
	}

	if (*arg5)
	{
		if (!match(ses, ses->map->room_list[room]->note, arg5))
		{
			return 0;
		}
	}

	return 1;
}

int find_room(struct session *ses, char *arg)
{
	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], arg4[BUFFER_SIZE], arg5[BUFFER_SIZE];
	int room, vnum, size;

	push_call("find_room(%p,%s)",ses,arg);

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN); // name
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN); // exits
	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN); // desc
	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN); // area
	arg = sub_arg_in_braces(ses, arg, arg5, GET_ALL, SUB_VAR|SUB_FUN); // note

	room = atoi(arg1);

	if (room > 0 && room < ses->map->size)
	{
		if (ses->map->room_list[room])
		{
			pop_call();
			return room;
		}

		if (!strcmp(arg2, "dig"))
		{
			sprintf(arg3, "{%d} {0} {} {%d} { }", room, room);
			create_room(ses, arg3);

			pop_call();
			return room;
		}
		pop_call();
		return -1;
	}

	fill_map(ses);

	vnum = -1;
	size = MAP_SEARCH_SIZE + 1;

	for (room = 0 ; room < ses->map->size ; room++)
	{
		if (!match_room(ses, room, arg1, arg2, arg3, arg4, arg5))
		{
			continue;
		}

		if (ses->map->room_list[room]->size < size)
		{
			size = ses->map->room_list[room]->size;
			vnum = room;
		}
	}
	pop_call();
	return vnum;
}

void goto_room(struct session *ses, int room)
{
	int last_room = ses->map->in_room;

	push_call("goto_room(%p,%d)",ses,room);

	if (ses->map->in_room)
	{
		check_all_events(ses, 0, 2, "MAP EXIT ROOM", ntos(last_room), ntos(room));
		check_all_events(ses, 1, 2, "MAP EXIT ROOM %d", last_room, ntos(last_room), ntos(room));
	}

	ses->map->in_room = room;

	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);

	if (last_room == 0)
	{
		check_all_events(ses, 0, 1, "MAP ENTER MAP", ntos(room));
	}

	check_all_events(ses, 0, 2, "MAP ENTER ROOM", ntos(room), ntos(last_room));
	check_all_events(ses, 1, 2, "MAP ENTER ROOM %d", room, ntos(room), ntos(last_room));

	pop_call();
	return;
}

struct exit_data *find_exit(struct session *ses, int room, char *arg)
{
	struct exit_data *exit;

	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
	{
		if (!strcmp(exit->name, arg) || exit->vnum == atoi(arg))
		{
			return exit;
		}
	}
	return NULL;
}

int revdir(int dir)
{
	int revdir = 0;

	if (HAS_BIT(dir, MAP_EXIT_N))
	{
		SET_BIT(revdir, MAP_EXIT_S);
	}

	if (HAS_BIT(dir, MAP_EXIT_E))
	{
		SET_BIT(revdir, MAP_EXIT_W);
	}

	if (HAS_BIT(dir, MAP_EXIT_S))
	{
		SET_BIT(revdir, MAP_EXIT_N);
	}

	if (HAS_BIT(dir, MAP_EXIT_W))
	{
		SET_BIT(revdir, MAP_EXIT_E);
	}

	if (HAS_BIT(dir, MAP_EXIT_U))
	{
		SET_BIT(revdir, MAP_EXIT_D);
	}

	if (HAS_BIT(dir, MAP_EXIT_D))
	{
		SET_BIT(revdir, MAP_EXIT_U);
	}

	return revdir;
}

struct exit_data *find_exit_dir(struct session *ses, int room, int dir)
{
	struct exit_data *exit;

	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
	{
		if (exit->dir == dir)
		{
			return exit;
		}
	}

	if (get_map_exits(ses, room) != 2)
	{
		show_message(map_search_ses, -1, "#ERROR: ROOM {%d} IS AN INVALID VOID ROOM.", room);

		return NULL;
	}

	if (ses->map->room_list[room]->f_exit->dir != revdir(dir))
	{
		return ses->map->room_list[room]->f_exit;
	}
	else
	{
		return ses->map->room_list[room]->l_exit;
	}
}

/*
	Fast, short distance node weighted algorithms - Igor
*/

int follow_void(struct session *ses, int from, int room, int dir)
{
	struct exit_data *exit;

	map_search_last_room = from;

	if (room == map_search_tar_room)
	{
		return room;
	}

	exit = find_exit_dir(ses, room, dir);

	if (exit)
	{
		if (HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_VOID))
		{
			return follow_void(ses, room, exit->vnum, exit->dir);
		}
		else
		{
			return exit->vnum;
		}
	}
	else
	{
		return room;
	}
}

void search_path(int room, int size, int dir)
{
	struct exit_data *exit;

	map_search_ses->map->room_list[room]->size = size;

	if (size >= map_search_max_size)
	{
		return;
	}

	if (room == map_search_tar_room)
	{
		map_search_exit_best = map_search_exit_node;
		map_search_max_size  = size;
	}
	else
	{
		if (HAS_BIT(map_search_ses->map->room_list[room]->flags, ROOM_FLAG_AVOID))
		{
			return;
		}

		if (HAS_BIT(map_search_ses->map->room_list[room]->flags, ROOM_FLAG_VOID))
		{
			exit = find_exit_dir(map_search_ses, room, dir);

			if (exit && map_search_ses->map->room_list[exit->vnum]->size > size)
			{
				search_path(exit->vnum, size, exit->dir);
			}
		}
		else
		{
			size++;

			for (exit = map_search_ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
			{
				if (map_search_ses->map->room_list[exit->vnum]->size > size)
				{
					search_path(exit->vnum, size, exit->dir);
				}
			}
		}
	}
}

void fill_map(struct session *ses)
{
	int vnum, room;
	struct exit_data *exit;

	push_call("fill_map(%p)",ses);

	map_search_ses       = ses;
	map_search_tar_room  = -1;
	map_search_max_size  = MAP_SEARCH_SIZE;

	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
	{
		if (ses->map->room_list[vnum])
		{
			ses->map->room_list[vnum]->size = map_search_max_size;
		}
	}

	if (ses->map->in_room == 0)
	{
		pop_call();
		return;
	}

	room = ses->map->in_room;

	ses->map->room_list[room]->size = 0;

	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
	{
		if (ses->map->room_list[exit->vnum])
		{
			search_path(exit->vnum, 1, exit->dir);
		}
	}

	pop_call();
	return;
}

void shortest_path(struct session *ses, int run, char *delay, char *arg)
{
	struct exit_data *exit;
	int room, vnum;

	if (HAS_BIT(ses->flags, SES_FLAG_MAPPING))
	{
		tintin_printf2(ses, "#SHORTEST PATH: You have to stop #PATH TRACKING first.");

		return;
	}

	kill_list(ses->list[LIST_PATH]);

	room = find_room(ses, arg);

	if (room == -1)
	{
		tintin_printf2(ses, "#SHORTEST PATH: Couldn't find the room %s", arg);
		return;
	}

	if (room == ses->map->in_room)
	{
		tintin_printf2(ses, "Already there.");
		return;
	}

	map_search_exit_best = NULL;
	map_search_ses       = ses;
	map_search_tar_room  = room;
	map_search_max_size  = MAP_SEARCH_SIZE;

	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
	{
		if (ses->map->room_list[vnum])
		{
			ses->map->room_list[vnum]->size = map_search_max_size;

			DEL_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
		}
	}

	room = ses->map->in_room;

	ses->map->room_list[room]->size = 0;

	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
	{
		if (ses->map->room_list[exit->vnum])
		{
			map_search_exit_node = exit;
			search_path(exit->vnum, 1, exit->dir);
		}
	}

	if (map_search_exit_best == NULL)
	{
		tintin_printf2(ses, "#SHORTEST PATH: No path found.");
		return;
	}

	while (TRUE)
	{
		ses->map->room_list[room]->size = 0;

		for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
		{
			if (ses->map->room_list[exit->vnum])
			{
				map_search_exit_node = exit;
				search_path(exit->vnum, 1, exit->dir);
			}
		}

		if (map_search_exit_best == NULL)
		{
			return;
		}

		if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
		{
		
			insert_node_list(ses->list[LIST_PATH], map_search_exit_best->cmd, "", "0");
		}
		else
		{
			insert_node_list(ses->list[LIST_PATH], map_search_exit_best->name, "", "0");
		}

		if (HAS_BIT(ses->map->room_list[map_search_exit_best->vnum]->flags, ROOM_FLAG_VOID))
		{
			room = follow_void(ses, room, map_search_exit_best->vnum, map_search_exit_best->dir);
		}
		else
		{
			room = map_search_exit_best->vnum;
		}

		SET_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);

		if (room == map_search_tar_room)
		{
			break;
		}

	}

	if (run)
	{
		path_run(ses, delay);
	}
}

/*
	Do a coordinate based search.
*/

int find_coord(struct session *ses, char *arg)
{
	int vnum, coord;

	map_grid_x = 0;
	map_grid_y = 0;
	map_grid_z = 0;

	map_search_ses      = ses;
	map_search_tar_room = 0;

	coord = get_map_exit(ses, arg);

	if (coord == 0)
	{
		return 0;
	}

	map_grid_y += (HAS_BIT(coord, MAP_EXIT_N) ? 1 : HAS_BIT(coord, MAP_EXIT_S) ? -1 : 0);
	map_grid_x += (HAS_BIT(coord, MAP_EXIT_E) ? 1 : HAS_BIT(coord, MAP_EXIT_W) ? -1 : 0);
	map_grid_z += (HAS_BIT(coord, MAP_EXIT_U) ? 1 : HAS_BIT(coord, MAP_EXIT_D) ? -1 : 0);

	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
	{
		if (ses->map->room_list[vnum])
		{
			ses->map->room_list[vnum]->size = MAP_SEARCH_SIZE;
		}
	}

	search_coord_bf(ses->map->in_room);

	if (ses->map->room_list[map_search_tar_room])
	{
		if (HAS_BIT(ses->map->room_list[map_search_tar_room]->flags, ROOM_FLAG_STATIC))
		{
			show_message(ses, -1, "#MAP: Linkable room is marked static. Creating overlapping room instead.");

			return 0;
		}
	}
	return map_search_tar_room;
}

void search_coord_bf(int vnum)
{
	int head, tail;
	struct grid_node *node, *temp, list[MAP_BF_SIZE];
	struct exit_data *exit;
	struct room_data *room;
	int xx, yy, zz;

	push_call("search_coord_bf(%d)",vnum);

	head = 0;
	tail = 1;

	node = &list[head];

	node->vnum = vnum;
	node->x    = 0;
	node->y    = 0;
	node->z    = 0;
	node->size = 0;

	while (head != tail)
	{
		node = &list[head];

		head = (head + 1) % MAP_BF_SIZE;

		room = map_search_ses->map->room_list[node->vnum];

		if (room->size <= node->size)
		{
			continue;
		}

		room->size = node->size;

		if (node->x == map_grid_x && node->y == map_grid_y && node->z == map_grid_z)
		{
			map_search_tar_room = node->vnum;

			pop_call();
			return;
		}

		for (exit = room->f_exit ; exit ; exit = exit->next)
		{
			if (head == (tail + 1) % MAP_BF_SIZE)
			{
				break;
			}

			if (exit->dir == 0)
			{
				continue;
			}

			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE))
			{
				continue;
			}

			if (HAS_BIT(map_search_ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
			{
				continue;
			}

			xx = node->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
			yy = node->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
			zz = node->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);

			temp = &list[tail];

			temp->vnum = exit->vnum;
			temp->x    = xx;
			temp->y    = yy;
			temp->z    = zz;
			temp->size = node->size + 1;

			tail = (tail + 1) % MAP_BF_SIZE;
		}
	}
	pop_call();
	return;
}

void explore_path(struct session *ses, int run, char *arg1, char *arg2)
{
	struct exit_data *exit;
	int room, vnum;

	if (HAS_BIT(ses->flags, SES_FLAG_MAPPING))
	{
		tintin_printf2(ses, "#MAP EXPLORE: You have to stop #PATH TRACKING first.");

		return;
	}

	kill_list(ses->list[LIST_PATH]);

	room = ses->map->in_room;

	exit = find_exit(ses, room, arg1);

	if (exit == NULL)
	{
		tintin_printf2(ses, "#MAP: There's no exit named '%s'.", arg1);
		return;
	}

	vnum = exit->vnum;

	if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
	{
	
		insert_node_list(ses->list[LIST_PATH], exit->cmd, "", "0");
	}
	else
	{
		insert_node_list(ses->list[LIST_PATH], exit->name, "", "0");
	}

	while (get_map_exits(ses, vnum) == 2)
	{
		if (ses->map->room_list[vnum]->f_exit->vnum != room)
		{
			exit = ses->map->room_list[vnum]->f_exit;
		}
		else
		{
			exit = ses->map->room_list[vnum]->l_exit;
		}

		if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
		{
			insert_node_list(ses->list[LIST_PATH], exit->cmd, "", "0");
		}
		else
		{
			insert_node_list(ses->list[LIST_PATH], exit->name, "", "0");
		}

		if (HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_VOID))
		{
			vnum = follow_void(ses, room, exit->vnum, exit->dir);
			room = map_search_last_room;
		}
		else
		{
			room = vnum;
			vnum = exit->vnum;
		}
	}

	if (run)
	{
		path_run(ses, arg2);
	}
}