rm6/
rm6/clans/
rm6/councils/
rm6/deity/
rm6/doc/mudprogs/
rm6/exchange/
rm6/gods/
rm6/homes/
rm6/nations/
rm6/player/
rm6/player/a/
rm6/src/RCS/
rm6/src/dmalloc/
rm6/src/dmalloc/bin/
rm6/src/dmalloc/include/
rm6/src/dmalloc/lib/
rm6/src/scripts/
rm6/src/utils/
/****************************************************************************
 * ResortMUD Version 5.0 was mainly programmed by Ntanel, Garinan, Josh,    *
 * Badastaz, Digifuzz, Senir, Kratas, Scion, Shogar and Tagith.             *
 * ResortMud Version 5.0b programed By Badastaz and Garinan
 * ------------------------------------------------------------------------ *
 * Copyright (C) 1996 - 2001 Haslage Net Electronics: MudWorld of Lorain,   *
 * Ohio.    ALL RIGHTS RESERVED    See /doc/RMLicense.txt for more details. *
 ****************************************************************************/

/****************************************************************************
 *                   ^     +----- |  / ^     ^ |     | +-\                  *
 *                  / \    |      | /  |\   /| |     | |  \                 *
 *                 /   \   +---   |<   | \ / | |     | |  |                 *
 *                /-----\  |      | \  |  v  | |     | |  /                 *
 *               /       \ |      |  \ |     | +-----+ +-/                  *
 ****************************************************************************
 * AFKMud Copyright 1997-2002 Alsherok. Contributors: Samson, Dwip, Whir,   *
 * Cyberfox, Karangi, Rathian, Cam, Raine, and Tarl.                        *
 *                                                                          *
 * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag,        *
 * Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard,        *
 * Grishnakh, Fireblade, and Nivek.                                         *
 *                                                                          *
 * Original MERC 2.1 code by Hatchet, Furey, and Kahn.                      *
 *                                                                          *
 * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen,      *
 * Michael Seifert, and Sebastian Hammer.                                   *
 ****************************************************************************
 *                          Dynamic Channel System                          *
 ****************************************************************************/

#include <string.h>
#include <ctype.h>
#include <time.h>
#include "mud.h"

MUD_CHANNEL *first_channel;
MUD_CHANNEL *last_channel;
char *drunk_speech args( ( const char *argument, CHAR_DATA * ch ) );
bool check_cuss args( ( char *cuss ) );

char *const chan_types[] = {
   "Global", "Zone", "Guild", "Council", "PK", "Log"
};

int get_chantypes( char *name )
{
   size_t x;

   for( x = 0; x < sizeof( chan_types ) / sizeof( chan_types[0] ); x++ )
      if( !str_cmp( name, chan_types[x] ) )
         return x;
   return -1;
}

void read_channel( MUD_CHANNEL * channel, FILE * fp )
{
   char *word;
   bool fMatch;

   for( ;; )
   {
      word = feof( fp ) ? "End" : fread_word( fp );
      fMatch = FALSE;

      switch ( UPPER( word[0] ) )
      {
         case '*':
            fMatch = TRUE;
            fread_to_eol( fp );
            break;

         case 'C':
            KEY( "ChanName", channel->name, fread_string( fp ) );
            KEY( "ChanLevel", channel->level, fread_number( fp ) );
            KEY( "ChanType", channel->type, fread_number( fp ) );
            KEY( "ChanHistory", channel->keephistory, fread_number( fp ) );
            break;

         case 'E':
            if( !str_cmp( word, "End" ) )
               return;
            break;
      }
      if( !fMatch )
         bug( "read_channel: no match: %s", word );
   }
}

void load_mudchannels( void )
{
   FILE *fp;
   MUD_CHANNEL *channel;

   first_channel = NULL;
   last_channel = NULL;

   log_string( "Loading mud channels..." );

   if( ( fp = fopen( CHANNEL_FILE, "r" ) ) == NULL )
   {
      log_string( "No channel file found." );
      return;
   }

   for( ;; )
   {
      char letter;
      char *word;

      letter = fread_letter( fp );
      if( letter == '*' )
      {
         fread_to_eol( fp );
         continue;
      }

      if( letter != '#' )
      {
         bug( "load_channels: # not found.", 0 );
         break;
      }

      word = fread_word( fp );
      if( !str_cmp( word, "CHANNEL" ) )
      {
         CREATE( channel, MUD_CHANNEL, 1 );
         read_channel( channel, fp );

         LINK( channel, first_channel, last_channel, next, prev );
         continue;
      }
      else if( !str_cmp( word, "END" ) )
         break;
      else
      {
         bug( "load_channels: bad section: %s.", word );
         continue;
      }
   }
   fclose( fp );
   return;
}

void save_mudchannels( void )
{
   FILE *fp;
   MUD_CHANNEL *channel;

   if( ( fp = fopen( CHANNEL_FILE, "w" ) ) == NULL )
   {
      log_string( "Couldn't write to channel file." );
      return;
   }

   for( channel = first_channel; channel; channel = channel->next )
   {
      if( channel->name )
      {
         fprintf( fp, "#CHANNEL\n" );
         fprintf( fp, "ChanName    %s~\n", channel->name );
         fprintf( fp, "ChanLevel   %d\n", channel->level );
         fprintf( fp, "ChanType    %d\n", channel->type );
         fprintf( fp, "ChanHistory %d\n", channel->keephistory );
         fprintf( fp, "End\n\n" );
      }
   }
   fprintf( fp, "#END\n" );
   fclose( fp );
}

MUD_CHANNEL *find_channel( char *name )
{
   MUD_CHANNEL *channel = NULL;

   for( channel = first_channel; channel; channel = channel->next )
   {
      if( !str_cmp( channel->name, name ) )
         return channel;
   }
   return NULL;
}

void do_makechannel( CHAR_DATA * ch, char *argument )
{
   MUD_CHANNEL *channel;

   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "&GSyntax: makechannel <name>\r\n", ch );
      return;
   }

   if( ( channel = find_channel( argument ) ) )
   {
      send_to_char( "&RA channel with that name already exists.\r\n", ch );
      return;
   }

   CREATE( channel, MUD_CHANNEL, 1 );
   channel->name = STRALLOC( argument );
   channel->level = LEVEL_IMMORTAL;
   channel->type = CHAN_GLOBAL;
   channel->keephistory = FALSE;
   LINK( channel, first_channel, last_channel, next, prev );
   ch_printf( ch, "New channel %s created.\r\n", argument );
   save_mudchannels(  );
   return;
}

void do_setchannel( CHAR_DATA * ch, char *argument )
{
   MUD_CHANNEL *channel;
   char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];

   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Syntax: setchannel <channel> <field> <value>\r\n\r\n", ch );
      send_to_char( "Field may be one of the following:\r\n", ch );
      send_to_char( "name level type history\r\n", ch );
      return;
   }

   argument = one_argument( argument, arg );

   if( !( channel = find_channel( arg ) ) )
   {
      send_to_char( "No channel by that name exists.\r\n", ch );
      return;
   }

   argument = one_argument( argument, arg2 );

   if( !arg || arg2[0] == '\0' )
   {
      do_setchannel( ch, "" );
      return;
   }

   if( !str_cmp( arg2, "name" ) )
   {
      ch_printf( ch, "Channel %s renamed to %s\r\n", channel->name, argument );
      STRFREE( channel->name );
      channel->name = STRALLOC( argument );
      save_mudchannels(  );
      return;
   }

   if( !str_cmp( arg2, "level" ) )
   {
      int level;

      if( !is_number( argument ) )
      {
         send_to_char( "Level must be numerical.\r\n", ch );
         return;
      }

      level = atoi( argument );

      if( level < 1 || level > MAX_LEVEL )
      {
         ch_printf( ch, "Invalid level. Acceptable range is 1 to %d.\r\n", MAX_LEVEL );
         return;
      }

      channel->level = level;
      ch_printf( ch, "Channel %s level changed to %d\r\n", channel->name, level );
      save_mudchannels(  );
      return;
   }

   if( !str_cmp( arg2, "type" ) )
   {
      int type = get_chantypes( argument );

      if( type == -1 )
      {
         send_to_char( "Invalid channel type.\r\n", ch );
         return;
      }

      channel->type = type;
      ch_printf( ch, "Channel %s type changed to %s\r\n", channel->name, argument );
      save_mudchannels(  );
      return;
   }

   if( !str_cmp( arg2, "history" ) )
   {
      channel->keephistory = !channel->keephistory;

      if( channel->keephistory )
         ch_printf( ch, "Channel %s will now keep a history.\r\n", channel->name );
      else
         ch_printf( ch, "Channel %s will no longer keep a history.\r\n", channel->name );
      save_mudchannels(  );
      return;
   }

   do_setchannel( ch, "" );
   return;
}

void do_destroychannel( CHAR_DATA * ch, char *argument )
{
   MUD_CHANNEL *channel;

   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Syntax: destroychannel <name>\r\n", ch );
      return;
   }

   if( !( channel = find_channel( argument ) ) )
   {
      send_to_char( "No channel with that name exists.\r\n", ch );
      return;
   }

   STRFREE( channel->name );
   UNLINK( channel, first_channel, last_channel, next, prev );
   DISPOSE( channel );

   ch_printf( ch, "Channel %s destroyed.\r\n", argument );
   save_mudchannels(  );
   return;
}

void do_showchannels( CHAR_DATA * ch, char *argument )
{
   MUD_CHANNEL *channel;

   send_to_char( "&WName               Level Type       History?&D\r\n", ch );
   send_to_char( "&B-------------------------------------------&D\r\n", ch );
   for( channel = first_channel; channel; channel = channel->next )
      ch_printf( ch, "&Y%-18s %-4d  %-10s %s\r\n", capitalize( channel->name ),
                 channel->level, chan_types[channel->type], channel->keephistory ? "Yes" : "No" );
   return;
}

/* Stuff borrowed from I3/MUD-Net code to handle channel listening */

/*  changetarg: extract a single argument (with given max length) from
 *  argument to arg; if arg==NULL, just skip an arg, don't copy it out
 */
const char *getarg( const char *argument, char *arg, int length )
{
   int len = 0;

   while( *argument && isspace( *argument ) )
      argument++;

   if( arg )
      while( *argument && !isspace( *argument ) && len < length - 1 )
         *arg++ = *argument++, len++;
   else
      while( *argument && !isspace( *argument ) )
         argument++;

   while( *argument && !isspace( *argument ) )
      argument++;

   while( *argument && isspace( *argument ) )
      argument++;

   if( arg )
      *arg = 0;

   return argument;
}

/* Check for a name in a list */
int hasname( const char *list, const char *name )
{
   const char *p;
   char arg[MAX_INPUT_LENGTH];

   if( !list )
      return ( 0 );

   p = getarg( list, arg, MAX_INPUT_LENGTH );
   while( arg[0] )
   {
      if( !strcasecmp( name, arg ) )
         return 1;
      p = getarg( p, arg, MAX_INPUT_LENGTH );
   }

   return 0;
}

/* Add a name to a list */
void addname( char **list, const char *name )
{
   char buf[MAX_STRING_LENGTH];

   if( hasname( *list, name ) )
      return;

   if( *list && *list[0] != '\0' )
      sprintf( buf, "%s %s", *list, name );
   else
      strcpy( buf, name );

   if( *list )
      STRFREE( *list );
   *list = STRALLOC( buf );
}

/* Remove a name from a list */
void removename( char **list, const char *name )
{
   char buf[MAX_STRING_LENGTH];
   char arg[MAX_INPUT_LENGTH];
   const char *p;

   buf[0] = 0;
   p = getarg( *list, arg, MAX_INPUT_LENGTH );
   while( arg[0] )
   {
      if( strcasecmp( arg, name ) )
      {
         if( buf[0] )
            strcat( buf, " " );
         strcat( buf, arg );
      }
      p = getarg( p, arg, MAX_INPUT_LENGTH );
   }

   STRFREE( *list );
   *list = STRALLOC( buf );
}

void do_listen( CHAR_DATA * ch, char *argument )
{
   MUD_CHANNEL *channel;

   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Syntax: listen \r\n", ch );
      send_to_char( "Syntax: listen all\r\n", ch );
      send_to_char( "Syntax: listen none\r\n", ch );
      send_to_char( "For a list of channels, type channels\r\n", ch );
      send_to_char( "You are listenting to the following local mud channels:\r\n\r\n", ch );
      ch_printf( ch, "%s\r\n", ch->pcdata->chan_listen );
      return;
   }

   if( !str_cmp( argument, "all" ) )
   {
      for( channel = first_channel; channel; channel = channel->next )
      {
         if( ch->level >= channel->level && !hasname( ch->pcdata->chan_listen, channel->name ) )
            addname( &ch->pcdata->chan_listen, channel->name );
      }
      send_to_char( "You are now listening to all available channels.\r\n", ch );
      return;
   }

   if( !str_cmp( argument, "none" ) )
   {
      for( channel = first_channel; channel; channel = channel->next )
      {
         if( ch->level >= channel->level && hasname( ch->pcdata->chan_listen, channel->name ) )
            removename( &ch->pcdata->chan_listen, channel->name );
      }
      send_to_char( "You no longer listen to any available channel.\r\n", ch );
      return;
   }

   if( hasname( ch->pcdata->chan_listen, argument ) )
   {
      removename( &ch->pcdata->chan_listen, argument );
      ch_printf( ch, "You no longer listen to %s\r\n", argument );
   }
   else
   {
      if( !( channel = find_channel( argument ) ) )
      {
         send_to_char( "No such channel.\r\n", ch );
         return;
      }
      if( channel->level > ch->level )
      {
         send_to_char( "That channel is above your level.\r\n", ch );
         return;
      }
      addname( &ch->pcdata->chan_listen, argument );
      ch_printf( ch, "You now listen to %s\r\n", channel->name );
   }
   return;
}

/* Revised channel display by Zarius */
void do_channels( CHAR_DATA * ch, char *argument )
{
   MUD_CHANNEL *channel;
   int count = 0, second = 0, third = 0;
   MUD_CHANNEL *offchannel;
   int first = 0;

   send_to_char( "&YThe following channels are available:\r\n", ch );
   send_to_char( "To toggle a channel, use the &Wlisten &Ycommand.\r\n\r\n", ch );

   send_to_char( "&B----------------------------------------------------------------&D\r\n", ch );
   for( channel = first_channel; channel; channel = channel->next )
   {
      if( ch->level >= channel->level )
      {
         if( hasname( ch->pcdata->chan_listen, channel->name ) == 0 )
            continue;

         third += 1;
         first += 1;
         count += 1;
         if( third == 1 )
            ch_printf( ch, "&WYou are listening to these channels!\r\n" );

         ch_printf( ch, "&C%-15.15s &D", capitalize( channel->name ) );
         if( count == 4 )
         {
            ch_printf( ch, "\r\n" );
            count = 0;
         }
      }
   }
   if( count != 0 )
      ch_printf( ch, "\r\n" );
   if( first != 0 )
      send_to_char( "&B----------------------------------------------------------------&D\r\n", ch );
   third = 0;
   first = 0;
   for( offchannel = first_channel; offchannel; offchannel = offchannel->next )
   {
      if( ch->level >= offchannel->level )
      {
         if( hasname( ch->pcdata->chan_listen, offchannel->name ) == 1 )
            continue;

         third += 1;
         first += 1;
         second += 1;
         if( third == 1 )
            ch_printf( ch, "&WYou are not listening to these channels!\r\n" );

         ch_printf( ch, "&R%-15.15s &D", capitalize( offchannel->name ) );
         if( second == 4 )
         {
            ch_printf( ch, "\r\n" );
            second = 0;
         }
      }
   }
   if( second != 0 )
      send_to_char( "\r\n", ch );
   if( first != 0 )
      send_to_char( "&B----------------------------------------------------------------&D\r\n", ch );
   return;
}

void invert( char *arg1, char *arg2 )
{
   int i = 0;
   int len = strlen( arg1 ) - 1;

   while( i <= len )
   {
      *( arg2 + i ) = *( arg1 + ( len - i ) );
      i++;
   }
   *( arg2 + i ) = '\0';
}

/* Duplicate of to_channel from act_comm.c modified for dynamic channels */
void send_tochannel( CHAR_DATA * ch, MUD_CHANNEL * channel, char *argument )
{
   char buf[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH], word[MAX_INPUT_LENGTH], log_buf2[MAX_STRING_LENGTH];
   char *arg, *socbuf_char = NULL, *socbuf_vict = NULL, *socbuf_other = NULL;
   CHAR_DATA *victim = NULL;
   CHAR_DATA *vch;
   OBJ_DATA *obj; /* Burgundy Amulet */
   SOCIALTYPE *social = NULL;
   int position, x, msg;
   short color;
   char clr[MSL];
   struct tm *local;
   time_t t;
   bool emote = FALSE;

#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   if( IS_NPC( ch ) && channel->type == CHAN_GUILD )
   {
      send_to_char( "Mobs can't be in clans/guilds.\r\n", ch );
      return;
   }

   if( !IS_PKILL( ch ) && channel->type == CHAN_PK )
   {
      if( !IS_IMMORTAL( ch ) )
      {
         send_to_char( "Peacefuls have no need to use wartalk.\r\n", ch );
         return;
      }
   }

   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "The room absorbs your words!\r\n", ch );
      return;
   }

   if( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
   {
      if( ch->master )
         send_to_char( "I don't think so...\r\n", ch->master );
      return;
   }
   if( !IS_NPC( ch ) && !ch->pcdata->clan && channel->type == CHAN_GUILD )
   {
      ch_printf( ch, "You're not in a %s!\r\n",
                 !str_cmp( channel->name, "clantalk" ) ? "clan" : !str_cmp( channel->name,
                                                                            "guildtalk" ) ? "guild" : "order" );
      return;
   }

   if( !argument || argument[0] == '\0' )
   {
      char *name;

      if( !channel->keephistory )
      {
         ch_printf( ch, "%s what?\r\n", capitalize( channel->name ) );
         return;
      }

      ch_printf( ch, "The last 20 %s messages:\r\n", channel->name );
      for( x = 0; x < 20; x++ )
      {
         if( channel->history[x][0] != NULL )
         {
            switch ( channel->hlevel[x] )
            {
               case 0:
                  name = channel->history[x][0];
                  break;
               case 1:
                  if( IS_AFFECTED( ch, AFF_DETECT_INVIS ) || xIS_SET( ch->act, PLR_HOLYLIGHT ) )
                     name = channel->history[x][0];
                  else
                     name = "Someone";
                  break;
               case 2:
                  if( ch->level >= channel->hinvis[x] )
                     name = channel->history[x][0];
                  else
                     name = "Someone";
                  break;
               default:
                  name = "Someone";
            }
            ch_printf( ch, channel->history[x][1], name );
         }
         else
            break;
      }
      return;
   }

   if( xIS_SET( ch->act, PLR_SILENCE ) )
   {
      ch_printf( ch, "You can't %s.\r\n", channel->name );
      return;
   }

   /*
    * Inverts the speech of anyone carrying the burgundy amulet 
    */
   for( obj = ch->first_carrying; obj; obj = obj->next_content )
   {
      if( obj->pIndexData->vnum == 1405 ) /* The amulet itself */
      {
         invert( argument, log_buf );
         strcpy( argument, log_buf );
         break;
      }
   }

   /*
    * OK, this is hackish - until I can figure out a better method 
    */
   color = -1;
   if( !str_cmp( channel->name, "chat" ) )
      sprintf( clr, "G" );
   else if( !str_cmp( channel->name, "immtalk" ) )
      sprintf( clr, "Y" );
   else if( !str_cmp( channel->name, "avtalk" ) )
      sprintf( clr, "O" );
   else if( !str_cmp( channel->name, "ooc" ) )
      sprintf( clr, "G" );
   else if( !str_cmp( channel->name, "icc" ) )
      sprintf( clr, "G" );
   else if( !str_cmp( channel->name, "yell" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "shout" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "muse" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "think" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "auction" ) )
      sprintf( clr, "G" );
   else if( !str_cmp( channel->name, "wartalk" ) )
      sprintf( clr, "R" );
   else if( !str_cmp( channel->name, "music" ) )
      sprintf( clr, "P" );
   else if( !str_cmp( channel->name, "quest" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "newbiechat" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "guildtalk" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "counciltalk" ) )
      sprintf( clr, "c" );
   else if( !str_cmp( channel->name, "clantalk" ) )
      sprintf( clr, "R" );
   else if( !str_cmp( channel->name, "ordertalk" ) )
      sprintf( clr, "C" );
   else if( !str_cmp( channel->name, "quote" ) )
      sprintf( clr, "c" );
   else
      sprintf( clr, "G" );

   if( color == -1 )
      color = AT_GOSSIP;

   set_char_color( color, ch );

   arg = argument;
   arg = one_argument( arg, word );

   if( word[0] == '@' && ( social = find_social( word + 1 ) ) != NULL )
   {
      if( arg && *arg )
      {
         char name[MAX_INPUT_LENGTH];

         one_argument( arg, name );

         if( ( victim = get_char_world( ch, name ) ) )
            arg = one_argument( arg, name );

         if( !victim )
         {
            socbuf_char = social->char_no_arg;
            socbuf_vict = social->others_no_arg;
            socbuf_other = social->others_no_arg;
            if( !socbuf_char && !socbuf_other )
               social = NULL;
         }
         else if( victim == ch )
         {
            socbuf_char = social->char_auto;
            socbuf_vict = social->others_auto;
            socbuf_other = social->others_auto;
            if( !socbuf_char && !socbuf_other )
               social = NULL;
         }
         else if( victim != ch )
         {
            socbuf_char = social->char_found;
            socbuf_vict = social->vict_found;
            socbuf_other = social->others_found;
            if( !socbuf_char && !socbuf_other && !socbuf_vict )
               social = NULL;
         }
         else
            social = NULL;
      }
      else
      {
         socbuf_char = social->char_no_arg;
         socbuf_vict = social->others_no_arg;
         socbuf_other = social->others_no_arg;
         if( !socbuf_char && !socbuf_other )
            social = NULL;
      }
   }

   if( word[0] == ',' )
      emote = TRUE;

   if( social )
   {
      sprintf( buf, "&w[&%s%s&w] &%s%s", clr, capitalize( channel->name ), clr, socbuf_char );
      act( AT_PLAIN, buf, ch, argument, victim, TO_CHAR );
   }
   else if( emote )
   {
      sprintf( log_buf, "&w[&%s%s&w] &%s%s %s\r\n", clr, capitalize( channel->name ), clr, ch->name, argument + 1 );
      send_to_char( log_buf, ch );
      argument = argument + 1;
   }
   else
   {  // Profanity Filter
      if( check_cuss( argument ) && !IS_IMMORTAL( ch ) && str_cmp( channel->name, "wartalk" ) )
      {
         msg = number_range( 0, 4 );
         if( msg == 0 )
            send_to_char( "Potty Mouth!\r\n", ch );
         if( msg == 1 )
            send_to_char( "Shame on You!\r\n", ch );
         if( msg == 2 )
            send_to_char( "Do you kiss your mother with that filthy mouth!?\r\n", ch );
         if( msg == 3 )
            send_to_char( "Git tha soap Ma, it's time fer a mouth washin'!\r\n", ch );
         if( msg == 4 )
            send_to_char( "Somewhere, a single tear is rolling down Garinan's cheek.\r\n", ch );

         sprintf( buf, "Profanity attempt by %s on channel %s: %s", ch->name, channel->name, argument );
         log_string( buf );
         return;
      }
      ch_printf( ch, "&w[&%s%s&w] You: &%s%s\r\n", clr, capitalize( channel->name ), clr, argument );
   }

   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf2, "%s: %s (%s)", IS_NPC( ch ) ? ch->short_descr : ch->name, argument, channel->name );
      append_to_file( LOG_FILE, buf2 );
   }

   /*
    * Channel history. Records the last 20 messages to channels which keep historys 
    */
   if( channel->keephistory )
   {
      for( x = 0; x < 20; x++ )
      {
         int type;

         type = 0;
         if( IS_AFFECTED( ch, AFF_INVISIBLE ) )
            type = 1;
         if( xIS_SET( ch->act, PLR_WIZINVIS ) )
            type = 2;

         if( channel->history[x][0] == NULL )
         {
            if( IS_NPC( ch ) )
               channel->history[x][0] = str_dup( ch->short_descr );
            else
               channel->history[x][0] = str_dup( ch->name );

            t = time( NULL );
            local = localtime( &t );
            sprintf( log_buf2, "   [%-2.2d:%-2.2d] %%s%s %s\r\n",
                     local->tm_hour, local->tm_min, emote ? "" : ":", argument );

            channel->history[x][1] = str_dup( log_buf2 );
            channel->hlevel[x] = type;
            if( type == 2 )
               channel->hinvis[x] = ch->pcdata->wizinvis;
            else
               channel->hinvis[x] = 0;
            break;
         }

         if( x == 19 )
         {
            int y;

            for( y = 1; y < 20; y++ )
            {
               int z = y - 1;

               if( channel->history[z][0] != NULL )
               {
                  DISPOSE( channel->history[z][0] );
                  DISPOSE( channel->history[z][1] );
                  channel->history[z][0] = str_dup( channel->history[y][0] );
                  channel->history[z][1] = str_dup( channel->history[y][1] );
                  channel->hlevel[z] = channel->hlevel[y];
                  channel->hinvis[z] = channel->hinvis[y];
               }
            }
            if( IS_NPC( ch ) )
               channel->history[x][0] = str_dup( ch->short_descr );
            else
               channel->history[x][0] = str_dup( ch->name );

            t = time( NULL );
            local = localtime( &t );
            sprintf( log_buf2, "   [%-2.2d:%-2.2d] %%s%s %s\r\n",
                     local->tm_hour, local->tm_min, emote ? "" : ":", argument );
            channel->history[x][1] = str_dup( log_buf2 );

            channel->hlevel[x] = type;
            if( type == 2 )
               channel->hinvis[x] = ch->pcdata->wizinvis;
            else
               channel->hinvis[x] = 0;
         }
      }
   }

   for( vch = first_char; vch; vch = vch->next )
   {
      /*
       * Hackish solution to stop that damned "someone chat" bug - Matarael 17.3.2002 
       */

      if( IS_NPC( vch ) || vch == ch || !vch->desc )
         continue;

      if( vch->desc->connected == CON_PLAYING && hasname( vch->pcdata->chan_listen, channel->name ) )
      {
         char *sbuf = argument;
         char lbuf[MAX_INPUT_LENGTH + 4]; /* invis level string + buf */

         if( vch->level < channel->level )
            continue;

         /*
          * Another hackish deal for now 
          */
         if( !str_cmp( channel->name, "newbiechat" ) && ( !IS_IMMORTAL( vch ) && vch->level < 5 ) )
            continue;

         if( !str_cmp( channel->name, "immtalk" ) && !IS_IMMORTAL( vch ) )
            continue;

         if( !str_cmp( channel->name, "avtalk" ) && vch->level < LEVEL_AVATAR )
            continue;

         if( IS_SET( vch->in_room->room_flags, ROOM_SILENCE ) )
            continue;

         if( channel->type == CHAN_ZONE && vch->in_room->area != ch->in_room->area )
            continue;

         if( channel->type == CHAN_PK && !IS_PKILL( vch ) && !IS_IMMORTAL( vch ) )
            continue;

         if( channel->type == CHAN_GUILD )
         {
            if( IS_NPC( vch ) )
               continue;
            if( vch->pcdata->clan != ch->pcdata->clan )
               continue;
         }

         if( channel->type == CHAN_COUNCIL )
         {
            if( IS_NPC( vch ) )
               continue;
            if( vch->pcdata->council != ch->pcdata->council )
               continue;
         }

         position = vch->position;
         vch->position = POS_STANDING;

         set_char_color( color, vch );
         if( xIS_SET( ch->act, PLR_WIZINVIS ) && can_see( vch, ch ) && IS_IMMORTAL( vch ) )
            sprintf( lbuf, "(%d) ", ( !IS_NPC( ch ) ) ? ch->pcdata->wizinvis : ch->mobinvis );
         else
            lbuf[0] = '\0';

#ifndef SCRAMBLE
         if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
         {
            int speakswell = UMIN( knows_language( vch, ch->speaking ), knows_language( ch, ch->speaking ) );

            if( speakswell < 85 )
               sbuf = translate( speakswell, argument, lang_names[speaking] );
         }
#else
         if( !knows_language( vch, ch->speaking ) && ( !IS_NPC( ch ) || ch->speaking != 0 ) )
            sbuf = scramble( argument, ch->speaking );
#endif

         /*
          * Check to see if target is ignoring the sender 
          */
         if( is_ignoring( vch, ch ) )
         {
            /*
             * If the sender is an imm then they cannot be ignored 
             */
            if( !IS_IMMORTAL( ch ) || vch->level > ch->level )
            {
               /*
                * Off to oblivion! 
                */
               continue;
            }
            else
               set_char_color( AT_IGNORE, vch );
         }

         MOBtrigger = FALSE;

         /*
          * Hackish solution to stop that damned "someone chat" bug - Matarael 17.3.2002 
          */

         if( !social && !emote )
         {
            sprintf( buf, "&w[&%s%s&w] $n: &%s$t", clr, capitalize( channel->name ), clr );
            act( AT_PLAIN, strcat( lbuf, buf ), ch, sbuf, vch, TO_VICT );
         }
         if( emote )
         {
            sprintf( buf, "&w[&%s%s&w] &%s$n $t", clr, capitalize( channel->name ), clr );
            act( AT_PLAIN, strcat( lbuf, buf ), ch, sbuf, vch, TO_VICT );
         }
         if( social )
         {
            if( vch == victim )
            {
               sprintf( buf, "&w[&%s%s&w] &%s%s", clr, capitalize( channel->name ), clr, socbuf_vict );
               act( AT_PLAIN, buf, ch, NULL, vch, TO_VICT );
            }
            else if( vch != ch )
            {
               sprintf( buf, "&w[&%s%s&w] &%s%s", clr, capitalize( channel->name ), clr, socbuf_other );
               act( AT_PLAIN, buf, ch, vch, victim, TO_THIRD );
            }
         }
         vch->position = position;
         /*
          * Hackish solution to stop that damned "someone chat" bug - Matarael 17.3.2002 
          */
      }
   }
   return;
}

void to_channel( const char *argument, char *xchannel, int level )
{
   MUD_CHANNEL *channel;
   char buf[MAX_STRING_LENGTH];
   DESCRIPTOR_DATA *d;

   if( !first_descriptor || argument[0] == '\0' )
      return;

   if( !( channel = find_channel( xchannel ) ) )
      return;

   if( channel->type != CHAN_LOG )
      return;

   sprintf( buf, "%s: %s\r\n", capitalize( channel->name ), argument );

   for( d = first_descriptor; d; d = d->next )
   {
      CHAR_DATA *vch;

      vch = d->original ? d->original : d->character;

      if( !vch )
         continue;

      if( d->original )
         continue;

      /*
       * This could be coming in higher than the normal level, so check first 
       */
      if( vch->level < level )
         continue;

      if( d->connected == CON_PLAYING && vch->level >= channel->level && hasname( vch->pcdata->chan_listen, channel->name ) )
      {
         set_char_color( AT_LOG, vch );
         send_to_char_color( buf, vch );
      }
   }
   return;
}

bool local_channel_hook( CHAR_DATA * ch, char *command, char *argument )
{
   MUD_CHANNEL *channel;

   if( !( channel = find_channel( command ) ) )
      return FALSE;

   if( ch->level < channel->level )
      return FALSE;

   /*
    * Logs are meant to be seen, not talked on 
    */
   if( channel->type == CHAN_LOG )
      return FALSE;

   if( !IS_NPC( ch ) && !hasname( ch->pcdata->chan_listen, command ) )
   {
      ch_printf( ch, "You are not listening to the %s channel.\r\n", channel->name );
      return TRUE;
   }

   send_tochannel( ch, channel, argument );
   return TRUE;
}

void do_ask( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *vch;
   CHAR_DATA *victim;
   EXT_BV actflags;
#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   argument = one_argument( argument, arg );

   if( arg[0] == '\0' || argument[0] == '\0' )
   {
      send_to_char( "Ask who what?\r\n", ch );
      return;
   }

   if( ( victim = get_char_world( ch, arg ) ) == NULL
       || ( IS_NPC( victim ) && victim->in_room != ch->in_room )
       || ( !NOT_AUTHED( ch ) && NOT_AUTHED( victim ) && !IS_IMMORTAL( ch ) ) )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return;
   }

   actflags = ch->act;
   if( IS_NPC( ch ) )
      xREMOVE_BIT( ch->act, ACT_SECRETIVE );
   for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
   {
      char *sbuf = argument;

      if( vch == ch )
         continue;

      /*
       * Check to see if character is ignoring speaker 
       */
      if( is_ignoring( vch, ch ) )
      {
         /*
          * continue unless speaker is an immortal 
          */
         if( !IS_IMMORTAL( ch ) || get_trust( vch ) > get_trust( ch ) )
            continue;
         else
         {
            set_char_color( AT_IGNORE, vch );
            ch_printf( vch, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name );
         }
      }

#ifndef SCRAMBLE
      if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
      {
         int speakswell = UMIN( knows_language( vch, ch->speaking ), knows_language( ch, ch->speaking ) );
         if( speakswell < 75 )
            sbuf = translate( speakswell, argument, lang_names[speaking] );
      }
#else
      if( !knows_language( vch, ch->speaking ) && ( !IS_NPC( ch ) || ch->speaking != 0 ) )
         sbuf = scramble( argument, ch->speaking );
#endif
      sbuf = drunk_speech( sbuf, ch );

      MOBtrigger = FALSE;
   }
   ch->act = actflags;
   MOBtrigger = FALSE;

   act( AT_SAY, "You ask $N '$t'", ch, drunk_speech( argument, ch ), victim, TO_CHAR );
   act( AT_SAY, "$n asks you '$t'", ch, drunk_speech( argument, ch ), victim, TO_VICT );

   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s: %s", IS_NPC( ch ) ? ch->short_descr : ch->name, argument );
      append_to_file( LOG_FILE, buf );
   }

   mprog_speech_trigger( argument, ch );
   return;
}

void do_say( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *vch;
   EXT_BV actflags;
   char *to_vict, *to_char, *to_char_log;
   int x, arglen, rn;
   struct tm *lcl;
   time_t cur;

   /*
    * Various tables for randomness -- Kratas 
    */
   struct
   {
      char *to_char;
      char *to_vict;
      char *to_char_log;
   }
   state_list[] =
   {
      {
      "say", "says", "said"},
      {
      "state", "states", "stated"}
   };
   struct
   {
      char *to_char;
      char *to_vict;
      char *to_char_log;
   }
   question_list[] =
   {
      {
      "ask", "asks", "asked"},
      {
      "inquire", "inquires", "inquired"}
   };
   struct
   {
      char *to_char;
      char *to_vict;
      char *to_char_log;
   }
   exclaim_list[] =
   {
      {
      "yell", "yells", "yelled"},
      {
      "exclaim", "exclaims", "exclaimed"}
   };

#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   if( argument[0] == '\0' )
   {
      char buffer[MAX_STRING_LENGTH];

      if( IS_NPC( ch ) )
      {
         send_to_char( "Say what?", ch );
         return;
      }

      send_to_char_color( "&cLast things you heard said&W:&w\r\n", ch );

      strcpy( buf, "" );
      for( x = 0; x < 10; x++ )
      {
         if( ch->pcdata->say_history[x] == NULL )
            break;
         sprintf( buffer, " &c%s&w\r\n", ch->pcdata->say_history[x] );
         strcat( buf, buffer );
      }
      strcat( buf, "\r\n" );
      send_to_char( buf, ch );

      return;
   }

   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return;
   }


   actflags = ch->act;
   if( IS_NPC( ch ) )
      xREMOVE_BIT( ch->act, ACT_SECRETIVE );

   arglen = strlen( argument ) - 1;

   while( argument[arglen] == ' ' || argument[arglen] == '\t' )
      --arglen;

   switch ( argument[arglen] )
   {
      case '?':
         rn = rand(  ) % ( sizeof( question_list ) / sizeof( question_list[0] ) );
         to_vict = question_list[rn].to_vict;
         to_char = question_list[rn].to_char;
         to_char_log = question_list[rn].to_char_log;
         break;

      case '!':
         rn = rand(  ) % ( sizeof( exclaim_list ) / sizeof( exclaim_list[0] ) );
         to_vict = exclaim_list[rn].to_vict;
         to_char = exclaim_list[rn].to_char;
         to_char_log = exclaim_list[rn].to_char_log;
         break;

      case '"':
         if( argument[0] == '"' )
         {
            to_vict = "quotes";
            to_char = "quote";
            to_char_log = "quoted";
            break;
         }

      case '.':
         if( argument[arglen - 1] == '.' && argument[arglen - 2] == '.' )
         {
            to_vict = "trails off saying";
            to_char = "trail off saying";
            to_char_log = "trailed off saying";
            break;
         }

      default:
         rn = rand(  ) % ( sizeof( state_list ) / sizeof( state_list[0] ) );
         to_vict = state_list[rn].to_vict;
         to_char = state_list[rn].to_char;
         to_char_log = state_list[rn].to_char_log;
         break;
   }

   for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
   {
      char *sbuf = argument;
      char tmpbuf[MAX_STRING_LENGTH];
      char actbuf[MAX_STRING_LENGTH];

      if( vch == ch )
         continue;

      /*
       * Check to see if character is ignoring speaker 
       */
      if( is_ignoring( vch, ch ) )
      {
         /*
          * continue unless speaker is an immortal 
          */
         if( !IS_IMMORTAL( ch ) || get_trust( vch ) > get_trust( ch ) )
            continue;
         else
         {
            set_char_color( AT_IGNORE, vch );
            ch_printf( vch, "You attempt to ignore %s, but" " are unable to do so.\r\n", ch->name );
         }
      }

#ifndef SCRAMBLE
      if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
      {
         int speakswell = UMIN( knows_language( vch, ch->speaking ),
                                knows_language( ch, ch->speaking ) );

         if( speakswell < 75 )
            sbuf = translate( speakswell, argument, lang_names[speaking] );
      }
#else
      if( !knows_language( vch, ch->speaking ) && ( !IS_NPC( ch ) || ch->speaking != 0 ) )
         sbuf = scramble( argument, ch->speaking );
#endif
      sbuf = drunk_speech( sbuf, ch );

      MOBtrigger = FALSE;

      cur = time( NULL );
      lcl = localtime( &cur );
      sprintf( tmpbuf, "[%-2.2d:%-2.2d] %s %s '%s&c'", lcl->tm_hour, lcl->tm_min, PERS( ch, vch ), to_char_log, sbuf );
      sprintf( actbuf, "$n %s '$t'", to_vict );
      //            act( AT_SAY, "$n says '$t'", ch, sbuf, vch, TO_VICT );

      act( AT_SAY, actbuf, ch, sbuf, vch, TO_VICT );

      if( !IS_NPC( vch ) )
      {
         for( x = 0; x < 10; x++ )
         {
            if( vch->pcdata->say_history[x] == '\0' )
            {
               vch->pcdata->say_history[x] = strdup( tmpbuf );
               break;
            }

            if( x == 9 )
            {
               int i;

               for( i = 1; i < 10; i++ )
               {
                  DISPOSE( vch->pcdata->say_history[i - 1] );
                  vch->pcdata->say_history[i - 1] = strdup( vch->pcdata->say_history[i] );
               }
               DISPOSE( vch->pcdata->say_history[x] );
               vch->pcdata->say_history[x] = strdup( tmpbuf );
            }
         }
      }
   }
   /*
    * MOBtrigger = FALSE;
    * act( AT_SAY, "$n says '$T'", ch, NULL, argument, TO_ROOM );
    */
   ch->act = actflags;
   MOBtrigger = FALSE;

   sprintf( buf, "You %s '$T'", to_char );
   act( AT_SAY, buf, ch, NULL, drunk_speech( argument, ch ), TO_CHAR );

   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s: %s", IS_NPC( ch ) ? ch->short_descr : ch->name, argument );
      append_to_file( LOG_FILE, buf );
   }
   mprog_speech_trigger( argument, ch );
   if( char_died( ch ) )
      return;
   oprog_speech_trigger( argument, ch );
   if( char_died( ch ) )
      return;
   rprog_speech_trigger( argument, ch );
   return;
}

void StoreTell( CHAR_DATA * ch, char *arg )
{
   int x;
   if( !IS_NPC( ch ) )
   {

      for( x = 0; x < 10; x++ )
      {
         if( ch->pcdata->tell_histories[x] == NULL )
         {
            ch->pcdata->tell_histories[x] = str_dup( arg );
            break;
         }
         if( x == 9 )
         {
            int i;

            for( i = 1; i < 10; i++ )
            {
               DISPOSE( ch->pcdata->tell_histories[i - 1] );
               ch->pcdata->tell_histories[i - 1] = str_dup( ch->pcdata->tell_histories[i] );
            }
            ch->pcdata->tell_histories[x] = str_dup( arg );
         }
      }
   }
}

void do_tell( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;
   int position, x;
   CHAR_DATA *switched_victim = NULL;
   struct tm *lol;
   time_t cor;

#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   MOBtrigger = TRUE;

   if( !IS_IMMORTAL( ch ) )
      REMOVE_BIT( ch->deaf, CHANNEL_TELLS );

   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return;
   }

   if( !IS_NPC( ch ) && ( xIS_SET( ch->act, PLR_SILENCE ) || xIS_SET( ch->act, PLR_NO_TELL ) ) )
   {
      send_to_char( "You can't do that.\r\n", ch );
      return;
   }

   argument = one_argument( argument, arg );

   if( arg[0] == '\0' || argument[0] == '\0' )
   {
      if( IS_NPC( ch ) )
      {
         send_to_char( "Tell whom what?\r\n", ch );
         return;
      }
      send_to_char_color( "&cThe Last Tells You Have Recieved&W:&w\r\n", ch );

      buf[0] = '\0';
      for( x = 0; x < 10; x++ )
      {
         if( ch->pcdata->tell_histories[x] == NULL )
            break;
         sprintf( buf + strlen( buf ), "%s\r\n", ch->pcdata->tell_histories[x] );
      }
      strcat( buf, "\r\n" );
      send_to_char( buf, ch );
      return;
   }

   if( ( victim = get_char_world( ch, arg ) ) == NULL
       || ( IS_NPC( victim ) && victim->in_room != ch->in_room )
       || ( !NOT_AUTHED( ch ) && NOT_AUTHED( victim ) && !IS_IMMORTAL( ch ) ) )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( ch == victim )
   {
      send_to_char( "You have a nice little chat with yourself.\r\n", ch );
      return;
   }

   if( NOT_AUTHED( ch ) && !NOT_AUTHED( victim ) && !IS_IMMORTAL( victim ) )
   {
      send_to_char( "They can't hear you because you are not authorized.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && ( victim->switched )
       && ( get_trust( ch ) > LEVEL_AVATAR ) && !IS_AFFECTED( victim->switched, AFF_POSSESS ) )
   {
      send_to_char( "That player is switched.\r\n", ch );
      return;
   }
   else if( !IS_NPC( victim ) && ( victim->switched ) && IS_AFFECTED( victim->switched, AFF_POSSESS ) )
      switched_victim = victim->switched;
   else if( !IS_NPC( victim ) && ( !victim->desc ) )
   {
      send_to_char( "That player is link-dead.\r\n", ch );
      return;
   }
   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_AFK ) )
   {
      send_to_char( "That player is away and may not have received your tell.\r\n", ch );
   }

   if( IS_SET( victim->deaf, CHANNEL_TELLS ) && ( !IS_IMMORTAL( ch ) || ( get_trust( ch ) <= get_trust( victim ) ) ) )
   {
      act( AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim, TO_CHAR );
      return;
   }

   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_SILENCE ) )
      send_to_char( "That player is silenced.  They will receive your message but can not respond.\r\n", ch );

   if( ( !IS_IMMORTAL( ch ) && !IS_AWAKE( victim ) )
       || ( !IS_NPC( victim ) && IS_SET( victim->in_room->room_flags, ROOM_SILENCE ) ) )
   {
      act( AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR );
      return;
   }

   if( victim->desc  /* make sure desc exists first  -Thoric */
       && ( victim->desc->connected == CON_EDITING
            || ( victim->desc->connected >= CON_NOTE_TO
                 && victim->desc->connected <= CON_NOTE_FINISH ) ) && get_trust( ch ) < LEVEL_GOD )
   {
      act( AT_PLAIN, "$E is currently in a writing buffer.  Please try again in a few minutes.", ch, 0, victim, TO_CHAR );
      return;
   }

   /*
    * Check to see if target of tell is ignoring the sender 
    */
   if( is_ignoring( victim, ch ) )
   {
      /*
       * If the sender is an imm then they cannot be ignored 
       */
      if( !IS_IMMORTAL( ch ) || get_trust( victim ) > get_trust( ch ) )
      {
         set_char_color( AT_IGNORE, ch );
         ch_printf( ch, "%s is ignoring you.\r\n", victim->name );
         return;
      }
      else
      {
         set_char_color( AT_IGNORE, victim );
         ch_printf( victim, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name );
      }
   }

   ch->retell = victim;

   if( !IS_NPC( victim ) && IS_IMMORTAL( victim ) && victim->pcdata->tell_history &&
       isalpha( IS_NPC( ch ) ? ch->short_descr[0] : ch->name[0] ) )
   {
      sprintf( buf, "%s told you '%s'\r\n", capitalize( IS_NPC( ch ) ? ch->short_descr : ch->name ), argument );

      /*
       * get lasttell index... assumes names begin with characters 
       */
      victim->pcdata->lt_index = tolower( IS_NPC( ch ) ? ch->short_descr[0] : ch->name[0] ) - 'a';

      /*
       * get rid of old messages 
       */
      if( victim->pcdata->tell_history[victim->pcdata->lt_index] )
         STRFREE( victim->pcdata->tell_history[victim->pcdata->lt_index] );

      /*
       * store the new message 
       */
      victim->pcdata->tell_history[victim->pcdata->lt_index] = STRALLOC( buf );
   }

   if( switched_victim )
      victim = switched_victim;

   /*
    * Bug fix by guppy@wavecomputers.net 
    */
   MOBtrigger = FALSE;

   act( AT_TELL, "You tell $N '$t'", ch, argument, victim, TO_CHAR );
   position = victim->position;
   victim->position = POS_STANDING;
   if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
   {
      int speakswell = UMIN( knows_language( victim, ch->speaking ),
                             knows_language( ch, ch->speaking ) );

      if( speakswell < 85 )
      {
         MOBtrigger = FALSE;
         act( AT_TELL, "$n tells you '$t'", ch, translate( speakswell, argument, lang_names[speaking] ), victim, TO_VICT );
      }
      else
         act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
   }
   else
      act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );

   MOBtrigger = TRUE;

   victim->position = position;
   victim->reply = ch;

   cor = time( NULL );
   lol = localtime( &cor );
   sprintf( buf2, "&R[%-2.2d:%-2.2d] %s told you &r'&R%s&r'&w", lol->tm_hour, lol->tm_min,
            capitalize( IS_NPC( ch ) ? ch->short_descr : ch->name ), argument );

   StoreTell( victim, buf2 );

   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s: %s (tell to) %s.",
               IS_NPC( ch ) ? ch->short_descr : ch->name, argument, IS_NPC( victim ) ? victim->short_descr : victim->name );
      append_to_file( LOG_FILE, buf );
   }


   mprog_speech_trigger( argument, ch );
   return;
}

void do_say_to_char( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   char buf[MAX_STRING_LENGTH];
   CHAR_DATA *vch;
   CHAR_DATA *victim;
   EXT_BV actflags;

#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   argument = one_argument( argument, arg );

   if( arg[0] == '\0' || argument[0] == '\0' )
   {
      send_to_char( "Say what to whom?\r\n", ch );
      return;
   }
   if( ( victim = get_char_room( ch, arg ) ) == NULL
       || ( IS_NPC( victim )
            && victim->in_room != ch->in_room ) || ( !NOT_AUTHED( ch ) && NOT_AUTHED( victim ) && !IS_IMMORTAL( ch ) ) )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( victim == ch )
   {
      send_to_char( "Do you enjoy talking to yourself?\r\n", ch );
      return;
   }

   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return;
   }

   actflags = ch->act;
   if( IS_NPC( ch ) )
      xREMOVE_BIT( ch->act, ACT_SECRETIVE );
   for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
   {
      char *sbuf = argument;

      if( vch == ch )
         continue;

      /*
       * Check to see if character is ignoring speaker 
       */
      if( is_ignoring( vch, ch ) )
      {
         /*
          * continue unless speaker is an immortal 
          */
         if( !IS_IMMORTAL( ch ) || get_trust( vch ) > get_trust( ch ) )
            continue;
         else
         {
            set_char_color( AT_IGNORE, vch );
            ch_printf( vch, "You attempt to ignore %s, but" " are unable to do so.\r\n", ch->name );
         }
      }

#ifndef SCRAMBLE
      if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
      {
         int speakswell = UMIN( knows_language( vch, ch->speaking ),
                                knows_language( ch, ch->speaking ) );
         if( speakswell < 75 )
            sbuf = translate( speakswell, argument, lang_names[speaking] );
      }
#else
      if( !knows_language( vch, ch->speaking ) && ( !IS_NPC( ch ) || ch->speaking != 0 ) )
         sbuf = scramble( argument, ch->speaking );
#endif
      sbuf = drunk_speech( sbuf, ch );

      MOBtrigger = FALSE;

   }
   ch->act = actflags;
   MOBtrigger = FALSE;

   act( AT_SAY, "You say to $N '$t'", ch, drunk_speech( argument, ch ), victim, TO_CHAR );
   act( AT_SAY, "$n says to $N '$t'", ch, drunk_speech( argument, ch ), victim, TO_NOTVICT );
   act( AT_SAY, "$n says to you '$t'", ch, drunk_speech( argument, ch ), victim, TO_VICT );

   /*
    * act( AT_SAY, "$n say$% to $O '$t'", ch, drunk_speech( argument, ch ), victim, TO_ALL ); 
    */
   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s: %s", IS_NPC( ch ) ? ch->short_descr : ch->name, argument );
      append_to_file( LOG_FILE, buf );
   }
   mprog_speech_trigger( argument, ch );
   if( char_died( ch ) )
      return;
   oprog_speech_trigger( argument, ch );
   if( char_died( ch ) )
      return;
   rprog_speech_trigger( argument, ch );
   return;
}

void do_whisper( CHAR_DATA * ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   char buf[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;
   int position;
   int speaking = -1, lang;


#ifndef SCRAMBLE

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   REMOVE_BIT( ch->deaf, CHANNEL_WHISPER );

   argument = one_argument( argument, arg );

   if( arg[0] == '\0' || argument[0] == '\0' )
   {
      send_to_char( "Whisper to whom what?\r\n", ch );
      return;
   }


   if( ( victim = get_char_room( ch, arg ) ) == NULL )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( ch == victim )
   {
      send_to_char( "You have a nice little chat with yourself.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && ( victim->switched ) && !IS_AFFECTED( victim->switched, AFF_POSSESS ) )
   {
      send_to_char( "That player is switched.\r\n", ch );
      return;
   }
   else if( !IS_NPC( victim ) && ( !victim->desc ) )
   {
      send_to_char( "That player is link-dead.\r\n", ch );
      return;
   }
   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_AFK ) )
   {
      send_to_char( "That player is away.\r\n", ch );
      return;
   }
   if( IS_SET( victim->deaf, CHANNEL_WHISPER ) && ( !IS_IMMORTAL( ch ) || ( get_trust( ch ) < get_trust( victim ) ) ) )
   {
      act( AT_PLAIN, "$E has $S whispers turned off.", ch, NULL, victim, TO_CHAR );
      return;
   }
   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_SILENCE ) )
      send_to_char( "That player is silenced.  They will receive your message but can not respond.\r\n", ch );

   if( victim->desc  /* make sure desc exists first  -Thoric */
       && ( victim->desc->connected == CON_EDITING
            || ( victim->desc->connected >= CON_NOTE_TO
                 && victim->desc->connected <= CON_NOTE_FINISH ) ) && get_trust( ch ) < LEVEL_GOD )
   {
      act( AT_PLAIN, "$E is currently in a writing buffer.  Please try again in a few minutes.", ch, 0, victim, TO_CHAR );
      return;
   }

   /*
    * Check to see if target of tell is ignoring the sender 
    */
   if( is_ignoring( victim, ch ) )
   {
      /*
       * If the sender is an imm then they cannot be ignored 
       */
      if( !IS_IMMORTAL( ch ) || get_trust( victim ) > get_trust( ch ) )
      {
         set_char_color( AT_IGNORE, ch );
         ch_printf( ch, "%s is ignoring you.\r\n", victim->name );
         return;
      }
      else
      {
         set_char_color( AT_IGNORE, victim );
         ch_printf( victim, "You attempt to ignore %s, but are unable to do so.\r\n", ch->name );
      }
   }
   /*
    * Bug fix by guppy@wavecomputers.net 
    */
   MOBtrigger = FALSE;

   act( AT_WHISPER, "You whisper to $N '$t'", ch, argument, victim, TO_CHAR );
   position = victim->position;
   victim->position = POS_STANDING;
#ifndef SCRAMBLE
   if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
   {
      int speakswell = UMIN( knows_language( victim, ch->speaking ),
                             knows_language( ch, ch->speaking ) );

      if( speakswell < 85 )
      {
         act( AT_WHISPER, "$n whispers to you '$t'", ch,
              translate( speakswell, argument, lang_names[speaking] ), victim, TO_VICT );
#else
   if( !knows_language( vch, ch->speaking ) && ( !IS_NPC( ch ) || ch->speaking != 0 ) )
   {
      act( AT_WHISPER, "$n whispers to you '$t'", ch,
           translate( speakswell, argument, lang_names[speaking] ), victim, TO_VICT );
#endif

   }
   else
      act( AT_WHISPER, "$n whispers to you '$t'", ch, argument, victim, TO_VICT );
}

else
act( AT_WHISPER, "$n whispers to you '$t'", ch, argument, victim, TO_VICT );

if( !IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   act( AT_WHISPER, "$n whispers something to $N.", ch, argument, victim, TO_NOTVICT );

MOBtrigger = TRUE;

victim->position = position;
if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
{
   sprintf( buf, "%s: %s (whisper to) %s.",
            IS_NPC( ch ) ? ch->short_descr : ch->name, argument, IS_NPC( victim ) ? victim->short_descr : victim->name );
   append_to_file( LOG_FILE, buf );
}


mprog_speech_trigger( argument, ch );
return;
}

void do_reply( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_STRING_LENGTH], buf2[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;
   int position;
#ifndef SCRAMBLE
   int speaking = -1, lang;

   MOBtrigger = TRUE;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   if( !IS_IMMORTAL( ch ) )
      REMOVE_BIT( ch->deaf, CHANNEL_TELLS );

   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return;
   }

   if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_SILENCE ) )
   {
      send_to_char( "Your message didn't get through.\r\n", ch );
      return;
   }

   if( ( victim = ch->reply ) == NULL )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && ( victim->switched ) && can_see( ch, victim ) && ( get_trust( ch ) > LEVEL_AVATAR ) )
   {
      send_to_char( "That player is switched.\r\n", ch );
      return;
   }
   else if( !IS_NPC( victim ) && ( !victim->desc ) )
   {
      send_to_char( "That player is link-dead.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_AFK ) )
   {
      send_to_char( "That player is away, so they may not recieve your message.\r\n", ch );
   }

   if( IS_SET( victim->deaf, CHANNEL_TELLS ) && ( !IS_IMMORTAL( ch ) || ( get_trust( ch ) <= get_trust( victim ) ) ) )
   {
      act( AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim, TO_CHAR );
      return;
   }

   if( ( !IS_IMMORTAL( ch ) && !IS_AWAKE( victim ) )
       || ( !IS_NPC( victim ) && IS_SET( victim->in_room->room_flags, ROOM_SILENCE ) ) )
   {
      act( AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR );
      return;
   }

   if( victim->desc  /* make sure desc exists first  -Thoric */
       && ( victim->desc->connected == CON_EDITING
            || ( victim->desc->connected >= CON_NOTE_TO
                 && victim->desc->connected <= CON_NOTE_FINISH ) ) && get_trust( ch ) < LEVEL_GOD )
   {
      act( AT_PLAIN, "$E is currently in a writing buffer.  Please try again in a few minutes.", ch, 0, victim, TO_CHAR );
      return;
   }

   /*
    * Check to see if the receiver is ignoring the sender 
    */
   if( is_ignoring( victim, ch ) )
   {
      /*
       * If the sender is an imm they cannot be ignored 
       */
      if( !IS_IMMORTAL( ch ) || get_trust( victim ) > get_trust( ch ) )
      {
         set_char_color( AT_IGNORE, ch );
         ch_printf( ch, "%s is ignoring you.\r\n", victim->name );
         return;
      }
      else
      {
         set_char_color( AT_IGNORE, victim );
         ch_printf( victim, "You attempt to ignore %s, but " "are unable to do so.\r\n", ch->name );
      }
   }

   /*
    * Bug fix by guppy@wavecomputers.net 
    */
   MOBtrigger = FALSE;

   act( AT_TELL, "You tell $N '$t'", ch, argument, victim, TO_CHAR );

   position = victim->position;
   victim->position = POS_STANDING;
#ifndef SCRAMBLE
   if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
   {
      int speakswell = UMIN( knows_language( victim, ch->speaking ),
                             knows_language( ch, ch->speaking ) );

      if( speakswell < 85 )
      {
         MOBtrigger = FALSE;
         act( AT_TELL, "$n tells you '$t'", ch, translate( speakswell, argument, lang_names[speaking] ), victim, TO_VICT );
      }
      else
         act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
   }
   else
      act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
#else
   if( knows_language( victim, ch->speaking ) || ( IS_NPC( ch ) && !ch->speaking ) )
      act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
   else
      act( AT_TELL, "$n tells you '$t'", ch, scramble( argument, ch->speaking ), victim, TO_VICT );
#endif

   MOBtrigger = TRUE;

   mprog_speech_trigger( argument, ch );

   sprintf( buf2, "&R%s told you &r'&R%s&r'&w", capitalize( IS_NPC( ch ) ? ch->short_descr : ch->name ), argument );

   StoreTell( victim, buf2 );

   victim->position = position;
   victim->reply = ch;
   ch->retell = victim;
   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s: %s (reply to) %s.",
               IS_NPC( ch ) ? ch->short_descr : ch->name, argument, IS_NPC( victim ) ? victim->short_descr : victim->name );
      append_to_file( LOG_FILE, buf );
   }

   if( !IS_NPC( victim ) && IS_IMMORTAL( victim ) && victim->pcdata->tell_history &&
       isalpha( IS_NPC( ch ) ? ch->short_descr[0] : ch->name[0] ) )
   {
      sprintf( buf, "%s told you '%s'\r\n", capitalize( IS_NPC( ch ) ? ch->short_descr : ch->name ), argument );

      /*
       * get lasttell index... assumes names begin with characters 
       */
      victim->pcdata->lt_index = tolower( IS_NPC( ch ) ? ch->short_descr[0] : ch->name[0] ) - 'a';

      /*
       * get rid of old messages 
       */
      if( victim->pcdata->tell_history[victim->pcdata->lt_index] )
         STRFREE( victim->pcdata->tell_history[victim->pcdata->lt_index] );

      /*
       * store the new message 
       */
      victim->pcdata->tell_history[victim->pcdata->lt_index] = STRALLOC( buf );
   }

   return;
}

void do_retell( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;
   int position;
   CHAR_DATA *switched_victim = NULL;
#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   if( !IS_IMMORTAL( ch ) )
      REMOVE_BIT( ch->deaf, CHANNEL_TELLS );
   if( IS_SET( ch->in_room->room_flags, ROOM_SILENCE ) )
   {
      send_to_char( "You can't do that here.\r\n", ch );
      return;
   }

   if( !IS_NPC( ch ) && ( xIS_SET( ch->act, PLR_SILENCE ) || xIS_SET( ch->act, PLR_NO_TELL ) ) )
   {
      send_to_char( "You can't do that.\r\n", ch );
      return;
   }

   if( argument[0] == '\0' )
   {
      ch_printf( ch, "What message do you wish to send?\r\n" );
      return;
   }

   victim = ch->retell;

   if( !victim )
   {
      send_to_char( "They aren't here.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && ( victim->switched ) &&
       ( get_trust( ch ) > LEVEL_AVATAR ) && !IS_AFFECTED( victim->switched, AFF_POSSESS ) )
   {
      send_to_char( "That player is switched.\r\n", ch );
      return;
   }
   else if( !IS_NPC( victim ) && ( victim->switched ) && IS_AFFECTED( victim->switched, AFF_POSSESS ) )
   {
      switched_victim = victim->switched;
   }
   else if( !IS_NPC( victim ) && ( !victim->desc ) )
   {
      send_to_char( "That player is link-dead.\r\n", ch );
      return;
   }

   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_AFK ) )
   {
      send_to_char( "That player is away.\r\n", ch );
      return;
   }

   if( IS_SET( victim->deaf, CHANNEL_TELLS ) && ( !IS_IMMORTAL( ch ) || ( get_trust( ch ) < get_trust( victim ) ) ) )
   {
      act( AT_PLAIN, "$E has $S tells turned off.", ch, NULL, victim, TO_CHAR );
      return;
   }

   if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_SILENCE ) )
      send_to_char( "That player is silenced. They will receive your message, but can not respond.\r\n", ch );

   if( ( !IS_IMMORTAL( ch ) && !IS_AWAKE( victim ) ) ||
       ( !IS_NPC( victim ) && IS_SET( victim->in_room->room_flags, ROOM_SILENCE ) ) )
   {
      act( AT_PLAIN, "$E can't hear you.", ch, 0, victim, TO_CHAR );
      return;
   }

   if( victim->desc
       && ( victim->desc->connected == CON_EDITING
            || ( victim->desc->connected >= CON_NOTE_TO
                 && victim->desc->connected <= CON_NOTE_FINISH ) ) && get_trust( ch ) < LEVEL_GOD )
   {
      act( AT_PLAIN, "$E is currently in a writing buffer. Please " "try again in a few minutes.", ch, 0, victim, TO_CHAR );
      return;
   }

   /*
    * check to see if the target is ignoring the sender 
    */
   if( is_ignoring( victim, ch ) )
   {
      /*
       * if the sender is an imm then they cannot be ignored 
       */
      if( !IS_IMMORTAL( ch ) || get_trust( victim ) > get_trust( ch ) )
      {
         set_char_color( AT_IGNORE, ch );
         ch_printf( ch, "%s is ignoring you.\r\n", victim->name );
         return;
      }
      else
      {
         set_char_color( AT_IGNORE, victim );
         ch_printf( victim, "You attempy to ignore %s, but " "are unable to do so.\r\n", ch->name );
      }
   }

   /*
    * store tell history for victim 
    */
   if( !IS_NPC( victim ) && IS_IMMORTAL( victim ) && victim->pcdata->tell_history &&
       isalpha( IS_NPC( ch ) ? ch->short_descr[0] : ch->name[0] ) )
   {
      sprintf( buf, "%s told you '%s'\r\n", capitalize( IS_NPC( ch ) ? ch->short_descr : ch->name ), argument );

      /*
       * get lasttel index... assumes names begin with chars 
       */
      victim->pcdata->lt_index = tolower( IS_NPC( ch ) ? ch->short_descr[0] : ch->name[0] ) - 'a';

      /*
       * get rid of old messages 
       */
      if( victim->pcdata->tell_history[victim->pcdata->lt_index] )
         STRFREE( victim->pcdata->tell_history[victim->pcdata->lt_index] );

      /*
       * store the new messagec 
       */
      victim->pcdata->tell_history[victim->pcdata->lt_index] = STRALLOC( buf );
   }

   if( switched_victim )
      victim = switched_victim;

   /*
    * Bug fix by guppy@wavecomputers.net 
    */
   MOBtrigger = FALSE;

   act( AT_TELL, "You tell $N '$t'", ch, argument, victim, TO_CHAR );
   position = victim->position;
   victim->position = POS_STANDING;
#ifndef SCRAMBLE
   if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
   {
      int speakswell = UMIN( knows_language( victim, ch->speaking ),
                             knows_language( ch, ch->speaking ) );

      if( speakswell < 85 )
      {
         MOBtrigger = FALSE;
         act( AT_TELL, "$n tells you '$t'", ch, translate( speakswell, argument, lang_names[speaking] ), victim, TO_VICT );
      }
      else
         act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
   }
   else
      act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
#else
   if( knows_language( victim, ch->speaking ) || ( IS_NPC( ch ) && !ch->speaking ) )
   {
      act( AT_TELL, "$n tells you '$t'", ch, argument, victim, TO_VICT );
   }
   else
   {
      act( AT_TELL, "$n tells you '$t'", ch, scramble( argument, ch->speaking ), victim, TO_VICT );
   }
#endif
   victim->position = position;
   victim->reply = ch;

   MOBtrigger = TRUE;

   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s: %s (retell to) %s.",
               IS_NPC( ch ) ? ch->short_descr : ch->name, argument, IS_NPC( victim ) ? victim->short_descr : victim->name );
      append_to_file( LOG_FILE, buf );
   }


   mprog_speech_trigger( argument, ch );
   return;
}

void do_repeat( CHAR_DATA * ch, char *argument )
{
   int tindex;

   if( IS_NPC( ch ) || !IS_IMMORTAL( ch ) || !ch->pcdata->tell_history )
   {
      no_find( ch );
      return;
   }

   if( argument[0] == '\0' )
   {
      tindex = ch->pcdata->lt_index;
   }
   else if( isalpha( argument[0] ) && argument[1] == '\0' )
   {
      tindex = tolower( argument[0] ) - 'a';
   }
   else
   {
      send_to_char( "You may only index your tell history using a single letter.\r\n", ch );
      return;
   }

   if( ch->pcdata->tell_history[tindex] )
   {
      set_char_color( AT_TELL, ch );
      send_to_char( ch->pcdata->tell_history[tindex], ch );
   }
   else
   {
      send_to_char( "No one like that has sent you a tell.\r\n", ch );
   }
   return;
}

void do_emote( CHAR_DATA * ch, char *argument )
{
   char buf[MAX_STRING_LENGTH];
   char *plast;
   CHAR_DATA *vch;
   EXT_BV actflags;
#ifndef SCRAMBLE
   int speaking = -1, lang;

   for( lang = 0; lang_array[lang] != LANG_UNKNOWN; lang++ )
      if( ch->speaking & lang_array[lang] )
      {
         speaking = lang;
         break;
      }
#endif

   if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_NO_EMOTE ) )
   {
      send_to_char( "You can't show your emotions.\r\n", ch );
      return;
   }

   if( argument[0] == '\0' )
   {
      send_to_char( "Emote what?\r\n", ch );
      return;
   }

   actflags = ch->act;
   if( IS_NPC( ch ) )
      xREMOVE_BIT( ch->act, ACT_SECRETIVE );
   for( plast = argument; *plast != '\0'; plast++ )
      ;

   strcpy( buf, argument );
   if( isalpha( plast[-1] ) )
      strcat( buf, "." );
   for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
   {
      char *sbuf = buf;

      /*
       * Check to see if character is ignoring emoter 
       */
      if( is_ignoring( vch, ch ) )
      {
         /*
          * continue unless emoter is an immortal 
          */
         if( !IS_IMMORTAL( ch ) || get_trust( vch ) > get_trust( ch ) )
            continue;
         else
         {
            set_char_color( AT_IGNORE, vch );
            ch_printf( vch, "You attempt to ignore %s, but" " are unable to do so.\r\n", ch->name );
         }
      }
#ifndef SCRAMBLE
      if( speaking != -1 && ( !IS_NPC( ch ) || ch->speaking ) )
      {
         int speakswell = UMIN( knows_language( vch, ch->speaking ),
                                knows_language( ch, ch->speaking ) );

         if( speakswell < 85 )
            sbuf = translate( speakswell, argument, lang_names[speaking] );
      }
#else
      if( !knows_language( vch, ch->speaking ) && ( !IS_NPC( ch ) && ch->speaking != 0 ) )
         sbuf = scramble( buf, ch->speaking );
#endif
      MOBtrigger = FALSE;
      act( AT_SOCIAL, "$n $t", ch, sbuf, vch, ( vch == ch ? TO_CHAR : TO_VICT ) );
   }
   /*
    * MOBtrigger = FALSE;
    * act( AT_ACTION, "$n $T", ch, NULL, buf, TO_ROOM );
    * MOBtrigger = FALSE;
    * act( AT_ACTION, "$n $T", ch, NULL, buf, TO_CHAR );
    */
   ch->act = actflags;
   if( IS_SET( ch->in_room->room_flags, ROOM_LOGSPEECH ) )
   {
      sprintf( buf, "%s %s (emote)", IS_NPC( ch ) ? ch->short_descr : ch->name, argument );
      append_to_file( LOG_FILE, buf );
   }
   return;
}