diff -urN origsrc/act.comm.c src/act.comm.c
--- origsrc/act.comm.c	Fri Oct  6 13:46:20 2000
+++ src/act.comm.c	Tue Dec 12 01:22:54 2000
@@ -133,6 +133,8 @@
     act("$E's writing a message right now; try again later.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
   else if ((!IS_NPC(vict) && PRF_FLAGGED(vict, PRF_NOTELL)) || ROOM_FLAGGED(vict->in_room, ROOM_SOUNDPROOF))
     act("$E can't hear you.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
+  else if (STATE(vict->desc) == CON_CHATTING)
+    act("$E is busy chatting with someone else.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
   else
     return (TRUE);
 
diff -urN origsrc/act.informative.c src/act.informative.c
--- origsrc/act.informative.c	Fri Oct  6 13:46:20 2000
+++ src/act.informative.c	Tue Dec 12 16:32:02 2000
@@ -277,6 +277,8 @@
     strcat(buf, " (linkless)");
   if (!IS_NPC(i) && PLR_FLAGGED(i, PLR_WRITING))
     strcat(buf, " (writing)");
+  if (i->desc && STATE(i->desc) == CON_CHATTING)
+    strcat(buf, " (chatting)");
 
   if (GET_POS(i) != POS_FIGHTING)
     strcat(buf, positions[(int) GET_POS(i)]);
@@ -997,9 +999,13 @@
   send_to_char("Players\r\n-------\r\n", ch);
 
   for (d = descriptor_list; d; d = d->next) {
-    if (STATE(d) != CON_PLAYING)
+    if (STATE(d) != CON_PLAYING && STATE(d) != CON_CHATTING)
       continue;
 
+    if (STATE(d) == CON_CHATTING && (!d->character ||
+      (d->character && IN_ROOM(d->character) == NOWHERE)))
+        continue;
+
     if (d->original)
       tch = d->original;
     else if (!(tch = d->character))
@@ -1040,7 +1046,9 @@
       else if (AFF_FLAGGED(tch, AFF_INVISIBLE))
 	strcat(buf, " (invis)");
 
-      if (PLR_FLAGGED(tch, PLR_MAILING))
+      if (STATE(d) == CON_CHATTING)
+    strcat(buf, " (chatting)");
+      else if (PLR_FLAGGED(tch, PLR_MAILING))
 	strcat(buf, " (mailing)");
       else if (PLR_FLAGGED(tch, PLR_WRITING))
 	strcat(buf, " (writing)");
diff -urN origsrc/act.wizard.c src/act.wizard.c
--- origsrc/act.wizard.c	Fri Oct  6 13:46:20 2000
+++ src/act.wizard.c	Tue Dec 12 14:42:00 2000
@@ -57,6 +57,7 @@
 int parse_class(char arg);
 
 /* local functions */
+ACMD(do_chat);
 int perform_set(struct char_data *ch, struct char_data *vict, int mode, char *val_arg);
 void perform_immort_invis(struct char_data *ch, int level);
 ACMD(do_echo);
@@ -2633,3 +2634,76 @@
     free_char(cbuf);
 }
 
+ACMD(do_chat) {
+
+    struct descriptor_data *d = NULL;
+    struct chat_data *chat;
+    int num = 0;
+
+    skip_spaces(&argument);
+
+    if (!*argument)
+        send_to_char("Usage: chat [socket#/char name] (Type USERS for a list)\r\n", ch);
+    else {
+
+        /* Check to see if argument is valid char name or descriptor num */
+        num = atoi(argument);
+        for (d = descriptor_list; d && d->desc_num != num; d = d->next)
+            if (d->character && (!str_cmp(GET_NAME(d->character), argument))) {
+                num = d->desc_num;
+                break;
+            }
+
+        if (!d)
+            send_to_char("No such connection.\r\n", ch);
+        else if (ch->desc->desc_num == num)
+            send_to_char("You don't need a MUD to talk to yourself.\r\n", ch);
+        else if (STATE(d) == CON_CHATTING)
+            send_to_char("They're already chatting with someone.\r\n", ch);
+        else {
+
+            /* Output strings to everyone */
+            sprintf(buf2, "Entering chat mode with %s...\r\n", GET_NAME(ch));
+            if (d->character) {
+                sprintf(buf, "%sEntering chat mode with %s...\r\n", CCWHT(ch, C_SPR), GET_NAME(d->character));
+                act("$n has entered chat mode with $N.", TRUE, ch, NULL, d->character, TO_NOTVICT);
+                if (GET_LEVEL(d->character) >= GET_LEVEL(ch))
+                    strcat(buf2, "(Type /A on a blank line to abort)\r\n");
+            } else {
+                sprintf(buf, "%sEntering chat mode with descriptor #%d...\r\n", CCWHT(ch, C_SPR), num);
+                act("$n has entered chat mode with someone.", TRUE, ch, NULL, NULL, TO_ROOM);
+            }
+            sprintf(buf, "%s(Type /A on a blank line to abort)%s\r\n", buf, CCNRM(ch, C_SPR));
+            
+            send_to_char(buf, ch);
+            write_to_output(buf2, d);
+
+            /* allocate memory */
+            CREATE(chat, struct chat_data, 1);
+            /* Save connect state before changing it */
+            CHAT_BOSS_SAVED_STATE(chat) = STATE(ch->desc);
+            CHAT_SLAVE_SAVED_STATE(chat) = STATE(d);
+            /* assign boss and slave in chat data */
+            CHAT_BOSS(chat) = ch->desc;
+            CHAT_SLAVE(chat) = d;
+            /* Attach chat data to both characters */
+            CHAT_DATA(d) = chat;
+            CHAT_DATA(ch->desc) = chat;
+
+            /* Keep chatters in the void */
+            if (d->character && d->character->in_room != NOWHERE) {
+                GET_WAS_IN(d->character) = d->character->in_room;
+                char_from_room(d->character);
+                char_to_room(d->character, 0);
+            }
+            GET_WAS_IN(ch) = ch->in_room;
+            char_from_room(ch);
+            char_to_room(ch, 0);
+            
+            /* Last but not least, change connection state */
+            STATE(ch->desc) = CON_CHATTING;
+            STATE(d) = CON_CHATTING;
+
+        }
+    }
+}
diff -urN origsrc/comm.c src/comm.c
--- origsrc/comm.c	Fri Oct  6 13:46:20 2000
+++ src/comm.c	Tue Dec 12 16:24:20 2000
@@ -104,6 +104,9 @@
 FILE *logfile = NULL;		/* Where to send the log messages. */
 
 /* functions in this file */
+void void_return(struct descriptor_data *d);
+void chatter(struct descriptor_data *d, char *argument);
+void end_chat(struct chat_data *chat);
 RETSIGTYPE reread_wizlists(int sig);
 RETSIGTYPE unrestrict_game(int sig);
 RETSIGTYPE reap(int sig);
@@ -696,11 +699,8 @@
 	/* Reset the idle timer & pull char back from void if necessary */
 	d->character->char_specials.timer = 0;
 	if (STATE(d) == CON_PLAYING && GET_WAS_IN(d->character) != NOWHERE) {
-	  if (d->character->in_room != NOWHERE)
-	    char_from_room(d->character);
-	  char_to_room(d->character, GET_WAS_IN(d->character));
-	  GET_WAS_IN(d->character) = NOWHERE;
-	  act("$n has returned.", TRUE, d->character, 0, 0, TO_ROOM);
+        void_return(d);
+        act("$n has returned.", TRUE, d->character, 0, 0, TO_ROOM);
 	}
         GET_WAIT_STATE(d->character) = 1;
       }
@@ -710,6 +710,8 @@
 	string_add(d, comm);
       else if (d->showstr_count) /* Reading something w/ pager */
 	show_string(d, comm);
+      else if (STATE(d) == CON_CHATTING)
+        chatter(d, comm);
       else if (STATE(d) != CON_PLAYING) /* In menus, etc. */
 	nanny(d, comm);
       else {			/* else: we're playing normally. */
@@ -945,7 +947,9 @@
     sprintf(prompt,
 	    "\r[ Return to continue, (q)uit, (r)efresh, (b)ack, or page number (%d/%d) ]",
 	    d->showstr_page, d->showstr_count);
-  } else if (STATE(d) == CON_PLAYING && !IS_NPC(d->character)) {
+  } else if (STATE(d) == CON_CHATTING)
+      strcpy(prompt, ": ");
+  else if (STATE(d) == CON_PLAYING && !IS_NPC(d->character)) {
     int count = 0;
     *prompt = '\0';
 
@@ -1792,6 +1796,19 @@
     d->snoop_by->snooping = NULL;
   }
 
+    /* Forget chatting */
+    if (CHAT_DATA(d)) {
+        /* Determine char that is still connected */
+        if (d == CHAT_BOSS(CHAT_DATA(d)))
+            temp = CHAT_SLAVE(CHAT_DATA(d));
+        else
+            temp = CHAT_BOSS(CHAT_DATA(d));
+        /* Inform him about the situation */
+        write_to_output("\r\nCharacter lost link, Exiting chat...\r\n", temp);
+        /* End it all.. */
+        end_chat(CHAT_DATA(d));
+    }
+
   if (d->character) {
     /*
      * Plug memory leak, from Eric Green.
@@ -2057,7 +2074,7 @@
 
 void send_to_char(const char *messg, struct char_data *ch)
 {
-  if (ch->desc && messg)
+  if (ch->desc && messg && STATE(ch->desc) != CON_CHATTING)
     SEND_TO_Q(messg, ch->desc);
 }
 
@@ -2253,6 +2270,8 @@
       continue;
     if (type != TO_ROOM && to == vict_obj)
       continue;
+    if (STATE(to->desc) != CON_PLAYING)
+      continue; /* Keep text from going through chat */
     perform_act(str, ch, obj, vict_obj, to);
   }
 }
@@ -2385,3 +2404,81 @@
 }
 
 #endif /* CIRCLE_WINDOWS */
+
+void chatter(struct descriptor_data *d, char *argument) {
+
+    struct descriptor_data *out;
+    struct chat_data *chat = CHAT_DATA(d);
+    char name[MAX_NAME_LENGTH+1];
+
+    /* Forget about blank lines */
+    skip_spaces(&argument);
+
+    if (!*argument)
+        return;
+
+    delete_doubledollar(argument);
+
+    if (d == CHAT_BOSS(chat))
+        out = CHAT_SLAVE(chat);
+    else
+        out = CHAT_BOSS(chat);
+
+    if ((!str_cmp(argument, "/a")) && d->character
+     && CHAT_LEVEL(chat) <= GET_LEVEL(d->character)) {
+        write_to_output("Exiting chat mode...\r\n", d);
+        write_to_output("Exiting chat, please continue what you were doing.\r\n", out);
+        end_chat(chat);
+        return;
+    }
+
+    if (d->character)
+        strcpy(name, GET_NAME(d->character));
+    else
+        strcpy(name, "Unknown");
+
+    CAP(name);
+
+    sprintf(buf, "%s> %s\r\n", name, argument);
+    write_to_output(buf, out);
+    sprintf(buf, "You> %s\r\n", argument);
+    write_to_output(buf, d);
+
+}
+
+void end_chat(struct chat_data *chat) {
+
+/* Do not change the order in which these things are done at all */
+
+    /* Return chars from void */
+    void_return(CHAT_BOSS(chat));
+    void_return(CHAT_SLAVE(chat));
+
+    /* let people around know what's happening */
+    act("$n has returned from chat mode.", TRUE, CHAT_BOSS(chat)->character, 0, 0, TO_NOTVICT);
+    if (CHAT_SLAVE(chat)->character && CHAT_SLAVE(chat)->character->in_room != NOWHERE)
+        act("$n has returned from chat mode.", TRUE, CHAT_SLAVE(chat)->character, 0, 0, TO_NOTVICT);
+
+    /* Restore connection states */
+    STATE(CHAT_BOSS(chat)) = CHAT_BOSS_SAVED_STATE(chat);
+    STATE(CHAT_SLAVE(chat)) = CHAT_SLAVE_SAVED_STATE(chat);
+
+    /* Null out pointers to chat data */
+    CHAT_DATA(CHAT_BOSS(chat)) = NULL;
+    CHAT_DATA(CHAT_SLAVE(chat)) = NULL;
+
+    /* Free the chat data structure */
+    free(chat);
+
+}
+
+void void_return(struct descriptor_data *d) {
+
+    if (d->character && d->character->in_room != NOWHERE &&
+     GET_WAS_IN(d->character) != NOWHERE) {
+        char_from_room(d->character);
+        char_to_room(d->character, GET_WAS_IN(d->character));
+        GET_WAS_IN(d->character) = NOWHERE;
+    }
+
+}
diff -urN origsrc/constants.c src/constants.c
--- origsrc/constants.c	Fri Oct  6 13:46:20 2000
+++ src/constants.c	Tue Dec 12 15:42:58 2000
@@ -235,6 +235,7 @@
   "Self-Delete 1",
   "Self-Delete 2",
   "Disconnecting",
+  "Chatting     ",
   "\n"
 };
 
diff -urN origsrc/fight.c src/fight.c
--- origsrc/fight.c	Fri Oct  6 13:46:20 2000
+++ src/fight.c	Tue Dec 12 01:28:34 2000
@@ -660,6 +660,10 @@
   if (!IS_NPC(victim) && (GET_LEVEL(victim) >= LVL_IMMORT))
     dam = 0;
 
+  /* Prevent people who entered chat wounded from suffering */
+  if (victim->desc && STATE(victim->desc) == CON_CHATTING)
+    dam = 0;
+
   if (victim != ch) {
     /* Start the attacker fighting the victim */
     if (GET_POS(ch) > POS_STUNNED && (FIGHTING(ch) == NULL))
diff -urN origsrc/handler.c src/handler.c
--- origsrc/handler.c	Fri Oct  6 13:46:20 2000
+++ src/handler.c	Tue Dec 12 01:37:46 2000
@@ -36,6 +36,7 @@
 void update_char_objects(struct char_data * ch);
 
 /* external functions */
+void end_chat(struct chat_data *chat);
 int invalid_class(struct char_data *ch, struct obj_data *obj);
 void remove_follower(struct char_data * ch);
 void clearMemory(struct char_data * ch);
@@ -846,7 +847,7 @@
 void extract_char(struct char_data * ch)
 {
   struct char_data *k, *temp;
-  struct descriptor_data *t_desc;
+  struct descriptor_data *t_desc, *other;
   struct obj_data *obj;
   int i, freed = 0;
 
@@ -876,6 +877,20 @@
       ch->desc->snoop_by = NULL;
     }
   }
+
+    /* Forget chatting if applicable */
+    if (ch->desc && CHAT_DATA(ch->desc)) {
+        /* Determine char who is still alive */
+        if (ch->desc == CHAT_BOSS(CHAT_DATA(ch->desc)))
+            other = CHAT_SLAVE(CHAT_DATA(ch->desc));
+        else
+            other = CHAT_BOSS(CHAT_DATA(ch->desc));
+        /* Inform him about the situation */
+        write_to_output("\r\nCharacter extracted, Exiting chat...\r\n", other);
+        /* End it all.. */
+        end_chat(CHAT_DATA(ch->desc));
+    }
+
   /* transfer objects to room, if any */
   while (ch->carrying) {
     obj = ch->carrying;
diff -urN origsrc/interpreter.c src/interpreter.c
--- origsrc/interpreter.c	Fri Oct  6 13:46:20 2000
+++ src/interpreter.c	Tue Dec 12 00:45:12 2000
@@ -75,6 +75,7 @@
 ACMD(do_ban);
 ACMD(do_bash);
 ACMD(do_cast);
+ACMD(do_chat);
 ACMD(do_color);
 ACMD(do_commands);
 ACMD(do_consider);
@@ -242,6 +243,7 @@
   { "buy"      , POS_STANDING, do_not_here , 0, 0 },
   { "bug"      , POS_DEAD    , do_gen_write, 0, SCMD_BUG },
 
+  { "chat"     , POS_DEAD    , do_chat     , LVL_GRGOD, 0 },
   { "cast"     , POS_SITTING , do_cast     , 1, 0 },
   { "cackle"   , POS_RESTING , do_action   , 0, 0 },
   { "check"    , POS_STANDING, do_not_here , 1, 0 },
diff -urN origsrc/structs.h src/structs.h
--- origsrc/structs.h	Fri Oct  6 13:46:20 2000
+++ src/structs.h	Tue Dec 12 00:49:36 2000
@@ -246,6 +246,7 @@
 #define CON_DELCNF1	 15		/* Delete confirmation 1	*/
 #define CON_DELCNF2	 16		/* Delete confirmation 2	*/
 #define CON_DISCONNECT	 17		/* In-game disconnection	*/
+#define CON_CHATTING     18     /* Character is in chat mode */
 
 /* Character equipment positions: used as index for char_data.equipment[] */
 /* NOTE: Don't confuse these constants with the ITEM_ bitvectors
@@ -975,6 +976,7 @@
    struct descriptor_data *snooping; /* Who is this char snooping	*/
    struct descriptor_data *snoop_by; /* And who is snooping this char	*/
    struct descriptor_data *next; /* link to next descriptor		*/
+   struct chat_data *chat_info;  /* NULL if not chatting */
 };
 
 
@@ -1065,3 +1067,12 @@
    int	number;		/* number of existing units of this mob/obj	*/
    SPECIAL(*func);
 };
+
+/*********** Chat stuff **************************************************/
+
+   struct chat_data {
+       int boss_saved_con;    /* mode of connectedness before entering chat*/
+       int slave_saved_con;   /* mode of connectedness before entering chat*/
+       struct descriptor_data *boss;  /* Descriptor that initiated chat */
+       struct descriptor_data *slave; /* and the other guy.. */
+   };
diff -urN origsrc/utils.h src/utils.h
--- origsrc/utils.h	Fri Oct  6 13:46:20 2000
+++ src/utils.h	Tue Dec 12 00:43:34 2000
@@ -504,3 +504,14 @@
 #define CRYPT(a,b) ((char *) crypt((a),(b)))
 #endif
 
+/** Defines for chat system ************************************************/
+
+#define CHAT_BOSS(chat)                  ((chat)->boss)
+#define CHAT_SLAVE(chat)                 ((chat)->slave)
+
+#define CHAT_BOSS_SAVED_STATE(chat)      ((chat)->boss_saved_con)
+#define CHAT_SLAVE_SAVED_STATE(chat)     ((chat)->slave_saved_con)
+
+#define CHAT_DATA(d)                     ((d)->chat_info)
+
+#define CHAT_LEVEL(chat)                 (GET_LEVEL((chat)->boss->character))
