LOP/
LOP/area/
LOP/boards/
LOP/channels/
LOP/clans/
LOP/classes/
LOP/color/
LOP/councils/
LOP/deity/
LOP/races/
LOP/src/specials/
/****************************************************************************
 *                   ^     +----- |  / ^     ^ |     | +-\                  *
 *                  / \    |      | /  |\   /| |     | |  \                 *
 *                 /   \   +---   |<   | \ / | |     | |  |                 *
 *                /-----\  |      | \  |  v  | |     | |  /                 *
 *               /       \ |      |  \ |     | +-----+ +-/                  *
 ****************************************************************************
 * AFKMud Copyright 1997-2005 by Roger Libiez (Samson),                     *
 * Levi Beckerson (Whir), Michael Ward (Tarl), Erik Wolfe (Dwip),           *
 * Cameron Carroll (Cam), Cyberfox, Karangi, Rathian, Raine, and Adjani.    *
 * All Rights Reserved.                                                     *
 * Registered with the United States Copyright Office. TX 5-877-286         *
 *                                                                          *
 * External contributions from Xorith, Quixadhal, Zarius, and many others.  *
 *                                                                          *
 * 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.                                   *
 ****************************************************************************
 *               Color Module -- Allow user customizable Colors.            *
 *                                   --Matthew                              *
 *                      Enhanced ANSI parser by Samson                      *
 ****************************************************************************/

/*
* The following instructions assume you know at least a little bit about
* coding.  I firmly believe that if you can't code (at least a little bit),
* you don't belong running a mud.  So, with that in mind, I don't hold your
* hand through these instructions.
*
* You may use this code provided that:
*
*     1)  You understand that the authors _DO NOT_ support this code
*         Any help you need must be obtained from other sources.  The
*         authors will ignore any and all requests for help.
*     2)  You will mention the authors if someone asks about the code.
*         You won't take credit for the code, but you can take credit
*         for any enhancements you make.
*     3)  This message remains intact.
*
* If you would like to find out how to send the authors large sums of money,
* you may e-mail the following address:
*
* Matthew Bafford & Christopher Wigginton
* wiggy@mudservices.com
*/

/*
 * To add new color types:
 *
 * 1.  Edit color.h, and:
 *     1.  Add a new AT_ define.
 *     2.  Increment MAX_COLORS by however many AT_'s you added.
 * 2.  Edit color.c and:
 *     1.  Add the name(s) for your new color(s) to the end of the pc_displays array.
 *     2.  Add the default color(s) to the end of the default_set array.
 */
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <dirent.h>
#include "h/mud.h"

char *const pc_displays[MAX_COLORS] =
{
   "black",      "dred",       "dgreen",      "orange",
   "dblue",      "purple",     "cyan",        "grey",
   "dgrey",      "red",        "green",       "yellow",
   "blue",       "pink",       "lblue",       "white",
   "blink",      "bdred",      "bdgreen",     "borange",
   "bdblue",     "bpurple",    "bcyan",       "bgrey",
   "bdgrey",     "bred",       "bgreen",      "byellow",
   "bblue",      "bpink",      "blblue",      "bwhite",
   /* Above are the basic 0 - 31 that should always be the same */
   "plain",      "action",     "hurt",        "falling",
   "danger",     "magic",      "skill",       "social",
   "consider",   "report",     "poison",      "dying",
   "dead",       "carnage",    "damage",      "flee",
   "hit",        "hitme",      "say",         "rmname",
   "rmdesc",     "objects",    "people",      "bye",
   "gold",       "gtells",     "hungry",      "thirsty",
   "fire",       "sober",      "wearoff",     "exits",
   "reset",      "log",        "diemsg",      "chat",
   "yell",       "tell",       "immort",      "wartalk",
   "muse",       "think",      "racetalk",    "clantalk",
   "nation",     "ignore",     "whisper",     "shout",
   "auction",    "intermud",   "divider",     "morph",
   "help",       "help2",      "board",       "board2",
   "note",       "note2",      "score",       "score2",
   "who",        "who2",       "male",        "female",
   "hint",       "hint2",      "prac",        "prac2",
   "prac3",      "group",      "group2",      "sudoku",
   "sudoku2",    "hscore",     "hscore2",     "music",
   "council",    "quest",      "classtalk",   "traffic"
};

/* All defaults are set to Alsherok default scheme, if you don't 
like it, change it around to suite your own needs - Samson */
const short default_set[MAX_COLORS] =
{
   AT_BLACK,        AT_BLOOD,         AT_DGREEN,        AT_ORANGE,
   AT_DBLUE,        AT_PURPLE,        AT_CYAN,          AT_GREY,
   AT_DGREY,        AT_RED,           AT_GREEN,         AT_YELLOW,
   AT_BLUE,         AT_PINK,          AT_LBLUE,         AT_WHITE,
   AT_BLACK_BLINK,  AT_BLOOD_BLINK,   AT_DGREEN_BLINK,  AT_ORANGE_BLINK,
   AT_DBLUE_BLINK,  AT_PURPLE_BLINK,  AT_CYAN_BLINK,    AT_GREY_BLINK,
   AT_DGREY_BLINK,  AT_RED_BLINK,     AT_GREEN_BLINK,   AT_YELLOW_BLINK,
   AT_BLUE_BLINK,   AT_PINK_BLINK,    AT_LBLUE_BLINK,   AT_WHITE_BLINK,
   /* Above are the basic 0 - 31 that should always be the same */
   AT_GREY,         AT_PURPLE,        AT_RED,           AT_RED,
   AT_YELLOW,       AT_LBLUE,         AT_WHITE,         AT_GREEN,
   AT_LBLUE,        AT_LBLUE,         AT_RED,           AT_RED,
   AT_RED,          AT_RED,           AT_RED,           AT_GREEN,
   AT_LBLUE,        AT_BLOOD,         AT_LBLUE,         AT_GREY,
   AT_BLUE,         AT_GREY,          AT_DBLUE,         AT_GREY,
   AT_RED,          AT_GREY,          AT_BLUE,          AT_PINK,
   AT_GREY,         AT_GREY,          AT_YELLOW,        AT_GREEN,
   AT_GREY,         AT_ORANGE,        AT_BLUE,          AT_RED,
   AT_GREY,         AT_GREY,          AT_GREEN,         AT_DGREEN,
   AT_DGREEN,       AT_ORANGE,        AT_GREY,          AT_RED,
   AT_GREY,         AT_DGREEN,        AT_RED,           AT_BLUE,
   AT_RED,          AT_CYAN,          AT_YELLOW,        AT_PINK,
   AT_DGREEN,       AT_WHITE,         AT_PINK,          AT_WHITE,
   AT_BLUE,         AT_BLUE,          AT_BLUE,          AT_GREEN,
   AT_GREY,         AT_GREEN,         AT_LBLUE,         AT_PURPLE,
   AT_GREY,         AT_CYAN,          AT_BLUE,          AT_CYAN,
   AT_RED,          AT_DGREEN,        AT_GREEN,         AT_YELLOW,
   AT_GREEN,        AT_YELLOW,        AT_LBLUE,         AT_DGREY,
   AT_GREEN,        AT_RED,           AT_LBLUE,         AT_GREEN
};

char *const valid_color[] =
{
   "black",    "dred",      "dgreen",    "orange",
   "dblue",    "purple",    "cyan",      "grey",
   "dgrey",    "red",       "green",     "yellow",
   "blue",     "pink",      "lblue",     "white",
   "blink",    "bdred",     "bdgreen",   "bdorange",
   "bdblue",   "bpurple",   "bcyan",     "bgrey",
   "bdgrey",   "bred",      "bgreen",    "byellow",
   "bblue",    "bpink",     "blblue",    "bwhite",
   "\0"
};

void show_colorthemes( CHAR_DATA *ch )
{
   DIR *dp;
   struct dirent *dentry;
   int count = 0, col = 0;

   send_to_pager( "&W*********************************[ &wTHEMES &W]**********************************\r\n", ch );

   dp = opendir( COLOR_DIR );
   dentry = readdir( dp );
   while( dentry )
   {
      /* Added by Tarl 3 Dec 02 because we are now using CVS */
      if( !str_cmp( dentry->d_name, "CVS" ) )
      {
         dentry = readdir( dp );
         continue;
      }
      if( dentry->d_name[0] != '.' )
      {
         ++count;
         pager_printf( ch, "%s%-15.15s", color_str( AT_PLAIN, ch ), dentry->d_name );
         if( ++col % 4 == 0 )
            send_to_pager( "\r\n", ch );
      }
      dentry = readdir( dp );
   }
   closedir( dp );

   if( count == 0 )
      send_to_pager( "No themes defined yet.\r\n", ch );

   if( col % 4 != 0 )
      send_to_pager( "\r\n", ch );
   return;
}

void show_colors( CHAR_DATA *ch )
{
   short count;

   send_to_pager( "&BUsage: color ansitest\r\n", ch );
   send_to_pager( "&BUsage: color [color type] [color] | default\r\n", ch );
   send_to_pager( "&BUsage: color _reset_ (Resets all colors to default set)\r\n", ch );
   send_to_pager( "&BUsage: color _all_ [color] (Sets all color types to [color])\r\n", ch );
   send_to_pager( "&BUsage: color theme [name] (Sets all color types to a defined theme)\r\n", ch );

   send_to_pager( "&W*********************************[ &wCOLORS &W]**********************************\r\n", ch );
   for( count = 0; count < 32; ++count )
   {
      if( ( count % 8 ) == 0 && count != 0 )
      {
         send_to_pager( "\r\n", ch );
      }
      pager_printf( ch, "%s%-10s%s", color_str( count, ch ), pc_displays[count], ANSI_RESET );
   }

   send_to_pager( "\r\n&W*******************************[ &wCOLOR TYPES &W]*******************************\r\n", ch );
   for( count = 32; count < MAX_COLORS; ++count )
   {
      if( ( count % 8 ) == 0 && count != 32 )
      {
         send_to_pager( "\r\n", ch );
      }
      pager_printf( ch, "%s%-10s%s", color_str( count, ch ), pc_displays[count], ANSI_RESET );
   }
   send_to_pager( "\r\n", ch );

   show_colorthemes( ch );
}

void reset_colors( CHAR_DATA *ch )
{
   int x;
   char filename[256];
   FILE *fp;
   int max_colors = 0;

   if( is_npc( ch ) )
   {
      log_printf( "%s: Attempting to reset NPC colors: %s", __FUNCTION__, ch->short_descr );
      return;
   }

   /* Set up the defaults for everyone incase the files dont have all that they should */
   memcpy( &ch->colors, &default_set, sizeof( default_set ) );

   snprintf( filename, sizeof( filename ), "%s%s", COLOR_DIR, "default" );
   if( !( fp = fopen( filename, "r" ) ) )
      return;

   while( !feof( fp ) )
   {
      char *word = fread_word( fp );
      if( !str_cmp( word, "MaxColors" ) )
      {
         max_colors = fread_number( fp );
         continue;
      }
      if( !str_cmp( word, "Colors" ) )
      {
         for( x = 0; x < max_colors; ++x )
         {
            if( x < MAX_COLORS )
               ch->colors[x] = fread_number( fp );
            else
               fread_number( fp );
         }
         continue;
      }
      if( !str_cmp( word, "End" ) )
      {
         fclose( fp );
         fp = NULL;
         return;
      }
   }
   fclose( fp );
   fp = NULL;
}

void do_color( CHAR_DATA *ch, char *argument )
{
   bool dMatch, cMatch;
   short count = 0, y = 0;
   int x;
   char arg[MIL], arg2[MIL];
   char log_buf[MSL];

   dMatch = false;
   cMatch = false;

   if( is_npc( ch ) )
   {
      send_to_pager( "Only PC's can change colors.\r\n", ch );
      return;
   }

   if( !argument || argument[0] == '\0' )
   {
      show_colors( ch );
      return;
   }

   argument = one_argument( argument, arg );

   if( !str_cmp( arg, "savetheme" ) && is_immortal( ch ) )
   {
      FILE *fp;
      char filename[256];

      if( !argument || argument[0] == '\0' )
      {
         send_to_char( "You must specify a name for this theme to save it.\r\n", ch );
         return;
      }
      if( strstr( argument, ".." ) || strstr( argument, "/" ) || strstr( argument, "\\" ) )
      {
         send_to_char( "Invalid theme name.\r\n", ch );
         return;
      }
      snprintf( filename, sizeof( filename ), "%s%s", COLOR_DIR, argument );
      if( !( fp = fopen( filename, "w" ) ) )
      {
         ch_printf( ch, "Unable to write to color file %s\r\n", filename );
         return;
      }
      fprintf( fp, "%s", "#COLORTHEME\n" );
      fprintf( fp, "Name         %s~\n", argument );
      fprintf( fp, "MaxColors    %d\n", MAX_COLORS );
      fprintf( fp, "%s", "Colors      " );
      for( x = 0; x < MAX_COLORS; ++x )
         fprintf( fp, " %d", ch->colors[x] );
      fprintf( fp, "%s", "\nEnd\n" );
      fclose( fp );
      fp = NULL;
      ch_printf( ch, "Color theme %s saved.\r\n", argument );
      return;
   }

   if( !str_cmp( arg, "theme" ) )
   {
      FILE *fp;
      char filename[256];
      int max_colors = 0;

      if( !argument || argument[0] == '\0' )
      {
         show_colorthemes( ch );
         return;
      }

      if( strstr( argument, ".." ) || strstr( argument, "/" ) || strstr( argument, "\\" ) )
      {
         send_to_char( "Invalid theme.\r\n", ch );
         return;
      }

      snprintf( filename, sizeof( filename ), "%s%s", COLOR_DIR, argument );
      if( !( fp = fopen( filename, "r" ) ) )
      {
         ch_printf( ch, "There is no theme called %s.\r\n", argument );
         return;
      }

      while( !feof( fp ) )
      {
         char *word = fread_word( fp );
         if( !str_cmp( word, "MaxColors" ) )
         {
            max_colors = fread_number( fp );
            continue;
         }
         if( !str_cmp( word, "Colors" ) )
         {
            for( x = 0; x < max_colors; ++x )
            {
               if( x < MAX_COLORS )
                  ch->colors[x] = fread_number( fp );
               else
                  fread_number( fp );
            }
            if( max_colors < MAX_COLORS )
            {
               for( x = max_colors; x < MAX_COLORS; ++x )
                  ch->colors[x] = default_set[x];
            }
            continue;
         }
         if( !str_cmp( word, "End" ) )
         {
            fclose( fp );
            fp = NULL;
            ch_printf( ch, "Color theme has been changed to %s.\r\n", argument );
            save_char_obj( ch );
            return;
         }
      }
      fclose( fp );
      fp = NULL;
      ch_printf( ch, "An error occured while trying to set color theme %s.\r\n", argument );
      return;
   }

   if( !str_cmp( arg, "ansitest" ) )
   {
      write_to_buffer( ch->desc, ANSI_RESET, 0 );
      write_to_buffer( ch->desc, "Normal Colors:\r\n", 0 );

      snprintf( log_buf, sizeof( log_buf ), "%sBlack%s  %sDRed%s  %sDGreen%s  %sOrange%s  %sDBlue%s  %sPurple%s  %sCyan%s   %sGrey%s\r\n",
         ANSI_BLACK, ANSI_RESET, ANSI_DRED, ANSI_RESET, ANSI_DGREEN, ANSI_RESET, ANSI_ORANGE, ANSI_RESET, ANSI_DBLUE,
         ANSI_RESET, ANSI_PURPLE, ANSI_RESET, ANSI_CYAN, ANSI_RESET, ANSI_GREY, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );

      snprintf( log_buf, sizeof( log_buf ), "%sDGrey%s  %sRed%s   %sGreen%s   %sYellow%s  %sBlue%s   %sPink%s    %sLBlue%s  %sWhite%s\r\n",
         ANSI_DGREY, ANSI_RESET, ANSI_RED, ANSI_RESET, ANSI_GREEN, ANSI_RESET, ANSI_YELLOW, ANSI_RESET, ANSI_BLUE,
         ANSI_RESET, ANSI_PINK, ANSI_RESET, ANSI_LBLUE, ANSI_RESET, ANSI_WHITE, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );

      write_to_buffer( ch->desc, ANSI_RESET, 0 );
      write_to_buffer( ch->desc, "Blinking Colors:\r\n", 0 );

      snprintf( log_buf, sizeof( log_buf ), "%sBlack%s  %sDRed%s  %sDGreen%s  %sOrange%s  %sDBlue%s  %sPurple%s  %sCyan%s   %sGrey%s\r\n",
         BLINK_BLACK, ANSI_RESET, BLINK_DRED, ANSI_RESET, BLINK_DGREEN, ANSI_RESET, BLINK_ORANGE, ANSI_RESET,
         BLINK_DBLUE, ANSI_RESET, BLINK_PURPLE, ANSI_RESET, BLINK_CYAN, ANSI_RESET, BLINK_GREY, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );

      snprintf( log_buf, sizeof( log_buf ), "%sDGrey%s  %sRed%s   %sGreen%s   %sYellow%s  %sBlue%s   %sPink%s    %sLBlue%s  %sWhite%s\r\n",
         BLINK_DGREY, ANSI_RESET, BLINK_RED, ANSI_RESET, BLINK_GREEN, ANSI_RESET, BLINK_YELLOW, ANSI_RESET,
         BLINK_BLUE, ANSI_RESET, BLINK_PINK, ANSI_RESET, BLINK_LBLUE, ANSI_RESET, BLINK_WHITE, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );

      write_to_buffer( ch->desc, ANSI_RESET, 0 );
      write_to_buffer( ch->desc, "Background Colors:\r\n", 0 );

      snprintf( log_buf, sizeof( log_buf ), "%s%sBlack%s  %s%sDRed%s  %s%sDGreen%s  %s%sOrange%s  %s%sDBlue%s  %s%sPurple%s  %s%sCyan%s   %s%sGrey%s\r\n",
         ANSI_BLACK,  BACK_BLACK,  ANSI_RESET, ANSI_DRED,   BACK_DRED,   ANSI_RESET,
         ANSI_DGREEN, BACK_DGREEN, ANSI_RESET, ANSI_ORANGE, BACK_ORANGE, ANSI_RESET,
         ANSI_DBLUE,  BACK_DBLUE,  ANSI_RESET, ANSI_PURPLE, BACK_PURPLE, ANSI_RESET,
         ANSI_CYAN,   BACK_CYAN,   ANSI_RESET, ANSI_GREY,   BACK_GREY,   ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );

      snprintf( log_buf, sizeof( log_buf ), "%s%sDGrey%s  %s%sRed%s   %s%sGreen%s   %s%sYellow%s  %s%sBlue%s   %s%sPink%s    %s%sLBlue%s  %s%sWhite%s\r\n",
         ANSI_DGREY, BACK_DGREY, ANSI_RESET, ANSI_RED,    BACK_RED,    ANSI_RESET,
         ANSI_GREEN, BACK_GREEN, ANSI_RESET, ANSI_YELLOW, BACK_YELLOW, ANSI_RESET,
         ANSI_BLUE,  BACK_BLUE,  ANSI_RESET, ANSI_PINK,   BACK_PINK,   ANSI_RESET,
         ANSI_LBLUE, BACK_LBLUE, ANSI_RESET, ANSI_WHITE,  BACK_WHITE,  ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );

      write_to_buffer( ch->desc, ANSI_RESET, 0 );
      write_to_buffer( ch->desc, "Other Things:\r\n", 0 );

      snprintf( log_buf, sizeof( log_buf ), "%s%sItalics%s\r\n", ANSI_GREY, ANSI_ITALIC, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );
      snprintf( log_buf, sizeof( log_buf ), "%sStrikeout%s\r\n", ANSI_STRIKEOUT, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );
      snprintf( log_buf, sizeof( log_buf ), "%sUnderline%s\r\n", ANSI_UNDERLINE, ANSI_RESET );
      write_to_buffer( ch->desc, log_buf, 0 );
      return;
   }

   if( !str_prefix( arg, "_reset_" ) )
   {
      reset_colors( ch );
      send_to_pager( "All color types reset to default colors.\r\n", ch );
      return;
   }

   argument = one_argument( argument, arg2 );

   if( !arg || arg[0] == '\0' )
   {
      send_to_char( "Change which color type?\r\n", ch );
      return;
   }

   if( !arg || arg[0] == '\0' || !arg2 || arg2[0] == '\0' )
      cMatch = false;
   else if( !str_prefix( arg, "_all_" ) )
   {
      dMatch = true;
      count = -1;

      /* search for a valid color setting */
      for( y = 0; y < 32; y++ )
      {
         if( !str_cmp( arg2, valid_color[y] ) )
         {
            cMatch = true;
            break;
         }
      }
   }
   else
   {
      /* search for the display type and str_cmp */
      for( count = 32; count < MAX_COLORS; count++ )
      {
         if( !str_prefix( arg, pc_displays[count] ) )
         {
            dMatch = true;
            break;
         }
      }

      if( !dMatch )
      {
         ch_printf( ch, "%s is an invalid color type.\r\n", arg );
         send_to_char( "Type color with no arguments to see available options.\r\n", ch );
         return;
      }

      if( !str_cmp( arg2, "default" ) )
      {
         ch->colors[count] = default_set[count];
         ch_printf( ch, "Display %s set back to default.\r\n", pc_displays[count] );
         return;
      }

      /* search for a valid color setting */
      for( y = 0; y < 32; y++ )
      {
         if( !str_cmp( arg2, valid_color[y] ) )
         {
            cMatch = true;
            break;
         }
      }
   }

   if( !cMatch )
   {
      if( arg[0] )
         ch_printf( ch, "Invalid color for type %s.\n", arg );
      else
         send_to_pager( "Invalid color.\r\n", ch );

      send_to_pager( "Choices are:\r\n", ch );

      for( count = 0; count < 32; count++ )
      {
         if( count % 8 == 0 && count != 0 )
            send_to_pager( "\r\n", ch );

         pager_printf( ch, "%-10s", valid_color[count] );
      }
      pager_printf( ch, "\r\n%-10s\r\n", "default" );
      return;
   }
   else
      pager_printf( ch, "Color type %s set to color %s.\r\n", count == -1 ? "_all_" : pc_displays[count], valid_color[y] );

   /* Only toss in blink of we need to */
   if( !str_cmp( argument, "blink" ) && y < 16 )
      y += AT_BLINK;

   if( count == -1 )
   {
      int ccount;

      for( ccount = 0; ccount < MAX_COLORS; ++ccount )
         ch->colors[ccount] = y;

      set_pager_color( y, ch );

      pager_printf( ch, "All color types set to color %s%s.%s\r\n",
                    valid_color[y > AT_BLINK ? y - AT_BLINK : y], y > AT_BLINK ? " [BLINKING]" : "", ANSI_RESET );
   }
   else
   {
      ch->colors[count] = y;

      set_pager_color( count, ch );

      if( !str_cmp( argument, "blink" ) )
         ch_printf( ch, "Display %s set to color %s [BLINKING]%s\r\n",
                    pc_displays[count], valid_color[y - AT_BLINK], ANSI_RESET );
      else
         ch_printf( ch, "Display %s set to color %s.\r\n", pc_displays[count], valid_color[y] );
   }
}

char *color_str( short AType, CHAR_DATA *ch )
{
   if( !ch )
   {
      bug( "%s", "color_str: NULL ch!" );
      return ( "" );
   }

   if( is_npc( ch ) || !xIS_SET( ch->act, PLR_ANSI ) )
      return ( "" );

   switch( ch->colors[AType] )
   {
      case 0:
         return ( ANSI_BLACK );
      case 1:
         return ( ANSI_DRED );
      case 2:
         return ( ANSI_DGREEN );
      case 3:
         return ( ANSI_ORANGE );
      case 4:
         return ( ANSI_DBLUE );
      case 5:
         return ( ANSI_PURPLE );
      case 6:
         return ( ANSI_CYAN );
      case 7:
         return ( ANSI_GREY );
      case 8:
         return ( ANSI_DGREY );
      case 9:
         return ( ANSI_RED );
      case 10:
         return ( ANSI_GREEN );
      case 11:
         return ( ANSI_YELLOW );
      case 12:
         return ( ANSI_BLUE );
      case 13:
         return ( ANSI_PINK );
      case 14:
         return ( ANSI_LBLUE );
      case 15:
         return ( ANSI_WHITE );

      /* 16 thru 31 are for blinking colors */
      case 16:
         return ( BLINK_BLACK );
      case 17:
         return ( BLINK_DRED );
      case 18:
         return ( BLINK_DGREEN );
      case 19:
         return ( BLINK_ORANGE );
      case 20:
         return ( BLINK_DBLUE );
      case 21:
         return ( BLINK_PURPLE );
      case 22:
         return ( BLINK_CYAN );
      case 23:
         return ( BLINK_GREY );
      case 24:
         return ( BLINK_DGREY );
      case 25:
         return ( BLINK_RED );
      case 26:
         return ( BLINK_GREEN );
      case 27:
         return ( BLINK_YELLOW );
      case 28:
         return ( BLINK_BLUE );
      case 29:
         return ( BLINK_PINK );
      case 30:
         return ( BLINK_LBLUE );
      case 31:
         return ( BLINK_WHITE );

      default:
         return ( ANSI_RESET );
   }
}

/* Random Ansi Color Code -- Xorith */
char *random_ansi( short type )
{
   switch( type )
   {
      default:
      case 1: /* Default ANSI Fore-ground */
         switch( number_range( 1, 15 ) )
         {
            case 1:
               return ( ANSI_DRED );
            case 2:
               return ( ANSI_DGREEN );
            case 3:
               return ( ANSI_ORANGE );
            case 4:
               return ( ANSI_DBLUE );
            case 5:
               return ( ANSI_PURPLE );
            case 6:
               return ( ANSI_CYAN );
            case 7:
               return ( ANSI_GREY );
            case 8:
               return ( ANSI_DGREY );
            case 9:
               return ( ANSI_RED );
            case 10:
               return ( ANSI_GREEN );
            case 11:
               return ( ANSI_YELLOW );
            case 12:
               return ( ANSI_BLUE );
            case 13:
               return ( ANSI_PINK );
            case 14:
               return ( ANSI_LBLUE );
            case 15:
               return ( ANSI_WHITE );
            default:
               return ( ANSI_RESET );
         }

      case 2: /* ANSI Blinking */
         switch( number_range( 1, 14 ) )
         {
            case 1:
               return ( BLINK_DGREEN );
            case 2:
               return ( BLINK_ORANGE );
            case 3:
               return ( BLINK_DBLUE );
            case 4:
               return ( BLINK_PURPLE );
            case 5:
               return ( BLINK_CYAN );
            case 6:
               return ( BLINK_GREY );
            case 7:
               return ( BLINK_DGREY );
            case 8:
               return ( BLINK_RED );
            case 9:
               return ( BLINK_GREEN );
            case 10:
               return ( BLINK_YELLOW );
            case 11:
               return ( BLINK_BLUE );
            case 12:
               return ( BLINK_PINK );
            case 13:
               return ( BLINK_LBLUE );
            default:
            case 14:
               return ( BLINK_WHITE );
         }

      case 3: /* ANSI Background */
         switch( number_range( 1, 15 ) )
         {
            case 1:
               return ( BACK_DRED );
            case 2:
               return ( BACK_DGREEN );
            case 3:
               return ( BACK_ORANGE );
            case 4:
               return ( BACK_DBLUE );
            case 5:
               return ( BACK_PURPLE );
            case 6:
               return ( BACK_CYAN );
            case 7:
               return ( BACK_GREY );
            case 8:
               return ( BACK_DGREY );
            case 9:
               return ( BACK_RED );
            case 10:
               return ( BACK_GREEN );
            case 11:
               return ( BACK_YELLOW );
            case 12:
               return ( BACK_BLUE );
            case 13:
               return ( BACK_PINK );
            case 14:
               return ( BACK_LBLUE );
            default:
            case 15:
               return ( BACK_WHITE );
         }
   }
}

/*
 * Quixadhal - I rewrote this from scratch.  It now returns the number of
 * characters in the SOURCE string that should be skipped, it always fills
 * the DESTINATION string with a valid translation (even if that is itself,
 * or an empty string), and the default for ANSI is false, since mobs and
 * logfiles shouldn't need colour.
 *
 * NOTE:  dstlen is the length of your pre-allocated buffer that you passed
 * in.  It must be at least 3 bytes, but should be long enough to hold the
 * longest translation sequence (probably around 16-32).
 *
 * NOTE:  vislen is the "visible" length of the translation token.  This is
 * used by color_strlen to properly figure the visual length of a string.
 * If you need the number of bytes (such as for output buffering), use the
 * normal strlen function.
 */
int colorcode( const char *src, char *dst, DESCRIPTOR_DATA *d, int dstlen, int *vislen )
{
   CHAR_DATA *ch = NULL;
   bool ansi = false;
   char *sympos = NULL;

   /* No descriptor, assume ANSI conversion can't be done. */
   if( !d )
      ansi = false;
   /* But, if we have one, check for a PC and set accordingly. If no PC, assume ANSI can be done. For color logins. */
   else
   {
      ch = d->character;

      if( ch )
         ansi = ( !is_npc( ch ) && xIS_SET( ch->act, PLR_ANSI ) );
      else
         ansi = true;
   }

   if( !dst )
      return 0;   /* HEY, I said at least 3 BYTES! */

   dst[0] = '\0'; /* Initialize the the default NOTHING */

   /* Move along, nothing to see here */
   if( !src || !*src )
      return 0;

   switch( *src )
   {
      case '&':  /* NORMAL, Foreground colour */
         switch( src[1] )
         {
            case '&':  /* Escaped self, return one of us */
               dst[0] = src[0];
               dst[1] = '\0';
               if( vislen )
                  *vislen = 1;
               return 2;

            case 'Z':  /* Random Ansi Foreground */
               if( ansi )
                  mudstrlcpy( dst, random_ansi( 1 ), dstlen );
               break;

            case '[':  /* Symbolic color name */
               if( ( sympos = strchr( src + 2, ']' ) ) )
               {
                  register int subcnt = 0;
                  unsigned int sublen = 0;

                  sublen = sympos - src - 2;
                  for( subcnt = 0; subcnt < MAX_COLORS; subcnt++ )
                  {
                     if( !strncmp( src + 2, pc_displays[subcnt], sublen ) )
                     {
                        if( strlen( pc_displays[subcnt] ) == sublen )
                        {
                           /*
                            * These can only be used with a logged in char 
                            */
                           if( ansi && ch )
                              mudstrlcpy( dst, color_str( subcnt, ch ), dstlen );
                           if( vislen )
                              *vislen = 0;
                           return sublen + 3;
                        }
                     }
                  }
               }  /* found matching ] */

               /*
                * Unknown symbolic name, return just the sequence  
                */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;

            case 'i':  /* Italic text */
            case 'I':
               if( ansi )
                  mudstrlcpy( dst, ANSI_ITALIC, dstlen );
               break;

            case 'v':  /* Reverse colors */
            case 'V':
               if( ansi )
                  mudstrlcpy( dst, ANSI_REVERSE, dstlen );
               break;

            case 'u':  /* Underline */
            case 'U':
               if( ansi )
                  mudstrlcpy( dst, ANSI_UNDERLINE, dstlen );
               break;

            case 's':  /* Strikeover */
            case 'S':
               if( ansi )
                  mudstrlcpy( dst, ANSI_STRIKEOUT, dstlen );
               break;

            case 'd':  /* Player's client default color */
               if( ansi )
                  mudstrlcpy( dst, ANSI_RESET, dstlen );
               break;

            case 'D':  /* Reset to custom color for whatever is being displayed */
               if( ansi )
               {
                  /* Yes, this reset here is quite necessary to cancel out other things */
                  mudstrlcpy( dst, ANSI_RESET, dstlen );
                  if( ch && ch->desc )
                     mudstrlcat( dst, color_str( ch->desc->pagecolor, ch ), dstlen );
               }
               break;

            case 'x':  /* Black */
               if( ansi )
                  mudstrlcpy( dst, ANSI_BLACK, dstlen );
               break;

            case 'O':  /* Orange/Brown */
               if( ansi )
                  mudstrlcpy( dst, ANSI_ORANGE, dstlen );
               break;

            case 'c':  /* Cyan */
               if( ansi )
                  mudstrlcpy( dst, ANSI_CYAN, dstlen );
               break;

            case 'z':  /* Dark Grey */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DGREY, dstlen );
               break;

            case 'g':  /* Dark Green */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DGREEN, dstlen );
               break;

            case 'G':  /* Light Green */
               if( ansi )
                  mudstrlcpy( dst, ANSI_GREEN, dstlen );
               break;

            case 'P':  /* Pink/Light Purple */
               if( ansi )
                  mudstrlcpy( dst, ANSI_PINK, dstlen );
               break;

            case 'r':  /* Dark Red */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DRED, dstlen );
               break;

            case 'b':  /* Dark Blue */
               if( ansi )
                  mudstrlcpy( dst, ANSI_DBLUE, dstlen );
               break;

            case 'w':  /* Grey */
               if( ansi )
                  mudstrlcpy( dst, ANSI_GREY, dstlen );
               break;

            case 'Y':  /* Yellow */
               if( ansi )
                  mudstrlcpy( dst, ANSI_YELLOW, dstlen );
               break;

            case 'C':  /* Light Blue */
               if( ansi )
                  mudstrlcpy( dst, ANSI_LBLUE, dstlen );
               break;

            case 'p':  /* Purple */
               if( ansi )
                  mudstrlcpy( dst, ANSI_PURPLE, dstlen );
               break;

            case 'R':  /* Red */
               if( ansi )
                  mudstrlcpy( dst, ANSI_RED, dstlen );
               break;

            case 'B':  /* Blue */
               if( ansi )
                  mudstrlcpy( dst, ANSI_BLUE, dstlen );
               break;

            case 'W':  /* White */
               if( ansi )
                  mudstrlcpy( dst, ANSI_WHITE, dstlen );
               break;

            default:   /* Unknown sequence, return all the chars */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;
         }
         break;

      case '^':  /* BACKGROUND colour */
         switch( src[1] )
         {
            case '^':  /* Escaped self, return one of us */
               dst[0] = src[0];
               dst[1] = '\0';
               if( vislen )
                  *vislen = 1;
               return 2;

            case 'Z':  /* Random Ansi Background */
               if( ansi )
                  mudstrlcpy( dst, random_ansi( 3 ), dstlen );
               break;

            case 'x':  /* Black */
               if( ansi )
                  mudstrlcpy( dst, BACK_BLACK, dstlen );
               break;

            case 'r':  /* Dark Red */
               if( ansi )
                  mudstrlcpy( dst, BACK_DRED, dstlen );
               break;

            case 'g':  /* Dark Green */
               if( ansi )
                  mudstrlcpy( dst, BACK_DGREEN, dstlen );
               break;

            case 'O':  /* Orange/Brown */
               if( ansi )
                  mudstrlcpy( dst, BACK_ORANGE, dstlen );
               break;

            case 'b':  /* Dark Blue */
               if( ansi )
                  mudstrlcpy( dst, BACK_DBLUE, dstlen );
               break;

            case 'p':  /* Purple */
               if( ansi )
                  mudstrlcpy( dst, BACK_PURPLE, dstlen );
               break;

            case 'c':  /* Cyan */
               if( ansi )
                  mudstrlcpy( dst, BACK_CYAN, dstlen );
               break;

            case 'w':  /* Grey */
               if( ansi )
                  mudstrlcpy( dst, BACK_GREY, dstlen );
               break;

            case 'z':  /* Dark Grey */
               if( ansi )
                  mudstrlcpy( dst, BACK_DGREY, dstlen );
               break;

            case 'R':  /* Red */
               if( ansi )
                  mudstrlcpy( dst, BACK_RED, dstlen );
               break;

            case 'G':  /* Green */
               if( ansi )
                  mudstrlcpy( dst, BACK_GREEN, dstlen );
               break;

            case 'Y':  /* Yellow */
               if( ansi )
                  mudstrlcpy( dst, BACK_YELLOW, dstlen );
               break;

            case 'B':  /* Blue */
               if( ansi )
                  mudstrlcpy( dst, BACK_BLUE, dstlen );
               break;

            case 'P':  /* Pink */
               if( ansi )
                  mudstrlcpy( dst, BACK_PINK, dstlen );
               break;

            case 'C':  /* Light Blue */
               if( ansi )
                  mudstrlcpy( dst, BACK_LBLUE, dstlen );
               break;

            case 'W':  /* White */
               if( ansi )
                  mudstrlcpy( dst, BACK_WHITE, dstlen );
               break;

            default:   /* Unknown sequence, return all the chars */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;
         }
         break;

      case '}':  /* BLINK Foreground colour */
         switch( src[1] )
         {
            case '}':  /* Escaped self, return one of us */
               dst[0] = src[0];
               dst[1] = '\0';
               if( vislen )
                  *vislen = 1;
               return 2;

            case 'Z':  /* Random Ansi Blink */
               if( ansi )
                  mudstrlcpy( dst, random_ansi( 2 ), dstlen );
               break;

            case 'x':  /* Black */
               if( ansi )
                  mudstrlcpy( dst, BLINK_BLACK, dstlen );
               break;

            case 'O':  /* Orange/Brown */
               if( ansi )
                  mudstrlcpy( dst, BLINK_ORANGE, dstlen );
               break;

            case 'c':  /* Cyan */
               if( ansi )
                  mudstrlcpy( dst, BLINK_CYAN, dstlen );
               break;

            case 'z':  /* Dark Grey */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DGREY, dstlen );
               break;

            case 'g':  /* Dark Green */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DGREEN, dstlen );
               break;

            case 'G':  /* Light Green */
               if( ansi )
                  mudstrlcpy( dst, BLINK_GREEN, dstlen );
               break;

            case 'P':  /* Pink/Light Purple */
               if( ansi )
                  mudstrlcpy( dst, BLINK_PINK, dstlen );
               break;

            case 'r':  /* Dark Red */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DRED, dstlen );
               break;

            case 'b':  /* Dark Blue */
               if( ansi )
                  mudstrlcpy( dst, BLINK_DBLUE, dstlen );
               break;

            case 'w':  /* Grey */
               if( ansi )
                  mudstrlcpy( dst, BLINK_GREY, dstlen );
               break;

            case 'Y':  /* Yellow */
               if( ansi )
                  mudstrlcpy( dst, BLINK_YELLOW, dstlen );
               break;

            case 'C':  /* Light Blue */
               if( ansi )
                  mudstrlcpy( dst, BLINK_LBLUE, dstlen );
               break;

            case 'p':  /* Purple */
               if( ansi )
                  mudstrlcpy( dst, BLINK_PURPLE, dstlen );
               break;

            case 'R':  /* Red */
               if( ansi )
                  mudstrlcpy( dst, BLINK_RED, dstlen );
               break;

            case 'B':  /* Blue */
               if( ansi )
                  mudstrlcpy( dst, BLINK_BLUE, dstlen );
               break;

            case 'W':  /* White */
               if( ansi )
                  mudstrlcpy( dst, BLINK_WHITE, dstlen );
               break;

            default:   /* Unknown sequence, return all the chars */
               dst[0] = src[0];
               dst[1] = src[1];
               dst[2] = '\0';
               if( vislen )
                  *vislen = 2;
               return 2;
         }
         break;

      default:   /* Just a normal character */
         dst[0] = *src;
         dst[1] = '\0';
         if( vislen )
            *vislen = 1;
         return 1;
   }
   if( vislen )
      *vislen = 0;
   return 2;
}

/*
 * Quixadhal - I rewrote this too, so that it uses colorcode.  It may not
 * be as efficient as just walking over the string and counting, but it
 * keeps us from duplicating the code several times.
 *
 * This function returns the intended screen length of a string which has
 * color codes embedded in it.  It does this by stripping the codes out
 * entirely (A NULL descriptor means ANSI will be false).
 */
int color_strlen( const char *src )
{
   register unsigned int i = 0;
   int len = 0;

   if( !src || !*src )  /* Move along, nothing to see here */
      return 0;

   for( i = 0; i < strlen( src ); )
   {
      char dst[20];
      int vislen;

      switch( src[i] )
      {
         case '&':  /* NORMAL, Foreground colour */
         case '^':  /* BACKGROUND colour */
         case '}':  /* BLINK Foreground colour */
            *dst = '\0';
            vislen = 0;
            i += colorcode( &src[i], dst, NULL, 20, &vislen ); /* Skip input token */
            len += vislen; /* Count output token length */
            break;   /* this was missing - if you have issues, remove it */

         default:   /* No conversion, just count */
            ++len;
            ++i;
            break;
      }
   }
   return len;
}

/* Quixadhal - And this one needs to use the new version too. */
char *color_align( const char *argument, int size, int align )
{
   int space = 0;
   int len = 0;
   static char buf[MSL];

   len = color_strlen( argument );
   space = ( size - len );
   if( align == ALIGN_RIGHT || len >= size )
      snprintf( buf, sizeof( buf ), "%*.*s", len, len, argument );
   else if( align == ALIGN_CENTER )
      snprintf( buf, sizeof( buf ), "%*s%s%*s", ( space / 2 ), "", argument,
                ( ( space / 2 ) * 2 ) == space ? ( space / 2 ) : ( ( space / 2 ) + 1 ), "" );
   else if( align == ALIGN_LEFT )
      snprintf( buf, sizeof( buf ), "%s%*s", argument, space, "" );

   return buf;
}

/*
 * Quixadhal - This takes a string and converts any and all color tokens
 * in it to the desired output tokens, using the provided character's
 * preferences.
 */
char *colorize( const char *txt, DESCRIPTOR_DATA * d )
{
   static char result[MSL];

   *result = '\0';
   if( txt && *txt && d )
   {
      char *colstr;
      const char *prevstr = txt;
      char colbuf[20];
      int ln;

      while( ( colstr = strpbrk( prevstr, "&^}h" ) ) )
      {
         register int reslen = 0;

         if( colstr > prevstr )
         {
            if( ( MSL - ( reslen = strlen( result ) ) ) <= ( colstr - prevstr ) )
            {
               bug( "%s: OVERFLOW in internal MSL buffer!", __PRETTY_FUNCTION__ );
               break;
            }
            strncat( result, prevstr, ( colstr - prevstr ) );  /* Leave this one alone! BAD THINGS(TM) will happen if you don't! */
            result[reslen + ( colstr - prevstr )] = '\0';   /* strncat WON'T NULL terminate this! */
         }
         if( colstr[0] == 'h' && colstr[1] == 't' && colstr[2] == 't' && colstr[3] == 'p' )
         {
            char http[MIL];

            one_argument( colstr, http );
            mudstrlcat( result, http, sizeof( result ) );
            ln = strlen( http );
            prevstr = colstr + ln;
            continue;
         }
         ln = colorcode( colstr, colbuf, d, 20, NULL );
         if( ln > 0 )
         {
            mudstrlcat( result, colbuf, sizeof( result ) );
            prevstr = colstr + ln;
         }
         else
            prevstr = colstr + 1;
      }
      if( *prevstr )
         mudstrlcat( result, prevstr, sizeof( result ) );
   }
   return result;
}

/* Moved from comm.c */
void set_char_color( short AType, CHAR_DATA *ch )
{
   if( !ch || !ch->desc )
      return;

   if( is_npc( ch ) )
      return;

   write_to_buffer( ch->desc, color_str( AType, ch ), 0 );
   if( !ch->desc )
   {
      bug( "%s: NULL descriptor after WTB! CH: %s", __FUNCTION__, ch->name ? ch->name : "Unknown?!?" );
      return;
   }
   ch->desc->pagecolor = ch->colors[AType];
}

void write_to_pager( DESCRIPTOR_DATA * d, const char *txt, unsigned int length )
{
   int pageroffset;  /* Pager fix by thoric */

   if( length <= 0 )
      length = strlen( txt );

   if( length == 0 )
      return;

   if( !d->pagebuf )
   {
      d->pagesize = MSL;
      CREATE( d->pagebuf, char, d->pagesize );
   }
   if( !d->pagepoint )
   {
      d->pagepoint = d->pagebuf;
      d->pagetop = 0;
      d->pagecmd = '\0';
   }
   if( d->pagetop == 0 && !d->fcommand )
   {
      d->pagebuf[0] = '\r';
      d->pagebuf[1] = '\n';
      d->pagetop = 2;
   }
   pageroffset = d->pagepoint - d->pagebuf;  /* pager fix (goofup fixed 08/21/97) */
   while( d->pagetop + length >= d->pagesize )
   {
      if( d->pagesize > MSL * 16 )
      {
         bug( "%s: Pager overflow. Ignoring.", __FUNCTION__ );
         d->pagetop = 0;
         d->pagepoint = NULL;
         DISPOSE( d->pagebuf );
         d->pagesize = MSL;
         return;
      }
      d->pagesize *= 2;
      RECREATE( d->pagebuf, char, d->pagesize );
   }
   d->pagepoint = d->pagebuf + pageroffset;  /* pager fix (goofup fixed 08/21/97) */
   strncpy( d->pagebuf + d->pagetop, txt, length );   /* Leave this one alone! BAD THINGS(TM) will happen if you don't! */
   d->pagetop += length;
   d->pagebuf[d->pagetop] = '\0';
   return;
}

void set_pager_color( short AType, CHAR_DATA * ch )
{
   if( !ch || !ch->desc )
      return;

   if( is_npc( ch ) )
      return;

   write_to_pager( ch->desc, color_str( AType, ch ), 0 );
   if( !ch->desc )
   {
      bug( "set_pager_color: NULL descriptor after WTP! CH: %s", ch->name ? ch->name : "Unknown?!?" );
      return;
   }
   ch->desc->pagecolor = ch->colors[AType];
}

/* Writes to a descriptor, usually best used when there's no character to send to ( like logins ) */
void send_to_desc( const char *txt, DESCRIPTOR_DATA *d )
{
   if( !d )
   {
      bug( "%s: NULL *d", __FUNCTION__ );
      return;
   }

   if( !txt || !d->descriptor )
      return;

   write_to_buffer( d, colorize( txt, d ), 0 );
   return;
}

/*
 * Write to one char. Convert color into ANSI sequences.
 */
void send_to_char( const char *txt, CHAR_DATA * ch )
{
   if( !ch )
   {
      bug( "%s", "send_to_char: NULL ch!" );
      return;
   }

   if( txt && ch->desc )
      send_to_desc( txt, ch->desc );
   return;
}

void send_to_pager( const char *txt, CHAR_DATA * ch )
{
   if( !ch )
   {
      bug( "%s", "send_to_pager: NULL ch!" );
      return;
   }

   if( txt && ch->desc )
   {
      DESCRIPTOR_DATA *d = ch->desc;

      ch = d->character;
      if( is_npc( ch ) || !xIS_SET( ch->pcdata->flags, PCFLAG_PAGERON ) )
      {
         if( ch->desc )
            send_to_desc( txt, ch->desc );
      }
      else
      {
         if( ch->desc )
            write_to_pager( ch->desc, colorize( txt, ch->desc ), 0 );
      }
   }
   return;
}

void ch_printf( CHAR_DATA *ch, char *fmt, ... )
{
   char buf[MSL * 2];
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   send_to_char( buf, ch );
}

void act_printf( short AType, CHAR_DATA *ch, void *arg1, void *arg2, int type, char *fmt, ... )
{
   char buf[MSL * 2];
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   act( AType, buf, ch, arg1, arg2, type );
}

/* Sends to all playing characters except ch */
void playing_printf( CHAR_DATA *ch, char *fmt, ... )
{
   DESCRIPTOR_DATA *d;
   char buf[MSL * 2];
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   for( d = first_descriptor; d; d = d->next )
      if( d->connected == CON_PLAYING && d->character != ch )
         send_to_char( buf, d->character );
   return;
}

void pager_printf( CHAR_DATA *ch, char *fmt, ... )
{
   char buf[MSL * 2];
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   send_to_pager( buf, ch );
}

/*
 * The primary output interface for formatted output.
 */
/* Major overhaul. -- Alty */
void ch_printf_color( CHAR_DATA *ch, char *fmt, ... )
{
   char buf[MSL * 2];
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   send_to_char( buf, ch );
}

void pager_printf_color( CHAR_DATA *ch, char *fmt, ... )
{
   char buf[MSL * 2];
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   send_to_pager( buf, ch );
}

void paint( short AType, CHAR_DATA *ch, const char *fmt, ... )
{
   char buf[MSL * 2];   /* better safe than sorry */
   va_list args;

   va_start( args, fmt );
   vsnprintf( buf, sizeof( buf ), fmt, args );
   va_end( args );

   set_char_color( AType, ch );
   send_to_char( buf, ch );
   set_char_color( AType, ch );
}

/* Wrapper function for any "legacy" code that may be installed later */
void send_to_char_color( const char *txt, CHAR_DATA * ch )
{
   send_to_char( txt, ch );
   return;
}

/* Wrapper function for any "legacy" code that may be installed later */
void send_to_pager_color( const char *txt, CHAR_DATA * ch )
{
   send_to_pager( txt, ch );
   return;
}