invis-patch/
diff -ur pgplus.old/doc/help pgplus/doc/help
--- pgplus.old/doc/help	Thu Dec  2 06:26:56 1999
+++ pgplus/doc/help	Sat Jul 29 18:52:02 2000
@@ -3642,7 +3642,8 @@
 :w
 
 W  - provides a more detailed listing of who is on the program along with
-     their rank, location and idle time.
+     their rank, location and idle time. People who are invisible but  
+     are visible to you will be shown with an [i] in front of their name.
 
 (Code written by tonhE)
 
@@ -3694,7 +3695,8 @@
 
 :who
 
-WHO  - shows you who is on the program.
+WHO  - shows you who is on the program.  People who are currently
+invisible but visible to you will be shown with an [i] before their name.
 
 :whois
 
@@ -4263,3 +4265,30 @@
   Release date:  8th July 1999
   Initial date:  30th November 1998
 		
+:invis
+
+INVIS -	Go invisible.
+
+	When you go 'invis', you become invisible to all functions like
+	'who' and 'tell'.  You can not see room conversations or use
+	room communication in any room, and you can only communicate in
+	tells to people who can 'see' you.  You can allow people to see
+	you while invisible by using the 'vis' list flag.  See help 'vis'
+	for more details.
+
+	To calm any fears, yes admins can see everyone who is invisible
+	(so they can talk to people who are get stuck invisible, etc)
+	but they have no other special privileges.  No, they can not
+	see room conversations.
+
+	The source code to invis will be released on astyanax's homepage
+	at http://www.asty.org when more thoroughly tested.
+
+:vis
+
+VIS - 	Add someone to your 'visibility' list.  Anyone you have flagged
+	for 'vis' can see you when you connect and disconnect, even when
+	you are invisible. They can also see you in the 'who' 'w' and
+	other system info lists (invisible people appear with a
+	^Y[i]^N next to their name).
+
diff -ur pgplus.old/src/admin.c pgplus/src/admin.c
--- pgplus.old/src/admin.c	Sat Jul 29 16:52:18 2000
+++ pgplus/src/admin.c	Sat Jul 29 18:26:55 2000
@@ -3403,6 +3403,9 @@
     char *oldstack = stack;
 
 
+    if (check_invis(p))
+	return;
+
     if (p->flags & BLOCK_SU) {
 	tell_player(p, " Try going back on duty first, biiach! =)\n");
 	return;
diff -ur pgplus.old/src/admin2.c pgplus/src/admin2.c
--- pgplus.old/src/admin2.c	Sat Jul 29 16:52:18 2000
+++ pgplus/src/admin2.c	Sat Jul 29 18:26:55 2000
@@ -1419,7 +1419,7 @@
 
 void lsu(player * p, char *str)
 {
-    int count = 0;
+    int count = 0, i = 0;
     char *oldstack, *prestack, middle[80];
     player *scan;
     int current_supers;
@@ -1440,7 +1440,7 @@
 
     for (scan = flatlist_start; scan; scan = scan->flat_next) {
 	prestack = stack;
-	if (scan->location && scan->residency & PSU) {
+	if (scan->location && scan->residency & PSU && !is_invis(scan)) {
 	    if (p->residency & PSU && *str != '-') {
 		count++;
 		*stack = ' ';
@@ -1526,10 +1526,10 @@
 	    /* This used to be really complicated but stupid since all the su's
 	       would think it was a bug if they weren't listed on LSU - so now they
 	       all are --Silver */
-	    else if (!(scan->flags & OFF_LSU) && !(scan->flags & BLOCK_SU)
-		     && scan->
-		     residency & (SU | ASU | LOWER_ADMIN | ADMIN | HCADMIN
-				  | CODER)) {
+	    else if (!(scan->flags & OFF_LSU) &&
+		     !(scan->flags & BLOCK_SU) && !is_invis(scan)
+		     && scan->residency & (SU | ASU | LOWER_ADMIN | ADMIN |
+					   HCADMIN | CODER)) {
 		count++;
 		*stack = ' ';
 		stack++;
diff -ur pgplus.old/src/channel.c pgplus/src/channel.c
--- pgplus.old/src/channel.c	Sat Jul 29 16:52:18 2000
+++ pgplus/src/channel.c	Sat Jul 29 18:26:55 2000
@@ -378,21 +378,33 @@
  */
 void ce(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "ce") && is_on_channel(p, NO_MAIN_CHANNEL))
 	channel_emote(p, str, cu_chan);
 }
 void cs(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "cs") && is_on_channel(p, NO_MAIN_CHANNEL))
 	channel_sing(p, str, cu_chan);
 }
 void ct(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "ct") && is_on_channel(p, NO_MAIN_CHANNEL))
 	channel_think(p, str, cu_chan);
 }
 void cu(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "cu") && is_on_channel(p, NO_MAIN_CHANNEL))
 	channel_say(p, str, cu_chan);
 }
@@ -432,21 +444,33 @@
  */
 void pe(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "pe") && is_on_channel(p, NO_SPOD_CHANNEL))
 	channel_emote(p, str, pu_chan);
 }
 void ps(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "ps") && is_on_channel(p, NO_SPOD_CHANNEL))
 	channel_sing(p, str, pu_chan);
 }
 void pt(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "pt") && is_on_channel(p, NO_SPOD_CHANNEL))
 	channel_think(p, str, pu_chan);
 }
 void pu(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "pu") && is_on_channel(p, NO_SPOD_CHANNEL))
 	channel_say(p, str, pu_chan);
 }
@@ -457,21 +481,33 @@
  */
 void suemote(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "se") && not_blocking_su_channel(p))
 	channel_emote(p, str, su_chan);
 }
 void susing(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "ss") && not_blocking_su_channel(p))
 	channel_sing(p, str, su_chan);
 }
 void suthink(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "st") && not_blocking_su_channel(p))
 	channel_think(p, str, su_chan);
 }
 void su(player * p, char *str)
 {
+    if (check_invis(p))
+	return;
+
     if (got_msg(p, str, "su") && not_blocking_su_channel(p))
 	channel_say(p, str, su_chan);
 }
diff -ur pgplus.old/src/commands.c pgplus/src/commands.c
--- pgplus.old/src/commands.c	Sat Jul 29 16:52:18 2000
+++ pgplus/src/commands.c	Sat Jul 29 18:47:17 2000
@@ -404,7 +404,7 @@
 
     for (count = 0; (count < (TERM_LINES - 1) && scan);
 	 scan = scan->flat_next) {
-	if (scan->name[0] && scan->location) {
+	if (scan->name[0] && scan->location && can_see(p, scan)) {
 	    if (p->custom_flags & NOPREFIX) {
 		strcpy(namestring, scan->name);
 	    } else if ((*scan->pretitle)) {
@@ -1647,8 +1647,12 @@
 
     for (count = 0; (count < (TERM_LINES - 1) && scan);
 	 scan = scan->flat_next) {
-	if (scan->location) {
-	    sprintf(stack, "    %-18s ", scan->name);
+	if (scan->location && can_see(p, scan)) {
+	    if (is_invis(scan))
+		sprintf(stack, "^Y[i]^n %-18s ", scan->name);
+	    else
+		sprintf(stack, "    %-18s ", scan->name);
+
 	    stack = strchr(stack, 0);
 #ifdef ROBOTS
 	    if (scan->residency & ROBOT_PRIV)
@@ -1993,4 +1997,220 @@
 	tell_player(p, " (which is being checked now)\n");
     }
     return 0;
+}
+
+
+void fake_login(player * p)
+{
+    char *oldstack, *hello;
+
+    oldstack = stack;
+
+    current_players++;
+    p->on_since = time(0);
+    logins++;
+
+#ifdef LAST
+    stampLogin(p->name);
+#endif
+
+    if (!(p->location)) {
+	trans_to(p, sys_room_id(ENTRANCE_ROOM));
+    }
+    do_invis_login(p);
+    p->misc_flags ^= INVIS_ATM;
+
+    if (strlen(p->logonmsg) < 1) {
+	stack += sprintf(stack, "%s %s enters the program. ",
+			 get_config_msg("logon_prefix"), p->name);
+	stack += sprintf(stack, "^N%s\n", get_config_msg("logon_suffix"));
+    } else {
+	if (*p->logonmsg == 39 || *p->logonmsg == ',') {
+	    stack += sprintf(stack, "%s %s%s ",
+			     get_config_msg("logon_prefix"), p->name,
+			     p->logonmsg);
+	    stack +=
+		sprintf(stack, "^N%s\n", get_config_msg("logon_suffix"));
+	} else {
+	    stack += sprintf(stack, "%s %s %s ",
+			     get_config_msg("logon_prefix"), p->name,
+			     p->logonmsg);
+	    stack +=
+		sprintf(stack, "^N%s\n", get_config_msg("logon_suffix"));
+	}
+    }
+    stack = end_string(oldstack);
+    command_type |= LOGIN_TAG;
+    tell_room(p->location, oldstack);
+    command_type &= ~LOGIN_TAG;
+
+    if (p->saved) {
+	if (p->flags & RECONNECTION) {
+	    hello = do_alias_match(p, "_recon");
+	    if (strcmp(hello, "\n"))
+		match_commands(p, "_recon");
+	} else {
+	    hello = do_alias_match(p, "_logon");
+	    if (strcmp(hello, "\n"))
+		match_commands(p, "_logon");
+	}
+    }
+    /* clear the chanflags, just in case... */
+    if (p->flags & RECONNECTION)
+	p->flags &= ~RECONNECTION;
+
+    stack = oldstack;
+    return;
+}
+
+void fake_quit(player * p)
+{
+    char *oldstack, *hasta;
+
+    oldstack = stack;
+
+#ifdef LAST
+    stampLogout(p->name);
+#endif
+
+    if (p->residency & SU && true_count_su() <= 1)
+	su_quit_log(p);
+
+    hasta = do_alias_match(p, "_logoff");
+    if (strcmp(hasta, "\n")) {
+	match_commands(p, "_logoff");
+    }
+    if (p == p_sess) {
+	session_reset = 0;
+    }
+    if (strlen(p->logoffmsg) < 1) {
+	stack += sprintf(stack, "%s %s ",
+			 get_config_msg("logoff_prefix"), p->name);
+	stack += sprintf(stack, "%s ", get_config_msg("def_logout"));
+	stack += sprintf(stack, "^N%s\n", get_config_msg("logoff_suffix"));
+    } else {
+	if (emote_no_break(*p->logoffmsg)) {
+	    stack +=
+		sprintf(stack, "%s %s%s ", get_config_msg("logoff_prefix"),
+			p->name, p->logoffmsg);
+	    stack +=
+		sprintf(stack, "^N%s\n", get_config_msg("logoff_suffix"));
+	} else {
+	    stack +=
+		sprintf(stack, "%s %s %s ",
+			get_config_msg("logoff_prefix"), p->name,
+			p->logoffmsg);
+	    stack +=
+		sprintf(stack, "^N%s\n", get_config_msg("logoff_suffix"));
+	}
+    }
+
+    stack = end_string(stack);
+    command_type |= LOGOUT_TAG;
+    tell_room(p->location, oldstack);
+    command_type &= ~LOGOUT_TAG;
+    stack = oldstack;
+    save_player(p);
+    current_players--;
+    p->misc_flags ^= INVIS_ATM;
+    do_invis_logout(p);
+    if (p->saved && !(p->flags & NO_SAVE_LAST_ON))
+	p->saved->last_on = time(0);
+}
+
+void go_invis(player * p, char *str)
+{
+    if (!(p->misc_flags & INVIS_ATM)) {
+	fake_quit(p);
+	TELLPLAYER(p,
+		   " You fade into the shadows and become invisible...\n");
+    } else {
+	fake_login(p);
+	p->suh_seen = 0;
+	p->total_login += p->time_invis;
+	p->time_invis = 0;
+	TELLPLAYER(p, " Your invisibility spell wears off...\n");
+    }
+}
+
+int is_invis(player * p)
+{
+    if (!p->name || !p->location)
+	return -1;
+
+    if (p->misc_flags & INVIS_ATM)
+	return 1;
+    else
+	return 0;
+}
+
+int can_see(player * p, player * q)
+{
+    list_ent *invis_ent;
+
+    /* HACK!!!! */
+    if (!p || !q)
+	return 1;
+
+    if (!p->name[0] || !p->location)
+	return 0;
+
+    if (!q->name[0] || !q->location)
+	return 0;
+
+    if (!strcmp(p->lower_name, q->lower_name))
+	return 1;
+
+    /* Admins can see everyone.....for now */
+    if (p->residency & ADMIN)
+	return 1;
+
+    /* Does the see-ee have the invisible priv? */
+    if (!(q->residency & INVISPRIV))
+	return 1;
+
+    /* Are they even invisible? */
+    if (!(q->misc_flags & INVIS_ATM))
+	return 1;
+
+    invis_ent = find_list_entry(q, p->lower_name);
+    if (ENT_FLAGS(invis_ent, INVISLIST))
+	return 1;
+    else
+	return 0;
+}
+
+int check_invis(player * p)
+{
+    if (is_invis(p)) {
+	tell_player(p, " Sorry, you can not do that while invisible.\n");
+	return 1;
+    } else
+	return 0;
+}
+
+int tell_to_invis(player * p, player * q)
+{
+    if (is_invis(q) && !can_see(p, q)) {
+	TELLPLAYER(p, " No one of the name \'%s\' on at the moment\n",
+		   q->name);
+	return 1;
+    } else
+	return 0;
+}
+
+int colorless_strlen(char *str)
+{
+    int i, len = 0;
+
+    for (i = 0; str[i] != 0; i++) {
+	if (str[i] == '^') {
+	    if (str[++i] == 0)
+		return len;
+	} else
+	    len++;
+    }
+
+    LOGF("error", "colorless_strlen for str \"%s\" returned %d", str, len);
+    return len;
 }
diff -ur pgplus.old/src/examine.c pgplus/src/examine.c
--- pgplus.old/src/examine.c	Sat Jul 29 16:52:18 2000
+++ pgplus/src/examine.c	Sat Jul 29 18:26:55 2000
@@ -169,6 +169,9 @@
 	if (priv & TRACE)
 	    ADDSTACK(" You can trace login sites.\n");
 
+	if (priv & INVISPRIV)
+	    ADDSTACK(" You possess a scroll of invisibility *grin*.\n");
+
 	/* added a lil tiny extra for those talkers that get creative
 	   with there privs so staff will know exactly where they stand
 	 */
@@ -190,11 +193,6 @@
 	else
 	    ADDSTACK("standard resident.\n");
 
-	/* in following with the tradition of changing this 
-	   as new releases are done.... */
-	if (priv & HOUSE)
-	    ADDSTACK(" You are one with the inner child\n");
-
     }
     if (who == 1)
 	/* privs for someone else */
@@ -270,6 +268,9 @@
 	    if (priv & TRACE)
 		ADDSTACK("%s can trace login sites.\n", name);
 
+	    if (priv & INVISPRIV)
+		ADDSTACK("%s knows the invisibility spell.\n", name);
+
 	    ADDSTACK("%s's residency level is ", name);
 	    if (priv & CODER)
 		ADDSTACK("%s (coder).\n", get_config_msg("coder_name"));
@@ -289,10 +290,6 @@
 	    else
 		ADDSTACK("standard resident.\n");
 
-	    if (priv & HOUSE)
-		ADDSTACK("%s was rode hard and put up wet.\n", name);
-
-
 	    stack += sprintf(stack, "%s            " RES_BIT_HEAD "\n"
 			     "Residency   %s\n", LINE,
 			     privs_bit_string(p2->residency));
@@ -867,10 +864,16 @@
 	ADDSTACK(LINE "%s %s^N \n" LINE, p2->name, p2->title);
 
     if (p->jetlag) {
-	overtime = p2->on_since + (p->jetlag * 3600);
+	if (!can_see(p, p2))
+	    overtime = p2->saved->last_on + (p->jetlag * 3600);
+	else
+	    overtime = p2->on_since + (p->jetlag * 3600);
 	strcpy(datastring, "(Your time)");
     } else {
-	overtime = p2->on_since;
+	if (!can_see(p, p2))
+	    overtime = p2->saved->last_on;
+	else
+	    overtime = p2->on_since;
 	sprintf(datastring, "(%s time)", get_config_msg("talker_name"));
     }
 
@@ -879,10 +882,11 @@
     } else {
 	jettime = 0;
     }
-    if (p2 != &dummy) {
-	ADDSTACK("Time on so far      : %s\nLogged on at        : %s %s\n",
-		 word_time(time(0) - (p2->on_since)),
-		 convert_time(overtime), datastring);
+    if (p2 != &dummy && can_see(p, p2)) {
+
+	     ADDSTACK("Time on so far      : %s\nLogged on at        : %s %s\n",
+	     word_time(time(0) - (p2->on_since)), convert_time(overtime),
+	     datastring);
     } else if (p2->saved) {
 	if (p->jetlag) {
 	    ADDSTACK("Date last logged on : %s %s\n",
@@ -948,14 +952,14 @@
 	}
     }
     /* alt_email stolen for URL -- you probably knew that tho :P */
-    if (p2->alt_email[0])
+    if (p2->alt_email[0] && can_see(p, p2))
 	ADDSTACK("WWW homepage URL    : %s^N \n", p2->alt_email);
-    if (p2->icq)
+    if (p2->icq && can_see(p, p2))
 	ADDSTACK("ICQ number          : %d\n", p2->icq);
-    if (p2->hometown[0])
+    if (p2->hometown[0] && can_see(p, p2))
 	ADDSTACK("Place of residency  : %s^N \n", p2->hometown);
-    if (p2->
-	residency & (BUILDER | MINISTER | SPECIALK | SU | ADMIN | SPOD))
+    if (p2->residency &
+	(BUILDER | MINISTER | SPECIALK | SU | ADMIN | SPOD))
 	    ADDSTACK("Online Positions    : ");
     if (p2->residency & SPOD)
 	ADDSTACK("Spod ");
diff -ur pgplus.old/src/include/admin.h pgplus/src/include/admin.h
--- pgplus.old/src/include/admin.h	Wed Dec  1 06:27:22 1999
+++ pgplus/src/include/admin.h	Sat Jul 29 18:26:55 2000
@@ -24,7 +24,7 @@
    {"debug",		DEBUG},
    {"echo",		ECHO_PRIV},
    {"hcadmin",		HCADMIN|ADMIN|LOWER_ADMIN|ASU|SU|PSU|WARN|DUMB},
-   {"house",		HOUSE},
+   {"invis",		INVISPRIV},
    {"list",		LIST},
    {"lower_admin",	LOWER_ADMIN | SU | ASU | PSU | WARN | DUMB},
    {"mail",		MAIL},
@@ -32,7 +32,7 @@
    {"nosync",		NO_SYNC},
    {"no_timeout",	NO_TIMEOUT},
    {"psu",		PSU},
-   {"residency",	BASE | BUILD | LIST | ECHO_PRIV | MAIL | SESSION },
+   {"residency",	BASE | BUILD | LIST | ECHO_PRIV | MAIL | SESSION | INVISPRIV},
 #ifdef ROBOTS
    {"robot",		ROBOT_PRIV},
 #endif
@@ -43,6 +43,7 @@
    {"trace",		TRACE},
    {"su",		SU | PSU | WARN | DUMB},
    {"warn",		WARN},
+
    {"", 0}
 };
 
@@ -69,7 +70,7 @@
    {"debug",		HCADMIN},
    {"spod",		ASU},
    {"condom",		HCADMIN},
-   {"house",		LOWER_ADMIN},
+   {"invis",		ADMIN},
    {"minister",		ADMIN},
    {"script",		LOWER_ADMIN},
    {"trace",		LOWER_ADMIN},
Only in pgplus/src/include: autoconfig.h
diff -ur pgplus.old/src/include/clist.h pgplus/src/include/clist.h
--- pgplus.old/src/include/clist.h	Wed Dec  1 06:27:22 1999
+++ pgplus/src/include/clist.h	Sat Jul 29 18:26:55 2000
@@ -137,7 +137,7 @@
 	        set_made_from, fake_nuke_player;
 
 extern command_func     player_flags_verbose,blank_list, spodlist_view,
-		close_to_ressies, thinkin_wall, emoted_wall;
+		close_to_ressies, thinkin_wall, emoted_wall, go_invis, visible;
 
 /* extra commands added for Playground+ */
 
@@ -704,7 +704,7 @@
 {"eo", recho_others_friends, ECHO_PRIV, 0, 1, 0, INVISc|SPAMc},
 {"ereply", ereply, 0, 0, 1, 0, COMMc|SPAMc},
 {"etrace", use_search, ADMIN, 0, 1, 0, ADMINc}, 
-{"evict", sneeze, (SU | ADMIN), HOUSE, 1, 0, SUPERc|NOMATCHc},
+{"evict", sneeze, (SU | ADMIN), 0, 1, 0, SUPERc|NOMATCHc},
 {"ewall", emoted_wall, (LOWER_ADMIN | ADMIN), 0, 1, 0, ADMINc|NOMATCHc|SPAMc},
 {"examine", newexamine, 0, 0, 1, 0, INFOc},
 {"exclude", exclude, 0, 0, 1, 0, COMMc|M_SWEARc|SPAMc},
@@ -796,6 +796,7 @@
 #endif
 {"inv", inventory, BASE, 0, 1, 0, INVISc},
 {"inventory", inventory, BASE, 0, 1, 0, ITEMc},
+{"invis", go_invis, INVISPRIV, 0, 1, 0, MISCc},
 {"invite", invite, LIST, 0, 1, 0, LISTc},
 {"invites", invites_list, 0, 0, 1, 0, INFOc},
 {"irl_name", set_irl_name, BASE, 0, 1, 0, DESCc},
@@ -803,7 +804,7 @@
 {"is", is, BASE, 0, 1, 0, COMMc|SPAMc},
 {"it", it, BASE, 0, 1, 0, COMMc|SPAMc},
 #endif
-{"itrace", use_search, ADMIN, 0, 1, 0, ADMINc}, 
+{"itrace", use_search, SU, 0, 1, 0, SUPERc}, 
 #ifdef INTERCOM
 {"iu", iu, BASE, 0, 1, 0, COMMc|SPAMc},
 {"iw", i_who, BASE, 0, 1, 0, INFOc},
@@ -903,7 +904,7 @@
 {"marry", marry, MINISTER, 0, 1, 0, (INVISc|SYSc)},
 {"mball", eightball, 0, 0, 1, 0, MISCc},
 {"medit", marry_edit, ADMIN, 0, 1, 0, ADMINc},
-{"mindscape", go_home, BUILD, HOUSE, 1, 0, MOVEc},
+{"mindscape", go_home, BUILD, 0, 1, 0, MOVEc},
 {"mindseye", mindseye, BUILD, 0, 1, 0, (INFOc|ROOMc)},
 {"mode", mode, (PSU|SU|ADMIN), 0, 1, 0, SUPERc},
 {"motd", motd, 0, 0, 1, 0, INFOc},
@@ -1169,6 +1170,7 @@
 {"version", pg_version, 0, 0, 1, 0, MISCc},
 {"view_note", view_note, ADMIN, 0, 1, 0, ADMINc},
 {"view_flags", view_people_and_flags, ADMIN, 0, 1, 0, ADMINc},
+{"vis", visible, 0, 0, 1, 0, LISTc},
 {"visit", visit, 0, 0, 1, 0, MOVEc},
 {"vlist", view_others_list, (LOWER_ADMIN | ADMIN), 0, 1, 0, ADMINc},
 {"vemerg", vscript, (LOWER_ADMIN|ADMIN), 0, 1, 0, ADMINc},
diff -ur pgplus.old/src/include/player.h pgplus/src/include/player.h
--- pgplus.old/src/include/player.h	Wed Dec  1 06:27:22 1999
+++ pgplus/src/include/player.h	Sat Jul 29 18:26:55 2000
@@ -16,6 +16,7 @@
 #define FORMAT(ck,s)	if (!(*(ck)))  { tell_player(current_player, (s)); return; }
 #define HAS_PRIV(p,r)	((p)->residency & (r))
 #define RES_BIT_HEAD	"Sys |Ressie|MiscRes |Misc|Staff"
+#define ENT_FLAGS(e, f)         ((e) && (e)->flags & (f))
 
 #ifdef ROBOTS
 #define CHECKROBOT(p)   if (!p->residency & ROBOT_PRIV) \
@@ -71,10 +72,11 @@
 #define SPECIALK	(1<<11) /* can create socials */
 #define DEBUG		(1<<12) /* can view the debug channel */
 #define NONCLERGY	(1<<13) /* unused, left for backward compatiblity */
+
 #define PSU		(1<<14) /* can use su channel commands */
 #define WARN		(1<<15) /* can use 'warn' */
 #define ADC		(1<<16) /* can use admin channel commands */
-#define HOUSE		(1<<17) /* extra 'fun' priv */
+#define INVISPRIV	(1<<17) /* extra 'fun' priv */
 #define ASU		(1<<18) /* advanced su, can use advanced su commands */
 #define MINISTER	(1<<19) /* can do marriages and such */
 #define DUMB		(1<<20) /* can use dumb (frog) commands */
@@ -100,8 +102,8 @@
 
  /* these are the privs that arent counted when privs are compared */
 #define NONSU (BASE + ECHO_PRIV + NO_TIMEOUT + MAIL + LIST + BUILD + SESSION \
-               + SCRIPT + TRACE + DUMB + HOUSE + SPOD + WARN + BUILDER + \
-               MINISTER + SPECIALK + DEBUG + GIT)
+               + SCRIPT + TRACE + DUMB + SPOD + WARN + BUILDER + \
+               MINISTER + SPECIALK + DEBUG + GIT + INVISPRIV)
 
  /* privs a hard coded (in admin.h) player gets on login */
  /* Note, CODER isnt here...to have hcadmins seperate from coders */
@@ -329,6 +331,7 @@
 
 #define NO_PRS			(1<<0)
 #define NO_GIFT			(1<<1)
+#define INVIS_ATM		(1<<2)
 
 /* misc flags, upper */
 
@@ -374,6 +377,7 @@
 #define SHARE_ROOM		(1<<13)
 #define NO_FACCESS_LIST		(1<<14)
 #define PREFERRED		(1<<15)
+#define INVISLIST		(1<<16)
 
 /* command types */
 
@@ -791,6 +795,7 @@
           ttt_draw,              /*             draws */
           icq,                   /* ICQ number */
           news_last[MAX_LAST_NEWS_INTS], /* int array of last read news */
+	  time_invis,		/* How much time you accrue while invis */
 
              /* saved in saved_player */
           residency,             /* residency, privs and such */
diff -ur pgplus.old/src/include/proto.h pgplus/src/include/proto.h
--- pgplus.old/src/include/proto.h	Thu Dec  9 11:40:36 1999
+++ pgplus/src/include/proto.h	Sat Jul 29 18:26:55 2000
@@ -191,6 +191,9 @@
 extern void do_backup(player *, char *);
 extern void do_birthdays(void);
 extern void do_inform(player *, char *);
+extern void do_inform_one(player *, player *, char *);
+extern void do_invis_login(player *);
+extern void do_invis_logout(player *);
 extern void do_prompt(player *, char *);
 extern void do_update(int);
 extern void dynamic_defrag_rooms(player *, char *);
@@ -258,6 +261,7 @@
 extern void pstack_mid(char *);
 extern void purge_gaglist(player *, char *);
 extern void quit(player *, char *);
+extern void fake_quit(player *);
 extern void quit_pager(player *p, ed_info *);
 extern void qwho(player *, char *);
 extern void raw_room_wall(room *, char *);
@@ -413,6 +417,7 @@
 
 #ifdef LAST
 extern void stampLogout(char *);
+extern void stampLogin(char *);
 #endif
 
 extern void          connect_channels (player *);
@@ -502,6 +507,12 @@
 extern void         multi_block (player *p, char *str);
 extern void         multi_list (player *p, char *str);
 extern void         multi_idle (player *p, char *str);
+extern void 	    su_quit_log(player *p);
+extern int	    is_invis(player *p);
+extern int	    can_see(player *p, player *q);
+extern int	    check_invis(player *p);
+extern int 	    tell_to_invis(player *p, player *q);
+extern int	    colorless_strlen(char *str);
 
 #ifdef SEAMLESS_REBOOT
 extern int          reboot_save_multis (void);
Only in pgplus/src/include: root.h
Only in pgplus/src/include: version.h
diff -ur pgplus.old/src/lists.c pgplus/src/lists.c
--- pgplus.old/src/lists.c	Sat Jul 29 16:52:18 2000
+++ pgplus/src/lists.c	Sat Jul 29 18:26:55 2000
@@ -21,8 +21,6 @@
 #include "include/fix.h"
 #include "include/proto.h"
 
-#define ENT_FLAGS(e, f)		((e) && (e)->flags & (f))
-
 /* interns */
 
 flag_list list_flags[] = {
@@ -58,6 +56,7 @@
     {"shr", SHARE_ROOM},
     {"nof", NO_FACCESS_LIST},
     {"prf", PREFERRED},
+    {"vis", INVISLIST},
     {0, 0}
 };
 
@@ -562,9 +561,9 @@
 }
 
 
-/* reset change on list */
+/* reset change on list - see toggle_list for logmsg variable */
 
-void reset_list(player * p, char *str)
+void reset_list(player * p, char *str, int logmsg)
 {
     char *flaglist, *oldstack, msg[50], *dummyname;
     int change, count = 0;
@@ -616,8 +615,16 @@
 		count++;
 		if (message_string) {
 		    tel = find_player_absolute_quiet(oldstack);
-		    if (tel)
+		    if (tel && (can_see(tel, p) || logmsg == 2)) {
 			tell_player(tel, message_string);
+			if (logmsg == 1)
+			    do_inform_one(p, tel,
+					  get_plists_msg("inform_login"));
+			else if (logmsg == 2)
+			    do_inform_one(p, tel,
+					  get_plists_msg("inform_logout"));
+
+		    }
 		}
 	    }
 	}
@@ -629,9 +636,14 @@
 	tell_player(p, " No changes to make.\n");
 }
 
-/* toggle change on list */
+/* toggle change on list 
 
-void toggle_list(player * p, char *str)
+   logmsg: 0 = no change 
+	1 = do_inform(login) for p
+	2 = do_inform(logout) for p
+*/
+
+void toggle_list(player * p, char *str, int logmsg)
 {
     char *flaglist, *oldstack, msg[50], *dummyname;
     int change, count = 0;
@@ -697,8 +709,15 @@
 		count++;
 		if (message_string && l->flags & change) {
 		    tel = find_player_absolute_quiet(oldstack);
-		    if (tel)
+		    if (tel && (can_see(tel, p) || logmsg == 2)) {
 			tell_player(tel, message_string);
+			if (logmsg == 1)
+			    do_inform_one(p, tel,
+					  get_plists_msg("inform_login"));
+			else if (logmsg == 2)
+			    do_inform_one(p, tel,
+					  get_plists_msg("inform_logout"));
+		    }
 		}
 	    }
 	}
@@ -738,7 +757,7 @@
 	sprintf(stack, " %s removes you from %s noisy list.\n",
 		p->name, gstring_possessive(p));
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -755,7 +774,7 @@
     sprintf(stack, " (%s adds you to %s noisy list)\n",
 	    p->name, gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     message_string = 0;
     stack = oldstack;
 }
@@ -786,7 +805,7 @@
     if (!strcasecmp("off", str)) {
 	sprintf(stack, " %s starts listening to you again.\n", p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -801,7 +820,7 @@
     }
     sprintf(stack, " (%s ignores you)\n", p->name);
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -832,7 +851,7 @@
     if (!strcasecmp("off", str)) {
 	sprintf(stack, " %s starts listening to you again.\n", p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -849,7 +868,7 @@
     sprintf(stack, " (%s blocks you off from doing tells to %s)\n",
 	    p->name, get_gender_string(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -875,7 +894,7 @@
     stack = strchr(stack, 0);
     *stack++ = 0;
     if (!strcasecmp("off", str)) {
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	return;
     }
@@ -884,7 +903,7 @@
 	stack = oldstack;
 	return;
     }
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
 }
 
@@ -914,7 +933,7 @@
 	sprintf(stack, " %s stops you from being able to grab %s.\n",
 		p->name, get_gender_string(p));
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -931,7 +950,7 @@
     sprintf(stack, " (%s allows you to grab %s)\n", p->name,
 	    get_gender_string(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -961,7 +980,7 @@
     if (!strcasecmp("off", str)) {
 	sprintf(stack, " %s doesn't like you any more.\n", p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -978,7 +997,63 @@
     sprintf(stack, " (%s makes you %s friend)\n", p->name,
 	    gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
+    stack = oldstack;
+    message_string = 0;
+}
+
+void visible(player * p, char *str)
+{
+    char *oldstack, *cmd;
+
+    oldstack = stack;
+
+    if (!*str) {
+	tell_player(p, " Format: vis <player(s)> on/off/[blank]\n");
+	return;
+    }
+    if (!check_legal_entry(p, str, 1))
+	return;
+
+    while (*str && *str != ' ')
+	*stack++ = *str++;
+    if (*str)
+	str++;
+    strcpy(stack, " vis");
+    stack = strchr(stack, 0);
+    *stack++ = 0;
+    cmd = stack;
+    message_string = cmd;
+    if (!strcasecmp("off", str)) {
+	sprintf(stack, " %s takes away your x-ray specs!\n", p->name);
+	stack = end_string(stack);
+	if (is_invis(p))
+	    reset_list(p, oldstack, 2);
+	else
+	    reset_list(p, oldstack, 0);
+	stack = oldstack;
+	message_string = 0;
+	return;
+    }
+    if (!strcasecmp("on", str)) {
+	sprintf(stack, " %s allows you to see %s when invisible.\n",
+		p->name, get_gender_string(p));
+	stack = end_string(stack);
+	if (is_invis(p))
+	    set_list(p, oldstack);
+	else
+	    set_list(p, oldstack);
+	stack = oldstack;
+	message_string = 0;
+	return;
+    }
+    sprintf(stack, " (%s allows you to see %s when invisible.)\n",
+	    p->name, get_gender_string(p));
+    stack = end_string(stack);
+    if (is_invis(p))
+	toggle_list(p, oldstack, 1);
+    else
+	toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -1009,7 +1084,7 @@
 	sprintf(stack, " %s allows you back into %s rooms.\n", p->name,
 		gstring_possessive(p));
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -1026,7 +1101,7 @@
     sprintf(stack, " (%s bars you from %s rooms)\n", p->name,
 	    gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -1057,7 +1132,7 @@
 	sprintf(stack, " %s strikes you off %s invite list.\n", p->name,
 		gstring_possessive(p));
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -1074,7 +1149,7 @@
     sprintf(stack, " (%s enters you onto %s invite list)\n", p->name,
 	    gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -1100,7 +1175,7 @@
     stack = strchr(stack, 0);
     *stack++ = 0;
     if (!strcasecmp("off", str)) {
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	return;
     }
@@ -1109,7 +1184,7 @@
 	stack = oldstack;
 	return;
     }
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
 }
 
@@ -1139,7 +1214,7 @@
 	sprintf(stack, " %s snatches %s key back off of you.\n", p->name,
 		gstring_possessive(p));
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -1156,7 +1231,7 @@
     sprintf(stack, " (%s presents you with the key to %s rooms)\n",
 	    p->name, gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -1386,8 +1461,8 @@
 	for (scan = p->saved->list_top; scan && !wibble; scan = scan->next) {
 	    if (!strcasecmp(scan->name, str)) {
 		sprintf(stack, "Your list entry for '%s'\n\n"
-			"                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF\n"
-			" = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf\n\n",
+			"                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF   Vis\n"
+			" = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf |\n\n",
 			scan->name);
 		stack = strchr(stack, 0);
 		strcpy(stack, list_lines(scan));
@@ -1424,8 +1499,8 @@
 
     if (count) {
 	strcpy(stack,
-	       "\n                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF\n"
-	       " = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf\n\n");
+	       "\n                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF   Vis\n"
+	       " = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf |\n\n");
 	stack = strchr(stack, 0);
 	for (l = sp->list_top; l; l = l->next) {
 	    if (!strcmp(l->name, "everyone"))
@@ -1530,8 +1605,8 @@
 	l = find_list_entry(p2, arg2);
 	if (l) {
 	    strcpy(stack,
-		   "\n                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF\n"
-		   " = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf\n\n");
+		   "\n                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF   Vis\n"
+		   " = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf |\n\n");
 	    stack = strchr(stack, 0);
 	    strcpy(stack, list_lines(l));
 	    stack = strchr(stack, 0);
@@ -1591,8 +1666,8 @@
     stack = strchr(stack, 0);
     if (count) {
 	strcpy(stack,
-	       "\n                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF\n"
-	       " = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf\n\n");
+	       "\n                  : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF   Vis\n"
+	       " = Name =         :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf |\n\n");
 	stack = strchr(stack, 0);
 	for (l = p2->saved->list_top; l; l = l->next) {
 	    if (!strcmp(l->name, "everyone"))
@@ -1665,7 +1740,7 @@
 
     string[0] = 0;
     sprintf(string, "%-18s:", l->name);
-    for (count = 1; count < 65536; count <<= 1) {
+    for (count = 1; count < 131072; count <<= 1) {
 	if (l->flags & count)
 	    strcat(string, "  Y");
 	else
@@ -1775,7 +1850,7 @@
     }
     *stack++ = ':';
 
-    for (count = 1; count < 32768; count <<= 1) {
+    for (count = 1; count < 131072; count <<= 1) {
 	if (l->flags & count)
 	    strcpy(stack, "  Y");
 	else
@@ -1816,8 +1891,8 @@
     text = stack;
 
     strcpy(stack,
-	   "                      : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF\n"
-	   " = Name =             :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf\n\n");
+	   "                      : Nsy   Inf   Fnd   Inv   Blk   Fin   MBk   NoF   Vis\n"
+	   " = Name =             :  | Ign | Grb | Bar | Bep | Key | FBk | ShR | Prf |\n\n");
     stack = strchr(stack, 0);
     for (scan = list, i = 0; i < n; i++, scan++)
 	if (*scan != p && (!every || entry_exists_for_player(p, *scan))) {
@@ -2009,11 +2084,163 @@
     return 1;
 }
 
+
 /* do inform bits */
 
 void do_inform(player * p, char *tmsg)
 {
     player *scan;
+    char msg[514];
+
+    if (!(p->location) || !(p->name[0]))
+	return;
+
+    /* we were passed soft_msg memeory, lets get our own now ... */
+    if (is_invis(p))
+	snprintf(msg, 513, "%s %s", tmsg, "(invisible)");
+    else
+	strncpy(msg, tmsg, 513);
+    msg[513] = 0;
+
+    for (scan = flatlist_start; scan; scan = scan->flat_next)
+	do_inform_one(p, scan, msg);
+}
+
+void do_inform_one(player * p, player * scan, char *msg)
+{
+    char *oldstack = stack;
+    list_ent *friend_ent, *sus_ent, *everyone_ent, *newbie_ent, *robot_ent,
+	*plain_ent, *invis_ent;
+    int informing, beeping;
+
+    if ((scan != p) && !(scan->flags & PANIC)) {
+	informing = 0;
+	beeping = 0;
+
+	plain_ent = find_list_entry(scan, p->lower_name);
+	if (ENT_FLAGS(plain_ent, INFORM))
+	    informing++;
+	if (ENT_FLAGS(plain_ent, BEEP))
+	    beeping++;
+
+	friend_ent = find_list_entry(scan, "friends");
+	if (ENT_FLAGS(friend_ent, INFORM))
+	    informing++;
+	if (ENT_FLAGS(friend_ent, BEEP))
+	    beeping++;
+
+	if (p->residency & PSU) {
+	    sus_ent = find_list_entry(scan, "sus");
+	    if (ENT_FLAGS(sus_ent, INFORM))
+		informing++;
+	    if (ENT_FLAGS(sus_ent, BEEP))
+		beeping++;
+	}
+	if (p->residency == NON_RESIDENT) {
+	    newbie_ent = find_list_entry(scan, "newbies");
+	    if (ENT_FLAGS(newbie_ent, INFORM))
+		informing++;
+	    if (ENT_FLAGS(newbie_ent, BEEP))
+		beeping++;
+	}
+#ifdef ROBOTS
+	if (p->residency & ROBOT_PRIV) {
+	    robot_ent = find_list_entry(scan, "robots");
+	    if (ENT_FLAGS(robot_ent, INFORM))
+		informing++;
+	    if (ENT_FLAGS(robot_ent, BEEP))
+		beeping++;
+	}
+#else				/* ROBOTS */
+	robot_ent = 0;
+#endif				/* !ROBOTS */
+
+	everyone_ent = find_list_entry(scan, "everyone");
+	{
+	    if (ENT_FLAGS(everyone_ent, INFORM))
+		informing++;
+	    if (ENT_FLAGS(everyone_ent, BEEP))
+		beeping++;
+	}
+
+	/* is there any reason to inform scan about p?
+	 */
+	if (!(informing))
+	    return;
+
+	invis_ent = find_list_entry(p, scan->lower_name);
+	if (!(ENT_FLAGS(invis_ent, INVISLIST)) &&
+	    (p->misc_flags & INVIS_ATM) && !(scan->residency & ADMIN))
+	    return;
+
+	/* we get to here, we know we are informing 
+	   now we just gotta build the inform string 
+	 */
+	command_type = 0;
+
+	if (scan->residency & (TRACE | SU | ADMIN))
+	    stack += sprintf(stack, msg, p->name, get_address(p, scan));
+	else
+	    stack += sprintf(stack, msg, p->name, "");
+
+	if (ENT_FLAGS(plain_ent, FRIEND)) {
+	    sys_color_atm = FRTsc;
+	    command_type = (PERSONAL | NO_HISTORY);
+	    if ((scan->system_flags & MARRIED) &&
+		(!strcasecmp(p->name, scan->married_to))) {
+		if (p->gender == MALE)
+		    sprintf(stack, " [Husband]");
+		else if (p->gender == FEMALE)
+		    sprintf(stack, " [Wife]");
+		else
+		    sprintf(stack, " [Spouse]");
+	    } else
+		sprintf(stack, " [Friend]");
+	    stack = strchr(stack, 0);
+	}
+
+	if (p->residency & PSU) {
+	    if (p->residency & CODER)
+		sprintf(stack, " [%s]", get_config_msg("coder_name"));
+	    else if (p->residency & HCADMIN)
+		sprintf(stack, " [%s]", get_config_msg("hc_name"));
+	    else if (p->residency & ADMIN)
+		sprintf(stack, " [%s]", get_config_msg("admin_name"));
+	    else if (p->residency & LOWER_ADMIN)
+		sprintf(stack, " [%s]", get_config_msg("la_name"));
+	    else if (p->residency & ASU)
+		sprintf(stack, " [%s]", get_config_msg("asu_name"));
+	    else if (p->residency & SU)
+		sprintf(stack, " [%s]", get_config_msg("su_name"));
+	    else
+		sprintf(stack, " [%s]", get_config_msg("psu_name"));
+	    stack = strchr(stack, 0);
+	}
+#ifdef ROBOTS
+	if (p->residency & ROBOT_PRIV)
+	    stack += sprintf(stack, " [Robot]");
+#endif
+	if (p->residency == NON_RESIDENT)
+	    stack += sprintf(stack, " [Newbie]");
+
+	if ((scan->residency & SU) && p->git_string[0])
+	    stack += sprintf(stack, " [Git]");
+
+	if (beeping)
+	    *stack++ = '\007';
+	*stack++ = '\n';
+	*stack++ = 0;
+
+	command_type = 0;
+	tell_player(scan, oldstack);
+	sys_color_atm = SYSsc;
+	stack = oldstack;
+    }
+}
+
+void do_invis_login(player * p)
+{
+    player *scan;
     char *oldstack = stack, msg[514];
     list_ent *friend_ent, *sus_ent, *everyone_ent, *newbie_ent, *robot_ent,
 	*plain_ent;
@@ -2022,10 +2249,6 @@
     if (!(p->location) || !(p->name[0]))
 	return;
 
-    /* we were passed soft_msg memeory, lets get our own now ... */
-    strncpy(msg, tmsg, 513);
-    msg[513] = 0;
-
     for (scan = flatlist_start; scan; scan = scan->flat_next) {
 	if ((scan != p) && !(scan->flags & PANIC) &&
 	    (scan->name[0]) && (scan->location)) {
@@ -2088,6 +2311,14 @@
 	     */
 	    command_type = 0;
 
+
+	    if (!can_see(scan, p))
+		strncpy(msg, get_plists_msg("inform_login"), 513);
+	    else
+		strncpy(msg, get_plists_msg("invis_login"), 513);
+	    msg[513] = 0;
+
+
 	    if (scan->residency & (TRACE | SU | ADMIN))
 		stack +=
 		    sprintf(stack, msg, p->name, get_address(p, scan));
@@ -2127,7 +2358,148 @@
 		    sprintf(stack, " [%s]", get_config_msg("psu_name"));
 		stack = strchr(stack, 0);
 	    }
+#ifdef ROBOTS
+	    if (p->residency & ROBOT_PRIV)
+		stack += sprintf(stack, " [Robot]");
+#endif
+	    if (p->residency == NON_RESIDENT)
+		stack += sprintf(stack, " [Newbie]");
 
+	    if ((scan->residency & SU) && p->git_string[0])
+		stack += sprintf(stack, " [Git]");
+
+	    if (beeping)
+		*stack++ = '\007';
+	    *stack++ = '\n';
+	    *stack++ = 0;
+
+	    tell_player(scan, oldstack);
+	    command_type = 0;
+	    sys_color_atm = SYSsc;
+	    stack = oldstack;
+	}
+    }
+}
+
+void do_invis_logout(player * p)
+{
+    player *scan;
+    char *oldstack = stack, msg[514];
+    list_ent *friend_ent, *sus_ent, *everyone_ent, *newbie_ent, *robot_ent,
+	*plain_ent;
+    int informing, beeping;
+
+    if (!(p->location) || !(p->name[0]))
+	return;
+
+    for (scan = flatlist_start; scan; scan = scan->flat_next) {
+	if ((scan != p) && !(scan->flags & PANIC) &&
+	    (scan->name[0]) && (scan->location)) {
+	    informing = 0;
+	    beeping = 0;
+
+	    plain_ent = find_list_entry(scan, p->lower_name);
+	    if (ENT_FLAGS(plain_ent, INFORM))
+		informing++;
+	    if (ENT_FLAGS(plain_ent, BEEP))
+		beeping++;
+
+	    friend_ent = find_list_entry(scan, "friends");
+	    if (ENT_FLAGS(friend_ent, INFORM))
+		informing++;
+	    if (ENT_FLAGS(friend_ent, BEEP))
+		beeping++;
+
+	    if (p->residency & PSU) {
+		sus_ent = find_list_entry(scan, "sus");
+		if (ENT_FLAGS(sus_ent, INFORM))
+		    informing++;
+		if (ENT_FLAGS(sus_ent, BEEP))
+		    beeping++;
+	    }
+	    if (p->residency == NON_RESIDENT) {
+		newbie_ent = find_list_entry(scan, "newbies");
+		if (ENT_FLAGS(newbie_ent, INFORM))
+		    informing++;
+		if (ENT_FLAGS(newbie_ent, BEEP))
+		    beeping++;
+	    }
+#ifdef ROBOTS
+	    if (p->residency & ROBOT_PRIV) {
+		robot_ent = find_list_entry(scan, "robots");
+		if (ENT_FLAGS(robot_ent, INFORM))
+		    informing++;
+		if (ENT_FLAGS(robot_ent, BEEP))
+		    beeping++;
+	    }
+#else				/* ROBOTS */
+	    robot_ent = 0;
+#endif				/* !ROBOTS */
+
+	    everyone_ent = find_list_entry(scan, "everyone");
+	    {
+		if (ENT_FLAGS(everyone_ent, INFORM))
+		    informing++;
+		if (ENT_FLAGS(everyone_ent, BEEP))
+		    beeping++;
+	    }
+
+	    /* is there any reason to inform scan about p?
+	     */
+	    if (!(informing))
+		continue;
+
+	    /* we get to here, we know we are informing 
+	       now we just gotta build the inform string 
+	     */
+	    command_type = 0;
+
+
+	    if (!can_see(scan, p))
+		strncpy(msg, get_plists_msg("inform_logout"), 513);
+	    else
+		strncpy(msg, get_plists_msg("invis_logout"), 513);
+	    msg[513] = 0;
+
+	    if (scan->residency & (TRACE | SU | ADMIN))
+		stack +=
+		    sprintf(stack, msg, p->name, get_address(p, scan));
+	    else
+		stack += sprintf(stack, msg, p->name, "");
+
+	    if (ENT_FLAGS(plain_ent, FRIEND)) {
+		sys_color_atm = FRTsc;
+		command_type = (PERSONAL | NO_HISTORY);
+		if ((scan->system_flags & MARRIED) &&
+		    (!strcasecmp(p->name, scan->married_to))) {
+		    if (p->gender == MALE)
+			sprintf(stack, " [Husband]");
+		    else if (p->gender == FEMALE)
+			sprintf(stack, " [Wife]");
+		    else
+			sprintf(stack, " [Spouse]");
+		} else
+		    sprintf(stack, " [Friend]");
+		stack = strchr(stack, 0);
+	    }
+
+	    if (p->residency & PSU) {
+		if (p->residency & CODER)
+		    sprintf(stack, " [%s]", get_config_msg("coder_name"));
+		else if (p->residency & HCADMIN)
+		    sprintf(stack, " [%s]", get_config_msg("hc_name"));
+		else if (p->residency & ADMIN)
+		    sprintf(stack, " [%s]", get_config_msg("admin_name"));
+		else if (p->residency & LOWER_ADMIN)
+		    sprintf(stack, " [%s]", get_config_msg("la_name"));
+		else if (p->residency & ASU)
+		    sprintf(stack, " [%s]", get_config_msg("asu_name"));
+		else if (p->residency & SU)
+		    sprintf(stack, " [%s]", get_config_msg("su_name"));
+		else
+		    sprintf(stack, " [%s]", get_config_msg("psu_name"));
+		stack = strchr(stack, 0);
+	    }
 #ifdef ROBOTS
 	    if (p->residency & ROBOT_PRIV)
 		stack += sprintf(stack, " [Robot]");
@@ -2554,7 +2926,7 @@
 	sprintf(stack, " %s resumes listening to your friendtells.\n",
 		p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -2572,7 +2944,7 @@
     sprintf(stack, " (%s blocks you off from doing friendtells to %s)\n",
 	    p->name, get_gender_string(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -2602,7 +2974,7 @@
     if (!strcasecmp("off", str)) {
 	sprintf(stack, " %s unblocks your mail.\n", p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -2619,7 +2991,7 @@
     sprintf(stack, " (%s redirects all your mail to /dev/null)\n",
 	    p->name);
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -2649,7 +3021,7 @@
     if (!strcasecmp("off", str)) {
 	sprintf(stack, " %s tears up your lease.\n", p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -2666,7 +3038,7 @@
     sprintf(stack, " (%s grants you a lease to %s rooms)\n", p->name,
 	    gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -2697,7 +3069,7 @@
 	sprintf(stack, " %s allows you to talk to %s friends.\n", p->name,
 		gstring_possessive(p));
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -2714,7 +3086,7 @@
     sprintf(stack, " (%s stops you from talking to %s friends)\n", p->name,
 	    gstring_possessive(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -2813,7 +3185,7 @@
     if (!strcasecmp("off", str)) {
 	sprintf(stack, " %s hides from your evil eyes.\n", p->name);
 	stack = end_string(stack);
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	message_string = 0;
 	return;
@@ -2832,7 +3204,7 @@
 	    " (%s lets you see where %s is, even when %s is hidden)\n",
 	    p->name, get_gender_string(p), get_gender_string(p));
     stack = end_string(stack);
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
     message_string = 0;
 }
@@ -3166,7 +3538,7 @@
     stack = strchr(stack, 0);
     *stack++ = 0;
     if (!strcasecmp("off", str)) {
-	reset_list(p, oldstack);
+	reset_list(p, oldstack, 0);
 	stack = oldstack;
 	return;
     }
@@ -3175,7 +3547,7 @@
 	stack = oldstack;
 	return;
     }
-    toggle_list(p, oldstack);
+    toggle_list(p, oldstack, 0);
     stack = oldstack;
 }
 
Only in pgplus/src: lists.c.orig
diff -ur pgplus.old/src/parse.c pgplus/src/parse.c
--- pgplus.old/src/parse.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/parse.c	Sat Jul 29 18:26:55 2000
@@ -900,7 +900,7 @@
 	    current_player = scan;
 
 	    if (scan->location && scan->name[0]
-		&& !(scan->flags & RECONNECTION)) {
+		&& !(scan->flags & RECONNECTION) && !is_invis(scan)) {
 #ifdef LAST
 		stampLogout(scan->name);
 #endif
@@ -914,44 +914,47 @@
 		if (scan == p_sess) {
 		    session_reset = 0;
 		}
-		if (strlen(scan->logoffmsg) < 1) {
-		    stack += sprintf(stack, "%s %s ",
-				     get_config_msg("logoff_prefix"),
-				     scan->name);
-		    stack +=
-			sprintf(stack, "%s ",
-				get_config_msg("def_logout"));
-		    stack +=
-			sprintf(stack, "^N%s\n",
-				get_config_msg("logoff_suffix"));
-		} else {
-		    if (emote_no_break(*scan->logoffmsg)) {
+		if (!is_invis(scan)) {
+		    if (strlen(scan->logoffmsg) < 1) {
+			stack += sprintf(stack, "%s %s ",
+					 get_config_msg("logoff_prefix"),
+					 scan->name);
 			stack +=
-			    sprintf(stack, "%s %s%s ",
-				    get_config_msg("logoff_prefix"),
-				    scan->name, scan->logoffmsg);
+			    sprintf(stack, "%s ",
+				    get_config_msg("def_logout"));
 			stack +=
 			    sprintf(stack, "^N%s\n",
 				    get_config_msg("logoff_suffix"));
 		    } else {
-			stack +=
-			    sprintf(stack, "%s %s %s ",
-				    get_config_msg("logoff_prefix"),
-				    scan->name, scan->logoffmsg);
-			stack +=
-			    sprintf(stack, "^N%s\n",
-				    get_config_msg("logoff_suffix"));
+			if (emote_no_break(*scan->logoffmsg)) {
+			    stack +=
+				sprintf(stack, "%s %s%s ",
+					get_config_msg("logoff_prefix"),
+					scan->name, scan->logoffmsg);
+			    stack +=
+				sprintf(stack, "^N%s\n",
+					get_config_msg("logoff_suffix"));
+			} else {
+			    stack +=
+				sprintf(stack, "%s %s %s ",
+					get_config_msg("logoff_prefix"),
+					scan->name, scan->logoffmsg);
+			    stack +=
+				sprintf(stack, "^N%s\n",
+					get_config_msg("logoff_suffix"));
+			}
 		    }
-		}
 
-		stack = end_string(stack);
-		command_type |= LOGOUT_TAG;
-		tell_room(scan->location, oldstack);
-		command_type &= ~LOGOUT_TAG;
+		    stack = end_string(stack);
+		    command_type |= LOGOUT_TAG;
+		    tell_room(scan->location, oldstack);
+		    command_type &= ~LOGOUT_TAG;
+		}
 		stack = oldstack;
 		save_player(scan);
 		command_type = 0;
 		do_inform(scan, get_plists_msg("inform_logout"));
+
 		if (scan->saved && !(scan->flags & NO_SAVE_LAST_ON))
 		    scan->saved->last_on = time(0);
 	    }
@@ -1120,7 +1123,11 @@
 
 	    scan->idle++;
 	    scan->idle_index++;
-	    scan->total_login++;
+	    if (is_invis(scan))
+		scan->time_invis++;
+	    else
+		scan->total_login++;
+
 	    if (scan->total_login % ONE_HOUR == 0)
 		scan->pennies += 10;
 	    if (scan->pennies > 100000)
diff -ur pgplus.old/src/plists.c pgplus/src/plists.c
--- pgplus.old/src/plists.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/plists.c	Sat Jul 29 18:28:39 2000
@@ -739,6 +739,7 @@
     stack = store_int(stack, p->ttt_loose);
     stack = store_int(stack, p->ttt_draw);
     stack = store_int(stack, p->icq);
+    stack = store_int(stack, p->time_invis);
     stack = store_string(stack, p->finger_message);
     stack = store_string(stack, p->swarn_message);
     stack = store_string(stack, p->swarn_sender);
@@ -852,7 +853,8 @@
     if (find_player_absolute_quiet(p->lower_name)) {
 	strncpy(sp->last_host, p->inet_addr, MAX_INET_ADDR - 2);
 	strncpy(sp->email, p->email, MAX_EMAIL - 3);
-	sp->last_on = time(0);
+	if (!is_invis(p))
+	    sp->last_on = time(0);
     }
     set_update(*(sp->lower_name));
     p->saved = sp;
@@ -1031,6 +1033,7 @@
     r = get_int_safe(&p->ttt_loose, r, sp->data);
     r = get_int_safe(&p->ttt_draw, r, sp->data);
     r = get_int_safe(&p->icq, r, sp->data);
+    r = get_int_safe(&p->time_invis, r, sp->data);
     r = get_string_safe(p->finger_message, r, sp->data);
     r = get_string_safe(p->swarn_message, r, sp->data);
     r = get_string_safe(p->swarn_sender, r, sp->data);
@@ -1423,6 +1426,44 @@
     return;
 }
 
+void do_login_msgs(player * p)
+{
+    char *oldstack;
+    oldstack = stack;
+
+    do_inform(p, get_plists_msg("inform_login"));
+
+    if (!is_invis(p)) {
+	if (strlen(p->logonmsg) < 1) {
+	    stack += sprintf(stack, "%s %s enters the program. ",
+			     get_config_msg("logon_prefix"), p->name);
+	    stack +=
+		sprintf(stack, "^N%s\n", get_config_msg("logon_suffix"));
+	} else {
+	    if (*p->logonmsg == 39 || *p->logonmsg == ',') {
+		stack += sprintf(stack, "%s %s%s ",
+				 get_config_msg("logon_prefix"), p->name,
+				 p->logonmsg);
+		stack +=
+		    sprintf(stack, "^N%s\n",
+			    get_config_msg("logon_suffix"));
+	    } else {
+		stack += sprintf(stack, "%s %s %s ",
+				 get_config_msg("logon_prefix"), p->name,
+				 p->logonmsg);
+		stack +=
+		    sprintf(stack, "^N%s\n",
+			    get_config_msg("logon_suffix"));
+	    }
+	}
+	stack = end_string(oldstack);
+	command_type |= LOGIN_TAG;
+	tell_room(p->location, oldstack);
+	command_type &= ~LOGIN_TAG;
+	stack = oldstack;
+    }
+}
+
 /* links a person into the program properly  (several fxns) */
 void finish_player_login(player * p, char *str)
 {
@@ -1440,7 +1481,7 @@
     p->on_since = time(0);
     logins++;
 
-    if (!(p->flags & RECONNECTION)) {
+    if (!(p->flags & RECONNECTION) && !(p->misc_flags & INVIS_ATM)) {
 #ifdef LAST
 	stampLogin(p->name);
 #endif
@@ -1500,35 +1541,8 @@
 	tell_room(p->location, oldstack);
 	command_type &= ~RECON_TAG;
     } else {
-	do_inform(p, get_plists_msg("inform_login"));
 	stack = oldstack;
 
-	if (strlen(p->logonmsg) < 1) {
-	    stack += sprintf(stack, "%s %s enters the program. ",
-			     get_config_msg("logon_prefix"), p->name);
-	    stack +=
-		sprintf(stack, "^N%s\n", get_config_msg("logon_suffix"));
-	} else {
-	    if (*p->logonmsg == 39 || *p->logonmsg == ',') {
-		stack += sprintf(stack, "%s %s%s ",
-				 get_config_msg("logon_prefix"), p->name,
-				 p->logonmsg);
-		stack +=
-		    sprintf(stack, "^N%s\n",
-			    get_config_msg("logon_suffix"));
-	    } else {
-		stack += sprintf(stack, "%s %s %s ",
-				 get_config_msg("logon_prefix"), p->name,
-				 p->logonmsg);
-		stack +=
-		    sprintf(stack, "^N%s\n",
-			    get_config_msg("logon_suffix"));
-	    }
-	}
-	stack = end_string(oldstack);
-	command_type |= LOGIN_TAG;
-	tell_room(p->location, oldstack);
-	command_type &= ~LOGIN_TAG;
     }
 
 #ifdef ALLOW_MULTIS
@@ -1557,6 +1571,8 @@
 
 	stack = oldstack;
 
+	do_login_msgs(p);
+
 	if (p->flags & RECONNECTION) {
 	    hello = do_alias_match(p, "_recon");
 	    if (strcmp(hello, "\n"))
@@ -1568,7 +1584,9 @@
 
 	    connect_channels(p);
 	}
-    }
+    } else
+	do_login_msgs(p);
+
     /* clear the chanflags, just in case... */
     if (p->flags & RECONNECTION)
 	p->flags &= ~RECONNECTION;
@@ -2846,6 +2864,10 @@
 	    strcpy(stack, "ignoring prefixes, ");
 	    stack = strchr(stack, 0);
 	}
+	if (p->misc_flags & INVIS_ATM) {
+	    strcpy(stack, "invisible, ");
+	    stack = strchr(stack, 0);
+	}
 	if ((str = strrchr(oldstack, ','))) {
 	    *str++ = '.';
 	    *str++ = '\n';
@@ -2927,6 +2949,10 @@
 	strcpy(stack, "in converse mode, ");
 	stack = strchr(stack, 0);
     }
+    if (p2->misc_flags & INVIS_ATM) {
+	strcpy(stack, "invisible, ");
+	stack = strchr(stack, 0);
+    }
     if (p2->custom_flags & NOPREFIX) {
 	strcpy(stack, "ignoring prefixes, ");
 	stack = strchr(stack, 0);
@@ -3069,7 +3095,7 @@
 			else if (scanlist->residency & PSU)
 			    psu++;
 			else if (scanlist->
-				 residency & (WARN | ADC | HOUSE | DUMB |
+				 residency & (WARN | ADC | DUMB |
 					      SCRIPT | TRACE | PROTECT))
 			    blessed++;
 			players++;
@@ -3494,8 +3520,8 @@
 	*ptr++ = 'K';
     else
 	*ptr++ = '_';
-    if (p & HOUSE)
-	*ptr++ = 'H';
+    if (p & INVISPRIV)
+	*ptr++ = 'I';
     else
 	*ptr++ = '_';
     if (p & MINISTER)
diff -ur pgplus.old/src/room.c pgplus/src/room.c
--- pgplus.old/src/room.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/room.c	Sat Jul 29 18:26:55 2000
@@ -1309,7 +1309,7 @@
     list = (player **) stack;
 
     for (scan = r->players_top; scan; scan = scan->room_next)
-	if (scan != p) {
+	if (scan != p && !is_invis(scan)) {
 	    *(player **) stack = scan;
 	    stack += sizeof(player **);
 	    count++;
@@ -1338,6 +1338,9 @@
 	    construct_name_list(list, count);
 	else
 	    for (i = count; i; i--, list++) {
+		if (is_invis((*list)))
+		    continue;
+
 		if (emote_no_break(*(*list)->title))
 		    sprintf(stack, "%s%s^N\n", (*list)->name,
 			    (*list)->title);
@@ -1497,7 +1500,8 @@
 	}
 
 	if (old_room->players_top) {
-	    if (!moveflag) {
+	    if (is_invis(p));
+	    else if (!moveflag) {
 		if (r->flags & EXITMSGS_OK && p->exitmsg[0]) {
 		    if (emote_no_break(*p->exitmsg))
 			sprintf(stack, " %s%s^N\n", p->name, p->exitmsg);
@@ -1515,7 +1519,8 @@
 		sprintf(stack, " %s^N\n", buf);
 	    }
 	    stack = end_string(stack);
-	    tell_room(p->location, oldstack);
+	    if (!is_invis(p))
+		tell_room(p->location, oldstack);
 	    stack = oldstack;
 	} else {
 	    compress_room(old_room);
@@ -1526,7 +1531,8 @@
     p->room_next = r->players_top;
     r->players_top = p;
     p->location = r;
-    if (moveflag) {
+    if (is_invis(p));
+    else if (moveflag) {
 	sprintf(buf, get_rooms_msg("grabbed_to"), p->name);
 	sprintf(stack, " %s\n", buf);
     } else {
@@ -1536,7 +1542,8 @@
 	    sprintf(stack, " %s %s^N\n", p->name, p->enter_msg);
     }
     stack = end_string(stack);
-    tell_room(p->location, oldstack);
+    if (!is_invis(p))
+	tell_room(p->location, oldstack);
     stack = oldstack;
     look(p, 0);
     if (p->custom_flags & SHOW_EXITS)
@@ -2614,13 +2621,14 @@
 	tell_player(p, " You seem to be stuck to the ground\n");
 	return;
     }
-    /* tell the room the leavemsg for bounce */
     oldstack = stack;
-    sprintf(oldstack, " %s spins round, and bounces into the air !!\n",
-	    p->name);
-    stack = end_string(oldstack);
-    tell_room(p->location, oldstack);
-
+    if (!is_invis(p)) {
+	/* tell the room the leavemsg for bounce */
+	sprintf(oldstack, " %s spins round, and bounces into the air !!\n",
+		p->name);
+	stack = end_string(oldstack);
+	tell_room(p->location, oldstack);
+    }
 #ifdef INTERCOM
     if (p->location == intercom_room)
 	do_intercom_room_exit_inform(p);
@@ -2635,7 +2643,8 @@
     trans_to(p, oldstack);
 
     stack = oldstack;
-    if (emote_no_break(*p->enter_msg))
+    if (is_invis(p));
+    else if (emote_no_break(*p->enter_msg))
 	sprintf(stack, " %s%s\n", p->name, p->enter_msg);
     else
 	sprintf(stack, " %s %s\n", p->name, p->enter_msg);
diff -ur pgplus.old/src/session.c pgplus/src/session.c
--- pgplus.old/src/session.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/session.c	Sat Jul 29 18:26:55 2000
@@ -251,12 +251,14 @@
 	if (pages <= page && line == 0)
 	    start = scan;
 
-	if (scan->comment[0] != 0)
-	    line++;
-
-	if (line > TERM_LINES - 2) {
-	    line = 0;
-	    pages++;
+	if (can_see(p, scan)) {
+	    if (scan->comment[0] != 0)
+		line++;
+
+	    if (line > TERM_LINES - 2) {
+		line = 0;
+		pages++;
+	    }
 	}
     }
 
@@ -276,7 +278,7 @@
 	if (line > TERM_LINES)
 	    break;
 
-	if (start->comment[0] != 0) {
+	if (start->comment[0] != 0 && !is_invis(start)) {
 	    if (!strcasecmp(sess_name, start->lower_name))
 		sprintf(stack, "%-19s*", start->name);
 	    else
@@ -828,11 +830,21 @@
 	} else if (scan->name[0])
 	    count--;
     for (count = 0; (count < (TERM_LINES - 1) && scan);
-	 scan = scan->flat_next) if (scan->name[0] && scan->location) {
+	 scan = scan->flat_next)
+	    if (scan->name[0] && scan->location && can_see(p, scan)) {
+
+	    if (is_invis(scan)) {
+		sprintf(stack, "^Y[i]^N ");
+		stack = strchr(stack, 0);
+	    } else {
+		sprintf(stack, "    ");
+		stack = strchr(stack, 0);
+	    }
+
 	    if (!strcasecmp(sess_name, scan->lower_name))
-		sprintf(stack, "%-19s*- ", scan->name);
+		sprintf(stack, "%-15s*- ", scan->name);
 	    else
-		sprintf(stack, "%-19s - ", scan->name);
+		sprintf(stack, "%-15s - ", scan->name);
 
 	    stack = strchr(stack, 0);
 
diff -ur pgplus.old/src/tag.c pgplus/src/tag.c
--- pgplus.old/src/tag.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/tag.c	Sat Jul 29 18:26:55 2000
@@ -122,7 +122,7 @@
     list = (player **) stack;
     scan = hashlist[(int) (*lname) - (int) 'a' + 1];
     for (; scan; scan = scan->hash_next) {
-	if (!scan->location)
+	if (!scan->location || !can_see(current_player, scan))
 	    continue;
 
 	test = match_player(scan->lower_name, lname);
@@ -183,7 +183,7 @@
     list = (player **) stack;
     scan = hashlist[(int) (*lname) - (int) 'a' + 1];
     for (; scan; scan = scan->hash_next) {
-	if (!scan->location)
+	if (!scan->location || !can_see(current_player, scan))
 	    continue;
 
 	test = match_player(scan->lower_name, lname);
@@ -336,7 +336,7 @@
 
     for (scan = flatlist_start; scan; scan = scan->flat_next) {
 	if (scan->residency & PSU && !(scan->flags & BLOCK_SU)
-	    && scan != p) {
+	    && scan != p && !is_invis(scan)) {
 	    if (scan->flags & NO_SU_WALL) {
 		scan->flags &= ~NO_SU_WALL;
 	    } else {
@@ -370,7 +370,8 @@
     strncpy(suhistory[0], str, MAX_SUH_LEN - 3);
 
     for (scan = flatlist_start; scan; scan = scan->flat_next) {
-	if (scan->residency & PSU && !(scan->flags & BLOCK_SU)) {
+	if (scan->residency & PSU && !(scan->flags & BLOCK_SU) &&
+	    !is_invis(scan)) {
 	    if (scan->flags & NO_SU_WALL) {
 		scan->flags &= ~NO_SU_WALL;
 	    } else {
@@ -406,7 +407,8 @@
     sys_color_atm = ROMsc;
     command_type = ROOM;
     for (scan = r->players_top; scan; scan = scan->room_next)
-	non_block_tell(scan, str);
+	if (!is_invis(scan))
+	    non_block_tell(scan, str);
     sys_color_atm = SYSsc;
 }
 
@@ -430,7 +432,7 @@
 	return;
     sys_color_atm = ROMsc;
     for (scan = r->players_top; scan; scan = scan->room_next)
-	if (scan != current_player)
+	if (scan != current_player && !is_invis(scan))
 	    tell_player(scan, str);
     sys_color_atm = SYSsc;
 }
@@ -444,7 +446,7 @@
 	return;
     sys_color_atm = ROMsc;
     for (scan = r->players_top; scan; scan = scan->room_next)
-	if (scan != p)
+	if (scan != p && is_invis(scan))
 	    tell_player(scan, str);
     sys_color_atm = SYSsc;
 }
@@ -455,7 +457,7 @@
 	return;
     sys_color_atm = ROMsc;
     for (scan = r->players_top; scan; scan = scan->room_next)
-	if (scan != p && scan != current_player)
+	if (scan != p && scan != current_player && !is_invis(scan))
 	    tell_player(scan, str);
     sys_color_atm = SYSsc;
 }
@@ -588,7 +590,7 @@
 #endif
 {
     list_ent *entry, *l;
-    char *oldstack, *start, *tmp;
+    char *oldstack, *start, *tmp, tmpstart[MAX_NAME + 1];
     player *o, *tag = 0, **list_start;
     int matches = 0;
 #ifdef ALLOW_MULTIS
@@ -648,7 +650,7 @@
 	    if (entry->flags & FRIEND
 		&& strcasecmp(entry->name, "everyone")) {
 		tag = find_player_absolute_quiet(entry->name);
-		if (tag && tag->location) {
+		if (tag && tag->location && can_see(p, tag)) {
 		    *((player **) stack) = tag;
 		    stack += sizeof(player **);
 		    tag->flags |= TAGGED;
@@ -797,6 +799,7 @@
 	if (*tag_str)
 	    tag_str++;
 
+	strncpy(tmpstart, start, MAX_NAME);
 	if (!strcasecmp(start, "me"))
 	    tag = p;
 #ifdef ALLOW_MULTIS
@@ -819,11 +822,15 @@
 	}
 
 	stack = start;
-	if ((tag) && !(tag->flags & TAGGED)) {
+	if ((tag) && !(tag->flags & TAGGED) && can_see(p, tag)) {
 	    tag->flags |= TAGGED;
 	    *((player **) stack) = tag;
 	    stack += sizeof(player *);
 	    matches++;
+	} else if ((tag) && !(tag->flags & TAGGED)) {
+	    tell_player(p, "No one of the name \'");
+	    tell_player(p, tmpstart);
+	    tell_player(p, "\' on at the moment.\n");
 	}
 	if (matches > NAME_MAX_IN_PIPE) {
 	    tell_player(p, " Too many names in tag list to evaluate "
@@ -1321,7 +1328,7 @@
     list = (player **) stack;
 
     for (scan = flatlist_start; scan; scan = scan->flat_next) {
-	if (scan->name[0] && scan->location) {
+	if (scan->name[0] && scan->location && !is_invis(scan)) {
 	    *(player **) stack = scan;
 	    stack += sizeof(player **);
 	    count++;
@@ -1489,7 +1496,7 @@
 
     /* last part */
 
-    for (n++; n < width; n++) {
+    for (n++; LINE[n] != '\n' /* n < width */ ; n++) {
 	*stack++ = LINE[pos];
 	pos = add_cycle(pos, linelen);
     }
@@ -1545,7 +1552,16 @@
 	} else if (scan->name[0])
 	    count--;
     for (count = 0; (count < (TERM_LINES - 1) && scan);
-	 scan = scan->flat_next) if (scan->name[0] && scan->location) {
+	 scan = scan->flat_next)
+	    if (scan->name[0] && scan->location && can_see(p, scan)) {
+	    if (is_invis(scan)) {
+		sprintf(stack, "^Y[i]^N ");
+		stack = strchr(stack, 0);
+	    } else {
+		sprintf(stack, "    ");
+		stack = strchr(stack, 0);
+	    }
+
 	    if (emote_no_break(*scan->title))
 		sprintf(stack, "%s%s^N\n", scan->name, scan->title);
 	    else
diff -ur pgplus.old/src/talking.c pgplus/src/talking.c
--- pgplus.old/src/talking.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/talking.c	Sat Jul 29 18:26:55 2000
@@ -82,7 +82,7 @@
     player *s;
 
     for (s = p->location->players_top; s; s = s->room_next) {
-	if (s != current_player) {
+	if (s != current_player && !is_invis(s)) {
 	    prepipe = stack;
 	    pip = do_pipe(s, str);
 	    if (!pip) {
@@ -354,6 +354,9 @@
 	tell_player(p, " Format: say <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if ((p->flags & FROGGED) && (p->location != prison))
 	str = get_frog_msg("say");
 
@@ -573,6 +576,9 @@
 	tell_player(p, " Format: shout <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (p->flags & FROGGED)
 	str = get_frog_msg("shout");
 
@@ -655,6 +661,9 @@
 	tell_player(p, " Format: emote <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if ((p->flags & FROGGED) && (p->location != prison))
 	str = get_frog_msg("emote");
 
@@ -876,6 +885,14 @@
 
     for (step = list, i = 0; i < n; i++, step++) {
 	if (*step != p) {
+	    if (!can_see(*step, p)) {
+		tell_player(p,
+			    " Nice try.  You can't talk to people who can't see you, Casper.\n");
+		cleanup_tag(list, n);
+		stack = oldstack;
+		return;
+	    }
+
 	    pstring = tag_string(*step, list, n);
 	    final = stack;
 	    if ((*step)->custom_flags & NOPREFIX)
@@ -1579,6 +1596,9 @@
 	tell_player(p, " Format: think <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (p->flags & FROGGED)
 	str = get_frog_msg("think");
 
@@ -1628,6 +1648,9 @@
 	tell_player(p, " Format: tf <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     oldstack = stack;
     sprintf(stack, "friends %s", str);
     stack = end_string(stack);
@@ -1645,6 +1668,9 @@
 	tell_player(p, " Format: rf <remote>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     oldstack = stack;
     sprintf(stack, "friends %s", str);
     stack = end_string(stack);
@@ -1689,6 +1715,9 @@
 	tell_player(p, " Format: yemote <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (p->flags & FROGGED)
 	str = get_frog_msg("yemote");
 
@@ -1747,6 +1776,9 @@
 	tell_player(p, " Format: pyemote <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (!(p->flags & FROGGED)) {
 	for (scan = p->lower_name; *scan; scan++);
 	if (*(scan - 1) == 's')
@@ -1777,6 +1809,9 @@
 	tell_player(p, " Format: ythink <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (p->flags & FROGGED)
 	str = get_frog_msg("ythink");
 
@@ -1830,6 +1865,9 @@
 	tell_player(p, " Format: yecho <msg>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (p->flags & FROGGED)
 	str = get_frog_msg("yecho");
 
@@ -1880,6 +1918,9 @@
 	tell_player(p, " Format: rtf <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     oldstack = stack;
     sprintf(stack, "friends thinks . o O ( %s ^N)", str);
     stack = end_string(stack);
@@ -1898,6 +1939,9 @@
 	tell_player(p, " Format: pf <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     oldstack = stack;
     sprintf(stack, "friends %s ", str);
     stack = end_string(stack);
@@ -1917,6 +1961,9 @@
 	tell_player(p, " Format: ef <echo>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     oldstack = stack;
     sprintf(stack, "friends %s", str);
     stack = end_string(stack);
@@ -1939,6 +1986,9 @@
 	tell_player(p, " Format: sing <song>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (!check_sing_ability(p, str)) {
 	str = temp;
 	return;
@@ -2125,6 +2175,9 @@
 	tell_player(p, " Format: sf <song> \n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     oldstack = stack;
     sprintf(stack, "friends %s", str);
     stack = end_string(stack);
@@ -2146,6 +2199,9 @@
 	tell_player(p, " Format: ysing <song>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     if (!check_sing_ability(p, str)) {
 	str = temp;
 	return;
@@ -2202,6 +2258,8 @@
 
     command_type = PERSONAL | SEE_ERROR;
 
+    if (check_invis(p))
+	return;
     if (p->tag_flags & BLOCK_TELLS) {
 	tell_player(p, " You can't yell at other people when you yourself "
 		    "are blocking tells.\n");
@@ -2411,6 +2469,9 @@
 	tell_player(p, " Format: tfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
@@ -2442,6 +2503,9 @@
 	tell_player(p, " Format: rfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
@@ -2473,6 +2537,9 @@
 	tell_player(p, " Format: rtfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
@@ -2504,6 +2571,9 @@
 	tell_player(p, " Format: pfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
@@ -2536,6 +2606,9 @@
 	tell_player(p, " Format: efo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
@@ -2567,6 +2640,9 @@
 	tell_player(p, " Format: sfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
@@ -2598,6 +2674,8 @@
 	tell_player(p, " Format: yfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
 
     if (p->tag_flags & BLOCK_FRIENDS) {
 	tell_player(p,
@@ -2620,6 +2698,9 @@
 	tell_player(p, " Format: yfo <player> <message>\n");
 	return;
     }
+    if (check_invis(p))
+	return;
+
     msg = next_space(str);
     *msg++ = 0;
     if (!*msg) {
diff -ur pgplus.old/src/version.c pgplus/src/version.c
--- pgplus.old/src/version.c	Sat Jul 29 16:52:19 2000
+++ pgplus/src/version.c	Sat Jul 29 18:26:55 2000
@@ -52,7 +52,7 @@
     sprintf(stack,
 	    "\nThis talker is based on Playground Plus by Silver (Richard Lawrence),\nblimey (Geoffrey Swift) and phypor (J. Bradley Christian), a stable\nbug"
 	    "fixed and improved version of Playground 96 by traP (Mike Bourdaa),\nastyanax (Chris Allegretta), Nogard (Hans Peterson) and "
-	    "vallie (Valerie Kelly)\nwhich is itself based on Summink by Athanasius (Neil Peter Charley)\nwhich itself was"
+	    "vallie (Valerie Kelley-Gosser)\nwhich is itself based on Summink by Athanasius (Neil Peter Charley)\nwhich itself was"
 	    " based on EW-Too by Burble (Simon Marsh).\n\n");
     stack = strchr(stack, 0);
 
@@ -168,6 +168,11 @@
 
 /* EWE */
     ewe_version();
+
+    stack +=
+	sprintf(stack,
+		" -=*> Invisibility code v0.9 (by astyanax) installed.\n");
+
 
 /* A warning that people are using debugging mode. This means sysops can
    slap silly people who use this mode in live usage -- Silver */