/**************************************************************************** * ^ +----- | / ^ ^ | | +-\ * * / \ | | / |\ /| | | | \ * * / \ +--- |< | \ / | | | | | * * /-----\ | | \ | 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" const char *pc_displays[MAX_COLORS] = { "black", "dred", "dgreen", "orange", "dblue", "purple", "cyan", "gray", "dgray", "red", "green", "yellow", "blue", "pink", "lblue", "white", "blink", "bdred", "bdgreen", "borange", "bdblue", "bpurple", "bcyan", "bgray", "bdgray", "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_GRAY, AT_DGRAY, 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_GRAY_BLINK, AT_DGRAY_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_GRAY, 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_GRAY, AT_BLUE, AT_GRAY, AT_DBLUE, AT_GRAY, AT_RED, AT_GRAY, AT_BLUE, AT_PINK, AT_GRAY, AT_GRAY, AT_YELLOW, AT_GREEN, AT_GRAY, AT_ORANGE, AT_BLUE, AT_RED, AT_GRAY, AT_GRAY, AT_GREEN, AT_DGREEN, AT_DGREEN, AT_ORANGE, AT_GRAY, AT_RED, AT_GRAY, 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_GRAY, AT_GREEN, AT_LBLUE, AT_PURPLE, AT_GRAY, AT_CYAN, AT_BLUE, AT_CYAN, AT_RED, AT_DGREEN, AT_GREEN, AT_YELLOW, AT_GREEN, AT_YELLOW, AT_LBLUE, AT_DGRAY, AT_GREEN, AT_RED, AT_LBLUE, AT_GREEN }; const char *valid_color[] = { "black", "dred", "dgreen", "orange", "dblue", "purple", "cyan", "gray", "dgray", "red", "green", "yellow", "blue", "pink", "lblue", "white", "blink", "bdred", "bdgreen", "bdorange", "bdblue", "bpurple", "bcyan", "bgray", "bdgray", "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 %sGray%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_GRAY, ANSI_RESET ); write_to_buffer( ch->desc, log_buf, 0 ); snprintf( log_buf, sizeof( log_buf ), "%sDGray%s %sRed%s %sGreen%s %sYellow%s %sBlue%s %sPink%s %sLBlue%s %sWhite%s\r\n", ANSI_DGRAY, 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 %sGray%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_GRAY, ANSI_RESET ); write_to_buffer( ch->desc, log_buf, 0 ); snprintf( log_buf, sizeof( log_buf ), "%sDGray%s %sRed%s %sGreen%s %sYellow%s %sBlue%s %sPink%s %sLBlue%s %sWhite%s\r\n", BLINK_DGRAY, 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%sGray%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_GRAY, BACK_GRAY, ANSI_RESET ); write_to_buffer( ch->desc, log_buf, 0 ); snprintf( log_buf, sizeof( log_buf ), "%s%sDGray%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_DGRAY, BACK_DGRAY, 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_GRAY, 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.\r\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] ); } } const 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_GRAY ); case 8: return ( ANSI_DGRAY ); 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_GRAY ); case 24: return ( BLINK_DGRAY ); 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 */ const 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_GRAY ); case 8: return ( ANSI_DGRAY ); 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_GRAY ); case 7: return ( BLINK_DGRAY ); 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_GRAY ); case 8: return ( BACK_DGRAY ); 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 Gray */ if( ansi ) mudstrlcpy( dst, ANSI_DGRAY, 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': /* Gray */ if( ansi ) mudstrlcpy( dst, ANSI_GRAY, 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': /* Gray */ if( ansi ) mudstrlcpy( dst, BACK_GRAY, dstlen ); break; case 'z': /* Dark Gray */ if( ansi ) mudstrlcpy( dst, BACK_DGRAY, 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 Gray */ if( ansi ) mudstrlcpy( dst, BLINK_DGRAY, 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': /* Gray */ if( ansi ) mudstrlcpy( dst, BLINK_GRAY, 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; send_to_char( color_str( AType, ch ), ch ); if( !ch->desc ) { bug( "%s: NULL descriptor after send_to_char! 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; send_to_pager( color_str( AType, ch ), ch ); if( !ch->desc ) { bug( "%s: NULL descriptor after send_to_pager! CH: %s", __FUNCTION__, 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, const 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, const 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, const 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, const 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, const 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; }