Scandum 6 years ago
parent
commit
4048d5a5ea
54 changed files with 12537 additions and 6200 deletions
  1. 1 1
      mods/igr.mods
  2. 1 1
      src/Makefile.in
  3. 11 11
      src/advertise.c
  4. 83 23
      src/buffer.c
  5. 147 131
      src/class.c
  6. 45 14
      src/config.c
  7. 137 49
      src/cursor.c
  8. 29 8
      src/daemon.c
  9. 132 57
      src/data.c
  10. 3 4
      src/debug.c
  11. 186 0
      src/dict.c
  12. 25 0
      src/dict.h
  13. 782 36
      src/draw.c
  14. 86 32
      src/event.c
  15. 14 6
      src/files.c
  16. 241 107
      src/help.c
  17. 2 3
      src/history.c
  18. 48 7
      src/input.c
  19. 64 5
      src/line.c
  20. 134 29
      src/list.c
  21. 13 7
      src/log.c
  22. 82 13
      src/main.c
  23. 6553 4424
      src/mapper.c
  24. 118 6
      src/math.c
  25. 2 3
      src/mccp.c
  26. 93 23
      src/memory.c
  27. 25 0
      src/misc.c
  28. 6 4
      src/msdp.c
  29. 309 15
      src/nest.c
  30. 7 29
      src/net.c
  31. 226 13
      src/parse.c
  32. 69 73
      src/path.c
  33. 3 4
      src/port.c
  34. 252 33
      src/regex.c
  35. 4 12
      src/scan.c
  36. 84 41
      src/screen.c
  37. 9 9
      src/session.c
  38. 19 2
      src/show.c
  39. 18 17
      src/split.c
  40. 580 20
      src/substitute.c
  41. 88 1
      src/system.c
  42. 242 85
      src/tables.c
  43. 7 2
      src/telnet.h
  44. 170 22
      src/telopt_client.c
  45. 39 3
      src/terminal.c
  46. 74 68
      src/text.c
  47. 264 105
      src/tintin.h
  48. 18 27
      src/tokenize.c
  49. 1 2
      src/trigger.c
  50. 96 33
      src/update.c
  51. 480 527
      src/utf8.c
  52. 3 3
      src/utils.c
  53. 326 41
      src/variable.c
  54. 86 9
      src/vt102.c

+ 1 - 1
mods/igr.mods

@@ -1,4 +1,4 @@
-Nov 2019        2.01.93
+Nov 2019        2.02.00
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------
 
 
 regex.c         Added support for using %+4s to match 4 spaces, or %+0..2d
 regex.c         Added support for using %+4s to match 4 spaces, or %+0..2d

+ 1 - 1
src/Makefile.in

@@ -64,7 +64,7 @@ system.o mapper.o tables.o buffer.o event.o tokenize.o chat.o utf8.o \
 advertise.o list.o forkpty.o utils.o line.o data.o variable.o msdp.o \
 advertise.o list.o forkpty.o utils.o line.o data.o variable.o msdp.o \
 port.o scan.o telopt_client.o screen.o cursor.o nest.o show.o mccp.o \
 port.o scan.o telopt_client.o screen.o cursor.o nest.o show.o mccp.o \
 telopt_server.o draw.o log.o path.o session.o class.o config.o ssl.o \
 telopt_server.o draw.o log.o path.o session.o class.o config.o ssl.o \
-regex.o substitute.o daemon.o
+regex.o substitute.o daemon.o dict.o
 
 
 default: all
 default: all
 
 

+ 11 - 11
src/advertise.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2009                       *
 *                      coded by Igor van den Hoven 2009                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -102,10 +101,10 @@ struct advertisement_type advertisement_table[] =
 		"<178>To connect to Kallisti MUD enter: #session LoK kallistimud.com 4000\n"
 		"<178>To connect to Kallisti MUD enter: #session LoK kallistimud.com 4000\n"
 		"\n",
 		"\n",
 	},
 	},
-
+/*
 	{
 	{
-		1400000000, /* 2014 */
- 		1800000000, /* 2027 */
+		1400000000, // 2014
+ 		1800000000, // 2027
 		100,
 		100,
 
 
 		"\n"
 		"\n"
@@ -134,7 +133,7 @@ struct advertisement_type advertisement_table[] =
 		"<178>To connect to Lowlands enter: #session lol lolamud.net 6969\n"
 		"<178>To connect to Lowlands enter: #session lol lolamud.net 6969\n"
 		"\n"
 		"\n"
 	},
 	},
-
+*/
 	{
 	{
 		1400000000,
 		1400000000,
 		1800000000,
 		1800000000,
@@ -176,7 +175,7 @@ struct advertisement_type advertisement_table[] =
 		"<078>Ateraan is a world of Intensive Roleplaying offering many unique and powerful\n"
 		"<078>Ateraan is a world of Intensive Roleplaying offering many unique and powerful\n"
 		"<078>guilds, races, politics, religion, justice, economy, and a storyline that is\n"
 		"<078>guilds, races, politics, religion, justice, economy, and a storyline that is\n"
 		"<078>dominantly player controlled and based on a novel. The game is based on a\n"
 		"<078>dominantly player controlled and based on a novel. The game is based on a\n"
-		"<078>Kingdom with fighters, merchants, mages, and thieves, and a fierce southern\n"
+		"<078>Kingdom with knights, merchants, mages, and thieves, and a fierce southern\n"
 		"<078>state that has warriors, shaman, slaves, and servants. Ships rule the seas and\n"
 		"<078>state that has warriors, shaman, slaves, and servants. Ships rule the seas and\n"
 		"<078>caravans travel the lands. With 100's of players and features like invasions,\n"
 		"<078>caravans travel the lands. With 100's of players and features like invasions,\n"
 		"<078>ship creation, house building, clans, theaters, leatherball fields, and massive\n"
 		"<078>ship creation, house building, clans, theaters, leatherball fields, and massive\n"
@@ -194,10 +193,10 @@ struct advertisement_type advertisement_table[] =
                 "<178>To connect to New Worlds Ateraan enter: #session nwa ateraan.com 4002\n"
                 "<178>To connect to New Worlds Ateraan enter: #session nwa ateraan.com 4002\n"
                 "\n"
                 "\n"
 	},
 	},
-
+/*
 	{
 	{
-		1400000000,  /* 2014 */ 
-		1800000000,  /* 2027 */ 
+		1400000000,  // 2014
+		1800000000,  // 2027
 		100,
 		100,
 
 
 		"\n"
 		"\n"
@@ -224,6 +223,7 @@ struct advertisement_type advertisement_table[] =
 		"<178>To connect to Primal Darkness enter: #session pd mud.primaldarkness.com 5000\n"
 		"<178>To connect to Primal Darkness enter: #session pd mud.primaldarkness.com 5000\n"
 		"\n"
 		"\n"
 	},
 	},
+*/
 /*	{
 /*	{
 		1400000000,
 		1400000000,
  		1800000000,
  		1800000000,

+ 83 - 23
src/buffer.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*              (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                   *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2004                        *
+*                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -98,7 +97,7 @@ void check_buffer(struct session *ses)
 	{
 	{
 		buffer = ses->scroll->buffer[index];
 		buffer = ses->scroll->buffer[index];
 
 
-		if (buffer->width < wrap)
+		if (buffer->height == 1 && buffer->width < wrap - 1)
 		{
 		{
 			buffer->height = buffer->lines;
 			buffer->height = buffer->lines;
 		}
 		}
@@ -269,7 +268,7 @@ void buffer_print(struct session *ses, int index, int start, int end)
 
 
 	col_len = get_scroll_cols(ses);
 	col_len = get_scroll_cols(ses);
 
 
-	if (end + start == 0)
+	if (start == 0 && end == 0)
 	{
 	{
 		if (HAS_BIT(ses->flags, SES_FLAG_PRINTBUFFER) || ses->scroll->line == ses->scroll->used - 1)
 		if (HAS_BIT(ses->flags, SES_FLAG_PRINTBUFFER) || ses->scroll->line == ses->scroll->used - 1)
 		{
 		{
@@ -284,7 +283,7 @@ void buffer_print(struct session *ses, int index, int start, int end)
 
 
 		if (ses->cur_row != ses->split->bot_row)
 		if (ses->cur_row != ses->split->bot_row)
 		{
 		{
-			print_stdout("%02d \e[1;32mmisaligned", ses->cur_row);
+			print_stdout("%02d \e[1;32mmisaligned (%d)", ses->cur_row, ses->scroll->line);
 		}
 		}
 		else
 		else
 		{
 		{
@@ -299,7 +298,10 @@ void buffer_print(struct session *ses, int index, int start, int end)
 		if (buffer->height == 1)
 		if (buffer->height == 1)
 		{
 		{
 //			print_stdout("\e[1;37m%02d", ses->cur_row);//
 //			print_stdout("\e[1;37m%02d", ses->cur_row);//
-			print_stdout("%s", buffer->str);
+
+			word_wrap_split(ses, buffer->str, temp, ses->wrap, start, end, 0, &height, &width);
+
+			print_stdout("%s", temp);
 
 
 			erase_cols(col_len - buffer->width);
 			erase_cols(col_len - buffer->width);
 
 
@@ -372,7 +374,7 @@ void buffer_print(struct session *ses, int index, int start, int end)
 
 
 int show_buffer(struct session *ses)
 int show_buffer(struct session *ses)
 {
 {
-	int scroll_size, scroll_cnt, scroll_tmp, scroll_add, scroll_cut;
+	int scroll_size, scroll_cnt, scroll_tmp, scroll_add, scroll_cut, start, end;
 
 
 	if (ses != gtd->ses)
 	if (ses != gtd->ses)
 	{
 	{
@@ -393,6 +395,8 @@ int show_buffer(struct session *ses)
 		scroll_add -= ses->scroll->base;
 		scroll_add -= ses->scroll->base;
 	}
 	}
 
 
+	// scroll_cut is cut from top line
+
 	while (TRUE)
 	while (TRUE)
 	{
 	{
 		scroll_tmp = ses->scroll->buffer[scroll_cnt]->height;
 		scroll_tmp = ses->scroll->buffer[scroll_cnt]->height;
@@ -438,28 +442,80 @@ int show_buffer(struct session *ses)
 		SET_BIT(ses->flags, SES_FLAG_READMUD);
 		SET_BIT(ses->flags, SES_FLAG_READMUD);
 	}
 	}
 
 
+	// scroll_cut is taken from top line
+	// scroll_base is taken from the bot line
+
 	if (scroll_cut)
 	if (scroll_cut)
 	{
 	{
 		scroll_tmp = ses->scroll->buffer[scroll_cnt]->height;
 		scroll_tmp = ses->scroll->buffer[scroll_cnt]->height;
 
 
-		if (ses->scroll->base >= scroll_size || scroll_cut == scroll_size)
+		// bottom
+
+		if (scroll_cut == scroll_size)
+		{
+			start = scroll_tmp - scroll_cut;
+			end   = scroll_tmp;
+
+			if (end - start != scroll_size)
+			{
+//				print_stdout("\e[1;32mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
+			}
+			else
+			{
+				buffer_print(ses, scroll_cnt, start, end);
+			}
+		}
+		// middle chunk
+
+		else if (scroll_cut > scroll_size)
 		{
 		{
-//			print_stdout("scroll_cnt %d, scroll->base: %d, scroll_tmp %d, scroll_cut %d\n", scroll_cnt, ses->scroll->base, scroll_tmp, scroll_cut);
-			buffer_print(ses, scroll_cnt, scroll_tmp - scroll_cut, scroll_tmp - scroll_cut + scroll_size);
+			start = scroll_tmp - scroll_cut;
+			end   = scroll_tmp - scroll_cut + scroll_size;
+
+//			if (end - start > scroll_size)
+			{
+//				print_stdout("\e[1;1H\e[1;33mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
+			}
+//			else
+			{
+				buffer_print(ses, scroll_cnt, start, end);
+			}
 
 
 			goto eof;
 			goto eof;
 		}
 		}
+
+		// top chunk
 		else if (scroll_add == 0)
 		else if (scroll_add == 0)
 		{
 		{
-//			print_stdout("scroll_add %d, scroll_cnt %d, scroll->base %d, scroll_tmp %d, scroll_cut %d\n", scroll_add, scroll_cnt, ses->scroll->base, scroll_tmp, scroll_cut);
+			start = ses->scroll->base;
+			end   = scroll_tmp - scroll_cut;
 
 
-			buffer_print(ses, scroll_cnt, ses->scroll->base, scroll_tmp - scroll_cut);
+//			if (end - start > scroll_size)
+			{
+//				print_stdout("\e[1;1H\e[1;34mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
+			}
+//			else
+			{
+				buffer_print(ses, scroll_cnt, start, end);
+			}
 
 
 			goto eof;
 			goto eof;
 		}
 		}
+		// bot chunk
+
 		else
 		else
 		{
 		{
-			buffer_print(ses, scroll_cnt, scroll_tmp - scroll_cut, scroll_tmp);
+			start = scroll_tmp - scroll_cut;
+			end   = scroll_tmp;
+
+//			if (end - start > scroll_size)
+			{
+//				print_stdout("\e[1;1H\e[1;35mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
+			}
+//			else
+			{
+				buffer_print(ses, scroll_cnt, start, end);
+			}
 		}
 		}
 		scroll_cnt++;
 		scroll_cnt++;
 		scroll_cut = 0;
 		scroll_cut = 0;
@@ -481,7 +537,10 @@ int show_buffer(struct session *ses)
 
 
 		scroll_add -= scroll_tmp;
 		scroll_add -= scroll_tmp;
 
 
-		buffer_print(ses, scroll_cnt, 0, scroll_tmp);
+		start = 0;
+		end   = scroll_tmp;
+
+		buffer_print(ses, scroll_cnt, start, end);
 
 
 		scroll_cnt++;
 		scroll_cnt++;
 	}
 	}
@@ -490,7 +549,10 @@ int show_buffer(struct session *ses)
 	{
 	{
 		scroll_tmp = ses->scroll->buffer[scroll_cnt]->height;
 		scroll_tmp = ses->scroll->buffer[scroll_cnt]->height;
 
 
-		buffer_print(ses, scroll_cnt, 0, scroll_tmp - ses->scroll->base);
+		start = 0;
+		end   = scroll_tmp - ses->scroll->base;
+
+		buffer_print(ses, scroll_cnt, start, end);
 	}
 	}
 
 
 	eof:
 	eof:
@@ -499,8 +561,6 @@ int show_buffer(struct session *ses)
 
 
 	buffer_print(ses, 0, 0, 0);
 	buffer_print(ses, 0, 0, 0);
 
 
-
-
 	restore_pos(ses);
 	restore_pos(ses);
 
 
 	if (IS_SPLIT(ses))
 	if (IS_SPLIT(ses))
@@ -831,7 +891,7 @@ DO_BUFFER(buffer_get)
 
 
 	if (*arg3 == 0)
 	if (*arg3 == 0)
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg1, "%s", ses->scroll->buffer[min]->str);
+		set_nest_node_ses(ses, arg1, "%s", ses->scroll->buffer[min]->str);
 
 
 		return;
 		return;
 	}
 	}
@@ -853,13 +913,13 @@ DO_BUFFER(buffer_get)
 
 
 	cnt = 0;
 	cnt = 0;
 
 
-	set_nest_node(ses->list[LIST_VARIABLE], arg1, "");
+	set_nest_node_ses(ses, arg1, "");
 
 
 	while (min <= max)
 	while (min <= max)
 	{
 	{
 		sprintf(arg2, "%s[%d]", arg1, ++cnt);
 		sprintf(arg2, "%s[%d]", arg1, ++cnt);
 
 
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", ses->scroll->buffer[min++]->str);
+		set_nest_node_ses(ses, arg2, "%s", ses->scroll->buffer[min++]->str);
 	}
 	}
 
 
 	show_message(ses, LIST_COMMAND, "#BUFFER GET: %d LINES SAVED TO {%s}.", cnt, arg1);
 	show_message(ses, LIST_COMMAND, "#BUFFER GET: %d LINES SAVED TO {%s}.", cnt, arg1);
@@ -887,7 +947,7 @@ DO_BUFFER(buffer_write)
 		{
 		{
 			show_message(ses, LIST_COMMAND, "#OK: WRITING BUFFER TO '%s'.", arg1);
 			show_message(ses, LIST_COMMAND, "#OK: WRITING BUFFER TO '%s'.", arg1);
 
 
-			loginit(ses, fp, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+			loginit(ses, fp, ses->logmode + LOG_FLAG_OVERWRITE);
 
 
 			for (cnt = 0 ; cnt < ses->scroll->used ; cnt++)
 			for (cnt = 0 ; cnt < ses->scroll->used ; cnt++)
 			{
 			{

+ 147 - 131
src/class.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*              (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                   *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2004                        *
+*                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 
 
@@ -32,7 +31,6 @@ DO_COMMAND(do_class)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	int i;
 	int i;
-
 	struct listroot *root;
 	struct listroot *root;
 	struct listnode *node;
 	struct listnode *node;
 
 
@@ -55,7 +53,7 @@ DO_COMMAND(do_class)
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
-		class_list(ses, arg1, arg2);
+		class_list(ses, NULL, arg1, arg2);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -73,13 +71,15 @@ DO_COMMAND(do_class)
 		}
 		}
 		else
 		else
 		{
 		{
-			if (!search_node_list(ses->list[LIST_CLASS], arg1))
+			node = search_node_list(ses->list[LIST_CLASS], arg1);
+
+			if (node == NULL)
 			{
 			{
 				check_all_events(ses, SUB_ARG, 0, 1, "CLASS CREATED", arg1);
 				check_all_events(ses, SUB_ARG, 0, 1, "CLASS CREATED", arg1);
 
 
-				update_node_list(ses->list[LIST_CLASS], arg1, arg2, arg3, "");
+				node = update_node_list(ses->list[LIST_CLASS], arg1, "", arg3, "");
 			}
 			}
-			class_table[i].group(ses, arg1, arg3);
+			class_table[i].fun(ses, node, arg1, arg3);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -108,32 +108,31 @@ int count_class(struct session *ses, struct listnode *group)
 	return cnt;
 	return cnt;
 }
 }
 
 
-
-DO_CLASS(class_open)
+DO_CLASS(class_clear)
 {
 {
-	int count;
+	int type, index;
 
 
-	if (!strcmp(ses->group, arg1))
-	{
-		show_message(ses, LIST_CLASS, "#CLASS {%s} IS ALREADY OPENED AND ACTIVATED.", arg1);
-	}
-	else
+	for (type = 0 ; type < LIST_MAX ; type++)
 	{
 	{
-		if (*ses->group)
+		if (!HAS_BIT(ses->list[type]->flags, LIST_FLAG_CLASS))
 		{
 		{
-			check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
-			check_all_events(ses, SUB_ARG, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
+			continue;
 		}
 		}
-		RESTRING(ses->group, arg1);
-
-		count = atoi(ses->list[LIST_CLASS]->list[0]->arg3);
 
 
-		update_node_list(ses->list[LIST_CLASS], arg1, "", ntos(--count), "");
+		for (index = 0 ; index < ses->list[type]->used ; index++)
+		{
+			if (!strcmp(ses->list[type]->list[index]->group, arg1))
+			{
+				delete_index_list(ses->list[type], index--);
+			}
+		}
+	}
 
 
-		show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN OPENED AND ACTIVATED.", arg1);
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN CLEARED.", arg1);
 
 
-		check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", arg1);
-		check_all_events(ses, SUB_ARG, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
+	if (!strcmp(ses->group, arg1))
+	{
+		class_close(ses, node, arg1, arg2);
 	}
 	}
 
 
 	return ses;
 	return ses;
@@ -141,52 +140,42 @@ DO_CLASS(class_open)
 
 
 DO_CLASS(class_close)
 DO_CLASS(class_close)
 {
 {
-	struct listnode *node;
-
-	node = search_node_list(ses->list[LIST_CLASS], arg1);
-
-	if (node == NULL)
+	if (atoi(node->arg3) == 0)
 	{
 	{
-		show_message(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
+		show_message(ses, LIST_CLASS, "#CLASS {%s} IS ALREADY CLOSED.", arg1);
 	}
 	}
 	else
 	else
 	{
 	{
-		if (atoi(node->arg3) == 0)
-		{
-			show_message(ses, LIST_CLASS, "#CLASS {%s} IS ALREADY CLOSED.", arg1);
-		}
-		else
-		{
-			show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN CLOSED.", arg1);
+		show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN CLOSED.", arg1);
 
 
-			update_node_list(ses->list[LIST_CLASS], arg1, "", "0","");
+		update_node_list(ses->list[LIST_CLASS], arg1, "", "0","");
 
 
-			if (!strcmp(ses->group, arg1))
-			{
-				check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
-				check_all_events(ses, SUB_ARG, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
+		if (!strcmp(ses->group, arg1))
+		{
+			check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
+			check_all_events(ses, SUB_ARG, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
 
 
-				node = ses->list[LIST_CLASS]->list[0];
+			node = ses->list[LIST_CLASS]->list[0];
 
 
-				if (atoi(node->arg3))
-				{
-					RESTRING(ses->group, node->arg1);
+			if (atoi(node->arg3))
+			{
+				RESTRING(ses->group, node->arg1);
 
 
-					show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN ACTIVATED.", node->arg1);
+				show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN ACTIVATED.", node->arg1);
 
 
-					check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", node->arg1);
-					check_all_events(ses, SUB_ARG, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
-				}
-				else
-				{
-					RESTRING(ses->group, "");
-				}
+				check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", node->arg1);
+				check_all_events(ses, SUB_ARG, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
+			}
+			else
+			{
+				RESTRING(ses->group, "");
 			}
 			}
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
 }
 }
 
 
+
 DO_CLASS(class_list)
 DO_CLASS(class_list)
 {
 {
 	int i, j;
 	int i, j;
@@ -223,36 +212,92 @@ DO_CLASS(class_list)
 	return ses;
 	return ses;
 }
 }
 
 
-DO_CLASS(class_read)
+
+DO_CLASS(class_kill)
 {
 {
-	class_open(ses, arg1, arg2);
+	int group;
 
 
-	do_read(ses, arg2);
+	class_clear(ses, node, arg1, arg2);
 
 
-	class_close(ses, arg1, arg2);
+	group = search_index_list(ses->list[LIST_CLASS], arg1, NULL);
+
+	delete_index_list(ses->list[LIST_CLASS], group);
+
+	check_all_events(ses, SUB_ARG, 0, 1, "CLASS DESTROYED", arg1);
+	check_all_events(ses, SUB_ARG, 1, 1, "CLASS DESTROYED %s", arg1, arg1);
+
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN KILLED.", arg1);
 
 
 	return ses;
 	return ses;
 }
 }
 
 
-
-DO_CLASS(class_write)
+DO_CLASS(class_load)
 {
 {
 	FILE *file;
 	FILE *file;
-	int list, index;
 
 
-	if (!search_node_list(ses->list[LIST_CLASS], arg1))
+	if (node->data == NULL)
 	{
 	{
-		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
-		
+		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT HAVE ANY DATA SAVED.", arg1);
+
 		return ses;
 		return ses;
 	}
 	}
+	file = fmemopen(node->data, node->val32[1], "r");
 
 
-	if (*arg2 == 0 || (file = fopen(arg2, "w")) == NULL)
+	read_file(ses, file, arg1);
+
+	return ses;
+}
+
+DO_CLASS(class_open)
+{
+	int count;
+
+	if (!strcmp(ses->group, arg1))
 	{
 	{
-		show_error(ses, LIST_CLASS, "#ERROR: #CLASS WRITE {%s} - COULDN'T OPEN FILE TO WRITE.", arg2);
-		
-		return ses;
+		show_message(ses, LIST_CLASS, "#CLASS {%s} IS ALREADY OPENED AND ACTIVATED.", arg1);
 	}
 	}
+	else
+	{
+		if (*ses->group)
+		{
+			check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
+			check_all_events(ses, SUB_ARG, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
+		}
+		RESTRING(ses->group, arg1);
+
+		count = atoi(ses->list[LIST_CLASS]->list[0]->arg3);
+
+		update_node_list(ses->list[LIST_CLASS], arg1, "", ntos(--count), "");
+
+		show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN OPENED AND ACTIVATED.", arg1);
+
+		check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", arg1);
+		check_all_events(ses, SUB_ARG, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
+	}
+
+	return ses;
+}
+
+
+DO_CLASS(class_read)
+{
+	class_open(ses, node, arg1, arg2);
+
+	do_read(ses, arg2);
+
+	class_close(ses, node, arg1, arg2);
+
+	return ses;
+}
+
+DO_CLASS(class_save)
+{
+	FILE *file;
+	int list, index;
+
+	str_cpy(&node->arg4, "");
+
+	file = open_memstream(&node->data, (size_t *) &node->val32[1]);
 
 
 	fprintf(file, "%cCLASS {%s} OPEN\n\n", gtd->tintin_char, arg1);
 	fprintf(file, "%cCLASS {%s} OPEN\n\n", gtd->tintin_char, arg1);
 
 
@@ -276,90 +321,61 @@ DO_CLASS(class_write)
 
 
 	fclose(file);
 	fclose(file);
 
 
-	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN WRITTEN TO FILE.", arg1);
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN SAVED TO MEMORY (%d BYTES) (%s).", arg1, node->val32[1], node->data);
+
+	return ses;
+}	
+
+DO_CLASS(class_size)
+{
+	if (*arg1 == 0 || *arg2 == 0)
+	{
+		show_error(ses, LIST_CLASS, "#SYNTAX: #CLASS {<class name>} SIZE {<variable>}.");
+		
+		return ses;
+	}
+
+	set_nest_node_ses(ses, arg2, "%d", count_class(ses, node));
 
 
 	return ses;
 	return ses;
 }
 }
 
 
-DO_CLASS(class_kill)
+
+DO_CLASS(class_write)
 {
 {
-	int type, index, group;
+	FILE *file;
+	int list, index;
 
 
-	if (!search_node_list(ses->list[LIST_CLASS], arg1))
+	if (*arg2 == 0 || (file = fopen(arg2, "w")) == NULL)
 	{
 	{
-		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
-
+		show_error(ses, LIST_CLASS, "#ERROR: #CLASS WRITE {%s} - COULDN'T OPEN FILE TO WRITE.", arg2);
+		
 		return ses;
 		return ses;
 	}
 	}
 
 
-	group = search_index_list(ses->list[LIST_CLASS], arg1, NULL);
+	fprintf(file, "%cCLASS {%s} OPEN\n\n", gtd->tintin_char, arg1);
 
 
-	for (type = 0 ; type < LIST_MAX ; type++)
+	for (list = 0 ; list < LIST_MAX ; list++)
 	{
 	{
-		if (!HAS_BIT(ses->list[type]->flags, LIST_FLAG_CLASS))
+		if (!HAS_BIT(ses->list[list]->flags, LIST_FLAG_CLASS))
 		{
 		{
 			continue;
 			continue;
 		}
 		}
 
 
-		for (index = 0 ; index < ses->list[type]->used ; index++)
+		for (index = 0 ; index < ses->list[list]->used ; index++)
 		{
 		{
-			if (!strcmp(ses->list[type]->list[index]->group, arg1))
+			if (!strcmp(ses->list[list]->list[index]->group, arg1))
 			{
 			{
-				delete_index_list(ses->list[type], index--);
+				write_node(ses, list, ses->list[list]->list[index], file);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	check_all_events(ses, SUB_ARG, 0, 1, "CLASS DESTROYED", arg1);
-	check_all_events(ses, SUB_ARG, 1, 1, "CLASS DESTROYED %s", arg1, arg1);
-
-	delete_index_list(ses->list[LIST_CLASS], group);
-
-	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN KILLED.", arg1);
-
-	if (!strcmp(ses->group, arg1))
-	{
-		check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
-
-		struct listnode *node = ses->list[LIST_CLASS]->list[0];
-
-		if (node && atoi(node->arg3))
-		{
-			RESTRING(ses->group, node->arg1);
-
-			show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN ACTIVATED.", node->arg1);
-
-			check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", arg1);
-		}
-		else
-		{
-			RESTRING(ses->group, "");
-		}
-	}
-
-	return ses;
-}
-
-DO_CLASS(class_size)
-{
-	struct listnode *node;
+	fprintf(file, "\n%cCLASS {%s} CLOSE\n", gtd->tintin_char, arg1);
 
 
-	if (*arg1 == 0 || *arg2 == 0)
-	{
-		show_error(ses, LIST_CLASS, "#SYNTAX: #CLASS {<class name>} SIZE {<variable>}.");
-		
-		return ses;
-	}
+	fclose(file);
 
 
-	node = search_node_list(ses->list[LIST_CLASS], arg1);
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN WRITTEN TO FILE.", arg1);
 
 
-	if (node == NULL)
-	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
-	}
-	else
-	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", count_class(ses, node));
-	}
 	return ses;
 	return ses;
 }
 }

+ 45 - 14
src/config.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*   file: config.c - funtions related tintin++ configuration                  *
-*              (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                   *
-*                     coded by Igor van den Hoven 2004                        *
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 
 
@@ -177,21 +176,26 @@ DO_CONFIG(config_charset)
 				DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 				DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			}
 			}
 		}
 		}
+		else if (is_abbrev(arg2, "ASCII"))
+		{
+			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
+		}
 		else if (is_abbrev(arg2, "BIG-5"))
 		else if (is_abbrev(arg2, "BIG-5"))
 		{
 		{
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			SET_BIT(ses->charset, CHARSET_FLAG_BIG5);
 			SET_BIT(ses->charset, CHARSET_FLAG_BIG5);
 		}
 		}
-		else if (is_abbrev(arg2, "UTF-8"))
+		else if (is_abbrev(arg2, "GBK-1"))
 		{
 		{
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
-			SET_BIT(ses->charset, CHARSET_FLAG_UTF8);
+			SET_BIT(ses->charset, CHARSET_FLAG_GBK1);
 		}
 		}
-		else if (is_abbrev(arg2, "ASCII"))
+		else if (is_abbrev(arg2, "UTF-8"))
 		{
 		{
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
+			SET_BIT(ses->charset, CHARSET_FLAG_UTF8);
 		}
 		}
-		else if (is_abbrev(arg2, "BIG2UTF"))
+		else if (is_abbrev(arg2, "BIG5TOUTF8") || is_abbrev(arg2, "BIG2UTF"))
 		{
 		{
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8);
@@ -201,14 +205,29 @@ DO_CONFIG(config_charset)
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8);
 		}
 		}
-		else if (is_abbrev(arg2, "KOI2UTF"))
+		else if (is_abbrev(arg2, "GBK1TOUTF8"))
+		{
+			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
+			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_GBK1TOUTF8);
+		}
+		else if (is_abbrev(arg2, "ISO1TOUTF8"))
+		{
+			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
+			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO1TOUTF8);
+		}
+		else if (is_abbrev(arg2, "ISO2TOUTF8"))
+		{
+			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
+			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO2TOUTF8);
+		}
+		else if (is_abbrev(arg2, "KOI8TOUTF8"))
 		{
 		{
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_KOI8TOUTF8);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_KOI8TOUTF8);
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|ASCII|BIG-5|FANSI|UTF-8|BIG2UTF|KOI2UTF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|ASCII|BIG-5|BIG5TOUTF8|FANSI|GBK-1|GBK1TOUTF8|KOI8TOUTF8|UTF-8>", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -219,17 +238,29 @@ DO_CONFIG(config_charset)
 		case CHARSET_FLAG_BIG5:
 		case CHARSET_FLAG_BIG5:
 			strcpy(arg2, "BIG-5");
 			strcpy(arg2, "BIG-5");
 			break;
 			break;
+		case CHARSET_FLAG_GBK1:
+			strcpy(arg2, "GBK-1");
+			break;
 		case CHARSET_FLAG_UTF8:
 		case CHARSET_FLAG_UTF8:
 			strcpy(arg2, "UTF-8");
 			strcpy(arg2, "UTF-8");
 			break;
 			break;
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8:
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8:
-			strcpy(arg2, "BIG2UTF");
+			strcpy(arg2, "BIG5TOUTF8");
 			break;
 			break;
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8:
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8:
 			strcpy(arg2, "FANSI");
 			strcpy(arg2, "FANSI");
 			break;
 			break;
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_GBK1TOUTF8:
+			strcpy(arg2, "GBK1TOUTF8");
+			break;
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_KOI8TOUTF8:
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_KOI8TOUTF8:
-			strcpy(arg2, "KOI2UTF");
+			strcpy(arg2, "KOI8TOUTF8");
+			break;
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO1TOUTF8:
+			strcpy(arg2, "ISO1TOUTF8");
+			break;
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO2TOUTF8:
+			strcpy(arg2, "ISO2TOUTF8");
 			break;
 			break;
 		default:
 		default:
 			strcpy(arg2, "ASCII");
 			strcpy(arg2, "ASCII");
@@ -592,7 +623,7 @@ DO_CONFIG(config_mousetracking)
 		{
 		{
 			DEL_BIT(ses->flags, SES_FLAG_MOUSEINFO);
 			DEL_BIT(ses->flags, SES_FLAG_MOUSEINFO);
 			SET_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
 			SET_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
-			SET_BIT(gtd->flags, SES_FLAG_MOUSETRACKING);
+			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
 			print_stdout("\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
 			print_stdout("\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
 		}
 		}
 		else if (is_abbrev(arg2, "DEBUG INFO"))
 		else if (is_abbrev(arg2, "DEBUG INFO"))

+ 137 - 49
src/cursor.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,29 +13,27 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*              (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                   *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2006                        *
+*                      coded by Igor van den Hoven 2006                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
-
 #include "tintin.h"
 #include "tintin.h"
 
 
 DO_COMMAND(do_cursor)
 DO_COMMAND(do_cursor)
 {
 {
-	char all[BUFFER_SIZE], arg1[BUFFER_SIZE], right[BUFFER_SIZE], temp[BUFFER_SIZE];
+	char all[BUFFER_SIZE], arg1[BUFFER_SIZE], temp[BUFFER_SIZE];
 	int cnt;
 	int cnt;
 
 
 	get_arg_in_braces(ses, arg, all, GET_ALL);
 	get_arg_in_braces(ses, arg, all, GET_ALL);
 
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	arg = sub_arg_in_braces(ses, arg, right, GET_ALL, SUB_VAR|SUB_FUN);
+//	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
@@ -60,7 +58,7 @@ DO_COMMAND(do_cursor)
 			{
 			{
 				if (is_abbrev(all, cursor_table[cnt].name))
 				if (is_abbrev(all, cursor_table[cnt].name))
 				{
 				{
-					cursor_table[cnt].fun(ses, right);
+					cursor_table[cnt].fun(ses, arg);
 
 
 					return ses;
 					return ses;
 				}
 				}
@@ -69,7 +67,7 @@ DO_COMMAND(do_cursor)
 			{
 			{
 				if (is_abbrev(arg1, cursor_table[cnt].name))
 				if (is_abbrev(arg1, cursor_table[cnt].name))
 				{
 				{
-					cursor_table[cnt].fun(ses, right);
+					cursor_table[cnt].fun(ses, arg);
 
 
 					return ses;
 					return ses;
 				}
 				}
@@ -225,23 +223,17 @@ int inputline_str_chk(int offset, int totlen)
 
 
 	while (offset < totlen)
 	while (offset < totlen)
 	{
 	{
-		if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_BIG5))
+		if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC))
 		{
 		{
-			if (HAS_BIT(gtd->input_buf[offset], 128) && (unsigned char) gtd->input_buf[offset] < 255)
+			if (is_euc_head(gtd->ses, &gtd->input_buf[offset]))
 			{
 			{
-				if (offset + 1 >= totlen)
-				{
-					return FALSE;
-				}
+				size = get_euc_size(gtd->ses, &gtd->input_buf[offset]);
 
 
-				if (is_big5(&gtd->input_buf[offset]))
-				{
-					offset += 2;
-				}
-				else
+				if (size == 1 || offset + size > totlen)
 				{
 				{
-					offset += 1;
+					return FALSE;
 				}
 				}
+				offset += size;
 			}
 			}
 			else
 			else
 			{
 			{
@@ -457,13 +449,18 @@ DO_CURSOR(cursor_delete)
 		return;
 		return;
 	}
 	}
 
 
-	if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && is_big5(&gtd->input_buf[gtd->input_cur]))
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(gtd->ses, &gtd->input_buf[gtd->input_cur]))
 	{
 	{
-		gtd->input_len--;
+		size = get_euc_width(gtd->ses, &gtd->input_buf[gtd->input_cur], &width);
 
 
-		memmove(&gtd->input_buf[gtd->input_cur+1], &gtd->input_buf[gtd->input_cur+2], gtd->input_len - gtd->input_cur + 1);
+		gtd->input_len -= size;
+
+		memmove(&gtd->input_buf[gtd->input_cur], &gtd->input_buf[gtd->input_cur + size], gtd->input_len - gtd->input_cur + 1);
 
 
-		input_printf("\e[2P");
+		if (width)
+		{
+			input_printf("\e[%dP", width);
+		}
 	}
 	}
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 	{
 	{
@@ -605,15 +602,19 @@ DO_CURSOR(cursor_delete_word_right)
 
 
 DO_CURSOR(cursor_echo)
 DO_CURSOR(cursor_echo)
 {
 {
-	if (*arg == 0)
+	char arg1[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
 	{
 	{
 		TOG_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 		TOG_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 	}
 	}
-	else if (!strcasecmp(arg, "ON"))
+	else if (!strcasecmp(arg1, "ON"))
 	{
 	{
 		SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 		SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 	}
 	}
-	else if (!strcasecmp(arg, "OFF"))
+	else if (!strcasecmp(arg1, "OFF"))
 	{
 	{
 		DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 		DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 	}
 	}
@@ -679,13 +680,17 @@ DO_CURSOR(cursor_exit)
 
 
 DO_CURSOR(cursor_get)
 DO_CURSOR(cursor_get)
 {
 {
-	if (*arg == 0)
+	char arg1[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
 	{
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR GET {variable}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR GET {variable}");
 	}
 	}
 	else
 	else
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg, "%s", gtd->input_buf);
+		set_nest_node_ses(ses, arg1, "%s", gtd->input_buf);
 	}
 	}
 }
 }
 
 
@@ -876,7 +881,7 @@ DO_CURSOR(cursor_history_find)
 
 
 	push_call("cursor_history_find(%s)", gtd->input_buf);
 	push_call("cursor_history_find(%s)", gtd->input_buf);
 
 
-	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5))
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_EUC))
 	{
 	{
 		if (inputline_str_chk(0, gtd->input_len) == FALSE)
 		if (inputline_str_chk(0, gtd->input_len) == FALSE)
 		{
 		{
@@ -931,15 +936,19 @@ DO_CURSOR(cursor_home)
 
 
 DO_CURSOR(cursor_insert)
 DO_CURSOR(cursor_insert)
 {
 {
-	if (*arg == 0)
+	char arg1[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
 	{
 	{
 		TOG_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
 		TOG_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
 	}
 	}
-	else if (!strcasecmp(arg, "ON"))
+	else if (!strcasecmp(arg1, "ON"))
 	{
 	{
 		SET_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
 		SET_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
 	}
 	}
-	else if (!strcasecmp(arg, "OFF"))
+	else if (!strcasecmp(arg1, "OFF"))
 	{
 	{
 		DEL_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
 		DEL_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
 	}
 	}
@@ -956,7 +965,7 @@ DO_CURSOR(cursor_left)
 
 
 	if (gtd->input_cur > 0)
 	if (gtd->input_cur > 0)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5))
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
 		{
 		{
 			gtd->input_cur--;
 			gtd->input_cur--;
 			gtd->input_pos--;
 			gtd->input_pos--;
@@ -1094,7 +1103,7 @@ DO_CURSOR(cursor_redraw_input)
 
 
 DO_CURSOR(cursor_redraw_line)
 DO_CURSOR(cursor_redraw_line)
 {
 {
-	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5))
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_EUC))
 	{
 	{
 		if (inputline_str_chk(0, gtd->input_len) == FALSE)
 		if (inputline_str_chk(0, gtd->input_len) == FALSE)
 		{
 		{
@@ -1160,15 +1169,12 @@ DO_CURSOR(cursor_right)
 
 
 	if (gtd->input_cur < gtd->input_len)
 	if (gtd->input_cur < gtd->input_len)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && (gtd->input_buf[gtd->input_cur] & 128) == 128)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
 		{
 		{
-			if (gtd->input_cur + 1 < gtd->input_len && gtd->input_buf[gtd->input_cur+1])
-			{
-				gtd->input_cur += 2;
-				gtd->input_pos += 2;
+			gtd->input_cur += get_euc_width(gtd->ses, &gtd->input_buf[gtd->input_cur], &width);
 
 
-				input_printf("\e[2C");
-			}
+			input_printf("\e[%dC", width);
+			gtd->input_pos += width;
 		}
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 		{
 		{
@@ -1230,17 +1236,21 @@ DO_CURSOR(cursor_right_word)
 
 
 DO_CURSOR(cursor_set)
 DO_CURSOR(cursor_set)
 {
 {
-	if (*arg == 0)
+	char arg1[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
 	{
 	{
 		return;
 		return;
 	}
 	}
 
 
-	ins_sprintf(&gtd->input_buf[gtd->input_cur], "%s", arg);
+	ins_sprintf(&gtd->input_buf[gtd->input_cur], "%s", arg1);
 
 
-	gtd->input_len += strlen(arg);
-	gtd->input_cur += strlen(arg);
+	gtd->input_len += strlen(arg1);
+	gtd->input_cur += strlen(arg1);
 
 
-	gtd->input_pos += inputline_raw_str_len(gtd->input_cur - strlen(arg), gtd->input_cur);
+	gtd->input_pos += inputline_raw_str_len(gtd->input_cur - strlen(arg1), gtd->input_cur);
 
 
 	cursor_redraw_line(ses, "");
 	cursor_redraw_line(ses, "");
 
 
@@ -1466,6 +1476,84 @@ int cursor_calc_input_now(void)
 	return input_now;
 	return input_now;
 }
 }
 
 
+DO_CURSOR(cursor_tab)
+{
+	char arg1[BUFFER_SIZE];
+	int flags;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	while (*arg)
+	{
+		if (is_abbrev(arg1, "LIST"))
+		{
+			SET_BIT(flags, TAB_FLAG_LIST);
+		}
+		else if (is_abbrev(arg1, "SCROLLBACK"))
+		{
+			SET_BIT(flags, TAB_FLAG_SCROLLBACK);
+		}
+
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
+	}
+
+	if (is_abbrev(arg1, "FORWARD"))
+	{
+		if (!HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB <LIST|SCROLLBACK> FORWARD");
+		}
+		else
+		{
+			if (HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK) == (TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+			{
+				cursor_mixed_tab_forward(ses, "");
+			}
+			else if (HAS_BIT(flags, TAB_FLAG_LIST))
+			{
+				cursor_tab_forward(ses, "");
+			}
+			else
+			{
+				cursor_auto_tab_forward(ses, "");
+			}
+		}
+		SET_BIT(flags, TAB_FLAG_FORWARD);
+	}
+	else if (is_abbrev(arg1, "BACKWARD"))
+	{
+		if (!HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB <LIST|SCROLLBACK> BACKWARD");
+		}
+		else
+		{
+			if (HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK) == (TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+			{
+				cursor_mixed_tab_backward(ses, "");
+			}
+			else if (HAS_BIT(flags, TAB_FLAG_LIST))
+			{
+				cursor_tab_backward(ses, "");
+			}
+			else
+			{
+				cursor_auto_tab_backward(ses, "");
+			}
+		}
+		SET_BIT(flags, TAB_FLAG_BACKWARD);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB <LIST|SCROLLBACK> <BACKWARD|FORWARD>");
+	}
+}
+
 DO_CURSOR(cursor_tab_forward)
 DO_CURSOR(cursor_tab_forward)
 {
 {
 	struct listroot *root = ses->list[LIST_COMMAND];
 	struct listroot *root = ses->list[LIST_COMMAND];
@@ -1643,7 +1731,7 @@ DO_CURSOR(cursor_screen_focus_in)
 {
 {
 	gtd->screen->focus = 1;
 	gtd->screen->focus = 1;
 
 
-	check_all_events(gtd->ses, SUB_ARG, 1, 1, "SCREEN FOCUS", ntos(gtd->screen->focus));
+	check_all_events(gtd->ses, SUB_ARG, 0, 1, "SCREEN FOCUS", ntos(gtd->screen->focus));
 
 
 	msdp_update_all("SCREEN_FOCUS", "%d", gtd->screen->focus);
 	msdp_update_all("SCREEN_FOCUS", "%d", gtd->screen->focus);
 }
 }

+ 29 - 8
src/daemon.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2007                        *
+*                      coded by Igor van den Hoven 2019                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -186,8 +185,6 @@ DO_DAEMON(daemon_attach)
 		return;
 		return;
 	}
 	}
 
 
-	DEL_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
-
 	sprintf(sock_file, "%s/%s.s", filename, arg2);
 	sprintf(sock_file, "%s/%s.s", filename, arg2);
 
 
 	if (access(sock_file, F_OK) == -1)
 	if (access(sock_file, F_OK) == -1)
@@ -203,12 +200,13 @@ DO_DAEMON(daemon_attach)
 
 
 		remove(sock_file);
 		remove(sock_file);
 
 
-		if (*arg1 == 0)
+		if (HAS_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE) || *arg1 == 0)
 		{
 		{
 			goto start;
 			goto start;
 		}
 		}
 		return;
 		return;
 	}
 	}
+	DEL_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
 
 
 	memset(&addr_un, 0, sizeof(addr_un));
 	memset(&addr_un, 0, sizeof(addr_un));
 
 
@@ -244,6 +242,16 @@ DO_DAEMON(daemon_attach)
 
 
 	show_message(ses, LIST_COMMAND, "#DAEMON ATTACH: CONNECTING {%d} TO {%d} {%s}", getpid(), gtd->attach_pid, sock_file);
 	show_message(ses, LIST_COMMAND, "#DAEMON ATTACH: CONNECTING {%d} TO {%d} {%s}", getpid(), gtd->attach_pid, sock_file);
 
 
+/*
+	error = select(gtd->attach_sock, NULL, &wds, NULL, &timeout);
+
+	if (error == -1)
+	{
+		syserr_printf(ses, "do_attach: %s: select:", sock_file);
+
+		return;
+	}
+*/
 	if (connect(gtd->attach_sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) == -1)
 	if (connect(gtd->attach_sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) == -1)
 	{
 	{
 		syserr_printf(ses, "do_attach: %s: connect:", sock_file);
 		syserr_printf(ses, "do_attach: %s: connect:", sock_file);
@@ -334,6 +342,11 @@ DO_DAEMON(daemon_detach)
 		return;
 		return;
 	}
 	}
 
 
+	if (!get_daemon_dir(ses, filename))
+	{
+		return;
+	}
+
 	pid = fork();
 	pid = fork();
 
 
 	if (pid < 0)
 	if (pid < 0)
@@ -349,7 +362,7 @@ DO_DAEMON(daemon_detach)
 		{
 		{
 			DEL_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
 			DEL_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
 
 
-//			usleep(100000);
+			usleep(2000);
 
 
 			daemon_attach(ses, *arg1 ? arg1 : "pid");
 			daemon_attach(ses, *arg1 ? arg1 : "pid");
 
 
@@ -640,6 +653,14 @@ void reset_daemon()
 
 
 		remove(gtd->detach_file);
 		remove(gtd->detach_file);
 	}
 	}
+/*
+	if (gtd->attach_sock > 0)
+	{
+		print_stdout("unlinking(%s)\n", gtd->attach_file);
+
+		unlink(gtd->attach_file);
+	}
+*/
 }
 }
 
 
 void winch_daemon()
 void winch_daemon()

+ 132 - 57
src/data.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                       coded by Igor van den Hoven 2004                      *
+*                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -53,6 +52,7 @@ void kill_list(struct listroot *root)
 	{
 	{
 		delete_index_list(root, root->used - 1);
 		delete_index_list(root, root->used - 1);
 	}
 	}
+//	root->update = 0;
 }
 }
 
 
 void free_list(struct listroot *root)
 void free_list(struct listroot *root)
@@ -79,10 +79,10 @@ struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int
 		{
 		{
 			node = (struct listnode *) calloc(1, sizeof(struct listnode));
 			node = (struct listnode *) calloc(1, sizeof(struct listnode));
 
 
-			node->arg1  = strdup(sourcelist->list[i]->arg1);
-			node->arg2  = strdup(sourcelist->list[i]->arg2);
-			node->arg3  = strdup(sourcelist->list[i]->arg3);
-			node->arg4  = strdup(sourcelist->list[i]->arg4);
+			node->arg1  = str_dup_clone(sourcelist->list[i]->arg1);
+			node->arg2  = str_dup_clone(sourcelist->list[i]->arg2);
+			node->arg3  = str_dup_clone(sourcelist->list[i]->arg3);
+			node->arg4  = str_dup_clone(sourcelist->list[i]->arg4);
 			node->flags = sourcelist->list[i]->flags;
 			node->flags = sourcelist->list[i]->flags;
 			node->group = strdup(sourcelist->list[i]->group);
 			node->group = strdup(sourcelist->list[i]->group);
 
 
@@ -129,15 +129,15 @@ struct listnode *insert_node_list(struct listroot *root, char *arg1, char *arg2,
 
 
 	node = (struct listnode *) calloc(1, sizeof(struct listnode));
 	node = (struct listnode *) calloc(1, sizeof(struct listnode));
 
 
-	if (HAS_BIT(root->flags, LIST_FLAG_PRIORITY) && *arg3 == 0)
+	if (list_table[root->type].priority_arg == 3 && *arg3 == 0)
 	{
 	{
 		strcpy(arg3, "5");
 		strcpy(arg3, "5");
 	}
 	}
 
 
-	node->arg1 = strdup(arg1);
-	node->arg2 = strdup(arg2);
-	node->arg3 = strdup(arg3);
-	node->arg4 = strdup(arg4);
+	node->arg1 = str_dup(arg1);
+	node->arg2 = str_dup(arg2);
+	node->arg3 = str_dup(arg3);
+	node->arg4 = str_dup(arg4);
 
 
 	if (gtd->level->oneshot)
 	if (gtd->level->oneshot)
 	{
 	{
@@ -190,19 +190,18 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 
 
 		if (strcmp(node->arg2, arg2) != 0)
 		if (strcmp(node->arg2, arg2) != 0)
 		{
 		{
-			free(node->arg2);
-			node->arg2 = strdup(arg2);
+			node->arg2 = str_cpy(&node->arg2, arg2);
 		}
 		}
 
 
 		switch (root->type)
 		switch (root->type)
 		{
 		{
 			case LIST_DELAY:
 			case LIST_DELAY:
 			case LIST_TICKER:
 			case LIST_TICKER:
-				node->data = 0;
+				node->val64 = 0;
 				break;
 				break;
 		}
 		}
 
 
-		if (HAS_BIT(root->flags, LIST_FLAG_PRIORITY) && *arg3 == 0)
+		if (list_table[root->type].priority_arg == 3 && *arg3 == 0)
 		{
 		{
 			strcpy(arg3, "5");
 			strcpy(arg3, "5");
 		}
 		}
@@ -226,8 +225,7 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 			case SORT_DELAY:
 			case SORT_DELAY:
 				if (strcmp(node->arg3, arg3) != 0)
 				if (strcmp(node->arg3, arg3) != 0)
 				{
 				{
-					free(node->arg3);
-					node->arg3 = strdup(arg3);
+					str_cpy(&node->arg3, arg3);
 				}
 				}
 				break;
 				break;
 
 
@@ -282,10 +280,11 @@ void delete_index_list(struct listroot *root, int index)
 		root->update--;
 		root->update--;
 	}
 	}
 
 
-	free(node->arg1);
-	free(node->arg2);
-	free(node->arg3);
-	free(node->arg4);
+	str_free(node->arg1);
+	str_free(node->arg2);
+	str_free(node->arg3);
+	str_free(node->arg4);
+
 	free(node->group);
 	free(node->group);
 
 
 	if (HAS_BIT(list_table[root->type].flags, LIST_FLAG_REGEX))
 	if (HAS_BIT(list_table[root->type].flags, LIST_FLAG_REGEX))
@@ -295,6 +294,21 @@ void delete_index_list(struct listroot *root, int index)
 			free(node->regex);
 			free(node->regex);
 		}
 		}
 	}
 	}
+
+	switch (root->type)
+	{
+		case LIST_TERRAIN:
+			free(node->room);
+			break;
+
+		case LIST_CLASS:
+			if (node->data)
+			{
+				free(node->data);
+			}
+			break;
+	}
+
 	free(node);
 	free(node);
 
 
 	memmove(&root->list[index], &root->list[index + 1], (root->used - index) * sizeof(struct listnode *));
 	memmove(&root->list[index], &root->list[index + 1], (root->used - index) * sizeof(struct listnode *));
@@ -327,6 +341,7 @@ struct listnode *search_node_list(struct listroot *root, char *text)
 		pop_call();
 		pop_call();
 		return root->list[index];
 		return root->list[index];
 	}
 	}
+
 	pop_call();
 	pop_call();
 	return NULL;
 	return NULL;
 }
 }
@@ -533,7 +548,7 @@ void show_node(struct listroot *root, struct listnode *node, int level)
 			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2, node->arg3, node->arg4);
 			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2, node->arg3, node->arg4);
 			break;
 			break;
 		case 3:
 		case 3:
-			if (HAS_BIT(list_table[root->type].flags, LIST_FLAG_PRIORITY) && !strcmp(node->arg3, "5"))
+			if (list_table[root->type].priority_arg == 3 && !strcmp(node->arg3, "5"))
 			{
 			{
 				tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2);
 				tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2);
 			}
 			}
@@ -583,35 +598,65 @@ int show_node_with_wild(struct session *ses, char *text, struct listroot *root)
 
 
 	if (node)
 	if (node)
 	{
 	{
-		switch(root->type)
+		if (list_table[root->type].script_arg == 2)
 		{
 		{
-			case LIST_EVENT:
-			case LIST_FUNCTION:
-			case LIST_MACRO:
+			if (list_table[root->type].args == 2)
+			{
 				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
 				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
-				break;
-
-			case LIST_ACTION:
-			case LIST_ALIAS:
-			case LIST_BUTTON:
-				if (!strcmp(node->arg3, "5"))
+			}
+			else if (list_table[root->type].args == 3)
+			{
+				if (list_table[root->type].priority_arg == 3)
 				{
 				{
-					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
+					if (!strcmp(node->arg3, "5"))
+					{
+						tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
+					}
+					else
+					{
+						tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
+					}
 				}
 				}
 				else
 				else
 				{
 				{
 					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
 					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
 				}
 				}
-				break;
-
-			case LIST_DELAY:
-			case LIST_TICKER:
-				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
-				break;
+			}
+		}
+		else
+		{
+			show_node(root, node, 0);
+		}
 
 
-			default:
-				show_node(root, node, 0);
-				break;
+		switch(root->type)
+		{
+//			case LIST_EVENT:
+//			case LIST_FUNCTION:
+//			case LIST_MACRO:
+//				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
+//				break;
+
+//			case LIST_ACTION:
+//			case LIST_ALIAS:
+//			case LIST_BUTTON:
+//				if (!strcmp(node->arg3, "5"))
+//				{
+//					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
+//				}
+//				else
+//				{
+//					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
+//				}
+//				break;
+
+//			case LIST_DELAY:
+//			case LIST_TICKER:
+//				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
+//				break;
+
+//			default:
+//				show_node(root, node, 0);
+//				break;
 		}
 		}
 		pop_call();
 		pop_call();
 		return TRUE;
 		return TRUE;
@@ -630,7 +675,7 @@ int show_node_with_wild(struct session *ses, char *text, struct listroot *root)
 	return found;
 	return found;
 }
 }
 
 
-void delete_node_with_wild(struct session *ses, int type, char *text)
+int delete_node_with_wild(struct session *ses, int type, char *text)
 {
 {
 	struct listroot *root = ses->list[type];
 	struct listroot *root = ses->list[type];
 	struct listnode *node;
 	struct listnode *node;
@@ -647,7 +692,7 @@ void delete_node_with_wild(struct session *ses, int type, char *text)
 
 
 		delete_node_list(ses, type, node);
 		delete_node_list(ses, type, node);
 
 
-		return;
+		return TRUE;
 	}
 	}
 
 
 	for (i = root->used - 1 ; i >= 0 ; i--)
 	for (i = root->used - 1 ; i >= 0 ; i--)
@@ -665,7 +710,10 @@ void delete_node_with_wild(struct session *ses, int type, char *text)
 	if (found == 0)
 	if (found == 0)
 	{
 	{
 		show_message(ses, type, "#KILL: NO MATCHES FOUND FOR %s {%s}.", list_table[type].name, arg1);
 		show_message(ses, type, "#KILL: NO MATCHES FOUND FOR %s {%s}.", list_table[type].name, arg1);
+
+		return FALSE;
 	}
 	}
+	return TRUE;
 }
 }
 
 
 
 
@@ -690,7 +738,10 @@ DO_COMMAND(do_kill)
 	{
 	{
 		for (index = 0 ; index < LIST_MAX ; index++)
 		for (index = 0 ; index < LIST_MAX ; index++)
 		{
 		{
-			kill_list(ses->list[index]);
+			if (!HAS_BIT(ses->list[index]->flags, LIST_FLAG_HIDE))
+			{
+				kill_list(ses->list[index]);
+			}
 		}
 		}
 		show_message(ses, LIST_COMMAND, "#KILL - ALL LISTS CLEARED.");
 		show_message(ses, LIST_COMMAND, "#KILL - ALL LISTS CLEARED.");
 
 
@@ -1002,13 +1053,13 @@ DO_COMMAND(do_info)
 				else if (is_abbrev(arg2, "SAVE"))
 				else if (is_abbrev(arg2, "SAVE"))
 				{
 				{
 					sprintf(name, "info[%s]", list_table[index].name);
 					sprintf(name, "info[%s]", list_table[index].name);
-					delete_nest_node(ses->list[LIST_VARIABLE], name);
+//					delete_nest_node(ses->list[LIST_VARIABLE], name);
 
 
 					for (cnt = 0 ; cnt < root->used ; cnt++)
 					for (cnt = 0 ; cnt < root->used ; cnt++)
 					{
 					{
 						sprintf(name, "info[%s][%d]", list_table[index].name, cnt);
 						sprintf(name, "info[%s][%d]", list_table[index].name, cnt);
 
 
-						set_nest_node(ses->list[LIST_VARIABLE], name, "{arg1}{%s}{arg2}{%s}{arg3}{%s}{arg4}{%s}{class}{%s}{flags}{%d}", root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->flags);
+						set_nest_node_ses(ses, name, "{arg1}{%s}{arg2}{%s}{arg3}{%s}{arg4}{%s}{class}{%s}{flags}{%d}", root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->flags);
 					}
 					}
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[%s]}", list_table[index].name);
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[%s]}", list_table[index].name);
 				}
 				}
@@ -1040,6 +1091,31 @@ DO_COMMAND(do_info)
 					tintin_printf2(ses, "#INFO MCCP3: TOTAL IN: %9ull TOTAL OUT: %9ull RATIO: %3d", ses->mccp3->total_in, ses->mccp3->total_out, 100 * ses->mccp3->total_out / ses->mccp3->total_in);
 					tintin_printf2(ses, "#INFO MCCP3: TOTAL IN: %9ull TOTAL OUT: %9ull RATIO: %3d", ses->mccp3->total_in, ses->mccp3->total_out, 100 * ses->mccp3->total_out / ses->mccp3->total_in);
 				}
 				}
 			}
 			}
+			else if (is_abbrev(arg1, "SESSION"))
+			{
+				if (is_abbrev(arg2, "SAVE"))
+				{
+					sprintf(name, "info[SESSION]");
+
+					set_nest_node_ses(ses, name, "{SESSION_NAME}{%s}", ses->name);
+					add_nest_node_ses(ses, name, "{SESSION_CLASS}{%s}", ses->group);
+					add_nest_node_ses(ses, name, "{SESSION_CREATED}{%d}", ses->created);
+					add_nest_node_ses(ses, name, "{SESSION_HOST} {%s}", ses->session_host);
+					add_nest_node_ses(ses, name, "{SESSION_IP} {%s}", ses->session_ip);
+					add_nest_node_ses(ses, name, "{SESSION_PORT} {%s}", ses->session_port);
+
+					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SESSION]}");
+				}
+				else
+				{
+					tintin_printf2(ses, "{SESSION_NAME}{%s}", ses->name);
+					tintin_printf2(ses, "{SESSION_CLASS}{%s}", ses->group);
+					tintin_printf2(ses, "{SESSION_CREATED}{%d}", ses->created);
+					tintin_printf2(ses, "{SESSION_HOST} {%s}", ses->session_host);
+					tintin_printf2(ses, "{SESSION_IP} {%s}", ses->session_ip);
+					tintin_printf2(ses, "{SESSION_PORT} {%s}", ses->session_port);
+				}
+			}
 			else if (is_abbrev(arg1, "STACK"))
 			else if (is_abbrev(arg1, "STACK"))
 			{
 			{
 				dump_stack();
 				dump_stack();
@@ -1050,13 +1126,10 @@ DO_COMMAND(do_info)
 				{
 				{
 					sprintf(name, "info[SYSTEM]");
 					sprintf(name, "info[SYSTEM]");
 
 
-					set_nest_node(ses->list[LIST_VARIABLE], name, "{CLIENT_NAME}{%s}{CLIENT_VERSION}{%-3s}", CLIENT_NAME, CLIENT_VERSION);
-
-					add_nest_node(ses->list[LIST_VARIABLE], name, "{CLIENT}{{NAME}{%s}{VERSION}{%-3s}}", CLIENT_NAME, CLIENT_VERSION);
-
-					add_nest_node(ses->list[LIST_VARIABLE], name, "{EXEC}{%s}{HOME}{%s}{LANG}{%s}{OS}{%s}{TERM}{%s}", gtd->exec, gtd->home, gtd->lang, gtd->os, gtd->term);
-
-					set_nest_node(ses->list[LIST_VARIABLE], name, "{DETACH_FILE}{%s}{ATTACH_FILE}{%-3s}", gtd->detach_port ? gtd->detach_file : "", gtd->attach_pid  ? gtd->attach_file : "");
+					set_nest_node_ses(ses, name, "{CLIENT_NAME}{%s}{CLIENT_VERSION}{%s}", CLIENT_NAME, CLIENT_VERSION);
+					add_nest_node_ses(ses, name, "{CLIENT}{{NAME}{%s}{VERSION}{%s}}", CLIENT_NAME, CLIENT_VERSION);
+					add_nest_node_ses(ses, name, "{EXEC}{%s}{HOME}{%s}{LANG}{%s}{OS}{%s}{TERM}{%s}", gtd->exec, gtd->home, gtd->lang, gtd->os, gtd->term);
+					add_nest_node_ses(ses, name, "{DETACH_FILE}{%s}{ATTACH_FILE}{%s}", gtd->detach_port > 0 ? gtd->detach_file : "", gtd->attach_sock > 0 ? gtd->attach_file : "");
 
 
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SYSTEM]}");
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SYSTEM]}");
 				}
 				}
@@ -1069,8 +1142,10 @@ DO_COMMAND(do_info)
 					tintin_printf2(ses, "#INFO SYSTEM: LANG           = %s", gtd->lang);
 					tintin_printf2(ses, "#INFO SYSTEM: LANG           = %s", gtd->lang);
 					tintin_printf2(ses, "#INFO SYSTEM: OS             = %s", gtd->os);
 					tintin_printf2(ses, "#INFO SYSTEM: OS             = %s", gtd->os);
 					tintin_printf2(ses, "#INFO SYSTEM: TERM           = %s", gtd->term);
 					tintin_printf2(ses, "#INFO SYSTEM: TERM           = %s", gtd->term);
+					tintin_printf2(ses, "#INFO SYSTEM: DETACH_PORT    = %d", gtd->detach_port);
 					tintin_printf2(ses, "#INFO SYSTEM: DETACH_FILE    = %s", gtd->detach_port ? gtd->detach_file : "");
 					tintin_printf2(ses, "#INFO SYSTEM: DETACH_FILE    = %s", gtd->detach_port ? gtd->detach_file : "");
-					tintin_printf2(ses, "#INFO SYSTEM: ATTACH_FILE    = %s", gtd->attach_pid  ? gtd->attach_file : "");
+					tintin_printf2(ses, "#INFO SYSTEM: ATTACH_SOCK    = %d", gtd->attach_sock);
+					tintin_printf2(ses, "#INFO SYSTEM: ATTACH_FILE    = %s", gtd->attach_sock ? gtd->attach_file : "");
 				}
 				}
 			}
 			}
 			else
 			else

+ 3 - 4
src/debug.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2004                        *
+*                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 
 

+ 186 - 0
src/dict.c

@@ -0,0 +1,186 @@
+/******************************************************************************
+*   This file is part of TinTin++                                             *
+*                                                                             *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
+*                                                                             *
+*   TinTin++ 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 3 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
+******************************************************************************/
+
+/******************************************************************************
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2019                       *
+******************************************************************************/
+
+#include "tintin.h"
+
+#include "dict.h"
+
+int dictionary_search(char **array, int array_size, char *key)
+{
+        // Copyright 2014-2020 Igor van den Hoven
+
+	register int mid, i, bot;
+	register char val;
+
+	bot = 0;
+	i = array_size - 1;
+	mid = i / 2;
+
+	while (mid)
+	{
+		val = strcmp(key, array[i - mid]);
+
+		if (val < 0)
+		{
+			i -= mid + 1;
+		}
+		else if (val > 0)
+		{
+			bot = i - mid;
+		}
+		else
+		{
+			return i - mid;
+		}
+		mid = (i - bot) / 2;
+	}
+
+	if (i > bot)
+	{
+		val = strcmp(key, array[i]);
+
+		if (val > 0)
+		{
+			return -1;
+		}
+		else if (val < 0)
+		{
+			--i;
+		}
+		else
+		{
+			return i;
+		}
+	}
+
+	if (!strcmp(key, array[i]))
+	{
+		return i;
+	}
+	return -1;
+}
+
+void dictionary_lowerstring(char *in, char *out)
+{
+	char *pti, *pto;
+
+	pti = in;
+	pto = out;
+
+	while (*pti)
+	{
+		if (isalpha(*pti))
+		{
+			*pto++ = tolower(*pti++);
+		}
+		else
+		{
+			pti++;
+		}
+	}
+	*pto = 0;
+}
+
+int spellcheck_count(struct session *ses, char *in)
+{
+	char *arg, arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	int cnt, hash, index;
+
+	cnt = 0;
+	arg = in;
+
+	while (*arg)
+	{
+		arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+
+		dictionary_lowerstring(arg1, arg2);
+
+		if (isalpha(*arg2))
+		{
+			hash = *arg2 - 'a';
+
+			index = dictionary_search(wordlist[hash], wordlist_size[hash], arg2 + 1);
+
+			if (index == -1)
+			{
+				cnt++;
+			}
+		}
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
+	}
+	return cnt;
+}
+
+DO_COMMAND(do_dictionary)
+{
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
+	int hash, size, index;
+
+	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0 || !isalpha(*arg1))
+	{
+		show_message(ses, LIST_COMMAND, "#SYNTAX: #DICTIONARY {WORD}");
+
+		return ses;
+	}
+
+	arg = arg1;
+
+	while (*arg)
+	{
+		arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
+
+		dictionary_lowerstring(arg2, arg3);
+
+		if (isalpha(*arg3))
+		{
+			hash = *arg3 - 'a';
+
+			size = wordlist_size[hash];
+
+			index = dictionary_search(wordlist[hash], size, arg3 + 1);
+
+			if (index == -1)
+			{
+				tintin_printf2(ses, "\e[1;31m%s", arg2);
+			}
+			else
+			{
+				tintin_printf2(ses, "\e[1;32m%s", arg2);
+			}
+		}
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
+	}
+	return ses;
+}

File diff suppressed because it is too large
+ 25 - 0
src/dict.h


File diff suppressed because it is too large
+ 782 - 36
src/draw.c


+ 86 - 32
src/event.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2007                       *
 *                      coded by Igor van den Hoven 2007                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -65,7 +64,7 @@ DO_COMMAND(do_event)
 
 
 				node = update_node_list(ses->list[LIST_EVENT], arg1, arg2, "", "");
 				node = update_node_list(ses->list[LIST_EVENT], arg1, arg2, "", "");
 
 
-				node->data = event_table[cnt].flags;
+				node->val64 = event_table[cnt].flags;
 
 
 				return ses;
 				return ses;
 			}
 			}
@@ -86,7 +85,7 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 {
 {
 	struct session *ses_ptr;
 	struct session *ses_ptr;
 	struct listnode *node;
 	struct listnode *node;
-	char name[BUFFER_SIZE], buf[BUFFER_SIZE];
+	char *name, buf[BUFFER_SIZE];
 	va_list list;
 	va_list list;
 	int cnt;
 	int cnt;
 
 
@@ -99,13 +98,13 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 	{
 	{
 		va_start(list, fmt);
 		va_start(list, fmt);
 
 
-		vsprintf(name, fmt, list);
+		vasprintf(&name, fmt, list);
 
 
 		va_end(list); 
 		va_end(list); 
 	}
 	}
 	else
 	else
 	{
 	{
-		strcpy(name, fmt);
+		name = strdup(fmt);
 	}
 	}
 
 
 	push_call("check_all_events(%p,%d,%d,%d,%s, ...)",ses,flags,args,vars,name);
 	push_call("check_all_events(%p,%d,%d,%d,%s, ...)",ses,flags,args,vars,name);
@@ -152,6 +151,8 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 
 				if (ses)
 				if (ses)
 				{
 				{
+					free(name);
+
 					pop_call();
 					pop_call();
 					return 1;
 					return 1;
 				}
 				}
@@ -160,10 +161,14 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 
 		if (ses)
 		if (ses)
 		{
 		{
+			free(name);
+
 			pop_call();
 			pop_call();
 			return 0;
 			return 0;
 		}
 		}
 	}
 	}
+	free(name);
+
 	pop_call();
 	pop_call();
 	return 0;
 	return 0;
 }
 }
@@ -171,12 +176,21 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], line[BUFFER_SIZE], word[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], line[BUFFER_SIZE], word[BUFFER_SIZE];
-	static char last[100];
+	static char last[100], dir[10];
 	static long long click[3];
 	static long long click[3];
-	int debug, info;
+	static int swipe[10];
+	int debug, info, rev_row, rev_col;
 
 
 	push_call("mouse_handler(%p,%d,%d,%d,%c)",ses,flags,row,col,type);
 	push_call("mouse_handler(%p,%d,%d,%d,%c)",ses,flags,row,col,type);
 
 
+	if (!HAS_BIT(ses->event_flags, EVENT_FLAG_MOUSE))
+	{
+		if (!HAS_BIT(ses->flags, SES_FLAG_MOUSEINFO) && !HAS_BIT(ses->list[LIST_EVENT]->flags, LIST_FLAG_INFO))
+		{
+			return;
+		}
+	}
+
 	if (HAS_BIT(flags, MOUSE_FLAG_MOTION))
 	if (HAS_BIT(flags, MOUSE_FLAG_MOTION))
 	{
 	{
 		strcpy(arg1, "MOVED");
 		strcpy(arg1, "MOVED");
@@ -297,7 +311,6 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 		}
 		}
 	}
 	}
 
 
-
 	debug = HAS_BIT(ses->flags, SES_FLAG_MOUSEDEBUG) ? 1 : 0;
 	debug = HAS_BIT(ses->flags, SES_FLAG_MOUSEDEBUG) ? 1 : 0;
 	info  = HAS_BIT(ses->flags, SES_FLAG_MOUSEINFO) ? 1 : 0;
 	info  = HAS_BIT(ses->flags, SES_FLAG_MOUSEINFO) ? 1 : 0;
 
 
@@ -306,18 +319,26 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 
 
 	check_all_buttons(ses, row, col, arg1, arg2, word, line);
 	check_all_buttons(ses, row, col, arg1, arg2, word, line);
 
 
-	check_all_events(ses, SUB_ARG, 2, 6, "%s %s", arg1, arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+	rev_row = -1 - (gtd->screen->rows - row);
+	rev_col = -1 - (gtd->screen->cols - col);
 
 
-	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+	check_all_events(ses, SUB_ARG, 2, 6, "%s %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
 
 
-	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, -1 - (gtd->screen->rows - row), ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-	map_mouse_handler(ses, arg1, arg2, col, row);
+	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
+
+	map_mouse_handler(ses, arg1, arg2, col, row, 0, 0);
 
 
 	if (!strcmp(arg1, "PRESSED"))
 	if (!strcmp(arg1, "PRESSED"))
 	{
 	{
 		sprintf(arg1, "PRESSED %s %d %d", arg2, col, row);
 		sprintf(arg1, "PRESSED %s %d %d", arg2, col, row);
 
 
+		swipe[0] = row;
+		swipe[1] = col;
+		swipe[2] = rev_row;
+		swipe[3] = rev_col;
+
 		if (!strcmp(arg1, last))
 		if (!strcmp(arg1, last))
 		{
 		{
 			click[2] = click[1];
 			click[2] = click[1];
@@ -330,13 +351,13 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 				{
 				{
 					check_all_buttons(ses, row, col, "TRIPLE-CLICKED", arg2, word, line);
 					check_all_buttons(ses, row, col, "TRIPLE-CLICKED", arg2, word, line);
 
 
-					check_all_events(ses, SUB_ARG, 1, 6, "TRIPLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+					check_all_events(ses, SUB_ARG, 1, 6, "TRIPLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, -1 - (gtd->screen->rows - row), ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-					map_mouse_handler(ses, "TRIPPLE-CLICKED", arg2, col, row);
+					map_mouse_handler(ses, "TRIPPLE-CLICKED", arg2, col, row, 0, 0);
 
 
 					strcpy(last, "");
 					strcpy(last, "");
 				}
 				}
@@ -344,13 +365,13 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 				{
 				{
 					check_all_buttons(ses, row, col, "DOUBLE-CLICKED", arg2, word, line);
 					check_all_buttons(ses, row, col, "DOUBLE-CLICKED", arg2, word, line);
 
 
-					check_all_events(ses, SUB_ARG, 1, 6, "DOUBLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+					check_all_events(ses, SUB_ARG, 1, 6, "DOUBLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, -1 - (gtd->screen->rows - row), ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-					map_mouse_handler(ses, "DOUBLE-CLICKED", arg2, col, row);
+					map_mouse_handler(ses, "DOUBLE-CLICKED", arg2, col, row, 0, 0);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -365,29 +386,62 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 	}
 	}
 	else if (!strcmp(arg1, "RELEASED"))
 	else if (!strcmp(arg1, "RELEASED"))
 	{
 	{
-		if (utime() - click[0] >= 500000)
+		swipe[4] = row;
+		swipe[5] = col;
+		swipe[6] = rev_row;
+		swipe[7] = rev_col;
+
+		swipe[8] = swipe[4] - swipe[0];
+		swipe[9] = swipe[5] - swipe[1];
+
+		if (abs(swipe[8]) > 3 || abs(swipe[9]) > 3)
+		{
+			if (abs(swipe[8]) <= 3)
+			{
+				strcpy(dir, swipe[9] > 0 ? "E" : "W");
+			}
+			else if (abs(swipe[9]) <= 3)
+			{
+				strcpy(dir, swipe[8] > 0 ? "S" : "N");
+			}
+			else if (swipe[8] > 0)
+			{
+				strcpy(dir, swipe[9] > 0 ? "SE" : "SW");
+			}
+			else
+			{
+				strcpy(dir, swipe[9] > 0 ? "NE" : "NW");
+			}
+			check_all_events(ses, SUB_ARG, 0, 12, "SWIPED", dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));			
+			check_all_events(ses, SUB_ARG, 1, 12, "SWIPED %s", dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
+			check_all_events(ses, SUB_ARG, 2, 12, "SWIPED %s %s", arg2, dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
+		}
+		else if (utime() - click[0] >= 500000)
 		{
 		{
 			check_all_buttons(ses, row, col, "LONG-CLICKED", arg2, word, line);
 			check_all_buttons(ses, row, col, "LONG-CLICKED", arg2, word, line);
 
 
-			check_all_events(ses, SUB_ARG, 1, 6, "LONG-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+			check_all_events(ses, SUB_ARG, 1, 6, "LONG-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, -1 - (gtd->screen->rows - row), ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-			map_mouse_handler(ses, "LONG-CLICKED", arg2, col, row);
+			map_mouse_handler(ses, "LONG-CLICKED", arg2, col, row, 0, 0);
 		}
 		}
 		else if (click[0] - click[1] >= 500000)
 		else if (click[0] - click[1] >= 500000)
 		{
 		{
-			check_all_buttons(ses, row, col, "SHORT-CLICKED", arg2, word, line);
+			if (abs(swipe[0] - swipe[4]) <= 3 && abs(swipe[1] - swipe[5]) <= 3)
+			{
+				check_all_buttons(ses, row, col, "SHORT-CLICKED", arg2, word, line);
 
 
-			check_all_events(ses, SUB_ARG, 1, 6, "SHORT-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+				check_all_events(ses, SUB_ARG, 1, 6, "SHORT-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-			check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+				check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-			check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, -1 - (gtd->screen->rows - row), ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
+				check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
 
-			map_mouse_handler(ses, "SHORT-CLICKED", arg2, col, row);
+				map_mouse_handler(ses, "SHORT-CLICKED", arg2, col, row, 0, 0);
+			}
 		}
 		}
 	}
 	}
 
 

+ 14 - 6
src/files.c

@@ -31,11 +31,8 @@
 
 
 DO_COMMAND(do_read)
 DO_COMMAND(do_read)
 {
 {
+	char filename[BUFFER_SIZE];
 	FILE *fp;
 	FILE *fp;
-	struct stat filedata;
-	char *bufi, *bufo, filename[BUFFER_SIZE], temp[BUFFER_SIZE], *pti, *pto, last = 0;
-	int lvl, cnt, com, lnc, fix, ok;
-	int counter[LIST_MAX];
 
 
 	sub_arg_in_braces(ses, arg, filename, GET_ONE, SUB_VAR|SUB_FUN);
 	sub_arg_in_braces(ses, arg, filename, GET_ONE, SUB_VAR|SUB_FUN);
 
 
@@ -48,13 +45,23 @@ DO_COMMAND(do_read)
 		return ses;
 		return ses;
 	}
 	}
 
 
+	return read_file(ses, fp, filename);
+}
+
+struct session *read_file(struct session *ses, FILE *fp, char *filename)
+{
+	struct stat filedata;
+	char *bufi, *bufo, temp[INPUT_SIZE], *pti, *pto, last = 0;
+	int lvl, cnt, com, lnc, fix, ok;
+	int counter[LIST_MAX];
+
 	temp[0] = getc(fp);
 	temp[0] = getc(fp);
 
 
 	if (!ispunct((int) temp[0]))
 	if (!ispunct((int) temp[0]))
 	{
 	{
 		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "INVALID START OF FILE");
 		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "INVALID START OF FILE");
 
 
-		tintin_printf(ses, "#ERROR: #READ {%s} - INVALID START OF FILE.", filename);
+		tintin_printf(ses, "#ERROR: #READ {%s} - INVALID START OF FILE '%c'.", filename, temp[0]);
 
 
 		fclose(fp);
 		fclose(fp);
 
 
@@ -95,10 +102,11 @@ DO_COMMAND(do_read)
 	{
 	{
 		if (com == 0)
 		if (com == 0)
 		{
 		{
-			if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+			if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 			{
 			{
 				*pto++ = *pti++;
 				*pto++ = *pti++;
 				*pto++ = *pti++;
 				*pto++ = *pti++;
+
 				continue;
 				continue;
 			}
 			}
 
 

+ 241 - 107
src/help.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -39,7 +38,7 @@ char *help_related(struct session *ses, int index, int html)
 {
 {
 	char *arg;
 	char *arg;
 	char tmp[BUFFER_SIZE], link[BUFFER_SIZE];
 	char tmp[BUFFER_SIZE], link[BUFFER_SIZE];
-	static char buf[BUFFER_SIZE];
+	static char buf[INPUT_SIZE];
 
 
 	push_call("help_related(%p,%d,%d)",ses,index,html);
 	push_call("help_related(%p,%d,%d)",ses,index,html);
 
 
@@ -297,7 +296,7 @@ struct help_type help_table[] =
 	{
 	{
 		"ALIAS",
 		"ALIAS",
 
 
-		"<178>Command<278>: #alias <178>{<278>name<178>} {<278>commands<178>}<278>\n"
+		"<178>Command<278>: #alias <178>{<278>name<178>} {<278>commands<178>} {<278>priority<178>}<278>\n"
 		"\n"
 		"\n"
 		"         The #alias command can be used to shorten up long or oftenly used\n"
 		"         The #alias command can be used to shorten up long or oftenly used\n"
 		"         commands. The %1-99 variables are substituted from the arguments when\n"
 		"         commands. The %1-99 variables are substituted from the arguments when\n"
@@ -530,6 +529,16 @@ struct help_type help_table[] =
 
 
 		"default statements switch"
 		"default statements switch"
 	},
 	},
+	{
+		"CAT",
+
+		"<178>Command<278>: #cat <178>{<278>variable<178>} {<278>argument<178>}<278>\n"
+		"\n"
+		"         The cat command will concatinate the argument to the given variable.\n",
+		
+		"format function local math replace script variable"
+	},
+
 	{
 	{
 		"CHARACTERS",
 		"CHARACTERS",
 
 
@@ -548,7 +557,7 @@ struct help_type help_table[] =
 		"         well. Trailing semi-colons are ignored when reading a script file\n"
 		"         well. Trailing semi-colons are ignored when reading a script file\n"
 		"         as this is a common error.\n"
 		"         as this is a common error.\n"
 		"\n"
 		"\n"
-		"{ }      Curly brackets aka braces are used for seperating multi word command\n"
+		"{ }      Curly brackets aka braces are used for separating multi word command\n"
 		"         arguments, nesting commands, and nesting variables. Braces cannot\n"
 		"         arguments, nesting commands, and nesting variables. Braces cannot\n"
 		"         easily be escaped and must always be used in pairs.\n"
 		"         easily be escaped and must always be used in pairs.\n"
 		"\n"
 		"\n"
@@ -610,13 +619,27 @@ struct help_type help_table[] =
 
 
 		"<178>Command<278>: #class <178>{<278>name<178>} {<278>open<178>|<278>close<178>|<278>list<178>|<278>read<178>|<278>size<178>|<278>write<178>|<278>kill<178>} {<278>arg<178>}<278>\n"
 		"<178>Command<278>: #class <178>{<278>name<178>} {<278>open<178>|<278>close<178>|<278>list<178>|<278>read<178>|<278>size<178>|<278>write<178>|<278>kill<178>} {<278>arg<178>}<278>\n"
 		"\n"
 		"\n"
-		"         The {open} option will open a class, closing a previously opened\n"
-		"         class. All triggers added afterwards are assigned to this class.\n"
-		"         The {close} option will close the given class.\n"
-		"         The {list} option will show the given list of the class.\n"
-		"         The {read} option will open the class, read, and close afterwards.\n"
-		"         The {size} option will store the size of the class in a variable.\n"
-		"         The {write} option will write all triggers of the given class to file.\n"
+		"         <178>#class {<name>} {open}\n"
+		"         <278>  Open a class, closing a previously opened class. All triggers\n"
+		"         <278>  added afterwards are assigned to this class.\n"
+		"         <178>#class {<name>} {clear}\n"
+		"         <278>  Will delete all triggers associated with the given class.\n"
+		"         <178>#class {<name>} {close}\n"
+		"         <278>  Close the given class, opening the last open class, if any.\n"
+		"         <178>#class {<name>} {kill}\n"
+		"         <278>  Will clear, close, and remove the class.\n"
+		"         <178>#class {<name>} {list}\n"
+		"         <278>  List all triggers associated with the given class.\n"
+		"         <178>#class {<name>} {load}\n"
+		"         <278>  Will load the saved copy of the class from memory.\n"
+		"         <178>#class {<name>} {read} {<filename>\n"
+		"         <278>  Will open the class, read the file, and close afterwards.\n"
+		"         <178>#class {<name>} {save}\n"
+		"         <278>  Will save all triggers of the given class to memory.\n"
+		"         <178>#class {<name>} {size} {<variable>}\n"
+		"         <278>  Will store the size of the class in a variable.\n"
+		"         <178>#class {<name>} {write} {<filename>}\n"
+		"         <278>  Will write all triggers of the given class to file.\n"
 		"         The {kill} option will delete all triggers of the given class.\n"
 		"         The {kill} option will delete all triggers of the given class.\n"
 		"\n"
 		"\n"
 		"         Keep in mind that the kill and read option are very fast allowing\n"
 		"         Keep in mind that the kill and read option are very fast allowing\n"
@@ -709,7 +732,7 @@ struct help_type help_table[] =
 		"<178>Command<278>: #config <178>{<278>option<178>} {<278>argument<178>}<278>\n"
 		"<178>Command<278>: #config <178>{<278>option<178>} {<278>argument<178>}<278>\n"
 		"\n"
 		"\n"
 		"         This allows you to configure various settings, the settings can be\n"
 		"         This allows you to configure various settings, the settings can be\n"
-		"         written to file with the #write or #writesession command.\n"
+		"         written to file with the #write command.\n"
 		"\n"
 		"\n"
 		"         If you configure the global session (the one you see as you start up\n"
 		"         If you configure the global session (the one you see as you start up\n"
 		"         tintin) all sessions started will inherite these settings.\n"
 		"         tintin) all sessions started will inherite these settings.\n"
@@ -723,7 +746,7 @@ struct help_type help_table[] =
 		"         #CONFIG {CHILD LOCK}   {ON|OFF} Enable or disable command input.\n"
 		"         #CONFIG {CHILD LOCK}   {ON|OFF} Enable or disable command input.\n"
 		"         #CONFIG {CONVERT META} {ON|OFF} Shows color codes and key bindings.\n"
 		"         #CONFIG {CONVERT META} {ON|OFF} Shows color codes and key bindings.\n"
 		"         #CONFIG {DEBUG TELNET} {ON|OFF} Shows telnet negotiations y/n.\n"
 		"         #CONFIG {DEBUG TELNET} {ON|OFF} Shows telnet negotiations y/n.\n"
-		"         #CONFIG {LOG LEVEL}  {LOW|HIGH} LOW logs mud output before triggers.\n"
+		"         #CONFIG {LOG LEVEL}  {LOW|HIGH} LOW logs server output before triggers.\n"
 		"         #CONFIG {INHERITANCE}  {ON|OFF} Session trigger inheritance y/n.\n"
 		"         #CONFIG {INHERITANCE}  {ON|OFF} Session trigger inheritance y/n.\n"
 		"         #CONFIG {MCCP}         {ON|OFF} Enable or disable MCCP support.\n"
 		"         #CONFIG {MCCP}         {ON|OFF} Enable or disable MCCP support.\n"
 		"         #CONFIG {PID}          {NUMBER} Set the PID of the master process.\n",
 		"         #CONFIG {PID}          {NUMBER} Set the PID of the master process.\n",
@@ -835,7 +858,7 @@ struct help_type help_table[] =
 		"         before executing the given command. tintin won't wait before\n"
 		"         before executing the given command. tintin won't wait before\n"
 		"         executing following input commands if any.\n"
 		"         executing following input commands if any.\n"
 		"\n"
 		"\n"
-		"         Floating point precision for miliseconds is possible.\n"
+		"         Floating point precision for milliseconds is possible.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #showme first;#delay {1} {#showme last}\n"
 		"<178>Example<278>: #showme first;#delay {1} {#showme last}\n"
 		"         This will print 'first', and 'last' around one second later.\n"
 		"         This will print 'first', and 'last' around one second later.\n"
@@ -871,15 +894,21 @@ struct help_type help_table[] =
 		"         BUMPED     will precede the draw with an enter.\n"
 		"         BUMPED     will precede the draw with an enter.\n"
 		"         CIRCLED    will circle the corners.\n"
 		"         CIRCLED    will circle the corners.\n"
 		"         CONVERT    will draw text with meta conversion.\n"
 		"         CONVERT    will draw text with meta conversion.\n"
-		"         CORNERED   will draw lines with corners if possible.\n"
 		"         CROSSED    will cross the corners.\n"
 		"         CROSSED    will cross the corners.\n"
+		"         FILLED     will fill circles and jewels.\n"
+		"         GRID       will draw TABLE as a grid.\n"
 		"         HORIZONTAL will draw horizontal if possible.\n"
 		"         HORIZONTAL will draw horizontal if possible.\n"
+		"         HUGE       will draw text in huge letters.\n"
 		"         JEWELED    will diamond the corners.\n"
 		"         JEWELED    will diamond the corners.\n"
+		"         JOINTED    will draw corners.\n"
 		"         LEFT       will draw on the left side if possible.\n"
 		"         LEFT       will draw on the left side if possible.\n"
+		"         NUMBERED   will draw numbered, mostly for debugging.\n"
 		"         PRUNED     will prune the corners.\n"
 		"         PRUNED     will prune the corners.\n"
 		"         RIGHT      will draw on the right side if possible.\n"
 		"         RIGHT      will draw on the right side if possible.\n"
 		"         ROUNDED    will round the corners.\n"
 		"         ROUNDED    will round the corners.\n"
+		"         SHADOWED   will shadow HUGE text.\n"
 		"         TEED       will tee the corners.\n"
 		"         TEED       will tee the corners.\n"
+		"         TRACED     will trace HUGE text.\n"
 		"         TOP        will draw on the top side if possible.\n"
 		"         TOP        will draw on the top side if possible.\n"
 		"         TUBED      will draw tubes instead of lines.\n"
 		"         TUBED      will draw tubes instead of lines.\n"
 		"         UNICODE    will draw in unicode mode.\n"
 		"         UNICODE    will draw in unicode mode.\n"
@@ -887,16 +916,26 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         The following types are available.\n"
 		"         The following types are available.\n"
 		"\n"
 		"\n"
-		"         BOX        will draw a box.\n"
-		"         LINE       will draw a line.\n"
-		"         SIDE       will draw one or more sides of a box.\n"
-		"         TILE       will draw a tile\n"
+		"         <178>[ASCII|UNICODE|HUGE] BOX {[TEXT1]} {[TEXT2]}\n"
+		"         <278>  will draw a box.\n"
+		"         <178>[BLANKED|CIRCLED|CROSSED|JEWELED|ROUNDED|TEED|PRUNED] CORNER\n"
+		"         <278>  will draw a corner.\n"
+		"         <178>[BLANKED|HORIZONTAL|NUMBERED|TUBED|VERTICAL] LINE {[TEXT]}\n"
+		"         <278>  will draw a line.\n"
+		"         <178>RAIN {<VARIABLE>} {[SPAWN]} {[FADE]} {[LEGEND]}\n"
+		"         <278>  will draw digital rain.\n"
+		"         <178>[JOINTED|TOP|LEFT|BOTTOM|RIGHT] SIDE\n"
+		"         <278>  will draw one or more sides of a box.\n"
+		"         <178>[GRID] TABLE {[LIST1]} {[LIST2]}\n"
+		"         <278> will draw a table.\n"
+		"         <178>[HUGE] TILE {[TEXT1]} {[TEXT2]}\n"
+		"         <278>  will draw a tile\n"
 		"\n"
 		"\n"
 		"         All draw types take an optional text argument as long as a valid\n"
 		"         All draw types take an optional text argument as long as a valid\n"
 		"         square with enough space has been defined. Text is automatically\n"
 		"         square with enough space has been defined. Text is automatically\n"
 		"         word wrapped.\n"
 		"         word wrapped.\n"
 		"\n"
 		"\n"
-		"<178>Example<278>: #draw {box} 1 1 3 20 {Hello world!}\n",
+		"<178>Example<278>: #draw Blue box 1 1 3 20 {Hello world!}\n",
 
 
 		"buffer echo grep showme"
 		"buffer echo grep showme"
 	},
 	},
@@ -907,7 +946,7 @@ struct help_type help_table[] =
 		"<178>Command<278>: #echo <178>{<278>format<178>} {<278>argument1<178>} {<278>argument2<178>} {<278>etc<178>}<278>\n"
 		"<178>Command<278>: #echo <178>{<278>format<178>} {<278>argument1<178>} {<278>argument2<178>} {<278>etc<178>}<278>\n"
 		"\n"
 		"\n"
 		"         Echo command displays text on the screen with formatting options. See\n"
 		"         Echo command displays text on the screen with formatting options. See\n"
-		"         the help file for the format command for more informations.\n"
+		"         the help file for the format command for more information.\n"
 		"\n"
 		"\n"
 		"         The echo command does not trigger actions.\n"
 		"         The echo command does not trigger actions.\n"
 		"\n"
 		"\n"
@@ -918,7 +957,7 @@ struct help_type help_table[] =
 		"         #echo {[%38s][%-38s]} {Hello World} {Hello World}\n"
 		"         #echo {[%38s][%-38s]} {Hello World} {Hello World}\n"
 		"         #echo {{this is %s on the top row} {-1}} {printed}\n",
 		"         #echo {{this is %s on the top row} {-1}} {printed}\n",
 		
 		
-		"buffer grep showme"
+		"buffer format grep showme"
 	},
 	},
 	{
 	{
 		"ELSE",
 		"ELSE",
@@ -1006,8 +1045,8 @@ struct help_type help_table[] =
 		"         IAC <VAR> <VAR>\n"
 		"         IAC <VAR> <VAR>\n"
 		"         IAC SB GMCP <MODULE>   %0 data     %1 raw data\n"
 		"         IAC SB GMCP <MODULE>   %0 data     %1 raw data\n"
 		"         IAC SB MSSP            %0 variable %1 value\n"
 		"         IAC SB MSSP            %0 variable %1 value\n"
-		"         IAC SB MSDP            %0 variable %1 value\n"
-		"         IAC SB MSDP <VAR>      %1 value\n"
+		"         IAC SB MSDP            %0 variable %1 value %2 plain value\n"
+		"         IAC SB MSDP <VAR>      %0 variable %1 value %2 plain value\n"
 		"         IAC SB NEW-ENVIRON     %0 variable %1 value\n"
 		"         IAC SB NEW-ENVIRON     %0 variable %1 value\n"
 		"         IAC SB ZMP <VAR>       %0 value\n"
 		"         IAC SB ZMP <VAR>       %0 value\n"
 		"         IAC SB <VAR>           %0 raw text %1 raw data\n"
 		"         IAC SB <VAR>           %0 raw text %1 raw data\n"
@@ -1019,6 +1058,7 @@ struct help_type help_table[] =
 		"         MAP EXIT ROOM          %0 old vnum %1 new vnum\n"
 		"         MAP EXIT ROOM          %0 old vnum %1 new vnum\n"
 		"         MAP EXIT ROOM <VAR>    %0 old vnum %1 new vnum\n"
 		"         MAP EXIT ROOM <VAR>    %0 old vnum %1 new vnum\n"
 		"         MAP FOLLOW MAP         %0 old vnum %1 new vnum %2 exit name\n"
 		"         MAP FOLLOW MAP         %0 old vnum %1 new vnum %2 exit name\n"
+		"         MAP MOUSE LOCATION     %0 vnum %1 location\n"
 		"         MAP UPDATED VTMAP\n"
 		"         MAP UPDATED VTMAP\n"
 		"         MINUTE                 %5 minute\n"
 		"         MINUTE                 %5 minute\n"
 		"         MONTH                  %1 month\n"
 		"         MONTH                  %1 month\n"
@@ -1042,7 +1082,10 @@ struct help_type help_table[] =
 		"         SCAN CSV LINE          %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN CSV LINE          %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN TSV HEADER        %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN TSV HEADER        %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN TSV LINE          %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN TSV LINE          %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
-		"         SCREEN RESIZE          %0 rows %1 cols %1 height %2 width\n"
+		"         SCREEN FOCUS           %0 focus (0 or 1)\n"
+		"         SCREEN LOCATION        %0 rows %1 cols  %2 height %3 width\n"
+		"         SCREEN MOUSE LOCATION  %0-3 screen row/col %4-7 cell row/col %8 loc\n"
+		"         SCREEN RESIZE          %0 rows %1 cols %2 height %3 width\n"
 		"         SCREEN SPLIT           %0 top row %1 top col %2 bot row %3 bot col\n"
 		"         SCREEN SPLIT           %0 top row %1 top col %2 bot row %3 bot col\n"
 		"         SCREEN UNSPLIT         %0 top row %1 top col %2 bot row %3 bot col\n"
 		"         SCREEN UNSPLIT         %0 top row %1 top col %2 bot row %3 bot col\n"
 		"         SCROLLED <VAR>         %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
 		"         SCROLLED <VAR>         %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
@@ -1056,6 +1099,9 @@ struct help_type help_table[] =
 		"         SESSION DISCONNECTED   %0 name %1 host %2 ip %3 port\n"
 		"         SESSION DISCONNECTED   %0 name %1 host %2 ip %3 port\n"
 		"         SESSION TIMED OUT      %0 name %1 host %2 ip %3 port\n"
 		"         SESSION TIMED OUT      %0 name %1 host %2 ip %3 port\n"
 		"         SHORT-CLICKED <VAR>    %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
 		"         SHORT-CLICKED <VAR>    %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
+		"         SWIPED <DIR>\n"
+		"           %0 dir %1 button %2 row %3 col %4 -row %5 -col %6 row %7 col %8 -row\n"
+		"           %9 -col %10 rows %11 cols\n"
 		"         SYSTEM ERROR           %0 name %1 system msg %2 error %3 error msg\n"
 		"         SYSTEM ERROR           %0 name %1 system msg %2 error %3 error msg\n"
 		"         TIME                   %4 hour : %5 minute : %6 second\n"
 		"         TIME                   %4 hour : %5 minute : %6 second\n"
 		"         TRIPLE-CLICKED <VAR>   %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
 		"         TRIPLE-CLICKED <VAR>   %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
@@ -1064,8 +1110,6 @@ struct help_type help_table[] =
 		"         VARIABLE UPDATED <VAR> %0 name %1 new value\n"
 		"         VARIABLE UPDATED <VAR> %0 name %1 new value\n"
 		"         VT100 SCROLL REGION    %0 top row %1 bot row %2 rows %3 cols %4 wrap\n"
 		"         VT100 SCROLL REGION    %0 top row %1 bot row %2 rows %3 cols %4 wrap\n"
 		"         WEEK <DAY>             %2 day of the week\n"
 		"         WEEK <DAY>             %2 day of the week\n"
-		"         WINDOW FOCUS IN        %0 name\n"
-		"         WINDOW FOCUS OUT       %0 name\n"
 		"         WRITE ERROR            %0 filename %1 error message\n"
 		"         WRITE ERROR            %0 filename %1 error message\n"
 		"         YEAR                   %0 year\n"
 		"         YEAR                   %0 year\n"
 		"\n"
 		"\n"
@@ -1083,7 +1127,7 @@ struct help_type help_table[] =
 
 
 		"<178>This command is obsolete, please use foreach instead.\n",
 		"<178>This command is obsolete, please use foreach instead.\n",
 
 
-		"cr"
+		"foreach"
 	},
 	},
 	{
 	{
 		"FOREACH",
 		"FOREACH",
@@ -1129,13 +1173,16 @@ struct help_type help_table[] =
 		"         #format {test} {%t}   {format}  display time with strftime format\n"
 		"         #format {test} {%t}   {format}  display time with strftime format\n"
 		"                                         optional {{format}{time}} syntax\n"
 		"                                         optional {{format}{time}} syntax\n"
 		"         #format {test} {%u}   {string}  uppercase text\n"
 		"         #format {test} {%u}   {string}  uppercase text\n"
-		"         #format {list} {%w}   {string}  store wordwrapped text in {list}\n"
+		"         #format {list} {%w}   {string}  store word wrapped text in {list}\n"
 		"                                         optional {{string}{width}} syntax\n"
 		"                                         optional {{string}{width}} syntax\n"
 		"         #format {test} {%x}      {hex}  print corresponding charset character\n"
 		"         #format {test} {%x}      {hex}  print corresponding charset character\n"
 		"         #format {test} {%A}     {char}  store corresponding character value\n"
 		"         #format {test} {%A}     {char}  store corresponding character value\n"
+		"         #format {test} {%C}   {number}  store number in chronological notation\n"
 		"         #format {test} {%D}      {hex}  convert hex to decimal in {test}\n"
 		"         #format {test} {%D}      {hex}  convert hex to decimal in {test}\n"
 		"         #format {hash} {%H}   {string}  store a 64 bit string hash in {hash}\n"
 		"         #format {hash} {%H}   {string}  store a 64 bit string hash in {hash}\n"
 		"         #format {test} {%L}   {string}  store the string length in {test}\n"
 		"         #format {test} {%L}   {string}  store the string length in {test}\n"
+		"         #format {test} {%M}   {number}  convert number to metric in {test}\n"
+		"         #format {test} {%S}   {string}  store the number of spelling errors\n"
 		"         #format {time} {%T}         {}  store the epoch time in {time}\n"
 		"         #format {time} {%T}         {}  store the epoch time in {time}\n"
 		"         #format {time} {%U}         {}  store the micro epoch time in {time}\n"
 		"         #format {time} {%U}         {}  store the micro epoch time in {time}\n"
 		"         #format {test} {%X}      {dec}  convert dec to hexadecimal in {test}\n\n"
 		"         #format {test} {%X}      {dec}  convert dec to hexadecimal in {test}\n\n"
@@ -1143,7 +1190,7 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"<178>Comment<278>: See #help TIME for help on the %t argument.\n",
 		"<178>Comment<278>: See #help TIME for help on the %t argument.\n",
 		
 		
-		"echo function local math replace script time variable"
+		"cat echo function local math replace script time variable"
 	},
 	},
 
 
 	{
 	{
@@ -1192,11 +1239,13 @@ struct help_type help_table[] =
 		"GREETING",
 		"GREETING",
 
 
 		"<268>      #<268>##################################################################<268>#\n"
 		"<268>      #<268>##################################################################<268>#\n"
-		"<268>      #<278>                     T I N T I N + +   "CLIENT_VERSION"                   <268>#\n"
 		"<268>      #<278>                                                                  <268>#\n"
 		"<268>      #<278>                                                                  <268>#\n"
-		"<268>      #<278>                 <268>T<278>he K<268>i<278>cki<268>n<278> <268>T<278>ickin D<268>i<278>kuMUD Clie<268>n<278>t <268>                #\n"
+		"<268>      #<278>                    T I N T I N + +   "CLIENT_VERSION"                    <268>#\n"
 		"<268>      #<278>                                                                  <268>#\n"
 		"<268>      #<278>                                                                  <268>#\n"
+//		"<268>      #<278>                 <268>T<278>he K<268>i<278>cki<268>n<278> <268>T<278>ickin D<268>i<278>kuMUD Clie<268>n<278>t <268>                #\n"
+//		"<268>      #<278>                                                                  <268>#\n"
 		"<268>      #<278>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      <268>#\n"
 		"<268>      #<278>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      <268>#\n"
+		"<268>      #<278>                                                                  <268>#\n"
 		"<268>      #<268>##################################################################<268>#<288>\n",
 		"<268>      #<268>##################################################################<268>#<288>\n",
 		
 		
 		""
 		""
@@ -1234,7 +1283,7 @@ struct help_type help_table[] =
 	{
 	{
 		"HIGHLIGHT",
 		"HIGHLIGHT",
 
 
-		"<178>Command<278>: #highlight <178>{<278>string<178>} {<278>color names<178>}<278>\n"
+		"<178>Command<278>: #highlight <178>{<278>string<178>} {<278>color names<178>} {<278>priority<178>}<278>\n"
 		"\n"
 		"\n"
 		"         The highlight command is used to allow you to highlight strings of text.\n"
 		"         The highlight command is used to allow you to highlight strings of text.\n"
 		"\n"
 		"\n"
@@ -1321,7 +1370,7 @@ struct help_type help_table[] =
 		"         when you press enter on an empty line.\n"
 		"         when you press enter on an empty line.\n"
 		"\n"
 		"\n"
 		"         You can press ctrl-r to enter an interactive regex enabled history\n"
 		"         You can press ctrl-r to enter an interactive regex enabled history\n"
-		"         search mode, or by issueing #cursor {history search}.\n"
+		"         search mode, or by issuing #cursor {history search}.\n"
 		"\n"
 		"\n"
 		"         TinTin++ tries to bind the arrow up and down keys to scroll through\n"
 		"         TinTin++ tries to bind the arrow up and down keys to scroll through\n"
 		"         the history list by default. You can bind these with a macro yourself\n"
 		"         the history list by default. You can bind these with a macro yourself\n"
@@ -1396,7 +1445,7 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         All TinTin++ commands starts with a '#'.\n"
 		"         All TinTin++ commands starts with a '#'.\n"
 		"\n"
 		"\n"
-		"<178>Example<278>: #help -- #help is a mud client command, and isn't send to the mud\n"
+		"<178>Example<278>: #help -- #help is a client command, and isn't send to the\n"
 		"         server.\n"
 		"         server.\n"
 		"\n"
 		"\n"
 		"         All TinTin++ commands can be abbreviated when typed.\n"
 		"         All TinTin++ commands can be abbreviated when typed.\n"
@@ -1411,12 +1460,12 @@ struct help_type help_table[] =
 		"         There are 3 ways ';'s can be overruled.\n"
 		"         There are 3 ways ';'s can be overruled.\n"
 		"\n"
 		"\n"
 		"         \\say Hello ;) -- Lines starting with a '\\' aren't parsed by TinTin++.\n"
 		"         \\say Hello ;) -- Lines starting with a '\\' aren't parsed by TinTin++.\n"
-		"         say Hello \\;) -- The escape character can esape 1 letter.\n"
+		"         say Hello \\;) -- The escape character can escape 1 letter.\n"
 		"         #config verbatim on -- Everything is send as is except '#' commands.\n"
 		"         #config verbatim on -- Everything is send as is except '#' commands.\n"
 		"<128>\n"
 		"<128>\n"
-		"         Connecting to a mud\n"
+		"         Connecting to a server\n"
 		"<178>\n"
 		"<178>\n"
-		"Command<278>: #session <178>{<278>session name<178>} {<278>mud address<178>} {<278>port<178>}<278>\n"
+		"Command<278>: #session <178>{<278>session name<178>} {<278>server address<178>} {<278>port<178>}<278>\n"
 		"\n"
 		"\n"
 		"         Example: #session someone tintin.sourceforge.net 4321\n"
 		"         Example: #session someone tintin.sourceforge.net 4321\n"
 		"\n"
 		"\n"
@@ -1425,8 +1474,7 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         You can get a list of all sessions by typing: #session. The current\n"
 		"         You can get a list of all sessions by typing: #session. The current\n"
 		"         active session is marked with (active). Snooped sessions with\n"
 		"         active session is marked with (active). Snooped sessions with\n"
-		"         (snooped). MCCP sessions (mud client compression protocol) with\n"
-		"         (mccp 2).\n"
+		"         (snooped). MCCP sessions (compression) with (mccp 2) and (mccp 3).\n"
 		"\n"
 		"\n"
 		"<128>\n"
 		"<128>\n"
 		"         Split\n"
 		"         Split\n"
@@ -1509,7 +1557,7 @@ struct help_type help_table[] =
 		"<178>Command<278>: #highlight <178>{<278>text<178>} {<278>color<178>}<278>\n"
 		"<178>Command<278>: #highlight <178>{<278>text<178>} {<278>color<178>}<278>\n"
 		"\n"
 		"\n"
 		"         This command works a bit like #action. The purpose of this command is\n"
 		"         This command works a bit like #action. The purpose of this command is\n"
-		"         to substitute text from the mud with color you provide. This command\n"
+		"         to substitute text from the server with color you provide. This command\n"
 		"         is a simplified version of the #substitute command.\n"
 		"         is a simplified version of the #substitute command.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #high <178>{<278>Snowy<178>} {<278>light yellow<178>}<278>\n"
 		"<178>Example<278>: #high <178>{<278>Snowy<178>} {<278>light yellow<178>}<278>\n"
@@ -1538,10 +1586,9 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"<178>Command<278>: #ticker <178>{<278>name<178>} {<278>commands<178>} {<278>seconds<178>}<278>\n"
 		"<178>Command<278>: #ticker <178>{<278>name<178>} {<278>commands<178>} {<278>seconds<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Every 60 seconds on a standard dikumud a so called tick occures. You\n"
-		"         regenerate hp/mana/move faster if you're sleeping/resting during a\n"
-		"         tick. So it's pretty nice to know when the next tick occures. TinTin++\n"
-		"         helps you with that.\n"
+		"         The name can be whatever you want it to be, and is only required for\n"
+		"         the unticker command. The commands will be executed every x amount of\n"
+		"         seconds, which is specified in the interval part.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #tick <178>{<278>tick<178>} {<278>#delay 50 #show 10 SECONDS TO TICK!;#show TICK!!!<178>} {<278>60<178>}<278>\n"
 		"<178>Example<278>: #tick <178>{<278>tick<178>} {<278>#delay 50 #show 10 SECONDS TO TICK!;#show TICK!!!<178>} {<278>60<178>}<278>\n"
 		"\n"
 		"\n"
@@ -1555,7 +1602,7 @@ struct help_type help_table[] =
 		"<278>\n"
 		"<278>\n"
 		"         When you order TinTin++ to read a command file, it parses all the text\n"
 		"         When you order TinTin++ to read a command file, it parses all the text\n"
 		"         in the file. You can use command files to keep aliases/actions in,\n"
 		"         in the file. You can use command files to keep aliases/actions in,\n"
-		"         login to a mud (name, password etc..) and basically all kinds of\n"
+		"         login to a server (name, password etc..) and basically all kinds of\n"
 		"         commands.\n"
 		"         commands.\n"
 		"\n"
 		"\n"
 		"         You can make the command files with either a text editor (suggested),\n"
 		"         You can make the command files with either a text editor (suggested),\n"
@@ -1647,6 +1694,9 @@ struct help_type help_table[] =
 		"         This data is written to the info variable.\n"
 		"         This data is written to the info variable.\n"
 		"\n"
 		"\n"
 		"         #info cpu will show information about tintin's cpu usage.\n"
 		"         #info cpu will show information about tintin's cpu usage.\n"
+		"         #info mccp will show information about data compression.\n"
+		"         #info stack will show the low level debugging stack.\n"
+		"         #info session will show some session information.\n"
 		"         #info system will show some system information.\n",
 		"         #info system will show some system information.\n",
 
 
 		"class debug ignore kill message"
 		"class debug ignore kill message"
@@ -1657,19 +1707,19 @@ struct help_type help_table[] =
 		"<278>When TinTin++ starts up it sends \\e= to the terminal to enable the terminal's\n"
 		"<278>When TinTin++ starts up it sends \\e= to the terminal to enable the terminal's\n"
 		"application keypad mode, which can be disabled using #showme {\\e>}\n"
 		"application keypad mode, which can be disabled using #showme {\\e>}\n"
 		"\n"
 		"\n"
-		"<178>     Configuration A            Configuration B            Configuration C<278>\n"
-		"+-----+-----+-----+-----+  +-----+-----+-----+-----+  +-----+-----+-----+-----+\n"
-		"|Num  |/    |*    |-    |  |Num  |/    |*    |-    |  |Num  |nkp/ |nkp* |nkp- |\n"
-		"+-----+-----+-----+-----+  +-----+-----+-----+-----+  +-----+-----+-----+-----+\n"
-		"|7    |8    |9    |     |  |Home |Up   |PgUp |     |  |nkp7 |nkp8 |nkp9 |     |\n"
-		"+-----+-----+-----+     |  +-----+-----+-----+     |  +-----+-----+-----+     |\n"
-		"|4    |5    |6    |+    |  |Left |Centr|Right|+    |  |nkp4 |nkp5 |nkp6 |nkp+ |\n"
-		"+-----+-----+-----+-----+  +-----+-----+-----+-----+  +-----+-----+-----+-----+\n"
-		"|1    |2    |3    |     |  |End  |Down |PgDn |     |  |nkp1 |nkp2 |nkp3 |     |\n"
-		"+-----+-----+-----+     |  +-----+-----+-----+     |  +-----+-----+-----+     |\n"
-		"|0          |.    |Enter|  |Ins        |Del  |Enter|  |nkp0       |nkp. |nkpEn|\n"
-		"+-----------+-----+-----+  +-----------+-----+-----+  +-----------+-----+-----+\n"
-		"\n"
+		"<178>      Configuration A           Configuration B           Configuration C<268>\n"
+		" ╭─────┬─────┬─────┬─────╮ ╭─────┬─────┬─────┬─────╮ ╭─────┬─────┬─────┬─────╮\n"
+		" │<178>num<268>  │<178>/<268>    │<178>*<268>    │<178>-<268>    │ │<178>num<268>  │<178>/<268>    │<178>*<268>    │<178>-<268>    │ │<178>Num<268>  │<178>nkp/<268> │<178>nkp*<268> │<178>nkp-<268> │\n"
+		" ├─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┤\n"
+		" │<178>7<268>    │<178>8<268>    │<178>9<268>    │<178>+<268>    │ │<178>Home<268> │<178>Up<268>   │<178>PgUp<268> │<178>+<268>    │ │<178>nkp7<268> │<178>nkp8<268> │<178>nkp9<268> │<178>nkp+<268> │\n"
+		" ├─────┼─────┼─────┤     │ ├─────┼─────┼─────┤     │ ├─────┼─────┼─────┤     │\n"
+		" │<178>4<268>    │<178>5<268>    │<178>6<268>    │     │ │<178>Left<268> │<178>Cntr<268> │<178>Right<268>│     │ │<178>nkp4<268> │<178>nkp5<268> │<178>nkp6<268> │     │\n"
+		" ├─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┤ ├─────┼─────┼─────┼─────┤\n"
+		" │<178>1<268>    │<178>2<268>    │<178>3<268>    │<178>Enter<268>│ │<178>End<268>  │<178>Down<268> │<178>PgDn<268> │<178>Enter<268>│ │<178>nkp1<268> │<178>nkp2<268> │<178>nkp3<268> │<178>nkpEn<268>│\n"
+		" ├─────┴─────┼─────┤     │ ├─────┴─────┼─────┤     │ ├─────┴─────┼─────┤     │\n"
+		" │<178>0<268>          │<178>.<268>    │     │ │<178>Ins<268>        │<178>Del<268><268>  │     │ │<178>nkp0<268>       │<178>nkp.<268> │     │\n"
+		" ╰───────────┴─────┴─────╯ ╰───────────┴─────┴─────╯ ╰───────────┴─────┴─────╯\n"
+		"<278>\n"
 		"With keypad mode disabled numlock on will give you configuration A, and numlock\n"
 		"With keypad mode disabled numlock on will give you configuration A, and numlock\n"
 		"off will give you configuration B. With keypad mode enabled you'll get\n"
 		"off will give you configuration B. With keypad mode enabled you'll get\n"
 		"configuration C.\n"
 		"configuration C.\n"
@@ -1719,6 +1769,9 @@ struct help_type help_table[] =
 		"         <178>#line background <argument>\n"
 		"         <178>#line background <argument>\n"
 		"         <278>  Prevent new session activation.\n"
 		"         <278>  Prevent new session activation.\n"
 		"\n"
 		"\n"
+		"         <178>#line capture <variable> <argument.\n"
+		"         <278>  Argument is executed and output stored in <variable>.\n"
+		"\n"
 		"         <178>#line debug <argument>\n"
 		"         <178>#line debug <argument>\n"
 		"         <278>  Argument is executed in debug mode.\n"
 		"         <278>  Argument is executed in debug mode.\n"
 		"\n"
 		"\n"
@@ -1773,12 +1826,15 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         #list {var} {add} {item}               Add {item} to the list\n"
 		"         #list {var} {add} {item}               Add {item} to the list\n"
 		"         #list {var} {clear}                    Empty the given list\n"
 		"         #list {var} {clear}                    Empty the given list\n"
+		"         #list {var} {collapse}                 Turn list into a variable\n"
 		"         #list {var} {create} {item}            Create a list using {items}\n"
 		"         #list {var} {create} {item}            Create a list using {items}\n"
 		"         #list {var} {delete} {index} {number}  Delete the item at {index},\n"
 		"         #list {var} {delete} {index} {number}  Delete the item at {index},\n"
 		"                                                the {number} is optional.\n"
 		"                                                the {number} is optional.\n"
+		"         #list {var} {explode}                  Turn list into a character list\n"
 		"         #list {var} {insert} {index} {string}  Insert {string} at given index\n"
 		"         #list {var} {insert} {index} {string}  Insert {string} at given index\n"
 		"         #list {var} {find} {string} {variable} Return the found index\n"
 		"         #list {var} {find} {string} {variable} Return the found index\n"
 		"         #list {var} {get} {index} {variable}   Copy an item to {variable}\n"
 		"         #list {var} {get} {index} {variable}   Copy an item to {variable}\n"
+		"         #list {var} {shuffle}                  Shuffle the list\n"
 		"         #list {var} {set} {index} {string}     Change the item at {index}\n"
 		"         #list {var} {set} {index} {string}     Change the item at {index}\n"
 		"         #list {var} {simplify} {variable}      Copy simple list to {variable}\n"
 		"         #list {var} {simplify} {variable}      Copy simple list to {variable}\n"
 		"         #list {var} {size} {variable}          Copy list size to {variable}\n"
 		"         #list {var} {size} {variable}          Copy list size to {variable}\n"
@@ -1826,10 +1882,10 @@ struct help_type help_table[] =
 	{
 	{
 		"LOG",
 		"LOG",
 
 
-		"<178>Command<278>: #log <178>{<278>append<178>|<278>overwrite<178>} {<278>filename<178>}<278>\n"
+		"<178>Command<278>: #log <178>{<278>append<178>|<278>overwrite<178>|<278>off<178>} {<278>[filename]<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Logs session to a file, you can set the data type to either plain,\n"
-		"         raw, or html with the config command.\n",
+		"         Logs session output to a file, you can set the data type to either\n"
+		"         plain, raw, or html with the config command.\n",
 		
 		
 		"read scan textin write"
 		"read scan textin write"
 	},
 	},
@@ -1907,8 +1963,8 @@ struct help_type help_table[] =
 		"         <178>#map create <size>\n"
 		"         <178>#map create <size>\n"
 		"         <278>  Creates a new map and room 1. The default size is 50000 rooms.\n"
 		"         <278>  Creates a new map and room 1. The default size is 50000 rooms.\n"
 		"\n"
 		"\n"
-		"         <178>#map destroy\n"
-		"         <278>  Deletes the map.\n"
+		"         <178>#map destroy {area|world} <name>\n"
+		"         <278>  Deletes the map or given area.\n"
 		"\n"
 		"\n"
 		"         <178>#map delete <exit|vnum>\n"
 		"         <178>#map delete <exit|vnum>\n"
 		"         <278>  Deletes the room for the given exit or vnum.\n"
 		"         <278>  Deletes the room for the given exit or vnum.\n"
@@ -1923,12 +1979,16 @@ struct help_type help_table[] =
 		"         <278>  to the given room vnum. If the room vnum doesn't exist a new\n"
 		"         <278>  to the given room vnum. If the room vnum doesn't exist a new\n"
 		"         <278>  room is created.\n"
 		"         <278>  room is created.\n"
 		"\n"
 		"\n"
+		"         <178>#map entrance <exit> [option] [arg]\n"
+		"         <278>  Set the entrance data for the given exit. You must specify a\n"
+		"         <278>  valid two-way exit for this to work.\n"
+		"\n"
 		"         <178>#map exit <exit> <option> <arg>\n"
 		"         <178>#map exit <exit> <option> <arg>\n"
 		"         <278>  Set the exit data. Useful with a closed door where you can\n"
 		"         <278>  Set the exit data. Useful with a closed door where you can\n"
 		"         <278>  set the exit command: '#map exit e command {open east;e}'.\n"
 		"         <278>  set the exit command: '#map exit e command {open east;e}'.\n"
 		"         <278>  Use #map exit <exit> for a list of available options.\n"
 		"         <278>  Use #map exit <exit> for a list of available options.\n"
 		"\n"
 		"\n"
-		"         <178>#map exitflag <exit> <HIDE|AVOID> [on|off]\n"
+		"         <178>#map exitflag <exit> <AVOID|BLOCK|HIDE|INVIS> [on|off]\n"
 		"         <278>  Set exit flags. See #map roomflag for more info.\n"
 		"         <278>  Set exit flags. See #map roomflag for more info.\n"
 		"\n"
 		"\n"
 		"         <178>#map explore <exit>\n"
 		"         <178>#map explore <exit>\n"
@@ -2006,6 +2066,12 @@ struct help_type help_table[] =
 		"         <278>  Jump to the given coordinate, which is relative\n"
 		"         <278>  Jump to the given coordinate, which is relative\n"
 		"         <278>  to your current room.\n"
 		"         <278>  to your current room.\n"
 		"\n"
 		"\n"
+		"         <178>#map landmark <name> <vnum> [description] [size]\n"
+		"         <278>  Creates an alias to target the provided room vnum. The\n"
+		"         <278>  description is optional and should be brief. The size\n"
+		"         <278>  determines from how many rooms away the landmark can be\n"
+		"         <278>  seen.\n"
+		"\n"
 		"         <178>#map leave\n"
 		"         <178>#map leave\n"
 		"         <278>  Makes you leave the map. Useful when entering a maze. You\n"
 		"         <278>  Makes you leave the map. Useful when entering a maze. You\n"
 		"         <278>  can return to your last known room using #map return.\n"
 		"         <278>  can return to your last known room using #map return.\n"
@@ -2080,12 +2146,17 @@ struct help_type help_table[] =
 		"         <278>\n"
 		"         <278>\n"
 		"         <178>#map roomflag avoid\n"
 		"         <178>#map roomflag avoid\n"
 		"         <278>  When set, '#map find' will avoid a route leading\n"
 		"         <278>  When set, '#map find' will avoid a route leading\n"
-		"         <278>  through that room. Useful when you want to avoid death traps.\n"
+		"         <278>  through that room. Useful for locked doors, etc.\n"
+		"         <178>#map roomflag block\n"
+		"         <278>  When set the automapper will prevent movement into or through\n"
+		"         <278>  the room. Useful for death traps.\n"
 		"         <178>#map roomflag hide\n"
 		"         <178>#map roomflag hide\n"
 		"         <278>  When set, '#map' will not display the map beyond\n"
 		"         <278>  When set, '#map' will not display the map beyond\n"
 		"         <278>  this room. When mapping overlapping areas or areas that aren't\n"
 		"         <278>  this room. When mapping overlapping areas or areas that aren't\n"
 		"         <278>  build consistently you need this flag as well to stop\n"
 		"         <278>  build consistently you need this flag as well to stop\n"
 		"         <278>  auto-linking, unless you use void rooms.\n"
 		"         <278>  auto-linking, unless you use void rooms.\n"
+		"         <178>#map roomflag invis\n"
+		"         <278>  When set the room will be colored with the INVIS color.\n"
 		"         <178>#map roomflag leave\n"
 		"         <178>#map roomflag leave\n"
 		"         <278>  When entering a room with this flag, you will\n"
 		"         <278>  When entering a room with this flag, you will\n"
 		"         <278>  automatically leave the map. Useful when set at the entrance\n"
 		"         <278>  automatically leave the map. Useful when set at the entrance\n"
@@ -2112,6 +2183,22 @@ struct help_type help_table[] =
 		"         <278>  Set a map value for your current room, or given room if a room\n"
 		"         <278>  Set a map value for your current room, or given room if a room\n"
 		"         <278>  vnum is provided.\n"
 		"         <278>  vnum is provided.\n"
 		"\n"
 		"\n"
+		"         <178>#map sync <filename>\n"
+		"         <278>  Similar to #map read except the current map won't be unloaded\n"
+		"         <278>  or overwritten.\n"
+		"\n"
+		"         <178>#map terrain <name> <symbol> [flag]\n"
+		"         <278>  Set the terrain symbol and flag.\n"
+		"\n"
+		"         <178>#map terrain <name> <symbol> [DENSE|SPARSE|SCANT]\n"
+		"         <278>  Determine symbol density, omit for the default.\n"
+		"\n"
+		"         <178>#map terrain <name> <symbol> [NARROW|WIDE|VAST]\n"
+		"         <278>  Determine symbol spread range, omit for the default.\n"
+		"\n"
+		"         <178>#map terrain <name> <symbol> [FADEIN|FADEOUT]\n"
+		"         <278>  Determine symbol spread density, omit for the default.\n"
+		"\n"
 		"         <178>#map travel <direction> <delay>\n"
 		"         <178>#map travel <direction> <delay>\n"
 		"         <278>  Follows the direction until a dead end or an intersection is\n"
 		"         <278>  Follows the direction until a dead end or an intersection is\n"
 		"         <278>  found. Use braces around the direction if you use the delay,\n"
 		"         <278>  found. Use braces around the direction if you use the delay,\n"
@@ -2126,11 +2213,17 @@ struct help_type help_table[] =
 		"         <178>#map uninsert <direction>\n"
 		"         <178>#map uninsert <direction>\n"
 		"         <278>  Exact opposite of the insert command.\n"
 		"         <278>  Exact opposite of the insert command.\n"
 		"\n"
 		"\n"
+		"         <178>#map unlandmark <name>\n"
+		"         <278>  Removes a landmark.\n"
+		"\n"
 		"         <178>#map unlink <direction> [both]\n"
 		"         <178>#map unlink <direction> [both]\n"
 		"         <278>  Will remove the exit, this isn't two way so you can have the\n"
 		"         <278>  Will remove the exit, this isn't two way so you can have the\n"
 		"         <278>  properly display no exit rooms and mazes.\n"
 		"         <278>  properly display no exit rooms and mazes.\n"
 		"         <278>  If you use the both argument the exit is removed two-ways.\n"
 		"         <278>  If you use the both argument the exit is removed two-ways.\n"
 		"\n"
 		"\n"
+		"         <178>#map unterrain <name>\n"
+		"         <278>  Removes a terrain.\n"
+		"\n"
 		"         <178>#map update\n"
 		"         <178>#map update\n"
 		"         <278>  Sets the vtmap to update within the next 0.1 seconds.\n"
 		"         <278>  Sets the vtmap to update within the next 0.1 seconds.\n"
 		"\n"
 		"\n"
@@ -2208,8 +2301,9 @@ struct help_type help_table[] =
 		"           {#if {{%0} == {Bubba} && $afk} {reply I'm away, my friend.}}\n"
 		"           {#if {{%0} == {Bubba} && $afk} {reply I'm away, my friend.}}\n"
 		"         When you are away from keyboard, it will only reply to your friend.\n",
 		"         When you are away from keyboard, it will only reply to your friend.\n",
 
 
-		"format function local mathematics replace script variable"
+		"cat format function local mathematics replace script variable"
 	},
 	},
+
 	{
 	{
 		"MATHEMATICS",
 		"MATHEMATICS",
 
 
@@ -2242,7 +2336,7 @@ struct help_type help_table[] =
 		"         ^^             10            logical xor\n"
 		"         ^^             10            logical xor\n"
 		"         ||             11            logical or\n"
 		"         ||             11            logical or\n"
 		"\n"
 		"\n"
-		"Operator priority can be ignored by using paranthesis, for example (1 + 1) * 2\n"
+		"Operator priority can be ignored by using parentheses, for example (1 + 1) * 2\n"
 		"equals 4, while 1 + 1 * 2 equals 3.\n"
 		"equals 4, while 1 + 1 * 2 equals 3.\n"
 		"\n"
 		"\n"
 		"<178>String operations<278>\n"
 		"<178>String operations<278>\n"
@@ -2275,6 +2369,33 @@ struct help_type help_table[] =
 
 
 		"class debug ignore info kill"
 		"class debug ignore info kill"
 	},
 	},
+
+	{
+		"METRIC SYSTEM",
+
+		"  Name  Symbol                              Factor\n"
+		"--------------------------------------------------\n"
+//		" Yotta       Y   1 000 000 000 000 000 000 000 000\n"
+//		" Zetta       Z       1 000 000 000 000 000 000 000\n"
+//		"   Exa       E           1 000 000 000 000 000 000\n"
+//		"  Peta       P               1 000 000 000 000 000\n"
+//		"  Tera       T                   1 000 000 000 000\n"
+//		"  Giga       G                       1 000 000 000\n"
+		"  Mega       M                           1 000 000\n"
+		"  Kilo       K                               1 000\n"
+		"\n"
+		" milli       m                               0.001\n"
+		" micro       u                           0.000 001\n",
+//		"  nano       n                       0.000 000 001\n"
+//		"  pico       p                   0.000 000 000 001\n"
+//		" femto       f               0.000 000 000 000 001\n"
+//		"  atto       a           0.000 000 000 000 000 001\n"
+//		" zepto       z       0.000 000 000 000 000 000 001\n"
+//		" yocto       y   0.000 000 000 000 000 000 000 001\n",
+		
+		"echo format math"
+	},
+	
 	{
 	{
 		"MSDP",
 		"MSDP",
 
 
@@ -2454,7 +2575,7 @@ struct help_type help_table[] =
 		"         Perl Compatible Regular Expressions<278>\n"
 		"         Perl Compatible Regular Expressions<278>\n"
 		"\n"
 		"\n"
 		"         You can embed a PCRE (Perl Compatible Regular Expression) using curley\n"
 		"         You can embed a PCRE (Perl Compatible Regular Expression) using curley\n"
-		"         braces { }, these braces are replaced with paranthesis ( ) unless you\n"
+		"         braces { }, these braces are replaced with parentheses ( ) unless you\n"
 		"         use %!{ }.\n"
 		"         use %!{ }.\n"
 		"<178>\n"
 		"<178>\n"
 		"         Or<278>\n"
 		"         Or<278>\n"
@@ -2498,17 +2619,17 @@ struct help_type help_table[] =
 		"         The example only triggers if someone provides a number between 1 and\n"
 		"         The example only triggers if someone provides a number between 1 and\n"
 		"         999.\n"
 		"         999.\n"
 		"\n"
 		"\n"
-		"         <178>Paranthesis<278>\n"
+		"         <178>Parantheses<278>\n"
 		"\n"
 		"\n"
 		"         TinTin Regular Expressions automatically add parenthesis, for example\n"
 		"         TinTin Regular Expressions automatically add parenthesis, for example\n"
 		"         %* translates to (.*?) in PCRE unless the %* is found at the start or\n"
 		"         %* translates to (.*?) in PCRE unless the %* is found at the start or\n"
 		"         end of the line, in which cases it translates to (.*). Paranthesis in\n"
 		"         end of the line, in which cases it translates to (.*). Paranthesis in\n"
 		"         PCRE causes a change in execution priority similar to mathematical\n"
 		"         PCRE causes a change in execution priority similar to mathematical\n"
-		"         expressions, but paranthesis also causes the match to be stored to a\n"
+		"         expressions, but parentheses also causes the match to be stored to a\n"
 		"         variable.\n"
 		"         variable.\n"
 		"\n"
 		"\n"
-		"         When nesting multiple sets of paranthesis each nest is assigned its\n"
-		"         numercial variable in order of appearance.\n"
+		"         When nesting multiple sets of parentheses each nest is assigned its\n"
+		"         numerical variable in order of appearance.\n"
 		"\n"
 		"\n"
 		"Example: #act {%* chats '{Mu(ha)+}'} {chat %2ha!}\n"
 		"Example: #act {%* chats '{Mu(ha)+}'} {chat %2ha!}\n"
 		"\n"
 		"\n"
@@ -2565,8 +2686,8 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"Example: #action {~\\e[1;37m%1} {#var roomname %1}\n"
 		"Example: #action {~\\e[1;37m%1} {#var roomname %1}\n"
 		"\n"
 		"\n"
-		"         If the room name is the only line on the mud in bright white this\n"
-		"         color trigger will save the roomname.\n"
+		"         If the room name is the only line on the server in bright white\n"
+		"         white color trigger will save the roomname.\n"
 		"\n"
 		"\n"
 		"\n"
 		"\n"
 		"         This covers the basics. PCRE has more options, most of which are\n"
 		"         This covers the basics. PCRE has more options, most of which are\n"
@@ -2612,7 +2733,7 @@ struct help_type help_table[] =
 		"         <278>  Send data to socket\n"
 		"         <278>  Send data to socket\n"
 		"\n"
 		"\n"
 		"         <178>#port {uninitialize}\n"
 		"         <178>#port {uninitialize}\n"
-		"         <278>  Unitialize the port session.\n"
+		"         <278>  Uninitialize the port session.\n"
 		"\n"
 		"\n"
 		"         <178>#port {who}\n"
 		"         <178>#port {who}\n"
 		"         <278>  Show all connections\n"
 		"         <278>  Show all connections\n"
@@ -2622,7 +2743,9 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         The port command is very similar to chat except that it creates a\n"
 		"         The port command is very similar to chat except that it creates a\n"
 		"         new session dedicated to receiving socket connections at the given\n"
 		"         new session dedicated to receiving socket connections at the given\n"
-		"         port number without built-in support for a communication protocol.\n",
+		"         port number without built-in support for a communication protocol.\n"
+		"\n"
+		"         You can init with 0 as the port number to create a dummy session.\n",
 
 
 		"all chat run session sessionname snoop ssl zap"
 		"all chat run session sessionname snoop ssl zap"
 	},
 	},
@@ -2698,16 +2821,26 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         Of the following the (lazy) match is available at %1-%99 + 1\n"
 		"         Of the following the (lazy) match is available at %1-%99 + 1\n"
 		"\n"
 		"\n"
-		"      %w match zero to any number of word characters.\n"
-		"      %W match zero to any number of non word characters.\n"
+		"      %a match zero to any number of characters except newlines.\n"
+		"      %A match zero to any number of newlines.\n"
 		"      %d match zero to any number of digits.\n"
 		"      %d match zero to any number of digits.\n"
 		"      %D match zero to any number of non digits.\n"
 		"      %D match zero to any number of non digits.\n"
+		"      %p match zero to any number of printable characters.\n"
+		"      %P match zero to any number of non printable characters.\n"
 		"      %s match zero to any number of spaces.\n"
 		"      %s match zero to any number of spaces.\n"
 		"      %S match zero to any number of non spaces.\n"
 		"      %S match zero to any number of non spaces.\n"
+		"      %u match zero to any number of unicode characters.\n"
+		"      %U match zero to any number of non unicode characters.\n"
+		"      %w match zero to any number of word characters.\n"
+		"      %W match zero to any number of non word characters.\n"
 		"\n"
 		"\n"
+		"      If you want to match 1 digit use %+1d, if you want to match between 3\n"
+		"      and 5 spaces use %+3..5s, if you want to match between 0 and 1 word\n"
+		"      characters use %+0..1w\n"
+		"\n"
+		"      %+ match one to any number of characters.\n"
 		"      %? match zero or one character.\n"
 		"      %? match zero or one character.\n"
-		"      %. match one character. (<118>do not use<278>)\n"
-		"      %+ match one to any number of characters. (<118>do not use<278>)\n"
+		"      %. match one character.\n"
 		"      %* match zero to any number of characters.\n"
 		"      %* match zero to any number of characters.\n"
 		"\n"
 		"\n"
 		"      %i matching becomes case insensitive.\n"
 		"      %i matching becomes case insensitive.\n"
@@ -2740,10 +2873,10 @@ struct help_type help_table[] =
 
 
 		"<178>Command<278>: #replace <178>{<278>variable<178>} {<278>oldtext<178>} {<278>newtext<178>}<278>\n"
 		"<178>Command<278>: #replace <178>{<278>variable<178>} {<278>oldtext<178>} {<278>newtext<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Searches the variable text replacing each occurance of 'oldtext' with\n"
+		"         Searches the variable text replacing each occurrence of 'oldtext' with\n"
 		"         'newtext'.\n",
 		"         'newtext'.\n",
 
 
-		"format function local math script variable"
+		"cat format function local math script variable"
 	},
 	},
 	{
 	{
 		"RETURN",
 		"RETURN",
@@ -2765,7 +2898,7 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"         The run command works much like the system command except that it\n"
 		"         The run command works much like the system command except that it\n"
 		"         runs the command in a pseudo terminal. The run command also creates\n"
 		"         runs the command in a pseudo terminal. The run command also creates\n"
-		"         a session that treats the given shell command as a mud server. This\n"
+		"         a session that treats the given shell command as a server. This\n"
 		"         allows you to run ssh, as well as any other shell application, with\n"
 		"         allows you to run ssh, as well as any other shell application, with\n"
 		"         full tintin scripting capabilities. If a file name is given the file\n"
 		"         full tintin scripting capabilities. If a file name is given the file\n"
 		"         is loaded prior to execution.\n"
 		"         is loaded prior to execution.\n"
@@ -2818,7 +2951,7 @@ struct help_type help_table[] =
 		"         <178>#scan {txt} <filename>\n"
 		"         <178>#scan {txt} <filename>\n"
 		"\n"
 		"\n"
 		"         <278>  The scan txt <filename> command reads in a file and sends its content\n"
 		"         <278>  The scan txt <filename> command reads in a file and sends its content\n"
-		"           to the screen as if it was send by a mud. After using scan you can\n"
+		"           to the screen as if it was send by a server. After using scan you can\n"
 		"           use page-up and down to view the file.\n"
 		"           use page-up and down to view the file.\n"
 		"\n"
 		"\n"
 		"           This command is useful to convert ansi color files to html or viewing\n"
 		"           This command is useful to convert ansi color files to html or viewing\n"
@@ -2900,10 +3033,10 @@ struct help_type help_table[] =
 
 
 		"<178>Command<278>: #config <178>{<278>SCREEN READER<178>} {<278>ON|OFF<178>}<278>\n"
 		"<178>Command<278>: #config <178>{<278>SCREEN READER<178>} {<278>ON|OFF<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Screen reader mode is enabled by using #config screen on. The main\n"
-		"         purpose of the screen reader mode is to tell MUDs that a screen reader\n"
-		"         is being used by using the MTTS standard. The MTTS specification is\n"
-		"         available at:\n"
+		"         Screen reader mode is enabled by using #config screen on.  The main\n"
+		"         purpose of the screen reader mode is to report to servers that a\n"
+		"         screen reader is being used by utilizing the MTTS standard.  The MTTS\n"
+		"         specification is available at:\n"
 		"\n"
 		"\n"
 		"         http://tintin.sourceforge.net/protocols/mtts\n"
 		"         http://tintin.sourceforge.net/protocols/mtts\n"
 		"\n"
 		"\n"
@@ -2940,8 +3073,8 @@ struct help_type help_table[] =
 
 
 		"<178>Command<278>: #send <178>{<278>text<178>}<278>\n"
 		"<178>Command<278>: #send <178>{<278>text<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Sends the text directly to the MUD, useful if you want to start with an\n"
-		"         escape code.\n",
+		"         Sends the text directly to the server, useful if you want to start\n"
+		"         with an escape code.\n",
 
 
 		"textin"
 		"textin"
 	},
 	},
@@ -2982,7 +3115,7 @@ struct help_type help_table[] =
 		"         The startup session is named 'gts' and can be used for relog scripts. Do\n"
 		"         The startup session is named 'gts' and can be used for relog scripts. Do\n"
 		"         keep in mind that tickers do not work in the startup session.\n"
 		"         keep in mind that tickers do not work in the startup session.\n"
 		"\n"
 		"\n"
-		"<178>Example<278>: #event {SESSION DISCONNECTED} {#gts #delay 10 #ses %0 mymud.com 4321}\n",
+		"<178>Example<278>: #event {SESSION DISCONNECTED} {#gts #delay 10 #ses %0 tintin.net 4321}\n",
 
 
 		"all port run sessionname snoop ssl zap"
 		"all port run sessionname snoop ssl zap"
 	},
 	},
@@ -3002,7 +3135,7 @@ struct help_type help_table[] =
 		"session when used without an argument. If an argument is given it will be\n"
 		"session when used without an argument. If an argument is given it will be\n"
 		"executed by that session as a command, the session will not be activated.\n"
 		"executed by that session as a command, the session will not be activated.\n"
 		"\n"
 		"\n"
-		"<178>Example<278>: #ses one mymud.com 23;#ses two mymud.com 23;#one;#two grin\n"
+		"<178>Example<278>: #ses one tintin.net 23;#ses two tintin.net 23;#one;#two grin\n"
 		"\n"
 		"\n"
 		"This will create two sessions, the session that was created last (two in this\n"
 		"This will create two sessions, the session that was created last (two in this\n"
 		"case) will be automatically activated upon creation. Using #one, session one is\n"
 		"case) will be automatically activated upon creation. Using #one, session one is\n"
@@ -3017,9 +3150,9 @@ struct help_type help_table[] =
 
 
 		"<178>Command<278>: #showme <178>{<278>string<178>} {<278>row<178>} <178>{<278>col<178>}<278>\n"
 		"<178>Command<278>: #showme <178>{<278>string<178>} {<278>row<178>} <178>{<278>col<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Display the string to the terminal, do not send to the mud.  Useful for\n"
-		"         status, warnings, etc.  The {row} and col number are optional and work\n"
-		"         the same way as the row number of the #prompt trigger.\n"
+		"         Display the string to the terminal, do not send to the server.  Useful\n"
+		"         for status, warnings, etc.  The {row} and col number are optional and\n"
+		"         work the same way as the row number of the #prompt trigger.\n"
 		"\n"
 		"\n"
 		"         Actions can be triggered by the showme command. If you want to avoid\n"
 		"         Actions can be triggered by the showme command. If you want to avoid\n"
 		"         this from happening use: #line ignore #showme {<string>}.\n"
 		"         this from happening use: #line ignore #showme {<string>}.\n"
@@ -3047,15 +3180,16 @@ struct help_type help_table[] =
 	{
 	{
 		"SPEEDWALK",
 		"SPEEDWALK",
 
 
-		"         <278>Speedwalking allows you to type multiple directions not separated by\n"
-		"         semicolons, and now it lets you prefix a direction with a number, to\n"
-		"         signify how many times to go that direction. You can turn it on/off\n"
-		"         with #config.\n"
+		"         <278>Speedwalking allows you to enter multiple directions without using\n"
+		"         semicolons. Directions should be prefixed with a number and will be\n"
+		"         executed the given number of times.\n"
+		"\n"
+		"         You can enable speedwalking with #CONFIG {SPEEDWALK} {ON}.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: Without speedwalk, you have to type:\n"
 		"<178>Example<278>: Without speedwalk, you have to type:\n"
 		"         s;s;w;w;w;w;w;s;s;s;w;w;w;n;n;w\n"
 		"         s;s;w;w;w;w;w;s;s;s;w;w;w;n;n;w\n"
 		"         With speedwalk, you only have to type:\n"
 		"         With speedwalk, you only have to type:\n"
-		"         2s5w3s3w2nw\n",
+		"         2s5w3s3w2n1w\n",
 
 
 		"alias cursor history keypad macro tab"
 		"alias cursor history keypad macro tab"
 	},
 	},
@@ -3142,9 +3276,9 @@ struct help_type help_table[] =
 	{
 	{
 		"SUBSTITUTE",
 		"SUBSTITUTE",
 
 
-		"<178>Command<278>: #substitute <178>{<278>text<178>} {<278>new text<178>}<278>\n"
+		"<178>Command<278>: #substitute <178>{<278>text<178>} {<278>new text<178>} {<278>priority<178>}<278>\n"
 		"\n"
 		"\n"
-		"         Allows you to replace original text from the mud with different text.\n"
+		"         Allows you to replace text from the server with the new text.\n"
 		"         This is helpful for complex coloring and making things more readable.\n"
 		"         This is helpful for complex coloring and making things more readable.\n"
 		"         The %1-%99 variables can be used to capture text and use it as part of\n"
 		"         The %1-%99 variables can be used to capture text and use it as part of\n"
 		"         the new output, and the ^ char is valid to only check the beginning of\n"
 		"         the new output, and the ^ char is valid to only check the beginning of\n"
@@ -3235,7 +3369,7 @@ struct help_type help_table[] =
 		"<178>Command<278>: #textin <178>{<278>filename<178>} {<278>delay<178>}<278>\n"
 		"<178>Command<278>: #textin <178>{<278>filename<178>} {<278>delay<178>}<278>\n"
 		"\n"
 		"\n"
 		"         Textin allows the user to read in a file, and send its contents\n"
 		"         Textin allows the user to read in a file, and send its contents\n"
-		"         directly to the mud.  Useful for doing online creation, or message\n"
+		"         directly to the server.  Useful for doing online creation, or message\n"
 		"         writing.\n"
 		"         writing.\n"
 		"\n"
 		"\n"
 		"         The delay is in seconds and takes a floating point number which is\n"
 		"         The delay is in seconds and takes a floating point number which is\n"
@@ -3353,7 +3487,7 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"<178>Comment<278>: You can remove a variable with the #unvariable command.\n",
 		"<178>Comment<278>: You can remove a variable with the #unvariable command.\n",
 
 
-		"format function local math replace script"
+		"cat format function local math replace script"
 	},
 	},
 	{
 	{
 		"WHILE",
 		"WHILE",

+ 2 - 3
src/history.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2006                       *
 *                      coded by Igor van den Hoven 2006                       *
 ******************************************************************************/
 ******************************************************************************/

+ 48 - 7
src/input.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2006                       *
 *                      coded by Igor van den Hoven 2006                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -33,11 +32,30 @@ void process_input(void)
 
 
 	push_call("process_input(void)");
 	push_call("process_input(void)");
 
 
+	gtd->time_input = gtd->time;
+
 	if (gtd->detach_port)
 	if (gtd->detach_port)
 	{
 	{
-		if (gtd->detach_sock)
+		if (gtd->detach_sock > 0)
 		{
 		{
 			len = read(gtd->detach_sock, input, 1);
 			len = read(gtd->detach_sock, input, 1);
+
+			if (len <= 0)
+			{
+				if (len == -1)
+				{
+					syserr_printf(gtd->ses, "process_input: read", gtd->detach_sock);
+				}
+				else
+				{
+					show_message(gtd->ses, LIST_COMMAND, "#DAEMON UPDATE: DETACHING FROM PID {%d} DUE TO READ FAILURE.", gtd->detach_pid);
+				}
+
+				gtd->detach_sock = close(gtd->detach_sock);
+
+				pop_call();
+				return;
+			}
 		}
 		}
 		else
 		else
 		{
 		{
@@ -63,7 +81,7 @@ void process_input(void)
 
 
 		gtd->attach_sock = close(gtd->attach_sock);
 		gtd->attach_sock = close(gtd->attach_sock);
 
 
-		show_message(gtd->ses, LIST_COMMAND, "#ATTACH: WRITE ERROR: UNATTACHING.");
+		show_message(gtd->ses, LIST_COMMAND, "#DAEMON ATTACH: WRITE ERROR: UNATTACHING.");
 	}
 	}
 
 
 	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) && !HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
 	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) && !HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
@@ -87,6 +105,7 @@ void process_input(void)
 	{
 	{
 		chat_paste(gtd->input_buf, NULL);
 		chat_paste(gtd->input_buf, NULL);
 
 
+		pop_call();
 		return;
 		return;
 	}
 	}
 
 
@@ -355,10 +374,12 @@ int check_key(char *input, int len)
 	char buf[BUFFER_SIZE];
 	char buf[BUFFER_SIZE];
 	struct listroot *root;
 	struct listroot *root;
 	struct listnode *node;
 	struct listnode *node;
-	int cnt, val[3];
+	int cnt, val[5];
 
 
 	push_call("check_key(%p,%d)",input,len);
 	push_call("check_key(%p,%d)",input,len);
 
 
+//	tintin_printf2(gtd->ses, "check_key(%d,%s)",*gtd->macro_buf, gtd->macro_buf);
+
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
 	{
 	{
 		root  = gtd->ses->list[LIST_MACRO];
 		root  = gtd->ses->list[LIST_MACRO];
@@ -463,10 +484,19 @@ int check_key(char *input, int len)
 				}
 				}
 				else if (gtd->macro_buf[2] >= '0' && gtd->macro_buf[2] <= '9')
 				else if (gtd->macro_buf[2] >= '0' && gtd->macro_buf[2] <= '9')
 				{
 				{
-					val[0] = val[1] = val[2] = cnt = input[0] = 0;
+					cnt = input[0] = 0;
+					memset(val, 0, sizeof(val));
 
 
+//					tintin_printf2(gtd->ses, "debug: %d %d %d %d %d", val[0], val[1], val[2], val[3], val[4], val[5]);
+		
 					for (len = 2 ; gtd->macro_buf[len] ; len++)
 					for (len = 2 ; gtd->macro_buf[len] ; len++)
 					{
 					{
+						if (cnt > 5)
+						{
+							pop_call();
+							return FALSE;
+						}
+
 						if (isdigit(gtd->macro_buf[len]))
 						if (isdigit(gtd->macro_buf[len]))
 						{
 						{
 							cat_sprintf(input, "%c", gtd->macro_buf[len]);
 							cat_sprintf(input, "%c", gtd->macro_buf[len]);
@@ -499,6 +529,17 @@ int check_key(char *input, int len)
 									pop_call();
 									pop_call();
 									return TRUE;
 									return TRUE;
 
 
+								case '&':
+									val[cnt++] = get_number(gtd->ses, input);
+									input[0] = 0;
+									break;
+
+								case 'w':
+									rqlp_handler(val[0], val[1], val[2], val[3]);
+									gtd->macro_buf[0] = 0;
+									pop_call();
+									return TRUE;
+
 								default:
 								default:
 									pop_call();
 									pop_call();
 									return FALSE;
 									return FALSE;

+ 64 - 5
src/line.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2008                       *
 *                      coded by Igor van den Hoven 2008                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -92,6 +91,62 @@ DO_LINE(line_background)
 	return ses;
 	return ses;
 }
 }
 
 
+DO_LINE(line_benchmark)
+{
+	long long start, end;
+	char arg1[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BENCHMARK} {command}.");
+
+		return ses;
+	}
+
+	start = utime();
+
+	ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	end = utime();
+
+	tintin_printf2(ses, "#LINE BENCHMARK: %lld USEC.", end - start);
+
+	return ses;
+}
+
+DO_LINE(line_capture)
+{
+	char arg1[BUFFER_SIZE], arg2[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);
+
+	if (*arg1 && *arg2)
+	{
+		if (ses->line_capturefile)
+		{
+			free(ses->line_capturefile);
+		}
+		ses->line_capturefile  = strdup(arg1);
+		ses->line_captureindex = 1;
+
+		ses = script_driver(ses, LIST_COMMAND, arg2);
+
+		if (ses->line_capturefile)
+		{
+			free(ses->line_capturefile);
+			ses->line_capturefile = NULL;
+		}
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE CAPTURE {VARIABLE} {command}.");
+	}
+	return ses;
+}
+
 DO_LINE(line_debug)
 DO_LINE(line_debug)
 {
 {
 	char arg1[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE];
@@ -242,19 +297,23 @@ DO_LINE(line_logmode)
 			break;
 			break;
 	}
 	}
 
 
-	DEL_BIT(ses->logmode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
-
 	if (is_abbrev(arg1, "HTML"))
 	if (is_abbrev(arg1, "HTML"))
 	{
 	{
 		SET_BIT(ses->logmode, LOG_FLAG_HTML);
 		SET_BIT(ses->logmode, LOG_FLAG_HTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->logmode, LOG_FLAG_RAW);
 	}
 	}
 	else if (is_abbrev(arg1, "PLAIN"))
 	else if (is_abbrev(arg1, "PLAIN"))
 	{
 	{
 		SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
 		SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->logmode, LOG_FLAG_HTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_RAW);
 	}
 	}
 	else if (is_abbrev(arg1, "RAW"))
 	else if (is_abbrev(arg1, "RAW"))
 	{
 	{
 		SET_BIT(ses->logmode, LOG_FLAG_RAW);
 		SET_BIT(ses->logmode, LOG_FLAG_RAW);
+		DEL_BIT(ses->logmode, LOG_FLAG_HTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
 	}
 	}
 	else
 	else
 	{
 	{

+ 134 - 29
src/list.c

@@ -31,12 +31,9 @@
 DO_COMMAND(do_list)
 DO_COMMAND(do_list)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-	struct listroot *root;
 	struct listnode *node;
 	struct listnode *node;
 	int index, cnt;
 	int index, cnt;
 
 
-	root = ses->list[LIST_VARIABLE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, 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, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
 
@@ -73,9 +70,9 @@ DO_COMMAND(do_list)
 		}
 		}
 		else
 		else
 		{
 		{
-			if ((node = search_nest_node(root, arg1)) == NULL)
+			if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 			{
 			{
-				node = set_nest_node(root, arg1, "");
+				node = set_nest_node_ses(ses, arg1, "");
 			}
 			}
 			array_table[cnt].fun(ses, node, arg, arg1);
 			array_table[cnt].fun(ses, node, arg, arg1);
 		}
 		}
@@ -107,13 +104,16 @@ DO_ARRAY(array_add)
 
 
 			set_nest_node(list->root, ntos(index++), "%s", arg2);
 			set_nest_node(list->root, ntos(index++), "%s", arg2);
 
 
-//			insert_node_list(list->root, ntos(index++), arg2, "");
-
 			if (*str == COMMAND_SEPARATOR)
 			if (*str == COMMAND_SEPARATOR)
 			{
 			{
 				str++;
 				str++;
 			}
 			}
 		}
 		}
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -127,8 +127,27 @@ DO_ARRAY(array_clear)
 		list->root = NULL;
 		list->root = NULL;
 	}
 	}
 
 
-	set_nest_node(ses->list[LIST_VARIABLE], var, "");
+	set_nest_node_ses(ses, var, "");
+
+	return ses;
+}
+
+DO_ARRAY(array_collapse)
+{
+	int index;
+
+	if (list->root)
+	{
+		str_cpy(&list->arg2, "");
+
+		for (index = 0 ; index < list->root->used ; index++)
+		{
+			str_cat(&list->arg2, list->root->list[index]->arg2);
+		}
+		free_list(list->root);
 
 
+		list->root = NULL;
+	}
 	return ses;
 	return ses;
 }
 }
 
 
@@ -200,7 +219,7 @@ DO_ARRAY(array_delete)
 
 
 			for (cnt = index + 1 ; cnt < list->root->used ; cnt++)
 			for (cnt = index + 1 ; cnt < list->root->used ; cnt++)
 			{
 			{
-				list->root->list[cnt]->arg1 = restringf(list->root->list[cnt]->arg1, "%d", cnt);
+				str_cpy_printf(&list->root->list[cnt]->arg1, "%d", cnt);
 			}
 			}
 
 
 			delete_index_list(list->root, index);
 			delete_index_list(list->root, index);
@@ -213,6 +232,61 @@ DO_ARRAY(array_delete)
 	return ses;
 	return ses;
 }
 }
 
 
+DO_ARRAY(array_explode)
+{
+	char buf[BUFFER_SIZE], tmp[BUFFER_SIZE], *pti;
+	int index = 1;
+
+	if (list->root)
+	{
+		array_collapse(ses, list, "", "");
+	}
+
+	list->root = init_list(ses, LIST_VARIABLE, LIST_SIZE);
+
+	pti = list->arg2;
+
+	while (*pti)
+	{
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
+		{
+			pti += sprintf(tmp, "%.*s", get_euc_size(ses, pti), pti);
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
+		{
+			pti += sprintf(tmp, "%.*s", get_utf8_size(pti), pti);
+		}
+		else
+		{
+			pti += sprintf(tmp, "%c", *pti);
+		}
+
+		set_nest_node(list->root, ntos(index++), "%s", tmp);
+	}
+	sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
+
+	pti = buf;
+
+	while (*pti)
+	{
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
+		{
+			pti += sprintf(tmp, "%.*s", get_euc_size(ses, pti), pti);
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
+		{
+			pti += sprintf(tmp, "%.*s", get_utf8_size(pti), pti);
+		}
+		else
+		{
+			pti += sprintf(tmp, "%c", *pti);
+		}
+
+		set_nest_node(list->root, ntos(index++), "%s", tmp);
+	}
+	return ses;
+}
+
 DO_ARRAY(array_find)
 DO_ARRAY(array_find)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
@@ -239,17 +313,17 @@ DO_ARRAY(array_find)
 		}
 		}
 		if (index < list->root->used)
 		if (index < list->root->used)
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", index + 1);
+			set_nest_node_ses(ses, arg2, "%d", index + 1);
 		}
 		}
 		else
 		else
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
+			set_nest_node_ses(ses, arg2, "0");
 		}
 		}
 		return ses;
 		return ses;
 	}
 	}
 	else
 	else
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
+		set_nest_node_ses(ses, arg2, "0");
 	}
 	}
 
 
 	return ses;
 	return ses;
@@ -276,17 +350,17 @@ DO_ARRAY(array_get)
 
 
 		if (atoi(arg1) == 0 || index == -1)
 		if (atoi(arg1) == 0 || index == -1)
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
+			set_nest_node_ses(ses, arg2, "0");
 		}
 		}
 		else
 		else
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", list->root->list[index]->arg2);
+			set_nest_node_ses(ses, arg2, "%s", list->root->list[index]->arg2);
 		}
 		}
 		return ses;
 		return ses;
 	}
 	}
 	else
 	else
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
+		set_nest_node_ses(ses, arg2, "0");
 	}
 	}
 
 
 	return ses;
 	return ses;
@@ -321,7 +395,7 @@ DO_ARRAY(array_insert)
 
 
 	for (cnt = index ; cnt < list->root->used ; cnt++)
 	for (cnt = index ; cnt < list->root->used ; cnt++)
 	{
 	{
-		list->root->list[cnt]->arg1 = restringf(list->root->list[cnt]->arg1, "%d", cnt + 2);
+		str_cpy_printf(&list->root->list[cnt]->arg1, "%d", cnt + 2);
 	}
 	}
 
 
 	set_nest_node(list->root, ntos(index + 1), "%s", arg2);
 	set_nest_node(list->root, ntos(index + 1), "%s", arg2);
@@ -333,38 +407,47 @@ DO_ARRAY(array_insert)
 
 
 DO_ARRAY(array_simplify)
 DO_ARRAY(array_simplify)
 {
 {
-	char arg1[BUFFER_SIZE], tmp[BUFFER_SIZE];
+	char arg1[BUFFER_SIZE], *str;
 	int index;
 	int index;
 
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-
+/*
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
 		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} SIMPLIFY {variable}");
 		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} SIMPLIFY {variable}");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
-
+*/
 	if (list->root)
 	if (list->root)
 	{
 	{
 		for (index = 0 ; index < list->root->used ; index++)
 		for (index = 0 ; index < list->root->used ; index++)
 		{
 		{
 			if (index == 0)
 			if (index == 0)
 			{
 			{
-				strcpy(tmp, list->root->list[index]->arg2);
+				str = str_dup(list->root->list[index]->arg2);
 			}
 			}
 			else
 			else
 			{
 			{
-				cat_sprintf(tmp, ";%s", list->root->list[index]->arg2);
+				str_cat_printf(&str, ";%s", list->root->list[index]->arg2);
 			}
 			}
 		}
 		}
-		set_nest_node(ses->list[LIST_VARIABLE], arg1, "%s", tmp);
+		if (*arg1 == 0)
+		{
+			set_nest_node_ses(ses, list->arg1, "%s", str);
+		}
+		else
+		{
+			set_nest_node_ses(ses, arg1, "%s", str);
+		}
+
+		str_free(str);
 
 
 		return ses;
 		return ses;
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#LIST SIMPLIFY: {%s} is not a list.", arg1);
+		show_error(ses, LIST_VARIABLE, "#LIST SIMPLIFY: {%s} is not a list.", list->arg1);
 	}
 	}
 
 
 	return ses;
 	return ses;
@@ -385,11 +468,11 @@ DO_ARRAY(array_size)
 
 
 	if (list->root)
 	if (list->root)
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg1, "%d", list->root->used);
+		set_nest_node_ses(ses, arg1, "%d", list->root->used);
 	}
 	}
 	else
 	else
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg1, "0");
+		set_nest_node_ses(ses, arg1, "0");
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -412,7 +495,9 @@ DO_ARRAY(array_set)
 			return ses;
 			return ses;
 		}
 		}
 
 
-		RESTRING(list->root->list[index]->arg2, arg2);
+		set_nest_node(list->root, ntos(index + 1), "%s", arg2);
+
+//		RESTRING(list->root->list[index]->arg2, arg2);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -422,6 +507,27 @@ DO_ARRAY(array_set)
 	return ses;
 	return ses;
 }
 }
 
 
+DO_ARRAY(array_shuffle)
+{
+	char *swap;
+	int cnt, rnd;
+
+	if (!list->root)
+	{
+		list->root = init_list(ses, LIST_VARIABLE, LIST_SIZE);
+	}
+
+	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	{
+		rnd = generate_rand(ses) % list->root->used;
+
+		swap = list->root->list[cnt]->arg2;
+		list->root->list[cnt]->arg2 = list->root->list[rnd]->arg2;
+		list->root->list[rnd]->arg2 = swap;
+	}
+	return ses;
+}
+
 DO_ARRAY(array_sort)
 DO_ARRAY(array_sort)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], *str;
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], *str;
@@ -492,9 +598,9 @@ DO_ARRAY(array_tokenize)
 
 
 	while (buf[i] != 0)
 	while (buf[i] != 0)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && buf[i] & 128 && buf[i+1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &buf[i]))
 		{
 		{
-			i += sprintf(tmp, "%c%c", buf[i], buf[i+1]);
+			i += sprintf(tmp, "%.*s", get_euc_size(ses, &buf[i]), &buf[i]);
 		}
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&buf[i]))
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&buf[i]))
 		{
 		{
@@ -509,4 +615,3 @@ DO_ARRAY(array_tokenize)
 	}
 	}
 	return ses;
 	return ses;
 }
 }
-

+ 13 - 7
src/log.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -78,7 +77,7 @@ void loginit(struct session *ses, FILE *file, int flags)
 	{
 	{
 		if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
 		if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
 		{
 		{
-			write_html_header(ses, ses->logfile);
+			write_html_header(ses, file);
 		}
 		}
 	}
 	}
 	pop_call();
 	pop_call();
@@ -166,10 +165,15 @@ void write_html_header(struct session *ses, FILE *fp)
 		sprintf(header, "<html>\n"
 		sprintf(header, "<html>\n"
 		"<head>\n"
 		"<head>\n"
 		"<meta http-equiv='content-type' content='text/html; charset=%s'>\n"
 		"<meta http-equiv='content-type' content='text/html; charset=%s'>\n"
+		"<meta name='viewport' content='width=device-width, initial-scale=1.0'>\n"
 		"<meta name='description' content='Generated by TinTin++ "CLIENT_VERSION" - http://tintin.sourceforge.net'>\n"
 		"<meta name='description' content='Generated by TinTin++ "CLIENT_VERSION" - http://tintin.sourceforge.net'>\n"
 		"<style type='text/css'>\n"
 		"<style type='text/css'>\n"
-		"{\n\tfont-family: Courier;\n\tfont-size: 10pt;\n}\n"
-		"a:link {color: cyan;} a:visited {color: green;} a:hover {color: white;} a:active {color:purple;}\n"
+		"body {font-family:Consolas;font-size:12pt;}\n"
+		"a {text-decoration:none;}\n"
+		"a:link {color:#06b;}\n"
+		"a:visited {color:#6b0;}\n"
+		"a:hover {text-decoration:underline;}\n"
+		"a:active {color:#b06;}\n"
 		".d30{ color: #000; } .l30{ color: #555; } .b40{ background-color: #000; } .b50{ background-color: #555 }\n"
 		".d30{ color: #000; } .l30{ color: #555; } .b40{ background-color: #000; } .b50{ background-color: #555 }\n"
 		".d31{ color: #B00; } .l31{ color: #F55; } .b41{ background-color: #B00; } .b51{ background-color: #F55 }\n"
 		".d31{ color: #B00; } .l31{ color: #F55; } .b41{ background-color: #B00; } .b51{ background-color: #F55 }\n"
 		".d32{ color: #0B0; } .l32{ color: #5F5; } .b42{ background-color: #0B0; } .b52{ background-color: #5F5 }\n"
 		".d32{ color: #0B0; } .l32{ color: #5F5; } .b42{ background-color: #0B0; } .b52{ background-color: #5F5 }\n"
@@ -185,7 +189,9 @@ void write_html_header(struct session *ses, FILE *fp)
 		"</head>\n"
 		"</head>\n"
 		"<pre>\n"
 		"<pre>\n"
 		"<span class='b49'><span class='d39'>\n",
 		"<span class='b49'><span class='d39'>\n",
-		HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) ? "utf-8" : HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) ? "big5" : "iso-8859-1");
+		HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) ? "utf-8" : 
+			HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) ? "big5" : 
+				HAS_BIT(ses->charset, CHARSET_FLAG_GBK1) ? "gb18030" : "iso-8859-1");
 
 
 	fputs(header, fp);
 	fputs(header, fp);
 }
 }

+ 82 - 13
src/main.c

@@ -22,6 +22,7 @@
 *                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
 *                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
 *                                                                             *
 *                                                                             *
 *                         coded by Peter Unold 1992                           *
 *                         coded by Peter Unold 1992                           *
+*                    recoded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -38,6 +39,26 @@ void pipe_handler(int signal)
 	syserr_printf(gtd->ses, "pipe_handler");
 	syserr_printf(gtd->ses, "pipe_handler");
 }
 }
 
 
+void xfsz_handler(int signal)
+{
+	syserr_printf(gtd->ses, "xfsz_handler");
+}
+
+void hub_handler(int signal)
+{
+	syserr_printf(gtd->ses, "hub_handler");
+}
+
+void ttin_handler(int signal)
+{
+	syserr_printf(gtd->ses, "ttin_handler");
+}
+
+void ttou_handler(int signal)
+{
+	syserr_printf(gtd->ses, "ttou_handler");
+}
+
 /*
 /*
 	when the screen size changes, take note of it
 	when the screen size changes, take note of it
 */
 */
@@ -69,7 +90,10 @@ void abort_handler(int signal)
 
 
 void child_handler(int signal)
 void child_handler(int signal)
 {
 {
-	// syserr_fatal(signal, "child_handler");
+	return;
+	syserr_printf(gtd->ses, "child_handler");
+
+//	syserr_fatal(signal, "child_handler");
 }
 }
 
 
 void interrupt_handler(int signal)
 void interrupt_handler(int signal)
@@ -149,10 +173,11 @@ int main(int argc, char **argv)
 		syserr_fatal(-1, "signal SIGTERM");
 		syserr_fatal(-1, "signal SIGTERM");
 	}
 	}
 
 
-	if (signal(SIGCHLD, child_handler) == BADSIG)
+/*	if (signal(SIGCHLD, child_handler) == BADSIG)
 	{
 	{
 		syserr_fatal(-1, "signal SIGCHLD");
 		syserr_fatal(-1, "signal SIGCHLD");
 	}
 	}
+*/
 /*
 /*
 	if (signal(SIGINT, interrupt_handler) == BADSIG)
 	if (signal(SIGINT, interrupt_handler) == BADSIG)
 	{
 	{
@@ -164,17 +189,39 @@ int main(int argc, char **argv)
 	{
 	{
 		syserr_fatal(-1, "signal SIGTSTP");
 		syserr_fatal(-1, "signal SIGTSTP");
 	}
 	}
-
+/*
 	if (signal(SIGPIPE, pipe_handler) == BADSIG)
 	if (signal(SIGPIPE, pipe_handler) == BADSIG)
 	{
 	{
 		syserr_fatal(-1, "signal SIGPIPE");
 		syserr_fatal(-1, "signal SIGPIPE");
 	}
 	}
 
 
+	if (signal(SIGXFSZ, xfsz_handler) == BADSIG)
+	{
+		syserr_fatal(-1, "signal SIGXFSZ");
+	}
+
+	if (signal(SIGHUP, hub_handler) == BADSIG)
+	{
+		syserr_fatal(-1, "signal SIGHUP");
+	}
+
+	if (signal(SIGTTIN, hub_handler) == BADSIG)
+	{
+		syserr_fatal(-1, "signal SIGTTIN");
+	}
+
+	if (signal(SIGTTOU, hub_handler) == BADSIG)
+	{
+		syserr_fatal(-1, "signal SIGTTOU");
+	}
+*/
 	if (signal(SIGWINCH, winch_handler) == BADSIG)
 	if (signal(SIGWINCH, winch_handler) == BADSIG)
 	{
 	{
 		syserr_fatal(-1, "signal SIGWINCH");
 		syserr_fatal(-1, "signal SIGWINCH");
 	}
 	}
 
 
+	signal(SIGPIPE, SIG_IGN);
+
 	for (c = 0 ; c < argc ; c++)
 	for (c = 0 ; c < argc ; c++)
 	{
 	{
 		if (c)
 		if (c)
@@ -188,7 +235,7 @@ int main(int argc, char **argv)
 
 
 	if (argc > 1)
 	if (argc > 1)
 	{
 	{
-		while ((c = getopt(argc, argv, "a: e: G h r: R:: s t: T v")) != EOF)
+		while ((c = getopt(argc, argv, "a: e: G h M:: r: R:: s t: T v V")) != EOF)
 		{
 		{
 			switch (c)
 			switch (c)
 			{
 			{
@@ -199,15 +246,17 @@ int main(int argc, char **argv)
 					printf("  -e  Execute given command.\n");
 					printf("  -e  Execute given command.\n");
 					printf("  -G  Don't show the greeting screen.\n");
 					printf("  -G  Don't show the greeting screen.\n");
 					printf("  -h  This help section.\n");
 					printf("  -h  This help section.\n");
+					printf("  -M  Matrix Digital Rain.\n");
 					printf("  -r  Read given file.\n");
 					printf("  -r  Read given file.\n");
 					printf("  -s  Enable screen reader mode.\n");
 					printf("  -s  Enable screen reader mode.\n");
 					printf("  -t  Set given title.\n");
 					printf("  -t  Set given title.\n");
 					printf("  -T  Don't set the default title.\n");
 					printf("  -T  Don't set the default title.\n");
 					printf("  -v  Enable verbose mode.\n");
 					printf("  -v  Enable verbose mode.\n");
+					printf("  -V  Show version information.\n");
 
 
 					exit(1);
 					exit(1);
-					break;
 
 
+				case 'M':
 				case 'G':
 				case 'G':
 					SET_BIT(greeting, STARTUP_FLAG_NOGREETING);
 					SET_BIT(greeting, STARTUP_FLAG_NOGREETING);
 					break;
 					break;
@@ -215,6 +264,12 @@ int main(int argc, char **argv)
 				case 's':
 				case 's':
 					SET_BIT(greeting, STARTUP_FLAG_SCREENREADER);
 					SET_BIT(greeting, STARTUP_FLAG_SCREENREADER);
 					break;
 					break;
+
+				case 'V':
+					printf("\nTinTin++ " CLIENT_VERSION "\n");
+					printf("\n(C) 2004-2019 Igor van den Hoven\n");
+					printf("\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\n");
+					exit(1);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -241,7 +296,7 @@ int main(int argc, char **argv)
 
 
 		RESTRING(gtd->vars[2], argv[1]);
 		RESTRING(gtd->vars[2], argv[1]);
 
 
-		while ((c = getopt(argc, argv, "a: e: G h r: R:: s t: T v")) != EOF)
+		while ((c = getopt(argc, argv, "a: e: G h M:: r: R:: s t: T v")) != EOF)
 		{
 		{
 			switch (c)
 			switch (c)
 			{
 			{
@@ -259,6 +314,10 @@ int main(int argc, char **argv)
 				case 'G':
 				case 'G':
 					break;
 					break;
 
 
+				case 'M':
+					do_test(gts, optarg ? optarg : "");
+					break;
+
 				case 'r':
 				case 'r':
 					gtd->level->input++;
 					gtd->level->input++;
 					gtd->ses = do_read(gtd->ses, optarg);
 					gtd->ses = do_read(gtd->ses, optarg);
@@ -366,7 +425,8 @@ void init_tintin(int greeting)
 
 
 	gtd->level          = (struct level_data *) calloc(1, sizeof(struct level_data));
 	gtd->level          = (struct level_data *) calloc(1, sizeof(struct level_data));
 
 
-	gtd->str_size       = sizeof(struct str_data);
+	gtd->memory         = calloc(1, sizeof(struct str_data));
+
 	gtd->buf            = str_alloc(STRING_SIZE);
 	gtd->buf            = str_alloc(STRING_SIZE);
 	gtd->out            = str_alloc(STRING_SIZE);
 	gtd->out            = str_alloc(STRING_SIZE);
 
 
@@ -448,6 +508,7 @@ void init_tintin(int greeting)
 	gts->name           = strdup("gts");
 	gts->name           = strdup("gts");
 	gts->group          = strdup("");
 	gts->group          = strdup("");
 	gts->session_host   = strdup("");
 	gts->session_host   = strdup("");
+	gts->session_ip     = strdup("");
 	gts->session_port   = strdup("");
 	gts->session_port   = strdup("");
 	gts->cmd_color      = strdup("");
 	gts->cmd_color      = strdup("");
 	gts->telopts        = TELOPT_FLAG_ECHO;
 	gts->telopts        = TELOPT_FLAG_ECHO;
@@ -467,12 +528,14 @@ void init_tintin(int greeting)
 	gts->split  = calloc(1, sizeof(struct split_data));
 	gts->split  = calloc(1, sizeof(struct split_data));
 	gts->scroll = calloc(1, sizeof(struct scroll_data));
 	gts->scroll = calloc(1, sizeof(struct scroll_data));
 
 
-	init_terminal_size(gts);
-
 	init_local(gts);
 	init_local(gts);
 
 
+	init_terminal_size(gts);
+
 	gtd->level->input++;
 	gtd->level->input++;
 
 
+	do_class(gts, "{CONFIG} {OPEN}");
+
 	do_configure(gts, "{AUTO TAB}         {5000}");
 	do_configure(gts, "{AUTO TAB}         {5000}");
 	do_configure(gts, "{BUFFER SIZE}     {10000}");
 	do_configure(gts, "{BUFFER SIZE}     {10000}");
 	do_configure(gts, "{COLOR MODE}         {ON}");
 	do_configure(gts, "{COLOR MODE}         {ON}");
@@ -499,7 +562,11 @@ void init_tintin(int greeting)
 	do_configure(gts, "{VERBOSE}           {OFF}");
 	do_configure(gts, "{VERBOSE}           {OFF}");
 	do_configure(gts, "{WORDWRAP}           {ON}");
 	do_configure(gts, "{WORDWRAP}           {ON}");
 
 
-	gtd->level->input--;
+	do_class(gts, "{CONFIG} {CLOSE}");
+
+
+
+	do_class(gts, "{PATHDIR} {OPEN}");
 
 
 	insert_node_list(gts->list[LIST_PATHDIR],  "n",  "s",  "1", "");
 	insert_node_list(gts->list[LIST_PATHDIR],  "n",  "s",  "1", "");
 	insert_node_list(gts->list[LIST_PATHDIR],  "e",  "w",  "2", "");
 	insert_node_list(gts->list[LIST_PATHDIR],  "e",  "w",  "2", "");
@@ -513,11 +580,13 @@ void init_tintin(int greeting)
 	insert_node_list(gts->list[LIST_PATHDIR], "se", "nw",  "6", "");
 	insert_node_list(gts->list[LIST_PATHDIR], "se", "nw",  "6", "");
 	insert_node_list(gts->list[LIST_PATHDIR], "sw", "ne", "12", "");
 	insert_node_list(gts->list[LIST_PATHDIR], "sw", "ne", "12", "");
 
 
+	do_class(gts, "{PATHDIR} {CLOSE}");
+
+	gtd->level->input--;
+
 	init_terminal(gts);
 	init_terminal(gts);
 
 
-	{
-		reset_screen(gts);
-	}
+	reset_screen(gts);
 
 
 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOGREETING))
 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOGREETING))
 	{
 	{

+ 6553 - 4424
src/mapper.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -38,21 +37,28 @@ int                 map_grid_y;
 
 
 extern  int dir_flags(struct session *ses, int room, int dir);
 extern  int dir_flags(struct session *ses, int room, int dir);
 extern void create_map(struct session *ses, char *arg);
 extern void create_map(struct session *ses, char *arg);
-extern  int create_room(struct session *ses, char *format, ...);
+extern struct room_data *create_room(struct session *ses, char *format, ...);
 extern void delete_room(struct session *ses, int room, int exits);
 extern void delete_room(struct session *ses, int room, int exits);
 extern struct exit_data *create_exit(struct session *ses, int room, char *format, ...);
 extern struct exit_data *create_exit(struct session *ses, int room, char *format, ...);
 extern void delete_exit(struct session *ses, int room, struct exit_data *exit);
 extern void delete_exit(struct session *ses, int room, struct exit_data *exit);
 extern void search_keywords(struct session *ses, char *arg, char *out, char *var);
 extern void search_keywords(struct session *ses, char *arg, char *out, char *var);
 extern void map_search_compile(struct session *ses, char *arg, char *var);
 extern void map_search_compile(struct session *ses, char *arg, char *var);
 extern  int match_room(struct session *ses, int room, struct search_data *search);
 extern  int match_room(struct session *ses, int room, struct search_data *search);
+extern  int find_location(struct session *ses, char *arg);
+extern  int find_path(struct session *ses, char *arg);
 extern  int find_room(struct session *ses, char *arg);
 extern  int find_room(struct session *ses, char *arg);
 extern void goto_room(struct session *ses, int room);
 extern void goto_room(struct session *ses, int room);
 extern  int find_new_room(struct session *ses);
 extern  int find_new_room(struct session *ses);
 extern struct exit_data *find_exit(struct session *ses, int room, char *arg);
 extern struct exit_data *find_exit(struct session *ses, int room, char *arg);
 extern  int get_exit_dir(struct session *ses, char *arg);
 extern  int get_exit_dir(struct session *ses, char *arg);
-extern  int get_exit_grid(struct session *ses, int dir);
+extern  int get_exit_length(struct session *ses, struct exit_data *exit);
+extern char *get_exit_color(struct session *ses, int room, struct exit_data *exit);
+extern  int dir_to_grid(int dir);
+extern  int revdir_to_grid(int dir);
 extern void set_room_exits(struct session *ses, int room);
 extern void set_room_exits(struct session *ses, int room);
 extern  int get_room_exits(struct session *ses, int room);
 extern  int get_room_exits(struct session *ses, int room);
+extern  int get_terrain_index(struct session *ses, struct room_data *room, int x, int y);
+extern char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line, int col, int x, int y, int flags);
 extern void displaygrid_build(struct session *ses, int room, int x, int y, int z);
 extern void displaygrid_build(struct session *ses, int room, int x, int y, int z);
 extern void add_undo(struct session *ses, char *format, ...);
 extern void add_undo(struct session *ses, char *format, ...);
 extern void del_undo(struct session *ses, struct link_data *link);
 extern void del_undo(struct session *ses, struct link_data *link);
@@ -65,55 +71,31 @@ extern  int tunnel_void(struct session *ses, int from, int room, int dir);
 extern  int check_global(struct session *ses, int room);
 extern  int check_global(struct session *ses, int room);
 extern  int find_coord(struct session *ses, char *arg);
 extern  int find_coord(struct session *ses, char *arg);
 extern  int spatialgrid_find(struct session *ses, int vnum, int x, int y, int z);
 extern  int spatialgrid_find(struct session *ses, int vnum, int x, int y, int z);
+extern void update_terrain(struct session *ses);
 
 
 DO_COMMAND(do_map)
 DO_COMMAND(do_map)
 {
 {
 	int cnt;
 	int cnt;
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 
 
+	push_call("do_map(%p,%p)",ses,arg);
+
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 
 
 	if (*arg1 == 0)
 	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> <z>              (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 global   <room vnum>              (sets the global exit room)");
-		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> <filename>      (shows an ascii map)");
-		tintin_printf2(ses, "#map move     <direction>              (move to given direction)");
-		tintin_printf2(ses, "#map offset   <square>                 (place vtmap in given square)");
-		tintin_printf2(ses, "#map read     <filename>               (load a map from 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 vnum     <low vnum> [high vnum]   (change room vnum)");
-		tintin_printf2(ses, "#map write    <filename>               (save the map)");
+		tintin_header(ses, " MAP OPTIONS ");
+
+		for (cnt = 0 ; *map_table[cnt].fun != NULL ; cnt++)
+		{
+			if (*map_table[cnt].desc)
+			{
+				tintin_printf2(ses, "  [%-13s] %s", map_table[cnt].name, map_table[cnt].desc);
+			}
+		}
+		tintin_header(ses, "");
 
 
+		pop_call();
 		return ses;
 		return ses;
 	}
 	}
 	else
 	else
@@ -126,15 +108,18 @@ DO_COMMAND(do_map)
 				{
 				{
 					show_error(ses, LIST_COMMAND, "#MAP: This session has no map data. Use #map create or #map read to create one.");
 					show_error(ses, LIST_COMMAND, "#MAP: This session has no map data. Use #map create or #map read to create one.");
 					
 					
+					pop_call();
 					return ses;
 					return ses;
 				}
 				}
 				if (map_table[cnt].check > 1 && ses->map->room_list[ses->map->in_room] == NULL)
 				if (map_table[cnt].check > 1 && ses->map->room_list[ses->map->in_room] == NULL)
 				{
 				{
 					show_error(ses, LIST_COMMAND, "#MAP: You are not inside the map. Use #map goto to enter it.");
 					show_error(ses, LIST_COMMAND, "#MAP: You are not inside the map. Use #map goto to enter it.");
 
 
+					pop_call();
 					return ses;
 					return ses;
 				}
 				}
-				*arg1 = *arg2 = 0;
+				*arg1 = 0;
+				*arg2 = 0;
 
 
 				if (gtd->level->ignore == 0)
 				if (gtd->level->ignore == 0)
 				{
 				{
@@ -143,5904 +128,8048 @@ DO_COMMAND(do_map)
 						SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 						SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 					}
 					}
 				}
 				}
+				pop_call();
 
 
-				map_table[cnt].map (ses, arg, arg1, arg2);
+				push_call("MAP_%s(%p,%p,%p,%p,%p)",map_table[cnt].name,ses,arg,arg1,arg2);
 
 
+				map_table[cnt].fun (ses, arg, arg1, arg2);
+
+				pop_call();
 				return ses;
 				return ses;
 			}
 			}
 		}
 		}
 
 
 		do_map(ses, "");
 		do_map(ses, "");
 	}
 	}
+	pop_call();
 	return ses;
 	return ses;
 }
 }
 
 
-DO_MAP(map_at)
-{
-	struct exit_data *exit;
-	int new_room;
+/*
+	Utility functions
+*/
 
 
-	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);
+void create_map(struct session *ses, char *arg)
+{
+	int group, legend;
 
 
-	new_room = find_room(ses, arg1);
+	push_call("create_map(%p,%p)",ses,arg);
 
 
-	if (new_room == 0)
+	if (ses->map)
 	{
 	{
-		exit = find_exit(ses, ses->map->in_room, arg1);
-
-		if (exit == NULL)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP AT: Couldn't find room or exit {%s}.", arg1);
-
-			return;
-		}
-		new_room = exit->vnum;
+		delete_map(ses);
 	}
 	}
 
 
-	ses->map->at_room = ses->map->in_room;
-	ses->map->in_room = new_room;
-
-	script_driver(ses, LIST_COMMAND, arg2);
+	ses->map = (struct map_data *) calloc(1, sizeof(struct map_data));
+	ses->map->size = atoi(arg) > 0 ? atoi(arg) : 50000;
 
 
-	if (ses->map)
-	{
-		ses->map->in_room = ses->map->at_room;
-	}
-}
+	ses->map->room_list = (struct room_data **) calloc(ses->map->size, sizeof(struct room_data *));
 
 
-DO_MAP(map_center)
-{
-	char arg3[BUFFER_SIZE];
+	ses->map->max_grid_x = 255;
+	ses->map->max_grid_y = 101;
 
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	ses->map->grid_rooms = (struct room_data **) calloc(ses->map->max_grid_x * ses->map->max_grid_y, sizeof(struct room_data *));
 
 
-	if (*arg1 == 0)
-	{
-		ses->map->center_x = ses->map->center_y = ses->map->center_z = 0;
-	}
-	else
-	{
-		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);
+	ses->map->search = calloc(1, sizeof(struct search_data));
 
 
-		if (!is_math(ses, arg1) || !is_math(ses, arg2) || !is_math(ses, arg3))
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP CENTER {X} {Y} {Z}");
+	ses->map->flags = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_DIRECTION|MAP_FLAG_TERRAIN;
 
 
-			return;
-		}
-		else
-		{
-			ses->map->center_x = get_number(ses, arg1);
-			ses->map->center_y = get_number(ses, arg2);
-			ses->map->center_z = get_number(ses, arg3);
+	ses->map->global_exit         = (struct exit_data *) calloc(1, sizeof(struct exit_data));
+		ses->map->global_exit->vnum   = ses->map->global_vnum;
+		ses->map->global_exit->name   = restringf(ses->map->global_exit->name, "%cnop global", gtd->tintin_char);
+		ses->map->global_exit->cmd    = restringf(ses->map->global_exit->cmd, "%cnop global", gtd->tintin_char);
+		ses->map->global_exit->data   = strdup("");
+		ses->map->global_exit->weight = 1;
+		ses->map->global_exit->color  = strdup("");
 
 
-			show_message(ses, LIST_COMMAND, "#MAP CENTER SET TO {%d} {%d} {%d}", ses->map->center_x, ses->map->center_y, ses->map->center_z);
-		}
-	}
-}
+	do_map(ses, "{COLOR} {RESET}");
 
 
-DO_MAP(map_color)
-{
-	char buf[BUFFER_SIZE];
-	int index;
+	ses->map->display_stamp = 1;
+	ses->map->search->stamp = 1;
 
 
-	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);
+	do_map(ses, "TERRAIN {} { }");
+/*
+	do_map(ses, "TERRAIN BEACH        <eea>~");
+	do_map(ses, "TERRAIN CITY         <ebf>-");
+	do_map(ses, "TERRAIN DESERT       <ffa>.");
+	do_map(ses, "TERRAIN FIELD        <228>.");
+	do_map(ses, "TERRAIN FOREST       <128>^");
+	do_map(ses, "TERRAIN HILL         <ddd>^");
+	do_map(ses, "TERRAIN LAKE         <248>~");
+	do_map(ses, "TERRAIN MOUNTAIN     <acf>^");
+	do_map(ses, "TERRAIN OCEAN        <148>@");
+	do_map(ses, "TERRAIN SWAMP        <bda>.");
+	do_map(ses, "TERRAIN UNDERGROUND  <baa>-");
+*/
 
 
-	if (*arg1)
-	{
-		if (!strcasecmp(arg1, "RESET"))
-		{
-			for (index = 0 ; map_color_table[index].name ; index++)
-			{
-				strncpy(ses->map->color[index], map_color_table[index].code, COLOR_SIZE - 1);
-			}
+	create_room(ses, "%s", "{1} {0} {} {} { } {} {} {} {} {} {1.0} {}");
 
 
-			return;
-		}
+	strcpy(arg, "");
 
 
-		for (index = 0 ; map_color_table[index].name ; index++)
+	for (group = 0 ; map_group_table[group].name ; group++)
+	{
+		for (legend = 0 ; map_legend_table[legend].group ; legend++)
 		{
 		{
-			if (is_abbrev(arg1, map_color_table[index].name))
+			if (*map_group_table[group].group == 0 || is_abbrev(map_group_table[group].group, map_legend_table[legend].group))
 			{
 			{
-				if (is_abbrev(arg2, "RESET"))
-				{
-					strncpy(ses->map->color[index], map_color_table[index].code, COLOR_SIZE - 1);
-				}
-				else
-				{
-					strncpy(ses->map->color[index], arg2, COLOR_SIZE - 1);
-				}
-				get_color_names(ses, ses->map->color[index], buf);
-
-				show_message(ses, LIST_COMMAND, "#MAP COLOR %s%10s\e[0m SET TO {%s}", buf, map_color_table[index].name, ses->map->color[index]);
-
 				break;
 				break;
 			}
 			}
 		}
 		}
 
 
-		if (map_color_table[index].name == NULL)
+		if (map_legend_table[legend].group)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP COLOR {AVOID|BACKGROUND|EXIT|HIDE|INVIS|PATH|ROOM|USER} {COLOR CODE}");
-
-			return;
+			map_group_table[group].start = legend;
 		}
 		}
-		show_message(ses, LIST_COMMAND, "#MAP: %s color set to: %s", arg1, arg2);
-	}
-	else
-	{
-		for (index = 0 ; map_color_table[index].name ; index++)
+		else
 		{
 		{
-			get_color_names(ses, ses->map->color[index], buf);
+			show_error(ses, LIST_COMMAND, "create_map: unknown legend group: %s, %s", map_group_table[group].name, map_group_table[group].group);
 
 
-			show_message(ses, LIST_COMMAND, "#MAP COLOR %s%10s\e[0m SET TO {%s}", buf, map_color_table[index].name, ses->map->color[index]);
+			continue;
 		}
 		}
-	}
-}
-
-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_debug)
-{
-	tintin_printf2(ses, "max spatial grid x: %d", ses->map->max_grid_x);
-	tintin_printf2(ses, "max spatial grid y: %d", ses->map->max_grid_y);
-	tintin_printf2(ses, "     max undo size: %d", ses->map->undo_size);
-	tintin_printf2(ses, "           in room: %d", ses->map->in_room);
-	tintin_printf2(ses, "           at room: %d", ses->map->at_room);
-	tintin_printf2(ses, "         last room: %d", ses->map->last_room);
-	tintin_printf2(ses, "             stamp: %d", ses->map->search->stamp);
-	tintin_printf2(ses, "            length: %f", ses->map->room_list[ses->map->in_room]->length);
-	tintin_printf2(ses, "          nofollow: %d", ses->map->nofollow);
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-	if (*arg1)
-	{
-		if (is_abbrev(arg1, "undo"))
+		while (map_legend_table[++legend].group)
 		{
 		{
-			struct link_data *link;
-
-			for (link = ses->map->undo_head ; link ; link = link->next)
+			if (*map_group_table[group].group && !is_abbrev(map_group_table[group].group, map_legend_table[legend].group))
 			{
 			{
-				tintin_printf2(ses, "%05s %05s %s", link->str1, link->str2, link->str3);
+				break;
 			}
 			}
 		}
 		}
+		map_group_table[group].end = legend;
 	}
 	}
+
+	gtd->level->quiet++;
+	do_map(ses, "LEGEND RESET");
+	gtd->level->quiet--;
+
+	pop_call();
+	return;
 }
 }
 
 
-DO_MAP(map_delete)
+int delete_map(struct session *ses)
 {
 {
-	int room;
-	struct exit_data *exit;
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+	int index, cnt;
 
 
-	if (is_number(arg1))
+	for (index = cnt = 0 ; index < ses->map->size ; index++)
 	{
 	{
-		room = find_room(ses, arg1);
-
-		if (room == 0)
+		if (ses->map->room_list[index])
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#MAP DELETE {%s} - No room with that vnum found", arg1);
+			cnt++;
 
 
-			return;
+			delete_room(ses, index, FALSE);
 		}
 		}
 	}
 	}
-	else
-	{
-		exit = find_exit(ses, ses->map->in_room, arg1);
+	free(ses->map->room_list);
 
 
-		if (exit)
-		{
-			room = exit->vnum;
-		}
+	while (ses->map->undo_head)
+	{
+		del_undo(ses, ses->map->undo_head);
+	}
 
 
-		if (exit == NULL)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP: No exit with that name found");
-			
-			return;
-		}
+	free(ses->map->global_exit->name);
+	free(ses->map->global_exit->cmd);
+	free(ses->map->global_exit->data);
+	free(ses->map->global_exit);
 
 
-		room = exit->vnum;
-	}
+	free(ses->map);
 
 
-	if (room == ses->map->in_room)
-	{
-		show_error(ses, LIST_COMMAND, "#MAP: You must first leave the room you're trying to delete");
-		
-		return;
-	}
+	ses->map = NULL;
 
 
-	delete_room(ses, room, TRUE);
+	kill_list(ses->list[LIST_LANDMARK]);
+	kill_list(ses->list[LIST_TERRAIN]);
 
 
-	show_message(ses, LIST_COMMAND, "#MAP: Room {%d} deleted", room);
+	return cnt;
 }
 }
 
 
-DO_MAP(map_destroy)
+struct room_data *create_room(struct session *ses, char *format, ...)
 {
 {
-	struct exit_data *exit;
-	int index, cnt;
+	char *arg, buf[BUFFER_SIZE];
+	struct room_data *newroom;
+	va_list args;
 
 
-	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);
+	va_start(args, format);
+	vsprintf(buf, format, args);
+	va_end(args);
 
 
-	if (is_abbrev(arg1, "AREA"))
-	{
-		if (*arg2 == 0)
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP DESTROY AREA {<AREA NAME>}");
+	newroom = (struct room_data *) calloc(1, sizeof(struct room_data));
 
 
-			return;
-		}
+	arg = buf;
 
 
-		if (ses->map->room_list[ses->map->in_room] && !strcmp(arg2, ses->map->room_list[ses->map->in_room]->area))
-		{
-			show_error(ses, LIST_COMMAND, "#MAP DESTROY AREA: YOU MUST FIRST LEAVE THE AREA YOU ARE TRYING TO DESTROY.");
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->vnum    = atoi(buf);
 
 
-			return;
-		}
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_SYNC) && ses->map->room_list[newroom->vnum] != NULL)
+	{
+		int vnum = newroom->vnum;
 
 
-		for (index = cnt = 0 ; index < ses->map->size ; index++)
-		{
-			if (ses->map->room_list[index])
-			{
-				if (!strcmp(arg2, ses->map->room_list[index]->area))
-				{
-					cnt++;
+		free(newroom);
 
 
-					delete_room(ses, index, FALSE);
-				}
-			}
-		}
+		return ses->map->room_list[vnum];
+	}
 
 
-		for (index = 0 ; index < ses->map->size ; index++)
-		{
-			if (ses->map->room_list[index])
-			{
-				for (exit = ses->map->room_list[index]->f_exit ; exit ; exit = exit->next)
-				{
-					if (ses->map->room_list[exit->vnum] == NULL)
-					{
-						delete_exit(ses, index, exit);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->flags   = atoi(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->color   = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->name    = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->symbol  = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->desc    = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->area    = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->note    = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->terrain = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->data    = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->weight  = atof(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->id      = strdup(buf);
 
 
-						if (ses->map->room_list[index]->f_exit)
-						{
-							exit = ses->map->room_list[index]->f_exit;
-						}
-						else
-						{
-							break;
-						}
-					}
-				}
-			}
-		}
-		show_message(ses, LIST_COMMAND, "#MAP DESTROY AREA: DELETED %d ROOMS.", cnt);
+	if (HAS_BIT(newroom->flags, ROOM_FLAG_AVOID))
+	{
+		SET_BIT(newroom->flags, ROOM_FLAG_AVOID_TMP);
 	}
 	}
-	else if (is_abbrev(arg1, "WORLD"))
+	if (HAS_BIT(newroom->flags, ROOM_FLAG_HIDE))
 	{
 	{
-		cnt = delete_map(ses);
+		SET_BIT(newroom->flags, ROOM_FLAG_HIDE_TMP);
+	}
+	if (HAS_BIT(newroom->flags, ROOM_FLAG_LEAVE))
+	{
+		SET_BIT(newroom->flags, ROOM_FLAG_LEAVE_TMP);
+	}
+	if (HAS_BIT(newroom->flags, ROOM_FLAG_VOID))
+	{
+		SET_BIT(newroom->flags, ROOM_FLAG_VOID_TMP);
+	}
+	if (HAS_BIT(newroom->flags, ROOM_FLAG_CURVED))
+	{
+		SET_BIT(newroom->flags, ROOM_FLAG_CURVED_TMP);
+	}
 
 
-		tintin_printf2(ses, "#MAP DESTROY WORLD: DELETED %d ROOMS.", cnt);
+	if (newroom->weight <= 0)
+	{
+		newroom->weight = 1;
 	}
 	}
-	else
+
+	if (newroom->vnum)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP DESTROY {AREA|WORLD} {<ARGUMENT>}");
+		ses->map->room_list[newroom->vnum] = newroom;
 	}
 	}
+
+	show_message(ses, LIST_COMMAND, "#MAP CREATE ROOM %5d {%s}.", newroom->vnum, newroom->name);
+
+	return newroom;
 }
 }
 
 
-DO_MAP(map_dig)
+void delete_room(struct session *ses, int room, int exits)
 {
 {
-	char arg3[BUFFER_SIZE];
-	int room;
-	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);
-	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
+	struct exit_data *exit, *exit_next;
+	int cnt;
 
 
-	if (*arg1 == 0)
+	while (ses->map->room_list[room]->f_exit)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP DIG {<DIRECTION>|<VNUM>} {<LOCATION>|NEW}");
-		
-		return;
+		delete_exit(ses, room, ses->map->room_list[room]->f_exit);
 	}
 	}
 
 
-	room = atoi(arg1);
+	free(ses->map->room_list[room]->area);
+	free(ses->map->room_list[room]->color);
+	free(ses->map->room_list[room]->id);
+	free(ses->map->room_list[room]->name);
+	free(ses->map->room_list[room]->symbol);
+	free(ses->map->room_list[room]->desc);
+	free(ses->map->room_list[room]->note);
+	free(ses->map->room_list[room]->terrain);
+	free(ses->map->room_list[room]->data); 
 
 
-	if (room > 0 && room < ses->map->size)
+	free(ses->map->room_list[room]);
+
+	ses->map->room_list[room] = NULL;
+
+	if (exits)
 	{
 	{
-		if (ses->map->room_list[room] == NULL)
+		for (cnt = 0 ; cnt < ses->map->size ; cnt++)
 		{
 		{
-			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE);
+			if (ses->map->room_list[cnt])
+			{
+				for (exit = ses->map->room_list[cnt]->f_exit ; exit ; exit = exit_next)
+				{
+					exit_next = exit->next;
 
 
-			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
+					if (exit->vnum == room)
+					{
+						delete_exit(ses, cnt, exit);
+					}
+				}
+			}
 		}
 		}
-		return;
 	}
 	}
 
 
-	exit = find_exit(ses, ses->map->in_room, arg1);
+}
 
 
-	if (exit)
-	{
-		show_message(ses, LIST_COMMAND, "#MAP DIG: There is already a room in that direction.");
-		return;
-	}
+struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
+{
+	struct exit_data *newexit;
+	struct room_data *room;
+	va_list args;
+	char *arg, buf[BUFFER_SIZE];
 
 
-	if (*arg2 && strcasecmp(arg2, "new"))
-	{
-		if (is_number(arg2))
-		{
-			room = get_number(ses, arg2);
-		}
-		else
-		{
-			room = find_room(ses, arg2);
-		}
+	push_call("create_exit(%p,%d,%p)",ses,vnum,format);
 
 
-		if (room == 0 && !strcasecmp(arg3, "new"))
-		{
-			room = find_new_room(ses);
-		}
+	va_start(args, format);
+	vsprintf(buf, format, args);
+	va_end(args);
 
 
-		if (room <= 0 || room >= ses->map->size)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP DIG {%s}: Couldn't find room {%s}.", arg1, arg2);
+	newexit = (struct exit_data *) calloc(1, sizeof(struct exit_data));
 
 
-			return;
-		}
+	room = ses->map->room_list[vnum];
 
 
-		if (ses->map->room_list[room] == NULL)
-		{
-			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE|MAP_UNDO_LINK);
+	arg = buf;
 
 
-			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {%s}", room, ses->map->search->id ? ses->map->search->id : "");
-			create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
-		}
-		else
-		{
-			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_LINK);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->vnum   = atoi(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);
 
 
-			create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
-		}
-		return;
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_SYNC) && find_exit(ses, vnum, buf))
+	{
+		free(newexit);
+
+		return find_exit(ses, vnum, buf);
 	}
 	}
+	newexit->name = strdup(buf);
 
 
-	room = find_coord(ses, arg1);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ALL);	newexit->cmd    = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->dir    = atoi(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->flags  = atoi(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ALL);	newexit->data   = strdup(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->weight = atof(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);        newexit->color  = strdup(buf);
 
 
-	if (room && strcasecmp(arg2, "new"))
+	if (newexit->dir == 0)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#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);
-
-		create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+		newexit->dir = get_exit_dir(ses, newexit->name);
 	}
 	}
-	else
-	{
-		for (room = 1 ; room < ses->map->size ; room++)
-		{
-			if (ses->map->room_list[room] == NULL)
-			{
-				break;
-			}
-		}
 
 
-		if (room == ses->map->size)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP DIG: Maximum amount of rooms of %d reached.", ses->map->size);
-			
-			return;
-		}
-		add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE|MAP_UNDO_LINK);
+	newexit->grid = dir_to_grid(newexit->dir);
 
 
-		create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
-		create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+	if (room->exit_grid[newexit->grid] == NULL)
+	{
+		room->exit_grid[newexit->grid] = newexit;
 	}
 	}
 
 
-	if ((node = search_node_list(ses->list[LIST_PATHDIR], arg1)) != NULL)
+	if (newexit->weight <= 0)
 	{
 	{
-		if (find_exit(ses, room, node->arg2) == NULL)
-		{
-			create_exit(ses, room, "{%d} {%s} {%s}", ses->map->in_room, node->arg2, node->arg2);
-		}
+		newexit->weight = 1;
 	}
 	}
+
+	LINK(newexit, room->f_exit, room->l_exit);
+
+	room->exit_size++;
+
+	SET_BIT(room->exit_dirs, (1LL << newexit->dir));
+
+	show_message(ses, LIST_COMMAND, "#MAP CREATE EXIT {%s} {%s} TO ROOM %d.", newexit->name, newexit->cmd, newexit->vnum);
+
+	pop_call();
+	return newexit;
 }
 }
 
 
-DO_MAP(map_exit)
+void delete_exit(struct session *ses, int room, struct exit_data *exit)
 {
 {
-	char arg3[BUFFER_SIZE];
-	struct exit_data *exit;
-	int room, dir;
+	free(exit->name);
+	free(exit->cmd);
+	free(exit->data);
+	free(exit->color);
 
 
-	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);
+	UNLINK(exit, ses->map->room_list[room]->f_exit, ses->map->room_list[room]->l_exit)
 
 
-	exit = find_exit(ses, ses->map->in_room, arg1);
+	set_room_exits(ses, room);
 
 
-	if (exit == NULL)
-	{
-		show_error(ses, LIST_COMMAND, "#MAP: Exit {%s} not found.", arg1);
-		
-		return;
-	}
+	free(exit);
+}
 
 
-	if (*arg2 == 0)
+int get_exit_dir(struct session *ses, char *arg)
+{
+	struct listnode *node;
+
+	node = search_node_list(ses->list[LIST_PATHDIR], arg);
+
+	if (node)
 	{
 	{
-		tintin_printf2(ses, "  command: %s", exit->cmd);
-		tintin_printf2(ses, "direction: %d", exit->dir);
-		tintin_printf2(ses, "    flags: %d", exit->flags);
-		tintin_printf2(ses, "  get/set: %s", exit->data);
-		tintin_printf2(ses, "     name: %s", exit->name);
-		tintin_printf2(ses, "     vnum: %d", exit->vnum);
-		tintin_printf2(ses, "   weight: %.3f", exit->weight);
+		return atoi(node->arg3);
 	}
 	}
-	else if (is_abbrev(arg2, "COMMAND"))
+	else
 	{
 	{
-		RESTRING(exit->cmd, arg3);
-
-		show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : COMMAND SET TO {%s}.", arg1, exit->cmd);
+		return 0;
 	}
 	}
-	else if (is_abbrev(arg2, "DIRECTION"))
+}
+
+int get_exit_length(struct session *ses, struct exit_data *exit)
+{
+	return (int) exit->weight + ses->map->room_list[exit->vnum]->length;
+}
+
+char *get_exit_color(struct session *ses, int room, struct exit_data *exit)
+{
+	push_call("get_exit_color(%p,%d,%p)",ses,room,exit);
+
+	if (exit)
 	{
 	{
-		if (is_math(ses, arg3))
-		{
-			dir = (int) get_number(ses, arg3);
-		}
-		else if ((dir = get_exit_dir(ses, arg3)) == 0)
+		if (*exit->color)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#MAP EXIT {%s} : DIRECTION {%s} NOT FOUND.", arg1, arg3);
-			
-			return;
+			pop_call();
+			return exit->color;
 		}
 		}
 
 
-		exit->dir = dir;
-
-		set_room_exits(ses, ses->map->in_room);
+		if (room)
+		{
+			struct exit_data *rev_exit = ses->map->room_list[exit->vnum]->exit_grid[revdir_to_grid(exit->dir)];
 
 
-		show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : DIRECTION {%s} SET TO {%d}.", arg1, arg3, dir);
-	}
-	else if (is_abbrev(arg2, "FLAGS"))
-	{
-		exit->flags = (int) get_number(ses, arg3);
+			if (rev_exit && rev_exit->vnum == room)
+			{
+				if (ses->map->room_list[exit->vnum]->length < ses->map->room_list[rev_exit->vnum]->length)
+				{
+					exit = rev_exit;
+				}
+			}
+		}
 
 
-		show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : FLAGS SET TO {%d}.", arg1, exit->flags);
-	}
-	else if (is_abbrev(arg2, "GET"))
-	{
-		if (*arg3)
+		if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID) && *ses->map->color[MAP_COLOR_AVOID])
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg3, "%s", exit->data);
+			pop_call();
+			return ses->map->color[MAP_COLOR_AVOID];
 		}
 		}
-		else
+		if (HAS_BIT(exit->flags, EXIT_FLAG_BLOCK) && *ses->map->color[MAP_COLOR_BLOCK])
 		{
 		{
-			tintin_printf2(ses, "#MAP EXIT GET: No destination variable.");
+			pop_call();
+			return ses->map->color[MAP_COLOR_BLOCK];
 		}
 		}
-	}
-	else if (is_abbrev(arg2, "NAME"))
-	{
-		RESTRING(exit->name, arg3);
-
-		show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : NAME SET TO {%s}.", arg1, exit->name);
-	}
-	else if (is_abbrev(arg2, "SAVE"))
-	{
-		if (*arg3)
+		if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) && *ses->map->color[MAP_COLOR_HIDE])
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg3, "{command}{%s}{destination}{%d}{dir}{%d}{flags}{%d}{name}{%s}{vnum}{%d}{weight}{%.3f}", exit->cmd, tunnel_void(ses, ses->map->in_room, exit->vnum, exit->dir), exit->dir, exit->flags, exit->name, exit->vnum, exit->weight);
+			pop_call();
+			return ses->map->color[MAP_COLOR_HIDE];
 		}
 		}
-		else
+		if (HAS_BIT(exit->flags, EXIT_FLAG_INVIS) && *ses->map->color[MAP_COLOR_INVIS])
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#MAP EXIT SAVE: No destination variable.");
+			pop_call();
+			return ses->map->color[MAP_COLOR_INVIS];
 		}
 		}
+		pop_call();
+		return ses->map->color[MAP_COLOR_EXIT];
 	}
 	}
-	else if (is_abbrev(arg2, "SET"))
+	else
 	{
 	{
-		RESTRING(exit->data, arg3);
+		pop_call();
+		return "";
+	}
+}
 
 
-		show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : DATA SET TO {%s}.", arg1, exit->data);
+int revdir_to_grid(int dir)
+{
+	switch (dir)
+	{
+		case 0:
+			return EXIT_GRID_0;
+		case MAP_EXIT_N:
+			return EXIT_GRID_S;
+		case MAP_EXIT_E:
+			return EXIT_GRID_W;
+		case MAP_EXIT_S:
+			return EXIT_GRID_N;
+		case MAP_EXIT_W:
+			return EXIT_GRID_E;
+		case MAP_EXIT_N|MAP_EXIT_E:
+			return EXIT_GRID_SW;
+		case MAP_EXIT_N|MAP_EXIT_W:
+			return EXIT_GRID_SE;
+		case MAP_EXIT_S|MAP_EXIT_E:
+			return EXIT_GRID_NW;
+		case MAP_EXIT_S|MAP_EXIT_W:
+			return EXIT_GRID_NE;
 	}
 	}
-	else if (is_abbrev(arg2, "VNUM"))
+
+	if (HAS_BIT(dir, MAP_EXIT_D))
 	{
 	{
-		room = atoi(arg3);
+		return EXIT_GRID_U;
+	}
 
 
-		if (room <= 0 || room >= ses->map->size)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP EXIT VNUM: Invalid room vnum: %d.", room);
-			return;
-		}
+	if (HAS_BIT(dir, MAP_EXIT_U))
+	{
+		return EXIT_GRID_D;
+	}
 
 
-		if (ses->map->room_list[room] == NULL)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP EXIT VNUM: Non existant room vnum: %d.", room);
-			return;
-		}
-		exit->vnum = room;
+	return EXIT_GRID_0;
+}
 
 
-		show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : VNUM SET TO {%s}.", arg1, arg3);
-	}
-	else if (is_abbrev(arg2, "WEIGHT"))
+int dir_to_grid(int dir)
+{
+	switch (dir)
 	{
 	{
-		if (get_number(ses, arg3) < 0.001)
-		{
-			show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : WEIGHT SHOULD BE AT LEAST 0.001", arg1);
-		}
-		else
-		{
-			exit->weight = (float) get_number(ses, arg3);
+		case 0:
+			return EXIT_GRID_0;
+		case MAP_EXIT_N:
+			return EXIT_GRID_N;
+		case MAP_EXIT_E:
+			return EXIT_GRID_E;
+		case MAP_EXIT_S:
+			return EXIT_GRID_S;
+		case MAP_EXIT_W:
+			return EXIT_GRID_W;
+		case MAP_EXIT_N|MAP_EXIT_E:
+			return EXIT_GRID_NE;
+		case MAP_EXIT_N|MAP_EXIT_W:
+			return EXIT_GRID_NW;
+		case MAP_EXIT_S|MAP_EXIT_E:
+			return EXIT_GRID_SE;
+		case MAP_EXIT_S|MAP_EXIT_W:
+			return EXIT_GRID_SW;
+	}
 
 
-			show_message(ses, LIST_COMMAND, "#MAP EXIT {%s} : WEIGHT SET TO {%.3f}", arg1, exit->weight);
-		}
+	if (HAS_BIT(dir, MAP_EXIT_D))
+	{
+		return EXIT_GRID_D;
 	}
 	}
-	else
+
+	if (HAS_BIT(dir, MAP_EXIT_U))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "Syntax: #MAP EXIT {<NAME>} {COMMAND|DIRECTION|GET|NAME|FLAGS|SAVE|SET|VNUM|WEIGHT} {<argument>}");
+		return EXIT_GRID_U;
 	}
 	}
+
+	return EXIT_GRID_0;
 }
 }
 
 
-DO_MAP(map_exitflag)
+int get_room_exits(struct session *ses, int room)
+{
+	return ses->map->room_list[room]->exit_size;
+}
+
+void set_room_exits(struct session *ses, int vnum)
 {
 {
 	struct exit_data *exit;
 	struct exit_data *exit;
-	char arg3[BUFFER_SIZE];
-	int flag;
+	struct room_data *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);
+	room = ses->map->room_list[vnum];
 
 
-	exit = find_exit(ses, ses->map->in_room, arg1);
+	room->exit_dirs = 0;
+	room->exit_size = 0;
 
 
-	if (exit == NULL)
+	memset(room->exit_grid, 0, sizeof(room->exit_grid));
+
+	for (exit = room->f_exit ; exit ; exit = exit->next)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP EXITFLAG: EXIT {%s} NOT FOUND.", arg1);
+		SET_BIT(room->exit_dirs, 1LL << exit->dir);
 
 
-		return;
+		if (room->exit_grid[exit->grid] == NULL)
+		{
+			room->exit_grid[exit->grid] = exit;
+		}
+		room->exit_size++;
 	}
 	}
+}
 
 
-	if (*arg2 == 0)
-	{
-		tintin_printf2(ses, "#MAP: AVOID FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_AVOID) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: HIDE FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_HIDE) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: INVIS FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_INVIS) ? "ON" : "OFF");
+int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
+{
+	struct listroot *root = ses->list[LIST_TERRAIN];
+	struct room_data *wide_grid[11], *vast_grid[11];
+	int terrain;
 
 
-		return;
+	if (room)
+	{
+		return room->terrain_index;
 	}
 	}
 
 
-	if (is_abbrev(arg2, "AVOID"))
+	wide_grid[EXIT_GRID_N]  = ses->map->grid_rooms[x     + map_grid_x * (y + 1)];
+	wide_grid[EXIT_GRID_NE] = ses->map->grid_rooms[x + 1 + map_grid_x * (y + 1)];
+	wide_grid[EXIT_GRID_E]  = ses->map->grid_rooms[x + 1 + map_grid_x * (y    )];
+	wide_grid[EXIT_GRID_SE] = ses->map->grid_rooms[x + 1 + map_grid_x * (y - 1)];
+	wide_grid[EXIT_GRID_S]  = ses->map->grid_rooms[x     + map_grid_x * (y - 1)];
+	wide_grid[EXIT_GRID_SW] = ses->map->grid_rooms[x - 1 + map_grid_x * (y - 1)];
+	wide_grid[EXIT_GRID_W]  = ses->map->grid_rooms[x - 1 + map_grid_x * (y    )];
+	wide_grid[EXIT_GRID_NW]	= ses->map->grid_rooms[x - 1 + map_grid_x * (y + 1)];
+
+	if (wide_grid[EXIT_GRID_N] && wide_grid[EXIT_GRID_N]->terrain_index != -1 && wide_grid[EXIT_GRID_N]->vnum && HAS_BIT(root->list[wide_grid[EXIT_GRID_N]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_WIDE))
 	{
 	{
-		flag = EXIT_FLAG_AVOID;
+		terrain = wide_grid[EXIT_GRID_N]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain))
+		{
+			return wide_grid[EXIT_GRID_N]->terrain_index;
+		}
 	}
 	}
-	else if (is_abbrev(arg2, "HIDE"))
+
+	if (wide_grid[EXIT_GRID_E] && wide_grid[EXIT_GRID_E]->terrain_index != -1 && wide_grid[EXIT_GRID_E]->vnum && HAS_BIT(root->list[wide_grid[EXIT_GRID_E]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_WIDE))
 	{
 	{
-		flag = EXIT_FLAG_HIDE;
+		terrain = wide_grid[EXIT_GRID_E]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain))
+		{
+			return wide_grid[EXIT_GRID_E]->terrain_index;
+		}
 	}
 	}
-	else if (is_abbrev(arg2, "INVISIBLE"))
+
+	if (wide_grid[EXIT_GRID_S] && wide_grid[EXIT_GRID_S]->terrain_index != -1 && wide_grid[EXIT_GRID_S]->vnum && HAS_BIT(root->list[wide_grid[EXIT_GRID_S]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_WIDE))
 	{
 	{
-		flag = EXIT_FLAG_INVIS;
+		terrain = wide_grid[EXIT_GRID_S]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain))
+		{
+			return wide_grid[EXIT_GRID_S]->terrain_index;
+		}
 	}
 	}
-	else
+
+	if (wide_grid[EXIT_GRID_W] && wide_grid[EXIT_GRID_W]->terrain_index != -1 && wide_grid[EXIT_GRID_W]->vnum && HAS_BIT(root->list[wide_grid[EXIT_GRID_W]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_WIDE))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} <AVOID|HIDE|INVIS> [ON|OFF]", arg1);
+		terrain = wide_grid[EXIT_GRID_W]->terrain_index;
 
 
-		return;
+		if ((wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain))
+		{
+			return wide_grid[EXIT_GRID_W]->terrain_index;
+		}
 	}
 	}
 
 
-	if (*arg3 == 0)
+	if (x < 2 || y < 2 || x > map_grid_x - 3 || y > map_grid_y - 3)
 	{
 	{
-		TOG_BIT(exit->flags, flag);
+		return -1;
 	}
 	}
-	else if (is_abbrev(arg3, "ON"))
+
+	vast_grid[EXIT_GRID_N]  = ses->map->grid_rooms[x     + map_grid_x * (y + 2)];
+	vast_grid[EXIT_GRID_NE] = ses->map->grid_rooms[x + 2 + map_grid_x * (y + 2)];
+	vast_grid[EXIT_GRID_E]  = ses->map->grid_rooms[x + 2 + map_grid_x * (y    )];
+	vast_grid[EXIT_GRID_SE] = ses->map->grid_rooms[x + 2 + map_grid_x * (y - 2)];
+	vast_grid[EXIT_GRID_S]  = ses->map->grid_rooms[x     + map_grid_x * (y - 2)];
+	vast_grid[EXIT_GRID_SW] = ses->map->grid_rooms[x - 2 + map_grid_x * (y - 2)];
+	vast_grid[EXIT_GRID_W]  = ses->map->grid_rooms[x - 2 + map_grid_x * (y    )];
+	vast_grid[EXIT_GRID_NW]	= ses->map->grid_rooms[x - 2 + map_grid_x * (y + 2)];
+
+	if (vast_grid[EXIT_GRID_N] && vast_grid[EXIT_GRID_N]->terrain_index != -1 && vast_grid[EXIT_GRID_N]->vnum && HAS_BIT(root->list[vast_grid[EXIT_GRID_N]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_VAST))
 	{
 	{
-		SET_BIT(exit->flags, flag);
+		terrain = vast_grid[EXIT_GRID_N]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain))
+		{
+			return vast_grid[EXIT_GRID_N]->terrain_index;
+		}
 	}
 	}
-	else if (is_abbrev(arg3, "OFF"))
+
+	if (vast_grid[EXIT_GRID_E] && vast_grid[EXIT_GRID_E]->terrain_index != -1 && vast_grid[EXIT_GRID_E]->vnum && HAS_BIT(root->list[vast_grid[EXIT_GRID_E]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_VAST))
 	{
 	{
-		DEL_BIT(exit->flags, flag);
+		terrain = vast_grid[EXIT_GRID_E]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain))
+		{
+			return vast_grid[EXIT_GRID_E]->terrain_index;
+		}
 	}
 	}
-	else
+
+	if (vast_grid[EXIT_GRID_S] && vast_grid[EXIT_GRID_S]->terrain_index != -1 && vast_grid[EXIT_GRID_S]->vnum && HAS_BIT(root->list[vast_grid[EXIT_GRID_S]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_VAST))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} {%s} [ON|OFF]", arg3);
+		terrain = vast_grid[EXIT_GRID_S]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain))
+		{
+			return vast_grid[EXIT_GRID_S]->terrain_index;
+		}
 	}
 	}
 
 
-	if (is_abbrev(arg2, "AVOID"))
+	if (vast_grid[EXIT_GRID_W] && vast_grid[EXIT_GRID_W]->terrain_index != -1 && vast_grid[EXIT_GRID_W]->vnum && HAS_BIT(root->list[vast_grid[EXIT_GRID_W]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_VAST))
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: AVOID FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_AVOID) ? "ON" : "OFF");
+		terrain = vast_grid[EXIT_GRID_W]->terrain_index;
+
+		if ((wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain))
+		{
+			return vast_grid[EXIT_GRID_W]->terrain_index;
+		}
 	}
 	}
-	else if (is_abbrev(arg2, "HIDE"))
+
+	return -1;
+}
+
+int get_terrain_density(struct room_data *room, int width)
+{
+	int flag = 0;
+
+	switch (width)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: HIDE FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_HIDE) ? "ON" : "OFF");
+		case 0:
+			if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEIN))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_AMPLE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_STANDARD|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+								flag = TERRAIN_FLAG_DENSE;
+								break;
+							case TERRAIN_FLAG_STANDARD:
+								flag = TERRAIN_FLAG_AMPLE;
+								break;
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+						}
+						break;
+					case TERRAIN_FLAG_AMPLE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_STANDARD|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+								flag = TERRAIN_FLAG_AMPLE;
+								break;
+							case TERRAIN_FLAG_STANDARD:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_SPARSE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+							case TERRAIN_FLAG_STANDARD:
+							case TERRAIN_FLAG_WIDE:
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_SCANT:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEOUT))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_AMPLE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						flag = TERRAIN_FLAG_DENSE;
+						break;
+					case TERRAIN_FLAG_AMPLE:
+						flag = TERRAIN_FLAG_AMPLE;
+						break;
+					case TERRAIN_FLAG_SPARSE:
+						flag = TERRAIN_FLAG_SPARSE;
+						break;
+					case TERRAIN_FLAG_SCANT:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else
+			{
+				flag = room->terrain_flags;
+			}
+			break;
+
+		case 1:
+			if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEIN))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+							case TERRAIN_FLAG_STANDARD:
+								flag = TERRAIN_FLAG_DENSE;
+								break;
+
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_AMPLE;
+								break;
+								
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_AMPLE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+							case TERRAIN_FLAG_STANDARD:
+								flag = TERRAIN_FLAG_AMPLE;
+								break;
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_SPARSE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+							case TERRAIN_FLAG_STANDARD:
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_SCANT:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEOUT))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						flag = TERRAIN_FLAG_AMPLE;
+						break;
+
+					case TERRAIN_FLAG_AMPLE:
+						flag = TERRAIN_FLAG_SPARSE;
+						break;
+
+					case TERRAIN_FLAG_SPARSE:
+					case TERRAIN_FLAG_SCANT:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else
+			{
+				flag = room->terrain_flags;
+			}
+			break;
+
+		case 2:
+			if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEIN))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+							case TERRAIN_FLAG_STANDARD:
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_DENSE;
+								break;
+
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_AMPLE;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_AMPLE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+							case TERRAIN_FLAG_STANDARD:
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_AMPLE;
+								break;
+
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_SPARSE:
+						switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_NARROW|TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST))
+						{
+							case TERRAIN_FLAG_NARROW:
+							case TERRAIN_FLAG_STANDARD:
+							case TERRAIN_FLAG_WIDE:
+								flag = TERRAIN_FLAG_SPARSE;
+								break;
+							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
+								flag = TERRAIN_FLAG_SCANT;
+								break;
+						}
+						break;
+
+					case TERRAIN_FLAG_SCANT:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEOUT))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						flag = TERRAIN_FLAG_SPARSE;
+						break;
+
+					default:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else
+			{
+				flag = room->terrain_flags;
+			}
+			break;
+
+		default:
+			if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEIN))
+			{
+				switch (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DENSE|TERRAIN_FLAG_SPARSE|TERRAIN_FLAG_SCANT))
+				{
+					case TERRAIN_FLAG_DENSE:
+						flag = TERRAIN_FLAG_DENSE;
+						break;
+					default:
+						flag = 0;
+						break;
+
+					case TERRAIN_FLAG_SPARSE:
+						flag = TERRAIN_FLAG_SPARSE;
+						break;
+
+					case TERRAIN_FLAG_SCANT:
+						flag = TERRAIN_FLAG_SCANT;
+						break;
+				}
+			}
+			else if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_FADEOUT))
+			{
+				flag = TERRAIN_FLAG_SCANT;
+			}
+			else
+			{
+				flag = room->terrain_flags;
+			}
+			break;
 	}
 	}
-	else if (is_abbrev(arg2, "INVISIBLE"))
+
+	if (HAS_BIT(room->terrain_flags, TERRAIN_FLAG_DOUBLE))
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: INVIS FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_INVIS) ? "ON" : "OFF");
+		SET_BIT(flag, TERRAIN_FLAG_DOUBLE);
 	}
 	}
+	return flag;
 }
 }
 
 
-DO_MAP(map_explore)
+char *blank_terrain_symbol(struct session *ses, struct room_data *room, int index, int flags)
 {
 {
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-
-	explore_path(ses, FALSE, arg1, "");
-}
+	if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE))
+	{
+		if (room && room->terrain_index != -1 && HAS_BIT(ses->list[LIST_TERRAIN]->list[room->terrain_index]->room->terrain_flags, TERRAIN_FLAG_DOUBLE))
+		{
+			if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
+			{
+				if (index % 2 == 1)
+				{
+					SET_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
 
 
-DO_MAP(map_find)
-{
-	shortest_path(ses, FALSE, arg1, arg);
+					return "  ";
+				}
+				else
+				{
+					DEL_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+					return "";
+				}
+			}
+			else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
+			{
+				switch (index)
+				{
+					case 1:
+					case 3:
+						SET_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+						return "  ";
+					case 2:
+					case 4:
+						DEL_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+						return "";
+					case 5:
+						return "\e[1;31m5";
+				}
+			}
+		}
+//		DEL_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+		return " ";
+	}
+	return " ";
 }
 }
 
 
-DO_MAP(map_flag)
+char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line, int index, int x, int y, int flags)
 {
 {
-	int flag = 0, unflag = 0;
+	struct room_data *room_grid[11], *terrain_room;
+	int terrain, width = 0, density, hash;
 
 
-	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 (!HAS_BIT(ses->map->flags, MAP_FLAG_TERRAIN))
+	{
+		return " ";
+	}
 
 
-	if (*arg1)
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_DOUBLED))
 	{
 	{
-		if (is_abbrev(arg1, "static"))
+		DEL_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+
+		if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE) && index != 1)
 		{
 		{
-			flag = MAP_FLAG_STATIC;
+			return "";
 		}
 		}
-		else if (is_abbrev(arg1, "vtmap"))
+//		return "\e[1;31m?";
+	}
+
+	room_grid[EXIT_GRID_0]  = ses->map->grid_rooms[x     + map_grid_x * (y    )];
+	room_grid[EXIT_GRID_N]  = ses->map->grid_rooms[x     + map_grid_x * (y + 1)];
+	room_grid[EXIT_GRID_NE] = ses->map->grid_rooms[x + 1 + map_grid_x * (y + 1)];
+	room_grid[EXIT_GRID_E]  = ses->map->grid_rooms[x + 1 + map_grid_x * (y    )];
+	room_grid[EXIT_GRID_SE] = ses->map->grid_rooms[x + 1 + map_grid_x * (y - 1)];
+	room_grid[EXIT_GRID_S]  = ses->map->grid_rooms[x     + map_grid_x * (y - 1)];
+	room_grid[EXIT_GRID_SW] = ses->map->grid_rooms[x - 1 + map_grid_x * (y - 1)];
+	room_grid[EXIT_GRID_W]  = ses->map->grid_rooms[x - 1 + map_grid_x * (y    )];
+	room_grid[EXIT_GRID_NW]	= ses->map->grid_rooms[x - 1 + map_grid_x * (y + 1)];
+
+	hash = index + (room && room->vnum ? room->vnum : x + y);
+
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
+	{
+		if (room == NULL)
 		{
 		{
-			flag = MAP_FLAG_VTMAP;
+			width++;
+
+			switch (line)
+			{
+				case 1:
+					switch (index)
+					{
+						case 1:
+						case 2:
+							room = room_grid[EXIT_GRID_N] ? room_grid[EXIT_GRID_N] : room_grid[EXIT_GRID_W] ? room_grid[EXIT_GRID_W] : room_grid[EXIT_GRID_NW] ? room_grid[EXIT_GRID_NW] : NULL;
+							break;
+						case 3:
+						case 4:
+							room = room_grid[EXIT_GRID_N] ? room_grid[EXIT_GRID_N] : NULL;
+							break;
+						case 5:
+						case 6:
+							room = room_grid[EXIT_GRID_N] ? room_grid[EXIT_GRID_N] : room_grid[EXIT_GRID_E] ? room_grid[EXIT_GRID_E] : room_grid[EXIT_GRID_NE] ? room_grid[EXIT_GRID_NE] : NULL;
+							break;
+					}
+					break;
+
+				case 2:
+					switch (index)
+					{
+						case 1:
+						case 2:
+							room = room_grid[EXIT_GRID_W] ? room_grid[EXIT_GRID_W] : room_grid[EXIT_GRID_NW] ? room_grid[EXIT_GRID_NW] : room_grid[EXIT_GRID_SW] ? room_grid[EXIT_GRID_SW] : NULL;
+							break;
+						case 3:
+						case 4:
+							room = room_grid[EXIT_GRID_N] ? room_grid[EXIT_GRID_N] : room_grid[EXIT_GRID_S] ? room_grid[EXIT_GRID_S] : NULL;
+							break;
+						case 5:
+						case 6:
+							room = room_grid[EXIT_GRID_E] ? room_grid[EXIT_GRID_E] : room_grid[EXIT_GRID_NE] ? room_grid[EXIT_GRID_NE] : room_grid[EXIT_GRID_SE] ? room_grid[EXIT_GRID_SE] : NULL;
+							break;
+					}
+					break;
+
+				case 3:
+					switch (index)
+					{
+						case 1:
+						case 2:
+							room = room_grid[EXIT_GRID_S] ? room_grid[EXIT_GRID_S] : room_grid[EXIT_GRID_W] ? room_grid[EXIT_GRID_W] : room_grid[EXIT_GRID_SW] ? room_grid[EXIT_GRID_SW] : NULL;
+							break;
+						case 3:
+						case 4:
+							room = room_grid[EXIT_GRID_S] ? room_grid[EXIT_GRID_S] : NULL;
+							break;
+						case 5:
+						case 6:
+							room = room_grid[EXIT_GRID_S] ? room_grid[EXIT_GRID_S] : room_grid[EXIT_GRID_E] ? room_grid[EXIT_GRID_E] : room_grid[EXIT_GRID_SE] ? room_grid[EXIT_GRID_SE] : NULL;
+							break;
+					}
+					break;
+			}
+
+			if (room == NULL || room->terrain_index == -1 || HAS_BIT(ses->list[LIST_TERRAIN]->list[room->terrain_index]->room->terrain_flags, TERRAIN_FLAG_NARROW))
+			{
+				return blank_terrain_symbol(ses, room, index, flags);
+			}
 		}
 		}
-		else if (is_abbrev(arg1, "asciigraphics"))
+
+		terrain = room->terrain_index;
+
+		if (terrain == -1)
 		{
 		{
-			flag = MAP_FLAG_ASCIIGRAPHICS;
-			unflag = MAP_FLAG_MUDFONT|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "asciivnums"))
+
+		terrain_room = ses->list[LIST_TERRAIN]->list[terrain]->room;
+
+		if (HAS_BIT(ses->list[LIST_TERRAIN]->list[room->terrain_index]->room->terrain_flags, TERRAIN_FLAG_DOUBLE))
 		{
 		{
-			flag = MAP_FLAG_ASCIIVNUMS;
+			if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE))
+			{
+				if (index % 2 == 0)
+				{
+					return "\e[1;36m?";
+				}
+				SET_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+			}
+			else
+			{
+				return " ";
+			}
 		}
 		}
-		else if (is_abbrev(arg1, "blockgraphics"))
+
+		if (HAS_BIT(terrain_room->terrain_flags, TERRAIN_FLAG_NARROW) && room->exit_grid[EXIT_GRID_E] == NULL)
 		{
 		{
-			flag = MAP_FLAG_BLOCKGRAPHICS;
-			unflag = MAP_FLAG_MUDFONT|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_ASCIIGRAPHICS;
+			switch (line * 10 + index)
+			{
+				case 16:
+				case 26:
+				case 36:
+					return blank_terrain_symbol(ses, room, index, flags);
+			}
 		}
 		}
-		else if (is_abbrev(arg1, "direction"))
+
+		if (room->vnum == 0)
 		{
 		{
-			flag = MAP_FLAG_DIRECTION;
+			width++;
+
+			density = 0;
+
+			density += (room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_N]->vnum);
+			density += (room_grid[EXIT_GRID_NE] && room_grid[EXIT_GRID_NE]->vnum);
+			density += (room_grid[EXIT_GRID_E] && room_grid[EXIT_GRID_E]->vnum);
+			density += (room_grid[EXIT_GRID_SE] && room_grid[EXIT_GRID_SE]->vnum);
+			density += (room_grid[EXIT_GRID_S] && room_grid[EXIT_GRID_S]->vnum);
+			density += (room_grid[EXIT_GRID_SW] && room_grid[EXIT_GRID_SW]->vnum);
+			density += (room_grid[EXIT_GRID_W] && room_grid[EXIT_GRID_W]->vnum);
+			density += (room_grid[EXIT_GRID_NW] && room_grid[EXIT_GRID_NW]->vnum);
+
+			if (density == 0)
+			{
+				width++;
+			}
 		}
 		}
-		else if (is_abbrev(arg1, "mudfont"))
+
+		density = get_terrain_density(terrain_room, width);
+
+		if (HAS_BIT(density, TERRAIN_FLAG_DENSE))
 		{
 		{
-			flag = MAP_FLAG_MUDFONT;
-			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+			return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
 		}
 		}
-		else if (is_abbrev(arg1, "nofollow"))
+
+		if (HAS_BIT(density, TERRAIN_FLAG_SPARSE))
 		{
 		{
-			flag = MAP_FLAG_NOFOLLOW;
+			switch (line * 10 + index)
+			{
+				case 11:
+				case 23:
+				case 35:
+					return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
+			}
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "simplegraphics"))
+
+		if (HAS_BIT(density, TERRAIN_FLAG_SCANT))
 		{
 		{
-			unflag = MAP_FLAG_ASCIIVNUMS|MAP_FLAG_SYMBOLGRAPHICS|MAP_FLAG_MUDFONT|MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+			switch (line * 10 + index)
+			{
+				case 11:
+					return hash % 3 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 23:
+					return hash % 3 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 35:
+					return hash % 3 == 2 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+			}
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "symbolgraphics"))
+
+		if (HAS_BIT(density, TERRAIN_FLAG_DOUBLE))
 		{
 		{
-			flag = MAP_FLAG_SYMBOLGRAPHICS;
-			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+			switch (y % 2 * 30 + line * 10 + index)
+			{
+				case 11:
+				case 15:
+				case 23:
+				case 31:
+				case 35:
+				case 43:
+				case 51:
+				case 55:
+				case 63:
+					return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
+			}
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "unicodegraphics"))
+
+		switch (y % 2 * 30 + line * 10 + index)
 		{
 		{
-			flag = MAP_FLAG_UNICODEGRAPHICS;
-			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_MUDFONT|MAP_FLAG_BLOCKGRAPHICS;
-		}
-		else
-		{
-			show_error(ses, LIST_COMMAND, "#MAP: Invalid flag {%s}.", arg1);
-
-			return;
-		}
-	}
-	else
-	{
-		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: BlockGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: Direction flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: MudFont flag is set to %s", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: NoFollow flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: SimpleGraphics flag is set to %s.", !HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS|MAP_FLAG_SYMBOLGRAPHICS|MAP_FLAG_MUDFONT|MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: Static flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: SymbolGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: UnicodeGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: VTmap flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "ON" : "OFF");
-
-		return;
-	}
+			case 11:
+			case 13:
+			case 15:
+			case 22:
+			case 24:
+			case 26:
+			case 31:
+			case 33:
+			case 35:
+			case 42:
+			case 44:
+			case 46:
+			case 51:
+			case 53:
+			case 55:
+			case 62:
+			case 64:
+			case 66:
+				return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
+		}
+		return blank_terrain_symbol(ses, room, index, flags);
+	}
+
+	// UNICODE
 
 
-	if (is_abbrev(arg2, "ON"))
-	{
-		SET_BIT(ses->map->flags, flag);
-	}
-	else if (is_abbrev(arg2, "OFF"))
-	{
-		DEL_BIT(ses->map->flags, flag);
-	}
-	else
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
 	{
 	{
-		TOG_BIT(ses->map->flags, flag);
-	}
+		if (room == NULL)
+		{
+			width++;
 
 
-	if (unflag)
-	{
-		DEL_BIT(ses->map->flags, unflag);
-	}
+			switch (line)
+			{
+				case 1:
+					switch (index)
+					{
+						case 1:
+						case 2:
+							room = room_grid[EXIT_GRID_W] ? room_grid[EXIT_GRID_W] : room_grid[EXIT_GRID_NW] ? room_grid[EXIT_GRID_NW] : NULL;
+							break;
+						case 3:
+						case 4:
+							room = room_grid[EXIT_GRID_N] ? room_grid[EXIT_GRID_N] : NULL;
+							break;
+						case 5:
+							room = room_grid[EXIT_GRID_N] ? room_grid[EXIT_GRID_N] : NULL;
+							break;
+					}
+					break;
 
 
-	if (is_abbrev(arg1, "asciigraphics"))
-	{
-		show_message(ses, LIST_COMMAND, "#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, LIST_COMMAND, "#MAP: AsciiVnums flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "direction"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: Direction flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "mudfont"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: MudFont flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "nofollow"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: NoFollow flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "static"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "simplegraphics"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: All graphic modes have been disabled.");
-	}
-	else if (is_abbrev(arg1, "symbolgraphics"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: SymbolGraphics flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "unicodegraphics"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: UnicodeGraphics flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) ? "ON" : "OFF");
-	}
-	else if (is_abbrev(arg1, "vtmap"))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: VTmap flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "ON" : "OFF");
-	}
+				case 2:
+					switch (index)
+					{
+						case 1:
+						case 2:
+							room = room_grid[EXIT_GRID_W] ? room_grid[EXIT_GRID_W] : NULL;
+							break;
+						case 3:
+						case 4:
+							if (room_grid[EXIT_GRID_S])
+							{
+								room = room_grid[EXIT_GRID_S];
+							}
+							else if (room_grid[EXIT_GRID_N])
+							{
+								room = room_grid[EXIT_GRID_N];
+							}
+							break;
+						case 5:
+							room = room_grid[EXIT_GRID_S] ? room_grid[EXIT_GRID_S] : NULL;
+							break;
+					}
+					break;
+			}
 
 
+			if (room == NULL || room->terrain_index == -1)
+			{
+				return blank_terrain_symbol(ses, room, index, flags);
+			}
 
 
-}
+			if (HAS_BIT(ses->list[LIST_TERRAIN]->list[room->terrain_index]->room->terrain_flags, TERRAIN_FLAG_NARROW))
+			{
+				switch (line * 10 + index)
+				{
+					case 23:
+					case 24:
+					case 25:
+						return blank_terrain_symbol(ses, room, index, flags);
+				}
 
 
-DO_MAP(map_get)
-{
-	struct room_data *room = ses->map->room_list[ses->map->in_room];
-	struct exit_data *exit;
-	char exits[BUFFER_SIZE], arg3[BUFFER_SIZE];
+				if (room_grid[EXIT_GRID_N] == NULL)
+				{
+					switch (line * 10 + index)
+					{
+						case 13:
+						case 14:
+						case 15:
+							return blank_terrain_symbol(ses, room, index, flags);
+					}
+				}
 
 
-	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 (room_grid[EXIT_GRID_W] == NULL && room_grid[EXIT_GRID_NW] == NULL)
+				{
+					switch (line * 10 + index)
+					{
+						case 11:
+						case 12:
+							return blank_terrain_symbol(ses, room, index, flags);
+					}
+				}
 
 
-	if (*arg3)
-	{
-		if (atoi(arg3) > 0 && atoi(arg3) < ses->map->size)
-		{
-			room = ses->map->room_list[atoi(arg3)];
+				if (room_grid[EXIT_GRID_W] == NULL)
+				{
+					switch (line * 10 + index)
+					{
+						case 21:
+						case 22:
+							return blank_terrain_symbol(ses, room, index, flags);
+					}
+				}
+			}
 		}
 		}
 		else
 		else
 		{
 		{
-			room = NULL;
-		}
-	}
-
-	if (room == NULL)
-	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "0");
-	}
-	else if (*arg1 == 0 || *arg2 == 0)
-	{
-		tintin_printf2(ses, " worldflags: %d", ses->map->flags);
-		tintin_printf2(ses, "  worldsize: %d", ses->map->size);
-		tintin_printf2(ses, "");
-		tintin_printf2(ses, "   roomvnum: %d", room->vnum);
-		tintin_printf2(ses, "   roomarea: %s", room->area);
-		tintin_printf2(ses, "  roomcolor: %s", room->color);
-		tintin_printf2(ses, "   roomdata: %s", room->data);
-		tintin_printf2(ses, "   roomdesc: %s", room->desc);
-		tintin_printf2(ses, "  roomexits: %d", get_room_exits(ses, room->vnum));
-		tintin_printf2(ses, "  roomflags: %d", room->flags);
-		tintin_printf2(ses, "     roomid: %s", room->id);
-		tintin_printf2(ses, "   roomname: %s", room->name);
-		tintin_printf2(ses, "   roomnote: %s", room->note);
-		tintin_printf2(ses, " roomsymbol: %s", room->symbol);
-		tintin_printf2(ses, "roomterrain: %s", room->terrain);
-		tintin_printf2(ses, " roomweight: %.3f", room->weight);
-	}
-	else
-	{
-		if (is_abbrev(arg1, "all"))
-		{
-			exits[0] = 0;
+			switch (line * 10 + index)
+			{
+				case 11:
+				case 12:
+					if (room_grid[EXIT_GRID_N] && hash % 4 == 0)
+					{
+						room = room_grid[EXIT_GRID_N];
+					}
+					else if (room_grid[EXIT_GRID_W] && hash % 4 == 1)
+					{
+						room = room_grid[EXIT_GRID_W];
+					}
+					else if (room_grid[EXIT_GRID_NW] && hash % 4 == 2)
+					{
+						room = room_grid[EXIT_GRID_NW];
+					}
+					break;
+				case 13:
+				case 14:
+					if (room_grid[EXIT_GRID_N] && hash % 2 == 0)
+					{
+						room = room_grid[EXIT_GRID_N];
+					}
+					break;
+				case 21:
+				case 22:
+					if (room_grid[EXIT_GRID_W] && hash % 2 == 0)
+					{
+						room = room_grid[EXIT_GRID_W];
+					}
+					break;
+			}
 
 
-			for (exit = room->f_exit ; exit ; exit = exit->next)
+			if (room == NULL)
 			{
 			{
-				cat_sprintf(exits, "{%s}{%d}", exit->name, exit->vnum);
+				return blank_terrain_symbol(ses, room, index, flags);
 			}
 			}
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "{area}{%s}{color}{%s}{data}{%s}{desc}{%s}{exits}{%s}{flags}{%d}{id}{%d}{name}{%s}{note}{%s}{symbol}{%s}{terrain}{%s}{vnum}{%d}{weight}{%.3f}", room->area, room->color, room->data, room->desc, exits, room->flags, room->id, room->name, room->note, room->symbol, room->terrain, room->vnum, room->weight);
 		}
 		}
-		else if (is_abbrev(arg1, "roomarea"))
+
+		terrain = room->terrain_index;
+
+		if (terrain == -1)
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->area);
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "roomcolor"))
+
+		terrain_room = ses->list[LIST_TERRAIN]->list[terrain]->room;
+
+		if (HAS_BIT(terrain_room->terrain_flags, TERRAIN_FLAG_DOUBLE))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->color);
+			if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE))
+			{
+				if (index == 5)
+				{
+					return "\e[1;32m5";
+				}
+				if (index % 2 == 0)
+				{
+					DEL_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+					if (index == 2)
+					{
+						return " ";
+					}
+					if (index == 4)
+					{
+						return " ";
+					}
+					return "\e[1;35m?";
+				}
+				SET_BIT(ses->map->flags, MAP_FLAG_DOUBLED);
+			}
+			else
+			{
+				return blank_terrain_symbol(ses, room, index, flags);
+			}
 		}
 		}
-		else if (is_abbrev(arg1, "roomdata"))
+
+		if (room->vnum == 0)
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->data);
+			width++;
+
+			density = 0;
+
+			density += (room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_N]->vnum);
+			density += (room_grid[EXIT_GRID_NE] && room_grid[EXIT_GRID_NE]->vnum);
+			density += (room_grid[EXIT_GRID_E] && room_grid[EXIT_GRID_E]->vnum);
+			density += (room_grid[EXIT_GRID_SE] && room_grid[EXIT_GRID_SE]->vnum);
+			density += (room_grid[EXIT_GRID_S] && room_grid[EXIT_GRID_S]->vnum);
+			density += (room_grid[EXIT_GRID_SW] && room_grid[EXIT_GRID_SW]->vnum);
+			density += (room_grid[EXIT_GRID_W] && room_grid[EXIT_GRID_W]->vnum);
+			density += (room_grid[EXIT_GRID_NW] && room_grid[EXIT_GRID_NW]->vnum);
+
+			if (density == 0)
+			{
+				width++;
+			}
 		}
 		}
-		else if (is_abbrev(arg1, "roomdesc"))
+
+		density = get_terrain_density(terrain_room, width);
+
+		if (HAS_BIT(density, TERRAIN_FLAG_DENSE))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->desc);
+			return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
 		}
 		}
-		else if (is_abbrev(arg1, "roomflags"))
+
+		if (HAS_BIT(density, TERRAIN_FLAG_SPARSE))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", room->flags);
+			if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE) && HAS_BIT(terrain_room->terrain_flags, TERRAIN_FLAG_DOUBLE))
+			{
+				if (room_grid[EXIT_GRID_0] && room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_0]->terrain_index != room_grid[EXIT_GRID_N]->terrain_index)
+				{
+					switch (line * 10 + index)
+					{
+						case 13:
+							return hash % 2 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+					}
+				}
+
+				switch (line * 10 + index)
+				{
+					case 11:
+						return hash % 2 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+
+					case 23:
+						return hash % 2 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				}
+				return blank_terrain_symbol(ses, room, index, flags);
+			}
+
+			if (room_grid[EXIT_GRID_0] && room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_0]->terrain_index != room_grid[EXIT_GRID_N]->terrain_index)
+			{
+				switch (line * 10 + index)
+				{
+					case 12:
+						return hash % 2 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+
+					case 14:
+						return hash % 2 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				}
+			}
+
+			switch (line * 10 + index)
+			{
+				case 11:
+					return hash % 5 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 13:
+					return hash % 5 == 2 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 15:
+					return hash % 5 == 4 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+
+				case 22:
+					return hash % 2 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 24:
+					return hash % 2 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+			}
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "roomid"))
+
+		if (HAS_BIT(density, TERRAIN_FLAG_SCANT))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->id);
+			if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE) && HAS_BIT(terrain_room->terrain_flags, TERRAIN_FLAG_DOUBLE))
+			{
+				if (room_grid[EXIT_GRID_0] && room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_0]->terrain_index != room_grid[EXIT_GRID_N]->terrain_index)
+				{
+					switch (line * 10 + index)
+					{
+						case 13:
+							return hash % 4 == 2 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+					}
+				}
+
+				switch (line * 10 + index)
+				{
+					case 11:
+						return hash % 4 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+//					case 13:
+//						return hash % 8 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+//					case 21:
+//						return hash % 8 == 2 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+					case 23:
+						return hash % 4 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				}
+				return blank_terrain_symbol(ses, room, index, flags);
+			}
+
+			if (room_grid[EXIT_GRID_0] && room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_0]->terrain_index != room_grid[EXIT_GRID_N]->terrain_index)
+			{
+				switch (line * 10 + index)
+				{
+					case 12:
+						return hash % 7 == 5 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+					case 14:
+						return hash % 7 == 6 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				}
+			}
+
+			switch (line * 10 + index)
+			{
+				case 11:
+					return hash % 7 == 0 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 13:
+					return hash % 7 == 1 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 15:
+					return hash % 7 == 2 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 22:
+					return hash % 7 == 3 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+				case 24:
+					return hash % 7 == 4 ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+			}
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "roomname"))
+
+		if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE) && HAS_BIT(terrain_room->terrain_flags, TERRAIN_FLAG_DOUBLE))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->name);
+			switch (line * 10 + index)
+			{
+				case 13:
+					return room_grid[EXIT_GRID_0] && room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_0]->terrain_index != room_grid[EXIT_GRID_N]->terrain_index ? ses->list[LIST_TERRAIN]->list[terrain]->arg2 : blank_terrain_symbol(ses, room, index, flags);
+
+				case 11:
+//					return "\e[1;31m1 ";
+				case 23:
+//					return "\e[1;34m3 ";
+					return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
+			}
+			return blank_terrain_symbol(ses, room, index, flags);
 		}
 		}
-		else if (is_abbrev(arg1, "roomnote"))
+
+		switch (line * 10 + index)
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->note);
+			case 12:
+			case 14:
+				if (room_grid[EXIT_GRID_0] && room_grid[EXIT_GRID_N] && room_grid[EXIT_GRID_0]->terrain_index != -1 && room_grid[EXIT_GRID_0]->terrain_index != room_grid[EXIT_GRID_N]->terrain_index)
+				{
+					if (!HAS_BIT(ses->list[LIST_TERRAIN]->list[room_grid[EXIT_GRID_N]->terrain_index]->room->terrain_flags, TERRAIN_FLAG_DOUBLE))
+					{
+						return ses->list[LIST_TERRAIN]->list[room_grid[EXIT_GRID_N]->terrain_index]->arg2;
+					}
+				}
+				return blank_terrain_symbol(ses, room, index, flags);
+			case 11:
+			case 13:
+			case 15:
+			case 22:
+			case 24:
+				return ses->list[LIST_TERRAIN]->list[terrain]->arg2;
 		}
 		}
-		else if (is_abbrev(arg1, "roomsymbol"))
+		return blank_terrain_symbol(ses, room, index, flags);
+	}
+	return blank_terrain_symbol(ses, room, index, flags);
+}
+
+int follow_map(struct session *ses, char *argument)
+{
+	struct room_data *room;
+	struct exit_data *exit;;
+	int in_room, vnum;
+
+	push_call("follow_map(%p,%p)",ses,argument);
+
+	room = ses->map->room_list[ses->map->in_room];
+
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
+	{
+		if (check_global(ses, room->vnum) && find_exit(ses, ses->map->global_vnum, argument))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->symbol);
+			in_room = ses->map->global_vnum;
 		}
 		}
-		else if (is_abbrev(arg1, "roomterrain"))
+		else
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", room->terrain);
+			in_room = ses->map->in_room;
 		}
 		}
-		else if (is_abbrev(arg1, "roomvnum"))
+		exit = find_exit(ses, in_room, argument);
+
+		if (exit)
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", room->vnum);
+			ses->map->dir = exit->dir;
+
+			vnum = tunnel_void(ses, in_room, exit->vnum, exit->dir);
+
+			check_all_events(ses, SUB_ARG, 0, 5, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name);
 		}
 		}
-		else if (is_abbrev(arg1, "roomweight"))
+		pop_call();
+		return 0;
+	}
+
+	if (check_global(ses, room->vnum))
+	{
+		if (find_exit(ses, ses->map->global_vnum, argument))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%.3f", room->weight);
+			goto_room(ses, ses->map->global_vnum);
 		}
 		}
-		else if (is_abbrev(arg1, "roomexits"))
+	}
+
+	exit = find_exit(ses, ses->map->in_room, argument);
+
+	if (exit)
+	{
+		ses->map->dir = exit->dir;
+
+		in_room = ses->map->in_room;
+
+		vnum = tunnel_void(ses, in_room, exit->vnum, exit->dir);
+
+		if (ses->map->nofollow == 0)
 		{
 		{
-			exits[0] = 0;
+			if (HAS_BIT(exit->flags, EXIT_FLAG_BLOCK) || HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_BLOCK))
+			{
+				show_error(ses, LIST_COMMAND, "#MAP FOLLOW: %s {%d} HAS THE BLOCK FLAG SET.", HAS_BIT(exit->flags, EXIT_FLAG_BLOCK) ? "EXIT" : "ROOM", vnum);
 
 
-			for (exit = room->f_exit ; exit ; exit = exit->next)
+				pop_call();
+				return 0;
+			}
+			else
 			{
 			{
-				cat_sprintf(exits, "{%s}{%d}", exit->name, exit->vnum);
+				ses->map->nofollow++;
+				script_driver(ses, LIST_COMMAND, exit->cmd);
+				ses->map->nofollow--;
 			}
 			}
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", exits);
-		}
-		else if (is_abbrev(arg1, "worldflags"))
-		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->map->flags);
 		}
 		}
-		else if (is_abbrev(arg1, "worldsize"))
+
+		check_all_events(ses, SUB_ARG, 0, 5, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name);
+
+		add_undo(ses, "%d %d %d", vnum, in_room, MAP_UNDO_MOVE);
+
+		goto_room(ses, vnum);
+
+		if (HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE))
 		{
 		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->map->size);
+			show_message(ses, LIST_COMMAND, "#MAP: LEAVE FLAG FOUND IN ROOM {%d}. LEAVING MAP.", ses->map->in_room);
+
+			map_leave(ses, "", "", "");
 		}
 		}
-		else
+
+		if (HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#MAP GET: unknown option: %s.", arg1);
+			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 		}
 		}
-	}
-}
 
 
-DO_MAP(map_global)
-{
-	int room;
-
-	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-	if (*arg1 == 0)
-	{
-		show_message(ses, LIST_COMMAND, "#MAP GLOBAL: GLOBAL ROOM SET TO VNUM %d.", ses->map->global_vnum);
+		pop_call();
+		return 1;
 	}
 	}
-	else if (!strcmp(arg1, "0"))
-	{
-		ses->map->global_vnum = ses->map->global_exit->vnum = 0;
 
 
-		show_message(ses, LIST_COMMAND, "#MAP GLOBAL: GLOBAL ROOM SET TO VNUM %d.", 0);
-	}
-	else
+	if (!HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) && !HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC))
 	{
 	{
-		room = find_room(ses, arg);
+		struct listnode *node;
 
 
-		if (room)
+		if ((node = search_node_list(ses->list[LIST_PATHDIR], argument)) == NULL)
 		{
 		{
-			ses->map->global_vnum = ses->map->global_exit->vnum = room;
+			pop_call();
+			return 0;
+		}
 
 
-			show_message(ses, LIST_COMMAND, "#MAP GLOBAL: GLOBAL ROOM SET TO VNUM %d.", room);
+		in_room = find_coord(ses, argument);
+
+		if (in_room)
+		{
+			show_message(ses, LIST_COMMAND, "#MAP CREATE LINK %5d {%s}.", in_room, ses->map->room_list[in_room]->name);
+
+			add_undo(ses, "%d %d %d", in_room, ses->map->in_room, MAP_UNDO_MOVE|MAP_UNDO_LINK);
 		}
 		}
 		else
 		else
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#MAP GLOBAL: COULDN'T FIND ROOM %s.", arg1);
-		}
-	}
-}
-
-DO_MAP(map_goto)
-{
-	struct exit_data *exit;
-	int room;
-
-	room = find_room(ses, arg);
+			for (in_room = 1 ; in_room < ses->map->size ; in_room++)
+			{
+				if (ses->map->room_list[in_room] == NULL)
+				{
+					break;
+				}
+			}
 
 
-	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); // look for dig argument
+			if (in_room == ses->map->size)
+			{
+				show_error(ses, LIST_COMMAND, "#MAP: Maximum amount of rooms of %d reached. Use #MAP RESIZE to increase the maximum.", ses->map->size);
 
 
-	if (room == 0 && ses->map->search->vnum > 0 && ses->map->search->vnum < ses->map->size && !strcasecmp(arg2, "dig"))
-	{
-		room = ses->map->search->vnum;
+				pop_call();
+				return 1;
+			}
+			add_undo(ses, "%d %d %d", in_room, ses->map->in_room, MAP_UNDO_MOVE|MAP_UNDO_CREATE|MAP_UNDO_LINK);
 
 
-		create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
-	}
+			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", in_room);
+		}
 
 
-	if (room == 0)
-	{
-		room = find_room(ses, arg1);
-	}
+		exit = create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", in_room, node->arg1, node->arg1);
 
 
-	if (room == 0 && ses->map->search->id && *ses->map->search->id && !strcasecmp(arg2, "dig"))
-	{
-		room = find_new_room(ses);
+		ses->map->dir = exit->dir;
 
 
-		if (room)
+		if (find_exit(ses, in_room, node->arg2) == NULL)
 		{
 		{
-			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {%s}", room, ses->map->search->id);
+			create_exit(ses, in_room, "{%d} {%s} {%s}", ses->map->in_room, node->arg2, node->arg2);
 		}
 		}
-	}
-
-	if (room == 0)
-	{
-		exit = find_exit(ses, ses->map->in_room, arg1);
 
 
-		if (exit == NULL)
+		if (ses->map->nofollow == 0)
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#MAP GOTO: COULDN'T FIND ROOM %s.", arg1);
+			ses->map->nofollow++;
 
 
-                        return;
-                }
-                room = exit->vnum;
-	}
+			script_driver(ses, LIST_COMMAND, argument);
 
 
-	add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_MOVE);
+			ses->map->nofollow--;
+		}
+		goto_room(ses, in_room);
 
 
-	goto_room(ses, room);
+		if (HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+		{
+			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+		}
 
 
-	show_message(ses, LIST_COMMAND, "#MAP GOTO: MOVED TO ROOM %d {%s}.", room, *ses->map->room_list[room]->name ? ses->map->room_list[room]->name : ses->map->room_list[room]->id);
+		pop_call();
+		return 1;
+	}
+	pop_call();
+	return 0;
 }
 }
 
 
-DO_MAP(map_info)
+void add_undo(struct session *ses, char *format, ...)
 {
 {
-	int room, cnt, exits;
-	struct exit_data *exit;
-	struct room_data *in_room = ses->map->room_list[ses->map->in_room];
+	struct link_data *link;
+	char buf[BUFFER_SIZE], *arg, dir[BUFFER_SIZE], rev[BUFFER_SIZE], flag[BUFFER_SIZE];
+	va_list args;
 
 
-	for (room = cnt = exits = 0 ; room < ses->map->size ; room++)
-	{
-		if (ses->map->room_list[room])
-		{
-			cnt++;
+	push_call("add_undo(%s,%s)",ses->name, format);
 
 
-			exits += get_room_exits(ses, room);
-		}
-	}
+	va_start(args, format);
+	vsprintf(buf, format, args);
+	va_end(args);
 
 
+	arg = get_arg_in_braces(ses, buf, dir, GET_ONE);
+	arg = get_arg_in_braces(ses, arg, rev, GET_ONE);
+	arg = get_arg_in_braces(ses, arg, flag, GET_ONE);
 
 
-	tintin_printf2(ses, " %+16s %-7d %+16s %-7d %+16s %-7d", "Total rooms:", cnt, "Total exits:", exits, "World size:", ses->map->size);
-	tintin_printf2(ses, " %+16s %-7d %+16s %-7d %+16s %-7d",  "Direction:", ses->map->dir, "Last room:", ses->map->last_room, "Undo size:", ses->map->undo_size);
-	tintin_printf2(ses, "");
+	link = (struct link_data *) calloc(1, sizeof(struct link_data));
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s", "AsciiGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS) ? "ON" : "off");
-	cat_sprintf(arg1, " %+16s %-7s", "AsciiVnums:", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) ? "ON" : "off");
-	cat_sprintf(arg1, " %+16s %-7s", "BlockGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS) ? "ON" : "off");
-	tintin_puts2(ses, arg1);
+	link->str1 = strdup(dir);
+	link->str2 = strdup(rev);
+	link->str3 = strdup(flag);
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s", "Direction:", HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION) ? "ON" : "OFF");
-	cat_sprintf(arg1, " %+16s %-7s", "MudFont:", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "ON" : "off");
-	cat_sprintf(arg1, " %+16s %-7s", "Nofollow:", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "ON" : "off");
-	tintin_puts2(ses, arg1);
+	LINK(link, ses->map->undo_head, ses->map->undo_tail);
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s", "Static:", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "ON" : "off");
-	cat_sprintf(arg1, " %+16s %-7s", "SymbolGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) ? "ON" : "off");
-	cat_sprintf(arg1, " %+16s %-7s", "UnicodeGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) ? "ON" : "off");
-	tintin_puts2(ses, arg1);
+	ses->map->undo_size++;
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s", "Vtmap:", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "ON" : "off");
-	tintin_puts2(ses, arg1);
-/*
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s",
-	cat_sprintf(arg1, " %+16s %-7s",
-	cat_sprintf(arg1, " %+16s %-7s",
-	tintin_puts2(ses, arg1);
-*/
-	if (ses->map->in_room == 0)
+	if (ses->map->undo_size > 100)
 	{
 	{
-		return;
+		del_undo(ses, ses->map->undo_head);
 	}
 	}
+	pop_call();
+	return;
+}
 
 
-	tintin_printf2(ses, "");
+void del_undo(struct session *ses, struct link_data *link)
+{
+	UNLINK(link, ses->map->undo_head, ses->map->undo_tail);
 
 
-	tintin_printf2(ses, "%+16s %s", "Room area:",    in_room->area);
-	tintin_printf2(ses, "%+16s %s", "Room data:",    in_room->data);
-	tintin_printf2(ses, "%+16s %s", "Room desc:",    in_room->desc);
-	tintin_printf2(ses, "%+16s %s", "Room id:",      in_room->id);
-	tintin_printf2(ses, "%+16s %s", "Room name:",    in_room->name);
-	tintin_printf2(ses, "%+16s %s", "Room note:",    in_room->note);
-	tintin_printf2(ses, "%+16s %s", "Room color:",   str_convert_meta(in_room->color, TRUE));
-	tintin_printf2(ses, "%+16s %s", "Room terrain:", in_room->terrain);
+	free(link->str1);
+	free(link->str2);
+	free(link->str3);
 
 
-	tintin_printf2(ses, "");
-	tintin_printf2(ses, " %+16s %-7d %+16s %-7.3f %+16s %-7s", "Room vnum:", ses->map->in_room, "Room weight:", in_room->weight, "Room symbol:", in_room->symbol);
+	free(link);
 
 
-	tintin_printf2(ses, " %+16s %-7d %+16s %-7d %+16s %-7d",   "Center x:", ses->map->center_x, "Center y:", ses->map->center_y, "Center z:", ses->map->center_z);
+	ses->map->undo_size--;
+}
 
 
-	tintin_printf2(ses, "");
+/*
+	Draws a map on a grid, original breadth first improvements by Bryan Turner
+*/
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s",    "Avoid:", HAS_BIT(in_room->flags, ROOM_FLAG_AVOID)    ? "on" : "off");
-	cat_sprintf(arg1, " %+16s %-7s",   "Curved:", HAS_BIT(in_room->flags, ROOM_FLAG_CURVED)   ? "on" : "off");
-	cat_sprintf(arg1, " %+16s %-7s",     "Hide:", HAS_BIT(in_room->flags, ROOM_FLAG_HIDE)     ? "on" : "off");
 
 
-	tintin_puts2(ses, arg1);
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s",    "Invis:", HAS_BIT(in_room->flags, ROOM_FLAG_INVIS)    ? "on" : "off");
-	cat_sprintf(arg1, " %+16s %-7s",    "Leave:", HAS_BIT(in_room->flags, ROOM_FLAG_LEAVE)    ? "on" : "off");
-	cat_sprintf(arg1, " %+16s %-7s", "NoGlobal:", HAS_BIT(in_room->flags, ROOM_FLAG_NOGLOBAL) ? "on" : "off");
-	tintin_puts2(ses, arg1);
+struct grid_node
+{
+	int vnum;
+	int from;
+	int flags;
+	float length;
+	int dir;
+	int w;
+	int x;
+	int y;
+	int z;
+};
 
 
-	strcpy(arg1, "");
-	cat_sprintf(arg1, " %+16s %-7s",   "Static:", HAS_BIT(in_room->flags, ROOM_FLAG_STATIC)   ? "on" : "off");
-	cat_sprintf(arg1, " %+16s %-7s",     "Void:", HAS_BIT(in_room->flags, ROOM_FLAG_VOID)     ? "on" : "off");
-	tintin_puts2(ses, arg1);
+void displaygrid_build(struct session *ses, 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, *toroom;
 
 
-	tintin_printf2(ses, "");
+	push_call("displaygrid_build(%p,%d,%d,%d,%d)",ses,vnum,x,y,z);
 
 
-	for (exit = in_room->f_exit ; exit ; exit = exit->next)
-	{
-		tintin_printf2(ses, "%+16s %-3s (%3s)   to room: %-5d (%5s)", "Exit:", exit->name, exit->cmd, exit->vnum, ses->map->room_list[exit->vnum]->name);
-	}
+	map_grid_x = x;
+	map_grid_y = y;
 
 
-	tintin_printf2(ses, "");
+	head = 0;
+	tail = 1;
 
 
-	for (room = 0 ; room < ses->map->size ; room++)
+	node = &list[head];
+
+	node->vnum   = vnum;
+	node->length = ses->map->room_list[vnum]->weight;
+	node->flags  = 0;
+
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
 	{
 	{
-		if (ses->map->room_list[room])
-		{
-			for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
-			{
-				if (exit->vnum == ses->map->in_room)
-				{
-					tintin_printf2(ses, "%+16s %-3s (%3s) from room: %-5d (%5s)", "Entrance:", exit->name, exit->cmd, room, ses->map->room_list[room]->name);
-				}
-			}
-		}
+		node->x      = (x - 2) / 2 + ses->map->center_x;
 	}
 	}
-/*
-	for (exit = in_room->f_exit ; exit ; exit = exit->next)
+	else
 	{
 	{
-		tintin_printf2(ses, "%+14s %-4s %+14s %5d %+14s %5d %+14s %5s", "Exit name:", exit->name, "vnum:", exit->vnum, "flags:", exit->flags, "command:", exit->cmd);
-		tintin_printf2(ses, "%+14s %s", "Exit data:", exit->data);
+		node->x      = x / 2 + ses->map->center_x;
 	}
 	}
-*/
-}
-
-DO_MAP(map_insert)
-{
-	int room, in_room, to_room;
-	struct exit_data *exit;
-	struct listnode *node;
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	node->y      = y / 2 + ses->map->center_y;
+	node->z      = z / 2 + ses->map->center_z;
 
 
-	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);
+	ses->map->display_stamp++;
 
 
-	if (exit == NULL)
+	for (vnum = 0 ; vnum < x * y ; vnum++)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP: There is no room in that direction.");
-
-		return;
+		ses->map->grid_rooms[vnum] = NULL;
 	}
 	}
 
 
-	if (room == ses->map->size)
+	while (head != tail)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP: Maximum amount of rooms of %d reached.", ses->map->size);
-		return;
-	}
+		node = &list[head];
 
 
-	if (node == NULL)
-	{
-		show_error(ses, LIST_COMMAND, "#MAP: Given direction must be a pathdir.");
-		return;
-	}
+		head = (head + 1) % MAP_BF_SIZE;
 
 
-	in_room = ses->map->in_room;
-	to_room = exit->vnum;
+		room = ses->map->room_list[node->vnum];
 
 
-	add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_INSERT);
+		if (ses->map->display_stamp != room->display_stamp)
+		{
+			room->display_stamp = ses->map->display_stamp;
+		}
+		else if (room->length <= node->length /*&& !HAS_BIT(room->flags, ROOM_FLAG_VOID)*/)
+		{
+			continue;
+		}
 
 
-	create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
+		room->length = node->length;
 
 
-	create_exit(ses, room, "{%d} {%s} {%s}", to_room, node->arg1, node->arg1);
+		if (node->x >= 0 && node->x < map_grid_x && node->y >= 0 && node->y < map_grid_y && node->z == 0)
+		{
+			if (ses->map->grid_rooms[node->x + map_grid_x * node->y] == NULL)
+			{
+				ses->map->grid_rooms[node->x + map_grid_x * node->y] = room;
+			}
+			else if (!HAS_BIT(room->flags, ROOM_FLAG_VOID))
+			{
+				continue;
+			}
+		}
 
 
-	create_exit(ses, room, "{%d} {%s} {%s}", in_room, node->arg2, node->arg2);
+		for (exit = room->f_exit ; exit ; exit = exit->next)
+		{
+			if (exit->dir == 0)
+			{
+				continue;
+			}
 
 
-	exit->vnum = room;
+			toroom = ses->map->room_list[exit->vnum];
 
 
-	if ((exit = find_exit(ses, to_room, node->arg2)) != NULL)
-	{
-		exit->vnum = room;
-	}
+			if (ses->map->display_stamp == toroom->display_stamp)
+			{
+				if (HAS_BIT(room->flags, ROOM_FLAG_VOID) || !HAS_BIT(toroom->flags, ROOM_FLAG_VOID))
+				{
+					if (room->length >= ses->map->room_list[exit->vnum]->length)
+					{
+						continue;
+					}
+				}
+			}
 
 
-	if (*arg)
-	{
-		ses->map->in_room = room;
-		map_roomflag(ses, arg, arg1, arg2);
-		ses->map->in_room = in_room;
-	}
-	show_message(ses, LIST_COMMAND, "#MAP: Inserted room {%d}.", room);
-}
+			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
+			{
+				continue;
+			}
 
 
-DO_MAP(map_jump)
-{
-	char arg3[BUFFER_SIZE];
-	int room, x, y, z;
+			if (head == (tail + 1) % MAP_BF_SIZE)
+			{
+				break;
+			}
 
 
-	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_ALL, SUB_VAR|SUB_FUN);
+			if (HAS_BIT(room->flags, ROOM_FLAG_VOID) && ses->map->in_room != room->vnum && get_room_exits(ses, room->vnum) % 2 == 0)
+			{
+				exit = room->exit_grid[dir_to_grid(node->dir)];
+			
+				if (exit == NULL)
+				{
+					if (ses->map->room_list[room->f_exit->vnum]->display_stamp != ses->map->display_stamp)
+					{
+						exit = room->f_exit;
+					}
+					else if (ses->map->room_list[room->l_exit->vnum]->display_stamp != ses->map->display_stamp)
+					{
+						exit = room->l_exit;
+					}
+					else if (ses->map->room_list[room->f_exit->vnum]->length <= ses->map->room_list[room->l_exit->vnum]->length)
+					{
+						exit = room->f_exit;
+					}
+					else
+					{
+						exit = room->l_exit;
+					}
+				}
+			}
 
 
-	x = get_number(ses, arg1);
-	y = get_number(ses, arg2);
-	z = get_number(ses, arg3);
+			temp = &list[tail];
 
 
-	room = spatialgrid_find(ses, ses->map->in_room, x, y, z);
+			temp->vnum   = exit->vnum;
+			temp->dir    = exit->dir;
+			temp->x      = node->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
+			temp->y      = node->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
+			temp->z      = node->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);
+			temp->length = node->length + exit->weight + ses->map->room_list[exit->vnum]->weight;
 
 
-	if (room)
-	{
-		add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_MOVE);
+			temp->flags  = 0;
 
 
-		goto_room(ses, room);
+			tail = (tail + 1) % MAP_BF_SIZE;
 
 
-		show_message(ses, LIST_COMMAND, "#MAP JUMP: JUMPED TO ROOM %d {%s}.", room, *ses->map->room_list[room]->name ? ses->map->room_list[room]->name : ses->map->room_list[room]->id);
-	}
-	else
-	{
-		show_message(ses, LIST_COMMAND, "#MAP JUMP: Couldn't find a room at {%d} {%d} {%d}.", x, y, z);
+			if (HAS_BIT(room->flags, ROOM_FLAG_VOID) && ses->map->in_room != room->vnum && get_room_exits(ses, room->vnum) % 2 == 0)
+			{
+				temp->length = node->length + 0.000001;
+				break;
+			}
+		}
 	}
 	}
-}
 
 
-DO_MAP(map_leave)
-{
-	if (ses->map->in_room == 0)
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_UPDATETERRAIN))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP: You're not currently inside the map.");
+		update_terrain(ses);
 	}
 	}
-	else
+
 	{
 	{
-		ses->map->last_room = ses->map->in_room;
-		ses->map->in_room = 0;
+		int terrain;
 
 
-		show_message(ses, LIST_COMMAND, "#MAP: Leaving the map. Use goto or return to return.");
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
+		{
+			for (x = 1 ; x < map_grid_x - 1 ; x++)
+			{
+				if (ses->map->grid_rooms[x + map_grid_x * y] == NULL)
+				{
+					terrain = get_terrain_index(ses, NULL, x, y);
 
 
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "MAP EXIT MAP", ntos(ses->map->in_room));
+					if (terrain != -1)
+					{
+						ses->map->grid_rooms[x + map_grid_x * y] = ses->list[LIST_TERRAIN]->list[terrain]->room;
+					}
+				}
+			}
+		}
 	}
 	}
+
+	pop_call();
+	return;
 }
 }
 
 
-void map_legend_index(struct session *ses, char *arg, int head, int tail)
+
+void show_vtmap(struct session *ses)
 {
 {
-	char esc[BUFFER_SIZE], raw[BUFFER_SIZE];
-	int cnt;
+	char buf[BUFFER_SIZE], out[BUFFER_SIZE], tmp[BUFFER_SIZE];
+	int x, y, line;
+	int top_row, top_col, bot_row, bot_col, rows, cols, row;
 
 
-	for (cnt = head ; cnt < tail ; cnt++)
-	{
-		arg = sub_arg_in_braces(ses, arg, raw, GET_ONE, SUB_NONE);
+	push_call("show_vtmap(%p)",ses);
 
 
-		substitute(ses, raw, esc, SUB_ESC);
+	if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+	{
+		pop_call();
+		return;
+	}
 
 
-		if (is_number(esc))
-		{
-			numbertocharacter(ses, esc);
-		}
-		snprintf(ses->map->legend[cnt],     LEGEND_SIZE - 1, "%s", esc);
-		snprintf(ses->map->legend_raw[cnt], LEGEND_SIZE - 1, "%s", raw);
-
-		if (*arg == 0)
-		{
-			break;
-		}
-	}
-	return;
-}
-
-DO_MAP(map_legend)
-{
-	char buf[BUFFER_SIZE], arg3[BUFFER_SIZE];
-	int group, legend;
-
-	push_call("map_legend(%p,%p,%p,%p)",ses,arg,arg1,arg2);
-
-	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);
-
-	strcpy(buf, arg2);
-
-	if (*arg1 == 0)
+	if (ses->map->room_list[ses->map->in_room] == NULL)
 	{
 	{
-		for (group = 0 ; map_group_table[group].name ; group++)
-		{
-			tintin_printf2(ses, "  [%-22s]  [%-22s]  [%3d]  [%3d]",
-				map_group_table[group].group,
-				map_group_table[group].name,
-				map_group_table[group].start,
-				map_group_table[group].end);
-		}
 		pop_call();
 		pop_call();
 		return;
 		return;
 	}
 	}
 
 
-	if (is_abbrev(arg1, "RESET"))
+	if (ses != gtd->ses || HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD))
 	{
 	{
-		map_legend(ses, "{ASCII} {RESET}", arg1, arg2);
-		map_legend(ses, "{NESW} {RESET}", arg1, arg2);
-		map_legend(ses, "{MUDFONT BRAILLE TUBE} {RESET}", arg1, arg2);
-
 		pop_call();
 		pop_call();
 		return;
 		return;
 	}
 	}
 
 
-	if (is_math(ses, arg1))
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_RESIZE))
 	{
 	{
-		legend = (int) get_number(ses, arg1);
+		DEL_BIT(ses->map->flags, MAP_FLAG_RESIZE);
 
 
-		if (legend < map_group_table[0].start || legend >= map_group_table[0].end)
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP LEGEND {%d - %d} {[SYMBOL]}", map_group_table[0].start,  map_group_table[0].end);
-		}
-		else if (*arg2 == 0)
-		{
-			tintin_printf2(ses, "  [%-22s]  [%-20s]  [%3d]  [ %8s ]  [ %s ]",
-				map_legend_table[legend].group,
-				map_legend_table[legend].name,
-				legend,
-				ses->map->legend_raw[legend],
-				ses->map->legend[legend]);
-		}
-		else
-		{
-			map_legend_index(ses, arg2, legend, legend + 1);
-		}
-		pop_call();
-		return;
+		map_offset(ses, NULL, "", "");
 	}
 	}
 
 
-	for (group = 0 ; map_group_table[group].name ; group++)
+	if (ses->map->rows > 1 && ses->map->cols > 1)
 	{
 	{
-		if (is_abbrev(arg1, map_group_table[group].name))
-		{
-			break;
-		}
+		top_row = ses->map->top_row;
+		top_col = ses->map->top_col;
+		bot_row = ses->map->bot_row;
+		bot_col = ses->map->bot_col;
+		rows    = ses->map->rows;
+		cols    = ses->map->cols;
+	}
+	else
+	{
+		top_row = 1;
+		top_col = 1;
+		bot_row = ses->split->top_row - 2;
+		bot_col = gtd->screen->cols;
+
+		rows    = ses->split->top_row - 2;
+		cols    = gtd->screen->cols;
 	}
 	}
 
 
+//	print_stdout("\e[%d;%d;%d;%d${", top_row, top_col, bot_row, bot_col);
 
 
-	if (!map_group_table[group].name)
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP LEGEND: UNKNOWN LEGEND {%s} TRY:", arg1);
-
-		map_legend(ses, "", arg1, arg2);
+		erase_square(ses, top_row, top_col, bot_row, bot_col);
 
 
-		pop_call();
-		return;
+		map_grid_y = 2 + rows / 3;
+		map_grid_x = 2 + cols / 6;
 	}
 	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
+	{
+		erase_square(ses, top_row, top_col, bot_row - 1, bot_col);
 
 
-	if (*arg2 == 0)
+		map_grid_y = 2 + (rows + 2) / 2;
+		map_grid_x = 2 + (cols + 4) / 5;
+	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
 	{
 	{
-		for (legend = map_group_table[group].start ; legend < map_group_table[group].end ; legend++)
-		{
-			tintin_printf2(ses, "  [%-22s]  [%-20s]  [%3d]  [ %8s ]  [ %s ]",
-				map_group_table[group].name,
-				map_legend_table[legend].name,
-				legend,
-				ses->map->legend_raw[legend],
-				ses->map->legend[legend]);
-		}
-		pop_call();
-		return;
+		erase_square(ses, top_row, top_col, bot_row, bot_col);
+
+		map_grid_y = 2 + rows / 2;
+		map_grid_x = 2 + cols / 5;
 	}
 	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
+	{
+		erase_square(ses, top_row, top_col, bot_row, bot_col);
 
 
-	if (is_abbrev(arg2, "RESET"))
+		map_grid_y = 2 + rows;
+		map_grid_x = 2 + cols / 2;
+	}
+	else
 	{
 	{
-		map_legend_index(ses, map_group_table[group].reset, map_group_table[group].start, map_group_table[group].end);
+		erase_square(ses, top_row, top_col, bot_row, bot_col);
 
 
-		pop_call();
-		return;
+		map_grid_y = 2 + rows;
+		map_grid_x = 2 + cols;
 	}
 	}
 
 
-	for (legend = map_group_table[group].start ; legend < map_group_table[group].end ; legend++)
+	displaygrid_build(ses, ses->map->in_room, map_grid_x, map_grid_y, 0);
+
+	save_pos(ses);
+
+	goto_pos(ses, top_row, 1);
+
+	row = top_row;
+
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
 	{
-		if (!strcasecmp(space_out(arg2), space_out(map_legend_table[legend].name)))
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			if (*arg3 == 0)
-			{
-				tintin_printf2(ses, "  [%-22s]  [%-20s]  [%3d]  [ %8s ]  [ %s ]",
-					map_group_table[group].name,
-					map_legend_table[legend].name,
-					legend,
-					ses->map->legend_raw[legend],
-					ses->map->legend[legend]);
-			}
-			else
+			for (line = 1 ; line <= 3 ; line++)
 			{
 			{
-				map_legend_index(ses, arg3, legend, legend + 1);
+				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+
+				for (x = 1 ; x < map_grid_x - 1 ; x++)
+				{
+					strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+				}
+				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+
+				print_stdout("\e[%d;%dH%s\e[0m", row++, top_col, out);
 			}
 			}
-			break;
 		}
 		}
 	}
 	}
-
-	if (legend == map_group_table[group].end)
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
 	{
 	{
-		for (legend = map_group_table[group].start ; legend < map_group_table[group].end ; legend++)
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			if (is_abbrev(space_out(arg2), space_out(map_legend_table[legend].name)))
+			for (line = 1 ; line <= 2 ; line++)
 			{
 			{
-				if (*arg3 == 0)
+				if (line == 2 && y == 1)
 				{
 				{
-					tintin_printf2(ses, "  [%-22s]  [%-20s]  [%3d]  [ %8s ]  [ %s ]",
-						map_group_table[group].name,
-						map_legend_table[legend].name,
-						legend,
-						ses->map->legend_raw[legend],
-						ses->map->legend[legend]);
+					continue;
 				}
 				}
-				else
+				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+
+				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
 				{
-					map_legend_index(ses, arg3, legend, legend + 1);
+					if (x == map_grid_x - 2)
+					{
+						strcpy(tmp, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+
+						cat_sprintf(buf, "%.*s", string_str_raw_len(ses, tmp, 0, 2), tmp);
+					}
+					else
+					{
+						strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+					}
 				}
 				}
-				break;
+				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+
+				print_stdout("\e[%d;%dH%s\e[0m", row++, top_col, out);
 			}
 			}
 		}
 		}
 	}
 	}
-
-
-	if (legend == map_group_table[group].end)
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
 	{
 	{
-		if (strlen(arg2) > (map_group_table[group].end - map_group_table[group].start) * 2)
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			map_legend_index(ses, arg2, map_group_table[group].start, map_group_table[group].end);
+			for (line = 1 ; line <= 2 ; line++)
+			{
+				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+
+				for (x = 1 ; x < map_grid_x - 1 ; x++)
+				{
+					strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+				}
+				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+
+				print_stdout("\e[%d;%dH%s\e[0m", row++, top_col, out);
+			}
 		}
 		}
-		else
+	}
+	else
+	{
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP LEGEND {%s} {{arg %d} {arg %d} ... {arg %d} {arg %d}",
-				map_group_table[group].group,
-				map_group_table[group].start,
-				map_group_table[group].start - 1,
-				map_group_table[group].end - 1,
-				map_group_table[group].end);
+			strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+
+			for (x = 1 ; x < map_grid_x - 1 ; x++)
+			{
+				strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
+			}
+			substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+
+			print_stdout("\e[%d;%dH%s\e[0m", row++, top_col, out);
 		}
 		}
 	}
 	}
 
 
+	restore_pos(ses);
+
 	pop_call();
 	pop_call();
 	return;
 	return;
 }
 }
 
 
-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);
-	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);
+// http://shapecatcher.com/unicode/block/Mathematical_Operators diagonal #⊥⊤#
 
 
-	if (*arg1 == 0 || *arg2 == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP LINK {<DIRECTION>} {<LOCATION>} {BOTH}");
-		return;
-	}
+char *draw_room(struct session *ses, struct room_data *room, int line, int x, int y)
+{
+	static char buf[201], *room_color, room_left[101], room_right[101];
+	int index, symsize = 1, exits, exit1, exit2, room1, room2, offset, flags = 0;
+//	struct room_data * room_grid[11];
 
 
-	room = find_room(ses, arg2);
+	push_call("draw_room(%p,%p,%d,%d,%d)",ses,room,line,x,y);
 
 
-	if (room == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#MAP: Couldn't find room {%s}.", arg1);
-		return;
-	}
+	offset = HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) ? LEGEND_UNICODE : LEGEND_ASCII;
 
 
-	exit = find_exit(ses, ses->map->in_room, arg1);
+	room_color = ses->map->color[MAP_COLOR_ROOM];
 
 
-	if (exit)
+	if (room && room->vnum)
 	{
 	{
-		delete_exit(ses, ses->map->in_room, exit);
-	}
-
-	create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+		symsize = strip_color_strlen(ses, room->symbol);
 
 
-	if (is_abbrev(arg3, "both"))
-	{
-		if ((node = search_node_list(ses->list[LIST_PATHDIR], arg1)) != NULL)
+		if (HAS_BIT(room->flags, ROOM_FLAG_PATH) && room->search_stamp == ses->map->search->stamp)
 		{
 		{
-			if (find_exit(ses, room, node->arg2) == NULL)
+			room_color = ses->map->color[MAP_COLOR_PATH];
+		}
+		else if (*room->color)
+		{
+			room_color = room->color;
+		}
+		else
+		{
+			if (HAS_BIT(room->flags, ROOM_FLAG_INVIS))
 			{
 			{
-				create_exit(ses, room, "{%d} {%s} {%s}", ses->map->in_room, node->arg2, node->arg2);
+				room_color = ses->map->color[MAP_COLOR_INVIS];
+			}
+			else if (HAS_BIT(room->flags, ROOM_FLAG_HIDE))
+			{
+				room_color = ses->map->color[MAP_COLOR_HIDE];
+			}
+			else if (HAS_BIT(room->flags, ROOM_FLAG_AVOID))
+			{
+				room_color = ses->map->color[MAP_COLOR_AVOID];
+			}
+			else if (HAS_BIT(room->flags, ROOM_FLAG_BLOCK))
+			{
+				room_color = ses->map->color[MAP_COLOR_BLOCK];
+			}
+			else if (HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS))
+			{
+				room_color = ses->map->color[MAP_COLOR_SYMBOL];
 			}
 			}
 		}
 		}
-	}
-	show_message(ses, LIST_COMMAND, "#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)
-{
-	struct room_data *room;
-	char var[BUFFER_SIZE];
-	int vnum;
-
-	map_search_compile(ses, "0", var);
 
 
-	searchgrid_find(ses, ses->map->in_room, ses->map->search);
+		if (room->vnum == ses->map->in_room)
+		{
+			if (HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION))
+			{
+				exits = ses->map->dir;
 
 
-	map_search_compile(ses, arg, var);
+				DEL_BIT(exits, MAP_EXIT_U|MAP_EXIT_D);
 
 
-	set_nest_node(ses->list[LIST_VARIABLE], var, "");
+				switch (exits)
+				{
+					case MAP_EXIT_N:
+						index = LEGEND_ASCII_DIRS + 0;
+						break;
+					case MAP_EXIT_N+MAP_EXIT_E:
+						index = LEGEND_ASCII_DIRS + 1;
+						break;
+					case MAP_EXIT_E:
+						index = LEGEND_ASCII_DIRS + 2;
+						break;
+					case MAP_EXIT_S+MAP_EXIT_E:
+						index = LEGEND_ASCII_DIRS + 3;
+						break;
+					case MAP_EXIT_S:
+						index = LEGEND_ASCII_DIRS + 4;
+						break;
+					case MAP_EXIT_W+MAP_EXIT_S:
+						index = LEGEND_ASCII_DIRS + 5;
+						break;
+					case MAP_EXIT_W:
+						index = LEGEND_ASCII_DIRS + 6;
+						break;
+					case MAP_EXIT_W+MAP_EXIT_N:
+						index = LEGEND_ASCII_DIRS + 7;
+						break;
+					default:
+						index = LEGEND_ASCII_MISC + 1;
+						break;
+				}
+			}
+			else
+			{
+				index = LEGEND_ASCII_MISC + 0;
+			}
+		}
+	}
 
 
-	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
 	{
 	{
-		if (match_room(ses, vnum, ses->map->search))
-		{
-			room = ses->map->room_list[vnum];
+		struct room_data *room_n, *room_nw, *room_w;
+		long long exit_n, exit_nw, exit_w;
 
 
-			if (*var)
+		if (room)
+		{
+			if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
 			{
 			{
-				add_nest_node(ses->list[LIST_VARIABLE], var, "{%d} {{distance}{%.3f}{x}{%d}{y}{%d}{z}{%d}}", room->vnum, ses->map->search->stamp == room->search_stamp ? room->length  : -1, room->x, room->y, room->z);
+				sprintf(room_left,  "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RL_CURVED]);
+				sprintf(room_right, "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RR_CURVED]);
 			}
 			}
 			else
 			else
 			{
 			{
-				if (ses->map->search->stamp == room->search_stamp)
-				{
-					if (room->w == 0)
-					{
-						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4d  y: %4d  z: %4d  name: %s", room->vnum, room->length, room->x, room->y, room->z, room->name);
-					}
-					else
-					{
-						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4s  y: %4s  z: %4s  name: %s", room->vnum, room->length, "?", "?", "?", room->name);
-					}
-				}
-				else
-				{
-						tintin_printf2(ses, "vnum: %5d  dist: %8.8s  x:    ?  y:    ?  z:    ?  name: %s", room->vnum, "-1", room->name);
-				}
+				
+				sprintf(room_left,  "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RL]);
+				sprintf(room_right, "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RR]);
 			}
 			}
 		}
 		}
-	}
-}
+		room_n  = ses->map->grid_rooms[x + 0 + map_grid_x * (y + 1)];
+		room_nw = ses->map->grid_rooms[x - 1 + map_grid_x * (y + 1)];
+		room_w  = ses->map->grid_rooms[x - 1 + map_grid_x * (y + 0)];
 
 
-DO_MAP(map_map)
-{
-	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
-	FILE *logfile = NULL;
-	int x, y, line, row;
+		exit_n = exit_nw = exit_w = 0;
 
 
-	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);
-	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
+		if (room_nw && room_nw->exit_grid[EXIT_GRID_SE])
+		{
+			SET_BIT(exit_nw, UNICODE_DIR_SE);
+		}
 
 
-	push_call("map_map(%p,%p)",ses,arg);
+		if (room_w && room_w->exit_grid[EXIT_GRID_NE])
+		{
+			SET_BIT(exit_nw, UNICODE_DIR_NE);
+		}
 
 
-	if (is_math(ses, arg1))
-	{
-		map_grid_y = get_number(ses, arg1);
+		if (room_n && room_n->exit_grid[EXIT_GRID_SW])
+		{
+			SET_BIT(exit_nw, UNICODE_DIR_SW);
+		}
 
 
-		if (map_grid_y <= 0)
+		if (room && HAS_BIT(room->exit_dirs, MAP_DIR_NW))
 		{
 		{
-			map_grid_y = UMAX(0, get_scroll_rows(ses) + map_grid_y);
+			SET_BIT(exit_nw, UNICODE_DIR_NW);
 		}
 		}
-	}
-	else
-	{
-		map_grid_y = get_scroll_rows(ses);
-	}
 
 
-	if (is_math(ses, arg2))
-	{
-		map_grid_x = get_number(ses, arg2);
 
 
-		if (map_grid_x <= 0)
+		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_D))
 		{
 		{
-			map_grid_x = UMAX(0, gtd->screen->cols + map_grid_x);
+			SET_BIT(exit_n, MAP_DIR_D);
 		}
 		}
-	}
-	else
-	{
-		map_grid_x = get_scroll_cols(ses);
-	}
 
 
-	if (*arg3)
-	{
-		switch (*arg3)
+		if (room && room->exit_grid[EXIT_GRID_N])
 		{
 		{
-			case 'a':
-			case 'A':
-
-				strcpy(arg3, "APPEND");
+			SET_BIT(exit_n, MAP_DIR_N);
+		}
 
 
-				logfile = fopen(arg4, "a");
+		if (room_n && room_n->exit_grid[EXIT_GRID_S])
+		{
+			SET_BIT(exit_n, MAP_DIR_S);
+		}
 
 
-				loginit(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+		if (room && room->exit_grid[EXIT_GRID_W])
+		{
+			SET_BIT(exit_w, UNICODE_DIR_W);
+		}
 
 
-				break;
+		if (room_w && room_w->exit_grid[EXIT_GRID_E])
+		{
+			SET_BIT(exit_w, UNICODE_DIR_E);
+		}
 
 
-			case 'd':
-			case 'D':
-				strcpy(arg3, "DRAW");
+		sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
 
 
-				if (*arg4 == 0)
+		switch (line)
+		{
+			case 1:
+				switch (exit_nw)
 				{
 				{
-					show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {square}", arg1, arg2, arg3);
-					pop_call();
-					return;
-				}
-				break;
+					case 0:
+						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
+						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
+						break;
 
 
-			case 'o':
-			case 'O':
-				strcpy(arg3, "OVERWRITE");
+					case UNICODE_DIR_SE:
+						cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE]);
+						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+						break;
+					case UNICODE_DIR_NE:
+						cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NE]);
+						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+						break;
+					case UNICODE_DIR_SE|UNICODE_DIR_NE:
+						cat_sprintf(buf, "%s%s", room_nw->length < room_w->length ? get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]) : get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE + UNICODE_DIR_NE]);
+						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+						break;
 
 
-				logfile = fopen(arg4, "w");
+					case UNICODE_DIR_SE|UNICODE_DIR_NW:
+						cat_sprintf(buf, "%s%s", room_nw->length < room->length ? get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]) : get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE + UNICODE_DIR_NW]);
+						break;
 
 
-				loginit(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+					case UNICODE_DIR_NE|UNICODE_DIR_SW:
+						cat_sprintf(buf, "%s%s", room_w->length < room_n->length ? get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]) : get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NE + UNICODE_DIR_SW]);
+						break;
+//
+					case UNICODE_DIR_NE|UNICODE_DIR_NW:
+						cat_sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NE], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NW]);
+						break;
 
 
-				break;
+					case UNICODE_DIR_NE|UNICODE_DIR_SW|UNICODE_DIR_NW:
+						cat_sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NE], room_n->length < room->length ? get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]) : get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NW + UNICODE_DIR_SW]);
+						break;
 
 
-			case 'l':
-			case 'L':
-				strcpy(arg3, "LIST");
-				break;
+					case UNICODE_DIR_SE|UNICODE_DIR_SW:
+						cat_sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE], get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SW]);
+						break;
 
 
-			case 'v':
-			case 'V':
-				strcpy(arg3, "VARIABLE");
-				break;
+					case UNICODE_DIR_SE|UNICODE_DIR_SW|UNICODE_DIR_NW:
+						cat_sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE], room_n->length < room->length ? get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]) : get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NW + UNICODE_DIR_SW]);
+						break;
 
 
-			default:
-				show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {rows} {cols} {append|overwrite|list|variable} {name}");
-				pop_call();
-				return;
-		}
+					case UNICODE_DIR_SE|UNICODE_DIR_NE|UNICODE_DIR_SW:
+						cat_sprintf(buf, "%s%s%s%s", room_nw->length < room_w->length ? get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]) : get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE + UNICODE_DIR_NE], get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SW]);
+						break;
 
 
-		if (*arg4 == 0)
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {name}", arg1, arg2, arg3);
-			pop_call();
-			return;
-		}
-	}
+					case UNICODE_DIR_SE|UNICODE_DIR_NE|UNICODE_DIR_NW:
+						cat_sprintf(buf, "%s%s%s%s", room_nw->length < room_w->length ? get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]) : get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE + UNICODE_DIR_NE], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NW]);
+						break;
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
-	{
-		map_grid_y = 2 + map_grid_y / 3;
-		map_grid_x = 2 + map_grid_x / 6;
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
-	{
-		map_grid_y = 2 + map_grid_y / 2;
-		map_grid_x = 2 + map_grid_x / 5;
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
-	{
-		map_grid_y = 2 + map_grid_y / 2;
-		map_grid_x = 2 + map_grid_x / 5;
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
-	{
-		map_grid_y = 2 + map_grid_y / 1;
-		map_grid_x = 2 + map_grid_x / 2;
-	}
-	else
-	{
-		map_grid_y = 2 + map_grid_y;
-		map_grid_x = 2 + map_grid_x;
-	}
+					case UNICODE_DIR_SW:
+						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, flags));
+						cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SW]);
+						break;
 
 
-	if (map_grid_x > ses->map->max_grid_x || map_grid_y > ses->map->max_grid_y)
-	{
-		if (map_grid_x > ses->map->max_grid_x)
-		{
-			ses->map->max_grid_x = map_grid_x + 1;
-		}
-		if (map_grid_y > ses->map->max_grid_y)
-		{
-			ses->map->max_grid_y = map_grid_y + 1;
-		}
+					case UNICODE_DIR_NW:
+						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, flags));
+						cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NW]);
+						break;
 
 
-		ses->map->grid_rooms = (struct room_data **) realloc(ses->map->grid_rooms, ses->map->max_grid_x * ses->map->max_grid_y * sizeof(struct room_data *));
-		ses->map->grid_flags =               (int *) realloc(ses->map->grid_flags, ses->map->max_grid_x * ses->map->max_grid_y * sizeof(int));
-	}
-
-	displaygrid_build(ses, ses->map->in_room, map_grid_x, map_grid_y, 0);
-
-	*arg1 = row = 0;
-
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
-	{
-		for (y = map_grid_y - 2 ; y >= 1 ; y--)
-		{
-			for (line = 1 ; line <= 3 ; line++)
-			{
-				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+					case UNICODE_DIR_SW|UNICODE_DIR_NW:
+						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, flags));
+						cat_sprintf(buf, "%s%s", room_n->length < room->length ? get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]) : get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SW + UNICODE_DIR_NW]);
+						break;
 
 
-				for (x = 1 ; x < map_grid_x - 1 ; x++)
-				{
-					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+					case UNICODE_DIR_NW|UNICODE_DIR_SE|UNICODE_DIR_NE|UNICODE_DIR_SW:
+//						cat_sprintf(buf, "ᐳᐸ");
+						cat_sprintf(buf, "%s%s%s%s", room_nw->length < room_w->length ? get_exit_color(ses, 0, room_nw->exit_grid[EXIT_GRID_SE]) : get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_NE]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_SE + UNICODE_DIR_NE], room_n->length < room->length ? get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_SW]) : get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NW + UNICODE_DIR_SW]);
+						break;
+					default:
+						cat_sprintf(buf, "??");
+						break;
 				}
 				}
 
 
-				str_clone(&gtd->out, gtd->buf);
-
-				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
-
-				if (logfile)
+				if (!HAS_BIT(exit_n, MAP_DIR_D) && !HAS_BIT(exit_n, MAP_DIR_N|MAP_DIR_S))
 				{
 				{
-					logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
+					strcat(buf, draw_terrain_symbol(ses, room, line, 3, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 4, x, y, TERRAIN_FLAG_DOUBLE));
 				}
 				}
-				else if (*arg3 == 'L')
+				else
 				{
 				{
-					cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
+					if (HAS_BIT(exit_n, MAP_DIR_D))
+					{
+						cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_D]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_D]);
+					}
+					else
+					{
+						strcat(buf, draw_terrain_symbol(ses, room, line, 3, x, y, flags));
+					}
+
+					switch (HAS_BIT(exit_n, MAP_DIR_N|MAP_DIR_S))
+					{
+						case MAP_DIR_N:
+							cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_N]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_N]);
+							break;
+						case MAP_DIR_S:
+							cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room_n->exit_grid[EXIT_GRID_S]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_S]);
+							break;
+						case MAP_DIR_N|MAP_DIR_S:
+							cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_N]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_NS]);
+							break;
+						default:
+							strcat(buf, draw_terrain_symbol(ses, room, line, 4, x, y, flags));
+							break;
+					}
 				}
 				}
-				else if (*arg3 == 'V' || *arg3 == 'D')
+
+				if (room && room->exit_grid[EXIT_GRID_U])
 				{
 				{
-					cat_sprintf(arg1, "%s\n", gtd->out);
+					cat_sprintf(buf, "%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_U]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_U]);
 				}
 				}
 				else
 				else
 				{
 				{
-					tintin_puts2(ses, gtd->out);
+					strcat(buf, draw_terrain_symbol(ses, room, line, 5, x, y, flags));
 				}
 				}
-			}
-		}
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) || HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
-	{
-		for (y = map_grid_y - 2 ; y >= 1 ; y--)
-		{
-			for (line = 1 ; line <= 2 ; line++)
-			{
-				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+				break;
 
 
-				for (x = 1 ; x < map_grid_x - 1 ; x++)
+			case 2:
+				buf[0] = 0;
+
+				if (room == NULL || room->vnum == 0)
 				{
 				{
-					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
-				}
+					if (HAS_BIT(exit_w, MAP_DIR_W))
+					{
+						sprintf(buf, "%s%s%s",
+							get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E],
+							draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+					}
+					else
+					{
+						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
+						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
+					}
+					strcat(buf, draw_terrain_symbol(ses, room, line, 3, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 4, x, y, TERRAIN_FLAG_DOUBLE));
 
 
-				str_clone(&gtd->out, gtd->buf);
+					strcat(buf, draw_terrain_symbol(ses, room, line, 5, x, y, flags));
 
 
-				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
+					pop_call();
+					return buf;
+				}
 
 
-				if (logfile)
+				switch (exit_w)
 				{
 				{
-					fprintf(logfile, "%s\n", gtd->out);
+					case 0:
+						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
+						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
+						break;
+					case UNICODE_DIR_E:
+						sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+						break;
+					case UNICODE_DIR_W:
+						sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), draw_terrain_symbol(ses, room, line, 1, x, y, flags), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
+						break;
+					case UNICODE_DIR_E|UNICODE_DIR_W:
+						if (room->exit_grid[EXIT_GRID_W]->vnum == room_w->vnum && room_w->exit_grid[EXIT_GRID_E]->vnum == room->vnum)
+						{
+							// ‒‒
+							sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_EW], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_EW]);
+						}
+						else
+						{
+							sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
+						}
+						break;
+					default:
+						strcat(buf, "??");
+						break;
 				}
 				}
-				else if (*arg3 == 'L')
+
+				if (room->vnum == ses->map->in_room)
 				{
 				{
-					cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
+					cat_sprintf(buf, "%s%s%s%s", room_left, ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index], room_right);
 				}
 				}
-				else if (*arg3 == 'V' || *arg3 == 'D')
+				else if (symsize > 3)
 				{
 				{
-					cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
+					cat_sprintf(buf, "%s%-3s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
 				}
 				}
 				else
 				else
 				{
 				{
-					tintin_puts2(ses, gtd->out);
+					if (symsize > 1)
+					{
+						cat_sprintf(buf, "%s%-3s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
+					}
+					else if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
+					{
+						if (HAS_BIT(room->exit_dirs, MAP_DIR_W))
+						{
+							cat_sprintf(buf, "%s─", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]));
+						}
+						else
+						{
+							cat_sprintf(buf, " ");
+						}
+
+						if (*room->symbol != ' ' && symsize == 1)
+						{
+							cat_sprintf(buf, "%s%-1s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
+						}
+						else
+						{
+							if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W) == (MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W))
+							{
+								if (get_exit_length(ses, room->exit_grid[EXIT_GRID_N]) < get_exit_length(ses, room->exit_grid[EXIT_GRID_W]))
+								{
+									cat_sprintf(buf, "%s│", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_N]));
+								}
+								else
+								{
+									cat_sprintf(buf, "%s─", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]));
+								}
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_E|MAP_DIR_W) == (MAP_DIR_E|MAP_DIR_W))
+							{
+								cat_sprintf(buf, "%s─", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_S) == (MAP_DIR_N|MAP_DIR_S))
+							{
+								cat_sprintf(buf, "%s│", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_N]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW) == (MAP_DIR_S))
+							{
+								cat_sprintf(buf, "%s│", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_S]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW) == (MAP_DIR_N))
+							{
+								cat_sprintf(buf, "%s│", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_N]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW) == (MAP_DIR_E))
+							{
+								cat_sprintf(buf, "%s─", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_E]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW) == (MAP_DIR_W))
+							{
+								cat_sprintf(buf, "%s─", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW) == (MAP_DIR_N|MAP_DIR_E|MAP_DIR_W))
+							{
+								cat_sprintf(buf, "%s├", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_N]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW) == (MAP_DIR_S|MAP_DIR_E|MAP_DIR_W))
+							{
+								cat_sprintf(buf, "%s┬", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_E]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_NW|MAP_DIR_SW) && HAS_BIT(room->exit_dirs, MAP_DIR_E))
+							{
+								cat_sprintf(buf, "%s─", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_E]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_NE))
+							{
+								cat_sprintf(buf, "%s╴", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NE]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_SE))
+							{
+								cat_sprintf(buf, "%s╴", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_SE]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_SW))
+							{
+								cat_sprintf(buf, "%s╴", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_SW]));
+							}
+							else if (HAS_BIT(room->exit_dirs, MAP_DIR_NW))
+							{
+								cat_sprintf(buf, "%s╴", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_NW]));
+							}
+							else
+							{
+								cat_sprintf(buf, " ");
+							}
+						}
+
+						if (HAS_BIT(room->exit_dirs, MAP_DIR_E))
+						{
+							cat_sprintf(buf, "%s─", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_E]));
+						}
+						else
+						{
+							cat_sprintf(buf, " ");
+						}
+					}
+					else
+					{
+						cat_sprintf(buf, "%s%s%-1s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, room_right);
+					}
 				}
 				}
-			}
+				cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_BACK]);
+
+				break;
 		}
 		}
+		pop_call();
+		return buf;
 	}
 	}
-	else
-	{
-		for (y = map_grid_y - 2 ; y >= 1 ; y--)
-		{
-			str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
 
 
-			for (x = 1 ; x < map_grid_x - 1 ; x++)
-			{
-				str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
-			}
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
+	{
+		struct room_data *room_w;
+		long long exit_w;
 
 
-			substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
+		room_w = ses->map->grid_rooms[x - 1 + map_grid_x * (y + 0)];
+		exit_w = 0;
 
 
-			if (logfile)
-			{
-				fprintf(logfile, "%s\n", gtd->out);
-			}
-			else if (*arg3 == 'L')
-			{
-				cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
-			}
-			else if (*arg3 == 'V' || *arg3 == 'D')
+		if (room_w)
+		{
+			if (HAS_BIT(room_w->exit_dirs, MAP_DIR_E))
 			{
 			{
-				cat_sprintf(arg1, "%s\n", gtd->out);
+				SET_BIT(exit_w, MAP_DIR_E);
 			}
 			}
-			else
+			if (HAS_BIT(room_w->exit_dirs, MAP_DIR_U))
 			{
 			{
-				tintin_puts2(ses, gtd->out);
+				SET_BIT(exit_w, MAP_DIR_U);
 			}
 			}
 		}
 		}
-	}
-
-	if (logfile)
-	{
-		fclose(logfile);
-	}
-	else if (*arg3 == 'D')
-	{
-		draw_map(ses, 1, 2, 3, 4, 5, 6, 7, "", arg4, arg2, arg1);
-	}
-	else if (*arg3 == 'L')
-	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg4, "%s", arg1);
-	}
-	else if (*arg3 == 'V')
-	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg4, "%s", arg1);
-	}
-
-	pop_call();
-	return;
-}
 
 
-DO_MAP(map_move)
-{
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+		sprintf(buf, "%s", room_color);
 
 
-	arg = arg1;
+		switch (line)
+		{
+			case 1:
+				switch (exit_w)
+				{
+					case 0:
+						strcat(buf, " ");
+						break;
+					case MAP_DIR_E:
+						strcat(buf, "═");
+						break;
+					case MAP_DIR_E|MAP_DIR_U:
+						strcat(buf, "═̂");
+						break;
+					case MAP_DIR_U:
+						strcat(buf, " ̂");
+						break;
+					default:
+						strcat(buf, "?");
+						break;
+				}
 
 
-	while (*arg)
-	{
-		arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
+				if (room == NULL)
+				{
+					strcat(buf, "    ");
+				}
+				else
+				{
+					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_W) ? "═" : " ");
 
 
-		ses->map->nofollow++;
+					if (room->vnum == ses->map->in_room)
+					{
+						cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_USER]);
+					}
 
 
-		follow_map(ses, arg2);
-
-		ses->map->nofollow--;
-
-		if (*arg == COMMAND_SEPARATOR)
-		{
-			arg++;
-		}
-	}
-}
-
-DO_MAP(map_name)
-{
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-
-	RESTRING(ses->map->room_list[ses->map->in_room]->name, arg1);
-}
-
-DO_MAP(map_offset)
-{
-	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
-
-	if (arg)
-	{
-		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);
-		arg = sub_arg_in_braces(ses, arg, arg4, GET_ONE, SUB_VAR|SUB_FUN);
-
-		ses->map->sav_top_row = get_number(ses, arg1);
-		ses->map->sav_top_col = get_number(ses, arg2);
-		ses->map->sav_bot_row = get_number(ses, arg3);
-		ses->map->sav_bot_col = get_number(ses, arg4);
-	}
+					switch (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_W))
+					{
+						case MAP_DIR_N:
+							strcat(buf, "║");
+							break;
+						case MAP_DIR_W:
+							strcat(buf, "═");
+							break;
+						case MAP_DIR_N|MAP_DIR_W:
+							strcat(buf, "╝");
+							break;
+						default:
+							strcat(buf, "╔");
+							break;
+					}
 
 
-	if (ses->map->sav_top_row == 0)
-	{
-		ses->map->top_row = 1;
-	}
-	else if (ses->map->sav_top_row < 0)
-	{
-		ses->map->top_row = 1 + gtd->screen->rows + ses->map->sav_top_row;
-	}
-	else
-	{
-		ses->map->top_row = ses->map->sav_top_row;
-	}
 
 
-	if (ses->map->sav_top_col == 0)
-	{
-		ses->map->top_col = 1;
-	}
-	else if (ses->map->sav_top_col < 0)
-	{
-		ses->map->top_col = 1 + gtd->screen->cols + ses->map->sav_top_col;
-	}
-	else
-	{
-		ses->map->top_col = ses->map->sav_top_col;
-	}
+					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_N) ? " " : "═");
 
 
-	if (ses->map->sav_bot_row == 0)
-	{
-		ses->map->bot_row = ses->split->top_row - 1;
-	}
-	else if (ses->map->sav_bot_row < 0)
-	{
-		ses->map->bot_row = 1 + gtd->screen->rows + ses->map->sav_bot_row;
-	}
-	else
-	{
-		ses->map->bot_row = ses->map->sav_bot_row;
-	}
 
 
-	if (ses->map->sav_bot_col == 0)
-	{
-		ses->map->bot_col = gtd->screen->cols;
-	}
-	else if (ses->map->sav_bot_col < 0)
-	{
-		ses->map->bot_col = 1 + gtd->screen->cols + ses->map->sav_bot_col;
-	}
-	else
-	{
-		ses->map->bot_col = ses->map->sav_bot_col;
-	}
+					switch (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E))
+					{
+						case MAP_DIR_N:
+							strcat(buf, "║");
+							break;
+						case MAP_DIR_E:
+							strcat(buf, "═");
+							break;
+						case MAP_DIR_N|MAP_DIR_E:
+							strcat(buf, "╚");
+							break;
+						default:
+							strcat(buf, "╗");
+							break;
+					}
+				}
+				break;
 
 
-	ses->map->rows = ses->map->bot_row - ses->map->top_row;
-	ses->map->cols = ses->map->bot_col - ses->map->top_col;
+			case 2:
+				switch (exit_w)
+				{
+					case 0:
+						strcat(buf, " ");
+						break;
+					case MAP_DIR_E:
+						strcat(buf, "═");
+						break;
+					case MAP_DIR_E|MAP_DIR_U:
+						strcat(buf, "═");
+						break;
+					default:
+						strcat(buf, " ");
+						break;
+				}
 
 
-	if (arg)
-	{
-		show_message(ses, LIST_COMMAND, "#MAP OFFSET: SQUARE {%d, %d, %d, %d} ROWS {%d} COLS {%d}", ses->map->top_row, ses->map->top_col, ses->map->bot_row, ses->map->bot_col, ses->map->rows, ses->map->cols);
-	}
-}
+				if (room == NULL)
+				{
+					strcat(buf, " ");
+				}
+				else
+				{
+					switch (HAS_BIT(room->exit_dirs, MAP_DIR_W|MAP_DIR_D))
+					{
+						case MAP_DIR_W:
+							strcat(buf, "═");
+							break;
+						case MAP_DIR_W|MAP_DIR_D:
+							strcat(buf, "═̬");
+							break;
+						case MAP_DIR_D:
+							strcat(buf, " ̬");
+							break;
+						default:
+							strcat(buf, " ");
+							break;
+					}
+				}
 
 
-DO_MAP(map_read)
-{
-	FILE *myfile;
-	struct exit_data *exit;
-	char buffer[BUFFER_SIZE], file[BUFFER_SIZE], *cptr;
-	int line = 1, room = 0;
+				if (room == NULL)
+				{
+					strcat(buf, "   ");
+				}
+				else
+				{
+					if (room->vnum == ses->map->in_room)
+					{
+						cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_USER]);
+					}
 
 
-	arg = sub_arg_in_braces(ses, arg, file, GET_ALL, SUB_VAR|SUB_FUN);
+					switch (HAS_BIT(room->exit_dirs, MAP_DIR_S|MAP_DIR_W))
+					{
+						case MAP_DIR_S:
+							strcat(buf, "║");
+							break;
+						case MAP_DIR_W:
+							strcat(buf, "═");
+							break;
+						case MAP_DIR_S|MAP_DIR_W:
+							strcat(buf, "╗");
+								break;
+						default:
+							strcat(buf, "╚");
+							break;
+					}
 
 
-	if ((myfile = fopen(file, "r")) == NULL)
-	{
-		show_error(ses, LIST_COMMAND, "#MAP: Map file {%s} not found.", file);
+					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_S) ? " " : "═");
 
 
-		return;
+					switch (HAS_BIT(room->exit_dirs, MAP_DIR_S|MAP_DIR_E))
+					{
+						case MAP_DIR_S:
+							strcat(buf, "║");
+							break;
+						case MAP_DIR_E:
+							strcat(buf, "═");
+							break;
+						case MAP_DIR_S|MAP_DIR_E:
+							strcat(buf, "╔");
+							break;
+						default:
+							strcat(buf, "╝");
+							break;
+					}
+				}
+				break;
+		}
+		pop_call();
+		return buf;
 	}
 	}
 
 
-	gtd->level->quiet++;
-
-	if (fgets(buffer, BUFFER_SIZE - 1, myfile))
+	if (room == NULL || room->vnum == 0)
 	{
 	{
-		cptr = strchr(buffer, '\r'); /* For map files editor on Windows systems. */
-
-		if (cptr)
+		if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 		{
 		{
-			*cptr = 0;
-		}
-
-		cptr = strchr(buffer, '\n');
+			strcpy(buf, "");
 
 
-		if (cptr)
-		{
-			*cptr = 0;
+			for (index = 1 ; index <= 6 ; index++)
+			{
+				strcat(buf, draw_terrain_symbol(ses, room, line, index, x, y, TERRAIN_FLAG_DOUBLE));
+			}
 		}
 		}
-
-		if (buffer[0] == 'C' && buffer[1] == ' ')
+		else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
 		{
 		{
-			create_map(ses, buffer + 2);
+			sprintf(buf, "  ");
 		}
 		}
 		else
 		else
 		{
 		{
-			gtd->level->quiet--;
-
-			show_error(ses, LIST_COMMAND, "#MAP READ {%s}: INVALID START OF FILE. ABORTING READ..", file);
-
-			fclose(myfile);
-
-			return;
+			sprintf(buf, " ");
 		}
 		}
+		pop_call();
+		return buf;
 	}
 	}
-	else
-	{
-		gtd->level->quiet--;
-
-		show_error(ses, LIST_COMMAND, "#MAP: INVALID READ ON LINE %d. ABORTING READ..", line);
 
 
-		fclose(myfile);
-		
-		return;
-	}
 
 
-	while (fgets(buffer, BUFFER_SIZE - 1, myfile))
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
 	{
-		line++;
+		strcpy(buf, "");
 
 
-		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])
+		switch (line)
 		{
 		{
-			case 'C':
-				switch (buffer[1])
+			case 1:
+				if (room->exit_grid[EXIT_GRID_NW])
 				{
 				{
-					case ' ':
-						gtd->level->quiet--;
-
-						show_error(ses, LIST_COMMAND, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
-
-						fclose(myfile);
-
-						delete_map(ses);
-
-						return;
-
-					case 'A':
-					case 'B':
-					case 'E':
-					case 'H':
-					case 'I':
-					case 'P':
-					case 'R':
-					case 'S':
-					case 'U':
-						map_color(ses, buffer + 1, arg1, arg2);
-						break;
-
-					default:
-						show_error(ses, LIST_COMMAND, "#MAP READ: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
-						break;
+					strcat(buf, get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_NW]));
+					strcat(buf, "\\");
+					strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+				}
+				else
+				{
+					strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
 				}
 				}
-				break;
-
-			case 'E':
-				create_exit(ses, room, "%s", buffer + 2);
-				break;
-
-			case 'F':
-				ses->map->flags = atoi(buffer + 2);
-				break;
 
 
-			case 'G':
-				ses->map->global_vnum = ses->map->global_exit->vnum = atoi(buffer + 2);
-				break;
+				if (room->exit_grid[EXIT_GRID_N] || room->exit_grid[EXIT_GRID_U])
+				{
+					cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_N]), room->exit_grid[EXIT_GRID_N]  ? "|"  : draw_terrain_symbol(ses, room, line, 3, x, y, flags));
+					cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_U]), room->exit_grid[EXIT_GRID_U]  ? "+"  : draw_terrain_symbol(ses, room, line, 4, x, y, flags));
+				}
+				else
+				{
+					strcat(buf, draw_terrain_symbol(ses, room, line, 3, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 4, x, y, TERRAIN_FLAG_DOUBLE));
+				}
 
 
-			case 'I':
-				ses->map->last_room = atoi(buffer + 2);
+				if (room->exit_grid[EXIT_GRID_NE])
+				{
+					cat_sprintf(buf, "%s%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_NE]), "/", draw_terrain_symbol(ses, room, line, 6, x, y, flags));
+				}
+				else
+				{
+					strcat(buf, draw_terrain_symbol(ses, room, line, 5, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 6, x, y, TERRAIN_FLAG_DOUBLE));
+				}
 				break;
 				break;
 
 
-			case 'L':
-				map_legend(ses, buffer + 2, arg1, arg2);
-				break;
+			case 2:
+				if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
+				{
+					sprintf(room_left,  "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RL_CURVED]);
+					sprintf(room_right, "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RR_CURVED]);
+				}
+				else
+				{
+					sprintf(room_left,  "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RL]);
+					sprintf(room_right, "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RR]);
+				}
 
 
-			case 'R':
-				room = create_room(ses, "%s", buffer + 2);
-				break;
+				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) && symsize <= 3)
+				{
+					cat_sprintf(buf, "%s%s",
+						get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_W]),
+						room->exit_grid[EXIT_GRID_W]  ? "-"  : draw_terrain_symbol(ses, room, line, 1, x, y, flags));
+				}
 
 
-			case 'V':
-				ses->map->version = atoi(buffer + 2);
-				break;
+				if (room->vnum == ses->map->in_room)
+				{
+					if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
+					{
+						cat_sprintf(buf, "%s%s%s%s", room_left, ses->map->color[MAP_COLOR_USER], ses->map->legend[index], room_right);
+					}
+					else
+					{
+						if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIILENGTH))
+						{
+							cat_sprintf(buf, "%s%5.1f", ses->map->color[MAP_COLOR_USER], room->length, ses->map->color[MAP_COLOR_EXIT]);
+						}
+						else
+						{
+							cat_sprintf(buf, "%s%05d", ses->map->color[MAP_COLOR_USER], room->vnum);
+						}
+					}
+				}
+				else
+				{
+					if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
+					{
+						if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIILENGTH))
+						{
+							cat_sprintf(buf, "%s%5.1f%s", ses->map->color[MAP_COLOR_USER], room->length, ses->map->color[MAP_COLOR_EXIT]);
+						}
+						else
+						{
+							cat_sprintf(buf, "%s%05d%s", room_color, room->vnum, ses->map->color[MAP_COLOR_EXIT]);
+						}
+					}
+					else if (symsize > 3)
+					{
+						cat_sprintf(buf, "%s%-5s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
+					}
+					else if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
+					{
+						if (*room->symbol != ' ' && symsize == 1)
+						{
+							if (room->exit_dirs == (MAP_DIR_E|MAP_DIR_W))
+							{
+								cat_sprintf(buf, "%s-%s%s%s-", ses->map->color[MAP_COLOR_EXIT], ses->map->color[MAP_COLOR_SYMBOL], room->symbol, ses->map->color[MAP_COLOR_EXIT]);
+							}
+							else
+							{
+								cat_sprintf(buf, "%s %-2s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
+							}
+						}
+						else if (*room->symbol != ' ' && strip_color_strlen(ses, room->symbol) > 1)
+						{
+							cat_sprintf(buf, "%s %-2s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
+						}
+						else
+						{
+							strcat(buf, ses->map->color[MAP_COLOR_EXIT]);
 
 
-			case '#':
-				buffer[0] = gtd->tintin_char;
-				ses = script_driver(ses, LIST_COMMAND, buffer);
-				break;
+							switch (room->exit_dirs)
+							{
+								case MAP_DIR_N|MAP_DIR_S:
+									cat_sprintf(buf, " | ");
+									break;
+								case MAP_DIR_E|MAP_DIR_W:
+									cat_sprintf(buf, "---");
+									break;
+								case MAP_DIR_NE|MAP_DIR_SW:
+									cat_sprintf(buf, " / ");
+									break;
+								case MAP_DIR_NW|MAP_DIR_SE:
+									cat_sprintf(buf, " \\ ");
+									break;
+								default:
+									cat_sprintf(buf, " * ");
+									break;
+							}
+						}
+					}
+					else
+					{
+						if (strip_color_strlen(ses, room->symbol) <= 1)
+						{
+							cat_sprintf(buf, "%s%s%-1s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, room_right);
+						}
+						else
+						{
+							cat_sprintf(buf, "%s%s%-3s", room_color, ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
+						}
+					}
+				}
 
 
-			case  0:
-			case 13:
+				if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) || symsize > 3)
+				{
+					cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_E]), room->exit_grid[EXIT_GRID_E] ? "-" : draw_terrain_symbol(ses, room, line, 6, x, y, flags));
+				}
+				else
+				{
+					if (room->exit_grid[EXIT_GRID_E])
+					{
+						cat_sprintf(buf, "%s--", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_E]));
+					}
+					else
+					{
+						strcat(buf, draw_terrain_symbol(ses, room, line, 5, x, y, TERRAIN_FLAG_DOUBLE));
+						strcat(buf, draw_terrain_symbol(ses, room, line, 6, x, y, TERRAIN_FLAG_DOUBLE));
+					}
+				}
 				break;
 				break;
 
 
-			default:
-				gtd->level->quiet--;
-
-				show_error(ses, LIST_COMMAND, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
-
-				fclose(myfile);
-
-				delete_map(ses);
-
-				return;
-		}
-	}
-
-	gtd->level->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)
-			{
-				show_error(ses, LIST_COMMAND, "#MAP READ: Room %d - invalid exit '%s' to room %d.", room, exit->name, exit->vnum);
+			case 3:
+				if (room->exit_grid[EXIT_GRID_SW] || room->exit_grid[EXIT_GRID_D])
+				{
+					cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_SW]), room->exit_grid[EXIT_GRID_SW] ? "/"  : draw_terrain_symbol(ses, room, line, 1, x, y, flags));
+					cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_D]), room->exit_grid[EXIT_GRID_D]  ? "-"  : draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+				}
+				else
+				{
+					strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
+				}
 
 
-				delete_exit(ses, room, exit);
+				if (room->exit_grid[EXIT_GRID_S])
+				{
+					cat_sprintf(buf, "%s|%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_S]), draw_terrain_symbol(ses, room, line, 4, x, y, flags));
+				}
+				else
+				{
+					strcat(buf, draw_terrain_symbol(ses, room, line, 3, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 4, x, y, TERRAIN_FLAG_DOUBLE));
+				}
 
 
-				if (ses->map->room_list[room]->f_exit)
+				if (room->exit_grid[EXIT_GRID_SE])
 				{
 				{
-					exit = ses->map->room_list[room]->f_exit;
+					cat_sprintf(buf, "%s\\%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_SE]), draw_terrain_symbol(ses, room, line, 6, x, y, flags));
 				}
 				}
 				else
 				else
 				{
 				{
-					break;
+					strcat(buf, draw_terrain_symbol(ses, room, line, 5, x, y, TERRAIN_FLAG_DOUBLE));
+					strcat(buf, draw_terrain_symbol(ses, room, line, 6, x, y, TERRAIN_FLAG_DOUBLE));
 				}
 				}
-			}
+				break;
 		}
 		}
+		pop_call();
+		return buf;
 	}
 	}
 
 
-	show_message(ses, LIST_COMMAND, "#MAP READ: Map file {%s} loaded.", file);
-
-
-}
-
-DO_MAP(map_resize)
-{
-	int size, vnum, room;
 
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+	if (room->vnum == ses->map->in_room)
+	{
+		exits = ses->map->dir;
 
 
-	size = atoi(arg1);
+		DEL_BIT(exits, MAP_EXIT_U|MAP_EXIT_D);
 
 
-	if (size <= ses->map->size)
-	{
-		for (room = vnum = 1 ; vnum < ses->map->size ; vnum++)
+		if (HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION))
 		{
 		{
-			if (ses->map->room_list[vnum])
+			switch (exits)
 			{
 			{
-				room = vnum;
+				case MAP_EXIT_N:
+					index = 24;
+					break;
+				case MAP_EXIT_N+MAP_EXIT_E:
+					index = 25;
+					break;
+				case MAP_EXIT_E:
+					index = 26;
+					break;
+				case MAP_EXIT_S+MAP_EXIT_E:
+					index = 27;
+					break;
+				case MAP_EXIT_S:
+					index = 28;
+					break;
+				case MAP_EXIT_S+MAP_EXIT_W:
+					index = 29;
+					break;
+				case MAP_EXIT_W:
+					index = 30;
+					break;
+				case MAP_EXIT_N+MAP_EXIT_W:
+					index = 31;
+					break;
+
+				default:
+					index = 17;
+					break;
 			}
 			}
 		}
 		}
-
-		if (room >= size)
+		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#MAP RESIZE: YOU MUST DELETE ALL ROOMS WITH VNUMS ABOVE (%d) FIRST.", size);
-			return;
+			index = 16;
 		}
 		}
-	}
 
 
-	ses->map->room_list = (struct room_data **) realloc(ses->map->room_list, size * sizeof(struct room_data *));
-
-	if (ses->map->size < size)
-	{
-		while (ses->map->size < size)
+		if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
 		{
 		{
-			ses->map->room_list[ses->map->size++] = NULL;
+			sprintf(buf, "%s%s%s", ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index], ses->map->legend[offset + index]);
 		}
 		}
+		else
+		{
+			sprintf(buf, "%s%s", ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index]);
+		}
+		pop_call();
+		return buf;
 	}
 	}
-	else
+
+	exit1 = 0;
+	exit2 = 0;
+	exits = 0;
+
+	if (HAS_BIT(room->exit_dirs, MAP_DIR_N))
 	{
 	{
-		ses->map->size = size;
+		SET_BIT(exit1, 1 << 0);
+		SET_BIT(exit2, 1 << 0);
+		SET_BIT(exits, MAP_EXIT_N);
 	}
 	}
 
 
-	show_message(ses, LIST_COMMAND, "#MAP RESIZE: MAP RESIZED TO %d ROOMS.", ses->map->size);
-}
+	if (HAS_BIT(room->exit_dirs, MAP_DIR_W))
+	{
+		SET_BIT(exit1, 1 << 2);
+		SET_BIT(exits, MAP_EXIT_W);
+	}
 
 
-DO_MAP(map_return)
-{
-	if (ses->map == NULL || ses->map->room_list[ses->map->last_room] == NULL)
+	if (HAS_BIT(room->exit_dirs, MAP_DIR_E))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP RETURN: NO KNOWN LAST ROOM.");
+		SET_BIT(exit2, 1 << 2);
+		SET_BIT(exits, MAP_EXIT_E);
+	}
 
 
-		return;
+	if (HAS_BIT(room->exit_dirs, MAP_DIR_S))
+	{
+		SET_BIT(exit1, 1 << 4);
+		SET_BIT(exit2, 1 << 4);
+		SET_BIT(exits, MAP_EXIT_S);
 	}
 	}
 
 
-	if (ses->map->in_room)
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP RETURN: ALREADY IN THE MAP.");
+		if (HAS_BIT(room->exit_dirs, MAP_DIR_NW))
+		{
+			SET_BIT(exit1, 1 << 1);
+		}
+		if (HAS_BIT(room->exit_dirs, MAP_DIR_NE))
+		{
+			SET_BIT(exit2, 1 << 1);
+		}
+		if (HAS_BIT(room->exit_dirs, MAP_DIR_SW))
+		{
+			SET_BIT(exit1, 1 << 3);
+		}
+		if (HAS_BIT(room->exit_dirs, MAP_DIR_SE))
+		{
+			SET_BIT(exit2, 1 << 3);
+		}
+
+		room1 = exit1 + LEGEND_MUDFONT_NWS;
+		room2 = exit2 + LEGEND_MUDFONT_NES;
+
+		if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
+		{
+			room1 += 64;
+			room2 += 64;
+		}
+
+		if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
+		{
+			switch (room->exit_dirs)
+			{
+				case MAP_DIR_N|MAP_DIR_E:
+				case MAP_DIR_N|MAP_DIR_SE:
+					room1 = LEGEND_MUDFONT_CURVED + 0;
+					break;
+				case MAP_DIR_S|MAP_DIR_E:
+				case MAP_DIR_S|MAP_DIR_NE:
+					room1 = LEGEND_MUDFONT_CURVED + 1;
+					break;
+				case MAP_DIR_S|MAP_DIR_W:
+				case MAP_DIR_S|MAP_DIR_NW:
+					room2 = LEGEND_MUDFONT_CURVED + 2;
+					break;
+				case MAP_DIR_N|MAP_DIR_W:
+				case MAP_DIR_N|MAP_DIR_SW:
+					room2 = LEGEND_MUDFONT_CURVED + 3;
+					break;
+			}
+		}
+
+		sprintf(buf, "%s%s%s", room_color, ses->map->legend[room1], ses->map->legend[room2]);
 	}
 	}
 	else
 	else
 	{
 	{
-		goto_room(ses, ses->map->last_room);
-
-		show_message(ses, LIST_COMMAND, "#MAP RETURN: RETURNED TO ROOM %d {%s}.", ses->map->in_room, ses->map->room_list[ses->map->in_room]->name);
+		if (HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) && room->symbol[0] && room->symbol[0] != ' ')
+		{
+			sprintf(buf, "%s%-1s", room_color, room->symbol);
+		}
+		else
+		{
+			if (HAS_BIT(room->flags, ROOM_FLAG_VOID) && (exits == MAP_EXIT_N+MAP_EXIT_S || exits == MAP_EXIT_E+MAP_EXIT_W))
+			{
+				sprintf(buf, "%s%s", room_color, exits == MAP_EXIT_N+MAP_EXIT_S ? ses->map->legend[offset+16+2] : ses->map->legend[offset+16+3]);
+			}
+			else
+			{
+				if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
+				{
+					switch (room->exit_dirs)
+					{
+						case MAP_DIR_N|MAP_DIR_E:
+							exits = 16 + 4;
+							break;
+						case MAP_DIR_S|MAP_DIR_E:
+							exits = 16 + 5;
+							break;
+						case MAP_DIR_S|MAP_DIR_W:
+							exits = 16 + 6;
+							break;
+						case MAP_DIR_N|MAP_DIR_W:
+							exits = 16 + 7;
+							break;
+					}
+				}
+				sprintf(buf, "%s%s", room_color, ses->map->legend[offset + exits]);
+			}
+		}
 	}
 	}
+	pop_call();
+	return buf;
 }
 }
 
 
-DO_MAP(map_roomflag)
+void search_keywords(struct session *ses, char *arg, char *out, char *var)
 {
 {
-	char buf[BUFFER_SIZE], *str, arg3[BUFFER_SIZE];
-	int flag = 0;
+	char buf[MAP_SEARCH_MAX][BUFFER_SIZE], arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	int type, max;
 
 
-	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_ALL, SUB_VAR|SUB_FUN);
+	push_call("search_keywords(%p,%p,%p,%p)",ses,arg,out,var);
 
 
-	if (*arg1 == 0)
+	for (type = 0 ; type < MAP_SEARCH_MAX ; type++)
 	{
 	{
-		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: Invis flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_INVIS) ? "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");
-		tintin_printf2(ses, "#MAP: Curved flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "off");
-		tintin_printf2(ses, "#MAP: NoGlobal flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_NOGLOBAL) ? "ON" : "off");
-		return;
+		buf[type][0] = 0;
 	}
 	}
 
 
-	str = arg1;
+	var[0] = 0;
 
 
-	while (*str)
+	type = 0;
+
+	while (*arg && type < MAP_SEARCH_MAX)
 	{
 	{
-		str = get_arg_in_braces(ses, str, buf, GET_ONE);
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-		if (is_abbrev(buf, "avoid"))
+		if (*arg1 == '{')
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_AVOID);
+			strcpy(arg2, arg1);
+
+			arg = get_arg_in_braces(ses, arg2, arg1, GET_ALL);
 		}
 		}
-		else if (is_abbrev(buf, "curved"))
+
+		if (!strcasecmp(arg1, "roomid"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_CURVED);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_ID], GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
-		else if (is_abbrev(buf, "hide"))
+		else if (!strcasecmp(arg1, "roomname"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_HIDE);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_NAME], GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
-		else if (is_abbrev(buf, "invisible"))
+		else if (!strcasecmp(arg1, "roomexits"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_INVIS);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_EXITS], GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
-		else if (is_abbrev(buf, "leave"))
+		else if (!strcasecmp(arg1, "roomdesc"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_LEAVE);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_DESC], GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
-		else if (is_abbrev(buf, "noglobal"))
+		else if (!strcasecmp(arg1, "roomarea"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_NOGLOBAL);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_AREA], GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
-		else if (is_abbrev(buf, "static"))
+		else if (!strcasecmp(arg1, "roomnote"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_STATIC);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_NOTE], GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
-		else if (is_abbrev(buf, "void"))
+		else if (!strcasecmp(arg1, "roomterrain"))
 		{
 		{
-			SET_BIT(flag, ROOM_FLAG_VOID);
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_TERRAIN], GET_ALL, SUB_VAR|SUB_FUN);
+		}
+		else if (!strcasecmp(arg1, "roomflag"))
+		{
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_FLAG], GET_ALL, SUB_VAR|SUB_FUN);
+		}
+		else if (!strcasecmp(arg1, "variable"))
+		{
+			arg = sub_arg_in_braces(ses, arg, var, GET_ALL, SUB_VAR|SUB_FUN);
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#MAP: Invalid room flag {%s}.", buf);
-
-			return;
+			strcpy(buf[type++], arg1);
 		}
 		}
+	}
 
 
-		if (*str == COMMAND_SEPARATOR)
+	for (max = MAP_SEARCH_MAX - 1 ; max >= 0 ; max--)
+	{
+		if (*buf[max])
 		{
 		{
-			str++;
+			break;
 		}
 		}
 	}
 	}
 
 
-	if (*arg2 == 0)
+	out[0] = 0;
+
+	for (type = 0 ; type <= max ; type++)
 	{
 	{
-		TOG_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);	
+		cat_sprintf(out, "{%s}", buf[type]);
 	}
 	}
-	else if (is_abbrev(arg2, "ON"))
+	pop_call();
+	return;
+}
+
+void map_search_compile(struct session *ses, char *arg, char *var)
+{
+	char tmp[BUFFER_SIZE], buf[BUFFER_SIZE], *ptb;
+	struct listnode *node;
+
+	push_call("map_search_compile(%p,%p,%p)",ses,arg,var);
+
+	search_keywords(ses, arg, tmp, var);
+
+	arg = sub_arg_in_braces(ses, tmp, buf, GET_ALL, SUB_VAR|SUB_FUN); // name
+
+	if (is_math(ses, buf))
 	{
 	{
-		SET_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
+		ses->map->search->vnum = (int) get_number(ses, buf);
 	}
 	}
-	else if (is_abbrev(arg2, "OFF"))
+	else
 	{
 	{
-		DEL_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
+		ses->map->search->vnum = 0;
 	}
 	}
-	else if (is_abbrev(arg2, "GET"))
+
+	if (ses->map->search->vnum)
 	{
 	{
-		if (*arg3 == 0)
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {GET} {<VARIABLE>}.", buf);
-		}
-		else
-		{
-			set_nest_node(ses->list[LIST_VARIABLE], arg3, "%d", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, flag));
-		}
+		pop_call();
 		return;
 		return;
 	}
 	}
-	else
+
+	if (ses->map->search->arg)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {[GET|ON|OFF]}.", buf);
+		free(ses->map->search->arg);
 	}
 	}
 
 
-
-	if (HAS_BIT(flag, ROOM_FLAG_AVOID))
+	if (*buf)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: Avoid flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "ON" : "off");
+		ses->map->search->arg = strdup(buf);
+
+		node = search_node_list(ses->list[LIST_LANDMARK], ses->map->search->arg);
+
+		if (node)
+		{
+			ses->map->search->vnum = node->val32[0];
+
+			if (ses->map->search->vnum)
+			{
+				pop_call();
+				return;
+			}
+		}
 	}
 	}
-	if (HAS_BIT(flag, ROOM_FLAG_CURVED))
+	else
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: Curved flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "off");
+		ses->map->search->arg = NULL;
 	}
 	}
-	if (HAS_BIT(flag, ROOM_FLAG_HIDE))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: Hide flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "ON" : "off");
-	}
-	if (HAS_BIT(flag, ROOM_FLAG_INVIS))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: Invis flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_INVIS) ? "ON" : "off");
-	}
-	if (HAS_BIT(flag, ROOM_FLAG_LEAVE))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: Leave flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE) ? "ON" : "off");
-	}
-	if (HAS_BIT(flag, ROOM_FLAG_NOGLOBAL))
+
+	if (ses->map->search->name)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: NoGlobal flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_NOGLOBAL) ? "ON" : "off");
+		free(ses->map->search->name);
 	}
 	}
-	if (HAS_BIT(flag, ROOM_FLAG_VOID))
+
+	if (*buf)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: Void flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "ON" : "off");
+		strcat(buf, "$");
+
+		ses->map->search->name = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
 	}
 	}
-	if (HAS_BIT(flag, ROOM_FLAG_STATIC))
+	else
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "ON" : "off");
+		ses->map->search->name = NULL;
 	}
 	}
 
 
-}
-
-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, buf, GET_ALL, SUB_VAR|SUB_FUN); // exits
 
 
-	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);
+	ses->map->search->exit_dirs = 0;
+	ses->map->search->exit_size = 0;
 
 
-	if (*arg3)
+	if (ses->map->search->exit_list)
 	{
 	{
-		if (atoi(arg3) > 0 && atoi(arg3) < ses->map->size)
-		{
-			room = ses->map->room_list[atoi(arg3)];
-		}
-		else
-		{
-			room = NULL;
-		}
+		free(ses->map->search->exit_list);
 	}
 	}
 
 
-	if (room == NULL)
-	{
-		show_message(ses, LIST_COMMAND, "#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, "   roomdata: %s", room->data);
-		tintin_printf2(ses, "   roomdesc: %s", room->desc);
-		tintin_printf2(ses, "  roomflags: %d", room->flags);
-		tintin_printf2(ses, "     roomid: %s", room->id);
-		tintin_printf2(ses, "   roomname: %s", room->name);
-		tintin_printf2(ses, "   roomnote: %s", room->note);
-		tintin_printf2(ses, " roomsymbol: %s", room->symbol);
-		tintin_printf2(ses, "roomterrain: %s", room->terrain);
-		tintin_printf2(ses, " roomweight: %.3f", room->weight);
-	}
-	else
+	if (*buf)
 	{
 	{
-		if (is_abbrev(arg1, "roomarea"))
-		{
-			RESTRING(room->area, arg2);
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomarea set to: %s", room->area);
-		}
-		else if (is_abbrev(arg1, "roomcolor"))
-		{
-			RESTRING(room->color, arg2);
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomcolor set to: %s", arg2);
-		}
-		else if (is_abbrev(arg1, "roomdata"))
-		{
-			RESTRING(room->data, arg2);
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomdata set to: %s", arg2);
-		}
-		else if (is_abbrev(arg1, "roomdesc"))
-		{
-			RESTRING(room->desc, arg2);
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomdesc set to: %s", arg2);
-		}
-		else if (is_abbrev(arg1, "roomflags"))
-		{
-			room->flags = (int) get_number(ses, arg2);
-
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomflags set to: %d", room->flags);
-		}
-		else if (is_abbrev(arg1, "roomid"))
-		{
-			RESTRING(room->id, arg2);
-
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomid set to: %s", room->id);
-		}
-		else if (is_abbrev(arg1, "roomname"))
-		{
-			RESTRING(room->name, arg2);
+		struct listnode *node;
+		char exit[BUFFER_SIZE];
+		ptb = buf;
 
 
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomname set to: %s", room->name);
-		}
-		else if (is_abbrev(arg1, "roomnote"))
-		{
-			RESTRING(room->note, arg2);
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomnote set to: %s", arg2);
-		}
-		else if (is_abbrev(arg1, "roomsymbol"))
-		{
-			RESTRING(room->symbol, arg2);
+		tmp[0] = 0;
 
 
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomsymbol set to: %s", room->symbol);
-		}
-		else if (is_abbrev(arg1, "roomterrain"))
-		{
-			RESTRING(room->terrain, arg2);
-			show_message(ses, LIST_COMMAND, "#MAP SET: roomterrain set to: %s", arg2);
-		}
-		else if (is_abbrev(arg1, "roomweight"))
+		if (is_math(ses, buf))
 		{
 		{
-			if (get_number(ses, arg2) < 0.001)
-			{
-				show_message(ses, LIST_COMMAND, "#MAP SET: roomweight should be at least 0.001");
-			}
-			else
-			{
-				room->weight = (float) get_number(ses, arg2);
+			ses->map->search->exit_dirs = get_number(ses, buf);
 
 
-				show_message(ses, LIST_COMMAND, "#MAP SET: roomweight set to: %.3f", room->weight);
-			}
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_N))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_E))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_S))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_W))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_U))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_D))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_NE)) ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_NW)) ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_SE)) ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_SW)) ses->map->search->exit_size++;
 		}
 		}
 		else
 		else
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#MAP SET: unknown option: %s", arg1);
-		}
-	}
-}
+			while (*ptb)
+			{
+				ptb = get_arg_in_braces(ses, ptb, exit, GET_ONE);
 
 
-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);
+				node = search_node_list(ses->list[LIST_PATHDIR], exit);
 
 
-	explore_path(ses, TRUE, arg1, arg2);
-}
+				ses->map->search->exit_size++;
 
 
+				if (node)
+				{
+					SET_BIT(ses->map->search->exit_dirs, 1LL << atoi(node->arg3));
+				}
+				else
+				{
+					SET_BIT(ses->map->search->exit_dirs, 1); // flag indicates no exits
 
 
-DO_MAP(map_uninsert)
-{
-	int room1, room2, room3;
-	struct exit_data *exit1, *exit2, *exit3;
-	struct listnode *node;
+					cat_sprintf(tmp, "{%s}", exit);
+				}
 
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+				if (*ptb == COMMAND_SEPARATOR)
+				{
+					ptb++;
+				}
+			}
+		}
+		ses->map->search->exit_list = strdup(tmp);
+	}
+	else
+	{
+		ses->map->search->exit_list = strdup("");
+	}
 
 
-	room1 = ses->map->in_room;
-	exit1 = find_exit(ses, room1, arg1);
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // desc
 
 
-	node = search_node_list(ses->list[LIST_PATHDIR], arg1);
+	if (ses->map->search->desc)
+	{
+		free(ses->map->search->desc);
+	}
 
 
-	if (exit1 == NULL)
+	if (*buf)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: There is no room in that direction.");
+		strcat(buf, "$");
 
 
-		return;
+		ses->map->search->desc = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
 	}
 	}
-
-	if (node == NULL)
+	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: Given direction must be a pathdir.");
-		return;
+		ses->map->search->desc = NULL;
 	}
 	}
 
 
-	room2 = exit1->vnum;
-	exit2 = find_exit(ses, room2, node->arg1);
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // area
 
 
-	if (exit2 == NULL)
+	if (ses->map->search->area)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: Unable to find backlink room.");
-		return;
+		free(ses->map->search->area);
 	}
 	}
 
 
-	room3 = exit2->vnum;
-	exit3 = find_exit(ses, room3, node->arg2);
-
-	if (exit3 == NULL)
+	if (*buf)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: Unable to find backlink exit.");
+		strcat(buf, "$");
 
 
-		return;
+		ses->map->search->area = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
 	}
 	}
-
-	exit1->vnum = room3;
-	exit3->vnum = room1;
-
-	delete_room(ses, room2, TRUE);
-
-	show_message(ses, LIST_COMMAND, "#MAP UNINSERT: Uninserted room {%d}.", room2);
-}
-
-// 1) timestamp 2) type 3) data
-
-DO_MAP(map_undo)
-{
-	struct link_data *link;
-	struct room_data *room;
-	int undo_flag;
-	struct exit_data *exit1, *exit2, *exit3;
-
-	link = ses->map->undo_tail;
-
-	if (link == NULL)
+	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNDO: No known last move.");
-
-		return;
+		ses->map->search->area = NULL;
 	}
 	}
 
 
-	room = ses->map->room_list[atoi(link->str1)];
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // note
 
 
-	if (room == NULL)
+	if (ses->map->search->note)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNDO: Room %s does not exist.", link->str2);
-		return;
+		free(ses->map->search->note);
 	}
 	}
 
 
-	if (ses->map->room_list[atoi(link->str2)] == NULL)
+	if (*buf)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNDO: Invalid last move.");
-		return;
+		strcat(buf, "$");
+
+		ses->map->search->note = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
+	}
+	else
+	{
+		ses->map->search->note = NULL;
 	}
 	}
 
 
-	undo_flag = atoi(link->str3);
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // terrain
 
 
-	if (HAS_BIT(undo_flag, MAP_UNDO_MOVE))
+	if (ses->map->search->terrain)
 	{
 	{
- 		if (ses->map->in_room != room->vnum)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP UNDO: Invalid last move.");
-			return;
-		}
-		show_message(ses, LIST_COMMAND, "#MAP UNDO: Moving to room %s.", link->str2);
-
-		goto_room(ses, atoi(link->str2));
+		free(ses->map->search->terrain);
 	}
 	}
 
 
-	if (HAS_BIT(undo_flag, MAP_UNDO_CREATE))
+	if (*buf)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting room %d.", room->vnum);
-		delete_room(ses, room->vnum, TRUE);
+		strcat(buf, "$");
+
+		ses->map->search->terrain = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
 	}
 	}
-	else if (HAS_BIT(undo_flag, MAP_UNDO_LINK))
+	else
 	{
 	{
-		exit1 = find_exit(ses, room->vnum, link->str2);
-
-		if (exit1)
-		{
-			show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting exit leading %s.", exit1->name);
-			delete_exit(ses, room->vnum, exit1);
-		}
+		ses->map->search->terrain = NULL;
+	}
 
 
-		exit2 = find_exit(ses, atoi(link->str2), link->str1);
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // flag
 
 
-		if (exit2)
-		{
-			show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting exit leading %s.", exit2->name);
-			delete_exit(ses, atoi(link->str2), exit2);
-		}
-	}
-	else if (HAS_BIT(undo_flag, MAP_UNDO_INSERT))
+	if (*buf)
 	{
 	{
-		exit1 = find_exit(ses, atoi(link->str2), link->str1);
+		char flags[BUFFER_SIZE];
 
 
-		if (exit1 == NULL)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP UNDO: Can't find exit between %s and %s.", link->str2, link->str1);
-			return;
-		}
+		ses->map->search->flag = get_number(ses, buf);
 
 
-		exit2 = find_exit(ses, room->vnum, exit1->name);
+		ptb = buf;
 
 
-		if (exit2 == NULL)
+		while (*buf)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#MAP UNDO: No valid exit found in room %d.", room->vnum);
-			return;
-		}
+			ptb = sub_arg_in_braces(ses, ptb, flags, GET_ONE, SUB_NONE);
 
 
-		exit3 = find_exit(ses, exit2->vnum, ntos(room->vnum));
+			if (is_abbrev(buf, "avoid"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_AVOID);
+			}
+			else if (is_abbrev(buf, "curved"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_CURVED);
+			}
+			else if (is_abbrev(buf, "hide"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_HIDE);
+			}
+			else if (is_abbrev(buf, "invis"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_INVIS);
+			}
+			else if (is_abbrev(buf, "leave"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_LEAVE);
+			}
+			else if (is_abbrev(buf, "void"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_VOID);
+			}
+			else if (is_abbrev(buf, "static"))
+			{
+				SET_BIT(ses->map->search->flag, ROOM_FLAG_STATIC);
+			}
 
 
-		if (exit3 == NULL)
-		{
-			show_error(ses, LIST_COMMAND, "#MAP UNDO: Can't find exit between %d and %d.", room->vnum, exit2->vnum);
-			return;
+			if (*ptb == COMMAND_SEPARATOR)
+			{
+				ptb++;
+			}
 		}
 		}
-
-		exit1->vnum = exit2->vnum;
-		exit3->vnum = atoi(link->str2);
-
-		delete_room(ses, room->vnum, TRUE);
-
-		show_message(ses, LIST_COMMAND, "#MAP UNDO: Uninserting room %s.", link->str1);
 	}
 	}
-	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);
+	else
+	{
+		ses->map->search->flag = 0;
+	}
 
 
-	exit1 = find_exit(ses, ses->map->in_room, arg1);
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // id
 
 
-	if (exit1 == NULL)
+	if (ses->map->search->id)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP UNLINK: No exit with that name found");
-
-		return;
+		free(ses->map->search->id);
 	}
 	}
 
 
-	if (*arg2 == 'b' || *arg == 'B')
+	if (*buf)
 	{
 	{
-		if (node)
-		{
-			exit2 = find_exit(ses, exit1->vnum, node->arg2);
-
-			if (exit2)
-			{
-				delete_exit(ses, exit1->vnum, exit2);
-			}
-		}
+		ses->map->search->id = strdup(buf);
+	}
+	else
+	{
+		ses->map->search->id = NULL;
 	}
 	}
 
 
-	delete_exit(ses, ses->map->in_room, exit1);
-
-	show_message(ses, LIST_COMMAND, "#MAP UNLINK: Exit deleted.");
+	pop_call();
+	return;
 }
 }
 
 
-DO_MAP(map_update)
+int match_room(struct session *ses, int vnum, struct search_data *search)
 {
 {
-	if (ses->map == NULL)
-	{
-		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NO MAP DATA.");
-	}
-	else if (ses->map->room_list[ses->map->in_room] == NULL)
+	struct room_data *room = ses->map->room_list[vnum];
+
+	if (room == NULL)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NOT INSIDE MAP.");
+		return 0;
 	}
 	}
-	else if (!HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+
+	if (search->vnum)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP UPDATE: VTMAP FLAG NOT SET.");
+		return room->vnum == search->vnum;
 	}
 	}
-	else if (ses != gtd->ses)
+
+	if (search->id)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NOT THE ACTIVE SESSION.");
+		return !strcmp(room->id, search->id);
 	}
 	}
-	else
+
+	if (search->name)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#MAP UPDATE: OK.");
-		
-		SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+		if (!regexp_compare(ses, search->name, room->name, "", 0, 0))
+		{
+			return 0;
+		}
 	}
 	}
-}
 
 
-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);
+	if (search->exit_dirs)
+	{
+		char *arg, exit[BUFFER_SIZE];
 
 
-	shortest_path(ses, TRUE, arg2, arg1);
-}
+		if (search->exit_dirs != room->exit_dirs)
+		{
+			return 0;
+		}
+		if (search->exit_size != room->exit_size)
+		{
+			return 0;
+		}
 
 
-DO_MAP(map_vnum)
-{
-	int vnum, vnum1, vnum2, old_room, new_room;
-	struct exit_data *exit;
+		arg = search->exit_list;
 
 
-	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);
+		while (*arg)
+		{
+			arg = get_arg_in_braces(ses, arg, exit, GET_ONE);
 
 
-	vnum1 = atoi(arg1);
+			if (!find_exit(ses, vnum, exit))
+			{
+				return 0;
+			}
 
 
-	if (*arg2)
-	{
-		vnum2 = atoi(arg2);
+			if (*arg == COMMAND_SEPARATOR)
+			{
+				arg++;
+			}
+		}
 	}
 	}
-	else
+
+	if (search->desc)
 	{
 	{
-		vnum2 = vnum1;
+		if (!regexp_compare(ses, search->desc, room->desc, "", 0, 0))
+		{
+			return 0;
+		}
 	}
 	}
-	
-	if (vnum1 <= 0 || vnum1 >= ses->map->size || vnum2 <= 0 || vnum2 >= ses->map->size)
+
+	if (search->area)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP VNUM {%s} {%s} - VNUMS MUST BE BETWEEN {1} and {%d}", arg1, arg2, ses->map->size - 1);
-		return;
+		if (!regexp_compare(ses, search->area, room->area, "", 0, 0))
+		{
+			return 0;
+		}
 	}
 	}
 
 
-	for (vnum = vnum1 ; vnum <= vnum2 ; vnum++)
+	if (search->note)
 	{
 	{
-		if (ses->map->room_list[vnum] == NULL)
+		if (!regexp_compare(ses, search->note, room->note, "", 0, 0))
 		{
 		{
-			break;
+			return 0;
 		}
 		}
 	}
 	}
 
 
-	if (vnum > vnum2)
+	if (search->terrain)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP VNUM {%s} {%s} - NO FREE VNUM FOUND.", arg1, arg2);
-		return;
+		if (!regexp_compare(ses, search->terrain, room->terrain, "", 0, 0))
+		{
+			return 0;
+		}
 	}
 	}
 
 
-	old_room = ses->map->in_room;
-	new_room = vnum;
-
-	ses->map->room_list[new_room] = ses->map->room_list[old_room];
-	ses->map->room_list[new_room]->vnum = new_room;
-	ses->map->room_list[old_room] = NULL;
-	ses->map->in_room = new_room;
-
-	if (ses->map->at_room == old_room)
+	if (search->flag)
 	{
 	{
-		ses->map->at_room = new_room;
+		if ((room->flags & search->flag) != search->flag)
+		{
+			return 0;
+		}
 	}
 	}
+	return 1;
+}
 
 
-	for (vnum = 1 ; vnum < ses->map->size ; vnum++)
+int find_path(struct session *ses, char *arg)
+{
+	struct exit_data *exit;
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	int room;
+
+	push_call("find_path(%p,%p)",ses,arg);
+
+	arg = substitute_speedwalk(ses, arg, arg1);
+
+	room = ses->map->in_room;
+
+	while (*arg)
 	{
 	{
-		if (ses->map->room_list[vnum] == NULL)
+		arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
+
+		exit = find_exit(ses, room, arg2);
+
+		if (exit == NULL)
 		{
 		{
-			continue;
+			pop_call();
+			return 0;
 		}
 		}
 
 
-		for (exit = ses->map->room_list[vnum]->f_exit ; exit ; exit = exit->next)
+		room = tunnel_void(ses, room, exit->vnum, exit->dir);
+
+		if (*arg == COMMAND_SEPARATOR)
 		{
 		{
-			if (exit->vnum == old_room)
-			{
-				exit->vnum = new_room;
-			}
+			arg++;
 		}
 		}
 	}
 	}
 
 
-	tintin_printf(ses, "#MAP VNUM: MOVED ROOM %d TO %d.", old_room, new_room);
+	pop_call();
+	return room == ses->map->in_room ? 0 : room;
 }
 }
 
 
-DO_MAP(map_write)
+int find_location(struct session *ses, char *arg)
 {
 {
-	FILE *file;
-	struct exit_data *exit;
-	int index;
-
-	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);
+	struct listnode *node;
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
+	int x, y, z;
+	
+	push_call("find_location(%p,%p)",ses,arg);
 
 
-	if (*arg1 == 0)
+	if (find_exit(ses, ses->map->in_room, arg))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP WRITE {<filename>} {FORCE}");
-
-		return;
+		pop_call();
+		return find_exit(ses, ses->map->in_room, arg)->vnum;
 	}
 	}
 
 
-	if (!str_suffix(arg1, ".tin") && !is_abbrev(arg2, "FORCE"))
+	if (is_math(ses, arg))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP WRITE {%s}: USE {FORCE} TO OVERWRITE .tin FILES.");
+		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_ALL, SUB_VAR|SUB_FUN);
 
 
-		return;
+		x = get_number(ses, arg1);
+		y = get_number(ses, arg2);
+		z = get_number(ses, arg3);
 	}
 	}
-
-	if ((file = fopen(arg1, "w")) == NULL)
+	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP WRITE {%s} - COULDN'T OPEN FILE TO WRITE.", arg1);
-
-		return;
-	}
+		x = y = z = 0;
 
 
-	fprintf(file, "C %d\n\n", ses->map->size);
-
-	fprintf(file, "V 2020\n\n");
-
-	for (index = 0 ; map_color_table[index].name ; index++)
-	{
-		fprintf(file, "C%s %s\n", map_color_table[index].name, ses->map->color[index]);
-	}
-	fprintf(file, "\n");
+		arg = substitute_speedwalk(ses, arg, arg2);
 
 
-	fprintf(file, "F %d\n\n", ses->map->flags);
+		while (*arg)
+		{
+			arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
 
-	fprintf(file, "G %d\n\n", ses->map->global_vnum);
+			node = search_node_list(ses->list[LIST_PATHDIR], arg3);
 
 
-	fprintf(file, "I %d\n\n", ses->map->in_room ? ses->map->in_room : ses->map->last_room);
+			if (node == NULL)
+			{
+//				show_error(ses, LIST_COMMAND, "#ERROR: #MAP FIND_LOCATION: {%s} IS AN INVALID PATHDIR.", arg3);
 
 
-	for (index = 0 ; map_legend_table[index].name ; index++)
-	{
-		fprintf(file, "L {%s} {%s} {%s}\n", map_legend_table[index].group, map_legend_table[index].name, ses->map->legend_raw[index]);
-	}
-	fprintf(file, "\n\n");
+				pop_call();
+				return 0;
+			}
 
 
-	for (index = 0 ; index < ses->map->size ; index++)
-	{
-		if (ses->map->room_list[index])
-		{
-			fprintf(file, "\nR {%5d} {%d} {%s} {%s} {%s} {%s} {%s} {%s} {%s} {%s} {%.3f} {%s}\n",
-				ses->map->room_list[index]->vnum,
-				ses->map->room_list[index]->flags,
-				ses->map->room_list[index]->color,
-				ses->map->room_list[index]->name,
-				ses->map->room_list[index]->symbol,
-				ses->map->room_list[index]->desc,
-				ses->map->room_list[index]->area,
-				ses->map->room_list[index]->note,
-				ses->map->room_list[index]->terrain,
-				ses->map->room_list[index]->data,
-				ses->map->room_list[index]->weight,
-				ses->map->room_list[index]->id);
+			x += (HAS_BIT(atoi(node->arg3), MAP_EXIT_E) ? 1 : HAS_BIT(atoi(node->arg3), MAP_EXIT_W) ? -1 : 0);
+			y += (HAS_BIT(atoi(node->arg3), MAP_EXIT_N) ? 1 : HAS_BIT(atoi(node->arg3), MAP_EXIT_S) ? -1 : 0);
+			z += (HAS_BIT(atoi(node->arg3), MAP_EXIT_U) ? 1 : HAS_BIT(atoi(node->arg3), MAP_EXIT_D) ? -1 : 0);
 
 
-			for (exit = ses->map->room_list[index]->f_exit ; exit ; exit = exit->next)
+			if (*arg == COMMAND_SEPARATOR)
 			{
 			{
-				fprintf(file, "E {%5d} {%s} {%s} {%d} {%d} {%s} {%.3f}\n",
-					exit->vnum,
-					exit->name,
-					exit->cmd,
-					exit->dir,
-					exit->flags,
-					exit->data,
-					exit->weight);
+				arg++;
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	fclose(file);
-
-	show_message(ses, LIST_COMMAND, "#MAP: Map file written to {%s}.", arg1);
+	pop_call();
+	return spatialgrid_find(ses, ses->map->in_room, x, y, z);
 }
 }
 
 
-void create_map(struct session *ses, char *arg)
+int find_room(struct session *ses, char *arg)
 {
 {
-	int group, legend;
+	char var[BUFFER_SIZE];
+	struct listnode *node;
+	int room;
 
 
-	push_call("create_map(%p,%p)",ses,arg);
+	push_call("find_room(%p,%s)",ses,arg);
 
 
-	if (ses->map)
+	map_search_compile(ses, arg, var);
+
+	if (ses->map->search->vnum > 0 && ses->map->search->vnum < ses->map->size)
 	{
 	{
-		delete_map(ses);
+		if (ses->map->room_list[ses->map->search->vnum])
+		{
+			pop_call();
+			return ses->map->search->vnum;
+		}
+		pop_call();
+		return 0;
 	}
 	}
 
 
-	ses->map = (struct map_data *) calloc(1, sizeof(struct map_data));
-	ses->map->size = atoi(arg) > 0 ? atoi(arg) : 50000;
-
-	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_rooms = (struct room_data **) calloc(ses->map->max_grid_x * ses->map->max_grid_y, sizeof(struct room_data *));
-	ses->map->grid_flags =             (int *) calloc(ses->map->max_grid_x * ses->map->max_grid_y, sizeof(struct room_data *));
-
-	ses->map->search = (struct search_data *) calloc(1, sizeof(struct search_data));
-
-	ses->map->flags = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_DIRECTION;
-
-	ses->map->global_exit         = (struct exit_data *) calloc(1, sizeof(struct exit_data));
-		ses->map->global_exit->vnum   = ses->map->global_vnum;
-		ses->map->global_exit->name   = restringf(ses->map->global_exit->name, "%cnop global", gtd->tintin_char);
-		ses->map->global_exit->cmd    = restringf(ses->map->global_exit->cmd, "%cnop global", gtd->tintin_char);
-		ses->map->global_exit->data   = strdup("");
-		ses->map->global_exit->weight = 1;
-
-	do_map(ses, "{COLOR} {RESET}");
-
-	ses->map->display_stamp = 1;
-	ses->map->search->stamp = 1;
-
-	create_room(ses, "%s", "{1} {0} {} {} { } {} {} {} {} {} {1.0} {}");
-
-	strcpy(arg, "");
-
-	for (group = 0 ; map_group_table[group].name ; group++)
+	if (ses->map->search->arg)
 	{
 	{
-		for (legend = 0 ; map_legend_table[legend].group ; legend++)
+		node = search_node_list(ses->list[LIST_LANDMARK], ses->map->search->arg);
+
+		if (node)
 		{
 		{
-			if (*map_group_table[group].group == 0 || is_abbrev(map_group_table[group].group, map_legend_table[legend].group))
+			if (ses->map->room_list[node->val32[0]])
 			{
 			{
-				break;
+				pop_call();
+				return node->val32[0];
 			}
 			}
+			pop_call();
+			return 0;
 		}
 		}
+	}
 
 
-		if (map_legend_table[legend].group)
+	if (ses->map->in_room)
+	{
+		room = searchgrid_find(ses, ses->map->in_room, ses->map->search);
+
+		if (room)
 		{
 		{
-			map_group_table[group].start = legend;
+			pop_call();
+			return room;
 		}
 		}
-		else
-		{
-			show_error(ses, LIST_COMMAND, "create_map: unknown legend group: %s, %s", map_group_table[group].name, map_group_table[group].group);
+	}
 
 
+	for (room = 0 ; room < ses->map->size ; room++)
+	{
+		if (ses->map->room_list[room] == NULL)
+		{
 			continue;
 			continue;
 		}
 		}
 
 
-		while (map_legend_table[++legend].group)
+		if (!match_room(ses, room, ses->map->search))
 		{
 		{
-			if (*map_group_table[group].group && !is_abbrev(map_group_table[group].group, map_legend_table[legend].group))
-			{
-				break;
-			}
+			continue;
 		}
 		}
-		map_group_table[group].end = legend;
+		pop_call();
+		return room;
 	}
 	}
-				
-	gtd->level->quiet++;
-	do_map(ses, "LEGEND RESET");
-	gtd->level->quiet--;
-
 	pop_call();
 	pop_call();
-	return;
+	return 0;
 }
 }
 
 
-int delete_map(struct session *ses)
+void goto_room(struct session *ses, int room)
 {
 {
-	int index, cnt;
-
-	for (index = cnt = 0 ; index < ses->map->size ; index++)
-	{
-		if (ses->map->room_list[index])
-		{
-			cnt++;
+	int last_room = ses->map->in_room;
 
 
-			delete_room(ses, index, FALSE);
-		}
-	}
-	free(ses->map->room_list);
+	push_call("goto_room(%p,%d)",ses,room);
 
 
-	while (ses->map->undo_head)
+	if (ses->map->in_room)
 	{
 	{
-		del_undo(ses, ses->map->undo_head);
+		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "MAP EXIT ROOM", ntos(last_room), ntos(room));
+		check_all_events(ses, SUB_ARG|SUB_SEC, 1, 2, "MAP EXIT ROOM %d", last_room, ntos(last_room), ntos(room));
 	}
 	}
 
 
-	free(ses->map->global_exit->name);
-	free(ses->map->global_exit->cmd);
-	free(ses->map->global_exit->data);
-	free(ses->map->global_exit);
+	ses->map->in_room = room;
 
 
-	free(ses->map);
+	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
 
 
-	ses->map = NULL;
+	if (last_room == 0)
+	{
+		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "MAP ENTER MAP", ntos(room));
+	}
 
 
-	return cnt;
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "MAP ENTER ROOM", ntos(room), ntos(last_room));
+	check_all_events(ses, SUB_ARG|SUB_SEC, 1, 2, "MAP ENTER ROOM %d", room, ntos(room), ntos(last_room));
+
+	pop_call();
+	return;
 }
 }
 
 
-int create_room(struct session *ses, char *format, ...)
+int find_new_room(struct session *ses)
 {
 {
-	char *arg, buf[BUFFER_SIZE];
-	struct room_data *newroom;
-	va_list args;
-
-	va_start(args, format);
-	vsprintf(buf, format, args);
-	va_end(args);
-
-	newroom = (struct room_data *) calloc(1, sizeof(struct room_data));
-
-	arg = buf;
-
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->vnum    = atoi(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->flags   = atoi(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->color   = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->name    = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->symbol  = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->desc    = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->area    = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->note    = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->terrain = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->data    = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->weight  = atof(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE); newroom->id      = strdup(buf);
+	int room;
 
 
-	if (HAS_BIT(newroom->flags, ROOM_FLAG_AVOID))
-	{
-		SET_BIT(newroom->flags, ROOM_FLAG_AVOID_TMP);
-	}
-	if (HAS_BIT(newroom->flags, ROOM_FLAG_HIDE))
-	{
-		SET_BIT(newroom->flags, ROOM_FLAG_HIDE_TMP);
-	}
-	if (HAS_BIT(newroom->flags, ROOM_FLAG_LEAVE))
-	{
-		SET_BIT(newroom->flags, ROOM_FLAG_LEAVE_TMP);
-	}
-	if (HAS_BIT(newroom->flags, ROOM_FLAG_VOID))
-	{
-		SET_BIT(newroom->flags, ROOM_FLAG_VOID_TMP);
-	}
-	if (HAS_BIT(newroom->flags, ROOM_FLAG_CURVED))
+	for (room = 1 ; room < ses->map->size ; room++)
 	{
 	{
-		SET_BIT(newroom->flags, ROOM_FLAG_CURVED_TMP);
+		if (ses->map->room_list[room] == NULL)
+		{
+			break;
+		}
 	}
 	}
 
 
-	if (newroom->weight <= 0)
+	if (room == ses->map->size)
 	{
 	{
-		newroom->weight = 1;
-	}
-
-	ses->map->room_list[newroom->vnum] = newroom;
-
-	show_message(ses, LIST_COMMAND, "#MAP CREATE ROOM %5d {%s}.", newroom->vnum, newroom->name);
+		show_error(ses, LIST_COMMAND, "#MAP CREATE ROOM: Maximum amount of rooms of %d reached. Use #map resize.", ses->map->size);
 
 
-	return newroom->vnum;
+		return 0;
+	}
+	return room;
 }
 }
 
 
-void delete_room(struct session *ses, int room, int exits)
+int dir_flags(struct session *ses, int room, int dir)
 {
 {
-	struct exit_data *exit, *exit_next;
-	int cnt;
+	struct exit_data *exit;
 
 
-	while (ses->map->room_list[room]->f_exit)
+	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
 	{
 	{
-		delete_exit(ses, room, ses->map->room_list[room]->f_exit);
+		if (exit->dir == dir)
+		{
+			return exit->flags; /* | HAS_BIT(ses->map->room_list[exit->vnum]->flags, EXIT_FLAG_ALL);*/
+		}
 	}
 	}
+	return 0;
+}
 
 
+struct exit_data *find_exit(struct session *ses, int room, char *arg)
+{
+	struct exit_data *exit;
 
 
-	free(ses->map->room_list[room]->area);
-	free(ses->map->room_list[room]->color);
-	free(ses->map->room_list[room]->id);
-	free(ses->map->room_list[room]->name);
-	free(ses->map->room_list[room]->symbol);
-	free(ses->map->room_list[room]->desc);
-	free(ses->map->room_list[room]->note);
-	free(ses->map->room_list[room]->terrain);
-	free(ses->map->room_list[room]->data); 
-
-	free(ses->map->room_list[room]);
-
-	ses->map->room_list[room] = NULL;
-
-	if (exits)
+	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
 	{
 	{
-		for (cnt = 0 ; cnt < ses->map->size ; cnt++)
+//		if (!strcmp(exit->name, arg) || exit->vnum == atoi(arg))
+		if (!strcmp(exit->name, arg))
 		{
 		{
-			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);
-					}
-				}
-			}
+			return exit;
 		}
 		}
 	}
 	}
+	return NULL;
 }
 }
 
 
-struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
+int check_global(struct session *ses, int room)
 {
 {
-	struct exit_data *newexit;
-	struct room_data *room;
-	va_list args;
-	char *arg, buf[BUFFER_SIZE];
-
-	push_call("create_exit(%p,%d,%p)",ses,vnum,format);
-
-	va_start(args, format);
-	vsprintf(buf, format, args);
-	va_end(args);
-
-	newexit = (struct exit_data *) calloc(1, sizeof(struct exit_data));
-
-	room = ses->map->room_list[vnum];
-
-	arg = buf;
-
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->vnum   = atoi(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->name   = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ALL);	newexit->cmd    = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->dir    = atoi(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->flags  = atoi(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ALL);	newexit->data   = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->weight = atof(buf);
-
-	if (newexit->dir == 0)
+	if (HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_NOGLOBAL))
 	{
 	{
-		newexit->dir = get_exit_dir(ses, newexit->name);
+		return FALSE;
 	}
 	}
-
-	newexit->grid = get_exit_grid(ses, newexit->dir);
-
-	if (room->exit_grid[newexit->grid] == NULL)
+	
+	if (ses->map->room_list[ses->map->global_vnum] == NULL)
 	{
 	{
-		room->exit_grid[newexit->grid] = newexit;
+		return FALSE;
 	}
 	}
 
 
-	if (newexit->weight <= 0)
+	if (room == ses->map->global_vnum)
 	{
 	{
-		newexit->weight = 1;
+		return FALSE;
 	}
 	}
-
-	LINK(newexit, room->f_exit, room->l_exit);
-
-	room->exit_size++;
-
-	SET_BIT(room->exit_dirs, (1LL << newexit->dir));
-
-	show_message(ses, LIST_COMMAND, "#MAP CREATE EXIT {%s} {%s} TO ROOM %d.", newexit->name, newexit->cmd, newexit->vnum);
-
-	pop_call();
-	return newexit;
-}
-
-void delete_exit(struct session *ses, int room, struct exit_data *exit)
-{
-	free(exit->name);
-	free(exit->cmd);
-	free(exit->data);
-
-	UNLINK(exit, ses->map->room_list[room]->f_exit, ses->map->room_list[room]->l_exit)
-
-	set_room_exits(ses, room);
-
-	free(exit);
+	return TRUE;
 }
 }
 
 
-int get_exit_dir(struct session *ses, char *arg)
+int tunnel_void(struct session *ses, int from, int room, int dir)
 {
 {
-	struct listnode *node;
-
-	node = search_node_list(ses->list[LIST_PATHDIR], arg);
-
-	if (node)
-	{
-		return atoi(node->arg3);
-	}
-	else
+	if (!HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_VOID))
 	{
 	{
-		return 0;
+		return room;
 	}
 	}
-}
 
 
-int get_exit_grid(struct session *ses, int dir)
-{
-	switch (dir)
+	if (get_room_exits(ses, room) != 2)
 	{
 	{
-		case 0:
-			return EXIT_GRID_0;
-		case MAP_EXIT_N:
-			return EXIT_GRID_N;
-		case MAP_EXIT_E:
-			return EXIT_GRID_E;
-		case MAP_EXIT_S:
-			return EXIT_GRID_S;
-		case MAP_EXIT_W:
-			return EXIT_GRID_W;
-		case MAP_EXIT_N|MAP_EXIT_E:
-			return EXIT_GRID_NE;
-		case MAP_EXIT_N|MAP_EXIT_W:
-			return EXIT_GRID_NW;
-		case MAP_EXIT_S|MAP_EXIT_E:
-			return EXIT_GRID_SE;
-		case MAP_EXIT_S|MAP_EXIT_W:
-			return EXIT_GRID_SW;
+		struct exit_data *exit = ses->map->room_list[room]->exit_grid[dir_to_grid(dir)];
+
+		if (exit)
+		{
+			return tunnel_void(ses, room, exit->vnum, exit->dir);
+		}
+		return room;
 	}
 	}
 
 
-	if (HAS_BIT(dir, MAP_EXIT_D))
+	if (ses->map->room_list[room]->f_exit->vnum != from)
 	{
 	{
-		return EXIT_GRID_D;
+		return tunnel_void(ses, room, ses->map->room_list[room]->f_exit->vnum, ses->map->room_list[room]->f_exit->dir);
 	}
 	}
-
-	if (HAS_BIT(dir, MAP_EXIT_U))
+	else
 	{
 	{
-		return EXIT_GRID_U;
+		return tunnel_void(ses, room, ses->map->room_list[room]->l_exit->vnum, ses->map->room_list[room]->l_exit->dir);
 	}
 	}
-
-	return EXIT_GRID_0;
 }
 }
 
 
-int get_room_exits(struct session *ses, int room)
-{
-	return ses->map->room_list[room]->exit_size;
-}
+// shortest_path() utilities
 
 
-void set_room_exits(struct session *ses, int vnum)
+int searchgrid_find(struct session *ses, int from, struct search_data *search)
 {
 {
+	int vnum, head, tail, index;
+	float length;
+	struct grid_node *node, *temp, list[MAP_BF_SIZE];
 	struct exit_data *exit;
 	struct exit_data *exit;
 	struct room_data *room;
 	struct room_data *room;
 
 
-	room = ses->map->room_list[vnum];
+	search->stamp++;
 
 
-	room->exit_dirs = 0;
-	room->exit_size = 0;
+	head = 0;
+	tail = 1;
 
 
-	memset(room->exit_grid, 0, sizeof(struct exit_data *) * 11);
+	node = &list[head];
 
 
-	for (exit = room->f_exit ; exit ; exit = exit->next)
-	{
-		SET_BIT(room->exit_dirs, 1LL << exit->dir);
+	node->vnum   = from;
+	node->length = ses->map->room_list[from]->weight;
 
 
-		if (room->exit_grid[exit->grid] == NULL)
-		{
-			room->exit_grid[exit->grid] = exit;
-		}
-		room->exit_size++;
-	}
-}
-
-int follow_map(struct session *ses, char *argument)
-{
-	struct room_data *room;
-	struct exit_data *exit;;
-	int in_room, vnum;
-
-	push_call("follow_map(%p,%p)",ses,argument);
+	// for map_list
 
 
-	room = ses->map->room_list[ses->map->in_room];
+	node->w      = 0;
+	node->x      = 0;
+	node->y      = 0;
+	node->z      = 0;
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
+	while (head != tail)
 	{
 	{
-		if (check_global(ses, room->vnum) && find_exit(ses, ses->map->global_vnum, argument))
-		{
-			in_room = ses->map->global_vnum;
-		}
-		else
-		{
-			in_room = ses->map->in_room;
-		}
-		exit = find_exit(ses, in_room, argument);
+		node = &list[head];
 
 
-		if (exit)
-		{
-			ses->map->dir = exit->dir;
+		room = ses->map->room_list[node->vnum];
 
 
-			vnum = tunnel_void(ses, in_room, exit->vnum, exit->dir);
+		length = node->length;
 
 
-			check_all_events(ses, SUB_ARG, 0, 5, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name);
-		}
-		pop_call();
-		return 0;
-	}
+		head = (head + 1) % MAP_BF_SIZE;
 
 
-	if (check_global(ses, room->vnum))
-	{
-		if (find_exit(ses, ses->map->global_vnum, argument))
+		if (search->stamp != room->search_stamp)
 		{
 		{
-			goto_room(ses, ses->map->global_vnum);
-		}
-	}
-
-	exit = find_exit(ses, ses->map->in_room, argument);
+			room->search_stamp = search->stamp;
 
 
-	if (exit)
-	{
-		ses->map->dir = exit->dir;
+			// first come first serve like with spatialgrid_find
 
 
-		in_room = ses->map->in_room;
+			room->w = node->w;
+			room->x = node->x;
+			room->y = node->y;
+			room->z = node->z;
 
 
-		if (ses->map->nofollow == 0)
+			DEL_BIT(room->flags, ROOM_FLAG_PATH);
+		}
+		else if (length >= room->length)
 		{
 		{
-			ses->map->nofollow++;
-
-			script_driver(ses, LIST_COMMAND, exit->cmd);
-
-			ses->map->nofollow--;
+			if (room->vnum != ses->map->global_vnum && room->w && node->w == 0)
+			{
+				room->w = node->w;
+				room->x = node->x;
+				room->y = node->y;
+				room->z = node->z;
+			}
+			continue;
 		}
 		}
 
 
-		vnum = tunnel_void(ses, in_room, exit->vnum, exit->dir);
-
-		check_all_events(ses, SUB_ARG, 0, 5, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name);
-
-		add_undo(ses, "%d %d %d", vnum, in_room, MAP_UNDO_MOVE);
-
-		goto_room(ses, vnum);
+		room->length = length;
 
 
-		if (HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE))
+		if (search->vnum)
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#MAP: LEAVE FLAG FOUND IN ROOM {%d}. LEAVING MAP.", ses->map->in_room);
-
-			map_leave(ses, "", "", "");
+			if (room->vnum == search->vnum)
+			{
+				return room->vnum;
+			}
 		}
 		}
-
-		if (HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+		else
 		{
 		{
-			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+			if (match_room(ses, room->vnum, search))
+			{
+				return room->vnum;
+			}
 		}
 		}
 
 
-		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))
-	{
-		struct listnode *node;
-
-		if ((node = search_node_list(ses->list[LIST_PATHDIR], argument)) == NULL)
+		if (check_global(ses, room->vnum))
 		{
 		{
-			pop_call();
-			return 0;
+			exit = ses->map->global_exit;
 		}
 		}
-
-		in_room = find_coord(ses, argument);
-
-		if (in_room)
+		else
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#MAP CREATE LINK %5d {%s}.", in_room, ses->map->room_list[in_room]->name);
-
-			add_undo(ses, "%d %d %d", in_room, ses->map->in_room, MAP_UNDO_MOVE|MAP_UNDO_LINK);
+			exit = room->f_exit;
 		}
 		}
-		else
+
+		for ( ; exit ; exit = exit->next)
 		{
 		{
-			for (in_room = 1 ; in_room < ses->map->size ; in_room++)
+			vnum = tunnel_void(ses, room->vnum, exit->vnum, exit->dir);
+
+			if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID|EXIT_FLAG_BLOCK) || HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_AVOID|ROOM_FLAG_BLOCK))
 			{
 			{
-				if (ses->map->room_list[in_room] == NULL)
+				goto next_exit;
+			}
+
+			length = room->length + exit->weight + ses->map->room_list[vnum]->weight;
+
+			if (search->stamp == ses->map->room_list[vnum]->search_stamp)
+			{
+				if (length >= ses->map->room_list[vnum]->length)
 				{
 				{
-					break;
+					goto next_exit;
 				}
 				}
 			}
 			}
 
 
-			if (in_room == ses->map->size)
+			temp = &list[tail];
+
+			temp->vnum   = vnum;
+			temp->length = length;
+			temp->w      = room->vnum == ses->map->global_vnum ? 1 : room->w;
+			temp->x      = room->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
+			temp->y      = room->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
+			temp->z      = room->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);
+
+			/*
+				list must remain ordered by length
+			*/
+
+			index = tail;
+
+			while (index != head)
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#MAP: Maximum amount of rooms of %d reached. Use #MAP RESIZE to increase the maximum.", ses->map->size);
+				temp = &list[index];
 
 
-				pop_call();
-				return 1;
-			}
-			add_undo(ses, "%d %d %d", in_room, ses->map->in_room, MAP_UNDO_MOVE|MAP_UNDO_CREATE|MAP_UNDO_LINK);
+				node = &list[index ? index - 1 : MAP_BF_SIZE - 1];
 
 
-			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", in_room);
-		}
+				if (temp->length >= node->length)
+				{
+					break;
+				}
 
 
-		exit = create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", in_room, node->arg1, node->arg1);
+				vnum         = temp->vnum;
+				length       = temp->length;
 
 
-		ses->map->dir = exit->dir;
+				temp->vnum   = node->vnum;
+				temp->length = node->length;
 
 
-		if (find_exit(ses, in_room, node->arg2) == NULL)
-		{
-			create_exit(ses, in_room, "{%d} {%s} {%s}", ses->map->in_room, node->arg2, node->arg2);
-		}
+				node->vnum   = vnum;
+				node->length = length;
 
 
-		if (ses->map->nofollow == 0)
-		{
-			ses->map->nofollow++;
+				index = index ? index - 1 : MAP_BF_SIZE - 1;
+			}
 
 
-			script_driver(ses, LIST_COMMAND, argument);
+			tail = (tail + 1) % MAP_BF_SIZE;
 
 
-			ses->map->nofollow--;
-		}
-		goto_room(ses, in_room);
+			if (tail == head)
+			{
+				show_error(ses, LIST_COMMAND, "#SHORTEST PATH: MAP TOO BIG FOR BF STACK OF %d", MAP_BF_SIZE);
+				break;
+			}
 
 
-		if (HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
-		{
-			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
-		}
+			next_exit:
 
 
-		pop_call();
-		return 1;
+			if (exit == ses->map->global_exit)
+			{
+				exit->next = room->f_exit;
+			}
+		}
 	}
 	}
-	pop_call();
 	return 0;
 	return 0;
 }
 }
 
 
-void add_undo(struct session *ses, char *format, ...)
+int searchgrid_walk(struct session *ses, int offset, int from, int dest)
 {
 {
-	struct link_data *link;
-	char buf[BUFFER_SIZE], *arg, dir[BUFFER_SIZE], rev[BUFFER_SIZE], flag[BUFFER_SIZE];
-	va_list args;
+	int vnum, trim, head, tail, index;
+	float length;
+	struct grid_node *node, *temp, list[MAP_BF_SIZE];
+	struct exit_data *exit;
+	struct room_data *room;
 
 
-	push_call("add_undo(%s,%s)",ses->name, format);
+	head = 0;
+	tail = 1;
 
 
-	va_start(args, format);
-	vsprintf(buf, format, args);
-	va_end(args);
+	list[head].vnum   = from;
+	list[head].length = ses->map->room_list[from]->weight;
 
 
-	arg = get_arg_in_braces(ses, buf, dir, GET_ONE);
-	arg = get_arg_in_braces(ses, arg, rev, GET_ONE);
-	arg = get_arg_in_braces(ses, arg, flag, GET_ONE);
+	while (head != tail)
+	{
+		node = &list[head];
 
 
-	link = (struct link_data *) calloc(1, sizeof(struct link_data));
+		room = ses->map->room_list[node->vnum];
 
 
-	link->str1 = strdup(dir);
-	link->str2 = strdup(rev);
-	link->str3 = strdup(flag);
+		length = node->length;
 
 
-	LINK(link, ses->map->undo_head, ses->map->undo_tail);
+		head = (head + 1) % MAP_BF_SIZE;
 
 
-	ses->map->undo_size++;
 
 
-	if (ses->map->undo_size > 100)
-	{
-		del_undo(ses, ses->map->undo_head);
-	}
-	pop_call();
-	return;
-}
+		if (length >= room->length)
+		{
+			continue;
+		}
 
 
-void del_undo(struct session *ses, struct link_data *link)
-{
-	UNLINK(link, ses->map->undo_head, ses->map->undo_tail);
+		room->length = length;
 
 
-	free(link->str1);
-	free(link->str2);
-	free(link->str3);
-
-	free(link);
-
-	ses->map->undo_size--;
-}
-
-/*
-	Draws a map on a grid, original breadth first improvements by Bryan Turner
-*/
+		if (room->vnum == dest)
+		{
+			return room->vnum;
+		}
 
 
+		trim = 1;
 
 
+		if (check_global(ses, room->vnum))
+		{
+			exit = ses->map->global_exit;
+		}
+		else
+		{
+			exit = room->f_exit;
+		}
 
 
-struct grid_node
-{
-	int vnum;
-	int flags;
-	float length;
-	int w;
-	int x;
-	int y;
-	int z;
-};
+		for ( ; exit ; exit = exit->next)
+		{
+			vnum = tunnel_void(ses, room->vnum, exit->vnum, exit->dir);
 
 
-void displaygrid_build(struct session *ses, 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;
+			if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID|EXIT_FLAG_BLOCK) || HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_AVOID|ROOM_FLAG_BLOCK))
+			{
+				goto next_exit;
+			}
 
 
-	push_call("displaygrid_build(%p,%d,%d,%d,%d)",ses,vnum,x,y,z);
+			length = room->length + exit->weight + ses->map->room_list[vnum]->weight;
 
 
-	map_grid_x = x;
-	map_grid_y = y;
+			if (ses->map->search->stamp != ses->map->room_list[vnum]->search_stamp)
+			{
+				goto next_exit;
+			}
 
 
-	head = 0;
-	tail = 1;
+			if (length >= ses->map->room_list[vnum]->length || length >= ses->map->room_list[dest]->length)
+			{
+				goto next_exit;
+			}
 
 
-	node = &list[head];
+			temp = &list[tail];
 
 
-	node->vnum   = vnum;
-	node->x      = x / 2 + ses->map->center_x;
-	node->y      = y / 2 + ses->map->center_y;
-	node->z      = z / 2 + ses->map->center_z;
-	node->length = 0;
-	node->flags  = 0;
+			temp->vnum   = vnum;
+			temp->length = length;
 
 
-	ses->map->display_stamp++;
+			/*
+				list must remain ordered by length
+			*/
 
 
-	for (vnum = 0 ; vnum < x * y ; vnum++)
-	{
-		ses->map->grid_rooms[vnum] = NULL;
-		ses->map->grid_flags[vnum] = 0;
-	}
+			index = tail;
 
 
-	while (head != tail)
-	{
-		node = &list[head];
+			while (index != head)
+			{
+				temp = &list[index];
 
 
-		head = (head + 1) % MAP_BF_SIZE;
+				node = &list[index ? index - 1 : MAP_BF_SIZE - 1];
 
 
-		room = ses->map->room_list[node->vnum];
+				if (temp->length >= node->length)
+				{
+					break;
+				}
 
 
-		if (ses->map->display_stamp != room->display_stamp)
-		{
-			room->display_stamp = ses->map->display_stamp;
-		}
-		else if (room->length <= node->length)
-		{
-			continue;
-		}
+				vnum = temp->vnum;
+				length = temp->length;
 
 
-		room->length = node->length;
+				temp->vnum = node->vnum;
+				temp->length = node->length;
 
 
-		if (node->x >= 0 && node->x < map_grid_x && node->y >= 0 && node->y < map_grid_y && node->z == 0)
-		{
-			if (ses->map->grid_rooms[node->x + map_grid_x * node->y] == NULL/* || HAS_BIT(ses->map->grid_flags[node->x + map_grid_x * node->y], GRID_FLAG_HIDE)*/)
-			{
-				ses->map->grid_rooms[node->x + map_grid_x * node->y] = room;
-				ses->map->grid_flags[node->x + map_grid_x * node->y] = node->flags;
-			}
-			else
-			{
-				continue;
-			}
-		}
-/*
-		if (HAS_BIT(node->flags, GRID_FLAG_HIDE))
-		{
-			continue;
-		}
-*/
-		for (exit = room->f_exit ; exit ; exit = exit->next)
-		{
-			if (ses->map->display_stamp == ses->map->room_list[exit->vnum]->display_stamp)
-			{
-				if (room->length >= ses->map->room_list[exit->vnum]->length)
-				{
-					continue;
-				}
-			}
+				node->vnum = vnum;
+				node->length = length;
 
 
-			if (exit->dir == 0)
-			{
-				continue;
+				index = index ? index - 1 : MAP_BF_SIZE - 1;
 			}
 			}
 
 
-			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
-			{
-				continue;
-			}
+			tail = (tail + 1) % MAP_BF_SIZE;
 
 
-			if (head == (tail + 1) % MAP_BF_SIZE)
+			if (tail == head)
 			{
 			{
+				show_error(ses, LIST_COMMAND, "#SHORTEST PATH: MAP TOO BIG FOR BF STACK OF %d", MAP_BF_SIZE);
 				break;
 				break;
 			}
 			}
+			trim = 0;
 
 
-			temp = &list[tail];
-
-			temp->vnum   = exit->vnum;
-			temp->x      = node->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
-			temp->y      = node->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
-			temp->z      = node->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);
-			temp->length = node->length + 1;
-			temp->flags  = 0;
-/*
-			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
-			{
-				SET_BIT(temp->flags, GRID_FLAG_HIDE);
+			next_exit:
 
 
-				temp->length += 1000;
-			}
-*/
-			if (HAS_BIT(exit->flags, EXIT_FLAG_INVIS) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_INVIS))
+			if (exit == ses->map->global_exit)
 			{
 			{
-				SET_BIT(temp->flags, GRID_FLAG_INVIS);
+				exit->next = room->f_exit;
 			}
 			}
+		}
 
 
-			tail = (tail + 1) % MAP_BF_SIZE;
+		if (trim)
+		{
+			room->length = 0;
 		}
 		}
 	}
 	}
-	pop_call();
-	return;
+	return 0;
 }
 }
 
 
-
-
-
-void show_vtmap(struct session *ses)
+void shortest_path(struct session *ses, int run, char *delay, char *arg)
 {
 {
-	char buf[BUFFER_SIZE], out[BUFFER_SIZE];
-	int x, y, line;
-	int top_row, top_col, bot_row, bot_col, rows, cols;
-
-	push_call("show_vtmap(%p)",ses);
+	char var[BUFFER_SIZE];
+	struct exit_data *exit;
+	struct room_data *room;
+	int vnum, dest;
 
 
-	if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		pop_call();
+		show_error(ses, LIST_COMMAND, "#SHORTEST PATH: You have to use #PATH END first.");
+
 		return;
 		return;
 	}
 	}
 
 
-	if (ses->map->room_list[ses->map->in_room] == NULL)
+	kill_list(ses->list[LIST_PATH]);
+
+	ses->list[LIST_PATH]->update = 0;
+
+	map_search_compile(ses, arg, var);
+
+	dest = searchgrid_find(ses, ses->map->in_room, ses->map->search);
+
+	if (dest == 0 || dest == ses->map->global_vnum)
 	{
 	{
-		pop_call();
+		show_error(ses, LIST_COMMAND, "#SHORTEST PATH: NO PATH FOUND TO %s.", arg);
 		return;
 		return;
 	}
 	}
 
 
-	if (ses != gtd->ses || HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD))
+	if (dest == ses->map->in_room)
 	{
 	{
-		pop_call();
+		show_error(ses, LIST_COMMAND, "#SHORTEST PATH: Already there.");
 		return;
 		return;
 	}
 	}
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_RESIZE))
-	{
-		DEL_BIT(ses->map->flags, MAP_FLAG_RESIZE);
+	vnum = ses->map->in_room;
 
 
-		map_offset(ses, NULL, "", "");
-	}
+	// Slower than a backtrace, but works with mazes.
 
 
-	if (ses->map->rows > 1 && ses->map->cols > 1)
-	{
-		top_row = ses->map->top_row;
-		top_col = ses->map->top_col;
-		bot_row = ses->map->bot_row;
-		bot_col = ses->map->bot_col;
-		rows    = ses->map->rows;
-		cols    = ses->map->cols;
-	}
-	else
+	while (TRUE)
 	{
 	{
-		top_row = 1;
-		top_col = 1;
-		bot_row = ses->split->top_row - 2;
-		bot_col = gtd->screen->cols;
+		room = ses->map->room_list[vnum];
 
 
-		rows    = ses->split->top_row - 2;
-		cols    = gtd->screen->cols;
-	}
+		if (check_global(ses, room->vnum))
+		{
+			exit = ses->map->global_exit;
+		}
+		else
+		{
+			exit = room->f_exit;
+		}
 
 
-	erase_square(ses, top_row, top_col, bot_row, bot_col);
+		for ( ; exit ; exit = exit->next)
+		{
+			if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID|EXIT_FLAG_BLOCK) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_AVOID|ROOM_FLAG_BLOCK))
+			{
+				goto exit_next;
+			}
 
 
-//	print_stdout("\e[%d;%d;%d;%d${", top_row, top_col, bot_row, bot_col);
+			vnum = tunnel_void(ses, room->vnum, exit->vnum, exit->dir);
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
-	{
-		map_grid_y = 2 + rows / 3;
-		map_grid_x = 2 + cols / 6;
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) || HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
-	{
-		map_grid_y = 2 + rows / 2;
-		map_grid_x = 2 + cols / 5;
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
-	{
-		map_grid_y = 2 + rows;
-		map_grid_x = 2 + cols / 2;
-	}
-	else
-	{
-		map_grid_y = 2 + rows;
-		map_grid_x = 2 + cols;
-	}
+			if (searchgrid_walk(ses, room->length, vnum, dest))
+			{
+				break;
+			}
 
 
-	displaygrid_build(ses, ses->map->in_room, map_grid_x, map_grid_y, 0);
+			exit_next:
 
 
-	save_pos(ses);
+			if (exit == ses->map->global_exit)
+			{
+				exit->next = room->f_exit;
+			}
+		}
 
 
-	goto_pos(ses, top_row, 1);
+		if (exit == NULL)
+		{
+			show_error(ses, LIST_COMMAND, "#SHORTEST PATH: UNKNOWN ERROR.");
+			return;
+		}
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
-	{
-		for (y = map_grid_y - 2 ; y >= 1 ; y--)
+		if (exit != ses->map->global_exit)
 		{
 		{
-			for (line = 1 ; line <= 3 ; line++)
+			if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
 			{
 			{
-				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+				check_append_path(ses, exit->cmd, "", 0);
+			}
+			else
+			{
+				check_append_path(ses, exit->name, "", 0);
+			}
+		}
 
 
-				for (x = 1 ; x < map_grid_x - 1 ; x++)
-				{
-					strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
-				}
+		SET_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
 
 
-				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+		if (ses->map->room_list[vnum]->search_stamp != ses->map->search->stamp)
+		{
+			show_error(ses, LIST_COMMAND, "%d bad search stamp %d vs %d", vnum, ses->map->room_list[vnum]->search_stamp, ses->map->search->stamp);
+		}
 
 
-				print_stdout("\e[%dG%s\e[0m\n", top_col, out);
-			}
+		if (vnum == dest)
+		{
+			break;
 		}
 		}
 	}
 	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) || HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
+
+	if (run)
 	{
 	{
-		for (y = map_grid_y - 2 ; y >= 1 ; y--)
-		{
-			for (line = 1 ; line <= 2 ; line++)
-			{
-				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+		path_run(ses, delay);
+	}
+}
 
 
-				for (x = 1 ; x < map_grid_x - 1 ; x++)
-				{
-					strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
-				}
-				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+/*
+	Virtual coordinate search for linkable rooms when creating a new room.
+*/
 
 
-				print_stdout("\e[%dG%s\e[0m\n", top_col, out);
-			}
-		}
+int find_coord(struct session *ses, char *arg)
+{
+	int dir, x, y, z, room;
+
+	dir = get_exit_dir(ses, arg);
+
+	if (dir == 0)
+	{
+		return 0;
 	}
 	}
-	else
+
+	x = (HAS_BIT(dir, MAP_EXIT_E) ? 1 : HAS_BIT(dir, MAP_EXIT_W) ? -1 : 0);
+	y = (HAS_BIT(dir, MAP_EXIT_N) ? 1 : HAS_BIT(dir, MAP_EXIT_S) ? -1 : 0);
+	z = (HAS_BIT(dir, MAP_EXIT_U) ? 1 : HAS_BIT(dir, MAP_EXIT_D) ? -1 : 0);
+
+	room = spatialgrid_find(ses, ses->map->in_room, x, y, z);
+
+	if (ses->map->room_list[room])
 	{
 	{
-		for (y = map_grid_y - 2 ; y >= 1 ; y--)
+		if (HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_STATIC))
 		{
 		{
-			strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
-
-			for (x = 1 ; x < map_grid_x - 1 ; x++)
-			{
-				strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
-			}
-			substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
+			show_message(ses, LIST_COMMAND, "#MAP: Linkable room is marked static. Creating overlapping room instead.");
 
 
-			print_stdout("\e[%dG%s\e[0m\n", top_col, out);
+			return 0;
 		}
 		}
 	}
 	}
-
-	restore_pos(ses);
-
-	pop_call();
-	return;
+	return room;
 }
 }
 
 
-// http://shapecatcher.com/unicode/block/Mathematical_Operators diagonal #⊥⊤#
+// Used by #map jump and the auto linker
 
 
-char *draw_room(struct session *ses, struct room_data *room, int line, int x, int y)
+int spatialgrid_find(struct session *ses, int from, int x, int y, int z)
 {
 {
-	static char buf[201], *room_color, room_left[101], room_right[101];
-	int index, flags, exits, exit1, exit2, room1, room2, offset;
+	int head, tail;
+	struct grid_node *node, *temp, list[MAP_BF_SIZE];
+	struct exit_data *exit;
+	struct room_data *room;
 
 
-	push_call("draw_room(%p,%p,%d,%d,%d)",ses,room,line,x,y);
+	push_call("spatialgrid_find(%s,%d,%d,%d,%d)",ses->name,from,x,y,z);
 
 
-	offset = HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) ? LEGEND_UNICODE : LEGEND_ASCII;
+	head = 0;
+	tail = 1;
 
 
-	room_color = ses->map->color[MAP_COLOR_ROOM];
+	node = &list[head];
 
 
-	if (room)
+	node->vnum   = from;
+	node->x      = 0;
+	node->y      = 0;
+	node->z      = 0;
+	node->length = 0;
+	node->flags  = 0;
+
+	ses->map->display_stamp++;
+
+	while (head != tail)
 	{
 	{
-		if (HAS_BIT(room->flags, ROOM_FLAG_PATH) && room->search_stamp == ses->map->search->stamp)
-		{
-			room_color = ses->map->color[MAP_COLOR_PATH];
-		}
-		else if (*room->color)
+		node = &list[head];
+
+		head = (head + 1) % MAP_BF_SIZE;
+
+		room = ses->map->room_list[node->vnum];
+
+		if (ses->map->display_stamp != room->display_stamp)
 		{
 		{
-			room_color = room->color;
+			room->display_stamp = ses->map->display_stamp;
 		}
 		}
-		else
+		else if (room->length <= node->length)
 		{
 		{
-			if (HAS_BIT(ses->map->grid_flags[x + map_grid_x * y], GRID_FLAG_INVIS))
-			{
-				room_color = ses->map->color[MAP_COLOR_INVIS];
-			}
-			else if (HAS_BIT(room->flags, ROOM_FLAG_INVIS))
-			{
-				room_color = ses->map->color[MAP_COLOR_INVIS];
-			}
-/*			else if (HAS_BIT(ses->map->grid_flags[x + map_grid_x * y], GRID_FLAG_HIDE))
-			{
-				room_color = ses->map->color[MAP_COLOR_HIDE];
-			}*/
-			else if (HAS_BIT(room->flags, ROOM_FLAG_HIDE))
-			{
-				room_color = ses->map->color[MAP_COLOR_HIDE];
-			}
-			else if (HAS_BIT(room->flags, ROOM_FLAG_AVOID))
-			{
-				room_color = ses->map->color[MAP_COLOR_AVOID];
-			}
-			else if (HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS))
-			{
-				room_color = ses->map->color[MAP_COLOR_SYMBOL];
-			}
+			continue;
 		}
 		}
 
 
-		if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
+		room->length = node->length;
+/*
+		if (HAS_BIT(node->flags, GRID_FLAG_HIDE))
 		{
 		{
-			sprintf(room_left, "%s(", room_color);
-			sprintf(room_right, "%s)", room_color);
+			continue;
 		}
 		}
-		else
+*/
+		if (node->x == x && node->y == y && node->z == z)
 		{
 		{
-			sprintf(room_left, "%s[", room_color);
-			sprintf(room_right, "%s]", room_color);
+			pop_call();
+			return node->vnum;
 		}
 		}
 
 
-		if (room->vnum == ses->map->in_room)
+		for (exit = room->f_exit ; exit ; exit = exit->next)
 		{
 		{
-			if (HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION))
+			if (ses->map->display_stamp == ses->map->room_list[exit->vnum]->display_stamp)
 			{
 			{
-				exits = ses->map->dir;
-
-				DEL_BIT(exits, MAP_EXIT_U|MAP_EXIT_D);
-
-				switch (exits)
+				if (room->length >= ses->map->room_list[exit->vnum]->length)
 				{
 				{
-					case MAP_EXIT_N:
-						index = 24;
-						break;
-					case MAP_EXIT_N+MAP_EXIT_E:
-						index = 25;
-						break;
-					case MAP_EXIT_E:
-						index = 26;
-						break;
-					case MAP_EXIT_S+MAP_EXIT_E:
-						index = 27;
-						break;
-					case MAP_EXIT_S:
-						index = 28;
-						break;
-					case MAP_EXIT_W+MAP_EXIT_S:
-						index = 29;
-						break;
-					case MAP_EXIT_W:
-						index = 30;
-						break;
-					case MAP_EXIT_W+MAP_EXIT_N:
-						index = 31;
-						break;
-					default:
-						index = 17;
-						break;
+					continue;
 				}
 				}
 			}
 			}
-			else
+
+			if (exit->dir == 0)
 			{
 			{
-				index = 16;
+				continue;
 			}
 			}
-		}
-	}
-
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
-	{
-		struct room_data *room_n, *room_nw, *room_w;
-		long long exit_n, exit_nw, exit_w;
 
 
-		room_n  = ses->map->grid_rooms[x + 0 + map_grid_x * (y + 1)];
-		room_nw = ses->map->grid_rooms[x - 1 + map_grid_x * (y + 1)];
-		room_w  = ses->map->grid_rooms[x - 1 + map_grid_x * (y + 0)];
+			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
+			{
+				continue;
+			}
 
 
-		exit_n = exit_nw = exit_w = 0;
+			if (head == (tail + 1) % MAP_BF_SIZE)
+			{
+				break;
+			}
 
 
-		if (room && room->exit_grid[EXIT_GRID_N])
-		{
-			SET_BIT(exit_n, MAP_DIR_N);
-		}
+			temp = &list[tail];
 
 
-		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_S))
-		{
-			SET_BIT(exit_n, MAP_DIR_S);
-		}
+			temp->vnum   = exit->vnum;
+			temp->w      = node->w;
+			temp->x      = node->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
+			temp->y      = node->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
+			temp->z      = node->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);
+			temp->length = node->length + 1;
+			temp->flags  = 0;
+/*
+			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
+			{
+				SET_BIT(temp->flags, GRID_FLAG_HIDE);
 
 
-		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_D))
-		{
-			SET_BIT(exit_n, MAP_DIR_D);
+				temp->length += 1000;
+			}
+*/
+			tail = (tail + 1) % MAP_BF_SIZE;
 		}
 		}
+	}
+	pop_call();
+	return 0;
+}
 
 
-		if (room && HAS_BIT(room->exit_dirs, MAP_DIR_NW))
-		{
-			SET_BIT(exit_nw, MAP_DIR_SE);
-		}
+void explore_path(struct session *ses, int run, char *arg1, char *arg2)
+{
+	struct exit_data *exit;
+	int room, vnum;
 
 
-		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_SW))
-		{
-			SET_BIT(exit_nw, MAP_DIR_NE);
-		}
-		if (room_nw && HAS_BIT(room_nw->exit_dirs, MAP_DIR_SE))
+	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
+	{
+		if (ses->map->room_list[vnum])
 		{
 		{
-			SET_BIT(exit_nw, MAP_DIR_NW);
+			DEL_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
 		}
 		}
+	}
 
 
-		if (room_w && HAS_BIT(room_w->exit_dirs, MAP_DIR_NE))
-		{
-			SET_BIT(exit_nw, MAP_DIR_SW);
-		}
+	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
+	{
+		show_error(ses, LIST_COMMAND, "#MAP EXPLORE: You have to use #PATH END first.");
 
 
-		if (room && room->exit_grid[EXIT_GRID_W])
-		{
-			SET_BIT(exit_w, MAP_DIR_E);
-		}
+		return;
+	}
 
 
-		if (room_w && room_w->exit_grid[EXIT_GRID_E])
-		{
-			SET_BIT(exit_w, MAP_DIR_W);
-		}
+	kill_list(ses->list[LIST_PATH]);
 
 
-		sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
+	ses->list[LIST_PATH]->update = 0;
 
 
-		switch (line)
-		{
-			case 1:
-				switch (exit_nw)
-				{
-					case 0:
-						strcat(buf, "  ");
-						break;
-					case MAP_DIR_NE:
-						strcat(buf, " ⸍");
-						break;
-					case MAP_DIR_SE:
-						strcat(buf, " ⸜");
-						break;
-					case MAP_DIR_NE|MAP_DIR_SE:
-						strcat(buf, " <");
-						break;
-					case MAP_DIR_SW:
-						strcat(buf, "⸝ ");
-						break;
-					case MAP_DIR_NE|MAP_DIR_SW:
-						strcat(buf, "/");
-						break;
-					case MAP_DIR_SE|MAP_DIR_SW:
-						strcat(buf, "⸝⸜");
-						break;
-					case MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW:
-						strcat(buf, "⸝<");
-						break;
-					case MAP_DIR_NW:
-						strcat(buf, "⸌ ");
-						break;
-					case MAP_DIR_NE|MAP_DIR_NW:
-						strcat(buf, "⸌⸍");
-						break;
-					case MAP_DIR_SE|MAP_DIR_NW:
-						strcat(buf, "\");
-						break;
-					case MAP_DIR_SW|MAP_DIR_NW:
-						strcat(buf, "> ");
-						break;
-					case MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_NW:
-						strcat(buf, "⸌<");
-						break;
-					case MAP_DIR_NE|MAP_DIR_SW|MAP_DIR_NW:
-						strcat(buf, ">⸍");
-						break;
-					case MAP_DIR_SE|MAP_DIR_SW|MAP_DIR_NW:
-						strcat(buf, ">⸜");
-						break;
-					case MAP_DIR_NW|MAP_DIR_SE|MAP_DIR_NE|MAP_DIR_SW:
-//						strcat(buf, "ᐳᐸ");
-						strcat(buf, "><");
-						break;
-					default:
-						strcat(buf, "??");
-						break;
-				}
+	room = ses->map->in_room;
 
 
-				if (HAS_BIT(exit_n, MAP_DIR_D))
-				{
-					flags = dir_flags(ses, room_n->vnum, MAP_EXIT_D); // merging
+	exit = find_exit(ses, room, arg1);
 
 
-					if (HAS_BIT(flags, EXIT_FLAG_AVOID))
-					{
-						cat_sprintf(buf, "%s-%s", ses->map->color[MAP_COLOR_AVOID], ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else if (HAS_BIT(flags, EXIT_FLAG_HIDE))
-					{
-						cat_sprintf(buf, "%s-%s", ses->map->color[MAP_COLOR_HIDE], ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else if (HAS_BIT(flags, EXIT_FLAG_INVIS))
-					{
-						cat_sprintf(buf, "%s-%s", ses->map->color[MAP_COLOR_INVIS], ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else
-					{
-						strcat(buf, "-");
-//						strcat(buf, "⏷");
-					}
-				}
-				else
-				{
-					strcat(buf, " ");
-				}
+	if (exit == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP: There's no exit named '%s'.", arg1);
+		return;
+	}
 
 
-				switch (HAS_BIT(exit_n, MAP_DIR_N|MAP_DIR_S))
-				{
-					case MAP_DIR_N:
-						strcat(buf, "↑");
-						break;
-					case MAP_DIR_S:
-						strcat(buf, "↓");
-						break;
-					case MAP_DIR_N|MAP_DIR_S:
-						strcat(buf, "│");
-						break;
-					default:
-						strcat(buf, " ");
-						break;
-				}
+	vnum = exit->vnum;
 
 
-				if (room && room->exit_grid[EXIT_GRID_U])
-				{
-					flags = room->exit_grid[EXIT_GRID_U]->flags;
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
+	{
+		check_append_path(ses, exit->cmd, "", 0);
+	}
+	else
+	{
+		check_append_path(ses, exit->name, "", 0);
+	}
 
 
-					if (HAS_BIT(flags, EXIT_FLAG_AVOID))
-					{
-						cat_sprintf(buf, "%s+%s", ses->map->color[MAP_COLOR_AVOID], ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else if (HAS_BIT(flags, EXIT_FLAG_HIDE))
-					{
-						cat_sprintf(buf, "%s+%s", ses->map->color[MAP_COLOR_HIDE], ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else if (HAS_BIT(flags, EXIT_FLAG_INVIS))
-					{
-						cat_sprintf(buf, "%s+%s", ses->map->color[MAP_COLOR_INVIS], ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else
-					{
-						strcat(buf, "+");
-//						strcat(buf, "⏶");
-					}
-				}
-				else
-				{
-					strcat(buf, " ");
-				}
-				break;
+	SET_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
+	SET_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
 
 
-			case 2:
-				if (room == NULL)
-				{
-					if (HAS_BIT(exit_w, MAP_DIR_W))
-					{
-						sprintf(buf, "%s→    ", ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else
-					{
-						strcpy(buf, "     ");
-					}
-					pop_call();
-					return buf;
-				}
+	while (get_room_exits(ses, vnum) == 2)
+	{
+		exit = ses->map->room_list[vnum]->f_exit;
 
 
-				switch (exit_w)
-				{
-					case 0:
-						strcpy(buf, "  ");
-						break;
-					case MAP_DIR_W:
-						sprintf(buf, "%s→ ", ses->map->color[MAP_COLOR_EXIT]);
-						break;
-					case MAP_DIR_E:
-						sprintf(buf, "%s ←", ses->map->color[MAP_COLOR_EXIT]);
-						break;
-					case MAP_DIR_W|MAP_DIR_E:
-						if (room->exit_grid[EXIT_GRID_W]->vnum == room_w->vnum && room_w->exit_grid[EXIT_GRID_E]->vnum == room->vnum)
-						{
-							// ‒‒
-							sprintf(buf, "%s──", ses->map->color[MAP_COLOR_EXIT]);
-						}
-						else
-						{
-							sprintf(buf, "%s→←", ses->map->color[MAP_COLOR_EXIT]);
-						}
-						break;
-					default:
-						strcat(buf, "??");
-						break;
-				}
+		if (HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_PATH))
+		{
+			exit = ses->map->room_list[vnum]->l_exit;
 
 
-				if (room->vnum == ses->map->in_room)
-				{
-					cat_sprintf(buf, "%s%s%s%s%s", room_left, ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index], room_right, ses->map->color[MAP_COLOR_EXIT]);
-					pop_call();
-					return buf;
-				}
-				else
-				{
-					// use a yet to be made 1x1 8 exit legend for void room drawing, call semi-recursively.
+			if (HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_PATH))
+			{
+				break;
+			}
+		}
 
 
-					if (strip_color_strlen(ses, room->symbol) > 1)
-					{
-						cat_sprintf(buf, "%s%-3s%s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol, ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
-					{
-						if (HAS_BIT(room->exit_dirs, MAP_DIR_W) && !HAS_BIT(room->exit_dirs, MAP_DIR_NW|MAP_DIR_SW))
-						{
-							cat_sprintf(buf, "─");
-						}
-						else
-						{
-							cat_sprintf(buf, " ");
-						}
+		if (!HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_VOID))
+		{
+			if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
+			{
+				check_append_path(ses, exit->cmd, "", 0);
+			}
+			else
+			{
+				check_append_path(ses, exit->name, "", 0);
+			}
+		}
 
 
-						if (*room->symbol != ' ' && strip_color_strlen(ses, room->symbol) == 1)
-						{
-							cat_sprintf(buf, "%s%-1s%s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol, ses->map->color[MAP_COLOR_EXIT]);
-						}
-						else
-						{
+		vnum = exit->vnum;
 
 
-							if (room->vnum == ses->map->in_room)
-							{
-								cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_USER]);
-							}
-							else
-							{
-								cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
-							}
+		SET_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
+	}
 
 
-							switch (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E|MAP_DIR_S|MAP_DIR_W|MAP_DIR_NW|MAP_DIR_NE|MAP_DIR_SE|MAP_DIR_SW))
-							{
-								case MAP_DIR_S:
-								case MAP_DIR_N:
-								case MAP_DIR_N|MAP_DIR_S:
-									cat_sprintf(buf, "│");
-									break;
+	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
 
 
-								case MAP_DIR_E:
-								case MAP_DIR_W:
-								case MAP_DIR_E|MAP_DIR_W:
-									cat_sprintf(buf, "─");
-									break;
+	if (run)
+	{
+		path_run(ses, arg2);
+	}
+}
 
 
-								default:
-									cat_sprintf(buf, "*");
-									break;
-							}
+void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int x, int y, int height, int width)
+{
+	char exit[10];
+	int max_x, max_y;
+	int top_row, top_col, bot_row, bot_col, rows, cols, char_height;
 
 
-							if (room->vnum == ses->map->in_room)
-							{
-								cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
-							}
-						}
+	push_call("map_mouse_handler(%p,%p,%p,%d,%d)",ses,arg1,arg2,x,y);
 
 
-						if (HAS_BIT(room->exit_dirs, MAP_DIR_E) && !HAS_BIT(room->exit_dirs, MAP_DIR_NE|MAP_DIR_SE))
-						{
-							cat_sprintf(buf, "─");
-						}
-						else
-						{
-							cat_sprintf(buf, " ");
-						}
-					}
-					else
-					{
-						cat_sprintf(buf, "%s%s%-1s%s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, room_right, ses->map->color[MAP_COLOR_EXIT]);
-					}
-				}
-				break;
-		}
+	if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) || ses->map->room_list[ses->map->in_room] == NULL)
+	{
 		pop_call();
 		pop_call();
-		return buf;
+		return;
+	}
+
+	if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
+	{
+		if (arg1 && arg2)
+		{
+//			do_screen(ses, "{RAISE} {SCREEN MOUSE LOCATION}");
+		}
 	}
 	}
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
+	exit[0] = 0;
+
+	char_height = 1 + height % UMAX(1, gtd->screen->char_height);
+
+	if (ses->map->rows > 1 && ses->map->cols > 1)
+	{
+		top_row = ses->map->top_row;
+		top_col = ses->map->top_col;
+		bot_row = ses->map->bot_row;
+		bot_col = ses->map->bot_col;
+		rows    = ses->map->rows;
+		cols    = ses->map->cols;
+	}
+	else
+	{
+		top_row = 1;
+		top_col = 1;
+		bot_row = ses->split->top_row - 2;
+		bot_col = gtd->screen->cols;
+		rows    = ses->split->top_row - 2;
+		cols    = gtd->screen->cols;
+	}
+
+	y = y - 1;
+	x = x - 1;
+
+	if (y > bot_row || y < top_row)
+	{
+		pop_call();
+		return;
+	}
+
+	if (x > bot_col || x < top_col)
+	{
+		pop_call();
+		return;
+	}
+
+	y = y + 1 - top_row;
+	x = x + 1 - top_col;
+
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
+	{
+		char *grid[] = { "nw",  "2",  "n",  "u", "ne",  "6",
+				  "w", "RL", "RC", "RR",  "e", "e",
+				 "sw",  "d",  "s", "16", "se", "18" };
+
+//		tintin_printf2(ses, "\e[1;32mdebug: y=%d x=%d mod(y)=%d mod(x)=%d", y / 3, y / 6, y % 3, x % 6);
+
+		strcpy(exit, grid[URANGE(0, y % 3 * 6 + x % 6, 17)]);
+
+		y /= 3;
+		x /= 6;
+
+		max_y = 2 + rows / 3;
+		max_x = 2 + cols / 6;
+	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
+	{
+		char *grid[] = { "se", "sw",  "d",  "s",  "5",   "ne", "nw",  "8",  "n",  "u",   "e", "w", "RL", "RC", "RR",   "e",  "w", "RL", "RC", "RR" };
+		int x_mod, y_mod;
+
+		y_mod = y  % 2 * 2 + (char_height * 2 / gtd->screen->char_height ? 1 : 0);
+		x_mod = x  % 5;
+
+		y = y  / 2;
+		x = x  / 5;
+
+		strcpy(exit, grid[URANGE(0, 5 * y_mod + x_mod, 20)]);
+
+		switch (5 * y_mod + x_mod)
+		{
+			case 0:
+				y--;
+			case 5:
+			case 10:
+			case 15:
+				x--;
+				break;
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				y--;
+				break;
+		}
+
+//		tintin_printf2(ses, "\e[1;32mdebug: y=%d x=%d y_mod=%d x_mod=%d y+x=%d y=%d x=%d", y, x, y_mod, x_mod, 5*y_mod+x_mod, y, x);
+
+		max_y = 2 + (rows + 2) / 2;
+		max_x = 2 + (cols + 4) / 5;
+	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
+	{
+		y /= 2;
+		x /= 5;
+
+		max_y = 2 + rows / 2;
+		max_x = 2 + cols / 5;
+	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
+	{
+		x /= 2;
+
+		max_y = 2 + rows;
+		max_x = 2 + cols / 2;
+	}
+	else
+	{
+		max_y = 2 + rows;
+		max_x = 2 + cols;
+	}
+
+	y = max_y - 1 - y;
+
+	if (x < 0 || y < 0)
+	{
+		pop_call();
+		return;
+	}
+
+	if (max_x != map_grid_x || max_y != map_grid_y)
+	{
+		pop_call();
+		return;
+	}
+
+	if (ses->map->grid_rooms[x + 1 + max_x * (y - 1)])
+	{
+		if (arg1 && arg2)
+		{
+			check_all_events(ses, SUB_ARG, 2, 2, "MAP %s %s", arg1, arg2, ntos(ses->map->grid_rooms[x + 1 + max_x * (y - 1)]->vnum), exit);
+		}
+		else
+		{
+			check_all_events(ses, SUB_ARG, 0, 2, "MAP MOUSE LOCATION", ntos(ses->map->grid_rooms[x + 1 + max_x * (y - 1)]->vnum), exit);
+		}
+	}
+	pop_call();
+	return;
+}
+
+void update_terrain(struct session *ses)
+{
+	struct room_data *room;
+	int vnum;
+
+	DEL_BIT(ses->map->flags, MAP_FLAG_UPDATETERRAIN);
+
+	for (vnum = 1 ; vnum < ses->map->size ; vnum++)
+	{
+		room = ses->map->room_list[vnum];
+
+		if (room)
+		{
+			room->terrain_index = bsearch_alpha_list(ses->list[LIST_TERRAIN], room->terrain, 0);
+		}
+	}
+}
+
+/*
+	Map options
+*/
+
+
+DO_MAP(map_at)
+{
+	int new_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);
+
+	ses->map->at_room = ses->map->in_room;
+
+	if (new_room == 0)
+	{
+		new_room = find_location(ses, arg1);
+
+		if (new_room == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP AT: Couldn't find room or exit {%s}.", arg1);
+
+			return;
+		}
+	}
+
+	ses->map->in_room = new_room;
+
+	script_driver(ses, LIST_COMMAND, arg2);
+
+	if (ses->map)
+	{
+		ses->map->in_room = ses->map->at_room;
+	}
+}
+
+DO_MAP(map_center)
+{
+	char arg3[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		ses->map->center_x = ses->map->center_y = ses->map->center_z = 0;
+	}
+	else
+	{
+		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);
+
+		if (!is_math(ses, arg1) || !is_math(ses, arg2) || !is_math(ses, arg3))
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP CENTER {X} {Y} {Z}");
+
+			return;
+		}
+		else
+		{
+			ses->map->center_x = get_number(ses, arg1);
+			ses->map->center_y = get_number(ses, arg2);
+			ses->map->center_z = get_number(ses, arg3);
+
+			show_message(ses, LIST_COMMAND, "#MAP CENTER SET TO {%d} {%d} {%d}", ses->map->center_x, ses->map->center_y, ses->map->center_z);
+		}
+	}
+}
+
+DO_MAP(map_color)
+{
+	char buf[BUFFER_SIZE];
+	int index;
+
+	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 (!strcasecmp(arg1, "RESET"))
+		{
+			for (index = 0 ; map_color_table[index].name ; index++)
+			{
+				strncpy(ses->map->color[index], map_color_table[index].code, COLOR_SIZE - 1);
+				strncpy(ses->map->color_raw[index], map_color_table[index].code, COLOR_SIZE - 1);
+			}
+
+			return;
+		}
+
+		for (index = 0 ; map_color_table[index].name ; index++)
+		{
+			if (is_abbrev(arg1, map_color_table[index].name))
+			{
+				if (is_abbrev(arg2, "RESET"))
+				{
+					translate_color_names(ses, map_color_table[index].code, ses->map->color[index]);
+					strncpy(ses->map->color_raw[index], map_color_table[index].code, COLOR_SIZE - 1);
+				}
+				else
+				{
+					translate_color_names(ses, arg2, ses->map->color[index]);
+					strncpy(ses->map->color_raw[index], arg2, COLOR_SIZE - 1);
+				}
+
+				get_color_names(ses, ses->map->color[index], buf);
+
+				show_message(ses, LIST_COMMAND, "#MAP COLOR %s%10s\e[0m SET TO {%s}", ses->map->color[index], buf, map_color_table[index].name, ses->map->color_raw[index]);
+
+				break;
+			}
+		}
+
+		if (map_color_table[index].name == NULL)
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP COLOR {AVOID|BACKGROUND|EXIT|HIDE|INVIS|PATH|ROOM|USER} {COLOR CODE}");
+
+			return;
+		}
+		show_message(ses, LIST_COMMAND, "#MAP: %s color set to: %s", arg1, arg2);
+	}
+	else
+	{
+		for (index = 0 ; map_color_table[index].name ; index++)
+		{
+			get_color_names(ses, ses->map->color[index], buf);
+
+			show_message(ses, LIST_COMMAND, "#MAP COLOR %s%10s\e[0m SET TO {%s}", buf, map_color_table[index].name, ses->map->color_raw[index]);
+		}
+	}
+}
+
+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_debug)
+{
+	tintin_printf2(ses, "max spatial grid x: %d", ses->map->max_grid_x);
+	tintin_printf2(ses, "max spatial grid y: %d", ses->map->max_grid_y);
+	tintin_printf2(ses, "     max undo size: %d", ses->map->undo_size);
+	tintin_printf2(ses, "           in room: %d", ses->map->in_room);
+	tintin_printf2(ses, "           at room: %d", ses->map->at_room);
+	tintin_printf2(ses, "         last room: %d", ses->map->last_room);
+	tintin_printf2(ses, "             stamp: %d", ses->map->search->stamp);
+	tintin_printf2(ses, "            length: %f", ses->map->room_list[ses->map->in_room]->length);
+	tintin_printf2(ses, "          nofollow: %d", ses->map->nofollow);
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1)
+	{
+		if (is_abbrev(arg1, "undo"))
+		{
+			struct link_data *link;
+
+			for (link = ses->map->undo_head ; link ; link = link->next)
+			{
+				tintin_printf2(ses, "%05s %05s %s", link->str1, link->str2, link->str3);
+			}
+		}
+	}
+}
+
+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 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP DELETE {%s} - No room with that vnum found", arg1);
+
+			return;
+		}
+	}
+	else
+	{
+		exit = find_exit(ses, ses->map->in_room, arg1);
+
+		if (exit)
+		{
+			room = exit->vnum;
+		}
+
+		if (exit == NULL)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP: No exit with that name found");
+			
+			return;
+		}
+
+		room = exit->vnum;
+	}
+
+	if (room == ses->map->in_room)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP: You must first leave the room you're trying to delete");
+		
+		return;
+	}
+
+	delete_room(ses, room, TRUE);
+
+	show_message(ses, LIST_COMMAND, "#MAP: Room {%d} deleted", room);
+}
+
+DO_MAP(map_destroy)
+{
+	struct exit_data *exit;
+	int index, cnt;
+
+	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 (is_abbrev(arg1, "AREA"))
+	{
+		if (*arg2 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP DESTROY AREA {<AREA NAME>}");
+
+			return;
+		}
+
+		if (ses->map->room_list[ses->map->in_room] && !strcmp(arg2, ses->map->room_list[ses->map->in_room]->area))
+		{
+			show_error(ses, LIST_COMMAND, "#MAP DESTROY AREA: YOU MUST FIRST LEAVE THE AREA YOU ARE TRYING TO DESTROY.");
+
+			return;
+		}
+
+		for (index = cnt = 0 ; index < ses->map->size ; index++)
+		{
+			if (ses->map->room_list[index])
+			{
+				if (!strcmp(arg2, ses->map->room_list[index]->area))
+				{
+					cnt++;
+
+					delete_room(ses, index, FALSE);
+				}
+			}
+		}
+
+		for (index = 0 ; index < ses->map->size ; index++)
+		{
+			if (ses->map->room_list[index])
+			{
+				for (exit = ses->map->room_list[index]->f_exit ; exit ; exit = exit->next)
+				{
+					if (ses->map->room_list[exit->vnum] == NULL)
+					{
+						delete_exit(ses, index, exit);
+
+						if (ses->map->room_list[index]->f_exit)
+						{
+							exit = ses->map->room_list[index]->f_exit;
+						}
+						else
+						{
+							break;
+						}
+					}
+				}
+			}
+		}
+		show_message(ses, LIST_COMMAND, "#MAP DESTROY AREA: DELETED %d ROOMS.", cnt);
+	}
+	else if (is_abbrev(arg1, "WORLD"))
+	{
+		cnt = delete_map(ses);
+
+		tintin_printf2(ses, "#MAP DESTROY WORLD: DELETED %d ROOMS.", cnt);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP DESTROY {AREA|WORLD} {<ARGUMENT>}");
+	}
+}
+
+DO_MAP(map_dig)
+{
+	char arg3[BUFFER_SIZE];
+	int room;
+	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);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP DIG {<DIRECTION>|<VNUM>} {<LOCATION>|NEW}");
+		
+		return;
+	}
+
+	room = atoi(arg1);
+
+	if (room > 0 && room < ses->map->size)
+	{
+		if (ses->map->room_list[room] == NULL)
+		{
+			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE);
+
+			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
+		}
+		return;
+	}
+
+	exit = find_exit(ses, ses->map->in_room, arg1);
+
+	if (exit)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP DIG: There is already a room in that direction.");
+		return;
+	}
+
+	if (*arg2 && strcasecmp(arg2, "new"))
+	{
+		if (is_number(arg2))
+		{
+			room = get_number(ses, arg2);
+		}
+		else
+		{
+			room = find_room(ses, arg2);
+		}
+
+		if (room == 0 && !strcasecmp(arg3, "new"))
+		{
+			room = find_new_room(ses);
+		}
+
+		if (room <= 0 || room >= ses->map->size)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP DIG {%s}: Couldn't find room {%s}.", arg1, arg2);
+
+			return;
+		}
+
+		if (ses->map->room_list[room] == NULL)
+		{
+			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE|MAP_UNDO_LINK);
+
+			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {%s}", room, ses->map->search->id ? ses->map->search->id : "");
+			create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+		}
+		else
+		{
+			add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_LINK);
+
+			create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+		}
+		return;
+	}
+
+	room = find_coord(ses, arg1);
+
+	if (room && strcasecmp(arg2, "new"))
+	{
+		show_message(ses, LIST_COMMAND, "#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);
+
+		create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+	}
+	else
+	{
+		for (room = 1 ; room < ses->map->size ; room++)
+		{
+			if (ses->map->room_list[room] == NULL)
+			{
+				break;
+			}
+		}
+
+		if (room == ses->map->size)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP DIG: Maximum amount of rooms of %d reached.", ses->map->size);
+			
+			return;
+		}
+		add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE|MAP_UNDO_LINK);
+
+		create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
+		create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
+	}
+
+	if ((node = search_node_list(ses->list[LIST_PATHDIR], arg1)) != NULL)
+	{
+		if (find_exit(ses, room, node->arg2) == NULL)
+		{
+			create_exit(ses, room, "{%d} {%s} {%s}", ses->map->in_room, node->arg2, node->arg2);
+		}
+	}
+}
+
+void exit_edit(struct session *ses, struct exit_data *exit, char *arg, char *arg1, char *arg2, char *arg3)
+{
+	int room, dir;
+
+	if (*arg2 == 0)
+	{
+		tintin_printf2(ses, "    color: %s", str_convert_meta(exit->color, TRUE));
+		tintin_printf2(ses, "  command: %s", exit->cmd);
+		tintin_printf2(ses, "direction: %d", exit->dir);
+		tintin_printf2(ses, "    flags: %d", exit->flags);
+		tintin_printf2(ses, "  get/set: %s", exit->data);
+		tintin_printf2(ses, "     name: %s", exit->name);
+		tintin_printf2(ses, "     vnum: %d", exit->vnum);
+		tintin_printf2(ses, "   weight: %.3f", exit->weight);
+	}
+	else if (is_abbrev(arg2, "COLOR"))
+	{
+		RESTRING(exit->color, arg3);
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : COLOR SET TO {%s}.", arg, arg1, exit->color);
+	}
+	else if (is_abbrev(arg2, "COMMAND"))
+	{
+		RESTRING(exit->cmd, arg3);
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : COMMAND SET TO {%s}.", arg, arg1, exit->cmd);
+	}
+	else if (is_abbrev(arg2, "DIRECTION"))
+	{
+		if (is_math(ses, arg3))
+		{
+			dir = (int) get_number(ses, arg3);
+		}
+		else if ((dir = get_exit_dir(ses, arg3)) == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP %s {%s} : DIRECTION {%s} NOT FOUND.", arg, arg1, arg3);
+			
+			return;
+		}
+
+		exit->dir = dir;
+
+		exit->grid = dir_to_grid(exit->dir);
+
+		set_room_exits(ses, ses->map->in_room);
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : DIRECTION {%s} SET TO {%d}.", arg, arg1, arg3, dir);
+	}
+	else if (is_abbrev(arg2, "FLAGS"))
+	{
+		exit->flags = (int) get_number(ses, arg3);
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : FLAGS SET TO {%d}.", arg, arg1, exit->flags);
+	}
+	else if (is_abbrev(arg2, "GET"))
+	{
+		if (*arg3)
+		{
+			set_nest_node_ses(ses, arg3, "%s", exit->data);
+		}
+		else
+		{
+			tintin_printf2(ses, "#MAP %s GET: No destination variable.", arg);
+		}
+	}
+	else if (is_abbrev(arg2, "NAME"))
+	{
+		RESTRING(exit->name, arg3);
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : NAME SET TO {%s}.", arg, arg1, exit->name);
+	}
+	else if (is_abbrev(arg2, "SAVE"))
+	{
+		if (*arg3)
+		{
+			set_nest_node_ses(ses, arg3, "{command}{%s}{destination}{%d}{dir}{%d}{flags}{%d}{name}{%s}{vnum}{%d}{weight}{%.3f}", exit->cmd, tunnel_void(ses, ses->map->in_room, exit->vnum, exit->dir), exit->dir, exit->flags, exit->name, exit->vnum, exit->weight);
+		}
+		else
+		{
+			show_error(ses, LIST_COMMAND, "#MAP %s SAVE: No destination variable.", arg);
+		}
+	}
+	else if (is_abbrev(arg2, "SET"))
+	{
+		RESTRING(exit->data, arg3);
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : DATA SET TO {%s}.", arg, arg1, exit->data);
+	}
+	else if (is_abbrev(arg2, "VNUM"))
+	{
+		room = atoi(arg3);
+
+		if (room <= 0 || room >= ses->map->size)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP %s VNUM: Invalid room vnum: %d.", arg, room);
+			return;
+		}
+
+		if (ses->map->room_list[room] == NULL)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP %s VNUM: Non existant room vnum: %d.", arg, room);
+			return;
+		}
+		exit->vnum = room;
+
+		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : VNUM SET TO {%s}.", arg, arg1, arg3);
+	}
+	else if (is_abbrev(arg2, "WEIGHT"))
+	{
+		if (get_number(ses, arg3) < 0.001)
+		{
+			show_message(ses, LIST_COMMAND, "#MAP %s {%s} : WEIGHT SHOULD BE AT LEAST 0.001", arg, arg1);
+		}
+		else
+		{
+			exit->weight = (float) get_number(ses, arg3);
+
+			show_message(ses, LIST_COMMAND, "#MAP %s {%s} : WEIGHT SET TO {%.3f}", arg, arg1, exit->weight);
+		}
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "Syntax: #MAP %s {<NAME>} {COMMAND|DIRECTION|GET|NAME|FLAGS|SAVE|SET|VNUM|WEIGHT} {<argument>}", arg);
+	}
+}
+
+DO_MAP(map_entrance)
+{
+	char arg3[BUFFER_SIZE];
+	struct exit_data *exit, *rev_exit;
+
+	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)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP ENTRANCE: Exit {%s} not found.", arg1);
+		
+		return;
+	}
+
+	rev_exit = ses->map->room_list[exit->vnum]->exit_grid[revdir_to_grid(exit->dir)];
+
+	if (rev_exit == NULL)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP ENTRANCE {%s}: Exit {%s} has no matching entrance.");
+
+		return;
+	}
+
+	exit_edit(ses, rev_exit, "ENTRANCE", arg1, arg2, arg3);
+}
+
+DO_MAP(map_exit)
+{
+	char arg3[BUFFER_SIZE];
+	struct exit_data *exit;
+
+	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)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP EXIT: Exit {%s} not found.", arg1);
+		
+		return;
+	}
+
+	exit_edit(ses, exit, "EXIT", arg1, arg2, arg3);
+}
+
+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)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP EXITFLAG: EXIT {%s} NOT FOUND.", arg1);
+
+		return;
+	}
+
+	if (*arg2 == 0)
+	{
+		tintin_printf2(ses, "#MAP: AVOID FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_AVOID) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: HIDE FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_HIDE) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: INVIS FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_INVIS) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: BLOCK FLAG IS SET TO: %s.", HAS_BIT(exit->flags, EXIT_FLAG_BLOCK) ? "ON" : "OFF");
+
+		return;
+	}
+
+	if (is_abbrev(arg2, "AVOID"))
+	{
+		flag = EXIT_FLAG_AVOID;
+	}
+	else if (is_abbrev(arg2, "BLOCK"))
+	{
+		flag = EXIT_FLAG_BLOCK;
+	}
+	else if (is_abbrev(arg2, "HIDE"))
+	{
+		flag = EXIT_FLAG_HIDE;
+	}
+	else if (is_abbrev(arg2, "INVISIBLE"))
+	{
+		flag = EXIT_FLAG_INVIS;
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} <AVOID|HIDE|INVIS> [ON|OFF]", arg1);
+
+		return;
+	}
+
+	if (*arg3 == 0)
+	{
+		TOG_BIT(exit->flags, flag);
+	}
+	else if (is_abbrev(arg3, "ON"))
+	{
+		SET_BIT(exit->flags, flag);
+	}
+	else if (is_abbrev(arg3, "OFF"))
+	{
+		DEL_BIT(exit->flags, flag);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} {%s} [ON|OFF]", arg3);
+	}
+
+	if (is_abbrev(arg2, "AVOID"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: AVOID FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_AVOID) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg2, "BLOCK"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: BLOCK FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_BLOCK) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg2, "HIDE"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: HIDE FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_HIDE) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg2, "INVISIBLE"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: INVIS FLAG SET TO %s.", HAS_BIT(exit->flags, EXIT_FLAG_INVIS) ? "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, "vtmap"))
+		{
+			flag   = MAP_FLAG_VTMAP;
+		}
+		else if (is_abbrev(arg1, "asciigraphics"))
+		{
+			flag   = MAP_FLAG_ASCIIGRAPHICS;
+			unflag = MAP_FLAG_MUDFONT|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+		}
+		else if (is_abbrev(arg1, "asciilength"))
+		{
+			flag   = MAP_FLAG_ASCIIVNUMS|MAP_FLAG_ASCIILENGTH;
+		}
+		else if (is_abbrev(arg1, "asciivnums"))
+		{
+			flag   = MAP_FLAG_ASCIIVNUMS;
+			unflag = MAP_FLAG_ASCIILENGTH;
+		}
+		else if (is_abbrev(arg1, "blockgraphics"))
+		{
+			flag = MAP_FLAG_BLOCKGRAPHICS;
+			unflag = MAP_FLAG_MUDFONT|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_ASCIIGRAPHICS;
+		}
+		else if (is_abbrev(arg1, "direction"))
+		{
+			flag = MAP_FLAG_DIRECTION;
+		}
+		else if (is_abbrev(arg1, "mudfont"))
+		{
+			flag = MAP_FLAG_MUDFONT;
+			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+		}
+		else if (is_abbrev(arg1, "nofollow"))
+		{
+			flag = MAP_FLAG_NOFOLLOW;
+		}
+		else if (is_abbrev(arg1, "simplegraphics"))
+		{
+			unflag = MAP_FLAG_ASCIIVNUMS|MAP_FLAG_SYMBOLGRAPHICS|MAP_FLAG_MUDFONT|MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+		}
+		else if (is_abbrev(arg1, "symbolgraphics"))
+		{
+			flag = MAP_FLAG_SYMBOLGRAPHICS;
+			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS;
+		}
+		else if (is_abbrev(arg1, "terrain"))
+		{
+			flag = MAP_FLAG_TERRAIN;
+		}
+		else if (is_abbrev(arg1, "unicodegraphics"))
+		{
+			flag = MAP_FLAG_UNICODEGRAPHICS;
+			unflag = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_MUDFONT|MAP_FLAG_BLOCKGRAPHICS;
+		}
+		else
+		{
+			show_error(ses, LIST_COMMAND, "#MAP: Invalid flag {%s}.", arg1);
+
+			return;
+		}
+	}
+	else
+	{
+		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: BlockGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Direction flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: MudFont flag is set to %s", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: NoFollow flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: SimpleGraphics flag is set to %s.", !HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS|MAP_FLAG_SYMBOLGRAPHICS|MAP_FLAG_MUDFONT|MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_UNICODEGRAPHICS|MAP_FLAG_BLOCKGRAPHICS) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Static flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: SymbolGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Terrain flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_TERRAIN) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: UnicodeGraphics flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: VTmap flag is set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "ON" : "OFF");
+
+		return;
+	}
+
+	if (is_abbrev(arg2, "ON"))
+	{
+		SET_BIT(ses->map->flags, flag);
+	}
+	else if (is_abbrev(arg2, "OFF"))
+	{
+		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, "asciigraphics"))
+	{
+		show_message(ses, LIST_COMMAND, "#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, LIST_COMMAND, "#MAP: AsciiVnums flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "direction"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: Direction flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "mudfont"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: MudFont flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "nofollow"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: NoFollow flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "static"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "simplegraphics"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: All graphic modes have been disabled.");
+	}
+	else if (is_abbrev(arg1, "symbolgraphics"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: SymbolGraphics flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "terrain"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: Terrain flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_TERRAIN) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "unicodegraphics"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: UnicodeGraphics flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) ? "ON" : "OFF");
+	}
+	else if (is_abbrev(arg1, "vtmap"))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: VTmap flag set to %s.", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "ON" : "OFF");
+	}
+
+
+}
+
+DO_MAP(map_get)
+{
+	struct room_data *room = ses->map->room_list[ses->map->in_room];
+	struct exit_data *exit;
+	char exits[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(ses, arg2, "0");
+	}
+	else if (*arg1 == 0 || *arg2 == 0)
+	{
+		tintin_printf2(ses, " worldflags: %d", ses->map->flags);
+		tintin_printf2(ses, "  worldsize: %d", ses->map->size);
+		tintin_printf2(ses, "");
+		tintin_printf2(ses, "   roomvnum: %d", room->vnum);
+		tintin_printf2(ses, "   roomarea: %s", room->area);
+		tintin_printf2(ses, "  roomcolor: %s", room->color);
+		tintin_printf2(ses, "   roomdata: %s", room->data);
+		tintin_printf2(ses, "   roomdesc: %s", room->desc);
+		tintin_printf2(ses, "  roomexits: %d", get_room_exits(ses, room->vnum));
+		tintin_printf2(ses, "  roomflags: %d", room->flags);
+		tintin_printf2(ses, "     roomid: %s", room->id);
+		tintin_printf2(ses, "   roomname: %s", room->name);
+		tintin_printf2(ses, "   roomnote: %s", room->note);
+		tintin_printf2(ses, " roomsymbol: %s", room->symbol);
+		tintin_printf2(ses, "roomterrain: %s", room->terrain);
+		tintin_printf2(ses, " roomweight: %.3f", room->weight);
+	}
+	else
+	{
+		if (is_abbrev(arg1, "all"))
+		{
+			exits[0] = 0;
+
+			for (exit = room->f_exit ; exit ; exit = exit->next)
+			{
+				cat_sprintf(exits, "{%s}{%d}", exit->name, exit->vnum);
+			}
+			set_nest_node_ses(ses, arg2, "{area}{%s}{color}{%s}{data}{%s}{desc}{%s}{exits}{%s}{flags}{%d}{id}{%d}{name}{%s}{note}{%s}{symbol}{%s}{terrain}{%s}{vnum}{%d}{weight}{%.3f}", room->area, room->color, room->data, room->desc, exits, room->flags, room->id, room->name, room->note, room->symbol, room->terrain, room->vnum, room->weight);
+		}
+		else if (is_abbrev(arg1, "roomarea"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->area);
+		}
+		else if (is_abbrev(arg1, "roomcolor"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->color);
+		}
+		else if (is_abbrev(arg1, "roomdata"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->data);
+		}
+		else if (is_abbrev(arg1, "roomdesc"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->desc);
+		}
+		else if (is_abbrev(arg1, "roomflags"))
+		{
+			set_nest_node_ses(ses, arg2, "%d", room->flags);
+		}
+		else if (is_abbrev(arg1, "roomid"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->id);
+		}
+		else if (is_abbrev(arg1, "roomname"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->name);
+		}
+		else if (is_abbrev(arg1, "roomnote"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->note);
+		}
+		else if (is_abbrev(arg1, "roomsymbol"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->symbol);
+		}
+		else if (is_abbrev(arg1, "roomterrain"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", room->terrain);
+		}
+		else if (is_abbrev(arg1, "roomvnum"))
+		{
+			set_nest_node_ses(ses, arg2, "%d", room->vnum);
+		}
+		else if (is_abbrev(arg1, "roomweight"))
+		{
+			set_nest_node_ses(ses, arg2, "%.3f", room->weight);
+		}
+		else if (is_abbrev(arg1, "roomexits"))
+		{
+			exits[0] = 0;
+
+			for (exit = room->f_exit ; exit ; exit = exit->next)
+			{
+				cat_sprintf(exits, "{%s}{%d}", exit->name, exit->vnum);
+			}
+			set_nest_node_ses(ses, arg2, "%s", exits);
+		}
+		else if (is_abbrev(arg1, "worldflags"))
+		{
+			set_nest_node_ses(ses, arg2, "%d", ses->map->flags);
+		}
+		else if (is_abbrev(arg1, "worldsize"))
+		{
+			set_nest_node_ses(ses, arg2, "%d", ses->map->size);
+		}
+		else
+		{
+			show_message(ses, LIST_COMMAND, "#MAP GET: unknown option: %s.", arg1);
+		}
+	}
+}
+
+DO_MAP(map_global)
+{
+	int room;
+
+	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP GLOBAL: GLOBAL ROOM SET TO VNUM %d.", ses->map->global_vnum);
+	}
+	else if (!strcmp(arg1, "0"))
+	{
+		ses->map->global_vnum = ses->map->global_exit->vnum = 0;
+
+		show_message(ses, LIST_COMMAND, "#MAP GLOBAL: GLOBAL ROOM SET TO VNUM %d.", 0);
+	}
+	else
+	{
+		room = find_room(ses, arg);
+
+		if (room)
+		{
+			ses->map->global_vnum = ses->map->global_exit->vnum = room;
+
+			show_message(ses, LIST_COMMAND, "#MAP GLOBAL: GLOBAL ROOM SET TO VNUM %d.", room);
+		}
+		else
+		{
+			show_message(ses, LIST_COMMAND, "#MAP GLOBAL: COULDN'T FIND ROOM %s.", arg1);
+		}
+	}
+}
+
+DO_MAP(map_goto)
+{
+	int room;
+
+	room = find_room(ses, arg);
+
+	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); // look for dig argument
+
+	if (room == 0 && ses->map->search->vnum > 0 && ses->map->search->vnum < ses->map->size && !strcasecmp(arg2, "dig"))
+	{
+		room = ses->map->search->vnum;
+
+		create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
+	}
+
+	if (room == 0)
+	{
+		room = find_room(ses, arg1);
+	}
+
+	if (room == 0 && ses->map->search->id && *ses->map->search->id && !strcasecmp(arg2, "dig"))
+	{
+		room = find_new_room(ses);
+
+		if (room)
+		{
+			create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {%s}", room, ses->map->search->id);
+		}
+	}
+
+	if (room == 0 && ses->map->in_room)
+	{
+		room = find_path(ses, arg1);
+
+		if (room == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP GOTO: COULDN'T FIND ROOM OR EXIT {%s}.", arg1);
+
+			return;
+		}
+	}
+
+	if (room == 0)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP GOTO: COULDN'T FIND ROOM %s.", arg1);
+
+		return;
+	}
+	add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_MOVE);
+
+	goto_room(ses, room);
+
+	show_message(ses, LIST_COMMAND, "#MAP GOTO: MOVED TO ROOM %d {%s}.", room, *ses->map->room_list[room]->name ? ses->map->room_list[room]->name : ses->map->room_list[room]->id);
+}
+
+DO_MAP(map_info)
+{
+	int room, cnt, exits;
+	struct exit_data *exit;
+	struct room_data *in_room = ses->map->room_list[ses->map->in_room];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (ses->map->in_room)
+	{
+		exit = find_exit(ses, ses->map->in_room, arg1);
+
+		if (exit)
+		{
+			tintin_printf2(ses, "    color: %s", str_convert_meta(exit->color, TRUE));
+			tintin_printf2(ses, "  command: %s", exit->cmd);
+			tintin_printf2(ses, "direction: %d", exit->dir);
+			tintin_printf2(ses, "    flags: %d", exit->flags);
+			tintin_printf2(ses, "  get/set: %s", exit->data);
+			tintin_printf2(ses, "   length: %d", get_exit_length(ses, exit));
+			tintin_printf2(ses, "     name: %s", exit->name);
+			tintin_printf2(ses, "     vnum: %d", exit->vnum);
+			tintin_printf2(ses, "   weight: %.3f", exit->weight);
+
+			return;
+		}
+	}
+
+	for (room = cnt = exits = 0 ; room < ses->map->size ; room++)
+	{
+		if (ses->map->room_list[room])
+		{
+			cnt++;
+
+			exits += get_room_exits(ses, room);
+		}
+	}
+
+	tintin_printf2(ses, " %+16s %-7d %+16s %-7d %+16s %-7d", "Total rooms:", cnt, "Total exits:", exits, "World size:", ses->map->size);
+	tintin_printf2(ses, " %+16s %-7d %+16s %-7d %+16s %-7d",  "Direction:", ses->map->dir, "Last room:", ses->map->last_room, "Undo size:", ses->map->undo_size);
+	tintin_printf2(ses, "");
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s", "AsciiGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS) ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "AsciiVnums:", HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "BlockGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS) ? "on" : "off");
+	tintin_puts2(ses, arg1);
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s", "Direction:", HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION) ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "MudFont:", HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT) ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "Nofollow:", HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW) ? "on" : "off");
+	tintin_puts2(ses, arg1);
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s", "Static:", HAS_BIT(ses->map->flags, MAP_FLAG_STATIC) ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "SymbolGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "UnicodeGraphics:", HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) ? "on" : "off");
+	tintin_puts2(ses, arg1);
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s", "Vtmap:", HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) ? "on" : "off");
+	tintin_puts2(ses, arg1);
+
+/*
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s",
+	cat_sprintf(arg1, " %+16s %-7s",
+	cat_sprintf(arg1, " %+16s %-7s",
+	tintin_puts2(ses, arg1);
+*/
+
+	tintin_printf2(ses, "");
+	tintin_printf2(ses, " %+16s %4d %4d %4d %4d", "Map Offset:", ses->map->sav_top_row, ses->map->sav_top_col, ses->map->sav_bot_row, ses->map->sav_bot_col);
+	tintin_printf2(ses, " %+16s %4d %4d %4d %4d", "Current Offset:", ses->map->top_row, ses->map->top_col, ses->map->bot_row, ses->map->bot_col);
+
+	if (ses->map->in_room == 0)
+	{
+		return;
+	}
+
+	tintin_printf2(ses, "");
+
+	tintin_printf2(ses, "%+16s %s", "Room area:",    in_room->area);
+	tintin_printf2(ses, "%+16s %s", "Room data:",    in_room->data);
+	tintin_printf2(ses, "%+16s %s", "Room desc:",    in_room->desc);
+	tintin_printf2(ses, "%+16s %s", "Room id:",      in_room->id);
+	tintin_printf2(ses, "%+16s %s", "Room name:",    in_room->name);
+	tintin_printf2(ses, "%+16s %s", "Room note:",    in_room->note);
+	tintin_printf2(ses, "%+16s %s", "Room color:",   str_convert_meta(in_room->color, TRUE));
+	tintin_printf2(ses, "%+16s %s (%d)", "Room terrain:", in_room->terrain, in_room->terrain_index);
+
+	tintin_printf2(ses, "");
+	tintin_printf2(ses, " %+16s %-7d %+16s %-7.3f %+16s %-7s", "Room vnum:", ses->map->in_room, "Room weight:", in_room->weight, "Room symbol:", in_room->symbol);
+
+	tintin_printf2(ses, " %+16s %-7d %+16s %-7d %+16s %-7d",   "Center x:", ses->map->center_x, "Center y:", ses->map->center_y, "Center z:", ses->map->center_z);
+
+	tintin_printf2(ses, "");
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s",    "Avoid:", HAS_BIT(in_room->flags, ROOM_FLAG_AVOID)    ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s",   "Curved:", HAS_BIT(in_room->flags, ROOM_FLAG_CURVED)   ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s",     "Hide:", HAS_BIT(in_room->flags, ROOM_FLAG_HIDE)     ? "on" : "off");
+
+	tintin_puts2(ses, arg1);
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s",    "Invis:", HAS_BIT(in_room->flags, ROOM_FLAG_INVIS)    ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s",    "Leave:", HAS_BIT(in_room->flags, ROOM_FLAG_LEAVE)    ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s", "NoGlobal:", HAS_BIT(in_room->flags, ROOM_FLAG_NOGLOBAL) ? "on" : "off");
+	tintin_puts2(ses, arg1);
+
+	strcpy(arg1, "");
+	cat_sprintf(arg1, " %+16s %-7s",   "Static:", HAS_BIT(in_room->flags, ROOM_FLAG_STATIC)   ? "on" : "off");
+	cat_sprintf(arg1, " %+16s %-7s",     "Void:", HAS_BIT(in_room->flags, ROOM_FLAG_VOID)     ? "on" : "off");
+	tintin_puts2(ses, arg1);
+
+	tintin_printf2(ses, "");
+
+	for (exit = in_room->f_exit ; exit ; exit = exit->next)
+	{
+		tintin_printf2(ses, "%+16s %-3s (%3s)   to room: %-5d (%5s)", "Exit:", exit->name, exit->cmd, exit->vnum, ses->map->room_list[exit->vnum]->name);
+	}
+
+	tintin_printf2(ses, "");
+
+	for (room = 0 ; room < ses->map->size ; room++)
+	{
+		if (ses->map->room_list[room])
+		{
+			for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
+			{
+				if (exit->vnum == ses->map->in_room)
+				{
+					tintin_printf2(ses, "%+16s %-3s (%3s) from room: %-5d (%5s)", "Entrance:", exit->name, exit->cmd, room, ses->map->room_list[room]->name);
+				}
+			}
+		}
+	}
+/*
+	for (exit = in_room->f_exit ; exit ; exit = exit->next)
+	{
+		tintin_printf2(ses, "%+14s %-4s %+14s %5d %+14s %5d %+14s %5s", "Exit name:", exit->name, "vnum:", exit->vnum, "flags:", exit->flags, "command:", exit->cmd);
+		tintin_printf2(ses, "%+14s %s", "Exit data:", exit->data);
+	}
+*/
+}
+
+DO_MAP(map_insert)
+{
+	int room, in_room, to_room;
+	struct exit_data *exit;
+	struct listnode *node;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, 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)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP: There is no room in that direction.");
+
+		return;
+	}
+
+	if (room == ses->map->size)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP: Maximum amount of rooms of %d reached.", ses->map->size);
+		return;
+	}
+
+	if (node == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP: Given direction must be a pathdir.");
+		return;
+	}
+
+	in_room = ses->map->in_room;
+	to_room = exit->vnum;
+
+	add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_INSERT);
+
+	create_room(ses, "{%d} {0} {} {} { } {} {} {} {} {} {1.0} {}", room);
+
+	create_exit(ses, room, "{%d} {%s} {%s}", to_room, node->arg1, node->arg1);
+
+	create_exit(ses, room, "{%d} {%s} {%s}", in_room, node->arg2, node->arg2);
+
+	exit->vnum = room;
+
+	if ((exit = find_exit(ses, to_room, node->arg2)) != NULL)
+	{
+		exit->vnum = room;
+	}
+
+	if (*arg)
+	{
+		ses->map->in_room = room;
+		map_roomflag(ses, arg, arg1, arg2);
+		ses->map->in_room = in_room;
+	}
+	show_message(ses, LIST_COMMAND, "#MAP: Inserted room {%d}.", room);
+}
+
+DO_MAP(map_jump)
+{
+	int room;
+
+	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	room = find_location(ses, arg1);
+
+	if (room)
+	{
+		add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_MOVE);
+
+		goto_room(ses, room);
+
+		show_message(ses, LIST_COMMAND, "#MAP JUMP: JUMPED TO ROOM %d {%s}.", room, *ses->map->room_list[room]->name ? ses->map->room_list[room]->name : ses->map->room_list[room]->id);
+	}
+	else
+	{
+		show_message(ses, LIST_COMMAND, "#MAP JUMP: Couldn't find a room at {%s}.", arg1);
+	}
+}
+
+DO_MAP(map_landmark)
+{
+	struct listroot *root = ses->list[LIST_LANDMARK];
+	struct listnode *node;
+	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
+	int room, i, found;
+
+	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_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0 || *arg2 == 0)
+	{
+		i = bsearch_alpha_list(root, arg1, 0);
+
+		if (i > 0)
+		{
+			tintin_printf2(ses, "name: %-16s  vnum:%7d  size: %7s desc %s", root->list[i]->arg1, root->list[i]->val32[0], root->list[i]->arg4, root->list[i]->arg3);
+		}
+		else
+		{
+			for (found = i = 0 ; i < root->used ; i++)
+			{
+				if (*arg1 == 0 || match(ses, root->list[i]->arg1, arg1, SUB_NONE))
+				{
+					tintin_printf2(ses, "name: %-16s  vnum:%7d  size: %7s desc: %s", root->list[i]->arg1, root->list[i]->val32[0], root->list[i]->arg4, root->list[i]->arg3);
+
+					found = TRUE;
+				}
+			}
+
+			if (found == FALSE)
+			{
+				show_message(ses, LIST_COMMAND, "#MAP LANDMARK: NO MATCHES FOUND FOR {%s}.", arg1);
+			}
+		}
+	}
+	else
+	{
+		if (is_math(ses, arg2))
+		{
+			room = (int) get_number(ses, arg2);
+		}
+
+		if (room <= 0 || room >= ses->map->size)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP LANDMARK: INVALID VNUM {%s}.", arg2);
+		}
+		else
+		{
+			node = update_node_list(root, arg1, arg2, arg3, arg4);
+
+			node->val32[0] = room;
+
+			show_message(ses, LIST_COMMAND, "#OK. LANDMARK {%s} HAS VNUM {%d} AND IS DESCRIBED AS {%s} WITH SIZE {%s}.", arg1, room, arg3, arg4);
+		}
+	} 
+}
+
+DO_MAP(map_unlandmark)
+{
+	delete_node_with_wild(ses, LIST_LANDMARK, arg);
+}
+
+DO_MAP(map_leave)
+{
+	if (ses->map->in_room == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#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, LIST_COMMAND, "#MAP: Leaving the map. Use goto or return to return.");
+
+		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "MAP EXIT MAP", ntos(ses->map->in_room));
+	}
+}
+
+void map_legend_index(struct session *ses, char *arg, int head, int tail)
+{
+	char esc[BUFFER_SIZE], raw[BUFFER_SIZE];
+	int cnt;
+
+	for (cnt = head ; cnt < tail ; cnt++)
+	{
+		arg = sub_arg_in_braces(ses, arg, raw, GET_ONE, SUB_NONE);
+
+		substitute(ses, raw, esc, SUB_ESC);
+
+		if (is_number(esc))
+		{
+			numbertocharacter(ses, esc);
+		}
+		snprintf(ses->map->legend[cnt],     LEGEND_SIZE - 1, "%s", esc);
+		snprintf(ses->map->legend_raw[cnt], LEGEND_SIZE - 1, "%s", raw);
+
+		if (*arg == 0)
+		{
+			break;
+		}
+	}
+	return;
+}
+
+DO_MAP(map_legend)
+{
+	char buf[BUFFER_SIZE], arg3[BUFFER_SIZE];
+	int group, legend;
+
+	push_call("map_legend(%p,%p,%p,%p)",ses,arg,arg1,arg2);
+
+	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);
+
+	strcpy(buf, arg2);
+
+	if (*arg1 == 0)
+	{
+		for (group = 0 ; map_group_table[group].name ; group++)
+		{
+			tintin_printf2(ses, " [%-22s] [%-22s] [%3d] [%3d]",
+				map_group_table[group].group,
+				map_group_table[group].name,
+				map_group_table[group].start,
+				map_group_table[group].end);
+		}
+		pop_call();
+		return;
+	}
+
+	if (is_abbrev(arg1, "RESET"))
+	{
+		map_legend(ses, "{ASCII} {RESET}", arg1, arg2);
+		map_legend(ses, "{NESW} {RESET}", arg1, arg2);
+		map_legend(ses, "{MUDFONT BRAILLE TUBE} {RESET}", arg1, arg2);
+		map_legend(ses, "{UNICODE GRAPHICS} {RESET}", arg1, arg2);
+
+		pop_call();
+		return;
+	}
+
+	if (is_math(ses, arg1))
+	{
+		legend = (int) get_number(ses, arg1);
+
+		if (legend < map_group_table[0].start || legend >= map_group_table[0].end)
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP LEGEND {%d - %d} {[SYMBOL]}", map_group_table[0].start,  map_group_table[0].end);
+		}
+		else if (*arg2 == 0)
+		{
+			if (strip_vt102_strlen(ses, ses->map->legend[legend]) > 1)
+			{
+				tintin_printf2(ses, " [%-22s] [%-20s] [%3d] [ %12s ] [ %s]",
+					map_legend_table[legend].group,
+					map_legend_table[legend].name,
+					legend,
+					ses->map->legend_raw[legend],
+					ses->map->legend[legend]);
+			}
+			else
+			{
+				tintin_printf2(ses, " [%-22s] [%-20s] [%3d] [ %12s ] [ %s ]",
+					map_legend_table[legend].group,
+					map_legend_table[legend].name,
+					legend,
+					ses->map->legend_raw[legend],
+					ses->map->legend[legend]);
+			}
+		}
+		else
+		{
+			map_legend_index(ses, arg2, legend, legend + 1);
+		}
+		pop_call();
+		return;
+	}
+
+	for (group = 0 ; map_group_table[group].name ; group++)
+	{
+		if (is_abbrev(arg1, map_group_table[group].name))
+		{
+			break;
+		}
+	}
+
+
+	if (!map_group_table[group].name)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP LEGEND: UNKNOWN LEGEND {%s} TRY:", arg1);
+
+		map_legend(ses, "", arg1, arg2);
+
+		pop_call();
+		return;
+	}
+
+	if (*arg2 == 0)
+	{
+		for (legend = map_group_table[group].start ; legend < map_group_table[group].end ; legend++)
+		{
+			if (strip_vt102_strlen(ses, ses->map->legend[legend]) > 1)
+			{
+				tintin_printf2(ses, " [%-22s] [%-20s] [%3d] [ %12s ] [ %s]",
+					map_legend_table[legend].group,
+					map_legend_table[legend].name,
+					legend,
+					ses->map->legend_raw[legend],
+					ses->map->legend[legend]);
+			}
+			else
+			{
+				tintin_printf2(ses, " [%-22s] [%-20s] [%3d] [ %12s ] [ %s ]",
+					map_legend_table[legend].group,
+					map_legend_table[legend].name,
+					legend,
+					ses->map->legend_raw[legend],
+					ses->map->legend[legend]);
+			}
+		}
+		pop_call();
+		return;
+	}
+
+	if (is_abbrev(arg2, "RESET"))
+	{
+		map_legend_index(ses, map_group_table[group].reset, map_group_table[group].start, map_group_table[group].end);
+
+		pop_call();
+		return;
+	}
+
+	for (legend = map_group_table[group].start ; legend < map_group_table[group].end ; legend++)
+	{
+		if (!strcasecmp(space_out(arg2), space_out(map_legend_table[legend].name)))
+		{
+			if (*arg3 == 0)
+			{
+				tintin_printf2(ses, "  [%-22s]  [%-20s]  [%3d]  [ %8s ]  [ %s ]",
+					map_group_table[group].name,
+					map_legend_table[legend].name,
+					legend,
+					ses->map->legend_raw[legend],
+					ses->map->legend[legend]);
+			}
+			else
+			{
+				map_legend_index(ses, arg3, legend, legend + 1);
+			}
+			break;
+		}
+	}
+
+	if (legend == map_group_table[group].end)
+	{
+		for (legend = map_group_table[group].start ; legend < map_group_table[group].end ; legend++)
+		{
+			if (is_abbrev(space_out(arg2), space_out(map_legend_table[legend].name)))
+			{
+				if (*arg3 == 0)
+				{
+					tintin_printf2(ses, "  [%-22s]  [%-20s]  [%3d]  [ %8s ]  [ %s ]",
+						map_group_table[group].name,
+						map_legend_table[legend].name,
+						legend,
+						ses->map->legend_raw[legend],
+						ses->map->legend[legend]);
+				}
+				else
+				{
+					map_legend_index(ses, arg3, legend, legend + 1);
+				}
+				break;
+			}
+		}
+	}
+
+
+	if (legend == map_group_table[group].end)
+	{
+		if (strlen(arg2) > (map_group_table[group].end - map_group_table[group].start) * 2)
+		{
+			map_legend_index(ses, arg2, map_group_table[group].start, map_group_table[group].end);
+		}
+		else
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP LEGEND {%s} {{arg %d} {arg %d} ... {arg %d} {arg %d}",
+				map_group_table[group].group,
+				map_group_table[group].start,
+				map_group_table[group].start - 1,
+				map_group_table[group].end - 1,
+				map_group_table[group].end);
+		}
+	}
+
+	pop_call();
+	return;
+}
+
+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);
+	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);
+
+	if (*arg1 == 0 || *arg2 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP LINK {<DIRECTION>} {<LOCATION>} {BOTH}");
+		return;
+	}
+
+	room = find_room(ses, arg2);
+
+	if (room == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP: Couldn't find room {%s}.", arg1);
+		return;
+	}
+
+	exit = find_exit(ses, ses->map->in_room, arg1);
+
+	if (exit)
 	{
 	{
-		struct room_data *room_w;
-		long long exit_w;
+		delete_exit(ses, ses->map->in_room, exit);
+	}
 
 
-		room_w = ses->map->grid_rooms[x - 1 + map_grid_x * (y + 0)];
-		exit_w = 0;
+	create_exit(ses, ses->map->in_room, "{%d} {%s} {%s}", room, arg1, arg1);
 
 
-		if (room_w)
+	if (is_abbrev(arg3, "both"))
+	{
+		if ((node = search_node_list(ses->list[LIST_PATHDIR], arg1)) != NULL)
 		{
 		{
-			if (HAS_BIT(room_w->exit_dirs, MAP_DIR_E))
-			{
-				SET_BIT(exit_w, MAP_DIR_E);
-			}
-			if (HAS_BIT(room_w->exit_dirs, MAP_DIR_U))
+			if (find_exit(ses, room, node->arg2) == NULL)
 			{
 			{
-				SET_BIT(exit_w, MAP_DIR_U);
+				create_exit(ses, room, "{%d} {%s} {%s}", ses->map->in_room, node->arg2, node->arg2);
 			}
 			}
 		}
 		}
+	}
+	show_message(ses, LIST_COMMAND, "#MAP LINK: Connected room {%s} to {%s}.", ses->map->room_list[ses->map->in_room]->name, ses->map->room_list[room]->name);
+}
 
 
-		sprintf(buf, "%s", room_color);
-
-		switch (line)
-		{
-			case 1:
-				switch (exit_w)
-				{
-					case 0:
-						strcat(buf, " ");
-						break;
-					case MAP_DIR_E:
-						strcat(buf, "═");
-						break;
-					case MAP_DIR_E|MAP_DIR_U:
-						strcat(buf, "═̂");
-						break;
-					case MAP_DIR_U:
-						strcat(buf, " ̂");
-						break;
-					default:
-						strcat(buf, "?");
-						break;
-				}
-
-				if (room == NULL)
-				{
-					strcat(buf, "    ");
-				}
-				else
-				{
-					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_W) ? "═" : " ");
+DO_MAP(map_list)
+{
+	struct room_data *room;
+	char var[BUFFER_SIZE];
+	int vnum;
 
 
-					if (room->vnum == ses->map->in_room)
-					{
-						cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_USER]);
-					}
+	map_search_compile(ses, "0", var);
 
 
-					switch (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_W))
-					{
-						case MAP_DIR_N:
-							strcat(buf, "║");
-							break;
-						case MAP_DIR_W:
-							strcat(buf, "═");
-							break;
-						case MAP_DIR_N|MAP_DIR_W:
-							strcat(buf, "╝");
-							break;
-						default:
-							strcat(buf, "╔");
-							break;
-					}
+	searchgrid_find(ses, ses->map->in_room, ses->map->search);
 
 
+	map_search_compile(ses, arg, var);
 
 
-					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_N) ? " " : "═");
+	set_nest_node_ses(ses, var, "");
 
 
+	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
+	{
+		if (match_room(ses, vnum, ses->map->search))
+		{
+			room = ses->map->room_list[vnum];
 
 
-					switch (HAS_BIT(room->exit_dirs, MAP_DIR_N|MAP_DIR_E))
+			if (*var)
+			{
+				add_nest_node_ses(ses, var, "{%d} {{distance}{%.3f}{x}{%d}{y}{%d}{z}{%d}}", room->vnum, ses->map->search->stamp == room->search_stamp ? room->length  : -1, room->x, room->y, room->z);
+			}
+			else
+			{
+				if (ses->map->search->stamp == room->search_stamp)
+				{
+					if (room->w == 0)
 					{
 					{
-						case MAP_DIR_N:
-							strcat(buf, "║");
-							break;
-						case MAP_DIR_E:
-							strcat(buf, "═");
-							break;
-						case MAP_DIR_N|MAP_DIR_E:
-							strcat(buf, "╚");
-							break;
-						default:
-							strcat(buf, "╗");
-							break;
+						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4d  y: %4d  z: %4d  name: %s", room->vnum, room->length, room->x, room->y, room->z, room->name);
 					}
 					}
-				}
-				break;
-
-			case 2:
-				switch (exit_w)
-				{
-					case 0:
-						strcat(buf, " ");
-						break;
-					case MAP_DIR_E:
-						strcat(buf, "═");
-						break;
-					case MAP_DIR_E|MAP_DIR_U:
-						strcat(buf, "═");
-						break;
-					default:
-						strcat(buf, " ");
-						break;
-				}
-
-				if (room == NULL)
-				{
-					strcat(buf, " ");
-				}
-				else
-				{
-					switch (HAS_BIT(room->exit_dirs, MAP_DIR_W|MAP_DIR_D))
+					else
 					{
 					{
-						case MAP_DIR_W:
-							strcat(buf, "═");
-							break;
-						case MAP_DIR_W|MAP_DIR_D:
-							strcat(buf, "═̬");
-							break;
-						case MAP_DIR_D:
-							strcat(buf, " ̬");
-							break;
-						default:
-							strcat(buf, " ");
-							break;
+						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4s  y: %4s  z: %4s  name: %s", room->vnum, room->length, "?", "?", "?", room->name);
 					}
 					}
 				}
 				}
-
-				if (room == NULL)
-				{
-					strcat(buf, "   ");
-				}
 				else
 				else
 				{
 				{
-					if (room->vnum == ses->map->in_room)
-					{
-						cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_USER]);
-					}
-
-					switch (HAS_BIT(room->exit_dirs, MAP_DIR_S|MAP_DIR_W))
-					{
-						case MAP_DIR_S:
-							strcat(buf, "║");
-							break;
-						case MAP_DIR_W:
-							strcat(buf, "═");
-							break;
-						case MAP_DIR_S|MAP_DIR_W:
-							strcat(buf, "╗");
-								break;
-						default:
-							strcat(buf, "╚");
-							break;
-					}
-
-					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_S) ? " " : "═");
-
-					switch (HAS_BIT(room->exit_dirs, MAP_DIR_S|MAP_DIR_E))
-					{
-						case MAP_DIR_S:
-							strcat(buf, "║");
-							break;
-						case MAP_DIR_E:
-							strcat(buf, "═");
-							break;
-						case MAP_DIR_S|MAP_DIR_E:
-							strcat(buf, "╔");
-							break;
-						default:
-							strcat(buf, "╝");
-							break;
-					}
+						tintin_printf2(ses, "vnum: %5d  dist: %8.8s  x:    ?  y:    ?  z:    ?  name: %s", room->vnum, "-1", room->name);
 				}
 				}
-				break;
+			}
 		}
 		}
-		pop_call();
-		return buf;
 	}
 	}
+}
 
 
-	if (room == NULL)
+DO_MAP(map_map)
+{
+	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
+	FILE *logfile = NULL;
+	int x, y, line, row;
+
+	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);
+	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
+
+	push_call("map_map(%p,%p)",ses,arg);
+
+	if (is_math(ses, arg1))
 	{
 	{
-		if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
-		{
-			sprintf(buf, "      ");
-		}
-		else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
+		map_grid_y = get_number(ses, arg1);
+
+		if (map_grid_y <= 0)
 		{
 		{
-			sprintf(buf, "  ");
+			map_grid_y = UMAX(0, get_scroll_rows(ses) + map_grid_y);
 		}
 		}
-		else
+	}
+	else
+	{
+		map_grid_y = get_scroll_rows(ses);
+	}
+
+	if (is_math(ses, arg2))
+	{
+		map_grid_x = get_number(ses, arg2);
+
+		if (map_grid_x <= 0)
 		{
 		{
-			sprintf(buf, " ");
+			map_grid_x = UMAX(0, gtd->screen->cols + map_grid_x);
 		}
 		}
-		pop_call();
-		return buf;
+	}
+	else
+	{
+		map_grid_x = get_scroll_cols(ses);
 	}
 	}
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
+	if (*arg3)
 	{
 	{
-		sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
+		switch (*arg3)
+		{
+			case 'a':
+			case 'A':
+
+				strcpy(arg3, "APPEND");
+
+				logfile = fopen(arg4, "a");
 
 
-		switch (line)
-		{
-			case 1:
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_NW) ? "\\ " : "  ");
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_N)  ? "|"   : " ");
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_U)  ? "+"   : " ");
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_NE) ? "/ "  : "  ");
-				break;
+				loginit(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
 
 
-			case 2:
-				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
-				{
-					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_W) ? "-" : " ");
-				}
+				break;
 
 
-				if (room->vnum == ses->map->in_room)
-				{
-					if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
-					{
-						cat_sprintf(buf, "%s%s%s%s%s", room_left, ses->map->color[MAP_COLOR_USER], ses->map->legend[index], room_right, ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else
-					{
-						cat_sprintf(buf, "%s%05d%s", ses->map->color[MAP_COLOR_USER], room->vnum, ses->map->color[MAP_COLOR_EXIT]);
-					}
-				}
-				else
-				{
-					if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
-					{
-						cat_sprintf(buf, "%s%05d%s", room_color, room->vnum, ses->map->color[MAP_COLOR_EXIT]);
-					}
-					else if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
-					{
-						switch (room->exit_dirs)
-						{
-							case MAP_DIR_N|MAP_DIR_S:
-								cat_sprintf(buf, " | ");
-								break;
-							case MAP_DIR_E|MAP_DIR_W:
-								cat_sprintf(buf, "---");
-								break;
-							case MAP_DIR_NE|MAP_DIR_SW:
-								cat_sprintf(buf, " / ");
-								break;
-							case MAP_DIR_NW|MAP_DIR_SE:
-								cat_sprintf(buf, " \\ ");
-								break;
-							default:
-								cat_sprintf(buf, " * ");
-								break;
-						}
-					}
-					else
-					{
-						if (strip_color_strlen(ses, room->symbol) <= 1)
-						{
-							cat_sprintf(buf, "%s%s%-1s%s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, room_right, ses->map->color[MAP_COLOR_EXIT]);
-						}
-						else
-						{
-							cat_sprintf(buf, "%s%s%-3s%s", room_color, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, ses->map->color[MAP_COLOR_EXIT]);
-						}
-					}
-				}
+			case 'd':
+			case 'D':
+				strcpy(arg3, "DRAW");
 
 
-				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
-				{
-					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_E) ? "--" : "  ");
-				}
-				else
+				if (*arg4 == 0)
 				{
 				{
-					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_E) ? "-" : " ");
+					show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {square}", arg1, arg2, arg3);
+					pop_call();
+					return;
 				}
 				}
 				break;
 				break;
 
 
-			case 3:
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_SW) ? "/"   : " ");
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_D)  ? "-"   : " ");
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_S)  ? "| "  : "  ");
-				strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_SE) ? "\\ " : "  ");
-				break;
-		}
-		pop_call();
-		return buf;
-	}
+			case 'o':
+			case 'O':
+				strcpy(arg3, "OVERWRITE");
 
 
+				logfile = fopen(arg4, "w");
 
 
-	if (room->vnum == ses->map->in_room)
-	{
-		exits = ses->map->dir;
+				loginit(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
 
 
-		DEL_BIT(exits, MAP_EXIT_U|MAP_EXIT_D);
+				break;
 
 
-		if (HAS_BIT(ses->map->flags, MAP_FLAG_DIRECTION))
-		{
-			switch (exits)
-			{
-				case MAP_EXIT_N:
-					index = 24;
-					break;
-				case MAP_EXIT_N+MAP_EXIT_E:
-					index = 25;
-					break;
-				case MAP_EXIT_E:
-					index = 26;
-					break;
-				case MAP_EXIT_S+MAP_EXIT_E:
-					index = 27;
-					break;
-				case MAP_EXIT_S:
-					index = 28;
-					break;
-				case MAP_EXIT_S+MAP_EXIT_W:
-					index = 29;
-					break;
-				case MAP_EXIT_W:
-					index = 30;
-					break;
-				case MAP_EXIT_N+MAP_EXIT_W:
-					index = 31;
-					break;
+			case 'l':
+			case 'L':
+				strcpy(arg3, "LIST");
+				break;
 
 
-				default:
-					index = 17;
-					break;
-			}
-		}
-		else
-		{
-			index = 16;
-		}
+			case 'v':
+			case 'V':
+				strcpy(arg3, "VARIABLE");
+				break;
 
 
-		if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
-		{
-			sprintf(buf, "%s%s%s", ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index], ses->map->legend[offset + index]);
+			default:
+				show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {rows} {cols} {append|overwrite|list|variable} {name}");
+				pop_call();
+				return;
 		}
 		}
-		else
+
+		if (*arg4 == 0)
 		{
 		{
-			sprintf(buf, "%s%s", ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index]);
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {name}", arg1, arg2, arg3);
+			pop_call();
+			return;
 		}
 		}
-		pop_call();
-		return buf;
 	}
 	}
 
 
-	exit1 = 0;
-	exit2 = 0;
-	exits = 0;
-
-	if (HAS_BIT(room->exit_dirs, MAP_DIR_N))
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
 	{
-		SET_BIT(exit1, 1 << 0);
-		SET_BIT(exit2, 1 << 0);
-		SET_BIT(exits, MAP_EXIT_N);
+		map_grid_y = 2 + map_grid_y / 3;
+		map_grid_x = 2 + map_grid_x / 6;
 	}
 	}
-
-	if (HAS_BIT(room->exit_dirs, MAP_DIR_W))
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS))
 	{
 	{
-		SET_BIT(exit1, 1 << 2);
-		SET_BIT(exits, MAP_EXIT_W);
+		map_grid_y = 2 + (map_grid_y + 1) / 2;
+		map_grid_x = 2 + (map_grid_x + 3) / 5;
 	}
 	}
-
-	if (HAS_BIT(room->exit_dirs, MAP_DIR_E))
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
 	{
 	{
-		SET_BIT(exit2, 1 << 2);
-		SET_BIT(exits, MAP_EXIT_E);
+		map_grid_y = 2 + map_grid_y / 2;
+		map_grid_x = 2 + map_grid_x / 5;
 	}
 	}
-
-	if (HAS_BIT(room->exit_dirs, MAP_DIR_S))
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
 	{
 	{
-		SET_BIT(exit1, 1 << 4);
-		SET_BIT(exit2, 1 << 4);
-		SET_BIT(exits, MAP_EXIT_S);
+		map_grid_y = 2 + map_grid_y / 1;
+		map_grid_x = 2 + map_grid_x / 2;
+	}
+	else
+	{
+		map_grid_y = 2 + map_grid_y;
+		map_grid_x = 2 + map_grid_x;
 	}
 	}
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
+	if (map_grid_x > ses->map->max_grid_x || map_grid_y > ses->map->max_grid_y)
 	{
 	{
-		if (HAS_BIT(room->exit_dirs, MAP_DIR_NW))
-		{
-			SET_BIT(exit1, 1 << 1);
-		}
-		if (HAS_BIT(room->exit_dirs, MAP_DIR_NE))
-		{
-			SET_BIT(exit2, 1 << 1);
-		}
-		if (HAS_BIT(room->exit_dirs, MAP_DIR_SW))
+		if (map_grid_x > ses->map->max_grid_x)
 		{
 		{
-			SET_BIT(exit1, 1 << 3);
+			ses->map->max_grid_x = map_grid_x + 1;
 		}
 		}
-		if (HAS_BIT(room->exit_dirs, MAP_DIR_SE))
+		if (map_grid_y > ses->map->max_grid_y)
 		{
 		{
-			SET_BIT(exit2, 1 << 3);
+			ses->map->max_grid_y = map_grid_y + 1;
 		}
 		}
 
 
-		room1 = exit1 + LEGEND_MUDFONT_NWS;
-		room2 = exit2 + LEGEND_MUDFONT_NES;
+		ses->map->grid_rooms = (struct room_data **) realloc(ses->map->grid_rooms, ses->map->max_grid_x * ses->map->max_grid_y * sizeof(struct room_data *));
+	}
 
 
-		if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
+	displaygrid_build(ses, ses->map->in_room, map_grid_x, map_grid_y, 0);
+
+	*arg1 = row = 0;
+
+	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
+	{
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			room1 += 64;
-			room2 += 64;
-		}
+			for (line = 1 ; line <= 3 ; line++)
+			{
+				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
 
 
-		if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
+				for (x = 1 ; x < map_grid_x - 1 ; x++)
+				{
+					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+				}
+
+				str_clone(&gtd->out, gtd->buf);
+
+				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
+
+				if (logfile)
+				{
+					logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
+				}
+				else if (*arg3 == 'L')
+				{
+					cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
+				}
+				else if (*arg3 == 'V' || *arg3 == 'D')
+				{
+					cat_sprintf(arg1, "%s\n", gtd->out);
+				}
+				else
+				{
+					tintin_puts2(ses, gtd->out);
+				}
+			}
+		}
+	}
+	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) || HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
+	{
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			switch (room->exit_dirs)
+			for (line = 1 ; line <= 2 ; line++)
 			{
 			{
-				case MAP_DIR_N|MAP_DIR_E:
-				case MAP_DIR_N|MAP_DIR_SE:
-					room1 = LEGEND_MUDFONT_CURVED + 0;
-					break;
-				case MAP_DIR_S|MAP_DIR_E:
-				case MAP_DIR_S|MAP_DIR_NE:
-					room1 = LEGEND_MUDFONT_CURVED + 1;
-					break;
-				case MAP_DIR_S|MAP_DIR_W:
-				case MAP_DIR_S|MAP_DIR_NW:
-					room2 = LEGEND_MUDFONT_CURVED + 2;
-					break;
-				case MAP_DIR_N|MAP_DIR_W:
-				case MAP_DIR_N|MAP_DIR_SW:
-					room2 = LEGEND_MUDFONT_CURVED + 3;
-					break;
+				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+
+				for (x = 1 ; x < map_grid_x - 1 ; x++)
+				{
+					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+				}
+
+				str_clone(&gtd->out, gtd->buf);
+
+				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
+
+				if (logfile)
+				{
+					fprintf(logfile, "%s\n", gtd->out);
+				}
+				else if (*arg3 == 'L')
+				{
+					cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
+				}
+				else if (*arg3 == 'V' || *arg3 == 'D')
+				{
+					cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
+				}
+				else
+				{
+					tintin_puts2(ses, gtd->out);
+				}
 			}
 			}
 		}
 		}
-
-		sprintf(buf, "%s%s%s", room_color, ses->map->legend[room1], ses->map->legend[room2]);
 	}
 	}
 	else
 	else
 	{
 	{
-		if (HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS) && room->symbol[0] && room->symbol[0] != ' ')
-		{
-			sprintf(buf, "%s%-1s", room_color, room->symbol);
-		}
-		else
+		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
 		{
-			if (HAS_BIT(room->flags, ROOM_FLAG_VOID) && (exits == MAP_EXIT_N+MAP_EXIT_S || exits == MAP_EXIT_E+MAP_EXIT_W))
+			str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+
+			for (x = 1 ; x < map_grid_x - 1 ; x++)
 			{
 			{
-				sprintf(buf, "%s%s", room_color, exits == MAP_EXIT_N+MAP_EXIT_S ? ses->map->legend[offset+16+2] : ses->map->legend[offset+16+3]);
+				str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
+			}
+
+			substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
+
+			if (logfile)
+			{
+				fprintf(logfile, "%s\n", gtd->out);
+			}
+			else if (*arg3 == 'L')
+			{
+				cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
+			}
+			else if (*arg3 == 'V' || *arg3 == 'D')
+			{
+				cat_sprintf(arg1, "%s\n", gtd->out);
 			}
 			}
 			else
 			else
 			{
 			{
-				if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
-				{
-					switch (room->exit_dirs)
-					{
-						case MAP_DIR_N|MAP_DIR_E:
-							exits = 16 + 4;
-							break;
-						case MAP_DIR_S|MAP_DIR_E:
-							exits = 16 + 5;
-							break;
-						case MAP_DIR_S|MAP_DIR_W:
-							exits = 16 + 6;
-							break;
-						case MAP_DIR_N|MAP_DIR_W:
-							exits = 16 + 7;
-							break;
-					}
-				}
-				sprintf(buf, "%s%s", room_color, ses->map->legend[offset + exits]);
+				tintin_puts2(ses, gtd->out);
 			}
 			}
 		}
 		}
 	}
 	}
-	pop_call();
-	return buf;
-}
-
-void search_keywords(struct session *ses, char *arg, char *out, char *var)
-{
-	char buf[MAP_SEARCH_MAX][BUFFER_SIZE], tmp[BUFFER_SIZE];
-	int type, max;
-
-	push_call("search_keywords(%p,%p,%p,%p)",ses,arg,out,var);
 
 
-	for (type = 0 ; type < MAP_SEARCH_MAX ; type++)
+	if (logfile)
 	{
 	{
-		buf[type][0] = 0;
+		fclose(logfile);
 	}
 	}
-
-	var[0] = 0;
-
-	type = 0;
-
-	while (*arg && type < MAP_SEARCH_MAX)
+	else if (*arg3 == 'D')
 	{
 	{
-		arg = sub_arg_in_braces(ses, arg, tmp, GET_ALL, SUB_VAR|SUB_FUN);
-
-		if (!strcasecmp(tmp, "roomid"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_ID], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomname"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_NAME], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomexits"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_EXITS], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomdesc"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_DESC], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomarea"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_AREA], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomnote"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_NOTE], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomterrain"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_TERRAIN], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "roomflag"))
-		{
-			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_FLAG], GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else if (!strcasecmp(tmp, "variable"))
-		{
-			arg = sub_arg_in_braces(ses, arg, var, GET_ALL, SUB_VAR|SUB_FUN);
-		}
-		else
-		{
-			strcpy(buf[type++], tmp);
-		}
+		draw_map(ses, 1, 2, 3, 4, 5, 6, 7, "", arg4, arg2, arg1);
 	}
 	}
-
-	for (max = MAP_SEARCH_MAX - 1 ; max >= 0 ; max--)
+	else if (*arg3 == 'L')
 	{
 	{
-		if (*buf[max])
-		{
-			break;
-		}
+		set_nest_node_ses(ses, arg4, "%s", arg1);
 	}
 	}
-
-	out[0] = 0;
-
-	for (type = 0 ; type <= max ; type++)
+	else if (*arg3 == 'V')
 	{
 	{
-		cat_sprintf(out, "{%s}", buf[type]);
+		set_nest_node_ses(ses, arg4, "%s", arg1);
 	}
 	}
+
 	pop_call();
 	pop_call();
 	return;
 	return;
 }
 }
 
 
-void map_search_compile(struct session *ses, char *arg, char *var)
+DO_MAP(map_move)
 {
 {
-	char tmp[BUFFER_SIZE], buf[BUFFER_SIZE], *ptb;
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-	push_call("map_search_compile(%p,%p,%p)",ses,arg,var);
+//	tintin_printf2(ses, "debug: %s vs %s", arg, arg1);
 
 
-	search_keywords(ses, arg, tmp, var);
+	arg = substitute_speedwalk(ses, arg1, arg2);
 
 
-	arg = sub_arg_in_braces(ses, tmp, buf, GET_ALL, SUB_VAR|SUB_FUN); // name
+//	tintin_printf2(ses, "debug: %s vs %s", arg, arg2);
 
 
-	if (is_math(ses, buf))
-	{
-		ses->map->search->vnum = (int) get_number(ses, buf);
-	}
-	else
-	{
-		ses->map->search->vnum = 0;
-	}
+	ses->map->nofollow++;
 
 
-	if (ses->map->search->vnum)
+	while (*arg)
 	{
 	{
-		pop_call();
-		return;
-	}
+		arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 
-	if (ses->map->search->name)
-	{
-		free(ses->map->search->name);
+		follow_map(ses, arg1);
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
 	}
 	}
 
 
-	if (*buf)
-	{
-		strcat(buf, "$");
+	ses->map->nofollow--;
+}
 
 
-		ses->map->search->name = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
-	}
-	else
-	{
-		ses->map->search->name = NULL;
-	}
+DO_MAP(map_name)
+{
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // exits
+	RESTRING(ses->map->room_list[ses->map->in_room]->name, arg1);
+}
 
 
-	ses->map->search->exit_dirs = 0;
-	ses->map->search->exit_size = 0;
+DO_MAP(map_offset)
+{
+	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
 
 
-	if (ses->map->search->exit_list)
+	if (arg)
 	{
 	{
-		free(ses->map->search->exit_list);
+		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);
+		arg = sub_arg_in_braces(ses, arg, arg4, GET_ONE, SUB_VAR|SUB_FUN);
+
+		ses->map->sav_top_row = get_number(ses, arg1);
+		ses->map->sav_top_col = get_number(ses, arg2);
+		ses->map->sav_bot_row = get_number(ses, arg3);
+		ses->map->sav_bot_col = get_number(ses, arg4);
 	}
 	}
 
 
-	if (*buf)
+	if (ses->map->sav_top_row == 0)
 	{
 	{
-		struct listnode *node;
-		char exit[BUFFER_SIZE];
-		ptb = buf;
-
-		tmp[0] = 0;
-
-		if (is_math(ses, buf))
-		{
-			ses->map->search->exit_dirs = get_number(ses, buf);
-
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_N))  ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_E))  ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_S))  ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_W))  ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_U))  ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_D))  ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_NE)) ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_NW)) ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_SE)) ses->map->search->exit_size++;
-			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_SW)) ses->map->search->exit_size++;
-		}
-		else
-		{
-			while (*ptb)
-			{
-				ptb = get_arg_in_braces(ses, ptb, exit, GET_ONE);
-
-				node = search_node_list(ses->list[LIST_PATHDIR], exit);
-
-				ses->map->search->exit_size++;
-
-				if (node)
-				{
-					SET_BIT(ses->map->search->exit_dirs, 1LL << atoi(node->arg3));
-				}
-				else
-				{
-					SET_BIT(ses->map->search->exit_dirs, 1); // flag indicates no exits
-
-					cat_sprintf(tmp, "{%s}", exit);
-				}
-
-				if (*ptb == COMMAND_SEPARATOR)
-				{
-					ptb++;
-				}
-			}
-		}
-		ses->map->search->exit_list = strdup(tmp);
+		ses->map->top_row = 1;
+	}
+	else if (ses->map->sav_top_row < 0)
+	{
+		ses->map->top_row = 1 + gtd->screen->rows + ses->map->sav_top_row;
 	}
 	}
 	else
 	else
 	{
 	{
-		ses->map->search->exit_list = strdup("");
+		ses->map->top_row = ses->map->sav_top_row;
 	}
 	}
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // desc
-
-	if (ses->map->search->desc)
+	if (ses->map->sav_top_col == 0)
 	{
 	{
-		free(ses->map->search->desc);
+		ses->map->top_col = 1;
 	}
 	}
-
-	if (*buf)
+	else if (ses->map->sav_top_col < 0)
 	{
 	{
-		strcat(buf, "$");
-
-		ses->map->search->desc = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
+		ses->map->top_col = 1 + gtd->screen->cols + ses->map->sav_top_col;
 	}
 	}
 	else
 	else
 	{
 	{
-		ses->map->search->desc = NULL;
+		ses->map->top_col = ses->map->sav_top_col;
 	}
 	}
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // area
-
-	if (ses->map->search->area)
+	if (ses->map->sav_bot_row == 0)
 	{
 	{
-		free(ses->map->search->area);
+		ses->map->bot_row = ses->split->top_row - 1;
 	}
 	}
-
-	if (*buf)
+	else if (ses->map->sav_bot_row < 0)
 	{
 	{
-		strcat(buf, "$");
-
-		ses->map->search->area = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
+		ses->map->bot_row = 1 + gtd->screen->rows + ses->map->sav_bot_row;
 	}
 	}
 	else
 	else
 	{
 	{
-		ses->map->search->area = NULL;
+		ses->map->bot_row = ses->map->sav_bot_row;
 	}
 	}
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // note
-
-	if (ses->map->search->note)
+	if (ses->map->sav_bot_col == 0)
 	{
 	{
-		free(ses->map->search->note);
+		ses->map->bot_col = gtd->screen->cols;
 	}
 	}
-
-	if (*buf)
+	else if (ses->map->sav_bot_col < 0)
 	{
 	{
-		strcat(buf, "$");
-
-		ses->map->search->note = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
+		ses->map->bot_col = 1 + gtd->screen->cols + ses->map->sav_bot_col;
 	}
 	}
 	else
 	else
 	{
 	{
-		ses->map->search->note = NULL;
+		ses->map->bot_col = ses->map->sav_bot_col;
 	}
 	}
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // terrain
+	ses->map->rows = ses->map->bot_row - ses->map->top_row;
+	ses->map->cols = ses->map->bot_col - ses->map->top_col;
 
 
-	if (ses->map->search->terrain)
+	if (arg)
 	{
 	{
-		free(ses->map->search->terrain);
+		show_message(ses, LIST_COMMAND, "#MAP OFFSET: SQUARE {%d, %d, %d, %d} ROWS {%d} COLS {%d}", ses->map->top_row, ses->map->top_col, ses->map->bot_row, ses->map->bot_col, ses->map->rows, ses->map->cols);
 	}
 	}
+}
 
 
-	if (*buf)
-	{
-		strcat(buf, "$");
 
 
-		ses->map->search->terrain = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
-	}
-	else
+DO_MAP(map_read)
+{
+	FILE *myfile;
+	struct room_data *room;
+	struct exit_data *exit;
+	char buffer[BUFFER_SIZE], file[BUFFER_SIZE], *cptr;
+	int line = 1, vnum = 0;
+
+	arg = sub_arg_in_braces(ses, arg, file, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if ((myfile = fopen(file, "r")) == NULL)
 	{
 	{
-		ses->map->search->terrain = NULL;
+		show_error(ses, LIST_COMMAND, "#MAP: Map file {%s} not found.", file);
+
+		return;
 	}
 	}
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // flag
+	gtd->level->quiet++;
 
 
-	if (*buf)
+	if (fgets(buffer, BUFFER_SIZE - 1, myfile))
 	{
 	{
-		char flags[BUFFER_SIZE];
+		cptr = strchr(buffer, '\r'); /* For map files editor on Windows systems. */
 
 
-		ses->map->search->flag = get_number(ses, buf);
+		if (cptr)
+		{
+			*cptr = 0;
+		}
 
 
-		ptb = buf;
+		cptr = strchr(buffer, '\n');
 
 
-		while (*buf)
+		if (cptr)
 		{
 		{
-			ptb = sub_arg_in_braces(ses, ptb, flags, GET_ONE, SUB_NONE);
+			*cptr = 0;
+		}
 
 
-			if (is_abbrev(buf, "avoid"))
-			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_AVOID);
-			}
-			else if (is_abbrev(buf, "curved"))
-			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_CURVED);
-			}
-			else if (is_abbrev(buf, "hide"))
-			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_HIDE);
-			}
-			else if (is_abbrev(buf, "invis"))
-			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_INVIS);
-			}
-			else if (is_abbrev(buf, "leave"))
-			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_LEAVE);
-			}
-			else if (is_abbrev(buf, "void"))
-			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_VOID);
-			}
-			else if (is_abbrev(buf, "static"))
+		if (buffer[0] == 'C' && buffer[1] == ' ')
+		{
+			if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_SYNC))
 			{
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_STATIC);
+				create_map(ses, buffer + 2);
 			}
 			}
+		}
+		else
+		{
+			gtd->level->quiet--;
 
 
-			if (*ptb == COMMAND_SEPARATOR)
-			{
-				ptb++;
-			}
+			show_error(ses, LIST_COMMAND, "#MAP READ {%s}: INVALID START OF FILE. ABORTING READ..", file);
+
+			fclose(myfile);
+
+			return;
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		ses->map->search->flag = 0;
-	}
+		gtd->level->quiet--;
 
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // id
+		show_error(ses, LIST_COMMAND, "#MAP: INVALID READ ON LINE %d. ABORTING READ..", line);
 
 
-	if (ses->map->search->id)
-	{
-		free(ses->map->search->id);
+		fclose(myfile);
+		
+		return;
 	}
 	}
 
 
-	if (*buf)
-	{
-		ses->map->search->id = strdup(buf);
-	}
-	else
+	while (fgets(buffer, BUFFER_SIZE - 1, myfile))
 	{
 	{
-		ses->map->search->id = NULL;
-	}
+		line++;
 
 
-	pop_call();
-	return;
-}
+		cptr = strchr(buffer, '\r'); /* For map files editor on Windows systems. */
 
 
-int match_room(struct session *ses, int vnum, struct search_data *search)
-{
-	struct room_data *room = ses->map->room_list[vnum];
+		if (cptr)
+		{
+			*cptr = 0;
+		}
 
 
-	if (room == NULL)
-	{
-		return 0;
-	}
+		cptr = strchr(buffer, '\n');
+
+		if (cptr)
+		{
+			*cptr = 0;
+		}
+
+		switch (buffer[0])
+		{
+			case 'C':
+				switch (buffer[1])
+				{
+					case ' ':
+						gtd->level->quiet--;
+
+						show_error(ses, LIST_COMMAND, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
+
+						fclose(myfile);
+
+						delete_map(ses);
+
+						return;
+
+					case 'A':
+					case 'B':
+					case 'E':
+					case 'H':
+					case 'I':
+					case 'P':
+					case 'R':
+					case 'S':
+					case 'U':
+						if (!HAS_BIT(ses->map->flags, MAP_FLAG_SYNC))
+						{
+							map_color(ses, buffer + 1, arg1, arg2);
+						}
+						break;
+
+					default:
+						show_error(ses, LIST_COMMAND, "#MAP READ: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
+						break;
+				}
+				break;
+
+			case 'E':
+				create_exit(ses, vnum, "%s", buffer + 2);
+				break;
+
+			case 'F':
+				if (!HAS_BIT(ses->map->flags, MAP_FLAG_SYNC))
+				{
+					ses->map->flags = atoi(buffer + 2);
+				}
+				break;
+
+			case 'G':
+				if (ses->map->global_vnum == 0)
+				{
+					ses->map->global_vnum = ses->map->global_exit->vnum = atoi(buffer + 2);
+				}
+				break;
+
+			case 'I':
+				if (ses->map->last_room == 0)
+				{
+					ses->map->last_room = atoi(buffer + 2);
+				}
+				break;
+
+			case 'L':
+				switch (buffer[1])
+				{
+					case ' ':
+						if (!HAS_BIT(ses->map->flags, MAP_FLAG_SYNC))
+						{
+							map_legend(ses, buffer + 2, arg1, arg2);
+						}
+						break;
+
+					case 'M':
+						map_landmark(ses, buffer + 3, arg1, arg2);
+						break;
+				}
+				break;
+
+			case 'R':
+				room = create_room(ses, "%s", buffer + 2);
+				vnum = room->vnum;
+				break;
+
+			case 'T':
+				if (!HAS_BIT(ses->map->flags, MAP_FLAG_SYNC))
+				{
+					map_terrain(ses, buffer + 2, arg1, arg2);
+				}
+				break;
+
+			case 'V':
+				if (ses->map->version == 0)
+				{
+					ses->map->version = atoi(buffer + 2);
+				}
+				break;
+
+			case '#':
+				buffer[0] = gtd->tintin_char;
+				ses = script_driver(ses, LIST_COMMAND, buffer);
+				break;
 
 
-	if (search->vnum)
-	{
-		return room->vnum == search->vnum;
-	}
+			case  0:
+			case 13:
+				break;
 
 
-	if (search->id)
-	{
-		return !strcmp(room->id, search->id);
-	}
+			default:
+				gtd->level->quiet--;
 
 
-	if (search->name)
-	{
-		if (!regexp_compare(search->name, room->name, "", 0, 0))
-		{
-			return 0;
+				show_error(ses, LIST_COMMAND, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d.", buffer[0], buffer, line);
+
+				gtd->level->quiet++;
 		}
 		}
 	}
 	}
 
 
-	if (search->exit_dirs)
-	{
-		char *arg, exit[BUFFER_SIZE];
+	gtd->level->quiet--;
 
 
-		if (search->exit_dirs != room->exit_dirs)
-		{
-			return 0;
-		}
-		if (search->exit_size != room->exit_size)
+	fclose(myfile);
+
+	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
+	{
+		if (ses->map->room_list[vnum] == NULL)
 		{
 		{
-			return 0;
+			continue;
 		}
 		}
 
 
-		arg = search->exit_list;
-
-		while (*arg)
+		for (exit = ses->map->room_list[vnum]->f_exit ; exit ; exit = exit->next)
 		{
 		{
-			arg = get_arg_in_braces(ses, arg, exit, GET_ONE);
-
-			if (!find_exit(ses, vnum, exit))
+			if (exit->vnum < 0 || exit->vnum >= ses->map->size || ses->map->room_list[exit->vnum] == NULL)
 			{
 			{
-				return 0;
-			}
+				show_error(ses, LIST_COMMAND, "#MAP READ: Room %d - invalid exit '%s' to room %d.", vnum, exit->name, exit->vnum);
 
 
-			if (*arg == COMMAND_SEPARATOR)
-			{
-				arg++;
+				delete_exit(ses, vnum, exit);
+
+				if (ses->map->room_list[vnum]->f_exit)
+				{
+					exit = ses->map->room_list[vnum]->f_exit;
+				}
+				else
+				{
+					break;
+				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	if (search->desc)
-	{
-		if (!regexp_compare(search->desc, room->desc, "", 0, 0))
-		{
-			return 0;
-		}
-	}
+	show_message(ses, LIST_COMMAND, "#MAP READ: Map file {%s} loaded.", file);
 
 
-	if (search->area)
+
+}
+
+DO_MAP(map_resize)
+{
+	int size, vnum, room;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	size = atoi(arg1);
+
+	if (size <= ses->map->size)
 	{
 	{
-		if (!regexp_compare(search->area, room->area, "", 0, 0))
+		for (room = vnum = 1 ; vnum < ses->map->size ; vnum++)
 		{
 		{
-			return 0;
+			if (ses->map->room_list[vnum])
+			{
+				room = vnum;
+			}
 		}
 		}
-	}
 
 
-	if (search->note)
-	{
-		if (!regexp_compare(search->note, room->note, "", 0, 0))
+		if (room >= size)
 		{
 		{
-			return 0;
+			show_error(ses, LIST_COMMAND, "#MAP RESIZE: YOU MUST DELETE ALL ROOMS WITH VNUMS ABOVE (%d) FIRST.", size);
+			return;
 		}
 		}
 	}
 	}
 
 
-	if (search->terrain)
+	ses->map->room_list = (struct room_data **) realloc(ses->map->room_list, size * sizeof(struct room_data *));
+
+	if (ses->map->size < size)
 	{
 	{
-		if (!regexp_compare(search->terrain, room->terrain, "", 0, 0))
+		while (ses->map->size < size)
 		{
 		{
-			return 0;
+			ses->map->room_list[ses->map->size++] = NULL;
 		}
 		}
 	}
 	}
-
-	if (search->flag)
+	else
 	{
 	{
-		if ((room->flags & search->flag) != search->flag)
-		{
-			return 0;
-		}
+		ses->map->size = size;
 	}
 	}
-	return 1;
+
+	show_message(ses, LIST_COMMAND, "#MAP RESIZE: MAP RESIZED TO %d ROOMS.", ses->map->size);
 }
 }
 
 
-int find_room(struct session *ses, char *arg)
+DO_MAP(map_return)
 {
 {
-	char var[BUFFER_SIZE];
-	int room;
-
-	push_call("find_room(%p,%s)",ses,arg);
-
-	map_search_compile(ses, arg, var);
-
-	if (ses->map->search->vnum > 0 && ses->map->search->vnum < ses->map->size)
+	if (ses->map == NULL || ses->map->room_list[ses->map->last_room] == NULL)
 	{
 	{
-		if (ses->map->room_list[ses->map->search->vnum])
-		{
-			pop_call();
-			return ses->map->search->vnum;
-		}
-		pop_call();
-		return 0;
+		show_error(ses, LIST_COMMAND, "#MAP RETURN: NO KNOWN LAST ROOM.");
+
+		return;
 	}
 	}
 
 
 	if (ses->map->in_room)
 	if (ses->map->in_room)
 	{
 	{
-		room = searchgrid_find(ses, ses->map->in_room, ses->map->search);
-
-		if (room)
-		{
-			pop_call();
-			return room;
-		}
+		show_error(ses, LIST_COMMAND, "#MAP RETURN: ALREADY IN THE MAP.");
 	}
 	}
-
-	for (room = 0 ; room < ses->map->size ; room++)
+	else
 	{
 	{
-		if (ses->map->room_list[room] == NULL)
-		{
-			continue;
-		}
+		goto_room(ses, ses->map->last_room);
 
 
-		if (!match_room(ses, room, ses->map->search))
-		{
-			continue;
-		}
-		pop_call();
-		return room;
+		show_message(ses, LIST_COMMAND, "#MAP RETURN: RETURNED TO ROOM %d {%s}.", ses->map->in_room, ses->map->room_list[ses->map->in_room]->name);
 	}
 	}
-	pop_call();
-	return 0;
 }
 }
 
 
-void goto_room(struct session *ses, int room)
+DO_MAP(map_roomflag)
 {
 {
-	int last_room = ses->map->in_room;
+	char buf[BUFFER_SIZE], *str, arg3[BUFFER_SIZE];
+	int flag = 0;
 
 
-	push_call("goto_room(%p,%d)",ses,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_ALL, SUB_VAR|SUB_FUN);
 
 
-	if (ses->map->in_room)
+	if (*arg1 == 0)
 	{
 	{
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "MAP EXIT ROOM", ntos(last_room), ntos(room));
-		check_all_events(ses, SUB_ARG|SUB_SEC, 1, 2, "MAP EXIT ROOM %d", last_room, ntos(last_room), ntos(room));
+		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: Block flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_BLOCK) ? "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: Invis flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_INVIS) ? "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");
+		tintin_printf2(ses, "#MAP: Curved flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: NoGlobal flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_NOGLOBAL) ? "ON" : "OFF");
+		return;
 	}
 	}
 
 
-	ses->map->in_room = room;
-
-	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
+	str = arg1;
 
 
-	if (last_room == 0)
+	while (*str)
 	{
 	{
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "MAP ENTER MAP", ntos(room));
-	}
-
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "MAP ENTER ROOM", ntos(room), ntos(last_room));
-	check_all_events(ses, SUB_ARG|SUB_SEC, 1, 2, "MAP ENTER ROOM %d", room, ntos(room), ntos(last_room));
+		str = get_arg_in_braces(ses, str, buf, GET_ONE);
 
 
-	pop_call();
-	return;
-}
+		if (is_abbrev(buf, "avoid"))
+		{
+			SET_BIT(flag, ROOM_FLAG_AVOID);
+		}
+		else if (is_abbrev(buf, "block"))
+		{
+			SET_BIT(flag, ROOM_FLAG_BLOCK);
+		}
+		else if (is_abbrev(buf, "curved"))
+		{
+			SET_BIT(flag, ROOM_FLAG_CURVED);
+		}
+		else if (is_abbrev(buf, "hide"))
+		{
+			SET_BIT(flag, ROOM_FLAG_HIDE);
+		}
+		else if (is_abbrev(buf, "invisible"))
+		{
+			SET_BIT(flag, ROOM_FLAG_INVIS);
+		}
+		else if (is_abbrev(buf, "leave"))
+		{
+			SET_BIT(flag, ROOM_FLAG_LEAVE);
+		}
+		else if (is_abbrev(buf, "noglobal"))
+		{
+			SET_BIT(flag, ROOM_FLAG_NOGLOBAL);
+		}
+		else if (is_abbrev(buf, "static"))
+		{
+			SET_BIT(flag, ROOM_FLAG_STATIC);
+		}
+		else if (is_abbrev(buf, "void"))
+		{
+			SET_BIT(flag, ROOM_FLAG_VOID);
+		}
+		else
+		{
+			show_error(ses, LIST_COMMAND, "#MAP: Invalid room flag {%s}.", buf);
 
 
-int find_new_room(struct session *ses)
-{
-	int room;
+			return;
+		}
 
 
-	for (room = 1 ; room < ses->map->size ; room++)
-	{
-		if (ses->map->room_list[room] == NULL)
+		if (*str == COMMAND_SEPARATOR)
 		{
 		{
-			break;
+			str++;
 		}
 		}
 	}
 	}
 
 
-	if (room == ses->map->size)
+	if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP CREATE ROOM: Maximum amount of rooms of %d reached. Use #map resize.", ses->map->size);
-
-		return 0;
+		TOG_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);	
 	}
 	}
-	return room;
-}
-
-int dir_flags(struct session *ses, int room, int dir)
-{
-	struct exit_data *exit;
-
-	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
+	else if (is_abbrev(arg2, "ON"))
 	{
 	{
-		if (exit->dir == dir)
+		SET_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
+	}
+	else if (is_abbrev(arg2, "OFF"))
+	{
+		DEL_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
+	}
+	else if (is_abbrev(arg2, "GET"))
+	{
+		if (*arg3 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {GET} {<VARIABLE>}.", buf);
+		}
+		else
 		{
 		{
-			return exit->flags; /* | HAS_BIT(ses->map->room_list[exit->vnum]->flags, EXIT_FLAG_ALL);*/
+			set_nest_node_ses(ses, arg3, "%d", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, flag));
 		}
 		}
+		return;
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {[GET|ON|OFF]}.", buf);
 	}
 	}
-	return 0;
-}
 
 
-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 (HAS_BIT(flag, ROOM_FLAG_AVOID))
 	{
 	{
-//		if (!strcmp(exit->name, arg) || exit->vnum == atoi(arg))
-		if (!strcmp(exit->name, arg))
-		{
-			return exit;
-		}
+		show_message(ses, LIST_COMMAND, "#MAP: Avoid flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "ON" : "OFF");
 	}
 	}
-	return NULL;
-}
-
-int check_global(struct session *ses, int room)
-{
-	if (HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_NOGLOBAL))
+	if (HAS_BIT(flag, ROOM_FLAG_BLOCK))
 	{
 	{
-		return FALSE;
+		show_message(ses, LIST_COMMAND, "#MAP: Block flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "ON" : "OFF");
 	}
 	}
-	
-	if (ses->map->room_list[ses->map->global_vnum] == NULL)
+	if (HAS_BIT(flag, ROOM_FLAG_CURVED))
 	{
 	{
-		return FALSE;
+		show_message(ses, LIST_COMMAND, "#MAP: Curved flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "OFF");
 	}
 	}
-
-	if (room == ses->map->global_vnum)
+	if (HAS_BIT(flag, ROOM_FLAG_HIDE))
 	{
 	{
-		return FALSE;
+		show_message(ses, LIST_COMMAND, "#MAP: Hide flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "ON" : "OFF");
 	}
 	}
-	return TRUE;
-}
-
-int tunnel_void(struct session *ses, int from, int room, int dir)
-{
-	if (!HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_VOID))
+	if (HAS_BIT(flag, ROOM_FLAG_INVIS))
 	{
 	{
-		return room;
+		show_message(ses, LIST_COMMAND, "#MAP: Invis flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_INVIS) ? "ON" : "OFF");
 	}
 	}
-
-	if (get_room_exits(ses, room) != 2)
+	if (HAS_BIT(flag, ROOM_FLAG_LEAVE))
 	{
 	{
-		struct exit_data *exit;
-
-		for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
-		{
-			if (exit->dir == dir)
-			{
-				return tunnel_void(ses, room, exit->vnum, exit->dir);
-			}
-		}
-		return room;
+		show_message(ses, LIST_COMMAND, "#MAP: Leave flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE) ? "ON" : "OFF");
 	}
 	}
-
-	if (ses->map->room_list[room]->f_exit->vnum != from)
+	if (HAS_BIT(flag, ROOM_FLAG_NOGLOBAL))
 	{
 	{
-		return tunnel_void(ses, room, ses->map->room_list[room]->f_exit->vnum, ses->map->room_list[room]->f_exit->dir);
+		show_message(ses, LIST_COMMAND, "#MAP: NoGlobal flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_NOGLOBAL) ? "ON" : "OFF");
 	}
 	}
-	else
+	if (HAS_BIT(flag, ROOM_FLAG_VOID))
 	{
 	{
-		return tunnel_void(ses, room, ses->map->room_list[room]->l_exit->vnum, ses->map->room_list[room]->l_exit->dir);
+		show_message(ses, LIST_COMMAND, "#MAP: Void flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "ON" : "OFF");
+	}
+	if (HAS_BIT(flag, ROOM_FLAG_STATIC))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "ON" : "OFF");
 	}
 	}
-}
 
 
-// shortest_path() utilities
+}
 
 
-int searchgrid_find(struct session *ses, int from, struct search_data *search)
+DO_MAP(map_set)
 {
 {
-	int vnum, head, tail, index;
-	float length;
-	struct grid_node *node, *temp, list[MAP_BF_SIZE];
-	struct exit_data *exit;
-	struct room_data *room;
-
-	search->stamp++;
-
-	head = 0;
-	tail = 1;
-
-	node = &list[head];
-
-	node->vnum   = from;
-	node->length = ses->map->room_list[from]->weight;
-
-	// for map_list
+	struct room_data *room = ses->map->room_list[ses->map->in_room];
+	char arg3[BUFFER_SIZE];
 
 
-	node->w      = 0;
-	node->x      = 0;
-	node->y      = 0;
-	node->z      = 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);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-	while (head != tail)
+	if (*arg3)
 	{
 	{
-		node = &list[head];
-
-		room = ses->map->room_list[node->vnum];
-
-		length = node->length;
-
-		head = (head + 1) % MAP_BF_SIZE;
-
-		if (search->stamp != room->search_stamp)
-		{
-			room->search_stamp = search->stamp;
-
-			// first come first serve like with spatialgrid_find
-
-			room->w = node->w;
-			room->x = node->x;
-			room->y = node->y;
-			room->z = node->z;
-
-			DEL_BIT(room->flags, ROOM_FLAG_PATH);
-		}
-		else if (length >= room->length)
-		{
-			if (room->vnum != ses->map->global_vnum && room->w && node->w == 0)
-			{
-				room->w = node->w;
-				room->x = node->x;
-				room->y = node->y;
-				room->z = node->z;
-			}
-			continue;
-		}
-
-		room->length = length;
-
-		if (search->vnum)
-		{
-			if (room->vnum == search->vnum)
-			{
-				return room->vnum;
-			}
-		}
-		else
-		{
-			if (match_room(ses, room->vnum, search))
-			{
-				return room->vnum;
-			}
-		}
-
-		if (check_global(ses, room->vnum))
+		if (atoi(arg3) > 0 && atoi(arg3) < ses->map->size)
 		{
 		{
-			exit = ses->map->global_exit;
+			room = ses->map->room_list[atoi(arg3)];
 		}
 		}
 		else
 		else
 		{
 		{
-			exit = room->f_exit;
-		}
-
-		for ( ; exit ; exit = exit->next)
-		{
-			vnum = tunnel_void(ses, room->vnum, exit->vnum, exit->dir);
-
-			if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID) || HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_AVOID))
-			{
-				goto next_exit;
-			}
-
-			length = room->length + exit->weight + ses->map->room_list[vnum]->weight;
-
-			if (search->stamp == ses->map->room_list[vnum]->search_stamp)
-			{
-				if (length >= ses->map->room_list[vnum]->length)
-				{
-					goto next_exit;
-				}
-			}
-
-			temp = &list[tail];
-
-			temp->vnum   = vnum;
-			temp->length = length;
-			temp->w      = room->vnum == ses->map->global_vnum ? 1 : room->w;
-			temp->x      = room->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
-			temp->y      = room->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
-			temp->z      = room->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);
-
-			/*
-				list must remain ordered by length
-			*/
-
-			index = tail;
-
-			while (index != head)
-			{
-				temp = &list[index];
-
-				node = &list[index ? index - 1 : MAP_BF_SIZE - 1];
-
-				if (temp->length >= node->length)
-				{
-					break;
-				}
-
-				vnum         = temp->vnum;
-				length       = temp->length;
-
-				temp->vnum   = node->vnum;
-				temp->length = node->length;
-
-				node->vnum   = vnum;
-				node->length = length;
-
-				index = index ? index - 1 : MAP_BF_SIZE - 1;
-			}
-
-			tail = (tail + 1) % MAP_BF_SIZE;
-
-			if (tail == head)
-			{
-				show_error(ses, LIST_COMMAND, "#SHORTEST PATH: MAP TOO BIG FOR BF STACK OF %d", MAP_BF_SIZE);
-				break;
-			}
-
-			next_exit:
-
-			if (exit == ses->map->global_exit)
-			{
-				exit->next = room->f_exit;
-			}
+			room = NULL;
 		}
 		}
 	}
 	}
-	return 0;
-}
-
-int searchgrid_walk(struct session *ses, int offset, int from, int dest)
-{
-	int vnum, trim, head, tail, index;
-	float length;
-	struct grid_node *node, *temp, list[MAP_BF_SIZE];
-	struct exit_data *exit;
-	struct room_data *room;
-
-	head = 0;
-	tail = 1;
 
 
-	list[head].vnum   = from;
-	list[head].length = ses->map->room_list[from]->weight;
-
-	while (head != tail)
+	if (room == NULL)
+	{
+		show_message(ses, LIST_COMMAND, "#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, "   roomdata: %s", room->data);
+		tintin_printf2(ses, "   roomdesc: %s", room->desc);
+		tintin_printf2(ses, "  roomflags: %d", room->flags);
+		tintin_printf2(ses, "     roomid: %s", room->id);
+		tintin_printf2(ses, "   roomname: %s", room->name);
+		tintin_printf2(ses, "   roomnote: %s", room->note);
+		tintin_printf2(ses, " roomsymbol: %s", room->symbol);
+		tintin_printf2(ses, "roomterrain: %s", room->terrain);
+		tintin_printf2(ses, " roomweight: %.3f", room->weight);
+	}
+	else
 	{
 	{
-		node = &list[head];
-
-		room = ses->map->room_list[node->vnum];
-
-		length = node->length;
-
-		head = (head + 1) % MAP_BF_SIZE;
-
-
-		if (length >= room->length)
+		if (is_abbrev(arg1, "roomarea"))
 		{
 		{
-			continue;
+			RESTRING(room->area, arg2);
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomarea set to: %s", room->area);
 		}
 		}
-
-		room->length = length;
-
-		if (room->vnum == dest)
+		else if (is_abbrev(arg1, "roomcolor"))
 		{
 		{
-			return room->vnum;
+			RESTRING(room->color, arg2);
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomcolor set to: %s", arg2);
 		}
 		}
-
-		trim = 1;
-
-		if (check_global(ses, room->vnum))
+		else if (is_abbrev(arg1, "roomdata"))
 		{
 		{
-			exit = ses->map->global_exit;
+			RESTRING(room->data, arg2);
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomdata set to: %s", arg2);
 		}
 		}
-		else
+		else if (is_abbrev(arg1, "roomdesc"))
 		{
 		{
-			exit = room->f_exit;
+			RESTRING(room->desc, arg2);
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomdesc set to: %s", arg2);
 		}
 		}
-
-		for ( ; exit ; exit = exit->next)
+		else if (is_abbrev(arg1, "roomflags"))
 		{
 		{
-			vnum = tunnel_void(ses, room->vnum, exit->vnum, exit->dir);
-
-			if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID) || HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_AVOID))
-			{
-				goto next_exit;
-			}
-
-			length = room->length + exit->weight + ses->map->room_list[vnum]->weight;
-
-			if (ses->map->search->stamp != ses->map->room_list[vnum]->search_stamp)
-			{
-				goto next_exit;
-			}
-
-			if (length >= ses->map->room_list[vnum]->length || length >= ses->map->room_list[dest]->length)
-			{
-				goto next_exit;
-			}
-
-			temp = &list[tail];
+			room->flags = (int) get_number(ses, arg2);
 
 
-			temp->vnum   = vnum;
-			temp->length = length;
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomflags set to: %d", room->flags);
+		}
+		else if (is_abbrev(arg1, "roomid"))
+		{
+			RESTRING(room->id, arg2);
 
 
-			/*
-				list must remain ordered by length
-			*/
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomid set to: %s", room->id);
+		}
+		else if (is_abbrev(arg1, "roomname"))
+		{
+			RESTRING(room->name, arg2);
 
 
-			index = tail;
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomname set to: %s", room->name);
+		}
+		else if (is_abbrev(arg1, "roomnote"))
+		{
+			RESTRING(room->note, arg2);
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomnote set to: %s", arg2);
+		}
+		else if (is_abbrev(arg1, "roomsymbol"))
+		{
+			RESTRING(room->symbol, arg2);
 
 
-			while (index != head)
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomsymbol set to: %s", room->symbol);
+		}
+		else if (is_abbrev(arg1, "roomterrain"))
+		{
+			RESTRING(room->terrain, arg2);
+			room->terrain_index = bsearch_alpha_list(ses->list[LIST_TERRAIN], room->terrain, 0);
+			show_message(ses, LIST_COMMAND, "#MAP SET: roomterrain set to: %s (%d)", arg2, room->terrain_index);
+		}
+		else if (is_abbrev(arg1, "roomweight"))
+		{
+			if (get_number(ses, arg2) < 0.001)
 			{
 			{
-				temp = &list[index];
-
-				node = &list[index ? index - 1 : MAP_BF_SIZE - 1];
-
-				if (temp->length >= node->length)
-				{
-					break;
-				}
-
-				vnum = temp->vnum;
-				length = temp->length;
-
-				temp->vnum = node->vnum;
-				temp->length = node->length;
-
-				node->vnum = vnum;
-				node->length = length;
-
-				index = index ? index - 1 : MAP_BF_SIZE - 1;
+				show_message(ses, LIST_COMMAND, "#MAP SET: roomweight should be at least 0.001");
 			}
 			}
-
-			tail = (tail + 1) % MAP_BF_SIZE;
-
-			if (tail == head)
+			else
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#SHORTEST PATH: MAP TOO BIG FOR BF STACK OF %d", MAP_BF_SIZE);
-				break;
-			}
-			trim = 0;
-
-			next_exit:
+				room->weight = (float) get_number(ses, arg2);
 
 
-			if (exit == ses->map->global_exit)
-			{
-				exit->next = room->f_exit;
+				show_message(ses, LIST_COMMAND, "#MAP SET: roomweight set to: %.3f", room->weight);
 			}
 			}
 		}
 		}
-
-		if (trim)
+		else
 		{
 		{
-			room->length = 0;
+			show_message(ses, LIST_COMMAND, "#MAP SET: unknown option: %s", arg1);
 		}
 		}
 	}
 	}
-	return 0;
 }
 }
 
 
-void shortest_path(struct session *ses, int run, char *delay, char *arg)
+DO_MAP(map_sync)
 {
 {
-	char var[BUFFER_SIZE];
-	struct exit_data *exit;
-	struct room_data *room;
-	int vnum, dest;
-
-	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
+	if (ses->map)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SHORTEST PATH: You have to use #PATH END first.");
-
-		return;
+		SET_BIT(ses->map->flags, MAP_FLAG_SYNC);
 	}
 	}
 
 
-	kill_list(ses->list[LIST_PATH]);
-
-	ses->list[LIST_PATH]->update = 0;
-
-	map_search_compile(ses, arg, var);
-
-	dest = searchgrid_find(ses, ses->map->in_room, ses->map->search);
-
-	if (dest == 0 || dest == ses->map->global_vnum)
-	{
-		show_error(ses, LIST_COMMAND, "#SHORTEST PATH: NO PATH FOUND TO %s.", arg);
-		return;
-	}
+	map_read(ses, arg, arg1, arg2);
 
 
-	if (dest == ses->map->in_room)
+	if (ses->map)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SHORTEST PATH: Already there.");
-		return;
+		DEL_BIT(ses->map->flags, MAP_FLAG_SYNC);
 	}
 	}
+}
 
 
-	vnum = ses->map->in_room;
+DO_MAP(map_terrain)
+{
+	struct listroot *root = ses->list[LIST_TERRAIN];
+	struct listnode *node;
+	struct room_data *room;
+	char arg3[BUFFER_SIZE], buf1[BUFFER_SIZE];
+	int i, found, flags, density, spread;
 
 
-	// Slower than a backtrace, but works with mazes.
+	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_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, buf1, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-	while (TRUE)
+	if (*arg2 == 0 || (*arg1 == 0 && *arg2 == 0))
 	{
 	{
-		room = ses->map->room_list[vnum];
+		i = bsearch_alpha_list(root, arg1, 0);
 
 
-		if (check_global(ses, room->vnum))
+		if (i > 0)
 		{
 		{
-			exit = ses->map->global_exit;
+			tintin_printf2(ses, "name: %-16s  index %4d symbol: %-12s  flags: %s %s", root->list[i]->arg1, i, root->list[i]->arg2, root->list[i]->arg3, root->list[i]->arg4);
 		}
 		}
 		else
 		else
 		{
 		{
-			exit = room->f_exit;
-		}
+			for (found = i = 0 ; i < root->used ; i++)
+			{
+				if (*arg1 == 0 || match(ses, root->list[i]->arg1, arg1, SUB_NONE))
+				{
+					room = root->list[i]->room;
 
 
-		for ( ; exit ; exit = exit->next)
-		{
-			if (HAS_BIT(exit->flags, EXIT_FLAG_AVOID) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_AVOID))
+					if (!HAS_BIT(room->flags, ROOM_FLAG_TERRAIN))
+					{
+						tintin_printf2(ses, "error: no terrain flag set.");
+					}
+					tintin_printf2(ses, "name: %-16s  index %4d  symbol: %-16s  %s %s", room->name, room->terrain_index, room->symbol, root->list[i]->arg3, root->list[i]->arg4);
+
+					found = TRUE;
+				}
+			}
+
+			if (found == FALSE)
 			{
 			{
-				goto exit_next;
+				show_message(ses, LIST_COMMAND, "#MAP TERRAIN: NO MATCHES FOUND FOR {%s}.", arg1);
 			}
 			}
+		}
+	}
+	else
+	{
+		SET_BIT(ses->map->flags, MAP_FLAG_UPDATETERRAIN);
 
 
-			vnum = tunnel_void(ses, room->vnum, exit->vnum, exit->dir);
+		density = TERRAIN_FLAG_AMPLE;
+		spread = TERRAIN_FLAG_STANDARD;
+		flags = 0;
 
 
-			if (searchgrid_walk(ses, room->length, vnum, dest))
+		arg = arg3;
+
+		while (*arg)
+		{
+			arg = get_arg_in_braces(ses, arg, buf1, GET_ONE);
+
+			if (is_abbrev(buf1, "DENSE"))
 			{
 			{
-				break;
+				density = TERRAIN_FLAG_DENSE;
+			}
+			else if (is_abbrev(buf1, "AMPLE"))
+			{
+				density = TERRAIN_FLAG_AMPLE;
+			}
+			else if (is_abbrev(buf1, "SPARSE"))
+			{
+				density = TERRAIN_FLAG_SPARSE;
+			}
+			else if (is_abbrev(buf1, "SCANT"))
+			{
+				density = TERRAIN_FLAG_SCANT;
+			}
+			else if (is_abbrev(buf1, "NARROW"))
+			{
+				spread = TERRAIN_FLAG_NARROW;
+			}
+			else if (is_abbrev(buf1, "WIDE"))
+			{
+				spread = TERRAIN_FLAG_WIDE;
+			}
+			else if (is_abbrev(buf1, "VAST"))
+			{
+				spread = TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST;
+			}
+			else if (is_abbrev(buf1, "FADEIN"))
+			{
+				SET_BIT(flags, TERRAIN_FLAG_FADEIN);
+			}
+			else if (is_abbrev(buf1, "FADEOUT"))
+			{
+				SET_BIT(flags, TERRAIN_FLAG_FADEOUT);
+			}
+			else if (is_abbrev(buf1, "DOUBLE"))
+			{
+				SET_BIT(flags, TERRAIN_FLAG_DOUBLE);
+			}
+			else
+			{
+				show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP TERRAIN {%s} [DENSE|DOUBLE|SPARSE|SCANT|NARROW|WIDE|VAST|FADEIN|FADEOUT]", arg1);
 			}
 			}
 
 
-			exit_next:
-
-			if (exit == ses->map->global_exit)
+			if (*arg == COMMAND_SEPARATOR)
 			{
 			{
-				exit->next = room->f_exit;
+				arg++;
 			}
 			}
 		}
 		}
 
 
-		if (exit == NULL)
-		{
-			show_error(ses, LIST_COMMAND, "#SHORTEST PATH: UNKNOWN ERROR.");
-			return;
-		}
+		strcpy(buf1, "");
 
 
-		if (exit != ses->map->global_exit)
+		SET_BIT(flags, density);
+		SET_BIT(flags, spread);
+
+		if (flags)
 		{
 		{
-			if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
+			if (HAS_BIT(flags, TERRAIN_FLAG_DENSE))
 			{
 			{
-				check_append_path(ses, exit->cmd, "", 0);
+				strcat(buf1, "DENSE ");
+			}
+			else if (HAS_BIT(flags, TERRAIN_FLAG_SPARSE))
+			{
+				strcat(buf1, "SPARSE ");
+			}
+			else if (HAS_BIT(flags, TERRAIN_FLAG_SCANT))
+			{
+				strcat(buf1, "SCANT ");
+			}
+
+			if (HAS_BIT(flags, TERRAIN_FLAG_NARROW))
+			{
+				strcat(buf1, "NARROW ");
+			}
+			else if (HAS_BIT(flags, TERRAIN_FLAG_VAST))
+			{
+				strcat(buf1, "VAST ");
+			}
+			else if (HAS_BIT(flags, TERRAIN_FLAG_WIDE))
+			{
+				strcat(buf1, "WIDE ");
+			}
+
+			if (HAS_BIT(flags, TERRAIN_FLAG_FADEIN))
+			{
+				strcat(buf1, "FADEIN ");
+			}
+			else if (HAS_BIT(flags, TERRAIN_FLAG_FADEOUT))
+			{
+				strcat(buf1, "FADEOUT ");
 			}
 			}
-			else
+
+			if (HAS_BIT(flags, TERRAIN_FLAG_DOUBLE))
 			{
 			{
-				check_append_path(ses, exit->name, "", 0);
+				strcat(buf1, "DOUBLE ");
 			}
 			}
+
+			buf1[strlen(buf1) - 1] = 0;
 		}
 		}
 
 
-		SET_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
+		node = update_node_list(root, arg1, arg2, buf1, "");
 
 
-		if (ses->map->room_list[vnum]->search_stamp != ses->map->search->stamp)
+		if (node->room)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "%d bad search stamp %d vs %d", vnum, ses->map->room_list[vnum]->search_stamp, ses->map->search->stamp);
+			if (node->room->symbol)
+			{
+				RESTRING(node->room->terrain, arg1);
+				RESTRING(node->room->symbol, arg2);
+			}
+		}
+		else
+		{
+			node->room = create_room(ses, "{0} {%d} {} {%s} {%s} {} {} {} {} {} {1.0} {}", ROOM_FLAG_TERRAIN, node->arg1, node->arg2);
 		}
 		}
 
 
-		if (vnum == dest)
+		node->room->terrain_flags = flags;
+
+		for (i = 0 ; i < root->used ; i++)
 		{
 		{
-			break;
+			root->list[i]->room->terrain_index = i;
 		}
 		}
+
+		show_message(ses, LIST_COMMAND, "#OK. TERRAIN {%s} HAS BEEN SET TO {%s} {%s}.", arg1, arg2, buf1);
 	}
 	}
+}
 
 
-	if (run)
+DO_MAP(map_unterrain)
+{
+	if (delete_node_with_wild(ses, LIST_TERRAIN, arg))
 	{
 	{
-		path_run(ses, delay);
+		SET_BIT(ses->map->flags, MAP_FLAG_UPDATETERRAIN);
 	}
 	}
 }
 }
 
 
-/*
-	Virtual coordinate search for linkable rooms when creating a new room.
-*/
+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);
 
 
-int find_coord(struct session *ses, char *arg)
+	explore_path(ses, TRUE, arg1, arg2);
+}
+
+
+DO_MAP(map_uninsert)
 {
 {
-	int dir, x, y, z, room;
+	int room1, room2, room3;
+	struct exit_data *exit1, *exit2, *exit3;
+	struct listnode *node;
 
 
-	dir = get_exit_dir(ses, arg);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 
-	if (dir == 0)
+	room1 = ses->map->in_room;
+	exit1 = find_exit(ses, room1, arg1);
+
+	node = search_node_list(ses->list[LIST_PATHDIR], arg1);
+
+	if (exit1 == NULL)
 	{
 	{
-		return 0;
+		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: There is no room in that direction.");
+
+		return;
 	}
 	}
 
 
-	x = (HAS_BIT(dir, MAP_EXIT_E) ? 1 : HAS_BIT(dir, MAP_EXIT_W) ? -1 : 0);
-	y = (HAS_BIT(dir, MAP_EXIT_N) ? 1 : HAS_BIT(dir, MAP_EXIT_S) ? -1 : 0);
-	z = (HAS_BIT(dir, MAP_EXIT_U) ? 1 : HAS_BIT(dir, MAP_EXIT_D) ? -1 : 0);
+	if (node == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: Given direction must be a pathdir.");
+		return;
+	}
 
 
-	room = spatialgrid_find(ses, ses->map->in_room, x, y, z);
+	room2 = exit1->vnum;
+	exit2 = find_exit(ses, room2, node->arg1);
 
 
-	if (ses->map->room_list[room])
+	if (exit2 == NULL)
 	{
 	{
-		if (HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_STATIC))
-		{
-			show_message(ses, LIST_COMMAND, "#MAP: Linkable room is marked static. Creating overlapping room instead.");
+		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: Unable to find backlink room.");
+		return;
+	}
 
 
-			return 0;
-		}
+	room3 = exit2->vnum;
+	exit3 = find_exit(ses, room3, node->arg2);
+
+	if (exit3 == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP UNINSERT: Unable to find backlink exit.");
+
+		return;
 	}
 	}
-	return room;
+
+	exit1->vnum = room3;
+	exit3->vnum = room1;
+
+	delete_room(ses, room2, TRUE);
+
+	show_message(ses, LIST_COMMAND, "#MAP UNINSERT: Uninserted room {%d}.", room2);
 }
 }
 
 
-// Used by #map jump and the auto linker
+// 1) timestamp 2) type 3) data
 
 
-int spatialgrid_find(struct session *ses, int from, int x, int y, int z)
+DO_MAP(map_undo)
 {
 {
-	int head, tail;
-	struct grid_node *node, *temp, list[MAP_BF_SIZE];
-	struct exit_data *exit;
+	struct link_data *link;
 	struct room_data *room;
 	struct room_data *room;
+	int undo_flag;
+	struct exit_data *exit1, *exit2, *exit3;
 
 
-	push_call("spatialgrid_find(%s,%d,%d,%d,%d)",ses->name,from,x,y,z);
+	link = ses->map->undo_tail;
 
 
-	head = 0;
-	tail = 1;
+	if (link == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP UNDO: No known last move.");
 
 
-	node = &list[head];
+		return;
+	}
 
 
-	node->vnum   = from;
-	node->x      = 0;
-	node->y      = 0;
-	node->z      = 0;
-	node->length = 0;
-	node->flags  = 0;
+	room = ses->map->room_list[atoi(link->str1)];
 
 
-	ses->map->display_stamp++;
+	if (room == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP UNDO: Room %s does not exist.", link->str2);
+		return;
+	}
 
 
-	while (head != tail)
+	if (ses->map->room_list[atoi(link->str2)] == NULL)
 	{
 	{
-		node = &list[head];
+		show_error(ses, LIST_COMMAND, "#MAP UNDO: Invalid last move.");
+		return;
+	}
 
 
-		head = (head + 1) % MAP_BF_SIZE;
+	undo_flag = atoi(link->str3);
 
 
-		room = ses->map->room_list[node->vnum];
+	if (HAS_BIT(undo_flag, MAP_UNDO_MOVE))
+	{
+ 		if (ses->map->in_room != room->vnum)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP UNDO: Invalid last move.");
+			return;
+		}
+		show_message(ses, LIST_COMMAND, "#MAP UNDO: Moving to room %s.", link->str2);
 
 
-		if (ses->map->display_stamp != room->display_stamp)
+		goto_room(ses, atoi(link->str2));
+	}
+
+	if (HAS_BIT(undo_flag, MAP_UNDO_CREATE))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting room %d.", room->vnum);
+		delete_room(ses, room->vnum, TRUE);
+	}
+	else if (HAS_BIT(undo_flag, MAP_UNDO_LINK))
+	{
+		exit1 = find_exit(ses, room->vnum, link->str2);
+
+		if (exit1)
 		{
 		{
-			room->display_stamp = ses->map->display_stamp;
+			show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting exit leading %s.", exit1->name);
+			delete_exit(ses, room->vnum, exit1);
 		}
 		}
-		else if (room->length <= node->length)
+
+		exit2 = find_exit(ses, atoi(link->str2), link->str1);
+
+		if (exit2)
 		{
 		{
-			continue;
+			show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting exit leading %s.", exit2->name);
+			delete_exit(ses, atoi(link->str2), exit2);
 		}
 		}
+	}
+	else if (HAS_BIT(undo_flag, MAP_UNDO_INSERT))
+	{
+		exit1 = find_exit(ses, atoi(link->str2), link->str1);
 
 
-		room->length = node->length;
-/*
-		if (HAS_BIT(node->flags, GRID_FLAG_HIDE))
+		if (exit1 == NULL)
 		{
 		{
-			continue;
+			show_error(ses, LIST_COMMAND, "#MAP UNDO: Can't find exit between %s and %s.", link->str2, link->str1);
+			return;
 		}
 		}
-*/
-		if (node->x == x && node->y == y && node->z == z)
+
+		exit2 = find_exit(ses, room->vnum, exit1->name);
+
+		if (exit2 == NULL)
 		{
 		{
-			pop_call();
-			return node->vnum;
+			show_error(ses, LIST_COMMAND, "#MAP UNDO: No valid exit found in room %d.", room->vnum);
+			return;
 		}
 		}
 
 
-		for (exit = room->f_exit ; exit ; exit = exit->next)
+		exit3 = find_exit(ses, exit2->vnum, ntos(room->vnum));
+
+		if (exit3 == NULL)
 		{
 		{
-			if (ses->map->display_stamp == ses->map->room_list[exit->vnum]->display_stamp)
-			{
-				if (room->length >= ses->map->room_list[exit->vnum]->length)
-				{
-					continue;
-				}
-			}
+			show_error(ses, LIST_COMMAND, "#MAP UNDO: Can't find exit between %d and %d.", room->vnum, exit2->vnum);
+			return;
+		}
 
 
-			if (exit->dir == 0)
-			{
-				continue;
-			}
+		exit1->vnum = exit2->vnum;
+		exit3->vnum = atoi(link->str2);
 
 
-			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
-			{
-				continue;
-			}
+		delete_room(ses, room->vnum, TRUE);
 
 
-			if (head == (tail + 1) % MAP_BF_SIZE)
-			{
-				break;
-			}
+		show_message(ses, LIST_COMMAND, "#MAP UNDO: Uninserting room %s.", link->str1);
+	}
+	del_undo(ses, link);
+}
 
 
-			temp = &list[tail];
+DO_MAP(map_unlink)
+{
+	struct exit_data *exit1;
+	struct exit_data *exit2;
+	struct listnode *node;
 
 
-			temp->vnum   = exit->vnum;
-			temp->w      = node->w;
-			temp->x      = node->x + (HAS_BIT(exit->dir, MAP_EXIT_E) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_W) ? -1 : 0);
-			temp->y      = node->y + (HAS_BIT(exit->dir, MAP_EXIT_N) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_S) ? -1 : 0);
-			temp->z      = node->z + (HAS_BIT(exit->dir, MAP_EXIT_U) ?  1 : HAS_BIT(exit->dir, MAP_EXIT_D) ? -1 : 0);
-			temp->length = node->length + 1;
-			temp->flags  = 0;
-/*
-			if (HAS_BIT(exit->flags, EXIT_FLAG_HIDE) || HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_HIDE))
-			{
-				SET_BIT(temp->flags, GRID_FLAG_HIDE);
+	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);
 
 
-				temp->length += 1000;
+	node = search_node_list(ses->list[LIST_PATHDIR], arg1);
+
+	exit1 = find_exit(ses, ses->map->in_room, arg1);
+
+	if (exit1 == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP UNLINK: No exit with that name found");
+
+		return;
+	}
+
+	if (*arg2 == 'b' || *arg == 'B')
+	{
+		if (node)
+		{
+			exit2 = find_exit(ses, exit1->vnum, node->arg2);
+
+			if (exit2)
+			{
+				delete_exit(ses, exit1->vnum, exit2);
 			}
 			}
-*/
-			tail = (tail + 1) % MAP_BF_SIZE;
 		}
 		}
 	}
 	}
-	pop_call();
-	return 0;
+
+	delete_exit(ses, ses->map->in_room, exit1);
+
+	show_message(ses, LIST_COMMAND, "#MAP UNLINK: Exit deleted.");
 }
 }
 
 
-void explore_path(struct session *ses, int run, char *arg1, char *arg2)
+DO_MAP(map_update)
 {
 {
-	struct exit_data *exit;
-	int room, vnum;
-
-	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
+	if (ses->map == NULL)
 	{
 	{
-		if (ses->map->room_list[vnum])
-		{
-			DEL_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
-		}
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NO MAP DATA.");
 	}
 	}
-
-	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
+	else if (ses->map->room_list[ses->map->in_room] == NULL)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP EXPLORE: You have to use #PATH END first.");
-
-		return;
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NOT INSIDE MAP.");
+	}
+	else if (!HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: VTMAP FLAG NOT SET.");
+	}
+	else if (ses != gtd->ses)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NOT THE ACTIVE SESSION.");
+	}
+	else
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: OK.");
+		
+		SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 	}
 	}
+}
 
 
-	kill_list(ses->list[LIST_PATH]);
+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);
 
 
-	ses->list[LIST_PATH]->update = 0;
+	shortest_path(ses, TRUE, arg2, arg1);
+}
 
 
-	room = ses->map->in_room;
+DO_MAP(map_vnum)
+{
+	int vnum, vnum1, vnum2, old_room, new_room;
+	struct exit_data *exit;
 
 
-	exit = find_exit(ses, room, arg1);
+	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);
 
 
-	if (exit == NULL)
+	vnum1 = atoi(arg1);
+
+	if (*arg2)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#MAP: There's no exit named '%s'.", arg1);
+		vnum2 = atoi(arg2);
+	}
+	else
+	{
+		vnum2 = vnum1;
+	}
+	
+	if (vnum1 <= 0 || vnum1 >= ses->map->size || vnum2 <= 0 || vnum2 >= ses->map->size)
+	{
+		show_error(ses, LIST_COMMAND, "#MAP VNUM {%s} {%s} - VNUMS MUST BE BETWEEN {1} and {%d}", arg1, arg2, ses->map->size - 1);
 		return;
 		return;
 	}
 	}
 
 
-	vnum = exit->vnum;
-
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
+	for (vnum = vnum1 ; vnum <= vnum2 ; vnum++)
 	{
 	{
-		check_append_path(ses, exit->cmd, "", 0);
+		if (ses->map->room_list[vnum] == NULL)
+		{
+			break;
+		}
 	}
 	}
-	else
+
+	if (vnum > vnum2)
 	{
 	{
-		check_append_path(ses, exit->name, "", 0);
+		show_error(ses, LIST_COMMAND, "#MAP VNUM {%s} {%s} - NO FREE VNUM FOUND.", arg1, arg2);
+		return;
 	}
 	}
 
 
-	SET_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
-	SET_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
+	old_room = ses->map->in_room;
+	new_room = vnum;
 
 
-	while (get_room_exits(ses, vnum) == 2)
+	ses->map->room_list[new_room] = ses->map->room_list[old_room];
+	ses->map->room_list[new_room]->vnum = new_room;
+	ses->map->room_list[old_room] = NULL;
+	ses->map->in_room = new_room;
+
+	if (ses->map->at_room == old_room)
 	{
 	{
-		exit = ses->map->room_list[vnum]->f_exit;
+		ses->map->at_room = new_room;
+	}
 
 
-		if (HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_PATH))
+	for (vnum = 1 ; vnum < ses->map->size ; vnum++)
+	{
+		if (ses->map->room_list[vnum] == NULL)
 		{
 		{
-			exit = ses->map->room_list[vnum]->l_exit;
-
-			if (HAS_BIT(ses->map->room_list[exit->vnum]->flags, ROOM_FLAG_PATH))
-			{
-				break;
-			}
+			continue;
 		}
 		}
 
 
-		if (!HAS_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_VOID))
+		for (exit = ses->map->room_list[vnum]->f_exit ; exit ; exit = exit->next)
 		{
 		{
-			if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
-			{
-				check_append_path(ses, exit->cmd, "", 0);
-			}
-			else
+			if (exit->vnum == old_room)
 			{
 			{
-				check_append_path(ses, exit->name, "", 0);
+				exit->vnum = new_room;
 			}
 			}
 		}
 		}
-
-		vnum = exit->vnum;
-
-		SET_BIT(ses->map->room_list[vnum]->flags, ROOM_FLAG_PATH);
 	}
 	}
 
 
-	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
-
-	if (run)
-	{
-		path_run(ses, arg2);
-	}
+	tintin_printf(ses, "#MAP VNUM: MOVED ROOM %d TO %d.", old_room, new_room);
 }
 }
 
 
-void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int x, int y)
+DO_MAP(map_write)
 {
 {
-	int max_x, max_y;
-	int top_row, top_col, bot_row, bot_col, rows, cols;
+	struct listroot *root;
+	FILE *file;
+	struct exit_data *exit;
+	int index;
 
 
-	push_call("map_mouse_handler(%p,%p,%p,%d,%d)",ses,arg1,arg2,x,y);
+	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);
 
 
-	if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) || ses->map->room_list[ses->map->in_room] == NULL)
+	if (*arg1 == 0)
 	{
 	{
-		pop_call();
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP WRITE {<filename>} {FORCE}");
+
 		return;
 		return;
 	}
 	}
 
 
-	if (ses->map->rows > 1 && ses->map->cols > 1)
-	{
-		top_row = ses->map->top_row;
-		top_col = ses->map->top_col;
-		bot_row = ses->map->bot_row;
-		bot_col = ses->map->bot_col;
-		rows    = ses->map->rows;
-		cols    = ses->map->cols;
-	}
-	else
+	if (!str_suffix(arg1, ".tin") && !is_abbrev(arg2, "FORCE"))
 	{
 	{
-		top_row = 1;
-		top_col = 1;
-		bot_row = ses->split->top_row - 2;
-		bot_col = gtd->screen->cols;
-		rows    = ses->split->top_row - 2;
-		cols    = gtd->screen->cols;
-	}
-
-	y = y - 1;
-	x = x - 1;
+		show_error(ses, LIST_COMMAND, "#MAP WRITE {%s}: USE {FORCE} TO OVERWRITE .tin FILES.");
 
 
-	if (y > bot_row || y < top_row)
-	{
-		pop_call();
 		return;
 		return;
 	}
 	}
 
 
-	if (x > bot_col || x < top_col)
+	if ((file = fopen(arg1, "w")) == NULL)
 	{
 	{
-		pop_call();
+		show_error(ses, LIST_COMMAND, "#MAP WRITE {%s} - COULDN'T OPEN FILE TO WRITE.", arg1);
+
 		return;
 		return;
 	}
 	}
 
 
-	y = y + 1 - top_row;
-	x = x + 1 - top_col;
+	fprintf(file, "C %d\n\n", ses->map->size);
 
 
-	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
-	{
-		y /= 3;
-		x /= 6;
+	fprintf(file, "V 2020\n\n");
 
 
-		max_y = 2 + rows / 3;
-		max_x = 2 + cols / 6;
-	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_UNICODEGRAPHICS) || HAS_BIT(ses->map->flags, MAP_FLAG_BLOCKGRAPHICS))
+	for (index = 0 ; map_color_table[index].name ; index++)
 	{
 	{
-		y /= 2;
-		x /= 5;
-
-		max_y = 2 + rows / 2;
-		max_x = 2 + cols / 5;
+		fprintf(file, "C%s %s\n", map_color_table[index].name, ses->map->color[index]);
 	}
 	}
-	else if (HAS_BIT(ses->map->flags, MAP_FLAG_MUDFONT))
-	{
-		x /= 2;
+	fprintf(file, "\n");
 
 
-		max_y = 2 + rows;
-		max_x = 2 + cols / 2;
-	}
-	else
+	fprintf(file, "F %d\n\n", ses->map->flags);
+
+	fprintf(file, "G %d\n\n", ses->map->global_vnum);
+
+	fprintf(file, "I %d\n\n", ses->map->in_room ? ses->map->in_room : ses->map->last_room);
+
+	for (index = 0 ; map_legend_table[index].name ; index++)
 	{
 	{
-		max_y = 2 + rows;
-		max_x = 2 + cols;
+		fprintf(file, "L {%s} {%s} {%s}\n", map_legend_table[index].group, map_legend_table[index].name, ses->map->legend_raw[index]);
 	}
 	}
+	fprintf(file, "\n\n");
 
 
-	y = max_y - 1 - y;
+	root = ses->list[LIST_LANDMARK];
 
 
-	if (x < 0 || y < 0)
+	for (index = 0 ; index < root->used ; index++)
 	{
 	{
-		pop_call();
-		return;
+		fprintf(file, "LM {%s} {%d} {%s} {%s}\n", root->list[index]->arg1, root->list[index]->val32[0], root->list[index]->arg3, root->list[index]->arg4);
 	}
 	}
+	fprintf(file, "\n\n");	
 
 
-	if (max_x != map_grid_x || max_y != map_grid_y)
+	root = ses->list[LIST_TERRAIN];
+
+	for (index = 0 ; index < root->used ; index++)
 	{
 	{
-		pop_call();
-		return;
+		fprintf(file, "T {%s} {%s} {%s}\n", root->list[index]->arg1, root->list[index]->arg2, root->list[index]->arg3);
 	}
 	}
+	fprintf(file, "\n\n");	
 
 
-	if (ses->map->grid_rooms[x + 1 + max_x * (y - 1)])
+	for (index = 0 ; index < ses->map->size ; index++)
 	{
 	{
-		check_all_events(ses, SUB_ARG, 2, 1, "MAP %s %s", arg1, arg2, ntos(ses->map->grid_rooms[x + 1 + max_x * (y - 1)]->vnum));
+		if (ses->map->room_list[index])
+		{
+			DEL_BIT(ses->map->room_list[index]->flags, ROOM_FLAG_PATH);
+
+			fprintf(file, "\nR {%5d} {%d} {%s} {%s} {%s} {%s} {%s} {%s} {%s} {%s} {%.3f} {%s}\n",
+				ses->map->room_list[index]->vnum,
+				ses->map->room_list[index]->flags,
+				ses->map->room_list[index]->color,
+				ses->map->room_list[index]->name,
+				ses->map->room_list[index]->symbol,
+				ses->map->room_list[index]->desc,
+				ses->map->room_list[index]->area,
+				ses->map->room_list[index]->note,
+				ses->map->room_list[index]->terrain,
+				ses->map->room_list[index]->data,
+				ses->map->room_list[index]->weight,
+				ses->map->room_list[index]->id);
+
+			for (exit = ses->map->room_list[index]->f_exit ; exit ; exit = exit->next)
+			{
+				fprintf(file, "E {%5d} {%s} {%s} {%d} {%d} {%s} {%.3f} {%s}\n",
+					exit->vnum,
+					exit->name,
+					exit->cmd,
+					exit->dir,
+					exit->flags,
+					exit->data,
+					exit->weight,
+					exit->color);
+			}
+		}
 	}
 	}
+
+	fclose(file);
+
+	show_message(ses, LIST_COMMAND, "#MAP: Map file written to {%s}.", arg1);
 }
 }

+ 118 - 6
src/math.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -71,7 +70,7 @@ DO_COMMAND(do_math)
 	{
 	{
 		result = get_number(ses, arg2);
 		result = get_number(ses, arg2);
 
 
-		node = set_nest_node(ses->list[LIST_VARIABLE], arg1, "%.*Lf", precision, result);
+		node = set_nest_node_ses(ses, arg1, "%.*Lf", precision, result);
 
 
 		show_message(ses, LIST_VARIABLE, "#MATH: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, node->arg2);
 		show_message(ses, LIST_VARIABLE, "#MATH: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, node->arg2);
 	}
 	}
@@ -201,6 +200,7 @@ void mathexp(struct session *ses, char *str, char *result, int seed)
 	if (badnumber && debug)                                 \
 	if (badnumber && debug)                                 \
 	{                                                       \
 	{                                                       \
 		badnumber = 0;                                  \
 		badnumber = 0;                                  \
+		precision = 0;                                  \
 		show_debug(ses, LIST_VARIABLE, "#MATH EXP: INVALID NUMBER %s.", buf3); \
 		show_debug(ses, LIST_VARIABLE, "#MATH EXP: INVALID NUMBER %s.", buf3); \
 	}                                                       \
 	}                                                       \
 	*pta = 0;                                               \
 	*pta = 0;                                               \
@@ -210,6 +210,7 @@ void mathexp(struct session *ses, char *str, char *result, int seed)
 	status = newstatus;                                     \
 	status = newstatus;                                     \
 	pta = buf3;                                             \
 	pta = buf3;                                             \
 	point = -1;                                             \
 	point = -1;                                             \
+	metric = 0;                                             \
 }
 }
 
 
 void add_math_node(char *arg1, char *arg2, char *arg3)
 void add_math_node(char *arg1, char *arg2, char *arg3)
@@ -239,10 +240,11 @@ void del_math_node(struct link_data *node)
 int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 {
 {
 	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE], buf3[STRING_SIZE], *pti, *pta;
 	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE], buf3[STRING_SIZE], *pti, *pta;
-	int level, status, point, badnumber, nest;
+	int level, status, point, badnumber, metric, nest;
 
 
 	nest      = 0;
 	nest      = 0;
 	level     = 0;
 	level     = 0;
+	metric    = 0;
 	point     = -1;
 	point     = -1;
 	status    = EXP_VARIABLE;
 	status    = EXP_VARIABLE;
 	precision = seed;
 	precision = seed;
@@ -275,6 +277,16 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 					case '9':
 					case '9':
 						*pta++ = *pti++;
 						*pta++ = *pti++;
 
 
+						if (metric)
+						{
+							badnumber = 1;
+
+							if (debug == 0)
+							{
+								return FALSE;
+							}
+						}
+
 						if (point >= 0)
 						if (point >= 0)
 						{
 						{
 							point++;
 							point++;
@@ -313,6 +325,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						status = EXP_BRACE;
 						status = EXP_BRACE;
 						nest++;
 						nest++;
 						break;
 						break;
+
 					case '"':
 					case '"':
 						if (pta != buf3)
 						if (pta != buf3)
 						{
 						{
@@ -396,6 +409,90 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						}
 						}
 						break;
 						break;
 
 
+					case 'K':
+					case 'M':
+//					case 'G':
+//					case 'T':
+//					case 'P':
+//					case 'E':
+//					case 'Z':
+//					case 'Y':
+						if (pta == buf3 || metric == 1)
+						{
+							badnumber = 1;
+
+							if (debug == 0)
+							{
+								return FALSE;
+							}
+							*pta++ = *pti++;
+							*pta = 0;
+						}
+						else
+						{
+							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
+
+							*pta++ = '*';
+							MATH_NODE(FALSE, EXP_PR_INTMUL, EXP_VARIABLE);
+
+							switch (*pti++)
+							{
+								case 'K': pta += sprintf(pta, "1000"); break;
+								case 'M': pta += sprintf(pta, "1000000"); break;
+								case 'G': pta += sprintf(pta, "1000000000"); break;
+								case 'T': pta += sprintf(pta, "1000000000000"); break;
+								case 'P': pta += sprintf(pta, "1000000000000000"); break;
+								case 'E': pta += sprintf(pta, "1000000000000000000"); break;
+								case 'Z': pta += sprintf(pta, "1000000000000000000000"); break;
+								case 'Y': pta += sprintf(pta, "1000000000000000000000000"); break;
+							}
+							metric = 1;
+						}
+						break;
+
+					case 'm':
+					case 'u':
+//					case 'n':
+//					case 'p':
+//					case 'f':
+//					case 'a':
+//					case 'z':
+//					case 'y':
+						if (pta == buf3 || metric == 1)
+						{
+							badnumber = 1;
+
+							if (debug == 0)
+							{
+								return FALSE;
+							}
+							*pta++ = *pti++;
+							*pta = 0;
+						}
+						else
+						{
+							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
+
+							*pta++ = '/';
+
+							MATH_NODE(FALSE, EXP_PR_INTMUL, EXP_VARIABLE);
+
+							switch (*pti++)
+							{
+								case 'm': pta += sprintf(pta, "1000"); break;
+								case 'u': pta += sprintf(pta, "1000000"); break;
+								case 'n': pta += sprintf(pta, "1000000000"); break;
+								case 'p': pta += sprintf(pta, "1000000000000"); break;
+								case 'f': pta += sprintf(pta, "1000000000000000"); break;
+								case 'a': pta += sprintf(pta, "1000000000000000000"); break;
+								case 'z': pta += sprintf(pta, "1000000000000000000000"); break;
+								case 'y': pta += sprintf(pta, "1000000000000000000000000"); break;
+							}
+							metric = 1;
+							precision = UMAX(precision, strlen(buf3) -1);
+						}
+						break;
+
 					default:
 					default:
 						*pta++ = *pti++;
 						*pta++ = *pti++;
 						*pta = 0;
 						*pta = 0;
@@ -782,7 +879,9 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 					if (tintoi(node->next->str3) == 0)
 					if (tintoi(node->next->str3) == 0)
 					{
 					{
 						show_debug(ses, LIST_VARIABLE, "#MATH ERROR: DIVISION ZERO.");
 						show_debug(ses, LIST_VARIABLE, "#MATH ERROR: DIVISION ZERO.");
-						value = tintoi(node->prev->str3);
+						value = 0;
+						precision = 0;
+//						value = tintoi(node->prev->str3);
 					}
 					}
 					else
 					else
 					{
 					{
@@ -1263,6 +1362,7 @@ long double tineval(struct session *ses, char *left, char *right)
 long double tindice(struct session *ses, char *left, char *right)
 long double tindice(struct session *ses, char *left, char *right)
 {
 {
 	unsigned long long cnt, numdice, sizedice, sum;
 	unsigned long long cnt, numdice, sizedice, sum;
+	long double estimate;
 
 
 	numdice  = (unsigned long long) tintoi(left);
 	numdice  = (unsigned long long) tintoi(left);
 	sizedice = (unsigned long long) tintoi(right);
 	sizedice = (unsigned long long) tintoi(right);
@@ -1272,10 +1372,22 @@ long double tindice(struct session *ses, char *left, char *right)
 		return 0;
 		return 0;
 	}
 	}
 
 
+	if (numdice > 100)
+	{
+		estimate = numdice / 100.0;
+		numdice = 100;
+	}
+	else
+	{
+		estimate = 1;
+	}
+
 	for (cnt = sum = 0 ; cnt < numdice ; cnt++)
 	for (cnt = sum = 0 ; cnt < numdice ; cnt++)
 	{
 	{
 		sum += generate_rand(ses) % sizedice + 1;
 		sum += generate_rand(ses) % sizedice + 1;
 	}
 	}
 
 
+	sum *= estimate;
+
 	return (long double) sum;
 	return (long double) sum;
 }
 }

+ 2 - 3
src/mccp.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/

+ 93 - 23
src/memory.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2007                       *
 *                      coded by Igor van den Hoven 2007                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -62,12 +61,16 @@ char *str_alloc(int size)
 {
 {
 	char *str;
 	char *str;
 
 
-	struct str_data *str_ptr = (struct str_data *) calloc(1, gtd->str_size + size + 1);
+	struct str_data *str_ptr = (struct str_data *) calloc(1, sizeof(struct str_data) + size + 1);
+
+	LINK(str_ptr, gtd->memory->next, gtd->memory->prev);
+
+	gtd->memory->max++;
 
 
 	str_ptr->max = size + 1;
 	str_ptr->max = size + 1;
 	str_ptr->len = 0;
 	str_ptr->len = 0;
 
 
-	str = (char *) str_ptr + gtd->str_size;
+	str = (char *) str_ptr + sizeof(struct str_data);
 
 
 	*str = 0;
 	*str = 0;
 
 
@@ -80,7 +83,11 @@ struct str_data *str_realloc(struct str_data *str_ptr, int size)
 	{
 	{
 		int len = str_ptr->len;
 		int len = str_ptr->len;
 
 
-		str_ptr = (struct str_data *) realloc(str_ptr, gtd->str_size + size + 1);
+		UNLINK(str_ptr, gtd->memory->next, gtd->memory->prev);
+
+		str_ptr = (struct str_data *) realloc(str_ptr, sizeof(struct str_data) + size + 1);
+
+		LINK(str_ptr, gtd->memory->next, gtd->memory->prev);
 
 
 		str_ptr->max = size + 1;
 		str_ptr->max = size + 1;
 		str_ptr->len = len;
 		str_ptr->len = len;
@@ -94,10 +101,7 @@ struct str_data *str_resize(struct str_data *str_ptr, int add)
 
 
 	if (str_ptr->max <= len + add)
 	if (str_ptr->max <= len + add)
 	{
 	{
-		str_ptr = (struct str_data *) realloc(str_ptr, gtd->str_size + (len + 1) * 2 + add + 1);
-
-		str_ptr->max = (len + 1) * 2 + add + 1;
-		str_ptr->len = len;
+		str_ptr = str_realloc(str_ptr, len * 2 + add);
 	}
 	}
 	return str_ptr;
 	return str_ptr;
 }
 }
@@ -117,29 +121,42 @@ char *str_mim(char *original)
 
 
 void str_clone(char **clone, char *original)
 void str_clone(char **clone, char *original)
 {
 {
-	struct str_data *clo_ptr = (struct str_data *) (*clone - gtd->str_size);
+	struct str_data *clo_ptr = (struct str_data *) (*clone - sizeof(struct str_data));
 	int len = str_len(original);
 	int len = str_len(original);
 
 
 	if (clo_ptr->max < len)
 	if (clo_ptr->max < len)
 	{
 	{
 		clo_ptr = str_realloc(clo_ptr, len * 2);
 		clo_ptr = str_realloc(clo_ptr, len * 2);
 
 
-		*clone = (char *) clo_ptr + gtd->str_size;
+		*clone = (char *) clo_ptr + sizeof(struct str_data);
 	}
 	}
 }
 }
 
 
+char *str_dup_clone(char *original)
+{
+	char *dup;
+	int len;
+
+	len = str_len(original);
+	dup = str_alloc(len);
+
+	memcpy(dup, original, len + 1);
+
+	return dup;
+}
+
 // call after a non str_ function alters *str to set the correct length.
 // call after a non str_ function alters *str to set the correct length.
 
 
 void str_fix(char *original)
 void str_fix(char *original)
 {
 {
-	struct str_data *str_ptr = (struct str_data *) (original - gtd->str_size);
+	struct str_data *str_ptr = (struct str_data *) (original - sizeof(struct str_data));
 
 
 	str_ptr->len = strlen(original);
 	str_ptr->len = strlen(original);
 }
 }
 
 
 int str_len(char *str)
 int str_len(char *str)
 {
 {
-	struct str_data *str_ptr = (struct str_data *) (str - gtd->str_size);
+	struct str_data *str_ptr = (struct str_data *) (str - sizeof(struct str_data));
 
 
 	return str_ptr->len;
 	return str_ptr->len;
 }
 }
@@ -179,13 +196,13 @@ char *str_cpy(char **str, char *buf)
 
 
 	buf_len = strlen(buf);
 	buf_len = strlen(buf);
 
 
-	str_ptr = (struct str_data *) (*str - gtd->str_size);
+	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
 
 
 	if (str_ptr->max <= buf_len)
 	if (str_ptr->max <= buf_len)
 	{
 	{
 		str_ptr = str_realloc(str_ptr, buf_len);
 		str_ptr = str_realloc(str_ptr, buf_len);
 
 
-		*str = (char *) str_ptr + gtd->str_size;
+		*str = (char *) str_ptr + sizeof(struct str_data);
 	}
 	}
 	str_ptr->len = buf_len;
 	str_ptr->len = buf_len;
 
 
@@ -235,13 +252,13 @@ char *str_ncpy(char **str, char *buf, int len)
 		buf_len = len;
 		buf_len = len;
 	}
 	}
 
 
-	str_ptr = (struct str_data *) (*str - gtd->str_size);
+	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
 
 
 	if (str_ptr->max <= buf_len)
 	if (str_ptr->max <= buf_len)
 	{
 	{
 		str_ptr = str_realloc(str_ptr, len);
 		str_ptr = str_realloc(str_ptr, len);
 
 
-		*str = (char *) str_ptr + gtd->str_size;
+		*str = (char *) str_ptr + sizeof(struct str_data);
 	}
 	}
 
 
 	str_ptr->len = UMIN(buf_len, len);
 	str_ptr->len = UMIN(buf_len, len);
@@ -260,13 +277,13 @@ char *str_cat(char **str, char *buf)
 
 
 	buf_len = strlen(buf);
 	buf_len = strlen(buf);
 
 
-	str_ptr = (struct str_data *) (*str - gtd->str_size);
+	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
 
 
 	if (str_ptr->max <= str_ptr->len + buf_len)
 	if (str_ptr->max <= str_ptr->len + buf_len)
 	{
 	{
 		str_ptr = str_resize(str_ptr, buf_len);
 		str_ptr = str_resize(str_ptr, buf_len);
 
 
-		*str = (char *) str_ptr + gtd->str_size;
+		*str = (char *) str_ptr + sizeof(struct str_data);
 	}
 	}
 
 
 	strcpy(&(*str)[str_ptr->len], buf);
 	strcpy(&(*str)[str_ptr->len], buf);
@@ -282,13 +299,13 @@ char *str_cat_chr(char **ptr, char chr)
 {
 {
 	struct str_data *str_ptr;
 	struct str_data *str_ptr;
 
 
-	str_ptr = (struct str_data *) (*ptr - gtd->str_size);
+	str_ptr = (struct str_data *) (*ptr - sizeof(struct str_data));
 
 
 	if (str_ptr->max <= str_ptr->len + 1)
 	if (str_ptr->max <= str_ptr->len + 1)
 	{
 	{
 		str_ptr = str_resize(str_ptr, 1);
 		str_ptr = str_resize(str_ptr, 1);
 
 
-		*ptr = (char *) str_ptr + gtd->str_size;
+		*ptr = (char *) str_ptr + sizeof(struct str_data);
 	}
 	}
 
 
 	(*ptr)[str_ptr->len++] = chr;
 	(*ptr)[str_ptr->len++] = chr;
@@ -315,7 +332,60 @@ char *str_cat_printf(char **ptr, char *fmt, ...)
 	return *ptr;
 	return *ptr;
 }
 }
 
 
+char *str_ins(char **str, int index, char *buf)
+{
+	int buf_len;
+	struct str_data *str_ptr;
+
+	buf_len = strlen(buf);
+
+	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
+
+	if (str_ptr->max <= str_ptr->len + buf_len)
+	{
+		str_ptr = str_resize(str_ptr, buf_len);
+
+		*str = (char *) str_ptr + sizeof(struct str_data);
+	}
+
+	if (index >= str_ptr->len)
+	{
+		strcpy(&(*str)[str_ptr->len], buf);
+	}
+	else
+	{
+		int cnt;
+		char *pta, *ptz;
+
+		pta = &(*str)[str_ptr->len + 1];
+		ptz = &(*str)[str_ptr->len + 1 + buf_len];
+
+		for (cnt = 0 ; cnt < buf_len + 1 ; cnt++)
+		{
+			*ptz-- = *pta--;
+		}
+
+		pta = &(*str)[index];
+		ptz = buf;
+
+		for (cnt = 0 ; cnt < buf_len ; cnt++)
+		{
+			*pta++ = *ptz++;
+		}
+	}
+
+	str_ptr->len += buf_len;
+
+	return *str;
+}
+
 void str_free(char *ptr)
 void str_free(char *ptr)
 {
 {
-	free((struct str_data *) (ptr - gtd->str_size));
+	struct str_data *str_ptr = (struct str_data *) (ptr - sizeof(struct str_data));
+
+	UNLINK(str_ptr, gtd->memory->next, gtd->memory->prev);
+
+	gtd->memory->max--;
+
+	free(str_ptr);
 }
 }

+ 25 - 0
src/misc.c

@@ -257,5 +257,30 @@ DO_COMMAND(do_send)
 
 
 DO_COMMAND(do_test)
 DO_COMMAND(do_test)
 {
 {
+	char arg1[BUFFER_SIZE], arg2[100], arg3[100], arg4[100];
+
+	strcpy(arg2, "9");
+	strcpy(arg3, "<f0b8>");
+	strcpy(arg4, "1 9");
+
+	if (isdigit(arg[0]))
+	{
+		sprintf(arg2, "%d", (arg[0] - '0') * (arg[0] - '0'));
+
+		if (isxdigit(arg[1]) && isxdigit(arg[2]) && isxdigit(arg[3]))
+		{
+			sprintf(arg3, "<f%c%c%c>", arg[1], arg[2], arg[3]);
+
+			if (isdigit(arg[4]) && isdigit(arg[5]))
+			{
+				sprintf(arg4, "%d %d %s", (arg[4] - '0') * (arg[4] - '0') / 10, (arg[5] - '0') * (arg[5] - '0'), &arg[6]);
+			}
+		}
+	}
+	sprintf(arg1, "#line quiet {#event {RECEIVED KEYPRESS} {#end \\};#screen cursor hide;#screen clear all;#event {SECOND} #loop 0 %s cnt #delay {$cnt / (1.0+%s)} #draw %s rain 1 1 -1 -1 rain %s}", arg2, arg2, arg3, arg4);
+
+	script_driver(gtd->ses, LIST_COMMAND, arg1);
+
 	return ses;
 	return ses;
 }
 }
+

+ 6 - 4
src/msdp.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2011                       *
 *                      coded by Igor van den Hoven 2011                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -121,7 +120,10 @@ void msdp_update_all(char *var, char *fmt, ...)
 		{
 		{
 			for (buddy = ses->port->next ; buddy ; buddy = buddy->next)
 			for (buddy = ses->port->next ; buddy ; buddy = buddy->next)
 			{
 			{
-				msdp_update_var(ses, buddy, var, buf);
+				if (buddy->msdp_data)
+				{
+					msdp_update_var(ses, buddy, var, buf);
+				}
 			}
 			}
 		}
 		}
 	}
 	}

+ 309 - 15
src/nest.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2009                       *
 *                      coded by Igor van den Hoven 2009                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -39,6 +38,40 @@ struct listroot *search_nest_root(struct listroot *root, char *arg)
 	return node->root;
 	return node->root;
 }
 }
 
 
+struct listroot *search_nest_base_ses(struct session *ses, char *arg)
+{
+	struct listnode *node;
+	struct listroot *root;
+
+	int index;
+
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
+	{
+		for (index = gtd->script_index ; index ; index--)
+		{
+			root = gtd->script_stack[index]->local;
+
+			if (root->used)
+			{
+				node = search_node_list(root, arg);
+
+				if (node)
+				{
+					return root;
+				}
+			}
+		}
+	}
+
+	node = search_node_list(ses->list[LIST_VARIABLE], arg);
+
+	if (node == NULL)
+	{
+		return NULL;
+	}
+	return ses->list[LIST_VARIABLE];
+}
+
 struct listnode *search_base_node(struct listroot *root, char *variable)
 struct listnode *search_base_node(struct listroot *root, char *variable)
 {
 {
 	char name[BUFFER_SIZE];
 	char name[BUFFER_SIZE];
@@ -48,6 +81,69 @@ struct listnode *search_base_node(struct listroot *root, char *variable)
 	return search_node_list(root, name);
 	return search_node_list(root, name);
 }
 }
 
 
+struct listnode *search_nest_node_ses(struct session *ses, char *variable)
+{
+	char name[BUFFER_SIZE], *arg;
+	struct listroot *root;
+	struct listnode *node;
+	int index;
+
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
+	{
+		for (index = gtd->script_index ; index ; index--)
+		{
+			root = gtd->script_stack[index]->local;
+
+			if (root->used)
+			{
+				arg = get_arg_to_brackets(root->ses, variable, name);
+
+				while (root && *arg)
+				{
+					root = search_nest_root(root, name);
+
+					if (root)
+					{
+						arg = get_arg_in_brackets(root->ses, arg, name);
+					}
+				}
+
+				if (root)
+				{
+					node = search_node_list(root, name);
+
+					if (node)
+					{
+						return node;
+					}
+				}
+			}
+		}
+	}
+
+	root = ses->list[LIST_VARIABLE];
+
+	arg = get_arg_to_brackets(ses, variable, name);
+
+	while (root && *arg)
+	{
+		root = search_nest_root(root, name);
+
+		if (root)
+		{
+			arg = get_arg_in_brackets(root->ses, arg, name);
+		}
+	}
+
+	if (root)
+	{
+		return search_node_list(root, name);
+	}
+
+	return NULL;
+}
+
+	
 struct listnode *search_nest_node(struct listroot *root, char *variable)
 struct listnode *search_nest_node(struct listroot *root, char *variable)
 {
 {
 	char name[BUFFER_SIZE], *arg;
 	char name[BUFFER_SIZE], *arg;
@@ -767,8 +863,166 @@ void view_nest_node(struct listnode *node, char **str_result, int nest, int init
 	}
 	}
 }
 }
 
 
+struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format, ...)
+{
+	struct listnode *node;
+	struct listroot *root;
+	char *arg, *arg2, name[BUFFER_SIZE];
+	va_list args;
+
+	push_call("set_nest_node_ses(%p,%s,%p,...)",ses,arg1,format);
+
+	va_start(args, format);
+	vasprintf(&arg2, format, args);
+	va_end(args);
+
+	arg = get_arg_to_brackets(ses, arg1, name);
+
+	check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+
+	root = search_nest_base_ses(ses, name);
+
+	if (root == NULL)
+	{
+		root = ses->list[LIST_VARIABLE];
+		node = NULL;
+	}
+	else
+	{
+		node = search_nest_node(root, arg1);
+	}
+
+	while (*arg)
+	{
+		root = update_nest_root(root, name);
+
+		if (root)
+		{
+			arg = get_arg_in_brackets(root->ses, arg, name);
+		}
+	}
+
+	node = search_node_list(root, name);
+
+	if (node && node->root)
+	{
+		free_list(node->root);
+
+		node->root = NULL;
+	}
+
+	if (*space_out(arg2) == DEFAULT_OPEN)
+	{
+		update_nest_node(update_nest_root(root, name), arg2);
+
+		node = search_node_list(root, name);
+	}
+	else if (node)
+	{
+		str_cpy(&node->arg2, arg2);
+	}
+	else
+	{
+		node = update_node_list(root, name, arg2, "", "");
+	}
+
+	if (gtd->level->oneshot)
+	{
+		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+	}
+
+	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+
+	free(arg2);
+
+	pop_call();
+	return node;
+}
+
+// like set, but we're adding here.
+
+struct listnode *add_nest_node_ses(struct session *ses, char *arg1, char *format, ...)
+{
+	struct listnode *node;
+	struct listroot *root;
+	char *arg, *arg2, name[BUFFER_SIZE];
+	va_list args;
+
+	push_call("add_nest_node_ses(%p,%s,%p,...)",ses,arg1,format);
+
+	va_start(args, format);
+	vasprintf(&arg2, format, args);
+	va_end(args);
+
+	arg = get_arg_to_brackets(ses, arg1, name);
+
+	check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+
+	root = search_nest_base_ses(ses, name);
+
+	if (root == NULL)
+	{
+		root = ses->list[LIST_VARIABLE];
+		node = NULL;
+	}
+	else
+	{
+		node = search_nest_node(root, arg1);
+	}
+
+	while (*arg)
+	{
+		root = update_nest_root(root, name);
+
+		if (root)
+		{
+			arg = get_arg_in_brackets(root->ses, arg, name);
+		}
+	}
+
+	node = search_node_list(root, name);
+
+/*
+	if (node && node->root)
+	{
+		free_list(node->root);
+
+		node->root = NULL;
+	}
+*/
+
+	if (*space_out(arg2) == DEFAULT_OPEN)
+	{
+		update_nest_node(update_nest_root(root, name), arg2);
+
+		node = search_node_list(root, name);
+	}
+	else if (node)
+	{
+		str_cpy(&node->arg2, arg2);
+	}
+	else
+	{
+		node = update_node_list(root, name, arg2, "", "");
+	}
+
+	if (gtd->level->oneshot)
+	{
+		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+	}
+
+	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+
+	free(arg2);
+
+	pop_call();
+	return node;
+}
+
+
 struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format, ...)
 struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format, ...)
 {
 {
+	struct listroot *base;
 	struct listnode *node;
 	struct listnode *node;
 	char *arg, *arg2, name[BUFFER_SIZE];
 	char *arg, *arg2, name[BUFFER_SIZE];
 	va_list args;
 	va_list args;
@@ -783,9 +1037,14 @@ struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format,
 
 
 	check_all_events(root->ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
 	check_all_events(root->ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
 
 
-	if (search_node_list(local_list(NULL), name))
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
 	{
 	{
-		root = local_list(NULL);
+		base = search_nest_base_ses(root->ses, name);
+
+		if (base)
+		{
+			root = base;
+		}
 	}
 	}
 
 
 	while (*arg)
 	while (*arg)
@@ -813,6 +1072,10 @@ struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format,
 
 
 		node = search_node_list(root, name);
 		node = search_node_list(root, name);
 	}
 	}
+	else if (node)
+	{
+		str_cpy(&node->arg2, arg2);
+	}
 	else
 	else
 	{
 	{
 		node = update_node_list(root, name, arg2, "", "");
 		node = update_node_list(root, name, arg2, "", "");
@@ -835,16 +1098,31 @@ struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format,
 
 
 struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format, ...)
 struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format, ...)
 {
 {
-//	struct listnode *node;
-	char arg2[BUFFER_SIZE], name[BUFFER_SIZE], *arg;
+	struct listroot *base;
+	struct listnode *node;
+	char *arg, *arg2, name[BUFFER_SIZE];
 	va_list args;
 	va_list args;
 
 
+	push_call("add_nest_node(%p,%s,%p,...)",root,arg1,format);
+
 	va_start(args, format);
 	va_start(args, format);
-	vsprintf(arg2, format, args);
+	vasprintf(&arg2, format, args);
 	va_end(args);
 	va_end(args);
 
 
 	arg = get_arg_to_brackets(root->ses, arg1, name);
 	arg = get_arg_to_brackets(root->ses, arg1, name);
 
 
+	check_all_events(root->ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
+	{
+		base = search_nest_base_ses(root->ses, name);
+
+		if (base)
+		{
+			root = base;
+		}
+	}
+
 	while (*arg)
 	while (*arg)
 	{
 	{
 		root = update_nest_root(root, name);
 		root = update_nest_root(root, name);
@@ -855,11 +1133,8 @@ struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format,
 		}
 		}
 	}
 	}
 
 
-/*
-	Adding here, so don't clear the variable.
-
 	node = search_node_list(root, name);
 	node = search_node_list(root, name);
-
+/*
 	if (node && node->root)
 	if (node && node->root)
 	{
 	{
 		free_list(node->root);
 		free_list(node->root);
@@ -867,16 +1142,35 @@ struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format,
 		node->root = NULL;
 		node->root = NULL;
 	}
 	}
 */
 */
+
 	if (*space_out(arg2) == DEFAULT_OPEN)
 	if (*space_out(arg2) == DEFAULT_OPEN)
 	{
 	{
-		update_nest_node(update_nest_root(root, name), arg2);
+		root = update_nest_root(root, name);
 
 
-		return search_node_list(root, name);
+		update_nest_node(root, arg2);
+
+		node = search_node_list(root, name);
+	}
+	else if (node)
+	{
+		str_cat(&node->arg2, arg2);
 	}
 	}
 	else
 	else
 	{
 	{
-		return update_node_list(root, name, arg2, "", "");
+		node = update_node_list(root, name, arg2, "", "");
+	}
+
+	if (gtd->level->oneshot)
+	{
+		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
 	}
 	}
+
+	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+
+	free(arg2);
+
+	pop_call();
+	return node;
 }
 }
 
 
 
 

+ 7 - 29
src/net.c

@@ -223,24 +223,13 @@ void write_line_mud(struct session *ses, char *line, int size)
 		return;
 		return;
 	}
 	}
 
 
-	if (!HAS_BIT(ses->telopts, TELOPT_FLAG_TELNET))
+	if (!HAS_BIT(ses->telopts, TELOPT_FLAG_TELNET) && HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5TOUTF8))
-		{
-			char buf[BUFFER_SIZE];
-
-			size = utf8_to_big5(line, buf);
-
-			strcpy(line, buf);
-		}
-		else if (HAS_BIT(ses->charset, CHARSET_FLAG_KOI8TOUTF8))
-		{
-			char buf[BUFFER_SIZE];
+		char buf[BUFFER_SIZE];
 
 
-			size = utf8_to_koi8(line, buf);
+		size = utf8_to_all(ses, line, buf);
 
 
-			strcpy(line, buf);
-		}
+		strcpy(line, buf);
 	}
 	}
 
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "SEND OUTPUT", line, ntos(size));
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "SEND OUTPUT", line, ntos(size));
@@ -252,7 +241,6 @@ void write_line_mud(struct session *ses, char *line, int size)
 			result = client_write_compressed(ses, line, size);
 			result = client_write_compressed(ses, line, size);
 		}
 		}
 #ifdef HAVE_GNUTLS_H
 #ifdef HAVE_GNUTLS_H
-
 		else if (ses->ssl)
 		else if (ses->ssl)
 		{
 		{
 			result = gnutls_record_send(ses->ssl, line, size);
 			result = gnutls_record_send(ses->ssl, line, size);
@@ -426,22 +414,12 @@ void readmud(struct session *ses)
 			strcpy(linebuf, line);
 			strcpy(linebuf, line);
 		}
 		}
 
 
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5TOUTF8) || HAS_BIT(ses->charset, CHARSET_FLAG_FANSITOUTF8) || HAS_BIT(ses->charset, CHARSET_FLAG_KOI8TOUTF8))
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 		{
 		{
 			char tempbuf[BUFFER_SIZE];
 			char tempbuf[BUFFER_SIZE];
 
 
-			if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5TOUTF8))
-			{
-				big5_to_utf8(linebuf, tempbuf);
-			}
-			else if (HAS_BIT(ses->charset, CHARSET_FLAG_FANSITOUTF8))
-			{
-				fansi_to_utf8(linebuf, tempbuf);
-			}
-			else
-			{
-				koi8_to_utf8(linebuf, tempbuf);
-			}
+			all_to_utf8(ses, linebuf, tempbuf);
+
 			process_mud_output(ses, tempbuf, next_line == NULL);
 			process_mud_output(ses, tempbuf, next_line == NULL);
 		}
 		}
 		else
 		else

+ 226 - 13
src/parse.c

@@ -222,9 +222,74 @@ struct session *parse_command(struct session *ses, char *input)
 	return ses;
 	return ses;
 }
 }
 
 
+char *substitute_speedwalk(struct session *ses, char *input, char *output)
+{
+	char num[NUMBER_SIZE], name[BUFFER_SIZE], *pti, *ptn, *pto;
+	int cnt, max;
+
+	pti = input;
+	pto = output;
+
+	while (*pti && pto - output < INPUT_SIZE)
+	{
+		while (isspace(*pti))
+		{
+			pti++;
+		}
+
+		if (isdigit(*pti))
+		{
+			ptn = num;
+
+			while (isdigit(*pti))
+			{
+				if (ptn - num < 4)
+				{
+					*ptn++ = *pti++;
+				}
+				else
+				{
+					pti++;
+				}
+			}
+			*ptn = 0;
+
+			max = atoi(num);
+		}
+		else
+		{
+			max = 1;
+		}
+
+		pti = get_arg_stop_digits(ses, pti, name, GET_ONE);
+
+		if (*name == 0)
+		{
+			break;
+		}
+
+		for (cnt = 0 ; cnt < max ; cnt++)
+		{
+			if (output != pto)
+			{
+				*pto++ = COMMAND_SEPARATOR;
+			}
+			pto += sprintf(pto, "%s", name);
+		}
+
+		if (*pti == COMMAND_SEPARATOR)
+		{
+			pti++;
+		}
+	}
+	*pto = 0;
+
+	return output;
+}
+	
 int is_speedwalk(struct session *ses, char *input)
 int is_speedwalk(struct session *ses, char *input)
 {
 {
-	int flag = FALSE;
+	int digit = 0, flag = FALSE;
 
 
 	while (*input)
 	while (*input)
 	{
 	{
@@ -236,7 +301,12 @@ int is_speedwalk(struct session *ses, char *input)
 			case 'w':
 			case 'w':
 			case 'u':
 			case 'u':
 			case 'd':
 			case 'd':
-				flag = TRUE;
+				if (digit > 3)
+				{
+					return FALSE;
+				}
+				digit = 0;
+				flag  = TRUE;
 				break;
 				break;
 
 
 			case '0':
 			case '0':
@@ -249,6 +319,7 @@ int is_speedwalk(struct session *ses, char *input)
 			case '7':
 			case '7':
 			case '8':
 			case '8':
 			case '9':
 			case '9':
+				digit++;
 				flag = FALSE;
 				flag = FALSE;
 				break;
 				break;
 
 
@@ -346,6 +417,28 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 }
 }
 
 
 
 
+int cnt_arg_all(struct session *ses, char *string, int flag)
+{
+	char *arg, tmp[BUFFER_SIZE];
+	int cnt;
+
+	arg = string;
+	cnt = 0;
+
+	while (*arg)
+	{
+		cnt++;
+
+		arg = get_arg_in_braces(ses, arg, tmp, flag);
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
+	}
+	return cnt;
+}
+
 /*
 /*
 	get all arguments - only check for unescaped command separators
 	get all arguments - only check for unescaped command separators
 */
 */
@@ -354,7 +447,7 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 {
 {
 	char *pto, *pti;
 	char *pto, *pti;
-	int nest = 0;
+	int skip, nest = 0;
 
 
 	pti = string;
 	pti = string;
 	pto = result;
 	pto = result;
@@ -372,13 +465,24 @@ char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			continue;
 			continue;
 		}
 		}
 
 
+		skip = find_secure_color_code(pti);
+
+		if (skip)
+		{
+			while (skip--)
+			{
+				*pto++ = *pti++;
+			}
+			continue;
+		}
+
 		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
 		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -419,7 +523,7 @@ char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 char *get_arg_in_braces(struct session *ses, char *string, char *result, int flag)
 char *get_arg_in_braces(struct session *ses, char *string, char *result, int flag)
 {
 {
 	char *pti, *pto;
 	char *pti, *pto;
-	int nest = 1;
+	int skip, nest = 1;
 
 
 	pti = space_out(string);
 	pti = space_out(string);
 	pto = result;
 	pto = result;
@@ -442,13 +546,24 @@ char *get_arg_in_braces(struct session *ses, char *string, char *result, int fla
 	while (*pti)
 	while (*pti)
 	{
 	{
 		
 		
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			continue;
 			continue;
 		}
 		}
 
 
+		skip = find_secure_color_code(pti);
+
+		if (skip)
+		{
+			while (skip--)
+			{
+				*pto++ = *pti++;
+			}
+			continue;
+		}
+
 		if (*pti == DEFAULT_OPEN)
 		if (*pti == DEFAULT_OPEN)
 		{
 		{
 			nest++;
 			nest++;
@@ -498,20 +613,31 @@ char *sub_arg_in_braces(struct session *ses, char *string, char *result, int fla
 char *get_arg_with_spaces(struct session *ses, char *string, char *result, int flag)
 char *get_arg_with_spaces(struct session *ses, char *string, char *result, int flag)
 {
 {
 	char *pto, *pti;
 	char *pto, *pti;
-	int nest = 0;
+	int skip, nest = 0;
 
 
 	pti = space_out(string);
 	pti = space_out(string);
 	pto = result;
 	pto = result;
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			continue;
 			continue;
 		}
 		}
 
 
+		skip = find_secure_color_code(pti);
+
+		if (skip)
+		{
+			while (skip--)
+			{
+				*pto++ = *pti++;
+			}
+			continue;
+		}
+
 		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
 		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -542,20 +668,32 @@ char *get_arg_with_spaces(struct session *ses, char *string, char *result, int f
 char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int flag)
 char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int flag)
 {
 {
 	char *pto, *pti;
 	char *pto, *pti;
-	int nest = 0;
+	int skip, nest = 0;
 
 
 	pti = space_out(string);
 	pti = space_out(string);
 	pto = result;
 	pto = result;
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			continue;
 			continue;
 		}
 		}
 
 
+		skip = find_secure_color_code(pti);
+
+		if (skip)
+		{
+			while (skip--)
+			{
+				*pto++ = *pti++;
+			}
+			continue;
+		}
+
+
 		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
 		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -592,6 +730,61 @@ char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int f
 	return pti;
 	return pti;
 }
 }
 
 
+// Get one arg, stop at numbers, used for speedwalks
+
+char *get_arg_stop_digits(struct session *ses, char *string, char *result, int flag)
+{
+	char *pto, *pti;
+	int nest = 0;
+
+	pti = space_out(string);
+	pto = result;
+
+	while (*pti)
+	{
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
+		{
+			*pto++ = *pti++;
+			*pto++ = *pti++;
+			continue;
+		}
+
+		if (*pti == '\\' && pti[1] == COMMAND_SEPARATOR)
+		{
+			*pto++ = *pti++;
+		}
+		else if (*pti == COMMAND_SEPARATOR && nest == 0)
+		{
+			break;
+		}
+		else if (isdigit((int) *pti) && nest == 0)
+		{
+			pti++;
+			break;
+		}
+		else if (*pti == DEFAULT_OPEN)
+		{
+			nest++;
+		}
+		else if (*pti == '[' && HAS_BIT(flag, GET_NST))
+		{
+			nest++;
+		}
+		else if (*pti == DEFAULT_CLOSE)
+		{
+			nest--;
+		}
+		else if (*pti == ']' && HAS_BIT(flag, GET_NST))
+		{
+			nest--;
+		}
+		*pto++ = *pti++;
+	}
+	*pto = '\0';
+
+	return pti;
+}
+
 /*
 /*
 	advance ptr to next none-space
 	advance ptr to next none-space
 */
 */
@@ -620,7 +813,7 @@ char *get_arg_to_brackets(struct session *ses, char *string, char *result)
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -687,7 +880,7 @@ char *get_arg_at_brackets(struct session *ses, char *string, char *result)
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -744,7 +937,7 @@ char *get_arg_in_brackets(struct session *ses, char *string, char *result)
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -780,6 +973,26 @@ char *get_arg_in_brackets(struct session *ses, char *string, char *result)
 	return pti;
 	return pti;
 }
 }
 
 
+char *get_char(struct session *ses, char *string, char *result)
+{
+	char *pti = string;
+
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
+	{
+		pti += sprintf(result, "%c%c", pti[0], pti[1]);
+	}
+	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
+	{
+		pti += sprintf(result, "%.*s", get_utf8_size(pti), pti);
+	}
+	else
+	{
+		pti += sprintf(result, "%c", pti[0]);
+	}
+
+	return pti;
+}
+
 /*
 /*
 	send command to the mud
 	send command to the mud
 */
 */

+ 69 - 73
src/path.c

@@ -81,7 +81,7 @@ DO_PATH(path_create)
 
 
 	root->update = 0;
 	root->update = 0;
 
 
-	show_message(ses, LIST_PATH, "#PATH CREATE: YOU START MAPPING A NEW PATH.");
+	show_message(ses, LIST_COMMAND, "#PATH CREATE: YOU START MAPPING A NEW PATH.");
 
 
 	SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 }
 }
@@ -97,7 +97,7 @@ DO_PATH(path_destroy)
 
 
 	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
 
-	show_message(ses, LIST_PATH, "#PATH DESTROY: PATH DESTROYED.");
+	show_message(ses, LIST_COMMAND, "#PATH DESTROY: PATH DESTROYED.");
 }
 }
 
 
 
 
@@ -105,13 +105,13 @@ DO_PATH(path_start)
 {
 {
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH START: ERROR: YOU ARE ALREADY MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH START: ERROR: YOU ARE ALREADY MAPPING A PATH.");
 	}
 	}
 	else
 	else
 	{
 	{
 		SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 		SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
 
-		show_message(ses, LIST_PATH, "#PATH START: YOU START MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH START: YOU START MAPPING A PATH.");
 	}
 	}
 }
 }
 
 
@@ -122,23 +122,23 @@ DO_PATH(path_stop)
 
 
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH STOP: YOU STOP MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH STOP: YOU STOP MAPPING A PATH.");
 
 
 		DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 		DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	}
 	}
 	else
 	else
 	{
 	{
-		if (root->list[root->update]->data)
+		if (root->list[root->update]->val64)
 		{
 		{
 			for (index = 0 ; index < root->used ; index++)
 			for (index = 0 ; index < root->used ; index++)
 			{
 			{
-				root->list[index]->data = 0;
+				root->list[index]->val64 = 0;
 			}
 			}
-			show_message(ses, LIST_PATH, "#PATH STOP: YOU STOP RUNNING A PATH.");
+			show_message(ses, LIST_COMMAND, "#PATH STOP: YOU STOP RUNNING A PATH.");
 		}
 		}
 		else
 		else
 		{
 		{
-			show_message(ses, LIST_PATH, "#PATH STOP: YOU ARE NOT MAPPING OR RUNNING A PATH.");
+			show_message(ses, LIST_COMMAND, "#PATH STOP: YOU ARE NOT MAPPING OR RUNNING A PATH.");
 		}
 		}
 	}
 	}
 }
 }
@@ -164,6 +164,8 @@ DO_PATH(path_describe)
 
 
 	i = x = y = z = 0;
 	i = x = y = z = 0;
 
 
+	i = root->update;
+
 	while (i < root->used)
 	while (i < root->used)
 	{
 	{
 		node = search_node_list(ses->list[LIST_PATHDIR], root->list[i++]->arg1);
 		node = search_node_list(ses->list[LIST_PATHDIR], root->list[i++]->arg1);
@@ -188,11 +190,18 @@ DO_PATH(path_describe)
 	{
 	{
 		if (z == 0)
 		if (z == 0)
 		{
 		{
-			tintin_printf2(ses, "The path is %d rooms long and the destination is right where you are.");
+			if (root->used > 2)
+			{
+				tintin_printf2(ses, "The path is %d rooms long and leads back to where you are at.", root->used);
+			}
+			else
+			{
+				tintin_printf2(ses, "The path is %d rooms long and the destination is right where you are at.", root->used);
+			}
 		}
 		}
 		else
 		else
 		{
 		{
-			tintin_printf2(ses, "The path is %d rooms long and the destination lies %d rooms %s you.", root->used, abs(z), z < 0 ? "below" : "above", s);
+			tintin_printf2(ses, "The path is %d rooms long and the destination lies %d rooms %s of you.", root->used, abs(z), z < 0 ? "below" : "above", s);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -222,7 +231,7 @@ DO_PATH(path_map)
 
 
 	if (root->used == 0)
 	if (root->used == 0)
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH MAP: EMPTY PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH MAP: EMPTY PATH.");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -268,7 +277,7 @@ DO_PATH(path_save)
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_PATH, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD|LENGTH|POSITION> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD|LENGTH|POSITION> <VARIABLE NAME>");
 	}
 	}
 	else if (is_abbrev(arg1, "BACKWARDS"))
 	else if (is_abbrev(arg1, "BACKWARDS"))
 	{
 	{
@@ -283,9 +292,9 @@ DO_PATH(path_save)
 				cat_sprintf(result, "%c", COMMAND_SEPARATOR);
 				cat_sprintf(result, "%c", COMMAND_SEPARATOR);
 			}
 			}
 		}
 		}
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", result);
+		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_PATH, "#PATH SAVE: BACKWARD PATH SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: BACKWARD PATH SAVED TO {%s}", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "FORWARDS"))
 	else if (is_abbrev(arg1, "FORWARDS"))
 	{
 	{
@@ -300,29 +309,29 @@ DO_PATH(path_save)
 				cat_sprintf(result, "%c", COMMAND_SEPARATOR);
 				cat_sprintf(result, "%c", COMMAND_SEPARATOR);
 			}
 			}
 		}
 		}
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", result);
+		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_PATH, "#PATH SAVE: FORWARD PATH SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: FORWARD PATH SAVED TO {%s}", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "LENGTH"))
 	else if (is_abbrev(arg1, "LENGTH"))
 	{
 	{
 		sprintf(result, "%d", root->used);
 		sprintf(result, "%d", root->used);
 
 
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", result);
+		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_PATH, "#PATH SAVE: PATH LENGTH SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH LENGTH SAVED TO {%s}", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "POSITION"))
 	else if (is_abbrev(arg1, "POSITION"))
 	{
 	{
 		sprintf(result, "%d", root->update + 1);
 		sprintf(result, "%d", root->update + 1);
 
 
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%s", result);
+		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_PATH, "#PATH SAVE: PATH POSITION SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH POSITION SAVED TO {%s}", arg2);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_PATH, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD|LENGTH|POSITION> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD|LENGTH|POSITION> <VARIABLE NAME>");
 	}
 	}
 }
 }
 
 
@@ -335,7 +344,7 @@ DO_PATH(path_load)
 
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 
-	if ((node = search_node_list(ses->list[LIST_VARIABLE], arg1)) == NULL)
+	if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 	{
 	{
 		arg = arg1;
 		arg = arg1;
 	}
 	}
@@ -366,7 +375,7 @@ DO_PATH(path_load)
 			insert_node_list(root, temp, temp, "0", "");
 			insert_node_list(root, temp, temp, "0", "");
 		}
 		}
 	}
 	}
-	show_message(ses, LIST_PATH, "#PATH LOAD: PATH WITH %d NODES LOADED.", root->used);
+	show_message(ses, LIST_COMMAND, "#PATH LOAD: PATH WITH %d NODES LOADED.", root->used);
 }
 }
 
 
 DO_PATH(path_delete)
 DO_PATH(path_delete)
@@ -375,7 +384,7 @@ DO_PATH(path_delete)
 
 
 	if (root->used)
 	if (root->used)
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH DELETE: DELETED MOVE {%s}.", root->list[root->used - 1]->arg1);
+		show_message(ses, LIST_COMMAND, "#PATH DELETE: DELETED MOVE {%s}.", root->list[root->used - 1]->arg1);
 
 
 		delete_index_list(root, root->used - 1);
 		delete_index_list(root, root->used - 1);
 
 
@@ -401,13 +410,13 @@ DO_PATH(path_insert)
 
 
 	if (*arg1 == 0 && *arg2 == 0)
 	if (*arg1 == 0 && *arg2 == 0)
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH INSERT: ERROR: YOU MUST GIVE A COMMAND TO INSERT");
+		show_message(ses, LIST_COMMAND, "#PATH INSERT: ERROR: YOU MUST GIVE A COMMAND TO INSERT");
 	}
 	}
 	else
 	else
 	{
 	{
 		insert_node_list(root, arg1, arg2, "0", "");
 		insert_node_list(root, arg1, arg2, "0", "");
 
 
-		show_message(ses, LIST_PATH, "#PATH INSERT: FORWARD {%s} BACKWARD {%s}.", arg1, arg2);
+		show_message(ses, LIST_COMMAND, "#PATH INSERT: FORWARD {%s} BACKWARD {%s}.", arg1, arg2);
 
 
 		if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 		if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 		{
 		{
@@ -444,7 +453,7 @@ DO_PATH(path_run)
 
 
 			for (index = root->update ; index < root->used ; index++)
 			for (index = root->update ; index < root->used ; index++)
 			{
 			{
-				root->list[index]->data = gtd->utime + total;
+				root->list[index]->val64 = gtd->utime + total;
 
 
 				total += delay;
 				total += delay;
 			}
 			}
@@ -453,7 +462,7 @@ DO_PATH(path_run)
 		{
 		{
 			while (root->update < root->used)
 			while (root->update < root->used)
 			{
 			{
-				script_driver(ses, LIST_PATH, root->list[root->update++]->arg1);
+				script_driver(ses, LIST_COMMAND, root->list[root->update++]->arg1);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -480,7 +489,7 @@ DO_PATH(path_walk)
 		}
 		}
 		else
 		else
 		{
 		{
-			script_driver(ses, LIST_PATH, root->list[--root->update]->arg2);
+			script_driver(ses, LIST_COMMAND, root->list[--root->update]->arg2);
 
 
 			if (root->update == 0)
 			if (root->update == 0)
 			{
 			{
@@ -496,7 +505,7 @@ DO_PATH(path_walk)
 		}
 		}
 		else
 		else
 		{
 		{
-			script_driver(ses, LIST_PATH, root->list[root->update++]->arg1);
+			script_driver(ses, LIST_COMMAND, root->list[root->update++]->arg1);
 
 
 			if (root->update == root->used)
 			if (root->update == root->used)
 			{
 			{
@@ -506,7 +515,7 @@ DO_PATH(path_walk)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_PATH, "#SYNTAX: #PATH WALK {FORWARD|BACKWARD}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH WALK {FORWARD|BACKWARD}.");
 	}
 	}
 }
 }
 
 
@@ -519,7 +528,7 @@ DO_PATH(path_swap)
 
 
 	if (root->used == 0)
 	if (root->used == 0)
 	{
 	{
-		show_error(ses, LIST_PATH, "#PATH SWAP: ERROR: PATH IS EMPTY.");
+		show_error(ses, LIST_COMMAND, "#PATH SWAP: ERROR: PATH IS EMPTY.");
 
 
 		return;
 		return;
 	}
 	}
@@ -554,7 +563,7 @@ DO_PATH(path_swap)
 		root->list[z]->arg2 = arg;
 		root->list[z]->arg2 = arg;
 	}
 	}
 
 
-	show_message(ses, LIST_PATH, "#PATH SWAP: PATH HAS BEEN SWAPPED.");
+	show_message(ses, LIST_COMMAND, "#PATH SWAP: PATH HAS BEEN SWAPPED.");
 }
 }
 
 
 
 
@@ -592,14 +601,8 @@ DO_PATH(path_zip)
 		}
 		}
 		else
 		else
 		{
 		{
-			if (cnt > 1)
-			{
-				cat_sprintf(arg1, "%d%s", cnt, root->list[i]->arg1);
-			}
-			else
-			{
-				cat_sprintf(arg1, "%s", root->list[i]->arg1);
-			}
+			cat_sprintf(arg1, "%d%s", cnt, root->list[i]->arg1);
+
 			cnt = 1;
 			cnt = 1;
 		}
 		}
 	}
 	}
@@ -627,14 +630,7 @@ DO_PATH(path_zip)
 		}
 		}
 		else
 		else
 		{
 		{
-			if (cnt > 1)
-			{
-				cat_sprintf(arg2, "%d%s", cnt, root->list[i]->arg2);
-			}
-			else
-			{
-				cat_sprintf(arg2, "%s", root->list[i]->arg2);
-			}
+			cat_sprintf(arg2, "%d%s", cnt, root->list[i]->arg2);
 			cnt = 1;
 			cnt = 1;
 		}
 		}
 	}
 	}
@@ -645,7 +641,7 @@ DO_PATH(path_zip)
 
 
 	insert_node_list(root, arg1, arg2, "0", "");
 	insert_node_list(root, arg1, arg2, "0", "");
 
 
-	show_message(ses, LIST_PATH, "#PATH ZIP: THE PATH HAS BEEN ZIPPED TO {%s} {%s}.", arg1, arg2);
+	show_message(ses, LIST_COMMAND, "#PATH ZIP: THE PATH HAS BEEN ZIPPED TO {%s} {%s}.", arg1, arg2);
 }
 }
 
 
 DO_PATH(path_unzip)
 DO_PATH(path_unzip)
@@ -656,7 +652,7 @@ DO_PATH(path_unzip)
 
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 
-	if ((node = search_node_list(ses->list[LIST_VARIABLE], arg1)) == NULL)
+	if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 	{
 	{
 		arg = arg1;
 		arg = arg1;
 	}
 	}
@@ -727,7 +723,7 @@ DO_PATH(path_unzip)
 			}
 			}
 		}
 		}
 	}
 	}
-	show_message(ses, LIST_PATH, "#PATH UNZIP: PATH WITH %d NODES UNZIPPED.", root->used);
+	show_message(ses, LIST_COMMAND, "#PATH UNZIP: PATH WITH %d NODES UNZIPPED.", root->used);
 }
 }
 
 
 
 
@@ -742,25 +738,25 @@ DO_PATH(path_goto)
 	{
 	{
 		root->update = root->used;
 		root->update = root->used;
 
 
-		show_message(ses, LIST_PATH, "#PATH GOTO: POSITION SET TO {%d}.", root->update + 1);
+		show_message(ses, LIST_COMMAND, "#PATH GOTO: POSITION SET TO {%d}.", root->update + 1);
 	}
 	}
 	else if (is_abbrev(arg1, "START"))
 	else if (is_abbrev(arg1, "START"))
 	{
 	{
 		root->update = 0;
 		root->update = 0;
 
 
-		show_message(ses, LIST_PATH, "#PATH GOTO: POSITION SET TO %d.", root->update + 1);
+		show_message(ses, LIST_COMMAND, "#PATH GOTO: POSITION SET TO %d.", root->update + 1);
 	}
 	}
 	else if (is_math(ses, arg1))
 	else if (is_math(ses, arg1))
 	{
 	{
 		if (get_number(ses, arg1) < 1 || get_number(ses, arg1) > root->used + 1)
 		if (get_number(ses, arg1) < 1 || get_number(ses, arg1) > root->used + 1)
 		{
 		{
-			show_message(ses, LIST_PATH, "#PATH GOTO: POSITION MUST BE BETWEEN 1 AND %d.", root->used + 1);
+			show_message(ses, LIST_COMMAND, "#PATH GOTO: POSITION MUST BE BETWEEN 1 AND %d.", root->used + 1);
 		}
 		}
 		else
 		else
 		{
 		{
 			root->update = get_number(ses, arg1) - 1;
 			root->update = get_number(ses, arg1) - 1;
 
 
-			show_message(ses, LIST_PATH, "#PATH GOTO: POSITION SET TO %d.", root->update + 1);
+			show_message(ses, LIST_COMMAND, "#PATH GOTO: POSITION SET TO %d.", root->update + 1);
 		}
 		}
 	}
 	}
 }
 }
@@ -777,33 +773,33 @@ DO_PATH(path_move)
 	{
 	{
 		if (root->update == 0)
 		if (root->update == 0)
 		{
 		{
-			show_message(ses, LIST_PATH, "#PATH GOTO: ALREADY AT START OF PATH.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH GOTO: ALREADY AT START OF PATH.", root->update);
 		}
 		}
 		else
 		else
 		{
 		{
 			root->update--;
 			root->update--;
 
 
-			show_message(ses, LIST_PATH, "#PATH MOVE: POSITION SET TO %d.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
 		}
 		}
 	}
 	}
 	else if (is_abbrev(arg1, "FORWARD"))
 	else if (is_abbrev(arg1, "FORWARD"))
 	{
 	{
 		if (root->update == root->used)
 		if (root->update == root->used)
 		{
 		{
-			show_message(ses, LIST_PATH, "#PATH MOVE: ALREADY AT END OF PATH.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH MOVE: ALREADY AT END OF PATH.", root->update);
 		}
 		}
 		else
 		else
 		{
 		{
 			root->update++;
 			root->update++;
 
 
-			show_message(ses, LIST_PATH, "#PATH MOVE: POSITION SET TO %d.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
 		}
 		}
 	}
 	}
 	else if (is_math(ses, arg1))
 	else if (is_math(ses, arg1))
 	{
 	{
 		root->update = URANGE(0, root->update + get_number(ses, arg1), root->used);
 		root->update = URANGE(0, root->update + get_number(ses, arg1), root->used);
 
 
-		show_message(ses, LIST_PATH, "#PATH MOVE: POSITION SET TO %d.", root->update + 1);
+		show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update + 1);
 	}
 	}
 }
 }
 
 
@@ -813,28 +809,28 @@ DO_PATH(path_undo)
 
 
 	if (root->used == 0)
 	if (root->used == 0)
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH UNDO: ERROR: PATH IS EMPTY.");
+		show_message(ses, LIST_COMMAND, "#PATH UNDO: ERROR: PATH IS EMPTY.");
 
 
 		return;
 		return;
 	}
 	}
 
 
 	if (root->update != root->used)
 	if (root->update != root->used)
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH UNDO: ERROR: YOUR POSITION IS NOT AT END OF PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH UNDO: ERROR: YOUR POSITION IS NOT AT END OF PATH.");
 	
 	
 		return;
 		return;
 	}
 	}
 
 
 	if (!HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (!HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH UNDO: ERROR: YOU ARE NOT CURRENTLY MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH UNDO: ERROR: YOU ARE NOT CURRENTLY MAPPING A PATH.");
 
 
 		return;
 		return;
 	}
 	}
 
 
 	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
 
-	script_driver(ses, LIST_PATH, root->list[root->used - 1]->arg2);
+	script_driver(ses, LIST_COMMAND, root->list[root->used - 1]->arg2);
 
 
 	SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
 
@@ -843,7 +839,7 @@ DO_PATH(path_undo)
 	root->update = root->used;
 	root->update = root->used;
 
 
 
 
-	show_message(ses, LIST_PATH, "#PATH MOVE: POSITION SET TO %d.", root->update);
+	show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
 }
 }
 
 
 void check_append_path(struct session *ses, char *forward, char *backward, int follow)
 void check_append_path(struct session *ses, char *forward, char *backward, int follow)
@@ -933,11 +929,11 @@ DO_COMMAND(do_unpathdir)
 	{
 	{
 		if (delete_nest_node(ses->list[LIST_PATHDIR], arg1))
 		if (delete_nest_node(ses->list[LIST_PATHDIR], arg1))
 		{
 		{
-			show_message(ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A PATHDIR.", arg1);
+			show_message(ses, LIST_PATHDIR, "#OK. {%s} IS NO LONGER A PATHDIR.", arg1);
 		}
 		}
 		else
 		else
 		{
 		{
-			delete_node_with_wild(ses, LIST_VARIABLE, arg1);
+			delete_node_with_wild(ses, LIST_PATHDIR, arg1);
 		}
 		}
 		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	}
 	}
@@ -954,7 +950,7 @@ DO_PATH(path_new)
 
 
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH NEW: YOU ARE ALREADY MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH NEW: YOU ARE ALREADY MAPPING A PATH.");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -962,7 +958,7 @@ DO_PATH(path_new)
 
 
 		root->update = 0;
 		root->update = 0;
 
 
-		show_message(ses, LIST_PATH, "#PATH NEW: YOU ARE NOW MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH NEW: YOU ARE NOW MAPPING A PATH.");
 
 
 		SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 		SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	}
 	}
@@ -972,13 +968,13 @@ DO_PATH(path_end)
 {
 {
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH END: YOU ARE NO LONGER MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH END: YOU ARE NO LONGER MAPPING A PATH.");
 
 
 		DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 		DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_message(ses, LIST_PATH, "#PATH: YOU ARE NOT MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#PATH: YOU ARE NOT MAPPING A PATH.");
 	}
 	}
 }
 }
 	
 	

+ 3 - 4
src/port.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2017                        *
+*                      coded by Igor van den Hoven 2017                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"

+ 252 - 33
src/regex.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -87,15 +86,14 @@ DO_COMMAND(do_regexp)
 	return ses;
 	return ses;
 }
 }
 
 
-int regexp_compare(pcre *nodepcre, char *str, char *exp, int option, int flag)
+int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, int option, int flag)
 {
 {
 	pcre *regex;
 	pcre *regex;
-	const char *error;
 	int i, j, matches, match[303];
 	int i, j, matches, match[303];
 
 
 	if (nodepcre == NULL)
 	if (nodepcre == NULL)
 	{
 	{
-		regex = pcre_compile(exp, option, &error, &i, NULL);
+		regex = regexp_compile(ses, exp, option);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -163,11 +161,16 @@ int regexp_compare(pcre *nodepcre, char *str, char *exp, int option, int flag)
 	return TRUE;
 	return TRUE;
 }
 }
 
 
-pcre *regexp_compile(char *exp, int option)
+pcre *regexp_compile(struct session *ses, char *exp, int option)
 {
 {
 	const char *error;
 	const char *error;
 	int i;
 	int i;
-
+/*
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
+	{
+		option |= PCRE_UTF8|PCRE_NO_UTF8_CHECK;
+	}
+*/
 	return pcre_compile(exp, option, &error, &i, NULL);
 	return pcre_compile(exp, option, &error, &i, NULL);
 }
 }
 
 
@@ -213,6 +216,103 @@ int check_one_regexp(struct session *ses, struct listnode *node, char *line, cha
 	Keep synched with tintin_regexp and tintin_regexp_compile
 	Keep synched with tintin_regexp and tintin_regexp_compile
 */
 */
 
 
+int get_regex_range(char *in, char *out, int *var, int *arg)
+{
+	char *pti, *pto, *ptr, range[BUFFER_SIZE];
+
+	pto = out;
+	pti = in;
+	ptr = range;
+
+	while (*pti)
+	{
+		switch (*pti)
+		{
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				*ptr++ = *pti++;
+				continue;
+
+			case '.':
+				if (pti[1] != '.')
+				{
+					goto end;
+				}
+				if (ptr == range)
+				{
+					*ptr++ = '0';
+				}
+				*ptr++ = ',';
+				pti += 2;
+				continue;
+
+			case 'a':
+				pto += sprintf(pto, "(.");
+				break;
+			case 'A':
+				pto += sprintf(pto, "(\\n");
+				break;
+			case 'd':
+				pto += sprintf(pto, "([0-9]");
+				break;
+			case 'D':
+				pto += sprintf(pto, "([^0-9]");
+				break;
+			case 'p':
+				pto += sprintf(pto, "([\\x20-\\xfe]");
+				break;
+			case 'P':
+				pto += sprintf(pto, "([^\\x20-\\xfe]");
+				break;
+			case 's':
+				pto += sprintf(pto, "(\\s");
+				break;
+			case 'S':
+				pto += sprintf(pto, "(\\S");
+				break;
+			case 'u':
+				pto += sprintf(pto, "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})");
+				break;
+			case 'U':
+				pto += sprintf(pto, "([\\x00-\\x7F\\xFF]");
+				break;
+			case 'w':
+				pto += sprintf(pto, "([a-zA-Z]");
+				break;
+			case 'W':
+				pto += sprintf(pto, "([^a-zA-Z]");
+				break;
+
+			default:
+				goto end;
+		}
+		*ptr = 0;
+		pti++;
+
+		pto += sprintf(pto, "{%s}%s", range, *pti ? "?)" : ")");
+
+		return pti - in;
+	}
+	end:
+
+	if (var)
+	{
+		gtd->args[next_arg(*var)] = next_arg(*arg);
+	}
+	strcpy(out, in[2] == 0 ? "(.+)" : "(.+?)");
+
+	return 0;
+}
+
+
 int tintin_regexp_check(struct session *ses, char *exp)
 int tintin_regexp_check(struct session *ses, char *exp)
 {
 {
 	if (*exp == '^')
 	if (*exp == '^')
@@ -223,7 +323,7 @@ int tintin_regexp_check(struct session *ses, char *exp)
 	while (*exp)
 	while (*exp)
 	{
 	{
 
 
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *exp & 128 && exp[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, exp))
 		{
 		{
 			exp += 2;
 			exp += 2;
 			continue;
 			continue;
@@ -255,12 +355,19 @@ int tintin_regexp_check(struct session *ses, char *exp)
 					case '7':
 					case '7':
 					case '8':
 					case '8':
 					case '9':
 					case '9':
+
+					case 'a':
+					case 'A':
 					case 'd':
 					case 'd':
 					case 'D':
 					case 'D':
 					case 'i':
 					case 'i':
 					case 'I':
 					case 'I':
+					case 'p':
+					case 'P':
 					case 's':
 					case 's':
 					case 'S':
 					case 'S':
+					case 'u':
+					case 'U':
 					case 'w':
 					case 'w':
 					case 'W':
 					case 'W':
 					case '?':
 					case '?':
@@ -273,10 +380,16 @@ int tintin_regexp_check(struct session *ses, char *exp)
 					case '!':
 					case '!':
 						switch (exp[2])
 						switch (exp[2])
 						{
 						{
+							case 'a':
+							case 'A':
 							case 'd':
 							case 'd':
 							case 'D':
 							case 'D':
+							case 'p':
+							case 'P':
 							case 's':
 							case 's':
 							case 'S':
 							case 'S':
+							case 'u':
+							case 'U':
 							case 'w':
 							case 'w':
 							case 'W':
 							case 'W':
 							case '?':
 							case '?':
@@ -294,7 +407,7 @@ int tintin_regexp_check(struct session *ses, char *exp)
 	}
 	}
 	return FALSE;
 	return FALSE;
 }
 }
-				
+
 int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int option, int flag)
 int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int option, int flag)
 {
 {
 	char out[BUFFER_SIZE], *pti, *pto;
 	char out[BUFFER_SIZE], *pti, *pto;
@@ -310,7 +423,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 
 
@@ -403,6 +516,20 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
+					case 'a':
+						gtd->args[next_arg(var)] = next_arg(arg);
+						pti += 2;
+						strcpy(pto, *pti == 0 ? "([^\\n]*)" : "([^\\n]*?)");
+						pto += strlen(pto);
+						break;
+
+					case 'A':
+						gtd->args[next_arg(var)] = next_arg(arg);
+						pti += 2;
+						strcpy(pto, *pti == 0 ? "(\\n*)" : "(\\n*?)");
+						pto += strlen(pto);
+						break;
+
 					case 'd':
 					case 'd':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
 						pti += 2;
@@ -429,6 +556,18 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
+					case 'p':
+						gtd->args[next_arg(var)] = next_arg(arg);
+						pti += 2;
+						pto += sprintf(pto, "%s", *pti == 0 ? "([\\x20-\\xfe]*)" : "([\\x20-\\xfe]*?)");
+						break;
+
+					case 'P':
+						gtd->args[next_arg(var)] = next_arg(arg);
+						pti += 2;
+						pto += sprintf(pto, "%s", *pti == 0 ? "([^\\x20-\\xfe]*)" : "([^\\x20-\\xfe]*?)");
+						break;
+
 					case 's':
 					case 's':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
 						pti += 2;
@@ -443,24 +582,31 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
-					case 'w':
+					case 'u':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "([a-zA-Z]*)" : "([a-zA-Z]*?)");
+						strcpy(pto, *pti == 0 ? "((?:[\\x00-\\x7F|\\xC0-\\xFE][\\x80-\\xC0]{1,3})*)" : "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?)");
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
-					case 'W':
+					case 'U':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "([^a-zA-Z]*)" : "([^a-zA-Z]*?)");
+						strcpy(pto, *pti == 0 ? "(^[\xFF]*)" : "([\\x00-\\x7F\\xFF]*?)");
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
-					case '?':
+					case 'w':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "(.?)" : "(.?" "?)");
+						strcpy(pto, *pti == 0 ? "([a-zA-Z]*)" : "([a-zA-Z]*?)");
+						pto += strlen(pto);
+						break;
+
+					case 'W':
+						gtd->args[next_arg(var)] = next_arg(arg);
+						pti += 2;
+						strcpy(pto, *pti == 0 ? "([^a-zA-Z]*)" : "([^a-zA-Z]*?)");
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
@@ -472,12 +618,15 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 						break;
 						break;
 
 
 					case '+':
 					case '+':
-						gtd->args[next_arg(var)] = next_arg(arg);
-						pti += 2;
-						strcpy(pto, *pti == 0 ? "(.+)" : "(.+?)");
+						pti += 2 + get_regex_range(&pti[2], pto, &var, &arg);
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
+					case '%':
+						*pto++ = *pti++;
+						pti++;
+						break;
+
 					case '.':
 					case '.':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
 						pti += 2;
@@ -485,14 +634,30 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
-					case '%':
-						*pto++ = *pti++;
-						pti++;
+					case '?':
+						gtd->args[next_arg(var)] = next_arg(arg);
+						pti += 2;
+						strcpy(pto, *pti == 0 ? "(.?)" : "(.?" "?)");
+						pto += strlen(pto);
 						break;
 						break;
 
 
 					case '!':
 					case '!':
 						switch (pti[2])
 						switch (pti[2])
 						{
 						{
+							case 'a':
+								gtd->args[next_arg(var)] = next_arg(arg);
+								pti += 2;
+								strcpy(pto, *pti == 0 ? "[^\\n]*" : "[^\\n]*?");
+								pto += strlen(pto);
+								break;
+
+							case 'A':
+								gtd->args[next_arg(var)] = next_arg(arg);
+								pti += 2;
+								strcpy(pto, *pti == 0 ? "\\n*" : "\\n*?");
+								pto += strlen(pto);
+								break;
+
 							case 'd':
 							case 'd':
 								pti += 3;
 								pti += 3;
 								strcpy(pto, *pti == 0 ? "[0-9]*" : "[0-9]*?");
 								strcpy(pto, *pti == 0 ? "[0-9]*" : "[0-9]*?");
@@ -505,6 +670,16 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 									pto += strlen(pto);
 									pto += strlen(pto);
 								break;
 								break;
 
 
+							case 'p':
+								pti += 3;
+								pto += sprintf(pto, "%s", *pti == 0 ? "[\\x20-\\xfe]*" : "[\\x20-\\xfe]*?");
+								break;
+
+							case 'P':
+								pti += 3;
+								pto += sprintf(pto, "%s", *pti == 0 ? "[^\\x20-\\xfe]*" : "[^\\x20-\\xfe]*?");
+								break;
+
 							case 's':
 							case 's':
 								pti += 3;
 								pti += 3;
 								strcpy(pto, *pti == 0 ? "\\s*" : "\\s*?");
 								strcpy(pto, *pti == 0 ? "\\s*" : "\\s*?");
@@ -517,6 +692,20 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 								pto += strlen(pto);
 								pto += strlen(pto);
 								break;
 								break;
 
 
+							case 'u':
+								gtd->args[next_arg(var)] = next_arg(arg);
+								pti += 3;
+								strcpy(pto, *pti == 0 ? "(?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*" : "(?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?");
+								pto += strlen(pto);
+								break;
+
+							case 'U':
+								gtd->args[next_arg(var)] = next_arg(arg);
+								pti += 3;
+								strcpy(pto, *pti == 0 ? "[\\x00-\\x7F\\xFF]*" : "[\\x00-\\x7F\\xFF]*?");
+								pto += strlen(pto);
+								break;
+
 							case 'w':
 							case 'w':
 								pti += 3;
 								pti += 3;
 								strcpy(pto, *pti == 0 ? "[a-zA-Z]*" : "[a-zA-Z]*?");
 								strcpy(pto, *pti == 0 ? "[a-zA-Z]*" : "[a-zA-Z]*?");
@@ -542,8 +731,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 								break;
 								break;
 
 
 							case '+':
 							case '+':
-								pti += 3;
-								strcpy(pto, *pti == 0 ? ".+" : ".+?");
+								pti += 3 + get_regex_range(&pti[3], pto, NULL, NULL);
 								pto += strlen(pto);
 								pto += strlen(pto);
 								break;
 								break;
 
 
@@ -577,7 +765,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 	}
 	}
 	*pto = 0;
 	*pto = 0;
 
 
-	return regexp_compare(nodepcre, str, out, option, flag + fix);
+	return regexp_compare(ses, nodepcre, str, out, option, flag + fix);
 }
 }
 
 
 pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *exp, int option)
 pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *exp, int option)
@@ -599,7 +787,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 
 
@@ -623,6 +811,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			continue;
 			continue;
 		}
 		}
+
 		switch (pti[0])
 		switch (pti[0])
 		{
 		{
 			case '\\':
 			case '\\':
@@ -740,6 +929,16 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
+					case 'p':
+						pti += 2;
+						pto += sprintf(pto, "%s", *pti == 0 ? "([\\x20-\\xfe]*)" : "([\\x20-\\xfe]*?)");
+						break;
+
+					case 'P':
+						pti += 2;
+						pto += sprintf(pto, "%s", *pti == 0 ? "([^\\x20-\\xfe]*)" : "([^\\x20-\\xfe]*?)");
+						break;
+						
 					case 's':
 					case 's':
 						pti += 2;
 						pti += 2;
 						strcpy(pto, *pti == 0 ? "(\\s*)" : "(\\s*?)");
 						strcpy(pto, *pti == 0 ? "(\\s*)" : "(\\s*?)");
@@ -752,6 +951,18 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
+					case 'u':
+						pti += 2;
+						strcpy(pto, *pti == 0 ? "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*)" : "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?)");
+						pto += strlen(pto);
+						break;
+
+					case 'U':
+						pti += 2;
+						strcpy(pto, *pti == 0 ? "([\\x00-\\x7F\\xFF]*)" : "([\\x00-\\x7F\\xFF]*?)");
+						pto += strlen(pto);
+						break;
+
 					case 'w':
 					case 'w':
 						pti += 2;
 						pti += 2;
 						strcpy(pto, *pti == 0 ? "([a-zA-Z]*)" : "([a-zA-Z]*?)");
 						strcpy(pto, *pti == 0 ? "([a-zA-Z]*)" : "([a-zA-Z]*?)");
@@ -777,8 +988,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 						break;
 						break;
 
 
 					case '+':
 					case '+':
-						pti += 2;
-						strcpy(pto, *pti == 0 ? "(.+)" : "(.+?)");
+						pti += 2 + get_regex_range(&pti[2], pto, NULL, NULL);
 						pto += strlen(pto);
 						pto += strlen(pto);
 						break;
 						break;
 
 
@@ -805,7 +1015,17 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 							case 'D':
 							case 'D':
 								pti += 3;
 								pti += 3;
 								strcpy(pto, *pti == 0 ? "[^0-9]*" : "[^0-9]*?");
 								strcpy(pto, *pti == 0 ? "[^0-9]*" : "[^0-9]*?");
-									pto += strlen(pto);
+								pto += strlen(pto);
+								break;
+
+							case 'p':
+								pti += 3;
+								pto += sprintf(pto, "%s", *pti == 0 ? "[\\x21-\\x7E]*" : "[\\x21-\\x7E]?*");
+								break;
+
+							case 'P':
+								pti += 3;
+								pto += sprintf(pto, "%s", *pti == 0 ? "[^\\x20-\\xfe]*" : "[^\\x20-\\xfe]*?");
 								break;
 								break;
 
 
 							case 's':
 							case 's':
@@ -845,8 +1065,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 								break;
 								break;
 
 
 							case '+':
 							case '+':
-								pti += 3;
-								strcpy(pto, *pti == 0 ? ".+" : ".+?");
+								pti += 3 + get_regex_range(&pti[3], pto, NULL, NULL);
 								pto += strlen(pto);
 								pto += strlen(pto);
 								break;
 								break;
 
 
@@ -891,7 +1110,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 	}
 	}
 	*pto = 0;
 	*pto = 0;
 
 
-	return regexp_compile(out, option);
+	return regexp_compile(ses, out, option);
 }
 }
 
 
 void tintin_macro_compile(char *input, char *output)
 void tintin_macro_compile(char *input, char *output)

+ 4 - 12
src/scan.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2005                        *
+*                      coded by Igor van den Hoven 2005                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -52,7 +51,7 @@ char *get_arg_in_quotes(struct session *ses, char *string, char *result, int fla
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -230,13 +229,6 @@ char *get_arg_stop_tabs(struct session *ses, char *string, char *result, int fla
 
 
 	while (*pti)
 	while (*pti)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
-		{
-			*pto++ = *pti++;
-			*pto++ = *pti++;
-			continue;
-		}
-
 		if (*pti == '\t')
 		if (*pti == '\t')
 		{
 		{
 			pti++;
 			pti++;

+ 84 - 41
src/screen.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*              (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                   *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2019                        *
+*                      coded by Igor van den Hoven 2019                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -101,10 +100,12 @@ DO_SCREEN(screen_cursor)
 {
 {
 	if (is_abbrev(arg1, "HIDE"))
 	if (is_abbrev(arg1, "HIDE"))
 	{
 	{
+		SET_BIT(gtd->flags, TINTIN_FLAG_HIDDENCURSOR);
 		screen_csi("?", "25", "", "", "l");
 		screen_csi("?", "25", "", "", "l");
 	}
 	}
 	else if (is_abbrev(arg1, "SHOW"))
 	else if (is_abbrev(arg1, "SHOW"))
 	{
 	{
+		DEL_BIT(gtd->flags, TINTIN_FLAG_HIDDENCURSOR);
 		screen_csi("?", "25", "", "", "h");
 		screen_csi("?", "25", "", "", "h");
 	}
 	}
 	else if (is_abbrev(arg1, "BAR"))
 	else if (is_abbrev(arg1, "BAR"))
@@ -202,13 +203,16 @@ DO_SCREEN(screen_clear)
 
 
 DO_SCREEN(screen_fill)
 DO_SCREEN(screen_fill)
 {
 {
+	char buf[BUFFER_SIZE];
+
 	if (is_abbrev(arg1, "DEFAULT"))
 	if (is_abbrev(arg1, "DEFAULT"))
 	{
 	{
-		char buf[BUFFER_SIZE];
-
-		sprintf(buf, "CLEAR ALL");
+		if (ses->split->sav_top_col || ses->split->sav_bot_col)
+		{
+			sprintf(buf, "CLEAR SPLIT");
 
 
-		do_screen(ses, buf);
+			do_screen(ses, buf);
+		}
 
 
 		if (ses->split->sav_top_row > 0)
 		if (ses->split->sav_top_row > 0)
 		{
 		{
@@ -328,83 +332,83 @@ DO_SCREEN(screen_get)
 
 
 	if (is_abbrev(arg1, "FOCUS"))
 	if (is_abbrev(arg1, "FOCUS"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->focus);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->focus);
 	}
 	}
 	else if (is_abbrev(arg1, "CHAR_HEIGHT"))
 	else if (is_abbrev(arg1, "CHAR_HEIGHT"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->char_height);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->char_height);
 	}
 	}
 	else if (is_abbrev(arg1, "CHAR_WIDTH"))
 	else if (is_abbrev(arg1, "CHAR_WIDTH"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->char_width);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->char_width);
 	}
 	}
 	else if (is_abbrev(arg1, "COLS"))
 	else if (is_abbrev(arg1, "COLS"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->cols);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->cols);
 	}
 	}
 	else if (is_abbrev(arg1, "CUR_COL"))
 	else if (is_abbrev(arg1, "CUR_COL"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->cur_col);
+		set_nest_node_ses(ses, arg2, "%d", ses->cur_col);
 	}
 	}
 	else if (is_abbrev(arg1, "CUR_ROW"))
 	else if (is_abbrev(arg1, "CUR_ROW"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->cur_row);
+		set_nest_node_ses(ses, arg2, "%d", ses->cur_row);
 	}
 	}
 	else if (is_abbrev(arg1, "HEIGHT"))
 	else if (is_abbrev(arg1, "HEIGHT"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->height);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->height);
 	}
 	}
 	else if (is_abbrev(arg1, "WIDTH"))
 	else if (is_abbrev(arg1, "WIDTH"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->width);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->width);
 	}
 	}
 
 
 	else if (is_abbrev(arg1, "ROWS"))
 	else if (is_abbrev(arg1, "ROWS"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", gtd->screen->rows);
+		set_nest_node_ses(ses, arg2, "%d", gtd->screen->rows);
 	}
 	}
 
 
 	else if (is_abbrev(arg1, "SPLIT_TOP_BAR"))
 	else if (is_abbrev(arg1, "SPLIT_TOP_BAR"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->sav_top_row);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->sav_top_row);
 	}
 	}
 	else if (is_abbrev(arg1, "SPLIT_LEFT_BAR"))
 	else if (is_abbrev(arg1, "SPLIT_LEFT_BAR"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->sav_top_col);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->sav_top_col);
 	}
 	}
 	else if (is_abbrev(arg1, "SPLIT_BOT_BAR"))
 	else if (is_abbrev(arg1, "SPLIT_BOT_BAR"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->sav_bot_row);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->sav_bot_row);
 	}
 	}
 	else if (is_abbrev(arg1, "SPLIT_RIGHT_BAR"))
 	else if (is_abbrev(arg1, "SPLIT_RIGHT_BAR"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->sav_bot_col);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->sav_bot_col);
 	}
 	}
 
 
 	else if (is_abbrev(arg1, "SCROLL_ROWS"))
 	else if (is_abbrev(arg1, "SCROLL_ROWS"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->bot_row - ses->split->top_row);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->bot_row - ses->split->top_row);
 	}
 	}
 	else if (is_abbrev(arg1, "SCROLL_COLS"))
 	else if (is_abbrev(arg1, "SCROLL_COLS"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->wrap);
+		set_nest_node_ses(ses, arg2, "%d", ses->wrap);
 	}
 	}
 
 
 	else if (is_abbrev(arg1, "SCROLL_TOP_ROW"))
 	else if (is_abbrev(arg1, "SCROLL_TOP_ROW"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->top_row);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->top_row);
 	}
 	}
 	else if (is_abbrev(arg1, "SCROLL_TOP_COL"))
 	else if (is_abbrev(arg1, "SCROLL_TOP_COL"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->top_col);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->top_col);
 	}
 	}
 	else if (is_abbrev(arg1, "SCROLL_BOT_ROW"))
 	else if (is_abbrev(arg1, "SCROLL_BOT_ROW"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->bot_row);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->bot_row);
 	}
 	}
 	else if (is_abbrev(arg1, "SCROLL_BOT_COL"))
 	else if (is_abbrev(arg1, "SCROLL_BOT_COL"))
 	{
 	{
-		set_nest_node(ses->list[LIST_VARIABLE], arg2, "%d", ses->split->bot_col);
+		set_nest_node_ses(ses, arg2, "%d", ses->split->bot_col);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -723,7 +727,8 @@ DO_SCREEN(screen_raise)
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN DESKTOP DIMENSIONS}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN DESKTOP DIMENSIONS}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN DIMENSIONS}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN DIMENSIONS}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN MINIMIZED}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN MINIMIZED}");
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN POSITION}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN MOUSE LOCATION}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN LOCATION}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN RESIZE}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN RESIZE}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN SIZE}");
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RAISE} {SCREEN SIZE}");
 
 
@@ -747,7 +752,11 @@ DO_SCREEN(screen_raise)
 	{
 	{
 		screen_csit(ses, "11", "", "");
 		screen_csit(ses, "11", "", "");
 	}
 	}
-	else if (is_abbrev(arg1, "POSITION"))
+	else if (is_abbrev(arg1, "MOUSE LOCATION"))
+	{
+		print_stdout("%s", "\e[2;1'z\e['|");
+	}
+	else if (is_abbrev(arg1, "LOCATION") || is_abbrev(arg1, "POSITION"))
 	{
 	{
 		screen_csit(ses, "13", "", "");
 		screen_csit(ses, "13", "", "");
 	}
 	}
@@ -823,7 +832,6 @@ int get_col_index(struct session *ses, char *arg)
 
 
 
 
 
 
-	
 void csit_handler(int ind, int var1, int var2)
 void csit_handler(int ind, int var1, int var2)
 {
 {
 //	tintin_printf2(gtd->ses, "csit_handler(%d,%d,%d)",ind,var1,var2);
 //	tintin_printf2(gtd->ses, "csit_handler(%d,%d,%d)",ind,var1,var2);
@@ -843,11 +851,11 @@ void csit_handler(int ind, int var1, int var2)
 			break;
 			break;
 
 
 		case 3:
 		case 3:
-			gtd->screen->pos_height = var2;
-			gtd->screen->pos_width  = var1;
-			check_all_events(NULL, SUB_ARG, 0, 2, "SCREEN POSITION", ntos(var2), ntos(var1)); // swap x y
-			msdp_update_all("SCREEN_POSITION_HEIGHT", "%d", gtd->screen->pos_height);
-			msdp_update_all("SCREEN_POSITION_WIDTH", "%d", gtd->screen->pos_width);
+			gtd->screen->pos_height = UMAX(0, var2);
+			gtd->screen->pos_width  = UMAX(0, var1);
+			check_all_events(NULL, SUB_ARG, 0, 4, "SCREEN LOCATION", ntos(var2 / gtd->screen->char_height), ntos(var1 / gtd->screen->char_width), ntos(var2), ntos(var1)); // swap x y
+			msdp_update_all("SCREEN_LOCATION_HEIGHT", "%d", gtd->screen->pos_height);
+			msdp_update_all("SCREEN_LOCATION_WIDTH", "%d", gtd->screen->pos_width);
 			break;
 			break;
 
 
 		case 4:
 		case 4:
@@ -893,6 +901,41 @@ void csit_handler(int ind, int var1, int var2)
 	}
 	}
 }
 }
 
 
+void rqlp_handler(int event, int button, int height, int width)
+{
+	int row, col, rev_row, rev_col, char_height, char_width, rev_char_height, rev_char_width, debug, info, grid_val;
+	char *grid[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9"};
+
+	row = 1 + height / UMAX(1, gtd->screen->char_height);
+	col = 1 + width / UMAX(1, gtd->screen->char_width);
+
+	char_height = 1 + height % UMAX(1, gtd->screen->char_height);
+	char_width  = 1 + width % UMAX(1, gtd->screen->char_width);
+
+	rev_row = -1 - (gtd->screen->rows - row);
+	rev_col = -1 - (gtd->screen->cols - col);
+
+	rev_char_height = -1 - (gtd->screen->char_height - char_height);
+	rev_char_width  = -1 - (gtd->screen->char_width - char_width);
+
+	grid_val = URANGE(0, char_height * 3 / gtd->screen->char_height, 2) * 3 + URANGE(0, char_width * 3 / gtd->screen->char_width, 2);
+
+	debug = HAS_BIT(gtd->ses->flags, SES_FLAG_MOUSEDEBUG) ? 1 : 0;
+	info  = HAS_BIT(gtd->ses->flags, SES_FLAG_MOUSEINFO) ? 1 : 0;
+
+	gtd->level->debug += debug;
+	gtd->level->info  += info;
+
+	check_all_events(gtd->ses, SUB_ARG, 0, 9, "SCREEN MOUSE LOCATION", ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), ntos(char_height), ntos(char_width), ntos(rev_char_height), ntos(rev_char_width), grid[grid_val]);
+
+	map_mouse_handler(gtd->ses, NULL, NULL, col, row, char_height, char_width);
+
+	gtd->level->debug -= debug;
+	gtd->level->info  -= info;
+
+//	tintin_printf2(gtd->ses, "rqlp_handler(%d,%d,%d,%d) (%d,%d,%d,%d) (%d,%d,%d,%d)", event,button,height,width, row,col,rev_row,rev_col, char_height,char_width,rev_char_height,rev_char_width);
+}
+
 void screen_osc(char *arg1, char *arg2)
 void screen_osc(char *arg1, char *arg2)
 {
 {
 	print_stdout("\e]%s;%s\a", arg1, arg2);
 	print_stdout("\e]%s;%s\a", arg1, arg2);
@@ -1035,12 +1078,12 @@ void init_screen(int rows, int cols, int height, int width)
 {
 {
 	int cnt;
 	int cnt;
 
 
-	gtd->screen->rows        = rows;
-	gtd->screen->cols        = cols;
-	gtd->screen->height      = height;
-	gtd->screen->width       = width;
-	gtd->screen->char_height = gtd->screen->height / gtd->screen->rows;
-	gtd->screen->char_width  = gtd->screen->width / gtd->screen->cols;
+	gtd->screen->rows        = UMAX(1, rows);
+	gtd->screen->cols        = UMAX(1, cols);
+	gtd->screen->height      = UMAX(1, height);
+	gtd->screen->width       = UMAX(1, width);
+	gtd->screen->char_height = UMAX(1, gtd->screen->height / gtd->screen->rows);
+	gtd->screen->char_width  = UMAX(1, gtd->screen->width / gtd->screen->cols);
 
 
 	gtd->screen->focus  = 1;
 	gtd->screen->focus  = 1;
 
 

+ 9 - 9
src/session.c

@@ -414,7 +414,9 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 		}
 		}
 	}
 	}
 
 
-	newses->split  = calloc(1, sizeof(struct split_data));
+	newses->event_flags = gts->event_flags;
+
+	newses->split   = calloc(1, sizeof(struct split_data));
 
 
 	memcpy(newses->split, gts->split, sizeof(struct split_data));
 	memcpy(newses->split, gts->split, sizeof(struct split_data));
 
 
@@ -698,22 +700,19 @@ void dispose_session(struct session *ses)
 		fclose(ses->logline_file);
 		fclose(ses->logline_file);
 	}
 	}
 
 
-	for (index = 0 ; index < LIST_MAX ; index++)
-	{
-		free_list(ses->list[index]);
-	}
-
 	if (ses->map)
 	if (ses->map)
 	{
 	{
 		delete_map(ses);
 		delete_map(ses);
 	}
 	}
 
 
-	if (ses->mccp2)
+	for (index = 0 ; index < LIST_MAX ; index++)
 	{
 	{
-		inflateEnd(ses->mccp2);
-		free(ses->mccp2);
+		free_list(ses->list[index]);
 	}
 	}
 
 
+	client_end_mccp2(ses);
+	client_end_mccp3(ses);
+
 	init_buffer(ses, 0);
 	init_buffer(ses, 0);
 
 
 	free(ses->name);
 	free(ses->name);
@@ -725,6 +724,7 @@ void dispose_session(struct session *ses)
 	free(ses->cmd_color);
 	free(ses->cmd_color);
 	free(ses->lognext_name);
 	free(ses->lognext_name);
 	free(ses->logline_name);
 	free(ses->logline_name);
+	free(ses->split);
 
 
 	free(ses);
 	free(ses);
 
 

+ 19 - 2
src/show.c

@@ -441,7 +441,10 @@ void tintin_puts(struct session *ses, char *string)
 
 
 		gtd->level->ignore++;
 		gtd->level->ignore++;
 
 
-		show_info(ses, LIST_GAG, "#INFO GAG {%s}", string);
+		if (HAS_BIT(ses->list[LIST_GAG]->flags, LIST_FLAG_INFO))
+		{
+			show_info(ses, LIST_GAG, "#INFO GAG {%s}", string);
+		}
 
 
 		gtd->level->ignore--;
 		gtd->level->ignore--;
 	}
 	}
@@ -479,7 +482,7 @@ void tintin_puts2(struct session *ses, char *string)
 
 
 void tintin_puts3(struct session *ses, char *string)
 void tintin_puts3(struct session *ses, char *string)
 {
 {
-	char *output;
+	char *output, temp[STRING_SIZE];
 
 
 	push_call("tintin_puts3(%p,%p)",ses,string);
 	push_call("tintin_puts3(%p,%p)",ses,string);
 
 
@@ -488,6 +491,20 @@ void tintin_puts3(struct session *ses, char *string)
 		ses = gtd->ses;
 		ses = gtd->ses;
 	}
 	}
 
 
+	if (ses->line_capturefile)
+	{
+		sprintf(temp, "{%d}{%s}", ses->line_captureindex++, string);
+
+		if (ses->line_captureindex == 1)
+		{
+			set_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
+		}
+		else
+		{
+			add_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
+		}
+	}
+
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->level->quiet && gtd->level->verbose == 0)
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->level->quiet && gtd->level->verbose == 0)
 	{
 	{
 		pop_call();
 		pop_call();

+ 18 - 17
src/split.c

@@ -107,6 +107,8 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 {
 {
 	push_call("init_split(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);
 	push_call("init_split(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);
 
 
+	SET_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE);
+
 	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	{
 	{
 		ses->split->top_row = 1;
 		ses->split->top_row = 1;
@@ -117,8 +119,6 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 
 
 		init_pos(ses, gtd->screen->rows, 1);
 		init_pos(ses, gtd->screen->rows, 1);
 
 
-		SET_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE);
-
 		if (ses->map && HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
 		if (ses->map && HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
 		{
 		{
 			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
@@ -156,8 +156,6 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 
 
 	init_pos(ses, gtd->screen->rows, 1);
 	init_pos(ses, gtd->screen->rows, 1);
 
 
-	SET_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE);
-
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
 	{
 	{
 		client_send_sb_naws(ses, 0, NULL);
 		client_send_sb_naws(ses, 0, NULL);
@@ -172,16 +170,19 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 	{
 	{
 		if (gtd->level->quiet == 0)
 		if (gtd->level->quiet == 0)
 		{
 		{
-			if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
+//			if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 			{
 			{
 				do_screen(ses, "FILL DEFAULT");
 				do_screen(ses, "FILL DEFAULT");
 			}
 			}
-			else
+/*			else
 			{
 			{
+				fill_split_region(ses, "-");
+
 				erase_scroll_region(ses);
 				erase_scroll_region(ses);
-				buffer_end(ses, "");
 				fill_split_region(ses, "-");
 				fill_split_region(ses, "-");
-			}
+				buffer_end(ses, "");
+
+			}*/
 		}
 		}
 	}
 	}
 	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN SPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
 	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN SPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
@@ -240,7 +241,7 @@ void dirty_screen(struct session *ses)
 
 
 void split_show(struct session *ses, char *prompt, int row, int col)
 void split_show(struct session *ses, char *prompt, int row, int col)
 {
 {
-	char temp[BUFFER_SIZE];
+	char buf1[BUFFER_SIZE];
 	int original_row, original_col, len, clear;
 	int original_row, original_col, len, clear;
 
 
 	original_row = row;
 	original_row = row;
@@ -252,7 +253,7 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 	}
 	}
 	else if (row == 0)
 	else if (row == 0)
 	{
 	{
-		row = gtd->screen->rows - 2;
+		row = gtd->screen->rows - 1;
 	}
 	}
 
 
 	clear = 0;
 	clear = 0;
@@ -281,7 +282,7 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 		return;
 		return;
 	}
 	}
 
 
-	if (row >= ses->split->top_row && row <= ses->split->bot_row)
+	if (row > ses->split->top_row && row <= ses->split->bot_row)
 	{
 	{
 		if (col >= ses->split->top_col && col <= ses->split->bot_col)
 		if (col >= ses->split->top_col && col <= ses->split->bot_col)
 		{
 		{
@@ -299,17 +300,17 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 
 
 	if (len == 0)
 	if (len == 0)
 	{
 	{
-		sprintf(temp, "%.*s", gtd->screen->cols + 4, "\e[0m--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
+		sprintf(buf1, "%.*s", gtd->screen->cols + 4, "\e[0m--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
 	}
 	}
 	else if (col - 1 + len <= gtd->screen->cols)
 	else if (col - 1 + len <= gtd->screen->cols)
 	{
 	{
-		sprintf(temp, "%s", prompt);
+		sprintf(buf1, "%s", prompt);
 	}
 	}
 	else
 	else
 	{
 	{
 		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
 		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
 
 
-		sprintf(temp, "#PROMPT SIZE (%d) LONGER THAN ROW SIZE (%d)", len, gtd->screen->cols);
+		sprintf(buf1, "#PROMPT SIZE (%d) LONGER THAN ROW SIZE (%d)", len, gtd->screen->cols);
 	}
 	}
 
 
 	save_pos(ses);
 	save_pos(ses);
@@ -320,7 +321,7 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 
 
 		goto_pos(ses, row, col);
 		goto_pos(ses, row, col);
 
 
-		print_stdout("%s%s", temp, gtd->input_buf);
+		print_stdout("%s%s", buf1, gtd->input_buf);
 
 
 		// bit of a hack
 		// bit of a hack
 
 
@@ -330,10 +331,10 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 	{
 	{
 		goto_pos(ses, row, col);
 		goto_pos(ses, row, col);
 
 
-		print_stdout("%s%s", clear ? "\e[2K" : "", temp);
+		print_stdout("%s%s", clear ? "\e[2K" : "", buf1);
 	}
 	}
 
 
-//	set_line_screen(temp, row - 1, col - 1);
+//	set_line_screen(buf1, row - 1, col - 1);
 
 
 	restore_pos(ses);
 	restore_pos(ses);
 }
 }

+ 580 - 20
src/substitute.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -134,6 +133,34 @@ char *c256to16_bg[256] =
 	 "\e[1;47m",  "\e[1;47m",  "\e[1;47m",  "\e[1;47m",  "\e[1;47m",  "\e[1;47m"
 	 "\e[1;47m",  "\e[1;47m",  "\e[1;47m",  "\e[1;47m",  "\e[1;47m",  "\e[1;47m"
 };
 };
 
 
+
+// input A to F
+
+int c256_val(char chr)
+{
+	static unsigned char c256_val[256] =
+	{
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   1,   2,    3,   4,   5,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   1,   2,    3,   4,   5,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,
+		  0,   0,   0,   0,    0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0
+	};
+
+	return (int) c256_val[(unsigned char) chr];
+}
+
 // input 00 to FF
 // input 00 to FF
 
 
 int c4096_val(char chr1, char chr2)
 int c4096_val(char chr1, char chr2)
@@ -188,14 +215,19 @@ int c4096_to_256_val(char chr1, char chr2)
 	return (int) c4096_to_256[c4096_val(chr1, chr2)];
 	return (int) c4096_to_256[c4096_val(chr1, chr2)];
 }
 }
 
 
+char int_to_hex[16] =
+{
+	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+char int_to_256[6] =
+{
+	'A', 'B', 'C', 'D', 'E', 'F'
+};
 
 
 void c4096_rnd(struct session *ses, char *str)
 void c4096_rnd(struct session *ses, char *str)
 {
 {
-	static char dec_to_hex[16] =
-	{
-		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-	};
-	sprintf(str, "%c%c%c", dec_to_hex[generate_rand(ses) % 16], dec_to_hex[generate_rand(ses) % 16], dec_to_hex[generate_rand(ses) % 16]);
+	sprintf(str, "%c%c%c", int_to_hex[generate_rand(ses) % 16], int_to_hex[generate_rand(ses) % 16], int_to_hex[generate_rand(ses) % 16]);
 }
 }
 
 
 int is_c32(char chr)
 int is_c32(char chr)
@@ -234,7 +266,6 @@ char *c32_fg_bold[26] =
 	"", "<ff80>", "<ff08>", "", "<ff00>", "<fddd>", "<fdb0>", "", "<f80f>", "<ffff>", "", "<fff0>", ""
 	"", "<ff80>", "<ff08>", "", "<ff00>", "<fddd>", "<fdb0>", "", "<f80f>", "<ffff>", "", "<fff0>", ""
 };
 };
 
 
-
 int is_variable(struct session *ses, char *str)
 int is_variable(struct session *ses, char *str)
 {
 {
 	struct listroot *root;
 	struct listroot *root;
@@ -401,6 +432,486 @@ int is_color_code(char *pti)
 	return 0;
 	return 0;
 }
 }
 
 
+
+char *fuzzy_char(struct session *ses, char val1, char val2, int mode)
+{
+	static char out[10][3];
+	static int cnt;
+	int tmp;
+
+	cnt = (cnt + 1) % 10;
+
+	switch (mode)
+	{
+		case 8:
+			tmp = c256_val(val2) - 1 + generate_rand(ses) % 3;
+
+			tmp = URANGE(0, tmp, 5);
+
+			if (isupper(val2))
+			{
+				sprintf(out[cnt], "%c", toupper(int_to_256[tmp]));
+			}
+			else
+			{
+				sprintf(out[cnt], "%c", tolower(int_to_256[tmp]));
+			}
+			break;
+
+		case 12:
+			tmp = c4096_val(0, val2);
+
+			tmp = tmp - 2 + generate_rand(ses) % 4;
+
+			tmp = URANGE(0, tmp, 15);
+
+			sprintf(out[cnt], "%c", int_to_hex[tmp]);
+			break;
+
+		case 24:
+			tmp = c4096_val(val1, val2);
+
+			tmp = (tmp - 12 + generate_rand(ses) % 24);
+
+			tmp = URANGE(0, tmp, 255);
+
+			sprintf(out[cnt], "%c%c", int_to_hex[tmp / 16], int_to_hex[tmp % 16]);
+			break;
+
+		default:
+			tintin_printf2(ses, "dim_char: invalid mode");
+			break;
+	}
+	return out[cnt];
+}
+
+char *fuzzy_color_code(struct session *ses, char *in)
+{
+	static char *pto, out[10][100];
+	static int cnt;
+	char *pti, buf[100];
+	int tmp;
+
+	if (*in == 0 || strlen(in) > 50)
+	{
+		return "";
+	}
+
+	strcpy(buf, in);
+
+	pti = buf;
+	cnt = (cnt + 1) % 10;
+	pto = out[cnt];
+
+	while (*pti)
+	{
+		if (pti[0] == '<')
+		{
+			if (pti[1] == 0 || pti[2] == 0 || pti[3] == 0 || pti[4] == 0)
+			{
+				return out[cnt];
+			}
+
+			if (pti[4] == '>')
+			{
+				if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+				{
+					pto += sprintf(pto, "<%c%c%c>", pti[1], pti[2], pti[3]);
+				}
+				else if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f')
+				{
+					pto += sprintf(pto, "<%s%s%s>", fuzzy_char(ses, 0, pti[1], 8), fuzzy_char(ses, 0, pti[2], 8), fuzzy_char(ses, 0, pti[3], 8));
+				}
+				else if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F')
+				{
+					pto += sprintf(pto, "<%s%s%s>", fuzzy_char(ses, 0, pti[1], 8), fuzzy_char(ses, 0, pti[2], 8), fuzzy_char(ses, 0, pti[3], 8));
+				}
+				else if ((pti[1] == 'g' || pti[1] == 'G') && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				{
+					tmp = (pti[2] - '0') * 10 + (pti[3] - '0') - 3 + generate_rand(ses) % 7;
+
+					pto += sprintf(pto, "<%c%02d>", pti[1], URANGE(0, tmp, 23));
+				}
+				else
+				{
+					return out[cnt];
+				}
+				pti += 5;
+			}
+			else if (toupper((int) pti[1]) == 'F')
+			{
+				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				{
+					pto += sprintf(pto, "<F%s%s%s>", fuzzy_char(ses, 0, pti[2], 12), fuzzy_char(ses, 0, pti[3], 12), fuzzy_char(ses, 0, pti[4], 12));
+
+					pti += 6;
+				}
+				else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				{
+					c4096_rnd(ses, &pti[2]);
+
+					pto += sprintf(pto, "<F%c%c%c>", pti[2], pti[3], pti[4]);
+
+					pti += 6;
+				}
+				else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				{
+					pto += sprintf(pto, "<F%s%s%s>", fuzzy_char(ses, pti[3], pti[4], 24), fuzzy_char(ses, pti[4], pti[5], 24), fuzzy_char(ses, pti[7], pti[7], 24));
+
+					pti += 9;
+				}
+				else
+				{
+					return out[cnt];
+				}
+			}
+			else if (toupper(pti[1]) == 'B')
+			{
+				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				{
+					pto += sprintf(pto, "<B%s%s%s>", fuzzy_char(ses, 0, pti[2], 12), fuzzy_char(ses, 0, pti[3], 12), fuzzy_char(ses, 0, pti[4], 12));
+
+					pti += 6;
+				}
+				else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				{
+					c4096_rnd(ses, &pti[2]);
+
+					pto += sprintf(pto, "<B%c%c%c>", pti[2], pti[3], pti[4]);
+
+					pti += 6;
+				}
+				else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				{
+					pto += sprintf(pto, "<B%s%s%s>", fuzzy_char(ses, pti[2], pti[3], 24), fuzzy_char(ses, pti[4], pti[5], 24), fuzzy_char(ses, pti[6], pti[7], 24));
+
+					pti += 9;
+				}
+				else
+				{
+					return out[cnt];
+				}
+			}
+			else
+			{
+				return out[cnt];
+			}
+		}
+		else
+		{
+			return out[cnt];
+		}
+	}
+	return out[cnt];
+}
+
+char *dim_char(struct session *ses, char val1, char val2, int mod, int mode)
+{
+	static char out[10][3];
+	static int cnt;
+	int tmp;
+
+	cnt = (cnt + 1) % 10;
+
+	switch (mode)
+	{
+		case 8:
+			tmp = c256_val(val2) - mod;
+
+			tmp = URANGE(0, tmp, 5);
+
+			if (isupper(val2))
+			{
+				sprintf(out[cnt], "%c", toupper(int_to_256[tmp]));
+			}
+			else
+			{
+				sprintf(out[cnt], "%c", tolower(int_to_256[tmp]));
+			}
+			break;
+
+		case 12:
+			tmp = c4096_val(0, val2);
+
+			tmp = tmp - mod - generate_rand(ses) % 3;
+
+			tmp = URANGE(0, tmp, 15);
+
+			sprintf(out[cnt], "%c", int_to_hex[tmp]);
+			break;
+
+		case 24:
+			tmp = c4096_val(val1, val2);
+
+			tmp = tmp - mod - generate_rand(ses) % 2;
+
+			tmp = URANGE(0, tmp, 255);
+
+			sprintf(out[cnt], "%c%c", int_to_hex[tmp / 16], int_to_hex[tmp % 16]);
+			break;
+
+		default:
+			tintin_printf2(ses, "dim_char: invalid mode");
+			break;
+	}
+	return out[cnt];
+}
+
+char *dim_color_code(struct session *ses, char *in, int mod)
+{
+	static char *pto, out[10][60], buf[60];
+	char *pti;
+	static int cnt;
+	int tmp;
+
+	if (*in == 0 || strlen(in) > 40)
+	{
+		return "";
+	}
+
+	strcpy(buf, in);
+
+	pti = buf;
+	cnt = (cnt + 1) % 10;
+	pto = out[cnt];
+
+	if (mod < 0)
+	{
+		strcpy(pto, buf);
+
+		return out[cnt];
+	}
+
+	*pto = 0;
+
+	while (*pti)
+	{
+		if (pti[0] == '<')
+		{
+			if (pti[1] == 0 || pti[2] == 0 || pti[3] == 0 || pti[4] == 0)
+			{
+				return out[cnt];
+			}
+
+			if (pti[4] == '>')
+			{
+				if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+				{
+					pto += sprintf(pto, "<%c%c%c>", pti[1], pti[2], pti[3]);
+				}
+				else if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f')
+				{
+					pto += sprintf(pto, "<%s%s%s>", dim_char(ses, 0, pti[1], mod, 8), dim_char(ses, 0, pti[2], mod, 8), dim_char(ses, 0, pti[3], mod, 8));
+				}
+				else if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F')
+				{
+					pto += sprintf(pto, "<%s%s%s>", dim_char(ses, 0, pti[1], mod, 8), dim_char(ses, 0, pti[2], mod, 8), dim_char(ses, 0, pti[3], mod, 8));
+				}
+				else if ((pti[1] == 'g' || pti[1] == 'G') && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				{
+					tmp = (pti[2] - '0') * 10 + (pti[3] - '0') - mod;
+
+					pto += sprintf(pto, "<%c%02d>", pti[1], URANGE(0, tmp, 23));
+				}
+				else
+				{
+					return out[cnt];
+				}
+				pti += 5;
+			}
+			else if (toupper((int) pti[1]) == 'F')
+			{
+				if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				{
+					c4096_rnd(ses, &pti[2]);
+				}
+
+				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				{
+					pto += sprintf(pto, "<F%s%s%s>", dim_char(ses, 0, pti[2], mod, 12), dim_char(ses, 0, pti[3], mod, 12), dim_char(ses, 0, pti[4], mod, 12));
+
+					pti += 6;
+				}
+				else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				{
+					pto += sprintf(pto, "<F%s%s%s>", dim_char(ses, pti[2], pti[3], mod, 24), dim_char(ses, pti[4], pti[5], mod, 24), dim_char(ses, mod, pti[6], pti[7], 24));
+
+					pti += 9;
+				}
+				else
+				{
+					return out[cnt];
+				}
+			}
+			else if (toupper(pti[1]) == 'B')
+			{
+				if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				{
+					c4096_rnd(ses, &pti[2]);
+				}
+
+				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				{
+					pto += sprintf(pto, "<B%s%s%s>", dim_char(ses, 0, pti[2], mod, 12), dim_char(ses, 0, pti[3], mod, 12), dim_char(ses, 0, pti[4], mod, 12));
+
+					pti += 6;
+				}
+				else if (toupper(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				{
+					pto += sprintf(pto, "<B%s%s%s>", dim_char(ses, pti[2], pti[3], mod, 24), dim_char(ses, pti[4], pti[5], mod, 24), dim_char(ses, pti[6], pti[7], mod, 24));
+
+					pti += 9;
+				}
+				else
+				{
+					return out[cnt];
+				}
+			}
+			else
+			{
+				return out[cnt];
+			}
+		}
+	}
+	return out[cnt];
+
+}
+
+char lit_char(struct session *ses, char max, char val, int mod, int mode)
+{
+	int tmp;
+
+	switch (mode)
+	{
+		case 8:
+			tmp = val + mod;
+
+			return UMIN(max, tmp);
+
+		case 12:
+			tmp = c4096_val(0, val);
+
+			tmp = URANGE(0, tmp + mod, 15);
+
+			return int_to_hex[tmp];
+	}
+	return val;
+}
+
+char *lit_color_code(struct session *ses, char *pti, int mod)
+{
+	static char fuzzy[10][20];
+	static int cnt;
+	int tmp;
+
+	cnt = (cnt + 1) % 10;
+
+	if (pti[0] == '<')
+	{
+		if (pti[1] == 0 || pti[2] == 0 || pti[3] == 0 || pti[4] == 0)
+		{
+			return "";
+		}
+
+		if (pti[4] == '>')
+		{
+			if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+			{
+				sprintf(fuzzy[cnt], "<%c%c%c>%.9s", pti[1], pti[2], pti[3], &pti[5]);
+
+				return fuzzy[cnt];
+			}
+
+			if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f')
+			{
+				sprintf(fuzzy[cnt], "<%c%c%c>%.9s", lit_char(ses, 'f', pti[1], mod, 8), lit_char(ses, 'f', pti[2], mod, 8), lit_char(ses, 'f', pti[3], mod, 8), &pti[5]);
+
+				return fuzzy[cnt];
+			}
+
+			if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F')
+			{
+				sprintf(fuzzy[cnt], "<%c%c%c>%.9s", lit_char(ses, 'F', pti[1], mod, 8), lit_char(ses, 'F', pti[2], mod, 8), lit_char(ses, 'F', pti[3], mod, 8), &pti[5]);
+
+				return fuzzy[cnt];
+			}
+		}
+
+		{
+			if (pti[1] == 'g' || pti[1] == 'G')
+			{
+				if (isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				{
+					tmp = (pti[2] - '0') * 10 + (pti[3] - '0');
+
+					tmp -= mod;
+
+					sprintf(fuzzy[cnt], "<%c%02d>%.9s", pti[1], URANGE(0, tmp, 23), &pti[5]);
+
+					return fuzzy[cnt];
+				}
+				return "";
+			}
+		}
+
+		if (pti[5] == 0)
+		{
+			return "";
+		}
+
+		if (toupper((int) pti[1]) == 'F')
+		{
+			if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+			{
+				sprintf(fuzzy[cnt], "<F%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[3], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), &pti[6]);
+
+				return fuzzy[cnt];
+			}
+			else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			{
+				sprintf(fuzzy[cnt], "<F??%c>%.9s", '?', &pti[6]);
+
+				c4096_rnd(ses, &fuzzy[cnt][2]);
+
+				return dim_color_code(ses, fuzzy[cnt], mod);
+			}
+			else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+			{
+				sprintf(fuzzy[cnt], "<F%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), lit_char(ses, mod, pti[6], 'F', 12), &pti[9]);
+
+				return fuzzy[cnt];
+			}
+			return "";
+		}
+
+		if (toupper(pti[1]) == 'B')
+		{
+			if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+			{
+				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[3], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), &pti[6]);
+
+				return fuzzy[cnt];
+			}
+			if (toupper(pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			{
+				sprintf(fuzzy[cnt], "<B??%c>%.9s", '?', &pti[6]);
+
+				c4096_rnd(ses, &fuzzy[cnt][2]);
+
+				return dim_color_code(ses, fuzzy[cnt], mod);
+			}
+			if (toupper(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+			{
+				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), lit_char(ses, mod, pti[6], 'F', 12), &pti[9]);
+
+				return fuzzy[cnt];
+			}
+			return "";
+		}
+	}
+	return "";
+}
+
 int substitute(struct session *ses, char *string, char *result, int flags)
 int substitute(struct session *ses, char *string, char *result, int flags)
 {
 {
 	struct listnode *node;
 	struct listnode *node;
@@ -408,7 +919,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 	struct session *sesptr;
 	struct session *sesptr;
 	char temp[BUFFER_SIZE], buf[BUFFER_SIZE], buffer[BUFFER_SIZE], *pti, *pto, *ptt, *str;
 	char temp[BUFFER_SIZE], buf[BUFFER_SIZE], buffer[BUFFER_SIZE], *pti, *pto, *ptt, *str;
 	char *pte, old[10] = { 0 };
 	char *pte, old[10] = { 0 };
-	int i, cnt, escape = FALSE, flags_neol = flags;
+	int i, skip, cnt, escape = FALSE, flags_neol = flags;
 
 
 	push_call("substitute(%p,%p,%p,%d)",ses,string,result,flags);
 	push_call("substitute(%p,%p,%p,%d)",ses,string,result,flags);
 
 
@@ -419,7 +930,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 
 	while (TRUE)
 	while (TRUE)
 	{
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
 			*pto++ = *pti++;
@@ -526,7 +1037,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						substitute(sesptr, temp, pto, flags_neol);
 						substitute(sesptr, temp, pto, flags_neol);
 
 
 						pto += strlen(pto);
 						pto += strlen(pto);
-						
+
 						continue;
 						continue;
 					}
 					}
 					else
 					else
@@ -662,7 +1173,14 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						continue;
 						continue;
 					}
 					}
 
 
-					pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+					if (brace == FALSE)
+					{
+						pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+					}
+					else
+					{
+						pti = ptt;
+					}
 
 
 					substitute(ses, temp, buf, flags_neol);
 					substitute(ses, temp, buf, flags_neol);
 
 
@@ -725,14 +1243,17 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 
 					if (*temp)
 					if (*temp)
 					{
 					{
-						root = local_list(ses);
+						root = search_nest_base_ses(ses, temp);
 
 
-						if ((node = search_node_list(root, temp)) == NULL)
+						if (root)
 						{
 						{
-							root = ses->list[LIST_VARIABLE];
-
 							node = search_node_list(root, temp);
 							node = search_node_list(root, temp);
 						}
 						}
+						else
+						{
+							root = ses->list[LIST_VARIABLE];
+							node = NULL;
+						}
 					}
 					}
 					else
 					else
 					{
 					{
@@ -760,7 +1281,14 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						continue;
 						continue;
 					}
 					}
 
 
-					pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+					if (brace == FALSE)
+					{
+						pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+					}
+					else
+					{
+						pti = ptt;
+					}
 
 
 					substitute(ses, temp, buf, flags_neol);
 					substitute(ses, temp, buf, flags_neol);
 
 
@@ -885,7 +1413,14 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						continue;
 						continue;
 					}
 					}
 
 
-					pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+					if (brace == FALSE)
+					{
+						pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+					}
+					else
+					{
+						pti = ptt;
+					}
 
 
 					substitute(ses, temp, buf, flags_neol);
 					substitute(ses, temp, buf, flags_neol);
 
 
@@ -928,7 +1463,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 
 						while (*ptt)
 						while (*ptt)
 						{
 						{
-							if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *ptt & 128 && ptt[1] != 0)
+							if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, ptt))
 							{
 							{
 								*pto++ = *ptt++;
 								*pto++ = *ptt++;
 								*pto++ = *ptt++;
 								*pto++ = *ptt++;
@@ -1003,6 +1538,11 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						pti += isdigit((int) pti[2]) ? 3 : 2;
 						pti += isdigit((int) pti[2]) ? 3 : 2;
 					}
 					}
 				}
 				}
+				else if (pti[1] == '*') // avoid %*variable triggers
+				{
+					*pto++ = *pti++;
+					*pto++ = *pti++;
+				}
 				else
 				else
 				{
 				{
 					*pto++ = *pti++;
 					*pto++ = *pti++;
@@ -1345,6 +1885,26 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				}
 				}
 				break;
 				break;
 
 
+			case ASCII_ESC:
+				if (HAS_BIT(flags, SUB_COL) && ses->color == 0)
+				{
+					skip = find_color_code(pti);
+
+					if (skip)
+					{
+						pti += skip;
+					}
+					else
+					{
+						*pto++ = *pti++;
+					}
+				}
+				else
+				{
+					*pto++ = *pti++;
+				}
+				break;
+
 			default:
 			default:
 				if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG))
 				if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG))
 				{
 				{

+ 88 - 1
src/system.c

@@ -38,6 +38,8 @@
 #include <termios.h>
 #include <termios.h>
 #include <sys/un.h>
 #include <sys/un.h>
 
 
+#include <sys/wait.h>
+
 DO_COMMAND(do_run)
 DO_COMMAND(do_run)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], temp[BUFFER_SIZE], file[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], temp[BUFFER_SIZE], file[BUFFER_SIZE];
@@ -147,7 +149,7 @@ DO_COMMAND(do_script)
 				cat_sprintf(var, "{%d}{%s}", index++, tmp);
 				cat_sprintf(var, "{%d}{%s}", index++, tmp);
 			}
 			}
 
 
-			set_nest_node(ses->list[LIST_VARIABLE], arg1, "%s", var);
+			set_nest_node_ses(ses, arg1, "%s", var);
 
 
 			pclose(script);
 			pclose(script);
 		}
 		}
@@ -181,7 +183,92 @@ DO_COMMAND(do_suspend)
 	return ses;
 	return ses;
 }
 }
 
 
+// use #run + waitpid() ?
+
+/*
+DO_COMMAND(do_system)
+{
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], temp[BUFFER_SIZE], buffer[BUFFER_SIZE];
+	int desc, pid;
+	struct winsize size;
+	char *argv[4] = {"sh", "-c", "", NULL};
+	int filedes[2];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {SHELL COMMAND}");
+		
+		return ses;
+	}
+
+	size.ws_row = get_scroll_rows(ses);
+	size.ws_col = get_scroll_cols(ses);
+	size.ws_ypixel = size.ws_row * gtd->screen->char_height;
+	size.ws_xpixel = size.ws_col * gtd->screen->char_width;
 
 
+	if (pipe(filedes) == -1)
+	{
+		perror("pipe");
+
+		return ses;
+	}
+
+	pid = fork();
+
+	switch (pid)
+	{
+		case -1:
+			syserr_printf(ses, "do_system: forkpty");
+			break;
+
+		case 0:
+			while ((dup2(filedes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+			close(filedes[1]);
+			close(filedes[0]);
+
+			sprintf(temp, "exec %s", arg1);
+			argv[2] = temp;
+			execv("/bin/sh", argv);
+			perror("execv");
+			break;
+
+		default:
+			close(filedes[1]);
+
+			while (TRUE)
+			{
+				ssize_t count = read(filedes[0], buffer, sizeof(buffer));
+
+				if (count == -1)
+				{
+					if (errno == EINTR)
+					{
+						continue;
+					}
+					else
+					{
+						perror("read");
+					}
+					return ses;
+				}
+				else if (count == 0)
+				{
+					break;
+				}
+				else
+				{
+					tintin_printf2(ses, "%s", buffer);
+				}
+			}
+			close(filedes[0]);
+			wait(0);
+			break;
+	}
+	return ses;
+}
+*/
 
 
 DO_COMMAND(do_system)
 DO_COMMAND(do_system)
 {
 {

+ 242 - 85
src/tables.c

@@ -34,12 +34,12 @@ struct command_type command_table[] =
 	{    "advertise",         do_advertise,         TOKEN_TYPE_COMMAND },
 	{    "advertise",         do_advertise,         TOKEN_TYPE_COMMAND },
 	{    "alias",             do_alias,             TOKEN_TYPE_COMMAND },
 	{    "alias",             do_alias,             TOKEN_TYPE_COMMAND },
 	{    "all",               do_all,               TOKEN_TYPE_COMMAND },
 	{    "all",               do_all,               TOKEN_TYPE_COMMAND },
-//	{    "attach",            do_attach,            TOKEN_TYPE_COMMAND },
 	{    "bell",              do_bell,              TOKEN_TYPE_COMMAND },
 	{    "bell",              do_bell,              TOKEN_TYPE_COMMAND },
 	{    "break",             do_nop,               TOKEN_TYPE_BREAK   },
 	{    "break",             do_nop,               TOKEN_TYPE_BREAK   },
 	{    "buffer",            do_buffer,            TOKEN_TYPE_COMMAND },
 	{    "buffer",            do_buffer,            TOKEN_TYPE_COMMAND },
 	{    "button",            do_button,            TOKEN_TYPE_COMMAND },
 	{    "button",            do_button,            TOKEN_TYPE_COMMAND },
 	{    "case",              do_nop,               TOKEN_TYPE_CASE    },
 	{    "case",              do_nop,               TOKEN_TYPE_CASE    },
+	{    "cat",               do_cat,               TOKEN_TYPE_COMMAND },
 	{    "chat",              do_chat,              TOKEN_TYPE_COMMAND },
 	{    "chat",              do_chat,              TOKEN_TYPE_COMMAND },
 	{    "class",             do_class,             TOKEN_TYPE_COMMAND },
 	{    "class",             do_class,             TOKEN_TYPE_COMMAND },
 	{    "commands",          do_commands,          TOKEN_TYPE_COMMAND },
 	{    "commands",          do_commands,          TOKEN_TYPE_COMMAND },
@@ -51,7 +51,7 @@ struct command_type command_table[] =
 	{    "debug",             do_debug,             TOKEN_TYPE_COMMAND },
 	{    "debug",             do_debug,             TOKEN_TYPE_COMMAND },
 	{    "default",           do_nop,               TOKEN_TYPE_DEFAULT },
 	{    "default",           do_nop,               TOKEN_TYPE_DEFAULT },
 	{    "delay",             do_delay,             TOKEN_TYPE_COMMAND },
 	{    "delay",             do_delay,             TOKEN_TYPE_COMMAND },
-//	{    "detach",            do_detach,            TOKEN_TYPE_COMMAND },
+	{    "dictionary",        do_dictionary,        TOKEN_TYPE_COMMAND },
 	{    "draw",              do_draw,              TOKEN_TYPE_COMMAND },
 	{    "draw",              do_draw,              TOKEN_TYPE_COMMAND },
 	{    "echo",              do_echo,              TOKEN_TYPE_COMMAND },
 	{    "echo",              do_echo,              TOKEN_TYPE_COMMAND },
 	{    "else",              do_nop,               TOKEN_TYPE_ELSE    },
 	{    "else",              do_nop,               TOKEN_TYPE_ELSE    },
@@ -133,26 +133,28 @@ struct command_type command_table[] =
 
 
 struct list_type list_table[LIST_MAX] =
 struct list_type list_table[LIST_MAX] =
 {
 {
-	{    "ACTION",            "ACTIONS",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
-	{    "ALIAS",             "ALIASES",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
-	{    "BUTTON",            "BUTTONS",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_PRIORITY },
-	{    "CLASS",             "CLASSES",            SORT_PRIORITY,    2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_INHERIT                                 },
-	{    "COMMAND",           "COMMANDS",           SORT_APPEND,      1,  LIST_FLAG_MESSAGE                                                                  },
-	{    "CONFIG",            "CONFIGURATIONS",     SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_INHERIT                 },
-	{    "DELAY",             "DELAYS",             SORT_DELAY,       3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ                                                   },
-	{    "EVENT",             "EVENTS",             SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "FUNCTION",          "FUNCTIONS",          SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "GAG",               "GAGS",               SORT_ALPHA,       1,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "HIGHLIGHT",         "HIGHLIGHTS",         SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
-	{    "HISTORY",           "HISTORIES",          SORT_APPEND,      1,  LIST_FLAG_MESSAGE                                                                  },
-	{    "MACRO",             "MACROS",             SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "PATH",              "PATHS",              SORT_APPEND,      2,  LIST_FLAG_MESSAGE                                                                  },
-	{    "PATHDIR",           "PATHDIRS",           SORT_ALPHA,       3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "PROMPT",            "PROMPTS",            SORT_PRIORITY,    4,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
-	{    "SUBSTITUTE",        "SUBSTITUTES",        SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
-	{    "TAB",               "TABS",               SORT_ALPHA,       1,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "TICKER",            "TICKERS",            SORT_ALPHA,       3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "VARIABLE",          "VARIABLES",          SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_NEST }
+	{    "ACTION",            "ACTIONS",            SORT_PRIORITY,    3, 2, 3, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "ALIAS",             "ALIASES",            SORT_PRIORITY,    3, 2, 3, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "BUTTON",            "BUTTONS",            SORT_PRIORITY,    3, 2, 3, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_PRIORITY },
+	{    "CLASS",             "CLASSES",            SORT_PRIORITY,    2, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_INHERIT                                 },
+	{    "COMMAND",           "COMMANDS",           SORT_ALPHA,       1, 0, 0, LIST_FLAG_MESSAGE                                                                  },
+	{    "CONFIG",            "CONFIGS",            SORT_ALPHA,       2, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "DELAY",             "DELAYS",             SORT_DELAY,       3, 2, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ                                                   },
+	{    "EVENT",             "EVENTS",             SORT_ALPHA,       2, 2, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "FUNCTION",          "FUNCTIONS",          SORT_ALPHA,       2, 2, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "GAG",               "GAGS",               SORT_ALPHA,       1, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "HIGHLIGHT",         "HIGHLIGHTS",         SORT_PRIORITY,    3, 0, 3, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "HISTORY",           "HISTORIES",          SORT_APPEND,      1, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_HIDE },
+	{    "LANDMARK",          "LANDMARKS",          SORT_ALPHA,       4, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_HIDE },
+	{    "MACRO",             "MACROS",             SORT_ALPHA,       2, 2, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "PATH",              "PATHS",              SORT_APPEND,      2, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_HIDE },
+	{    "PATHDIR",           "PATHDIRS",           SORT_ALPHA,       3, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "PROMPT",            "PROMPTS",            SORT_ALPHA,       4, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX },
+	{    "SUBSTITUTE",        "SUBSTITUTES",        SORT_PRIORITY,    3, 0, 3, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "TAB",               "TABS",               SORT_ALPHA,       1, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "TERRAIN",           "TERRAINS",           SORT_ALPHA,       2, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_HIDE },
+	{    "TICKER",            "TICKERS",            SORT_ALPHA,       3, 2, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "VARIABLE",          "VARIABLES",          SORT_ALPHA,       2, 0, 0, LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_NEST }
 };
 };
 
 
 struct substitution_type substitution_table[] =
 struct substitution_type substitution_table[] =
@@ -273,8 +275,8 @@ struct config_type config_table[] =
 
 
 	{
 	{
 		"LOG LEVEL",
 		"LOG LEVEL",
-		"TinTin++ only logs low level mud data",
-		"TinTin++ only logs high level mud data",
+		"TinTin++ only logs low level server data",
+		"TinTin++ only logs high level server data",
 		config_loglevel
 		config_loglevel
 	},
 	},
 
 
@@ -287,8 +289,8 @@ struct config_type config_table[] =
 
 
 	{
 	{
 		"MOUSE TRACKING",
 		"MOUSE TRACKING",
-		"Generates mouse tracking events.",
-		"Do does not generate mouse events.",
+		"Generate mouse tracking events.",
+		"Do not generate mouse events.",
 		config_mousetracking
 		config_mousetracking
 	},
 	},
 
 
@@ -336,8 +338,8 @@ struct config_type config_table[] =
 
 
 	{
 	{
 		"SCROLL LOCK",
 		"SCROLL LOCK",
-		"You do not see mud output while scrolling",
-		"You see mud output while scrolling",
+		"You do not see server output while scrolling",
+		"You see server output while scrolling",
 		config_scrolllock
 		config_scrolllock
 	},
 	},
 
 
@@ -392,8 +394,8 @@ struct config_type config_table[] =
 
 
 	{
 	{
 		"WORDWRAP",
 		"WORDWRAP",
-		"Mud output is word wrapped",
-		"Mud output is line wrapped",
+		"Server output is word wrapped",
+		"Server output is line wrapped",
 		config_wordwrap
 		config_wordwrap
 	},
 	},
 
 
@@ -531,6 +533,7 @@ struct color_type map_color_table[] =
 {
 {
 	{     "AVOID",            "<118>" },
 	{     "AVOID",            "<118>" },
 	{     "BACKGROUND",       ""      },
 	{     "BACKGROUND",       ""      },
+	{     "BLOCK",            "<218>" },
 	{     "EXITS",            "<278>" },
 	{     "EXITS",            "<278>" },
 	{     "HIDE",             "<168>" },
 	{     "HIDE",             "<168>" },
 	{     "INVISIBLE",        "<208>" },
 	{     "INVISIBLE",        "<208>" },
@@ -545,11 +548,14 @@ struct class_type class_table[] =
 {
 {
 	{    "OPEN",              class_open             },
 	{    "OPEN",              class_open             },
 	{    "CLOSE",             class_close            },
 	{    "CLOSE",             class_close            },
+	{    "KILL",              class_kill             },
 	{    "LIST",              class_list             },
 	{    "LIST",              class_list             },
+	{    "LOAD",              class_load             },
 	{    "READ",              class_read             },
 	{    "READ",              class_read             },
+	{    "SAVE",              class_save             },
 	{    "SIZE",              class_size             },
 	{    "SIZE",              class_size             },
 	{    "WRITE",             class_write            },
 	{    "WRITE",             class_write            },
-	{    "KILL",              class_kill             },
+
 	{    "",                  NULL                   },
 	{    "",                  NULL                   },
 };
 };
 
 
@@ -564,7 +570,7 @@ struct chat_type chat_table[] =
 	{     "DOWNLOADDIR",      chat_downloaddir,    1, 0, "Set the download directory"                     },
 	{     "DOWNLOADDIR",      chat_downloaddir,    1, 0, "Set the download directory"                     },
 	{     "EMOTE",            chat_emote,          0, 1, "Send an emoted chat message"                    },
 	{     "EMOTE",            chat_emote,          0, 1, "Send an emoted chat message"                    },
 	{     "FORWARD",          chat_forward,        1, 0, "Forward all chat messages to a buddy"           },
 	{     "FORWARD",          chat_forward,        1, 0, "Forward all chat messages to a buddy"           },
-	{     "FORWARDALL",       chat_forwardall,     1, 0, "Forward all chat/mud messages to a buddy"       },
+	{     "FORWARDALL",       chat_forwardall,     1, 0, "Forward all chat/server messages to a buddy"    },
 	{     "FILESTAT",         chat_filestat,       1, 0, "Show file transfer data"                        },
 	{     "FILESTAT",         chat_filestat,       1, 0, "Show file transfer data"                        },
 	{     "GROUP",            chat_group,          0, 1, "Assign a group to a buddy"                      },
 	{     "GROUP",            chat_group,          0, 1, "Assign a group to a buddy"                      },
 	{     "IGNORE",           chat_ignore,         1, 0, "Ignore all messages from a buddy"               },
 	{     "IGNORE",           chat_ignore,         1, 0, "Ignore all messages from a buddy"               },
@@ -630,14 +636,17 @@ struct array_type array_table[] =
 	{     "ADD",              array_add,         "Add an item to a list table"             },
 	{     "ADD",              array_add,         "Add an item to a list table"             },
 	{     "CLEAR",            array_clear,       "Clear a list"                            },
 	{     "CLEAR",            array_clear,       "Clear a list"                            },
 	{     "CLR",              array_clear,       NULL                                      },
 	{     "CLR",              array_clear,       NULL                                      },
+	{     "COLLAPSE",         array_collapse,    "Collapse the list into a variable"       },
 	{     "CREATE",           array_create,      "Create a list table with given items"    },
 	{     "CREATE",           array_create,      "Create a list table with given items"    },
 	{     "DELETE",           array_delete,      "Delete a list item with given index"     },
 	{     "DELETE",           array_delete,      "Delete a list item with given index"     },
+	{     "EXPLODE",          array_explode,     "Explode the variable into a list"        },
 	{     "FIND",             array_find,        "Find a list item with given regex"       },
 	{     "FIND",             array_find,        "Find a list item with given regex"       },
 	{     "FND",              array_find,        NULL                                      },
 	{     "FND",              array_find,        NULL                                      },
 	{     "GET",              array_get,         "Retrieve a list item with given index"   },
 	{     "GET",              array_get,         "Retrieve a list item with given index"   },
 	{     "INSERT",           array_insert,      "Insert a list item at given index"       },
 	{     "INSERT",           array_insert,      "Insert a list item at given index"       },
 	{     "LENGTH",           array_size,        NULL                                      },
 	{     "LENGTH",           array_size,        NULL                                      },
 	{     "SET",              array_set,         "Change a list item at given index"       },
 	{     "SET",              array_set,         "Change a list item at given index"       },
+	{     "SHUFFLE",          array_shuffle,     "Sort a list table randomly"              },
 	{     "SIMPLIFY",         array_simplify,    "Turn a list table into a simple list"    },
 	{     "SIMPLIFY",         array_simplify,    "Turn a list table into a simple list"    },
 	{     "SIZE",             array_size,        NULL                                      },
 	{     "SIZE",             array_size,        NULL                                      },
 	{     "SORT",             array_sort,        "Sort a list table alphabetically"        },
 	{     "SORT",             array_sort,        "Sort a list table alphabetically"        },
@@ -650,52 +659,59 @@ struct array_type array_table[] =
 
 
 struct map_type map_table[] =
 struct map_type map_table[] =
 {
 {
-	{     "AT",               map_at,              0,              2    },
-	{     "CENTER",           map_center,          MAP_FLAG_VTMAP, 2    },
-	{     "COLOR",            map_color,           MAP_FLAG_VTMAP, 1    },
-	{     "CREATE",           map_create,          MAP_FLAG_VTMAP, 0    },
-	{     "DEBUG",            map_debug,           0,              2    },
-	{     "DELETE",           map_delete,          MAP_FLAG_VTMAP, 1    },
-	{     "DESTROY",          map_destroy,         MAP_FLAG_VTMAP, 1    },
-	{     "DIG",              map_dig,             MAP_FLAG_VTMAP, 2    },
-	{     "EXIT",             map_exit,            MAP_FLAG_VTMAP, 2    },
-	{     "EXITFLAG",         map_exitflag,        MAP_FLAG_VTMAP, 2    },
-	{     "EXPLORE",          map_explore,         MAP_FLAG_VTMAP, 2    },
-	{     "FIND",             map_find,            MAP_FLAG_VTMAP, 2    },
-	{     "FLAG",             map_flag,            MAP_FLAG_VTMAP, 1    },
-	{     "GET",              map_get,             0,              2    },
-	{     "GLOBAL",           map_global,          0,              1    },
-	{     "GOTO",             map_goto,            MAP_FLAG_VTMAP, 1    },
-	{     "INFO",             map_info,            0,              1    },
-	{     "INSERT",           map_insert,          MAP_FLAG_VTMAP, 2    },
-	{     "JUMP",             map_jump,            MAP_FLAG_VTMAP, 2    },
-	{     "LEAVE",            map_leave,           MAP_FLAG_VTMAP, 2    },
-	{     "LEGENDA",          map_legend,          MAP_FLAG_VTMAP, 1    },
-	{     "LINK",             map_link,            MAP_FLAG_VTMAP, 2    },
-	{     "LIST",             map_list,            0,              2    },
-	{     "MAP",              map_map,             0,              2    },
-	{     "MOVE",             map_move,            MAP_FLAG_VTMAP, 2    },
-	{     "NAME",             map_name,            MAP_FLAG_VTMAP, 2    },
-	{     "OFFSET",           map_offset,          MAP_FLAG_VTMAP, 1    },
-	{     "READ",             map_read,            MAP_FLAG_VTMAP, 0    },
-	{     "RESIZE",           map_resize,          0,              1    },
-	{     "RETURN",           map_return,          MAP_FLAG_VTMAP, 1    },
-	{     "ROOMFLAG",         map_roomflag,        MAP_FLAG_VTMAP, 2    },
-	{     "RUN",              map_run,             MAP_FLAG_VTMAP, 2    },
-	{     "SET",              map_set,             MAP_FLAG_VTMAP, 2    },
-	{     "TRAVEL",           map_travel,          MAP_FLAG_VTMAP, 2    },
-	{     "UNDO",             map_undo,            MAP_FLAG_VTMAP, 2    },
-	{     "UNINSERT",         map_uninsert,        MAP_FLAG_VTMAP, 2    },
-	{     "UNLINK",           map_unlink,          MAP_FLAG_VTMAP, 2    },
-	{     "UPDATE",           map_update,          0,              0    },
-	{     "VNUM",             map_vnum,            MAP_FLAG_VTMAP, 2    },
-	{     "WRITE",            map_write,           0,              1    },
-	{     "",                 NULL,                0    }
+	{     "AT",               map_at,              0,              2, "Execute command at given location"    },
+	{     "CENTER",           map_center,          MAP_FLAG_VTMAP, 2, "Set the center of the map display"    },
+	{     "COLOR",            map_color,           MAP_FLAG_VTMAP, 1, "Set the color for given field"        },
+	{     "CREATE",           map_create,          MAP_FLAG_VTMAP, 0, "Creates the initial map"              },
+	{     "DEBUG",            map_debug,           0,              2, "Obscure debug information"            },
+	{     "DELETE",           map_delete,          MAP_FLAG_VTMAP, 1, "Delete the room at given direction"   },
+	{     "DESTROY",          map_destroy,         MAP_FLAG_VTMAP, 1, "Destroy area or map"                  },
+	{     "DIG",              map_dig,             MAP_FLAG_VTMAP, 2, "Create new room at given direction"   },
+	{     "ENTRANCE",         map_entrance,        MAP_FLAG_VTMAP, 2, "Change the given exit's entrance"     },
+	{     "EXIT",             map_exit,            MAP_FLAG_VTMAP, 2, "Change the given exit"                },
+	{     "EXITFLAG",         map_exitflag,        MAP_FLAG_VTMAP, 2, "Change the given exit's flags"        },
+	{     "EXPLORE",          map_explore,         MAP_FLAG_VTMAP, 2, "Save explored path to #path"          },
+	{     "FIND",             map_find,            MAP_FLAG_VTMAP, 2, "Save found path to #path"             },
+	{     "FLAG",             map_flag,            MAP_FLAG_VTMAP, 1, "Change the map's flags"               },
+	{     "GET",              map_get,             0,              2, "Get various room values"              },
+	{     "GLOBAL",           map_global,          0,              1, "Set the global exit room"             },
+	{     "GOTO",             map_goto,            MAP_FLAG_VTMAP, 1, "Move to the given room"               },
+	{     "INFO",             map_info,            0,              1, "Display map and room information"     },
+	{     "INSERT",           map_insert,          MAP_FLAG_VTMAP, 2, "Insert a room at given direction"     },
+	{     "JUMP",             map_jump,            MAP_FLAG_VTMAP, 2, "Move to the given coordinate"         },
+	{     "LANDMARK",         map_landmark,        0,              1, "Create a global room reference"       },
+	{     "LEAVE",            map_leave,           MAP_FLAG_VTMAP, 2, "Leave the map"                        },
+	{     "LEGEND" ,          map_legend,          MAP_FLAG_VTMAP, 1, "Manipulate the map legend"            },
+	{     "LINK",             map_link,            MAP_FLAG_VTMAP, 2, "Link room at given direction"         },
+	{     "LIST",             map_list,            0,              2, "List matching rooms"                  },
+	{     "MAP",              map_map,             0,              2, "Display the map"                      },
+	{     "MOVE",             map_move,            MAP_FLAG_VTMAP, 2, "Move to the given direction"          },
+	{     "NAME",             map_name,            MAP_FLAG_VTMAP, 2, "(obsolete) Use SET ROOMNAME instead"  },
+	{     "OFFSET",           map_offset,          MAP_FLAG_VTMAP, 1, "Set the offset of the vt map"         },
+	{     "READ",             map_read,            MAP_FLAG_VTMAP, 0, "Read a map file"                      },
+	{     "RESIZE",           map_resize,          0,              1, "Resize the map room vnum range"       },
+	{     "RETURN",           map_return,          MAP_FLAG_VTMAP, 1, "Return to last known room"            },
+	{     "ROOMFLAG",         map_roomflag,        MAP_FLAG_VTMAP, 2, "Change the room's flags"              },
+	{     "RUN",              map_run,             MAP_FLAG_VTMAP, 2, "Save found path to #path and run it"  },
+	{     "SET",              map_set,             MAP_FLAG_VTMAP, 2, "Set various room values"              },
+	{     "SYNC",             map_sync,            MAP_FLAG_VTMAP, 0, "Read a map file without overwriting"  },
+	{     "TERRAIN",          map_terrain,         MAP_FLAG_VTMAP, 1, "Create a terrain type"                },
+	{     "TRAVEL",           map_travel,          MAP_FLAG_VTMAP, 2, "Save explored path to #path and run it" },
+	{     "UNDO",             map_undo,            MAP_FLAG_VTMAP, 2, "Undo last map action"                 },
+	{     "UNINSERT",         map_uninsert,        MAP_FLAG_VTMAP, 2, "Uninsert room in given direction"     },
+	{     "UNLANDMARK",       map_unlandmark,      0,              1, "Remove a landmark"                    },
+	{     "UNLINK",           map_unlink,          MAP_FLAG_VTMAP, 2, "Remove given exit"                    },
+	{     "UNTERRAIN",        map_unterrain,       0,              1, "Remove a terrain type"                },
+	{     "UPDATE",           map_update,          0,              0, "Mark vt map for an auto update"       },
+	{     "VNUM",             map_vnum,            MAP_FLAG_VTMAP, 2, "Change the room vnum to given vnum"   },
+	{     "WRITE",            map_write,           0,              1, "Save the map to given file"           },
+	{     "",                 NULL,                0,              0, ""                                     }
 };
 };
 
 
 
 
 struct cursor_type cursor_table[] =
 struct cursor_type cursor_table[] =
 {
 {
+/*
 	{
 	{
 		"AUTO TAB BACKWARD",
 		"AUTO TAB BACKWARD",
 		"Tab completion from scrollback buffer, backward",
 		"Tab completion from scrollback buffer, backward",
@@ -710,6 +726,7 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ALL,
 		CURSOR_FLAG_GET_ALL,
 		cursor_auto_tab_forward
 		cursor_auto_tab_forward
 	},
 	},
+*/
 	{
 	{
 		"BACKSPACE",
 		"BACKSPACE",
 		"Delete backward character",
 		"Delete backward character",
@@ -888,6 +905,7 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ONE,
 		CURSOR_FLAG_GET_ONE,
 		cursor_insert
 		cursor_insert
 	},
 	},
+/*
 	{
 	{
 		"MIXED TAB BACKWARD",
 		"MIXED TAB BACKWARD",
 		"Tab completion on last word, search backward",
 		"Tab completion on last word, search backward",
@@ -902,6 +920,7 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ALL,
 		CURSOR_FLAG_GET_ALL,
 		cursor_mixed_tab_forward
 		cursor_mixed_tab_forward
 	},
 	},
+*/
 	{
 	{
 		"NEXT WORD",
 		"NEXT WORD",
 		"Move cursor to the next word",
 		"Move cursor to the next word",
@@ -958,6 +977,28 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ALL,
 		CURSOR_FLAG_GET_ALL,
 		cursor_suspend
 		cursor_suspend
 	},
 	},
+	{
+		"TAB",
+		"<LIST|SCROLLBACK> <BACKWARD|FORWARD>",
+		"",
+		CURSOR_FLAG_GET_ONE,
+		cursor_tab
+	},
+	{
+		"TAB L S BACKWARD",
+		"Tab completion on last word, search backward",
+		"\e[Z", // shift-tab
+		CURSOR_FLAG_GET_ALL,
+		cursor_mixed_tab_backward
+	},
+	{
+		"TAB L S FORWARD",
+		"Tab completion on last word, search forward",
+		"\t",
+		CURSOR_FLAG_GET_ALL,
+		cursor_mixed_tab_forward
+	},
+/*
 	{
 	{
 		"TAB BACKWARD",
 		"TAB BACKWARD",
 		"Tab completion from tab list, backward",
 		"Tab completion from tab list, backward",
@@ -972,7 +1013,7 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ALL,
 		CURSOR_FLAG_GET_ALL,
 		cursor_tab_forward
 		cursor_tab_forward
 	},
 	},
-
+*/
 	{
 	{
 		"", "", "\e[5~",   0, cursor_buffer_up
 		"", "", "\e[5~",   0, cursor_buffer_up
 	},
 	},
@@ -1054,11 +1095,18 @@ struct draw_type draw_table[] =
 {
 {
 	{
 	{
 		"BOX",
 		"BOX",
-		"Draw a box.",
+		"Draw four sides of a box.",
 		DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_RIGHT|DRAW_FLAG_TOP|DRAW_FLAG_BOT,
 		DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_RIGHT|DRAW_FLAG_TOP|DRAW_FLAG_BOT,
 		draw_box
 		draw_box
 	},
 	},
 
 
+	{
+		"CORNER",
+		"Draw a corner",
+		DRAW_FLAG_CORNERED,
+		draw_corner
+	},
+
 	{
 	{
 		"LINE",
 		"LINE",
 		"Draw a line.",
 		"Draw a line.",
@@ -1066,13 +1114,27 @@ struct draw_type draw_table[] =
 		draw_line
 		draw_line
 	},
 	},
 
 
+	{
+		"RAIN",
+		"Draw digital rain.",
+		DRAW_FLAG_NONE,
+		draw_rain
+	},
+
 	{
 	{
 		"SIDE",
 		"SIDE",
-		"Draw the side of a box.",
+		"Draw a line with corners.",
 		DRAW_FLAG_BOXED,
 		DRAW_FLAG_BOXED,
 		draw_side
 		draw_side
 	},
 	},
 
 
+	{
+		"TABLE",
+		"Draw a table.",
+		DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_RIGHT|DRAW_FLAG_TOP|DRAW_FLAG_BOT,
+		draw_table_grid
+	},
+
 	{
 	{
 		"TILE",
 		"TILE",
 		"Draw a tile.",
 		"Draw a tile.",
@@ -1299,11 +1361,13 @@ struct event_type event_table[] =
 	{    "MAP EXIT MAP",                           EVENT_FLAG_MAP,      "Triggers when exiting the map."          },
 	{    "MAP EXIT MAP",                           EVENT_FLAG_MAP,      "Triggers when exiting the map."          },
 	{    "MAP EXIT ROOM",                          EVENT_FLAG_MAP,      "Triggers when exiting a map room."       },
 	{    "MAP EXIT ROOM",                          EVENT_FLAG_MAP,      "Triggers when exiting a map room."       },
 	{    "MAP FOLLOW MAP",                         EVENT_FLAG_MAP,      "Triggers when moving to a map room."     },
 	{    "MAP FOLLOW MAP",                         EVENT_FLAG_MAP,      "Triggers when moving to a map room."     },
-	{    "MAP LONG-CLICKED ",                      EVENT_FLAG_MAP,      "Triggers on vt map click."               },
-	{    "MAP PRESSED ",                           EVENT_FLAG_MAP,      "Triggers on vt map click."               },
-	{    "MAP RELEASED ",                          EVENT_FLAG_MAP,      "Triggers on vt map click."               },
-	{    "MAP SHORT-CLICKED ",                     EVENT_FLAG_MAP,      "Triggers on vt map click."               },
-	{    "MAP TRIPLE-CLICKED ",                    EVENT_FLAG_MAP,      "Triggers on vt map click."               },
+	{    "MAP LOCATION",                           EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP LONG-CLICKED ",                      EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP MOUSE LOCATION",                     EVENT_FLAG_MOUSE,    "Triggers when called by #screen raise."  }, 
+	{    "MAP PRESSED ",                           EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP RELEASED ",                          EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP SHORT-CLICKED ",                     EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP TRIPLE-CLICKED ",                    EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
 	{    "MAP UPDATED VTMAP",                      EVENT_FLAG_MAP,      "Triggers on vt map update."              },
 	{    "MAP UPDATED VTMAP",                      EVENT_FLAG_MAP,      "Triggers on vt map update."              },
 	{    "MINUTE",                                 EVENT_FLAG_TIME,     "Triggers each minute or given minute."   },
 	{    "MINUTE",                                 EVENT_FLAG_TIME,     "Triggers each minute or given minute."   },
 	{    "MONTH",                                  EVENT_FLAG_TIME,     "Triggers each month or given month."     },
 	{    "MONTH",                                  EVENT_FLAG_TIME,     "Triggers each month or given month."     },
@@ -1330,8 +1394,10 @@ struct event_type event_table[] =
 	{    "SCREEN DESKTOP DIMENSIONS",              EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DESKTOP DIMENSIONS",              EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DESKTOP SIZE",                    EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DESKTOP SIZE",                    EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DIMENSIONS",                      EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DIMENSIONS",                      EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
+	{    "SCREEN FOCUS",                           EVENT_FLAG_SCREEN,   "Triggers when focus changes.",           },
+	{    "SCREEN LOCATION",                        EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN MINIMIZED",                       EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN MINIMIZED",                       EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
-	{    "SCREEN POSITION",                        EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
+	{    "SCREEN MOUSE LOCATION",                  EVENT_FLAG_MOUSE,    "Triggers when called by #screen raise."  },
 	{    "SCREEN REFRESH",                         EVENT_FLAG_SCREEN,   "Triggers when the screen is refreshed."  },
 	{    "SCREEN REFRESH",                         EVENT_FLAG_SCREEN,   "Triggers when the screen is refreshed."  },
 	{    "SCREEN RESIZE",                          EVENT_FLAG_SCREEN,   "Triggers when the screen is resized."    },
 	{    "SCREEN RESIZE",                          EVENT_FLAG_SCREEN,   "Triggers when the screen is resized."    },
 	{    "SCREEN ROTATE LANDSCAPE",                EVENT_FLAG_SCREEN,   "Triggers when the screen is rotated."    },
 	{    "SCREEN ROTATE LANDSCAPE",                EVENT_FLAG_SCREEN,   "Triggers when the screen is rotated."    },
@@ -1350,6 +1416,7 @@ struct event_type event_table[] =
 	{    "SESSION DISCONNECTED",                   EVENT_FLAG_SESSION,  "Triggers when a session disconnects."    },
 	{    "SESSION DISCONNECTED",                   EVENT_FLAG_SESSION,  "Triggers when a session disconnects."    },
 	{    "SESSION TIMED OUT",                      EVENT_FLAG_SESSION,  "Triggers when a session doesn't connect."},
 	{    "SESSION TIMED OUT",                      EVENT_FLAG_SESSION,  "Triggers when a session doesn't connect."},
 	{    "SHORT-CLICKED",                          EVENT_FLAG_MOUSE,    "Triggers when mouse is short-clicked."   },
 	{    "SHORT-CLICKED",                          EVENT_FLAG_MOUSE,    "Triggers when mouse is short-clicked."   },
+	{    "SWIPED",                                 EVENT_FLAG_MOUSE,    "Triggers on mouse swipe."},
 	{    "SYSTEM ERROR",                           EVENT_FLAG_SYSTEM,   "Triggers on system errors."              },
 	{    "SYSTEM ERROR",                           EVENT_FLAG_SYSTEM,   "Triggers on system errors."              },
 	{    "TIME",                                   EVENT_FLAG_TIME,     "Triggers on the given time."             },
 	{    "TIME",                                   EVENT_FLAG_TIME,     "Triggers on the given time."             },
 	{    "TRIPLE-CLICKED",                         EVENT_FLAG_MOUSE,    "Triggers when mouse is triple-clicked."  },
 	{    "TRIPLE-CLICKED",                         EVENT_FLAG_MOUSE,    "Triggers when mouse is triple-clicked."  },
@@ -1363,8 +1430,6 @@ struct event_type event_table[] =
 	{    "VT100 ENQ",                              EVENT_FLAG_VT100,    "Triggers on an \\x05 call."              },
 	{    "VT100 ENQ",                              EVENT_FLAG_VT100,    "Triggers on an \\x05 call."              },
 	{    "VT100 SCROLL REGION",                    EVENT_FLAG_VT100,    "Triggers on vt100 scroll region change." },
 	{    "VT100 SCROLL REGION",                    EVENT_FLAG_VT100,    "Triggers on vt100 scroll region change." },
 	{    "WEEK",                                   EVENT_FLAG_TIME,     "Triggers each week or given week."       },
 	{    "WEEK",                                   EVENT_FLAG_TIME,     "Triggers each week or given week."       },
-	{    "WINDOW FOCUS IN",                        EVENT_FLAG_SCREEN,   "Triggers on window focussing in."        },
-	{    "WINDOW FOCUS OUT",                       EVENT_FLAG_SCREEN,   "Triggers on window focussing out."       },
 	{    "WRITE ERROR",                            EVENT_FLAG_SYSTEM,   "Triggers when the write command fails."  },
 	{    "WRITE ERROR",                            EVENT_FLAG_SYSTEM,   "Triggers when the write command fails."  },
 	{    "YEAR",                                   EVENT_FLAG_TIME,     "Triggers each year or given year."       },
 	{    "YEAR",                                   EVENT_FLAG_TIME,     "Triggers each year or given year."       },
 	{    "",                                       0,                   ""                                        }
 	{    "",                                       0,                   ""                                        }
@@ -1399,6 +1464,8 @@ struct path_type path_table[] =
 struct line_type line_table[] =
 struct line_type line_table[] =
 {
 {
 	{    "BACKGROUND",        line_background,     "Execute line without stealing session focus."   },
 	{    "BACKGROUND",        line_background,     "Execute line without stealing session focus."   },
+	{    "BENCHMARK",         line_benchmark,      "Execute line and provide timing information."   },
+	{    "CAPTURE",           line_capture,        "Capture output in the given variable."          },
 	{    "DEBUG",             line_debug,          "Execute line in debug mode."                    },
 	{    "DEBUG",             line_debug,          "Execute line in debug mode."                    },
 	{    "GAG",               line_gag,            "Gag the next line."                             },
 	{    "GAG",               line_gag,            "Gag the next line."                             },
 	{    "IGNORE",            line_ignore,         "Execute line with triggers ignored."            },
 	{    "IGNORE",            line_ignore,         "Execute line with triggers ignored."            },
@@ -1490,7 +1557,7 @@ struct telopt_type telopt_table[] =
 	{    "OLD-ENVIRON",       TEL_N,               0 },
 	{    "OLD-ENVIRON",       TEL_N,               0 },
 	{    "AUTH",              TEL_N,               0 },
 	{    "AUTH",              TEL_N,               0 },
 	{    "ENCRYPT",           TEL_N,               0 },
 	{    "ENCRYPT",           TEL_N,               0 },
-	{    "NEW-ENVIRON",       TEL_N,               ANNOUNCE_DO },
+	{    "NEW-ENVIRON",       TEL_Y,               ANNOUNCE_DO },
 	{    "TN3270E",           TEL_N,               0 }, /* 40 */
 	{    "TN3270E",           TEL_N,               0 }, /* 40 */
 	{    "XAUTH",             TEL_N,               0 },
 	{    "XAUTH",             TEL_N,               0 },
 	{    "CHARSET",           TEL_Y,               ANNOUNCE_WILL },
 	{    "CHARSET",           TEL_Y,               ANNOUNCE_WILL },
@@ -1921,6 +1988,35 @@ struct map_legend_type map_legend_table[] =
 	{ "S W",		"MUDFONT CURVED",	"1x2",	"1x2"	},
 	{ "S W",		"MUDFONT CURVED",	"1x2",	"1x2"	},
 	{ "N W",		"MUDFONT CURVED",	"1x2",	"1x2"	},
 	{ "N W",		"MUDFONT CURVED",	"1x2",	"1x2"	},
 
 
+        { "NO DIAGONAL",        "UNICODE GRAPHICS",     "2x5",  "2x5"   },
+	{ "SE",                 "UNICODE GRAPHICS",     "⸌",    "2x5"   },
+	{ "NE",                 "UNICODE GRAPHICS",     "⸝",    "2x5"   }, 
+	{ "SE NE",              "UNICODE GRAPHICS",     ">",    "2x5"   }, 
+	{ "SW",                 "UNICODE GRAPHICS",     "⸍",    "2x5"   }, 
+	{ "SE SW",              "UNICODE GRAPHICS",     "⸌⸍",   "2x5"   }, 
+	{ "NE SW",              "UNICODE GRAPHICS",     "/",   "2x5"   }, 
+	{ "SE NE SW",           "UNICODE GRAPHICS",     ">⸍",   "2x5"   }, 
+	{ "NW",                 "UNICODE GRAPHICS",     "⸜",    "2x5"   }, 
+	{ "SE NW",              "UNICODE GRAPHICS",     "\",   "2x5"   }, 
+	{ "NE NW",              "UNICODE GRAPHICS",     "⸝⸜",   "2x5"   }, 
+	{ "SE NE NW",           "UNICODE GRAPHICS",     ">⸜",   "2x5"   }, 
+	{ "SW NW",              "UNICODE GRAPHICS",     "<",    "2x5"   },
+	{ "SE SW NW",           "UNICODE GRAPHICS",     "⸌<",   "2x5"   }, 
+	{ "NE SW NW",           "UNICODE GRAPHICS",     "⸝<",   "2x5"   }, 
+	{ "SE NE SW NW",        "UNICODE GRAPHICS",     "><",   "2x5"   }, 
+	{ "D",                  "UNICODE GRAPHICS",     "-",    "2x5"   }, 
+	{ "N",                  "UNICODE GRAPHICS",     "↑",    "2x5"   }, 
+	{ "S",                  "UNICODE GRAPHICS",     "↓",    "2x5"   }, 
+	{ "N S",                "UNICODE GRAPHICS",     "│",    "2x5"   }, 
+	{ "U",                  "UNICODE GRAPHICS",     "+",    "2x5"   }, 
+	{ "E",                  "UNICODE GRAPHICS",     "🠆",    "2x5"   }, 
+	{ "W",                  "UNICODE GRAPHICS",     "🠄",    "2x5"   }, 
+	{ "E W",                "UNICODE GRAPHICS",     "─",    "2x5"   }, 
+	{ "ROOM L",             "UNICODE GRAPHICS",     "[",    "2x5"   }, 
+	{ "ROOM L CURVED",      "UNICODE GRAPHICS",     "(",    "2x5"   }, 
+	{ "ROOM R",             "UNICODE GRAPHICS",     "]",    "2x5"   }, 
+	{ "ROOM R CURVED",      "UNICODE GRAPHICS",     ")",    "2x5"   },
+
 	{ NULL,			NULL,			NULL,	NULL	}
 	{ NULL,			NULL,			NULL,	NULL	}
 };
 };
 
 
@@ -1956,5 +2052,66 @@ struct map_group_type map_group_table[] =
 	{ "MUDFONT CURVED",		"MUDFONT CURVED",	1, 2,	1, 2,	0, 0,	"" },
 	{ "MUDFONT CURVED",		"MUDFONT CURVED",	1, 2,	1, 2,	0, 0,	"" },
 	{ "MUDFONT CURVED BRAILLE",	"MUDFONT CURVED",	1, 2,	1, 2,	0, 0,	"{\\u2818} {\\u28A0} {\\u2844} {\\u2803} {} {} {} {}" },
 	{ "MUDFONT CURVED BRAILLE",	"MUDFONT CURVED",	1, 2,	1, 2,	0, 0,	"{\\u2818} {\\u28A0} {\\u2844} {\\u2803} {} {} {} {}" },
 
 
+	{ "UNICODE GRAPHICS",           "UNICODE GRAPHICS",     2, 5,   2, 5,   0, 0,   "{ } {\\u2E0C} {\\u2E1D} {>} {\\u2E0D} {\\u2E0C\\u2E0D} {\\uFF0F} {>\\u2E0D} {\\u2E1C} {\\uFF3C} {\\u2E1D\\u2E1C} {>\\u2E1C} {<} {\\u2E0C<} {\\u2E1D<} {><} {-} {\\u2191} {\\u2193} {\\u2502} {+} {\\U01F806} {\\U01F804} {\\u2500} {[} {(} {]} {)}" },
+
 	{ NULL,				NULL,			0, 0,	0, 0,	0, 0,	"" }
 	{ NULL,				NULL,			0, 0,	0, 0,	0, 0,	"" }
 };
 };
+
+struct stamp_type huge_stamp_table[] =
+{
+	{ " ",  23, "   \n   \n   \n   \n   \n   " },
+	{ "!",  23, "██╗\n██║\n██║\n╚═╝\n██╗\n╚═╝" },
+	{ "\"", 41, "██╗██╗\n2██║██║\n╚═╝╚═╝\n   \n   \n   " },
+	{ "#",  59, " ██╗ ██╗ \n████████╗\n╚██╔═██╔╝\n████████╗\n╚██╔═██╔╝\n ╚═╝ ╚═╝ " },
+	{ "&",  59, "  ████╗  \n ██╔═██╗ \n ╚████╔╝ \n██╔══██═╗\n╚█████╔█║\n ╚════╝╚╝" },
+	{ "%",  47, "██╗ ██╗\n╚═╝██╔╝\n  ██╔╝ \n ██╔╝  \n██╔╝██╗\n╚═╝ ╚═╝" },
+	{ "'",  23, "╗██╗\n██║\n╚═╝\n   \n   \n   " },
+
+	{ "+",  59, "   ██╗   \n   ██║   \n████████╗\n╚══██╔══╝\n   ██║   \n   ╚═╝   " },
+
+	{ "0",  53, " █████╗ \n██╔══██╗\n██║  ██║\n██║  ██║\n╚█████╔╝\n ╚════╝ " },
+	{ "1",  53, "  ▄██╗  \n ████║  \n ╚═██║  \n   ██║  \n ██████╗\n ╚═════╝" },
+	{ "2",  53, "██████╗ \n╚════██╗\n █████╔╝\n██╔═══╝ \n███████╗\n╚══════╝" },
+	{ "3",  53, "██████╗ \n╚════██╗\n █████╔╝\n ╚═══██╗\n██████╔╝\n╚═════╝ " },
+	{ "4",  53, "██╗  ██╗\n██║  ██║\n███████║\n╚════██║\n     ██║\n     ╚═╝" },
+	{ "5",  53, "███████╗\n██╔════╝\n███████╗\n╚════██║\n███████║\n╚══════╝" },
+	{ "6",  53, " █████╗ \n██╔═══╝ \n██████╗ \n██╔══██╗\n╚█████╔╝\n ╚════╝ " },
+	{ "7",  53, "███████╗\n╚════██║\n    ██╔╝\n   ██╔╝ \n   ██║  \n   ╚═╝  " },
+	{ "8",  53, " █████╗ \n██╔══██╗\n╚█████╔╝\n██╔══██╗\n╚█████╔╝\n ╚════╝ " },
+	{ "9",  53, " █████╗ \n██╔══██╗\n╚██████║\n ╚═══██║\n █████╔╝\n ╚════╝ " },
+
+	{ ":",  53, "        \n   ██╗  \n   ╚═╝  \n        \n   ██╗  \n   ╚═╝  " },
+
+	{ "A",  53, " █████╗ \n██╔══██╗\n███████║\n██╔══██║\n██║  ██║\n╚═╝  ╚═╝" },
+	{ "B",  53, "██████╗ \n██╔══██╗\n██████╔╝\n██╔══██╗\n██████╔╝\n╚═════╝ " },
+	{ "C",  53, " ██████╗\n██╔════╝\n██║     \n██║     \n╚██████╗\n ╚═════╝" },
+	{ "D",  53, "██████╗ \n██╔══██╗\n██║  ██║\n██║  ██║\n██████╔╝\n╚═════╝ " },
+	{ "E",  53, "███████╗\n██╔════╝\n█████╗  \n██╔══╝  \n███████╗\n╚══════╝" },
+	{ "F",  53, "███████╗\n██╔════╝\n█████╗  \n██╔══╝  \n██║     \n╚═╝     " },
+	{ "G",  59, " ██████╗ \n██╔════╝ \n██║  ███╗\n██║   ██║\n╚██████╔╝\n ╚═════╝ " },
+	{ "H",  53, "██╗  ██╗\n██║  ██║\n███████║\n██╔══██║\n██║  ██║\n╚═╝  ╚═╝" },
+	{ "I",  47, "██████╗\n╚═██╔═╝\n  ██║  \n  ██║  \n██████╗\n╚═════╝" },
+	{ "J",  53, "     ██╗\n     ██║\n     ██║\n██   ██║\n╚█████╔╝\n ╚════╝ " },
+	{ "K",  53, "██╗  ██╗\n██║ ██╔╝\n█████╔╝ \n██╔═██╗ \n██║  ██╗\n╚═╝  ╚═╝" },
+	{ "L",  53, "██╗     \n██║     \n██║     \n██║     \n███████╗\n╚══════╝" },
+	{ "M",  71, "███╗  ███╗\n████╗████║\n██╔███╔██║\n██║╚█╔╝██║\n██║ ╚╝ ██║\n╚═╝    ╚═╝" },
+	{ "N",  65, "███╗   ██╗\n████╗  ██║\n██╔██╗ ██║\n██║╚██╗██║\n██║ ╚████║\n╚═╝  ╚═══╝" },
+	{ "O",  59, " ██████╗ \n██╔═══██╗\n██║   ██║\n██║   ██║\n╚██████╔╝\n ╚═════╝ " },
+	{ "P",  53, "██████╗ \n██╔══██╗\n██████╔╝\n██╔═══╝ \n██║     \n╚═╝     " },
+	{ "Q",  59, " ██████╗ \n██╔═══██╗\n██║   ██║\n██║▄▄ ██║\n╚██████╔╝\n ╚══▀▀═╝ " },
+	{ "R",  53, "██████╗ \n██╔══██╗\n██████╔╝\n██╔══██╗\n██║  ██║\n╚═╝  ╚═╝" },
+	{ "S",  53, "███████╗\n██╔════╝\n███████╗\n╚════██║\n███████║\n╚══════╝" },
+	{ "T",  59, "████████╗\n╚══██╔══╝\n   ██║   \n   ██║   \n   ██║   \n   ╚═╝   " },
+	{ "U",  59, "██╗   ██╗\n██║   ██║\n██║   ██║\n██║   ██║\n╚██████╔╝\n ╚═════╝ " },
+	{ "V",  59, "██╗   ██╗\n██║   ██║\n██║   ██║\n╚██╗ ██╔╝\n ╚████╔╝ \n  ╚═══╝  " },
+	{ "W",  65, "██╗    ██╗\n██║    ██║\n██║ █╗ ██║\n██║███╗██║\n╚███╔███╔╝\n ╚══╝╚══╝ " },
+	{ "X",  53, "██╗  ██╗\n╚██╗██╔╝\n ╚███╔╝ \n ██╔██╗ \n██╔╝ ██╗\n╚═╝  ╚═╝" },
+	{ "Y",  59, "██╗   ██╗\n╚██╗ ██╔╝\n ╚████╔╝ \n  ╚██╔╝  \n   ██║   \n   ╚═╝   " },
+	{ "Z",  53, "███████╗\n╚══███╔╝\n  ███╔╝ \n ███╔╝  \n███████╗\n╚══════╝" },
+
+	{ "i",  23, "██╗\n╚═╝\n██╗\n██║\n██║\n╚═╝" },
+	{ "n",  47, "       \n       \n██▟███╗\n██║ ██║\n██║ ██║\n╚═╝ ╚═╝" },
+
+	{ NULL, 0, NULL }
+};
+

+ 7 - 2
src/telnet.h

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,11 +13,16 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
+/******************************************************************************
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2004                       *
+******************************************************************************/
+
 #include "tintin.h"
 #include "tintin.h"
 
 
 /*
 /*

+ 170 - 22
src/telopt_client.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2001-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -62,7 +61,6 @@ extern  int  client_recv_dont_mccp3(struct session *ses, int cplen, unsigned cha
 extern  int  client_recv_wont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_wont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc);
 
 
 extern  int  client_init_mccp3(struct session *ses);
 extern  int  client_init_mccp3(struct session *ses);
-extern void  client_end_mccp3(struct session *ses);
 extern  int  client_skip_sb(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_skip_sb(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_sb(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_sb(struct session *ses, int cplen, unsigned char *cpsrc);
 
 
@@ -442,7 +440,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					continue;
 					continue;
 
 
 				case ASCII_ENQ:
 				case ASCII_ENQ:
-					check_all_events(ses, SUB_ARG, 0, 1, "VT100 ENQ", gtd->term);
+					check_all_events(ses, SUB_ARG, 0, 1, "VT100 ENQ", gtd->term); // obsolete, but we'll handle it for now.
 					cpsrc++;
 					cpsrc++;
 					cplen--;
 					cplen--;
 					continue;
 					continue;
@@ -672,7 +670,7 @@ int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 		sprintf(mtts, "MTTS %d",
 		sprintf(mtts, "MTTS %d",
 			(ses->color > 0 ? 1 : 0) +
 			(ses->color > 0 ? 1 : 0) +
 			(HAS_BIT(ses->flags, SES_FLAG_SPLIT) ? 0 : 2) +
 			(HAS_BIT(ses->flags, SES_FLAG_SPLIT) ? 0 : 2) +
-			(HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_BIG5TOUTF8) ? 4 : 0) +
+			(HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8) ? 4 : 0) +
 			(ses->color > 16 ? 8 : 0) +
 			(ses->color > 16 ? 8 : 0) +
 			(HAS_BIT(ses->flags, SES_FLAG_SCREENREADER) ? 64 : 0) +
 			(HAS_BIT(ses->flags, SES_FLAG_SCREENREADER) ? 64 : 0) +
 			(ses->color > 256 ? 256 : 0));
 			(ses->color > 256 ? 256 : 0));
@@ -1006,7 +1004,7 @@ int client_recv_sb_mssp(struct session *ses, int cplen, unsigned char *src)
 
 
 int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 {
 {
-	char var[BUFFER_SIZE], val[BUFFER_SIZE], *pto;
+	char var[BUFFER_SIZE], val[BUFFER_SIZE], plain[BUFFER_SIZE], *pto;
 	int i, nest, state[100], last;
 	int i, nest, state[100], last;
 
 
 	var[0] = val[0] = state[0] = nest = last = 0;
 	var[0] = val[0] = state[0] = nest = last = 0;
@@ -1087,9 +1085,10 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 
 
 					if (last)
 					if (last)
 					{
 					{
+						strip_vt102_codes(val, plain);
 						client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
 						client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
-						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP %s", var, var, val);
-						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP", var, val);
+						check_all_events(ses, SUB_ARG, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
+						check_all_events(ses, SUB_ARG, 0, 3, "IAC SB MSDP", var, val, plain);
 					}
 					}
 					pto = var;
 					pto = var;
 				}
 				}
@@ -1115,9 +1114,10 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 
 
 					if (last != MSDP_VAR)
 					if (last != MSDP_VAR)
 					{
 					{
+						strip_vt102_codes(val, plain);
 						client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
 						client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
-						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP %s", var, var, val);
-						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP", var, val);
+						check_all_events(ses, SUB_ARG, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
+						check_all_events(ses, SUB_ARG, 0, 3, "IAC SB MSDP", var, val, plain);
 					}
 					}
 					pto = val;
 					pto = val;
 				}
 				}
@@ -1164,9 +1164,10 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 
 
 		if (last)
 		if (last)
 		{
 		{
+			strip_vt102_codes(val, plain);
 			client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
 			client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
-			check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP %s", var, var, val);
-			check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP", var, val);
+			check_all_events(ses, SUB_ARG, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
+			check_all_events(ses, SUB_ARG, 0, 3, "IAC SB MSDP", var, val, plain);
 		}
 		}
 		i++;
 		i++;
 	}
 	}
@@ -1244,8 +1245,9 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 
 
 					if (last)
 					if (last)
 					{
 					{
-						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, val);
-						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, val);
+						strip_vt102_codes(val, plain);
+						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
+						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, plain);
 					}
 					}
 					pto = var;
 					pto = var;
 				}
 				}
@@ -1277,8 +1279,9 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 
 
 					if (last != MSDP_VAR)
 					if (last != MSDP_VAR)
 					{
 					{
-						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, val);
-						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, val);
+						strip_vt102_codes(val, plain);
+						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
+						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, plain);
 					}
 					}
 					pto = val;
 					pto = val;
 				}
 				}
@@ -1322,8 +1325,9 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 
 
 		if (last)
 		if (last)
 		{
 		{
-			check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, val);
-			check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, val);
+			strip_vt102_codes(val, plain);
+			check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
+			check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, plain);
 		}
 		}
 		i++;
 		i++;
 	}
 	}
@@ -1394,7 +1398,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 			{
 			{
 				if (!strcasecmp(var, "UTF-8"))
 				if (!strcasecmp(var, "UTF-8"))
 				{
 				{
-					if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_BIG5TOUTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_FANSITOUTF8))
+					if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 					{
 					{
 						telnet_printf(ses, 12, "%c%c%c%c UTF-8%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
 						telnet_printf(ses, 12, "%c%c%c%c UTF-8%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
 
 
@@ -1440,6 +1444,60 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 						}
 						}
 					}
 					}
 				}
 				}
+				else if (!strcasecmp(var, "ISO-8859-1") || !strcasecmp(var, "ISO-1"))
+				{
+					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					{
+						if (HAS_BIT(ses->charset, CHARSET_FLAG_ISO1TOUTF8))
+						{
+							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, var, IAC, SE);
+							
+							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED %s", var);
+						}
+						else
+						{
+							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, var, IAC, SE);
+
+							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED %s", var);
+						}
+					}
+				}
+				else if (!strcasecmp(var, "ISO-8859-2") || !strcasecmp(var, "ISO-2"))
+				{
+					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					{
+						if (HAS_BIT(ses->charset, CHARSET_FLAG_ISO2TOUTF8))
+						{
+							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, var, IAC, SE);
+							
+							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED %s", var);
+						}
+						else
+						{
+							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, var, IAC, SE);
+
+							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED %s", var);
+						}
+					}
+				}
+				else if (!strcasecmp(var, "GBK-1"))
+				{
+					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					{
+						if (HAS_BIT(ses->charset, CHARSET_FLAG_GBK1TOUTF8))
+						{
+							telnet_printf(ses, 11, "%c%c%c%c GBK-1%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
+
+							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED GBK-1");
+						}
+						else
+						{
+							telnet_printf(ses, 11, "%c%c%c%c GB-18030%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
+
+							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED GBK-1");
+						}
+					}
+				}
 			}
 			}
 		}
 		}
 		i++;
 		i++;
@@ -1456,6 +1514,26 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 	NEW-ENVIRON
 	NEW-ENVIRON
 */
 */
 
 
+int get_mtts_val(struct session *ses)
+{
+	return
+		(ses->color > 0 ? 1 : 0)
+		+
+		(HAS_BIT(ses->flags, SES_FLAG_SPLIT) ? 0 : 2)
+		+
+		(HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8) ? 4 : 0)
+		+
+		(ses->color > 16 ? 8 : 0)
+		+
+		(HAS_BIT(ses->flags, SES_FLAG_SCREENREADER) ? 64 : 0)
+		+
+//		proxy ? 128 : 0
+//		+
+		(ses->color > 256 ? 256 : 0)
+		+
+		512;
+}
+
 int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *src)
 int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *src)
 {
 {
 	char buf[BUFFER_SIZE], var[BUFFER_SIZE], val[BUFFER_SIZE], sub1[NUMBER_SIZE], sub2[NUMBER_SIZE];
 	char buf[BUFFER_SIZE], var[BUFFER_SIZE], val[BUFFER_SIZE], sub1[NUMBER_SIZE], sub2[NUMBER_SIZE];
@@ -1526,8 +1604,57 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 				{
 				{
 					client_telopt_debug(ses, "IAC SB NEW-ENVIRON SEND %s", sub2);
 					client_telopt_debug(ses, "IAC SB NEW-ENVIRON SEND %s", sub2);
 
 
-					check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, "");
-					check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, "");
+					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "CATCH IAC SB NEW-ENVIRON", sub1, sub2, var, ""))
+					{
+						check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, "");
+
+						if (!check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "CATCH IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, ""))
+						{
+							check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, "");
+
+							if (*var == 0)
+							{
+								telnet_printf(ses, -1, "%c%c%c" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c",
+									IAC, SB, TELOPT_NEW_ENVIRON,
+									ENV_IS, ENV_VAR, "CHARSET", ENV_VAL, get_charset(ses),
+									ENV_IS, ENV_VAR, "CLIENT_NAME", ENV_VAL, CLIENT_NAME,
+									ENV_IS, ENV_VAR, "CLIENT_VERSION", ENV_VAL, CLIENT_VERSION,
+									ENV_IS, ENV_VAR, "MTTS", ENV_VAL, get_mtts_val(ses),
+									ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term,
+									IAC, SE);
+							}
+							else if (!strcasecmp(var, "CHARSET"))
+							{
+								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "CHARSET", ENV_VAL, get_charset(ses), IAC, SE);
+
+								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CHARSET", get_charset(ses));
+							}
+							else if (!strcasecmp(var, "CLIENT_NAME"))
+							{
+								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "CLIENT_NAME", ENV_VAL, CLIENT_NAME, IAC, SE);
+
+								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_NAME", CLIENT_NAME);
+							}
+							else if (!strcasecmp(var, "CLIENT_VERSION"))
+							{
+								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "CLIENT_VERSION", ENV_VAL, CLIENT_VERSION, IAC, SE);
+
+								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_VERSION", CLIENT_VERSION);
+							}
+							else if (!strcasecmp(var, "MTTS") || *var == 0)
+							{
+								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%d%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "MTTS", ENV_VAL, get_mtts_val(ses), IAC, SE);
+
+								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR MTTS VAL %d", get_mtts_val(ses));
+							}
+							else if (!strcasecmp(var, "TERMINAL_TYPE"))
+							{
+								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term, IAC, SE);
+
+								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR TERMINAL_TYPE VAL %s", gtd->term);
+							}
+						}
+					}
 				}
 				}
 				break;
 				break;
 
 
@@ -1944,6 +2071,26 @@ int client_init_mccp2(struct session *ses, int cplen, unsigned char *cpsrc)
 	return 5;
 	return 5;
 }
 }
 
 
+void client_end_mccp2(struct session *ses)
+{
+	if (ses->mccp2 == NULL)
+	{
+		return;
+	}
+
+	if (deflateEnd(ses->mccp2) != Z_OK)
+	{
+		tintin_printf2(ses, "MCCP2: FAILED TO DEFLATE_END");
+	}
+
+	free(ses->mccp2);
+
+	ses->mccp2 = NULL;
+
+	client_telopt_debug(ses, "MCCP2: COMPRESSION END, DISABLING MCCP2");
+
+	return;
+}
 
 
 
 
 // MCCP3
 // MCCP3
@@ -2034,6 +2181,7 @@ int client_init_mccp3(struct session *ses)
 	if (deflateInit(stream, Z_BEST_COMPRESSION) != Z_OK)
 	if (deflateInit(stream, Z_BEST_COMPRESSION) != Z_OK)
 	{
 	{
 		client_telopt_debug(ses, "MCCP3: FAILED TO INITIALIZE");
 		client_telopt_debug(ses, "MCCP3: FAILED TO INITIALIZE");
+
 		free(stream);
 		free(stream);
 
 
 		return FALSE;
 		return FALSE;

+ 39 - 3
src/terminal.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2006                       *
 *                      coded by Igor van den Hoven 2006                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -98,6 +97,7 @@ void reset_terminal(struct session *ses)
 	{
 	{
 		print_stdout("\e[?1000l\e[?1002l\e[?1004l\e[?1006l");
 		print_stdout("\e[?1000l\e[?1002l\e[?1004l\e[?1006l");
 	}
 	}
+	print_stdout("\e[?25h");
 	print_stdout("\e[23t");
 	print_stdout("\e[23t");
 	print_stdout("\e[>4n");
 	print_stdout("\e[>4n");
 }
 }
@@ -201,3 +201,39 @@ int get_scroll_cols(struct session *ses)
 {
 {
 	return ses->wrap;
 	return ses->wrap;
 }
 }
+
+char *get_charset(struct session *ses)
+{
+	switch (HAS_BIT(ses->charset, CHARSET_FLAG_ALL))
+	{
+		case CHARSET_FLAG_BIG5:
+			return "BIG-5";
+
+		case CHARSET_FLAG_GBK1:
+			return "GBK-1";
+
+		case CHARSET_FLAG_UTF8:
+			return "UTF-8";
+
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8:
+			return "BIG5TOUTF8";
+
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8:
+			return "FANSI";
+		
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_GBK1TOUTF8:
+			return "GBK1TOUTF8";
+
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_KOI8TOUTF8:
+			return "KOI8TOUTF8";
+
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO1TOUTF8:
+			return "ISO1TOUTF8";
+
+		case CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO2TOUTF8:
+			return "ISO2TOUTF8";
+
+		default:
+			return "ASCII";
+	}
+}

+ 74 - 68
src/text.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -122,7 +121,7 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 {
 {
 	char color[COLOR_SIZE] = { 0 };
 	char color[COLOR_SIZE] = { 0 };
 	char *pti, *pto, *lis, *los, *chi, *cho;
 	char *pti, *pto, *lis, *los, *chi, *cho;
-	int cur_height, cur_width, size, skip, lines, cur_col, tab, wrap;
+	int cur_height, cur_width, size, i, skip, lines, cur_col, tab, wrap, cur_space;
 
 
 	push_call("word_wrap(%s,%p,%p)",ses->name,textin,textout);
 	push_call("word_wrap(%s,%p,%p)",ses->name,textin,textout);
 
 
@@ -145,18 +144,27 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 
 
 	while (*pti && pto - textout < BUFFER_SIZE)
 	while (*pti && pto - textout < BUFFER_SIZE)
 	{
 	{
-		if (skip_vt102_codes(pti))
-		{
-			get_color_codes(color, pti, color, GET_ONE);
+		skip = skip_vt102_codes(pti);
 
 
-			if (HAS_BIT(flags, WRAP_FLAG_DISPLAY))
+		if (skip)
+		{
+			if (ses->color)
 			{
 			{
-				interpret_vt102_codes(ses, pti, TRUE);
-			}
+				get_color_codes(color, pti, color, GET_ONE);
 
 
-			for (skip = skip_vt102_codes(pti) ; skip > 0 ; skip--)
+				if (HAS_BIT(flags, WRAP_FLAG_DISPLAY))
+				{
+					interpret_vt102_codes(ses, pti, TRUE);
+				}
+
+				for (i = 0 ; i < skip ; i++)
+				{
+					*pto++ = *pti++;
+				}
+			}
+			else
 			{
 			{
-				*pto++ = *pti++;
+				pti += skip;
 			}
 			}
 			continue;
 			continue;
 		}
 		}
@@ -183,24 +191,25 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 
 
 			cur_width    = 0;
 			cur_width    = 0;
 			ses->cur_col = 1;
 			ses->cur_col = 1;
+			cur_space    = 1;
 
 
 			continue;
 			continue;
 		}
 		}
 
 
-		if (*pti == ' ')
+		if (*pti == ' ' || *pti == '\t')
 		{
 		{
+			cur_space = ses->cur_col;
 			los = pto;
 			los = pto;
 			lis = pti;
 			lis = pti;
 		}
 		}
 
 
 		if (ses->cur_col > wrap)
 		if (ses->cur_col > wrap)
 		{
 		{
-			ses->cur_col = 1;
 			cur_height++;
 			cur_height++;
 
 
 			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
 			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
 			{
 			{
-				if (pto - los >= 15 || wrap <= 20 || !SCROLL(ses))
+				if (ses->cur_col - cur_space >= 15 || wrap <= 20 || !SCROLL(ses))
 				{
 				{
 					*pto++ = '\n';
 					*pto++ = '\n';
 					pto += sprintf(pto, "%s", color);
 					pto += sprintf(pto, "%s", color);
@@ -228,16 +237,21 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 			{
 			{
 				*pto++ = '\n';
 				*pto++ = '\n';
 			}
 			}
+			ses->cur_col = 1;
+			cur_space = 1;
 		}
 		}
 		else
 		else
 		{
 		{
-			if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+			if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 			{
 			{
-				*pto++ = *pti++;
-				*pto++ = *pti++;
+				size = get_euc_width(ses, pti, &tab);
 
 
-				cur_width += 2;
-				ses->cur_col += 2;
+				while (size--)
+				{
+					*pto++ = *pti++;
+				}
+				cur_width += tab;
+				ses->cur_col += tab;
 			}
 			}
 			else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 			else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 			{
 			{
@@ -258,14 +272,12 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 				{
 				{
 					tab = (wrap - ses->cur_col);
 					tab = (wrap - ses->cur_col);
 				}
 				}
-				pto += sprintf(pto, "%.*s", tab, "        ");
+				pto += sprintf(pto, "%.*s", tab, "                ");
 				pti++;
 				pti++;
 
 
 				cur_width += tab;
 				cur_width += tab;
 				ses->cur_col += tab;
 				ses->cur_col += tab;
-
-				los = pto;
-				lis = pti;
+				cur_space = ses->cur_col;
 			}
 			}
 			else
 			else
 			{
 			{
@@ -297,7 +309,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 {
 {
 	char color[COLOR_SIZE] = { 0 };
 	char color[COLOR_SIZE] = { 0 };
 	char *pti, *pto, *lis, *los;
 	char *pti, *pto, *lis, *los;
-	int cur_height, size, i, lines, cur_col, cur_width, tab;
+	int cur_height, size, i, lines, cur_col, cur_width, tab, skip, cur_space;
 
 
 	push_call("word_wrap_split(%s,%p,%p,%d,%d,%d,%d)",ses->name,textin,textout,wrap,start,end,flags);
 	push_call("word_wrap_split(%s,%p,%p,%d,%d,%d,%d)",ses->name,textin,textout,wrap,start,end,flags);
 
 
@@ -330,31 +342,33 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 
 
 	while (*pti && pto - textout < BUFFER_SIZE - 20)
 	while (*pti && pto - textout < BUFFER_SIZE - 20)
 	{
 	{
-		push_call("skip");
-
-		if (cur_height > 10000 || cur_width > 10000)
+		if (cur_height > 10000 || cur_width > 100000)
 		{
 		{
-			print_stdout("debug: word_wrap_split: infinite loop?\n");
+			print_stdout("debug: word_wrap_split: wrap %d height %d width %d los %d start %d end %d\n", wrap, cur_height, cur_width, pto - los, start, end);
 			pop_call();
 			pop_call();
-			return 1;			
+			return 1;
 		}
 		}
-		tab = skip_vt102_codes(pti);
 
 
-		if (tab)
+		skip = skip_vt102_codes(pti);
+
+		if (skip)
 		{
 		{
-			get_color_codes(color, pti, color, GET_ONE);
+			if (ses->color)
+			{
+				get_color_codes(color, pti, color, GET_ONE);
 
 
-			for (i = 0 ; i < tab ; i++)
+				for (i = 0 ; i < skip ; i++)
+				{
+					*pto++ = *pti++;
+				}
+			}
+			else
 			{
 			{
-				*pto++ = *pti++;
+				pti += skip;
 			}
 			}
-			pop_call();
 			continue;
 			continue;
 		}
 		}
 
 
-		pop_call();
-		push_call("nl");
-
 		if (*pti == '\n')
 		if (*pti == '\n')
 		{
 		{
 			lines++;
 			lines++;
@@ -386,33 +400,26 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 			}
 			}
 
 
 			cur_col = 1;
 			cur_col = 1;
+			cur_space = 1;
 			cur_width = 0;
 			cur_width = 0;
-			pop_call();
 			continue;
 			continue;
 		}
 		}
 
 
 		if (*pti == ' ' || *pti == '\t')
 		if (*pti == ' ' || *pti == '\t')
 		{
 		{
+			cur_space = cur_col;
 			lis = pti;
 			lis = pti;
 			los = pto;
 			los = pto;
 		}
 		}
 
 
-		pop_call();
-		push_call("wrap");
-
 		if (cur_col > wrap)
 		if (cur_col > wrap)
 		{
 		{
-			cur_col = 1;
-
 			cur_height++;
 			cur_height++;
 
 
 			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
 			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
 			{
 			{
-				if (pto - los > 15 || wrap <= 20)
+				if (cur_col - cur_space > 15 || wrap <= 20)
 				{
 				{
-					los = pto;
-					lis = pti;
-
 					if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
 					if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
 					{
 					{
 						*pto++ = '\n';
 						*pto++ = '\n';
@@ -421,6 +428,8 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 					if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
 					if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
 					{
 					{
 						pto += sprintf(pto, "%s", color);
 						pto += sprintf(pto, "%s", color);
+//						pto += sprintf(pto, "%s(%d,%d,%d)", color, start, end, cur_height);
+
 					}
 					}
 				}
 				}
 				else
 				else
@@ -438,13 +447,11 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 						pto += sprintf(pto, "%s", color);
 						pto += sprintf(pto, "%s", color);
 
 
 					}
 					}
+					pti++;
 				}
 				}
 			}
 			}
 			else
 			else
 			{
 			{
-				los = pto;
-				lis = pti;
-
 				if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
 				if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
 				{
 				{
 					*pto++ = '\n';
 					*pto++ = '\n';
@@ -455,26 +462,28 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 					pto += sprintf(pto, "%s", color);
 					pto += sprintf(pto, "%s", color);
 				}
 				}
 			}
 			}
-			pop_call();
+			cur_col = 1;
+			cur_space = 1;
 			continue;
 			continue;
 		}
 		}
 
 
-		pop_call();
-		push_call("default");
-
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && is_big5(pti))
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
 		{
+			size = get_euc_width(ses, pti, &tab);
+
 			if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
 			if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
 			{
 			{
-				*pto++ = *pti++;
-				*pto++ = *pti++;
+				while (size--)
+				{
+					*pto++ = *pti++;
+				}
 			}
 			}
 			else
 			else
 			{
 			{
-				pti += 2;
+				pti += size;
 			}
 			}
-			cur_width += 2;
-			cur_col += 2;
+			cur_width += tab;
+			cur_col += tab;
 		}
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 		{
 		{
@@ -508,10 +517,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 		{
 		{
 			if (*pti == '\t')
 			if (*pti == '\t')
 			{
 			{
-				los = pto;
-				lis = pti;
-
-				tab = ses->tab_width - (ses->cur_col - 1) % ses->tab_width;
+				tab = ses->tab_width - (cur_col - 1) % ses->tab_width;
 
 
 				if (cur_col + tab >= wrap)
 				if (cur_col + tab >= wrap)
 				{
 				{
@@ -520,12 +526,13 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 
 
 				if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
 				if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
 				{
 				{
-					pto += sprintf(pto, "%.*s", tab, "        ");
+					pto += sprintf(pto, "%.*s", tab, "                ");
 				}
 				}
 				pti++;
 				pti++;
 
 
 				cur_width += tab;
 				cur_width += tab;
 				cur_col += tab;
 				cur_col += tab;
+				cur_space = cur_col;
 			}
 			}
 			else
 			else
 			{
 			{
@@ -541,7 +548,6 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 				cur_col++;
 				cur_col++;
 			}
 			}
 		}
 		}
-		pop_call();
 	}
 	}
 	*pto = 0;
 	*pto = 0;
 
 

+ 264 - 105
src/tintin.h

@@ -142,6 +142,7 @@
 
 
 #define ASCII_NUL                        0
 #define ASCII_NUL                        0
 #define ASCII_ENQ                        5 // Ignore if possible
 #define ASCII_ENQ                        5 // Ignore if possible
+#define ASCII_HTML_AMP                   6 // Might conflict with VTON
 #define ASCII_BEL                        7
 #define ASCII_BEL                        7
 #define ASCII_BS                         8
 #define ASCII_BS                         8
 #define ASCII_HTAB                       9
 #define ASCII_HTAB                       9
@@ -150,6 +151,9 @@
 #define ASCII_FF                        12
 #define ASCII_FF                        12
 #define ASCII_CR                        13
 #define ASCII_CR                        13
 #define ASCII_ESC                       27
 #define ASCII_ESC                       27
+#define ASCII_HTML_OPEN                 28 // Also file separator, whatever that is
+#define ASCII_HTML_CLOSE                30 // Also record separator, whatever that is
+
 #define ASCII_DEL                      127
 #define ASCII_DEL                      127
 
 
 #define DAEMON_DIR               "daemons"
 #define DAEMON_DIR               "daemons"
@@ -157,16 +161,18 @@
 
 
 #define HISTORY_FILE         "history.txt"
 #define HISTORY_FILE         "history.txt"
 
 
-#define STRING_SIZE                  64000
-#define BUFFER_SIZE                  30000
+#define STRING_SIZE                  50000
+#define BUFFER_SIZE                  24000
+#define INPUT_SIZE                   10000
 #define STACK_SIZE                    1000
 #define STACK_SIZE                    1000
 #define NUMBER_SIZE                    100
 #define NUMBER_SIZE                    100
 #define LEGEND_SIZE                     50
 #define LEGEND_SIZE                     50
 #define COLOR_SIZE                      50
 #define COLOR_SIZE                      50
+#define CHAR_SIZE                        5
 #define LIST_SIZE                        2
 #define LIST_SIZE                        2
 
 
 #define CLIENT_NAME              "TinTin++"
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.01.92 "
+#define CLIENT_VERSION           "2.02.00 "
 
 
 #define XT_E                            0x27
 #define XT_E                            0x27
 #define XT_C                            0x5B
 #define XT_C                            0x5B
@@ -249,15 +255,17 @@
 #define LIST_GAG                         9
 #define LIST_GAG                         9
 #define LIST_HIGHLIGHT                  10
 #define LIST_HIGHLIGHT                  10
 #define LIST_HISTORY                    11
 #define LIST_HISTORY                    11
-#define LIST_MACRO                      12
-#define LIST_PATH                       13
-#define LIST_PATHDIR                    14
-#define LIST_PROMPT                     15
-#define LIST_SUBSTITUTE                 16
-#define LIST_TAB                        17
-#define LIST_TICKER                     18
-#define LIST_VARIABLE                   19
-#define LIST_MAX                        20
+#define LIST_LANDMARK                   12
+#define LIST_MACRO                      13
+#define LIST_PATH                       14
+#define LIST_PATHDIR                    15
+#define LIST_PROMPT                     16
+#define LIST_SUBSTITUTE                 17
+#define LIST_TAB                        18
+#define LIST_TERRAIN                    19
+#define LIST_TICKER                     20
+#define LIST_VARIABLE                   21
+#define LIST_MAX                        22
 
 
 /*
 /*
 	Command type
 	Command type
@@ -335,12 +343,23 @@ enum operators
 
 
 #define BUFFER_FLAG_GREP              BV01
 #define BUFFER_FLAG_GREP              BV01
 
 
-#define CHARSET_FLAG_BIG5                 BV27
-#define CHARSET_FLAG_UTF8                 BV28
-#define CHARSET_FLAG_BIG5TOUTF8           BV29
-#define CHARSET_FLAG_KOI8TOUTF8           BV30
-#define CHARSET_FLAG_FANSITOUTF8          BV31
-#define CHARSET_FLAG_ALL                  CHARSET_FLAG_BIG5|CHARSET_FLAG_UTF8|CHARSET_FLAG_KOI8TOUTF8|CHARSET_FLAG_BIG5TOUTF8|CHARSET_FLAG_FANSITOUTF8
+
+#define CHARSET_FLAG_UTF8                 BV01
+#define CHARSET_FLAG_BIG5                 BV02
+#define CHARSET_FLAG_GBK1                 BV03
+
+#define CHARSET_FLAG_BIG5TOUTF8           BV04
+#define CHARSET_FLAG_FANSITOUTF8          BV05
+#define CHARSET_FLAG_GBK1TOUTF8           BV06
+#define CHARSET_FLAG_ISO1TOUTF8           BV07
+#define CHARSET_FLAG_ISO2TOUTF8           BV08
+#define CHARSET_FLAG_KOI8TOUTF8           BV09
+
+
+#define CHARSET_FLAG_EUC                  CHARSET_FLAG_BIG5|CHARSET_FLAG_GBK1
+#define CHARSET_FLAG_ALL_TOUTF8           CHARSET_FLAG_BIG5TOUTF8|CHARSET_FLAG_FANSITOUTF8|CHARSET_FLAG_GBK1TOUTF8|CHARSET_FLAG_ISO1TOUTF8|CHARSET_FLAG_ISO2TOUTF8|CHARSET_FLAG_KOI8TOUTF8
+#define CHARSET_FLAG_ALL                  CHARSET_FLAG_UTF8|CHARSET_FLAG_ALL_TOUTF8|CHARSET_FLAG_EUC
+
 
 
 #define COL_BLD                       BV01
 #define COL_BLD                       BV01
 #define COL_UND                       BV02
 #define COL_UND                       BV02
@@ -408,29 +427,35 @@ enum operators
 
 
 #define DRAW_FLAG_NONE                   0
 #define DRAW_FLAG_NONE                   0
 #define DRAW_FLAG_ASCII               BV01
 #define DRAW_FLAG_ASCII               BV01
-#define DRAW_FLAG_UTF8                BV02
-#define DRAW_FLAG_CONVERT             BV03
-#define DRAW_FLAG_SCROLL              BV04
-#define DRAW_FLAG_COLOR               BV05
-#define DRAW_FLAG_BLANKED             BV06
-#define DRAW_FLAG_NUMBERED            BV07
-#define DRAW_FLAG_BOXED               BV08
-#define DRAW_FLAG_CROSSED             BV09
-#define DRAW_FLAG_PRUNED              BV10
-#define DRAW_FLAG_ROUNDED             BV11
-#define DRAW_FLAG_TEED                BV12
-#define DRAW_FLAG_CORNERED            BV13
-#define DRAW_FLAG_HOR                 BV14
-#define DRAW_FLAG_VER                 BV15
+#define DRAW_FLAG_BLANKED             BV02
+#define DRAW_FLAG_BOT                 BV03
+#define DRAW_FLAG_BOXED               BV04
+#define DRAW_FLAG_BUMP                BV05
+#define DRAW_FLAG_CIRCLED             BV06
+#define DRAW_FLAG_COLOR               BV07
+#define DRAW_FLAG_CONVERT             BV08
+#define DRAW_FLAG_COPY                BV30 // new
+#define DRAW_FLAG_CORNERED            BV09
+#define DRAW_FLAG_CROSSED             BV10
+#define DRAW_FLAG_FILLED              BV11
+#define DRAW_FLAG_GRID                BV12
+#define DRAW_FLAG_HOR                 BV13
+#define DRAW_FLAG_HUGE                BV14
+#define DRAW_FLAG_JEWELED             BV15
 #define DRAW_FLAG_LEFT                BV16
 #define DRAW_FLAG_LEFT                BV16
-#define DRAW_FLAG_RIGHT               BV17
-#define DRAW_FLAG_TOP                 BV18
-#define DRAW_FLAG_BOT                 BV19
-#define DRAW_FLAG_BUMP                BV20
-#define DRAW_FLAG_CIRCLED             BV21
-#define DRAW_FLAG_JEWELED             BV22
-#define DRAW_FLAG_FILLED              BV23
-#define DRAW_FLAG_TUBED               BV24
+#define DRAW_FLAG_LINED               BV17
+#define DRAW_FLAG_NUMBERED            BV18
+#define DRAW_FLAG_PRUNED              BV19
+#define DRAW_FLAG_RIGHT               BV20 
+#define DRAW_FLAG_ROUNDED             BV21
+#define DRAW_FLAG_SCROLL              BV22
+#define DRAW_FLAG_SHADOWED            BV23
+#define DRAW_FLAG_TEED                BV24
+#define DRAW_FLAG_TOP                 BV25
+#define DRAW_FLAG_TRACED              BV26
+#define DRAW_FLAG_TUBED               BV27
+#define DRAW_FLAG_UTF8                BV28
+#define DRAW_FLAG_VER                 BV29
 
 
 
 
 #define EVENT_FLAG_CATCH              BV01
 #define EVENT_FLAG_CATCH              BV01
@@ -515,14 +540,16 @@ enum operators
 #define SUB_CMP                       (1 << 10)
 #define SUB_CMP                       (1 << 10)
 #define SUB_LIT                       (1 << 11)
 #define SUB_LIT                       (1 << 11)
 
 
+#define TAB_FLAG_FORWARD              BV01
+#define TAB_FLAG_BACKWARD             BV02
+#define TAB_FLAG_LIST                 BV03
+#define TAB_FLAG_SCROLLBACK           BV04
+
 #define REGEX_FLAG_NONE               0
 #define REGEX_FLAG_NONE               0
 #define REGEX_FLAG_FIX                (1 <<  0)
 #define REGEX_FLAG_FIX                (1 <<  0)
 #define REGEX_FLAG_ARG                (1 <<  1)
 #define REGEX_FLAG_ARG                (1 <<  1)
 #define REGEX_FLAG_CMD                (1 <<  2)
 #define REGEX_FLAG_CMD                (1 <<  2)
 
 
-#define WRAP_FLAG_DISPLAY             (1 <<  0)
-#define WRAP_FLAG_WORD                (1 <<  1)
-#define WRAP_FLAG_SPLIT               (1 <<  2)
 
 
 
 
 //#define TINTIN_FLAG_RESETBUFFER       (1 <<  0)
 //#define TINTIN_FLAG_RESETBUFFER       (1 <<  0)
@@ -538,6 +565,8 @@ enum operators
 #define TINTIN_FLAG_MOUSETRACKING     (1 <<  9)
 #define TINTIN_FLAG_MOUSETRACKING     (1 <<  9)
 #define TINTIN_FLAG_FLUSH             (1 << 10)
 #define TINTIN_FLAG_FLUSH             (1 << 10)
 #define TINTIN_FLAG_DAEMONIZE         (1 << 11)
 #define TINTIN_FLAG_DAEMONIZE         (1 << 11)
+#define TINTIN_FLAG_HIDDENCURSOR      (1 << 12)
+#define TINTIN_FLAG_LOCAL             (1 << 13)
 
 
 #define SES_FLAG_ECHOCOMMAND          BV01
 #define SES_FLAG_ECHOCOMMAND          BV01
 #define SES_FLAG_SNOOP                BV02
 #define SES_FLAG_SNOOP                BV02
@@ -627,19 +656,23 @@ enum operators
 #define ROOM_FLAG_PATH                BV07
 #define ROOM_FLAG_PATH                BV07
 #define ROOM_FLAG_NOGLOBAL            BV08
 #define ROOM_FLAG_NOGLOBAL            BV08
 #define ROOM_FLAG_INVIS               BV09
 #define ROOM_FLAG_INVIS               BV09
-#define ROOM_FLAG_AVOID_TMP           BV10|ROOM_FLAG_AVOID
+
+#define ROOM_FLAG_AVOID_TMP           BV10|ROOM_FLAG_AVOID // To realign exit and room flags in the future.
 #define ROOM_FLAG_HIDE_TMP            BV11|ROOM_FLAG_HIDE
 #define ROOM_FLAG_HIDE_TMP            BV11|ROOM_FLAG_HIDE
 #define ROOM_FLAG_LEAVE_TMP           BV12|ROOM_FLAG_LEAVE
 #define ROOM_FLAG_LEAVE_TMP           BV12|ROOM_FLAG_LEAVE
 #define ROOM_FLAG_VOID_TMP            BV13|ROOM_FLAG_VOID
 #define ROOM_FLAG_VOID_TMP            BV13|ROOM_FLAG_VOID
 #define ROOM_FLAG_STATIC_TMP          BV13|ROOM_FLAG_STATIC
 #define ROOM_FLAG_STATIC_TMP          BV13|ROOM_FLAG_STATIC
 #define ROOM_FLAG_CURVED_TMP          BV14|ROOM_FLAG_CURVED
 #define ROOM_FLAG_CURVED_TMP          BV14|ROOM_FLAG_CURVED
+#define ROOM_FLAG_BLOCK               BV15
+#define ROOM_FLAG_TERRAIN             BV20
 
 
 // keep synced with room flags
 // keep synced with room flags
 
 
 #define EXIT_FLAG_HIDE                BV01
 #define EXIT_FLAG_HIDE                BV01
 #define EXIT_FLAG_AVOID               BV02
 #define EXIT_FLAG_AVOID               BV02
 #define EXIT_FLAG_INVIS               BV03
 #define EXIT_FLAG_INVIS               BV03
-#define EXIT_FLAG_ALL                 BV01|BV02|BV03
+#define EXIT_FLAG_BLOCK               BV04
+#define EXIT_FLAG_ALL                 BV01|BV02|BV03|BV04
 
 
 #define EXIT_GRID_0                     0
 #define EXIT_GRID_0                     0
 #define EXIT_GRID_N                     1
 #define EXIT_GRID_N                     1
@@ -653,9 +686,6 @@ enum operators
 #define EXIT_GRID_SE                    9
 #define EXIT_GRID_SE                    9
 #define EXIT_GRID_SW                   10
 #define EXIT_GRID_SW                   10
 
 
-#define GRID_FLAG_HIDE                BV02
-#define GRID_FLAG_INVIS               BV03
-
 #define MAP_FLAG_STATIC               BV01
 #define MAP_FLAG_STATIC               BV01
 #define MAP_FLAG_VTMAP                BV02
 #define MAP_FLAG_VTMAP                BV02
 #define MAP_FLAG_DIRECTION            BV03
 #define MAP_FLAG_DIRECTION            BV03
@@ -667,6 +697,11 @@ enum operators
 #define MAP_FLAG_UNICODEGRAPHICS      BV09
 #define MAP_FLAG_UNICODEGRAPHICS      BV09
 #define MAP_FLAG_BLOCKGRAPHICS        BV10
 #define MAP_FLAG_BLOCKGRAPHICS        BV10
 #define MAP_FLAG_RESIZE               BV11
 #define MAP_FLAG_RESIZE               BV11
+#define MAP_FLAG_SYNC                 BV12
+#define MAP_FLAG_ASCIILENGTH          BV13 // For debugging but might be useful
+#define MAP_FLAG_TERRAIN              BV14
+#define MAP_FLAG_UPDATETERRAIN        BV15
+#define MAP_FLAG_DOUBLED              BV16
 
 
 #define MAP_SEARCH_NAME                0
 #define MAP_SEARCH_NAME                0
 #define MAP_SEARCH_EXITS               1
 #define MAP_SEARCH_EXITS               1
@@ -702,10 +737,17 @@ enum operators
 #define MAP_UNDO_LINK                 (1 <<  2)
 #define MAP_UNDO_LINK                 (1 <<  2)
 #define MAP_UNDO_INSERT               (1 <<  3)
 #define MAP_UNDO_INSERT               (1 <<  3)
 
 
-#define STR_HASH_FLAG_NOGREP          (1 <<  0)
-
-#define MAX_STR_HASH                  50000
-
+#define TERRAIN_FLAG_DENSE            BV01
+#define TERRAIN_FLAG_AMPLE            BV02
+#define TERRAIN_FLAG_SPARSE           BV03
+#define TERRAIN_FLAG_SCANT            BV04
+#define TERRAIN_FLAG_NARROW           BV05
+#define TERRAIN_FLAG_STANDARD         BV06
+#define TERRAIN_FLAG_WIDE             BV07
+#define TERRAIN_FLAG_VAST             BV08
+#define TERRAIN_FLAG_FADEIN           BV09
+#define TERRAIN_FLAG_FADEOUT          BV10
+#define TERRAIN_FLAG_DOUBLE           BV11
 
 
 #define MOUSE_FLAG_BUTTON_A             1
 #define MOUSE_FLAG_BUTTON_A             1
 #define MOUSE_FLAG_BUTTON_B             2
 #define MOUSE_FLAG_BUTTON_B             2
@@ -728,6 +770,9 @@ enum operators
 #define STARTUP_FLAG_ARGUMENT           8
 #define STARTUP_FLAG_ARGUMENT           8
 #define STARTUP_FLAG_NOTITLE           16
 #define STARTUP_FLAG_NOTITLE           16
 
 
+#define WRAP_FLAG_DISPLAY             (1 <<  0)
+#define WRAP_FLAG_WORD                (1 <<  1)
+#define WRAP_FLAG_SPLIT               (1 <<  2)
 
 
 #define LEGEND_ASCII                    0
 #define LEGEND_ASCII                    0
 #define LEGEND_ASCII_MISC              16
 #define LEGEND_ASCII_MISC              16
@@ -741,18 +786,40 @@ enum operators
 #define LEGEND_MUDFONT_NWS             64
 #define LEGEND_MUDFONT_NWS             64
 #define LEGEND_MUDFONT_NES             96
 #define LEGEND_MUDFONT_NES             96
 #define LEGEND_MUDFONT_CURVED         192
 #define LEGEND_MUDFONT_CURVED         192
-#define LEGEND_MAX                    200
+#define LEGEND_UNICODE_GRAPHICS       196
+#define LEGEND_MAX                    230
+
+#define UNICODE_DIR_SE                  1
+#define UNICODE_DIR_NE                  2
+#define UNICODE_DIR_SW                  4
+#define UNICODE_DIR_NW                  8
+#define UNICODE_DIR_D                  16
+#define UNICODE_DIR_N                  17
+#define UNICODE_DIR_S                  18
+#define UNICODE_DIR_NS                 19
+#define UNICODE_DIR_U                  20
+#define UNICODE_DIR_E                  21
+#define UNICODE_DIR_W                  22
+#define UNICODE_DIR_EW                 23
+#define UNICODE_DIR_RL                 24
+#define UNICODE_DIR_RL_CURVED          25
+#define UNICODE_DIR_RR                 26
+#define UNICODE_DIR_RR_CURVED          27
+
+
 
 
 #define MAP_COLOR_AVOID                 0
 #define MAP_COLOR_AVOID                 0
 #define MAP_COLOR_BACK                  1
 #define MAP_COLOR_BACK                  1
-#define MAP_COLOR_EXIT                  2
-#define MAP_COLOR_HIDE                  3
-#define MAP_COLOR_INVIS                 4
-#define MAP_COLOR_PATH                  5
-#define MAP_COLOR_ROOM                  6
-#define MAP_COLOR_SYMBOL                7
-#define MAP_COLOR_USER                  8
-#define MAP_COLOR_MAX                   9
+#define MAP_COLOR_BLOCK                 2
+#define MAP_COLOR_EXIT                  3
+#define MAP_COLOR_HIDE                  4
+#define MAP_COLOR_INVIS                 5
+#define MAP_COLOR_PATH                  6
+#define MAP_COLOR_ROOM                  7
+#define MAP_COLOR_SYMBOL                8
+#define MAP_COLOR_USER                  9
+#define MAP_COLOR_MAX                   10
+
 
 
 /*
 /*
 	Some macros to deal with double linked lists
 	Some macros to deal with double linked lists
@@ -880,7 +947,7 @@ enum operators
 #define DO_ARRAY(array) struct session *array (struct session *ses, struct listnode *list, char *arg, char *var)
 #define DO_ARRAY(array) struct session *array (struct session *ses, struct listnode *list, char *arg, char *var)
 #define DO_BUFFER(buffer) void buffer (struct session *ses, char *arg)
 #define DO_BUFFER(buffer) void buffer (struct session *ses, char *arg)
 #define DO_CHAT(chat) void chat (char *arg1, char *arg2)
 #define DO_CHAT(chat) void chat (char *arg1, char *arg2)
-#define DO_CLASS(class) struct session *class (struct session *ses, char *arg1, char *arg2)
+#define DO_CLASS(class) struct session *class (struct session *ses, struct listnode *node, char *arg1, char *arg2)
 #define DO_COMMAND(command) struct session  *command (struct session *ses, char *arg)
 #define DO_COMMAND(command) struct session  *command (struct session *ses, char *arg)
 #define DO_CONFIG(config) struct session *config (struct session *ses, char *arg1, char *arg2, int index)
 #define DO_CONFIG(config) struct session *config (struct session *ses, char *arg1, char *arg2, int index)
 #define DO_CURSOR(cursor) void cursor (struct session *ses, char *arg)
 #define DO_CURSOR(cursor) void cursor (struct session *ses, char *arg)
@@ -891,7 +958,7 @@ enum operators
 #define DO_PATH(path) void path (struct session *ses, char *arg)
 #define DO_PATH(path) void path (struct session *ses, char *arg)
 #define DO_PORT(port) struct session *port (struct session *ses, char *arg1, char *arg2, char *arg)
 #define DO_PORT(port) struct session *port (struct session *ses, char *arg1, char *arg2, char *arg)
 #define DO_SCREEN(screen) void screen (struct session *ses, int ind, char *arg, char *arg1, char *arg2)
 #define DO_SCREEN(screen) void screen (struct session *ses, int ind, char *arg, char *arg1, char *arg2)
-#define DO_DRAW(draw) void draw (struct session *ses, int top_row, int top_col, int bot_row, int bot_col, int rows, int cols, int flags, char *color, char *arg, char *arg1, char *arg2)
+#define DO_DRAW(draw) void draw (struct session *ses, int top_row, int top_col, int bot_row, int bot_col, int rows, int cols, long long flags, char *color, char *arg, char *arg1, char *arg2)
 
 
 /*
 /*
 	Compatibility
 	Compatibility
@@ -925,13 +992,24 @@ struct listnode
 	int                     flags;
 	int                     flags;
 	union
 	union
 	{
 	{
-		pcre          * regex;
-		long long       data;
-		short           val16[4];
-		int             val32[2];
+		pcre              * regex;      // act, alias, gag, highlight, substitute
+		char              * data;       // class
+		struct room_data  * room;       // terrain
+		long long           val64;      // delay, tick, path
+		short               val16[4];   // button
+		int                 val32[2];   // landmark, class
 	};
 	};
 };
 };
 
 
+struct scriptroot
+{
+	struct scriptnode    * next;
+	struct scriptnode    * prev;
+	struct session       * ses;
+	struct listroot      * local;
+	int list;
+};
+
 struct process_data
 struct process_data
 {
 {
 	pid_t                   pid;
 	pid_t                   pid;
@@ -950,6 +1028,7 @@ struct tintin_data
 	struct termios          old_terminal;
 	struct termios          old_terminal;
 	struct screen_data    * screen;
 	struct screen_data    * screen;
 	struct level_data     * level;
 	struct level_data     * level;
+	struct str_data       * memory;
 	char                  * detach_file;
 	char                  * detach_file;
 	int                     detach_port;
 	int                     detach_port;
 	struct process_data     detach_info;
 	struct process_data     detach_info;
@@ -984,17 +1063,20 @@ struct tintin_data
 	char                  * term;
 	char                  * term;
 	char                  * exec;
 	char                  * exec;
 	time_t                  time;
 	time_t                  time;
+	time_t                  time_input;
+	time_t                  time_session;
 	struct tm		calendar;
 	struct tm		calendar;
 	unsigned long long      utime;
 	unsigned long long      utime;
 	long long               timer[TIMER_CPU][5];
 	long long               timer[TIMER_CPU][5];
 	long long               total_io_ticks;
 	long long               total_io_ticks;
 	long long               total_io_exec;
 	long long               total_io_exec;
 	long long               total_io_delay;
 	long long               total_io_delay;
-	int                     str_size;
 	int                     history_size;
 	int                     history_size;
 	int                     command_ref[26];
 	int                     command_ref[26];
 	int                     msdp_table_size;
 	int                     msdp_table_size;
 	int                     flags;
 	int                     flags;
+	struct scriptroot     * script_stack[STACK_SIZE];
+	int                     script_index;
 	char                    tintin_char;
 	char                    tintin_char;
 	char                    verbatim_char;
 	char                    verbatim_char;
 	char                    repeat_char;
 	char                    repeat_char;
@@ -1025,6 +1107,8 @@ struct session
 	FILE                  * logline_file;
 	FILE                  * logline_file;
 	char                  * logline_name;
 	char                  * logline_name;
 	time_t                  logline_time;
 	time_t                  logline_time;
+	char                  * line_capturefile;
+	int                     line_captureindex;
 	struct listroot       * list[LIST_MAX];
 	struct listroot       * list[LIST_MAX];
 	int                     created;
 	int                     created;
 	int                     cur_row;
 	int                     cur_row;
@@ -1202,6 +1286,8 @@ struct msdp_data
 
 
 struct str_data
 struct str_data
 {
 {
+	struct str_data         * next;
+	struct str_data         * prev;
 	int                       max;
 	int                       max;
 	int                       len;
 	int                       len;
 };
 };
@@ -1245,7 +1331,6 @@ struct map_data
 {
 {
 	struct room_data     ** room_list;
 	struct room_data     ** room_list;
 	struct room_data     ** grid_rooms;
 	struct room_data     ** grid_rooms;
-	int                   * grid_flags;
 	FILE                  * logfile;
 	FILE                  * logfile;
 	struct link_data      * undo_head;
 	struct link_data      * undo_head;
 	struct link_data      * undo_tail;
 	struct link_data      * undo_tail;
@@ -1253,6 +1338,7 @@ struct map_data
 	char                  * buf;
 	char                  * buf;
 	char                  * out;
 	char                  * out;
 	char                    color[MAP_COLOR_MAX][COLOR_SIZE];
 	char                    color[MAP_COLOR_MAX][COLOR_SIZE];
+	char                    color_raw[MAP_COLOR_MAX][COLOR_SIZE];
 	int                     center_x;
 	int                     center_x;
 	int                     center_y;
 	int                     center_y;
 	int                     center_z;
 	int                     center_z;
@@ -1278,7 +1364,7 @@ struct map_data
 	int                     global_vnum;
 	int                     global_vnum;
 	struct exit_data      * global_exit;
 	struct exit_data      * global_exit;
 	int                     version;
 	int                     version;
-	int                     display_stamp;
+	short                   display_stamp;
 	int                     nofollow;
 	int                     nofollow;
 	char                    legend[LEGEND_MAX][LEGEND_SIZE];
 	char                    legend[LEGEND_MAX][LEGEND_SIZE];
 	char                    legend_raw[LEGEND_MAX][LEGEND_SIZE];
 	char                    legend_raw[LEGEND_MAX][LEGEND_SIZE];
@@ -1290,17 +1376,19 @@ struct room_data
 	struct exit_data        * l_exit;
 	struct exit_data        * l_exit;
 	struct exit_data        * exit_grid[11];
 	struct exit_data        * exit_grid[11];
 	int                       vnum;
 	int                       vnum;
-	int                       exit_size;
+	short                     exit_size;
 	long long                 exit_dirs;
 	long long                 exit_dirs;
 	float                     length;
 	float                     length;
 	float                     weight;
 	float                     weight;
-	int                       search_stamp;
-	int                       display_stamp;
+	short                     search_stamp;
+	short                     display_stamp;
 	int                       flags;
 	int                       flags;
 	int                       w;
 	int                       w;
 	int                       x;
 	int                       x;
 	int                       y;
 	int                       y;
 	int                       z;
 	int                       z;
+	int                       terrain_index;
+	short                     terrain_flags;
 	char                    * area;
 	char                    * area;
 	char                    * color;
 	char                    * color;
 	char                    * data;
 	char                    * data;
@@ -1324,6 +1412,7 @@ struct exit_data
 	float                     weight;
 	float                     weight;
 	char                    * name;
 	char                    * name;
 	char                    * cmd;
 	char                    * cmd;
+	char                    * color;
 	char                    * data;
 	char                    * data;
 };
 };
 
 
@@ -1331,6 +1420,7 @@ struct search_data
 {
 {
 	int                     vnum;
 	int                     vnum;
 	short                   stamp;
 	short                   stamp;
+	char                  * arg;
 	pcre                  * name;
 	pcre                  * name;
 	int                     exit_size;
 	int                     exit_size;
 	long long               exit_dirs;
 	long long               exit_dirs;
@@ -1350,7 +1440,7 @@ struct search_data
 
 
 typedef struct session *ARRAY   (struct session *ses, struct listnode *list, char *arg, char *var);
 typedef struct session *ARRAY   (struct session *ses, struct listnode *list, char *arg, char *var);
 typedef void            CHAT    (char *arg1, char *arg2);
 typedef void            CHAT    (char *arg1, char *arg2);
-typedef struct session *CLASS   (struct session *ses, char *left, char *right);
+typedef struct session *CLASS   (struct session *ses, struct listnode *node, char *left, char *right);
 typedef struct session *CONFIG  (struct session *ses, char *arg1, char *arg2, int index);
 typedef struct session *CONFIG  (struct session *ses, char *arg1, char *arg2, int index);
 typedef struct session *COMMAND (struct session *ses, char *arg);
 typedef struct session *COMMAND (struct session *ses, char *arg);
 typedef void            DAEMON  (struct session *ses, char *arg);
 typedef void            DAEMON  (struct session *ses, char *arg);
@@ -1363,7 +1453,7 @@ typedef void            HISTORY (struct session *ses, char *arg);
 typedef void            BUFFER  (struct session *ses, char *arg);
 typedef void            BUFFER  (struct session *ses, char *arg);
 typedef void            MSDP    (struct session *ses, struct port_data *buddy, int index);
 typedef void            MSDP    (struct session *ses, struct port_data *buddy, int index);
 typedef void            SCREEN  (struct session *ses, int ind, char *arg, char *arg1, char *arg2);
 typedef void            SCREEN  (struct session *ses, int ind, char *arg, char *arg1, char *arg2);
-typedef void            DRAW    (struct session *ses, int top_row, int top_col, int bot_row, int bot_col, int rows, int cols, int flags, char *color, char *arg, char *arg1, char *arg2);
+typedef void            DRAW    (struct session *ses, int top_row, int top_col, int bot_row, int bot_col, int rows, int cols, long long flags, char *color, char *arg, char *arg1, char *arg2);
 
 
 /*
 /*
 	Structures for tables.c
 	Structures for tables.c
@@ -1395,7 +1485,7 @@ struct chat_type
 struct class_type
 struct class_type
 {
 {
 	char                  * name;
 	char                  * name;
-	CLASS                 * group;
+	CLASS                 * fun;
 };
 };
 
 
 struct color_type
 struct color_type
@@ -1464,6 +1554,8 @@ struct list_type
 	char                  * name_multi;
 	char                  * name_multi;
 	int                     mode;
 	int                     mode;
 	int                     args;
 	int                     args;
+	int                     script_arg;
+	int                     priority_arg;
 	int                     flags;
 	int                     flags;
 };
 };
 
 
@@ -1479,9 +1571,10 @@ struct line_type
 struct map_type
 struct map_type
 {
 {
 	char                  * name;
 	char                  * name;
-	MAP                   * map;
+	MAP                   * fun;
 	int                     flags;
 	int                     flags;
 	int                     check;
 	int                     check;
+	char                  * desc;
 };
 };
 
 
 struct msdp_type
 struct msdp_type
@@ -1531,6 +1624,13 @@ struct rank_type
 	int                     flags;
 	int                     flags;
 };
 };
 
 
+struct stamp_type
+{
+	char                  * name;
+	int                     length;
+	char                  * desc;
+};
+
 struct substitution_type
 struct substitution_type
 {
 {
 	char                  * name;
 	char                  * name;
@@ -1596,11 +1696,14 @@ extern DO_COMMAND(do_advertise);
 extern DO_COMMAND(do_list);
 extern DO_COMMAND(do_list);
 extern DO_ARRAY(array_add);
 extern DO_ARRAY(array_add);
 extern DO_ARRAY(array_clear);
 extern DO_ARRAY(array_clear);
+extern DO_ARRAY(array_collapse);
 extern DO_ARRAY(array_create);
 extern DO_ARRAY(array_create);
+extern DO_ARRAY(array_explode);
 extern DO_ARRAY(array_insert);
 extern DO_ARRAY(array_insert);
 extern DO_ARRAY(array_delete);
 extern DO_ARRAY(array_delete);
 extern DO_ARRAY(array_find);
 extern DO_ARRAY(array_find);
 extern DO_ARRAY(array_get);
 extern DO_ARRAY(array_get);
+extern DO_ARRAY(array_shuffle);
 extern DO_ARRAY(array_simplify);
 extern DO_ARRAY(array_simplify);
 extern DO_ARRAY(array_size);
 extern DO_ARRAY(array_size);
 extern DO_ARRAY(array_set);
 extern DO_ARRAY(array_set);
@@ -1689,13 +1792,15 @@ extern DO_COMMAND(do_class);
 extern  int count_class(struct session *ses, struct listnode *group);
 extern  int count_class(struct session *ses, struct listnode *group);
 extern void parse_class(struct session *ses, char *input, struct listnode *group);
 extern void parse_class(struct session *ses, char *input, struct listnode *group);
 
 
-extern DO_CLASS(class_open);
 extern DO_CLASS(class_close);
 extern DO_CLASS(class_close);
+extern DO_CLASS(class_kill);
 extern DO_CLASS(class_list);
 extern DO_CLASS(class_list);
+extern DO_CLASS(class_load);
+extern DO_CLASS(class_open);
 extern DO_CLASS(class_read);
 extern DO_CLASS(class_read);
+extern DO_CLASS(class_save);
 extern DO_CLASS(class_size);
 extern DO_CLASS(class_size);
 extern DO_CLASS(class_write);
 extern DO_CLASS(class_write);
-extern DO_CLASS(class_kill);
 
 
 #endif
 #endif
 
 
@@ -1746,6 +1851,7 @@ extern DO_CURSOR(cursor_right);
 extern DO_CURSOR(cursor_right_word);
 extern DO_CURSOR(cursor_right_word);
 extern DO_CURSOR(cursor_set);
 extern DO_CURSOR(cursor_set);
 extern DO_CURSOR(cursor_suspend);
 extern DO_CURSOR(cursor_suspend);
+extern DO_CURSOR(cursor_tab);
 extern DO_CURSOR(cursor_tab_backward);
 extern DO_CURSOR(cursor_tab_backward);
 extern DO_CURSOR(cursor_tab_forward);
 extern DO_CURSOR(cursor_tab_forward);
 extern DO_CURSOR(cursor_auto_tab_backward);
 extern DO_CURSOR(cursor_auto_tab_backward);
@@ -1781,7 +1887,7 @@ extern DO_COMMAND(do_map);
 
 
 extern  int follow_map(struct session *ses, char *argument);
 extern  int follow_map(struct session *ses, char *argument);
 extern void show_vtmap(struct session *ses);
 extern void show_vtmap(struct session *ses);
-extern void map_mouse_handler(struct session *ses, char *left, char *right, int row, int col);
+extern void map_mouse_handler(struct session *ses, char *left, char *right, int row, int col, int height, int width);
 extern  int delete_map(struct session *ses);
 extern  int delete_map(struct session *ses);
 
 
 extern DO_MAP(map_at);
 extern DO_MAP(map_at);
@@ -1792,6 +1898,7 @@ extern DO_MAP(map_debug);
 extern DO_MAP(map_delete);
 extern DO_MAP(map_delete);
 extern DO_MAP(map_destroy);
 extern DO_MAP(map_destroy);
 extern DO_MAP(map_dig);
 extern DO_MAP(map_dig);
+extern DO_MAP(map_entrance);
 extern DO_MAP(map_exit);
 extern DO_MAP(map_exit);
 extern DO_MAP(map_exitflag);
 extern DO_MAP(map_exitflag);
 extern DO_MAP(map_explore);
 extern DO_MAP(map_explore);
@@ -1803,6 +1910,7 @@ extern DO_MAP(map_goto);
 extern DO_MAP(map_info);
 extern DO_MAP(map_info);
 extern DO_MAP(map_insert);
 extern DO_MAP(map_insert);
 extern DO_MAP(map_jump);
 extern DO_MAP(map_jump);
+extern DO_MAP(map_landmark);
 extern DO_MAP(map_leave);
 extern DO_MAP(map_leave);
 extern DO_MAP(map_legend);
 extern DO_MAP(map_legend);
 extern DO_MAP(map_link);
 extern DO_MAP(map_link);
@@ -1817,10 +1925,14 @@ extern DO_MAP(map_return);
 extern DO_MAP(map_roomflag);
 extern DO_MAP(map_roomflag);
 extern DO_MAP(map_run);
 extern DO_MAP(map_run);
 extern DO_MAP(map_set);
 extern DO_MAP(map_set);
+extern DO_MAP(map_sync);
+extern DO_MAP(map_terrain);
 extern DO_MAP(map_travel);
 extern DO_MAP(map_travel);
 extern DO_MAP(map_undo);
 extern DO_MAP(map_undo);
 extern DO_MAP(map_uninsert);
 extern DO_MAP(map_uninsert);
+extern DO_MAP(map_unlandmark);
 extern DO_MAP(map_unlink);
 extern DO_MAP(map_unlink);
+extern DO_MAP(map_unterrain);
 extern DO_MAP(map_update);
 extern DO_MAP(map_update);
 extern DO_MAP(map_vnum);
 extern DO_MAP(map_vnum);
 extern DO_MAP(map_write);
 extern DO_MAP(map_write);
@@ -1897,6 +2009,9 @@ extern DO_CONFIG(config_wordwrap);
 #ifndef __SUBSTITUTE_H__
 #ifndef __SUBSTITUTE_H__
 #define __SUBSTITUTE_H__
 #define __SUBSTITUTE_H__
 
 
+extern char *fuzzy_color_code(struct session *ses, char *pti);
+extern char *dim_color_code(struct session *ses, char *pti, int mod);
+extern char *lit_color_code(struct session *ses, char *pti, int mod);
 extern int is_color_code(char *str);
 extern int is_color_code(char *str);
 extern int substitute_color(char *input, char *output, int colors);
 extern int substitute_color(char *input, char *output, int colors);
 
 
@@ -1935,7 +2050,7 @@ extern void show_node(struct listroot *root, struct listnode *node, int level);
 extern void show_nest(struct listnode *node, char *result);
 extern void show_nest(struct listnode *node, char *result);
 extern void show_list(struct listroot *root, int level);
 extern void show_list(struct listroot *root, int level);
 extern void delete_node_list(struct session *ses, int type, struct listnode *node);
 extern void delete_node_list(struct session *ses, int type, struct listnode *node);
-extern void delete_node_with_wild(struct session *ses, int index, char *string);
+extern  int delete_node_with_wild(struct session *ses, int index, char *string);
 extern void delete_index_list(struct listroot *root, int index);
 extern void delete_index_list(struct listroot *root, int index);
 extern  int search_index_list(struct listroot *root, char *text, char *priority);
 extern  int search_index_list(struct listroot *root, char *text, char *priority);
 extern  int locate_index_list(struct listroot *root, char *text, char *priority);
 extern  int locate_index_list(struct listroot *root, char *text, char *priority);
@@ -1964,6 +2079,15 @@ extern void dump_full_stack(void);
 
 
 #endif
 #endif
 
 
+#ifndef __DICT_H__
+#define __DICT_H__
+
+DO_COMMAND(do_dictionary);
+
+extern int spellcheck_count(struct session *ses, char *in);
+
+#endif
+
 
 
 #ifndef __DRAW_H__
 #ifndef __DRAW_H__
 #define __DRAW_H__
 #define __DRAW_H__
@@ -1973,23 +2097,21 @@ extern DO_COMMAND(do_draw);
 DO_DRAW(draw_blank);
 DO_DRAW(draw_blank);
 DO_DRAW(draw_bot_side);
 DO_DRAW(draw_bot_side);
 DO_DRAW(draw_box);
 DO_DRAW(draw_box);
-DO_DRAW(draw_box_text);
-DO_DRAW(draw_center_left_side);
-DO_DRAW(draw_center_right_side);
+DO_DRAW(draw_corner);
 DO_DRAW(draw_horizontal_line);
 DO_DRAW(draw_horizontal_line);
 DO_DRAW(draw_left_side);
 DO_DRAW(draw_left_side);
 DO_DRAW(draw_line);
 DO_DRAW(draw_line);
 DO_DRAW(draw_map);
 DO_DRAW(draw_map);
-DO_DRAW(draw_middle_bot_side);
-DO_DRAW(draw_middle_top_side);
 DO_DRAW(draw_right_side);
 DO_DRAW(draw_right_side);
 DO_DRAW(draw_side);
 DO_DRAW(draw_side);
-DO_DRAW(draw_vertical_lines);
-DO_DRAW(draw_vertical_lines_text);
 DO_DRAW(draw_square);
 DO_DRAW(draw_square);
+DO_DRAW(draw_stamp);
+DO_DRAW(draw_rain);
+DO_DRAW(draw_table_grid);
 DO_DRAW(draw_text);
 DO_DRAW(draw_text);
 DO_DRAW(draw_top_side);
 DO_DRAW(draw_top_side);
-DO_DRAW(draw_vertical_line);
+//DO_DRAW(draw_vertical_line);
+DO_DRAW(draw_vertical_lines);
 
 
 #endif
 #endif
 
 
@@ -2012,6 +2134,7 @@ extern void mouse_handler(struct session *ses, int val1, int val2, int val3, cha
 extern DO_COMMAND(do_read);
 extern DO_COMMAND(do_read);
 extern DO_COMMAND(do_write);
 extern DO_COMMAND(do_write);
 
 
+extern struct session *read_file(struct session *ses, FILE *fp, char *filename);
 extern void write_node(struct session *ses, int mode, struct listnode *node, FILE *file);
 extern void write_node(struct session *ses, int mode, struct listnode *node, FILE *file);
 
 
 #endif 
 #endif 
@@ -2051,6 +2174,8 @@ DO_HISTORY(history_write);
 
 
 extern DO_COMMAND(do_line);
 extern DO_COMMAND(do_line);
 extern DO_LINE(line_background);
 extern DO_LINE(line_background);
+extern DO_LINE(line_benchmark);
+extern DO_LINE(line_capture);
 extern DO_LINE(line_debug);
 extern DO_LINE(line_debug);
 extern DO_LINE(line_gag);
 extern DO_LINE(line_gag);
 extern DO_LINE(line_ignore);
 extern DO_LINE(line_ignore);
@@ -2112,10 +2237,12 @@ void  zlib_free(void *opaque, void *address);
 extern char *restring(char *point, char *string);
 extern char *restring(char *point, char *string);
 extern char *restringf(char *point, char *fmt, ...);
 extern char *restringf(char *point, char *fmt, ...);
 extern  int str_len(char *str);
 extern  int str_len(char *str);
+extern void str_fix(char *str);
 extern char *str_alloc(int len);
 extern char *str_alloc(int len);
 extern void str_clone(char **clone, char *original);
 extern void str_clone(char **clone, char *original);
 extern char *str_mim(char *original);
 extern char *str_mim(char *original);
 extern char *str_dup(char *original);
 extern char *str_dup(char *original);
+extern char *str_dup_clone(char *original);
 extern char *str_dup_printf(char *fmt, ...);
 extern char *str_dup_printf(char *fmt, ...);
 extern char *str_cpy(char **ptr, char *str);
 extern char *str_cpy(char **ptr, char *str);
 extern char *str_cpy_printf(char **ptr, char *fmt, ...);
 extern char *str_cpy_printf(char **ptr, char *fmt, ...);
@@ -2124,7 +2251,7 @@ extern char *str_ncpy(char **ptr, char *str, int len);
 extern char *str_cat(char **ptr, char *str);
 extern char *str_cat(char **ptr, char *str);
 extern char *str_cat_chr(char **ptr, char chr);
 extern char *str_cat_chr(char **ptr, char chr);
 extern char *str_cat_printf(char **ptr, char *fmt, ...);
 extern char *str_cat_printf(char **ptr, char *fmt, ...);
-extern void str_fix(char *str);
+extern char *str_ins(char **str, int index, char *buf);
 extern void str_free(char *ptr);
 extern void str_free(char *ptr);
 
 
 #endif
 #endif
@@ -2182,9 +2309,11 @@ extern struct msdp_type msdp_table[];
 #ifndef __NEST_H__
 #ifndef __NEST_H__
 #define __NEST_H__
 #define __NEST_H__
 
 
+extern struct listroot *search_nest_base_ses(struct session *ses, char *arg);
 extern struct listroot *search_nest_root(struct listroot *root, char *arg);
 extern struct listroot *search_nest_root(struct listroot *root, char *arg);
 extern struct listnode *search_base_node(struct listroot *root, char *variable);
 extern struct listnode *search_base_node(struct listroot *root, char *variable);
 extern struct listnode *search_nest_node(struct listroot *root, char *variable);
 extern struct listnode *search_nest_node(struct listroot *root, char *variable);
+extern struct listnode *search_nest_node_ses(struct session *ses, char *variable);
 extern int search_nest_index(struct listroot *root, char *variable);
 extern int search_nest_index(struct listroot *root, char *variable);
 extern struct listroot *update_nest_root(struct listroot *root, char *arg);
 extern struct listroot *update_nest_root(struct listroot *root, char *arg);
 extern void update_nest_node(struct listroot *root, char *arg);
 extern void update_nest_node(struct listroot *root, char *arg);
@@ -2196,6 +2325,8 @@ extern struct listnode *get_nest_node_val(struct listroot *root, char *variable,
 extern int get_nest_index(struct listroot *root, char *variable, char **result, int def);
 extern int get_nest_index(struct listroot *root, char *variable, char **result, int def);
 extern void show_nest_node(struct listnode *node, char **result, int initialize);
 extern void show_nest_node(struct listnode *node, char **result, int initialize);
 extern void view_nest_node(struct listnode *node, char **str_result, int nest, int initialize);
 extern void view_nest_node(struct listnode *node, char **str_result, int nest, int initialize);
+extern struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format, ...);
+extern struct listnode *add_nest_node_ses(struct session *ses, char *arg1, char *format, ...);
 extern struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format, ...);
 extern struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format, ...);
 extern struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format, ...);
 extern struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format, ...);
 extern void copy_nest_node(struct listroot *dst_root, struct listnode *dst, struct listnode *src);
 extern void copy_nest_node(struct listroot *dst_root, struct listnode *dst, struct listnode *src);
@@ -2222,17 +2353,21 @@ extern void filename_string(char *input, char *output);
 extern struct session *parse_input(struct session *ses, char *input);
 extern struct session *parse_input(struct session *ses, char *input);
 extern struct session *parse_command(struct session *ses, char *input);
 extern struct session *parse_command(struct session *ses, char *input);
 extern  int is_speedwalk(struct session *ses, char *input);
 extern  int is_speedwalk(struct session *ses, char *input);
+extern char *substitute_speedwalk(struct session *ses, char *input, char *output);
 extern void process_speedwalk(struct session *ses, char *input);
 extern void process_speedwalk(struct session *ses, char *input);
 extern struct session *parse_tintin_command(struct session *ses, char *input);
 extern struct session *parse_tintin_command(struct session *ses, char *input);
+extern int cnt_arg_all(struct session *ses, char *string, int flag);
 extern char *get_arg_all(struct session *ses, char *string, char *result, int verbatim);
 extern char *get_arg_all(struct session *ses, char *string, char *result, int verbatim);
 extern char *get_arg_in_braces(struct session *ses, char *string, char *result, int flag);
 extern char *get_arg_in_braces(struct session *ses, char *string, char *result, int flag);
 extern char *sub_arg_in_braces(struct session *ses, char *string, char *result, int flag, int sub);
 extern char *sub_arg_in_braces(struct session *ses, char *string, char *result, int flag, int sub);
 extern char *get_arg_with_spaces(struct session *ses, char *string, char *result, int flag);
 extern char *get_arg_with_spaces(struct session *ses, char *string, char *result, int flag);
 extern char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int flag);
 extern char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int flag);
+extern char *get_arg_stop_digits(struct session *ses, char *string, char *result, int flag);
 extern char *space_out(char *string);
 extern char *space_out(char *string);
 extern char *get_arg_to_brackets(struct session *ses, char *string, char *result);
 extern char *get_arg_to_brackets(struct session *ses, char *string, char *result);
 extern char *get_arg_at_brackets(struct session *ses, char *string, char *result);
 extern char *get_arg_at_brackets(struct session *ses, char *string, char *result);
 extern char *get_arg_in_brackets(struct session *ses, char *string, char *result);
 extern char *get_arg_in_brackets(struct session *ses, char *string, char *result);
+extern char *get_char(struct session *ses, char *string, char *result);
 extern void write_mud(struct session *ses, char *command, int flags);
 extern void write_mud(struct session *ses, char *command, int flags);
 extern void do_one_line(char *line, struct session *ses);
 extern void do_one_line(char *line, struct session *ses);
 
 
@@ -2346,6 +2481,7 @@ extern  int get_row_index(struct session *ses, char *arg);
 extern  int get_col_index(struct session *ses, char *arg);
 extern  int get_col_index(struct session *ses, char *arg);
 extern void csip_handler(int var1, int var2, int var3);
 extern void csip_handler(int var1, int var2, int var3);
 extern void csit_handler(int var1, int var2, int var3);
 extern void csit_handler(int var1, int var2, int var3);
+extern void rqlp_handler(int event, int button, int row, int col);
 extern void osc_handler(char ind, char *arg);
 extern void osc_handler(char ind, char *arg);
 extern void print_screen();
 extern void print_screen();
 extern void init_screen(int rows, int cols, int pix_rows, int pix_cols);
 extern void init_screen(int rows, int cols, int pix_rows, int pix_cols);
@@ -2400,7 +2536,7 @@ extern void print_lines(struct session *ses, int flags, char *format, ...);
 extern void show_lines(struct session *ses, char *str);
 extern void show_lines(struct session *ses, char *str);
 extern void tintin_header(struct session *ses, char *format, ...);
 extern void tintin_header(struct session *ses, char *format, ...);
 extern void socket_printf(struct session *ses, size_t length, char *format, ...);
 extern void socket_printf(struct session *ses, size_t length, char *format, ...);
-extern void telnet_printf(struct session *ses, size_t length, char *format, ...);
+extern void telnet_printf(struct session *ses, int length, char *format, ...);
 
 
 extern void tintin_printf2(struct session *ses, char *format, ...);
 extern void tintin_printf2(struct session *ses, char *format, ...);
 extern void tintin_printf(struct session *ses, char *format, ...);
 extern void tintin_printf(struct session *ses, char *format, ...);
@@ -2471,6 +2607,7 @@ extern struct map_type map_table[];
 extern struct path_type path_table[];
 extern struct path_type path_table[];
 extern struct port_type port_table[];
 extern struct port_type port_table[];
 extern struct rank_type rank_table[];
 extern struct rank_type rank_table[];
+extern struct stamp_type huge_stamp_table[];
 extern struct substitution_type substitution_table[];
 extern struct substitution_type substitution_table[];
 extern struct telopt_type telopt_table[];
 extern struct telopt_type telopt_table[];
 extern   char *telcmds[];
 extern   char *telcmds[];
@@ -2491,7 +2628,9 @@ extern  int client_send_sb_naws(struct session *ses, int cplen, unsigned char *c
 extern void announce_support(struct session *ses, struct port_data *buddy);
 extern void announce_support(struct session *ses, struct port_data *buddy);
 extern  int server_translate_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen, unsigned char *out, int outlen);
 extern  int server_translate_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen, unsigned char *out, int outlen);
 extern void write_mccp2(struct session *ses, struct port_data *buddy, char *txt, int length);
 extern void write_mccp2(struct session *ses, struct port_data *buddy, char *txt, int length);
+extern void client_end_mccp2(struct session *ses);
 extern void end_mccp2(struct session *ses, struct port_data *buddy);
 extern void end_mccp2(struct session *ses, struct port_data *buddy);
+extern void client_end_mccp3(struct session *ses);
 extern void end_mccp3(struct session *ses, struct port_data *buddy);
 extern void end_mccp3(struct session *ses, struct port_data *buddy);
 extern void init_msdp_table(void);
 extern void init_msdp_table(void);
 
 
@@ -2501,15 +2640,16 @@ extern void init_msdp_table(void);
 #ifndef __TERMINAL_H__
 #ifndef __TERMINAL_H__
 #define __TERMINAL_H__
 #define __TERMINAL_H__
 
 
-extern void init_terminal(struct session *ses);
-extern void reset_terminal(struct session *ses);
-extern void save_session_terminal(struct session *ses);
-extern void refresh_session_terminal(struct session *ses);
-extern void echo_on(struct session *ses);
-extern void echo_off(struct session *ses);
-extern void init_terminal_size(struct session *ses);
-extern  int get_scroll_rows(struct session *ses);
-extern  int get_scroll_cols(struct session *ses);
+extern void  init_terminal(struct session *ses);
+extern void  reset_terminal(struct session *ses);
+extern void  save_session_terminal(struct session *ses);
+extern void  refresh_session_terminal(struct session *ses);
+extern void  echo_on(struct session *ses);
+extern void  echo_off(struct session *ses);
+extern void  init_terminal_size(struct session *ses);
+extern  int  get_scroll_rows(struct session *ses);
+extern  int  get_scroll_cols(struct session *ses);
+extern char *get_charset(struct session *ses);
 
 
 #endif
 #endif
 
 
@@ -2535,11 +2675,11 @@ DO_COMMAND(do_regexp);
 extern int substitute(struct session *ses, char *string, char *result, int flags);
 extern int substitute(struct session *ses, char *string, char *result, int flags);
 extern int match(struct session *ses, char *str, char *exp, int flags);
 extern int match(struct session *ses, char *str, char *exp, int flags);
 extern int find(struct session *ses, char *str, char *exp, int sub, int flag);
 extern int find(struct session *ses, char *str, char *exp, int sub, int flag);
-extern int regexp_compare(pcre *regex, char *str, char *exp, int option, int flag);
+extern int regexp_compare(struct session *ses, pcre *regex, char *str, char *exp, int option, int flag);
 extern int check_one_regexp(struct session *ses, struct listnode *node, char *line, char *original, int option);
 extern int check_one_regexp(struct session *ses, struct listnode *node, char *line, char *original, int option);
 extern int tintin_regexp_check(struct session *ses, char *exp);
 extern int tintin_regexp_check(struct session *ses, char *exp);
 extern int tintin_regexp(struct session *ses, pcre *pcre, char *str, char *exp, int option, int flag);
 extern int tintin_regexp(struct session *ses, pcre *pcre, char *str, char *exp, int option, int flag);
-extern pcre *regexp_compile(char *exp, int option);
+extern pcre *regexp_compile(struct session *ses, char *exp, int option);
 extern pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *exp, int option);
 extern pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *exp, int option);
 extern void  tintin_macro_compile(char *input, char *output);
 extern void  tintin_macro_compile(char *input, char *output);
 
 
@@ -2649,12 +2789,25 @@ extern int get_utf8_width(char *str, int *width);
 extern int get_utf8_index(char *str, int *index);
 extern int get_utf8_index(char *str, int *index);
 extern int unicode_to_utf8(int index, char *out);
 extern int unicode_to_utf8(int index, char *out);
 extern int utf8_strlen(char *str);
 extern int utf8_strlen(char *str);
-extern int is_big5(char *str);
-extern int big5_to_utf8(char *input, char *output);
-extern int utf8_to_big5(char *input, char *output);
+
+extern int utf8_to_all(struct session *ses, char *in, char *out);
+extern int all_to_utf8(struct session *ses, char *in, char *out);
+extern int iso1_to_utf8(char *input, char *output);
+extern int utf8_to_iso1(char *input, char *output);
+extern int iso2_to_utf8(char *input, char *output);
+extern int utf8_to_iso2(char *input, char *output);
 extern int koi8_to_utf8(char *input, char *output);
 extern int koi8_to_utf8(char *input, char *output);
 extern int utf8_to_koi8(char *input, char *output);
 extern int utf8_to_koi8(char *input, char *output);
 extern int fansi_to_utf8(char *input, char *output);
 extern int fansi_to_utf8(char *input, char *output);
+extern int is_euc_head(struct session *ses, char *str);
+extern int get_euc_size(struct session *ses, char *str);
+extern int get_euc_width(struct session *ses, char *str, int *width);
+extern int is_big5(char *str);
+extern int big5_to_utf8(char *input, char *output);
+extern int utf8_to_big5(char *input, char *output);
+extern int is_gbk1(char *str);
+extern int gbk1_to_utf8(char *input, char *output);
+extern int utf8_to_gbk1(char *input, char *output);
 
 
 #endif
 #endif
 
 
@@ -2664,13 +2817,17 @@ extern int fansi_to_utf8(char *input, char *output);
 extern DO_COMMAND(do_variable);
 extern DO_COMMAND(do_variable);
 extern DO_COMMAND(do_unvariable);
 extern DO_COMMAND(do_unvariable);
 extern DO_COMMAND(do_local);
 extern DO_COMMAND(do_local);
+extern DO_COMMAND(do_cat);
 extern DO_COMMAND(do_format);
 extern DO_COMMAND(do_format);
 extern DO_COMMAND(do_replace);
 extern DO_COMMAND(do_replace);
 
 
+extern  int valid_variable(struct session *ses, char *arg);
 extern  int string_raw_str_len(struct session *ses, char *str, int start, int end);
 extern  int string_raw_str_len(struct session *ses, char *str, int start, int end);
 extern  int string_str_raw_len(struct session *ses, char *str, int start, int end);
 extern  int string_str_raw_len(struct session *ses, char *str, int start, int end);
+extern  int translate_color_names(struct session *ses, char *string, char *result);
 extern  int get_color_names(struct session *ses, char *htype, char *result);
 extern  int get_color_names(struct session *ses, char *htype, char *result);
 extern void lowerstring(char *str);
 extern void lowerstring(char *str);
+extern void upperstring(char *str);
 extern void numbertocharacter(struct session *ses, char *str);
 extern void numbertocharacter(struct session *ses, char *str);
 extern void charactertonumber(struct session *ses, char *str);
 extern void charactertonumber(struct session *ses, char *str);
 extern  int delete_variable(struct session *ses, char *variable);
 extern  int delete_variable(struct session *ses, char *variable);
@@ -2699,6 +2856,8 @@ extern void erase_scroll_region(struct session *ses);
 extern void reset(struct session *ses);
 extern void reset(struct session *ses);
 extern void scroll_region(struct session *ses, int top, int bottom);
 extern void scroll_region(struct session *ses, int top, int bottom);
 extern void reset_scroll_region(struct session *ses);
 extern void reset_scroll_region(struct session *ses);
+extern int find_color_code(char *str);
+extern int find_secure_color_code(char *str);
 extern int skip_vt102_codes(char *str);
 extern int skip_vt102_codes(char *str);
 extern int skip_vt102_codes_non_graph(char *str);
 extern int skip_vt102_codes_non_graph(char *str);
 extern void strip_vt102_codes(char *str, char *buf);
 extern void strip_vt102_codes(char *str, char *buf);

+ 18 - 27
src/tokenize.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2008                        *
+*                      coded by Igor van den Hoven 2008                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -62,19 +61,6 @@ struct script_regex
 	int                    val;
 	int                    val;
 };
 };
 
 
-struct scriptroot
-{
-	struct scriptnode    * next;
-	struct scriptnode    * prev;
-	struct session       * ses;
-	struct listroot      * local;
-	int list;
-};
-
-struct scriptroot *script_stack[1001];
-
-int script_index;
-
 void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode *token)
 void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode *token)
 {
 {
 	push_call("debugtoken(%p,%d,%p,%d)",ses,root->list,token,token->type);
 	push_call("debugtoken(%p,%d,%p,%d)",ses,root->list,token,token->type);
@@ -276,7 +262,7 @@ void handlereturntoken(struct session *ses, struct scriptnode *token)
 
 
 	substitute(ses, token->str, arg, SUB_VAR|SUB_FUN);
 	substitute(ses, token->str, arg, SUB_VAR|SUB_FUN);
 
 
-	set_nest_node(ses->list[LIST_VARIABLE], "result", "%s", arg);
+	set_nest_node_ses(ses, "result", "%s", arg);
 }
 }
 
 
 void handleswitchtoken(struct session *ses, struct scriptnode *token)
 void handleswitchtoken(struct session *ses, struct scriptnode *token)
@@ -349,9 +335,9 @@ char *get_arg_parse(struct session *ses, struct scriptnode *token)
 {
 {
 	static char buf[5];
 	static char buf[5];
 
 
-	if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && token->data->arg[0] & 128 && token->data->arg[1] != 0)
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, token->data->arg))
 	{
 	{
-		token->data->arg += sprintf(buf, "%c%c", token->data->arg[0], token->data->arg[1]);
+		token->data->arg += sprintf(buf, "%.*s", get_euc_size(ses, token->data->arg), token->data->arg);
 	}
 	}
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(token->data->arg))
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(token->data->arg))
 	{
 	{
@@ -455,7 +441,7 @@ void init_local(struct session *ses)
 	root->list = LIST_VARIABLE;
 	root->list = LIST_VARIABLE;
 	root->local = init_list(ses, LIST_VARIABLE, LIST_SIZE);
 	root->local = init_list(ses, LIST_VARIABLE, LIST_SIZE);
 
 
-	script_stack[0] = root;
+	gtd->script_stack[0] = root;
 
 
 	return;
 	return;
 }
 }
@@ -466,7 +452,7 @@ struct listroot *local_list(struct session *ses)
 
 
 	push_call("local_list(%p)",ses);
 	push_call("local_list(%p)",ses);
 
 
-	root = script_stack[script_index]->local;
+	root = gtd->script_stack[gtd->script_index]->local;
 
 
 	pop_call();
 	pop_call();
 	return root;
 	return root;
@@ -843,7 +829,7 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 				}
 				}
 				else
 				else
 				{
 				{
-					set_nest_node(root->ses->list[LIST_VARIABLE], token->str, "%s", get_arg_foreach(root, token));
+					set_nest_node_ses(root->ses, token->str, "%s", get_arg_foreach(root, token));
 
 
 					if (*token->data->arg == 0)
 					if (*token->data->arg == 0)
 					{
 					{
@@ -878,7 +864,7 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 					resetlooptoken(root->ses, token);
 					resetlooptoken(root->ses, token);
 				}
 				}
 
 
-				set_nest_node(root->ses->list[LIST_VARIABLE], token->str, "%lld", token->data->cnt);
+				set_nest_node_ses(root->ses, token->str, "%lld", token->data->cnt);
 
 
 				token->data->cnt += token->data->inc;
 				token->data->cnt += token->data->inc;
 
 
@@ -911,7 +897,7 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 
 
 				}
 				}
 
 
-				set_nest_node(root->ses->list[LIST_VARIABLE], token->str, "%s", get_arg_parse(root->ses, token));
+				set_nest_node_ses(root->ses, token->str, "%s", get_arg_parse(root->ses, token));
 
 
 				if (*token->data->arg == 0)
 				if (*token->data->arg == 0)
 				{
 				{
@@ -1183,13 +1169,16 @@ struct session *script_driver(struct session *ses, int list, char *str)
 
 
 	gtd->level->input += list != LIST_COMMAND;
 	gtd->level->input += list != LIST_COMMAND;
 
 
-	script_stack[++script_index] = root;
+	gtd->script_stack[++gtd->script_index] = root;
 
 
 	tokenize_script(root, 0, str);
 	tokenize_script(root, 0, str);
 
 
 	ses = (struct session *) parse_script(root, 0, root->next, root->prev);
 	ses = (struct session *) parse_script(root, 0, root->next, root->prev);
 
 
-	script_index--;
+	if (--gtd->script_index == 0)
+	{
+		DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+	}
 
 
 	gtd->level->input -= list != LIST_COMMAND;
 	gtd->level->input -= list != LIST_COMMAND;
 
 
@@ -1201,6 +1190,8 @@ struct session *script_driver(struct session *ses, int list, char *str)
 	free_list(root->local);
 	free_list(root->local);
 	free(root);
 	free(root);
 
 
+
+	
 	if (HAS_BIT(ses->flags, SES_FLAG_CLOSED))
 	if (HAS_BIT(ses->flags, SES_FLAG_CLOSED))
 	{
 	{
 		pop_call();
 		pop_call();

+ 1 - 2
src/trigger.c

@@ -31,7 +31,7 @@ DO_COMMAND(do_action)
 {
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
 
@@ -714,7 +714,6 @@ DO_COMMAND(do_prompt)
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
 
-
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
 		show_list(ses->list[LIST_PROMPT], 0);
 		show_list(ses->list[LIST_PROMPT], 0);

+ 96 - 33
src/update.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,15 +13,14 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
-*                     coded by Igor van den Hoven 2006                        *
+*                      coded by Igor van den Hoven 2006                       *
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "tintin.h"
 #include "tintin.h"
@@ -51,8 +50,9 @@ extern void close_timer(int timer);
 
 
 void mainloop(void)
 void mainloop(void)
 {
 {
-	static struct timeval start_time, end_time, span_time, wait_time;
+	static struct timeval start_time, end_time, wait_time;
 	static struct pulse_type pulse;
 	static struct pulse_type pulse;
+	static int wait_time_val, span_time_val;
 
 
 	pulse.update_input    =  0 + PULSE_UPDATE_INPUT;
 	pulse.update_input    =  0 + PULSE_UPDATE_INPUT;
 	pulse.update_sessions =  0 + PULSE_UPDATE_SESSIONS;
 	pulse.update_sessions =  0 + PULSE_UPDATE_SESSIONS;
@@ -73,8 +73,8 @@ void mainloop(void)
 	{
 	{
 		gettimeofday(&start_time, NULL);
 		gettimeofday(&start_time, NULL);
 
 
-		gtd->total_io_exec  += span_time.tv_usec;
-		gtd->total_io_delay += wait_time.tv_usec;
+		gtd->total_io_exec  += span_time_val;
+		gtd->total_io_delay += wait_time_val;
 
 
 		if (--pulse.update_delays == 0)
 		if (--pulse.update_delays == 0)
 		{
 		{
@@ -169,19 +169,27 @@ void mainloop(void)
 
 
 		if (start_time.tv_sec == end_time.tv_sec)
 		if (start_time.tv_sec == end_time.tv_sec)
 		{
 		{
-			span_time.tv_usec = end_time.tv_usec - start_time.tv_usec;
+			span_time_val = end_time.tv_usec - start_time.tv_usec;
 		}
 		}
 		else
 		else
 		{
 		{
-			span_time.tv_usec = (end_time.tv_sec * 1000000LL + end_time.tv_usec) - (start_time.tv_sec * 1000000LL + start_time.tv_usec);
+			span_time_val = (end_time.tv_sec * 1000000LL + end_time.tv_usec) - (start_time.tv_sec * 1000000LL + start_time.tv_usec);
 		}
 		}
 
 
-		wait_time.tv_usec = 1000000 / PULSE_PER_SECOND - span_time.tv_usec;
+		wait_time_val = 1000000 / PULSE_PER_SECOND - span_time_val;
+
+		wait_time.tv_usec = 1000000 / PULSE_PER_SECOND - span_time_val;
 
 
-		if (wait_time.tv_usec > 0)
+		if (wait_time_val > 0)
 		{
 		{
+			wait_time.tv_usec = wait_time_val;
+
 			select(0, NULL, NULL, NULL, &wait_time);
 			select(0, NULL, NULL, NULL, &wait_time);
 		}
 		}
+		else
+		{
+			wait_time_val = 0;
+		}
 	}
 	}
 	pop_call();
 	pop_call();
 	return;
 	return;
@@ -191,6 +199,7 @@ void update_input(void)
 {
 {
 	fd_set read_fd;
 	fd_set read_fd;
 	static struct timeval timeout;
 	static struct timeval timeout;
+	static int sleep;
 
 
 	if (gtd->detach_port)
 	if (gtd->detach_port)
 	{
 	{
@@ -219,6 +228,16 @@ void update_input(void)
 		return;
 		return;
 	}
 	}
 
 
+	if (gtd->time_input + 10 < gtd->time)
+	{
+		if (sleep < 10)
+		{
+			sleep++;
+			return;
+		}
+		sleep = 0;
+	}
+
 	while (TRUE)
 	while (TRUE)
 	{
 	{
 		FD_ZERO(&read_fd);
 		FD_ZERO(&read_fd);
@@ -251,9 +270,20 @@ void update_sessions(void)
 {
 {
 	fd_set read_fd, error_fd;
 	fd_set read_fd, error_fd;
 	static struct timeval timeout;
 	static struct timeval timeout;
+	static int sleep;
 	struct session *ses;
 	struct session *ses;
 	int rv;
 	int rv;
 
 
+	if (gtd->time_session + 10 < gtd->time)
+	{
+		if (sleep < 10)
+		{
+			sleep++;
+			return;
+		}
+		sleep = 0;
+	}
+
 	push_call("update_sessions(void)");
 	push_call("update_sessions(void)");
 
 
 	open_timer(TIMER_UPDATE_SESSIONS);
 	open_timer(TIMER_UPDATE_SESSIONS);
@@ -278,15 +308,15 @@ void update_sessions(void)
 
 
 					if (rv < 0)
 					if (rv < 0)
 					{
 					{
-						break;
+						break; // bug report after removal.
 
 
-						syserr_printf(ses, "update_sessions: %s:", ses->name);
+						syserr_printf(ses, "update_sessions: select:");
 
 
 						cleanup_session(ses);
 						cleanup_session(ses);
 
 
 						gtd->mud_output_len = 0;
 						gtd->mud_output_len = 0;
 
 
-						break;;
+						break;
 					}
 					}
 
 
 					if (rv == 0)
 					if (rv == 0)
@@ -320,6 +350,8 @@ void update_sessions(void)
 					}
 					}
 				}
 				}
 
 
+				gtd->time_session = gtd->time;
+
 				if (gtd->mud_output_len)
 				if (gtd->mud_output_len)
 				{
 				{
 					readmud(ses);
 					readmud(ses);
@@ -452,13 +484,17 @@ void update_daemon(void)
 			while (gtd->detach_sock)
 			while (gtd->detach_sock)
 			{
 			{
 				FD_ZERO(&read_fd);
 				FD_ZERO(&read_fd);
+//				FD_ZERO(&write_fd);
 				FD_ZERO(&error_fd);
 				FD_ZERO(&error_fd);
 
 
 				FD_SET(gtd->detach_sock, &read_fd);
 				FD_SET(gtd->detach_sock, &read_fd);
+//				FD_SET(gtd->detach_sock, &write_fd);
 				FD_SET(gtd->detach_sock, &error_fd);
 				FD_SET(gtd->detach_sock, &error_fd);
 
 
 				rv = select(FD_SETSIZE, &read_fd, NULL, &error_fd, &timeout);
 				rv = select(FD_SETSIZE, &read_fd, NULL, &error_fd, &timeout);
 
 
+//				tintin_printf2(gtd->ses, "debug: rv: %d (%d,%d,%d)\n", rv, FD_ISSET(gtd->detach_sock, &read_fd), FD_ISSET(gtd->detach_sock, &write_fd), FD_ISSET(gtd->detach_sock, &error_fd));
+
 				if (rv == 0)
 				if (rv == 0)
 				{
 				{
 					break;
 					break;
@@ -486,8 +522,20 @@ void update_daemon(void)
 						goto attach;
 						goto attach;
 					}
 					}
 
 
+/*					if (!FD_ISSET(gtd->detach_sock, &write_fd))
+					{
+						FD_CLR(gtd->detach_sock, &read_fd);
+
+						gtd->detach_sock = close(gtd->detach_sock);
+
+						show_error(gtd->ses, LIST_COMMAND, "update_daemon: detach_sock: write_fd");
+
+						goto attach;
+					}
+*/
 					if (!FD_ISSET(gtd->detach_sock, &read_fd))
 					if (!FD_ISSET(gtd->detach_sock, &read_fd))
 					{
 					{
+//						gtd->detach_sock = close(gtd->detach_sock); // experimental
 						break;
 						break;
 					}
 					}
 					process_input();
 					process_input();
@@ -697,18 +745,18 @@ void tick_update(void)
 		{
 		{
 			node = root->list[root->update];
 			node = root->list[root->update];
 
 
-			if (node->data == 0)
+			if (node->val64 == 0)
 			{
 			{
-				node->data = gtd->utime + (long long) (get_number(ses, node->arg3) * 1000000LL);
+				node->val64 = gtd->utime + (long long) (get_number(ses, node->arg3) * 1000000LL);
 
 
-				show_info(ses, LIST_TICKER, "#INFO TICK {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->data);
+				show_info(ses, LIST_TICKER, "#INFO TICK {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->val64);
 			}
 			}
 
 
-			if (node->data <= gtd->utime)
+			if (node->val64 <= gtd->utime)
 			{
 			{
-				node->data += (long long) (get_number(ses, node->arg3) * 1000000LL);
+				node->val64 += (long long) (get_number(ses, node->arg3) * 1000000LL);
 
 
-				show_info(ses, LIST_TICKER, "#INFO TICK {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->data);
+				show_info(ses, LIST_TICKER, "#INFO TICK {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->val64);
 
 
 				if (!HAS_BIT(root->flags, LIST_FLAG_IGNORE))
 				if (!HAS_BIT(root->flags, LIST_FLAG_IGNORE))
 				{
 				{
@@ -752,14 +800,14 @@ void delay_update(void)
 		{
 		{
 			node = root->list[root->update];
 			node = root->list[root->update];
 
 
-			if (node->data == 0)
+			if (node->val64 == 0)
 			{
 			{
-				node->data = gtd->utime + (long long) (get_number(ses, node->arg3) * 1000000LL);
+				node->val64 = gtd->utime + (long long) (get_number(ses, node->arg3) * 1000000LL);
 
 
-				show_info(ses, LIST_DELAY, "#INFO DELAY {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->data);
+				show_info(ses, LIST_DELAY, "#INFO DELAY {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->val64);
 			}
 			}
 
 
-			if (node->data <= gtd->utime)
+			if (node->val64 <= gtd->utime)
 			{
 			{
 				strcpy(buf, node->arg2);
 				strcpy(buf, node->arg2);
 
 
@@ -792,15 +840,15 @@ void path_update(void)
 		{
 		{
 			node = root->list[root->update];
 			node = root->list[root->update];
 
 
-			if (node->data > 0 && node->data <= gtd->utime)
+			if (node->val64 > 0 && node->val64 <= gtd->utime)
 			{
 			{
 				root->update++;
 				root->update++;
 
 
-				node->data = 0;
+				node->val64 = 0;
 
 
-				show_debug(ses, LIST_PATH, "#DEBUG PATH {%s}", node->arg1);
+				show_debug(ses, LIST_COMMAND, "#DEBUG PATH {%s}", node->arg1);
 
 
-				script_driver(ses, LIST_PATH, node->arg1);
+				script_driver(ses, LIST_COMMAND, node->arg1);
 			}
 			}
 			break;
 			break;
 		}
 		}
@@ -834,8 +882,18 @@ void packet_update(void)
 
 
 			ses->more_output[0] = 0;
 			ses->more_output[0] = 0;
 
 
-			process_mud_output(ses, result, TRUE);
+			if (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
+			{
+				char buf[BUFFER_SIZE];
+
+				all_to_utf8(ses, result, buf);
 
 
+				process_mud_output(ses, buf, TRUE);
+			}
+			else
+			{
+				process_mud_output(ses, result, TRUE);
+			}
 			DEL_BIT(ses->flags, SES_FLAG_READMUD);
 			DEL_BIT(ses->flags, SES_FLAG_READMUD);
 
 
 			if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 			if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
@@ -1024,14 +1082,14 @@ void time_update(void)
 
 
 void show_cpu(struct session *ses)
 void show_cpu(struct session *ses)
 {
 {
-	long long total_cpu;
+	long long total_cpu = 0;
 	int timer;
 	int timer;
 
 
 	tintin_printf2(ses, "Section                           Time (usec)    Freq (msec)  %%Prog         %%CPU");
 	tintin_printf2(ses, "Section                           Time (usec)    Freq (msec)  %%Prog         %%CPU");
 
 
 	tintin_printf2(ses, "");
 	tintin_printf2(ses, "");
 
 
-	for (total_cpu = timer = 0 ; timer < TIMER_CPU ; timer++)
+	for (timer = 0 ; timer < TIMER_CPU ; timer++)
 	{
 	{
 		total_cpu += display_timer(ses, timer);
 		total_cpu += display_timer(ses, timer);
 	}
 	}
@@ -1040,6 +1098,9 @@ void show_cpu(struct session *ses)
 
 
 	tintin_printf2(ses, "Unknown CPU Usage:             %7.3f percent", (gtd->total_io_exec - total_cpu) * 100.0 / (gtd->total_io_delay + gtd->total_io_exec));
 	tintin_printf2(ses, "Unknown CPU Usage:             %7.3f percent", (gtd->total_io_exec - total_cpu) * 100.0 / (gtd->total_io_delay + gtd->total_io_exec));
 	tintin_printf2(ses, "Average CPU Usage:             %7.3f percent", (gtd->total_io_exec)             * 100.0 / (gtd->total_io_delay + gtd->total_io_exec));
 	tintin_printf2(ses, "Average CPU Usage:             %7.3f percent", (gtd->total_io_exec)             * 100.0 / (gtd->total_io_delay + gtd->total_io_exec));
+//	tintin_printf2(ses, "Total   CPU Usecs:             %10ld", gtd->total_io_exec);
+//	tintin_printf2(ses, "Total   CPU Delay:             %10ld", gtd->total_io_delay);
+
 }
 }
 
 
 
 
@@ -1059,7 +1120,9 @@ long long display_timer(struct session *ses, int timer)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	indicated_usage = gtd->timer[timer][0] / gtd->timer[timer][1] * gtd->timer[timer][4];
+//	indicated_usage = gtd->timer[timer][0] / gtd->timer[timer][1] * gtd->timer[timer][4];
+
+	indicated_usage = gtd->timer[timer][0];
 
 
 	tintin_printf2(ses, "%-30s%8lld       %8lld      %8.2f     %8.3f",
 	tintin_printf2(ses, "%-30s%8lld       %8lld      %8.2f     %8.3f",
 		timer_table[timer].name,
 		timer_table[timer].name,
@@ -1084,7 +1147,7 @@ void open_timer(int timer)
 
 
 	if (gtd->timer[timer][2] == 0)
 	if (gtd->timer[timer][2] == 0)
 	{
 	{
-		gtd->timer[timer][2] = current_time ;
+		gtd->timer[timer][2] = current_time;
 	}
 	}
 	else
 	else
 	{
 	{

File diff suppressed because it is too large
+ 480 - 527
src/utf8.c


+ 3 - 3
src/utils.c

@@ -471,7 +471,7 @@ void socket_printf(struct session *ses, size_t length, char *format, ...)
 	}
 	}
 }
 }
 
 
-void telnet_printf(struct session *ses, size_t length, char *format, ...)
+void telnet_printf(struct session *ses, int length, char *format, ...)
 {
 {
 	size_t size;
 	size_t size;
 
 
@@ -482,7 +482,7 @@ void telnet_printf(struct session *ses, size_t length, char *format, ...)
 	size = vsprintf(buf, format, args);
 	size = vsprintf(buf, format, args);
 	va_end(args);
 	va_end(args);
 
 
-	if (size != length && HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG))
+	if (length != -1 && size != length && HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG))
 	{
 	{
 		tintin_printf(ses, "DEBUG TELNET: telnet_printf size difference: %d vs %d", size, length);
 		tintin_printf(ses, "DEBUG TELNET: telnet_printf size difference: %d vs %d", size, length);
 	}
 	}
@@ -491,7 +491,7 @@ void telnet_printf(struct session *ses, size_t length, char *format, ...)
 	{
 	{
 		SET_BIT(ses->telopts, TELOPT_FLAG_TELNET);
 		SET_BIT(ses->telopts, TELOPT_FLAG_TELNET);
 
 
-		write_line_mud(ses, buf, length);
+		write_line_mud(ses, buf, size);
 
 
 		DEL_BIT(ses->telopts, TELOPT_FLAG_TELNET);
 		DEL_BIT(ses->telopts, TELOPT_FLAG_TELNET);
 	}
 	}

+ 326 - 41
src/variable.c

@@ -69,7 +69,7 @@ DO_COMMAND(do_variable)
 	}
 	}
 	else
 	else
 	{
 	{
-		if (is_math(ses, arg1))
+		if (!valid_variable(ses, arg1))
 		{
 		{
 			show_message(ses, LIST_VARIABLE, "#VARIABLE: INVALID VARIALBE NAME {%s}.", arg1);
 			show_message(ses, LIST_VARIABLE, "#VARIABLE: INVALID VARIALBE NAME {%s}.", arg1);
 			return ses;
 			return ses;
@@ -115,7 +115,17 @@ DO_COMMAND(do_local)
 	}
 	}
 	else if (*arg1 && *arg == 0)
 	else if (*arg1 && *arg == 0)
 	{
 	{
-		node = search_nest_node(root, arg1);
+		root = search_nest_base_ses(ses, arg1);
+
+		if (root)
+		{
+			node = search_nest_node_ses(ses, arg1);
+		}
+		else
+		{
+			root = local_list(ses);
+			node = NULL;
+		}
 
 
 		if (node)
 		if (node)
 		{
 		{
@@ -132,7 +142,7 @@ DO_COMMAND(do_local)
 
 
 		arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 
 
-		node = set_nest_node(root, arg1, "%s", str);
+		node = set_nest_node_ses(ses, arg1, "%s", str);
 
 
 		while (*arg)
 		while (*arg)
 		{
 		{
@@ -149,6 +159,8 @@ DO_COMMAND(do_local)
 		show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
 		show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
 
 
 		str_free(str);
 		str_free(str);
+
+		SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -176,11 +188,52 @@ DO_COMMAND(do_unvariable)
 	return ses;
 	return ses;
 }
 }
 
 
+DO_COMMAND(do_cat)
+{
+	char arg1[BUFFER_SIZE], *str;
+	struct listnode *node;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0 || *arg == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: CAT {<VARIABLE>} {<ARGUMENT>}");
+	}
+	else
+	{
+		str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
+
+		if ((node = search_nest_node_ses(ses, arg1)) == NULL)
+		{
+			arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
+
+			node = set_nest_node(ses->list[LIST_VARIABLE], arg1, "%s", str);
+		}
+
+		while (*arg)
+		{
+			arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
+
+			check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", arg1, arg1, str);
+
+			if (*str)
+			{
+				str_cat(&node->arg2, str);
+			}
+		}
+
+		check_all_events(ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", arg1, arg1, str);
+
+		show_message(ses, LIST_VARIABLE, "#CAT: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, node->arg2);
+
+		str_free(str);
+	}
+	return ses;
+}
 
 
 DO_COMMAND(do_replace)
 DO_COMMAND(do_replace)
 {
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], buf[BUFFER_SIZE], tmp[BUFFER_SIZE], *pti, *ptm;
-	struct listroot *root;
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], tmp[BUFFER_SIZE], *pti, *ptm, *str;
 	struct listnode *node;
 	struct listnode *node;
 
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
@@ -194,18 +247,11 @@ DO_COMMAND(do_replace)
 		return ses;
 		return ses;
 	}
 	}
 
 
-	root = local_list(ses);
-
-	if ((node = search_nest_node(root, arg1)) == NULL)
+	if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 	{
 	{
-		root = ses->list[LIST_VARIABLE];
+		show_error(ses, LIST_VARIABLE, "#REPLACE: VARIABLE {%s} NOT FOUND.", arg1);
 
 
-		if ((node = search_nest_node(root, arg1)) == NULL)
-		{
-			show_error(ses, LIST_VARIABLE, "#REPLACE: VARIABLE {%s} NOT FOUND.", arg1);
-
-			return ses;
-		}
+		return ses;
 	}
 	}
 
 
 	if (tintin_regexp(ses, NULL, node->arg2, arg2, 0, REGEX_FLAG_CMD) == FALSE)
 	if (tintin_regexp(ses, NULL, node->arg2, arg2, 0, REGEX_FLAG_CMD) == FALSE)
@@ -215,7 +261,7 @@ DO_COMMAND(do_replace)
 	else
 	else
 	{
 	{
 		pti = node->arg2;
 		pti = node->arg2;
-		*buf = 0;
+		str = str_dup("");
 
 
 		do
 		do
 		{
 		{
@@ -235,19 +281,36 @@ DO_COMMAND(do_replace)
 
 
 			substitute(ses, arg3, tmp, SUB_CMD);
 			substitute(ses, arg3, tmp, SUB_CMD);
 
 
-			cat_sprintf(buf, "%s%s", pti, tmp);
+			str_cat_printf(&str, "%s%s", pti, tmp);
 
 
 			pti = ptm + strlen(gtd->cmds[0]);
 			pti = ptm + strlen(gtd->cmds[0]);
 		}
 		}
 		while (tintin_regexp(ses, NULL, pti, arg2, 0, REGEX_FLAG_CMD));
 		while (tintin_regexp(ses, NULL, pti, arg2, 0, REGEX_FLAG_CMD));
 
 
-		strcat(buf, pti);
+		str_cat(&str, pti);
+
+		str_cpy(&node->arg2, str);
 
 
-		set_nest_node(root, arg1, "%s", buf);
+		str_free(str);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
 
 
+int valid_variable(struct session *ses, char *arg)
+{
+	if (*arg == 0)
+	{
+		return FALSE;
+	}
+
+	if (is_math(ses, arg))
+	{
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 /*
 /*
 	support routines for #format
 	support routines for #format
 */
 */
@@ -272,7 +335,7 @@ void numbertocharacter(struct session *ses, char *str)
 	{
 	{
 		sprintf(str, "%c", (int) get_number(ses, str));
 		sprintf(str, "%c", (int) get_number(ses, str));
 	}
 	}
-	else if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5))
+	else if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
 	{
 	{
 		sprintf(str, "%c%c", (unsigned int) get_number(ses, str) % 256, (unsigned int) get_number(ses, str) / 256);
 		sprintf(str, "%c%c", (unsigned int) get_number(ses, str) % 256, (unsigned int) get_number(ses, str) / 256);
 	}
 	}
@@ -290,9 +353,16 @@ void charactertonumber(struct session *ses, char *str)
 {
 {
 	int result;
 	int result;
 
 
-	if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && is_big5(str))
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
 	{
 	{
-		result = (unsigned char) str[0] + (unsigned char) str[1] * 256;
+		if (get_euc_size(ses, str) == 4)
+		{
+			result = (unsigned char) str[0] + (unsigned char) str[1] * 256 + (unsigned char) str[2] * 256 * 256 + (unsigned char) str[3] * 256 * 256 * 256;
+		}
+		else
+		{
+			result = (unsigned char) str[0] + (unsigned char) str[1] * 256;
+		}
 	}
 	}
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
 	{
 	{
@@ -307,9 +377,16 @@ void charactertonumber(struct session *ses, char *str)
 
 
 void charactertohex(struct session *ses, char *str)
 void charactertohex(struct session *ses, char *str)
 {
 {
-	if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) && is_big5(str))
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
 	{
 	{
-		sprintf(str, "%u", (unsigned char) str[0] + (unsigned char) str[1] * 256);
+		if (get_euc_size(ses, str) == 4)
+		{
+			sprintf(str, "%u", (unsigned char) str[0] + (unsigned char) str[1] * 256 + (unsigned char) str[2] * 256 * 256 + (unsigned char) str[3] * 256 * 256 * 256);
+		}
+		else
+		{
+			sprintf(str, "%u", (unsigned char) str[0] + (unsigned char) str[1] * 256);
+		}
 	}
 	}
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
 	else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
 	{
 	{
@@ -335,6 +412,81 @@ void colorstring(struct session *ses, char *str)
 	strcpy(str, result);
 	strcpy(str, result);
 }
 }
 
 
+int translate_color_names(struct session *ses, char *string, char *result)
+{
+	int cnt;
+
+	*result = 0;
+
+	if (*string == '<')
+	{
+		strcpy(result, string);
+
+		return TRUE;
+	}
+
+	if (*string == '\\')
+	{
+		strcpy(result, string);
+
+		return TRUE;
+	}
+
+	while (*string)
+	{
+
+		if (isalpha(*string))
+		{
+			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+			{
+				if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
+				{
+					result += sprintf(result, "%s", color_table[cnt].code);
+
+					break;
+				}
+			}
+
+			if (*color_table[cnt].name == 0)
+			{
+				for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+				{
+					if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
+					{
+						result += sprintf(result, "%s", color_table[cnt].code);
+
+						break;
+					}
+				}
+
+				if (*color_table[cnt].name == 0)
+				{
+					return FALSE;
+				}
+			}
+			string += strlen(color_table[cnt].name);
+		}
+
+		switch (*string)
+		{
+			case ' ':
+			case ';':
+			case ',':
+			case '{':
+			case '}':
+				string++;
+				break;
+
+			case 0:
+				return TRUE;
+
+			default:
+				return FALSE;
+		}
+	}
+	return TRUE;
+}
+
 int get_color_names(struct session *ses, char *string, char *result)
 int get_color_names(struct session *ses, char *string, char *result)
 {
 {
 	int cnt;
 	int cnt;
@@ -413,20 +565,24 @@ int get_color_names(struct session *ses, char *string, char *result)
 	return TRUE;
 	return TRUE;
 }
 }
 
 
-void headerstring(char *str)
+void headerstring(struct session *ses, char *str)
 {
 {
-	char buf[BUFFER_SIZE];
+	char buf[BUFFER_SIZE], fill[BUFFER_SIZE];
+	int len, max;
 
 
-	if ((int) strlen(str) > gtd->screen->cols - 2)
+	len = string_raw_str_len(ses, str, 0, BUFFER_SIZE);
+	max =  get_scroll_cols(ses);
+
+	if (len > max - 2)
 	{
 	{
-		str[gtd->screen->cols - 2] = 0;
-	}
+		str[max] = 0;
 
 
-	memset(buf, '#', gtd->screen->cols);
+		return;
+	}
 
 
-	memcpy(&buf[(gtd->screen->cols - strlen(str)) / 2], str, strlen(str));
+	memset(fill, '#', max);
 
 
-	buf[gtd->screen->cols] = 0;
+	sprintf(buf, "%.*s%s%.*s%s", (max - len) / 2, fill, str, (max - len) / 2, fill, (max - len) % 2 ? "#" : "");
 
 
 	strcpy(str, buf);
 	strcpy(str, buf);
 }
 }
@@ -521,6 +677,131 @@ void thousandgroupingstring(struct session *ses, char *str)
 	strcpy(str, result + cnt2 + 1);
 	strcpy(str, result + cnt2 + 1);
 }
 }
 
 
+void chronosgroupingstring(struct session *ses, char *str)
+{
+	char *sign = "-";
+	long long val = (long long) get_number(ses, str);
+	int days, hours, minutes, seconds;
+
+	if (val < 0)
+	{
+		val *= -1;
+	}
+	else
+	{
+		sign = "";
+	}
+
+	seconds = val % 60;
+	val /= 60;
+
+	minutes = val % 60;
+	val /= 60;
+
+	hours = val % 24;
+	val /= 24;
+
+	days = val;
+
+	if (days)
+	{
+		sprintf(str, "%s%d:%02d:%02d:%02d", sign, days, hours, minutes, seconds);
+	}
+	else if (hours)
+	{
+		sprintf(str, "%s%d:%02d:%02d", sign, hours, minutes, seconds);
+	}
+	else
+	{
+		sprintf(str, "%s%d:%02d", sign, minutes, seconds);
+	}
+}
+
+void metricgroupingstring(struct session *ses, char *str)
+{
+	char big[]   = {' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', '?', '?', '?', '?', '?', '?', '?', '?'};
+	char small[] = {' ', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y', '?', '?', '?', '?', '?', '?', '?', '?'};
+	char tmp[NUMBER_SIZE];
+	long double val = get_number(ses, str);
+	int index = 0;
+
+	if (val >= 1000)
+	{
+                while (val >= 1000)
+                {
+                        val = val / 1000;
+                        index++;
+                }
+                if (val >= 100)
+                {
+                	sprintf(tmp, " %Lf", val);
+		}
+		else
+		{
+                	sprintf(tmp, "%Lf", val);
+		}
+                sprintf(str, "%.4s%c", tmp, big[index]);
+	}
+	else if (val > 0 && val < 0.01)
+	{
+		while (val < 0.01)
+		{
+			val = val * 1000;
+			index++;
+		}
+		sprintf(tmp, "%Lf", val);
+		sprintf(str, "%.4s%c", tmp, small[index]);
+	}
+	else if (val >= 0)
+	{
+		if (val >= 100)
+		{
+			sprintf(tmp, " %Lf", val);
+		}
+		else
+		{
+			sprintf(tmp, "%Lf", val);
+		}
+		sprintf(str, "%.4s%c", tmp, big[index]);
+	}
+	else if (val <= -0.01 && val > -1000)
+	{
+		if (val <= -100)
+		{
+			sprintf(tmp, " %Lf", val);
+		}
+		else
+		{
+			sprintf(tmp, "%Lf", val);
+		} 
+		sprintf(str, "%.5s%c", tmp, small[index]);
+	}
+	else if (val <= -1000)
+	{
+                while (val <= -100)
+                {
+                        if (val <= -10000)
+                        {
+                                val = (long double) ((long long) val / 100LL * 100LL);
+                        }
+                        val = val / 1000;
+                        index++;
+                }
+                sprintf(tmp, "%Lf", val);
+                sprintf(str, "%.5s%c", tmp, big[index]);
+	}
+
+	else if (val < 0 /*&& val > -0.01*/)
+	{
+		while (val > -0.01)
+		{
+			val = val * 1000;
+			index++;
+		}
+		sprintf(tmp, "%Lf", val);
+		sprintf(str, "%.5s%c", tmp, small[index]);
+	}
+}
 
 
 void stripspaces(char *str)
 void stripspaces(char *str)
 {
 {
@@ -741,7 +1022,13 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 			continue;
 			continue;
 		}
 		}
 
 
-		if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC)  && is_euc_head(ses, &str[raw_cnt]))
+		{
+			raw_cnt += get_euc_width(ses, &str[raw_cnt], &width);
+
+			ret_cnt += width;
+		}
+		else if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{
 		{
 			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
 			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
 
 
@@ -964,7 +1251,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						break;
 						break;
 
 
 					case 'h':
 					case 'h':
-						headerstring(arglist[i]);
+						headerstring(ses, arglist[i]);
 						break;
 						break;
 
 
 					case 'l':
 					case 'l':
@@ -1012,7 +1299,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						break;
 						break;
 
 
 					case 'C':
 					case 'C':
-						sprintf(arglist[i], "%d", gtd->screen->cols);
+						chronosgroupingstring(ses, arglist[i]);
 						break;
 						break;
 
 
 					case 'D':
 					case 'D':
@@ -1038,19 +1325,17 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						sprintf(arglist[i], "%d", stringlength(ses, arglist[i]));
 						sprintf(arglist[i], "%d", stringlength(ses, arglist[i]));
 						break;
 						break;
 
 
-					// undocumented
 					case 'M':
 					case 'M':
-						timeval_t  = (time_t) *arglist[i] ? atoll(arglist[i]) : gtd->time;
-						timeval_tm = *localtime(&timeval_t);
-						strftime(arglist[i], BUFFER_SIZE, "%m", &timeval_tm);
+						metricgroupingstring(ses, arglist[i]);
 						break;
 						break;
 
 
 					case 'R':
 					case 'R':
+						tintin_printf2(ses, "\e[1;31m#echo/#format %%R please use #screen {get} {rows} to get screen height.");
 						sprintf(arglist[i], "%d", gtd->screen->rows);
 						sprintf(arglist[i], "%d", gtd->screen->rows);
 						break;
 						break;
 
 
 					case 'S':
 					case 'S':
-						sprintf(arglist[i], "%s", ses->name);
+						sprintf(arglist[i], "%d", spellcheck_count(ses, arglist[i]));
 						break;
 						break;
 
 
 					case 'T':
 					case 'T':
@@ -1111,7 +1396,7 @@ DO_COMMAND(do_format)
 
 
 	format_string(ses, format, arg, result);
 	format_string(ses, format, arg, result);
 
 
-	set_nest_node(ses->list[LIST_VARIABLE], destvar, "%s", result);
+	set_nest_node_ses(ses, destvar, "%s", result);
 
 
 	show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", destvar, result);
 	show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", destvar, result);
 
 

+ 86 - 9
src/vt102.c

@@ -1,7 +1,7 @@
 /******************************************************************************
 /******************************************************************************
 *   This file is part of TinTin++                                             *
 *   This file is part of TinTin++                                             *
 *                                                                             *
 *                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
 *                                                                             *
 *                                                                             *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   TinTin++ is free software; you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by      *
 *   it under the terms of the GNU General Public License as published by      *
@@ -13,13 +13,12 @@
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU General Public License for more details.                              *
 *   GNU General Public License for more details.                              *
 *                                                                             *
 *                                                                             *
-*                                                                             *
 *   You should have received a copy of the GNU General Public License         *
 *   You should have received a copy of the GNU General Public License         *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
 ******************************************************************************/
 ******************************************************************************/
 
 
 /******************************************************************************
 /******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
+*                               T I N T I N + +                               *
 *                                                                             *
 *                                                                             *
 *                      coded by Igor van den Hoven 2004                       *
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 ******************************************************************************/
@@ -56,7 +55,11 @@ void save_pos(struct session *ses)
 	{
 	{
 		syserr_printf(ses, "sav_lev++ above 1000.");
 		syserr_printf(ses, "sav_lev++ above 1000.");
 	}
 	}
-	print_stdout("\e[?25l");
+
+	if (!HAS_BIT(gtd->flags, TINTIN_FLAG_HIDDENCURSOR))
+	{
+		print_stdout("\e[?25l");
+	}
 
 
 	pop_call();
 	pop_call();
 	return;
 	return;
@@ -82,7 +85,11 @@ void restore_pos(struct session *ses)
 	{
 	{
 		goto_pos(ses, gtd->screen->sav_row[gtd->screen->sav_lev], gtd->screen->sav_col[gtd->screen->sav_lev]);
 		goto_pos(ses, gtd->screen->sav_row[gtd->screen->sav_lev], gtd->screen->sav_col[gtd->screen->sav_lev]);
 	}
 	}
-	print_stdout("\e[?25h");
+
+	if (!HAS_BIT(gtd->flags, TINTIN_FLAG_HIDDENCURSOR))
+	{
+		print_stdout("\e[?25h");
+	}
 
 
 	SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
 	SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
 }
 }
@@ -178,7 +185,7 @@ void reset_scroll_region(struct session *ses)
 
 
 int skip_vt102_codes(char *str)
 int skip_vt102_codes(char *str)
 {
 {
-	int skip;
+	int skip = 0;
 
 
 	push_call("skip_vt102_codes(%p)",str);
 	push_call("skip_vt102_codes(%p)",str);
 
 
@@ -187,8 +194,8 @@ int skip_vt102_codes(char *str)
 		case   5:   /* ENQ */
 		case   5:   /* ENQ */
 		case   7:   /* BEL */
 		case   7:   /* BEL */
 		case   8:   /* BS  */
 		case   8:   /* BS  */
-	/*	case   9: *//* HT  */
-	/*	case  10: *//* LF  */
+	//	case   9:      HT
+	//	case  10:      LF
 		case  11:   /* VT  */
 		case  11:   /* VT  */
 		case  12:   /* FF  */
 		case  12:   /* FF  */
 		case  13:   /* CR  */
 		case  13:   /* CR  */
@@ -198,13 +205,26 @@ int skip_vt102_codes(char *str)
 		case  19:   /* DC3 */
 		case  19:   /* DC3 */
 		case  24:   /* CAN */
 		case  24:   /* CAN */
 		case  26:   /* SUB */
 		case  26:   /* SUB */
-		case 127:   /* DEL */
 			pop_call();
 			pop_call();
 			return 1;
 			return 1;
 
 
 		case  27:   /* ESC */
 		case  27:   /* ESC */
 			break;
 			break;
 
 
+		case  28: // HTML_OPEN
+			for (skip = 1 ; str[skip] ; skip++)
+			{
+				if (str[skip] == 30) // HTML_CLOSE
+				{
+					return skip + 1;
+				}
+			}
+			return 0;
+
+		case 127:   /* DEL */
+			pop_call();
+			return 1;
+
 		default:
 		default:
 			pop_call();
 			pop_call();
 			return 0;
 			return 0;
@@ -319,6 +339,63 @@ int find_color_code(char *str)
 	return 0;
 	return 0;
 }
 }
 
 
+int find_secure_color_code(char *str)
+{
+	int skip, valid = 1;
+
+	switch (str[0])
+	{
+		case  27:   /* ESC */
+			break;
+
+		default:
+			return 0;
+	}
+
+	switch (str[1])
+	{
+		case '[':
+			break;
+
+		default:
+			return 0;
+	}
+
+	for (skip = 2 ; str[skip] != 0 ; skip++)
+	{
+		switch (str[skip])
+		{
+			case 'm':
+				if (valid)
+				{
+					return skip + 1;
+				}
+				return 0;
+
+			case ';':
+				valid = 0;
+				break;
+
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				valid = 1;
+				break;
+
+			default:
+				return 0;
+		}
+	}
+	return 0;
+}
+
 
 
 int skip_vt102_codes_non_graph(char *str)
 int skip_vt102_codes_non_graph(char *str)
 {
 {

Some files were not shown because too many files changed in this diff