/**************************************************************************/ // colour.cpp - Dawn colour system, (c)1998-2001 Michael Garratt /*************************************************************************** * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt * * >> A number of people have contributed to the Dawn codebase, with the * * majority of code written by Michael Garratt - www.dawnoftime.org * * >> To use this source code, you must fully comply with the dawn license * * in licenses.txt... In particular, you may not remove this copyright * * notice. * **************************************************************************/ #include "include.h" #include "colour.h" #include "cust_col.h" #include "help.h" #include "clan.h" #include "socials.h" #include "interp.h" #define MAX_RANDOM 14 char randomColours[MAX_RANDOM+2] = "SrRgGyYbBmMcCwW"; bool colour_convert_disabled=true; //prototypes int number_range( int from, int to ); /**************************************************************************/ // this table as all the entries the colour table is made from colour_codes makeFullColourTableFrom[] = { // code,special,dont_repeat,noColour,ansi, irc, ircWhite, html // (think of dont_repeat as is_colour) // IRC White uses black for `X, `x, `W and `w. dark gray for `S // it doesn't use light gray (\00314,00) //silver {'s', false, true, "", "\033[1;30m", "\00314,01", "\00314,00", "</FONT><FONT COLOR=\"#7F7F7F\">"}, {'S', false, true, "", "\033[1;30m", "\00314,01", "\00314,00", "</FONT><FONT COLOR=\"#7F7F7F\">"}, //red {'r', false, true, "", "\033[0;31m", "\00304,01", "\00304,00", "</FONT><FONT COLOR=\"#FF007F\">"}, {'R', false, true, "", "\033[1;31m", "\00305,01", "\00305,00", "</FONT><FONT COLOR=\"#FF0000\">"}, //green {'g', false, true, "", "\033[0;32m", "\00303,01", "\00303,00", "</FONT><FONT COLOR=\"#007F00\">"}, {'G', false, true, "", "\033[1;32m", "\00309,01", "\00309,00", "</FONT><FONT COLOR=\"#00FF00\">"}, //yellow {'y', false, true, "", "\033[0;33m", "\00307,01", "\00308,00", "</FONT><FONT COLOR=\"#7F7F00\">"}, {'Y', false, true, "", "\033[1;33m", "\00308,01", "\00307,00", "</FONT><FONT COLOR=\"#FFFF00\">"}, //blue {'b', false, true, "", "\033[0;34m", "\00302,01", "\00302,00", "</FONT><FONT COLOR=\"#00007F\">"}, {'B', false, true, "", "\033[1;34m", "\00312,01", "\00312,00", "</FONT><FONT COLOR=\"#0000FF\">"}, //magenta {'m', false, true, "", "\033[0;35m", "\00306,01", "\00306,00", "</FONT><FONT COLOR=\"#7F007F\">"}, {'M', false, true, "", "\033[1;35m", "\00313,01", "\00313,00", "</FONT><FONT COLOR=\"#FF00FF\">"}, //cyan {'c', false, true, "", "\033[0;36m", "\00310,01", "\00310,00", "</FONT><FONT COLOR=\"#007F7F\">"}, {'C', false, true, "", "\033[1;36m", "\00311,01", "\00311,00", "</FONT><FONT COLOR=\"#00FFFF\">"}, //white {'w', false, true, "", "\033[0;37m", "\00315,01", "\00301,00", "</FONT><FONT COLOR=\"#BFBFBF\">"}, {'W', false, true, "", "\033[1;37m", "\00300,01", "\00301,00", "</FONT><FONT COLOR=\"#FFFFFF\">"}, //Clear - aliased to white {'x', false, true, "", "\033[0;37m", "\00315,01", "\00301,00", "</FONT><FONT COLOR=\"#BFBFBF\">"}, {'X', false, true, "", "\033[0;37m", "\00315,01", "\00301,00", "</FONT><FONT COLOR=\"#BFBFBF\">"}, // underlined character - ansi only {'_', false, true, "", "\033[4m", "", "", ""}, // ~ symbol {'-', false, false, "~", "~", "~", "~", "~"}, // ` symbol {COLOURCODE, false, false, CCSTR, CCSTR, CCSTR, CCSTR, CCSTR}, // newline {'1', true, false, "", "", "", "", "<BR>"}, // allowing `1 for newline {'}', true, false, "", "", "", "", "<BR>"}, // allowing `} for newline (historical reasons) {'+', false, false, "", "", "", "", ""}, // ignored by colour parser // SPECIAL CODES // flashing {'F', true, true, "", "\033[5m", "", "", ""}, // -- RANDOM COLOUR {'?', true, true, "", "", "", "", ""}, // -- SAVE {'#', true, true, "", "", "", "", ""}, // -- RESTORE - NO REWIND {'^', true, true, "", "", "", "", ""}, // -- RESTORE - AND REWIND {'&', true, true, "", "", "", "", ""}, // // clear the screen - ansi only - disabled by default // {'*', false, true, "", "\033[2J", "", "", ""}, {'=', true, true, "", "", "", "", ""}, // custom colour pointer // -- mud Name - converted to the name of the mud in the gamesettings. {'N', true, false, "", "", "", "", ""}, // CUSTOMISE THE OLC COLOURS TO CHANGE THE OLC COLOUR SCHEME // olc colour 1 {'o', false, true, "", "\033[0;33m", "\00305,01", "\00305,00", "</FONT><FONT COLOR=\"#7F7F00\">"}, // olc colour 2 {'O', false, true, "", "\033[0;36m", "\00310,01", "\00310,00", "</FONT><FONT COLOR=\"#007F7F\">"}, // syntax code {'.', false, true, "", "\033[1;33m", "\00308,01", "\00308,00", "</FONT><FONT COLOR=\"#FFFF00\">"}, // code,special,dont_repeat,noColour,ansi, mxp, irc , ircWhite, html // (think of dont_repeat as is_colour) // end of table marker {'\0', false, false, "", "", "", ""} }; /**************************************************************************/ // empty table now - it is configured when initColour is called colour_codes colourTable[256] = { {'\0', false, false, "", "", "","", ""} }; /**************************************************************************/ void init_custom_colours(); /**************************************************************************/ // sets up the colour void initColour(){ static bool already_initialised=false; // only initialise the system once if(already_initialised){ log_string("initColour(): Colour system already initialised"); return; } already_initialised=true; init_custom_colours(); static colour_codes blankColourEntry; int i; char buf[20]; // check the colour codes are setup correctly sprintf(buf,"%c",COLOURCODE); if (strcmp(CCSTR, buf)){ bugf("initColour: colour codes setup incorrectly!\n"); bugf("in colour.h CCSTR should be a string version of COLOURCODE\n"); exit_error( 1 , "initColour", "colour codes setup incorrectly!"); } // first initialise the table for (i=0;i<256; i++){ colourTable[i]= blankColourEntry; } i=0; while(makeFullColourTableFrom[i].code!='\0'){ colourTable[makeFullColourTableFrom[i].code]=makeFullColourTableFrom[i]; i++; } } /**************************************************************************/ // return the colour code letter for a particular custom colour code unsigned char resolve_custom_colour(unsigned char custom_colour_code, COLOUR_MEMORY_TYPE *cm) { // the character after the = is our pointer code unsigned char pointer_code=custom_colour_code; // find at what position the particular pointer // code is stored in the colour pointer table int custom_position=custom_colour_index[pointer_code]; // get the Custom Colour Code for that position unsigned char ccc=cm->custom_colour[custom_position]; // if they haven't changed that particular colour use the // colour from their underlying template for that position if(ccc=='.'){ // . marks no change from template ccc=cm->colour_template->template_colour[custom_position]; } // by this stage we have the Custom Colour Code (ccc) // that the user has assigned for a particular custom // colour pointer. // if Custom Colour Code is a number, it is a default // template colour, convert into the template value if(is_digit(ccc)){ // . marks no change from template int default_template=custom_colour_index[ccc]; ccc=cm->custom_colour[default_template]; if(ccc=='.'){ // . means use template ccc=cm->colour_template->template_colour[default_template]; } } return ccc; } /**************************************************************************/ #define sz ((int)sizeof(colour_codes)) char *fread_custom_colours(FILE* fp, bool player); /**************************************************************************/ char helplink_code='\0'; // out here so show_olc_cmd's can hook into it /**************************************************************************/ // process_colour returns a pointer to a static buffer... has a big buffer, // assumes it isnt going to get a buffer overrun... // easily big enough for anything Dawn uses at time of coding. char *process_colour(const char *raw_text, connection_data *d) { if(IS_NULLSTR(raw_text)){ return ""; } COLOUR_TYPE cType=CT_HTML; COLOUR_MEMORY_TYPE *cm=NULL; char_data *ch=NULL; bool mxp_client=false; bool mxp_secure_prefix_each_line=false; bool flashing_disabled=false; int gamename_count=0; // can only use gamename a fixed number of times per process colour if(d){ flashing_disabled=d->flashing_disabled; cType=d->colour_mode; cm=&d->colour_memory; mxp_client=d->mxp_enabled; if(mxp_client && IS_SET(d->flags, CONNECTFLAG_MXP_SECURE_PREFIX_EACH_LINE)){ mxp_secure_prefix_each_line=true; }else{ mxp_secure_prefix_each_line=false; } ch=CH(d); } char *sp=NULL; // static variables - memory allocated first time things are run static char *result; // permanantly allocated result buffer static COLOUR_MEMORY_TYPE *static_cm=NULL; static char brokenhelplink_code='\0'; if(result==NULL){ // first time run, initialise the statics // allocate memory the first time things are run logf("process_colour(): Allocating memory for colour processing."); result=new char[120120]; // 120120 bytes is used for historical reasons. // the old memory management system couldn't allocate a block larger // than this... in an ideal world, the code would be rewritten to not // use a buffer like this... but the implementation is acceptable // for the time being. assertp(result); // init the static_cm (static colour memory) static_cm=new COLOUR_MEMORY_TYPE; memset(static_cm, 0, sizeof(COLOUR_MEMORY_TYPE)); static_cm->current='x'; memset(static_cm->saved, 'x', MAX_SAVED_COLOUR_ARRAY); static_cm->saved_index=0; static_cm->custom_colour=fread_custom_colours(NULL, true); // allocate the helplink_code (the character used to specify helplinks) int i; for(i=0; custom_colour_table[i].custom_colour_code!='\0'; i++){ if(custom_colour_table[i].cc_code==CC_HELP_LINK){ helplink_code=custom_colour_table[i].custom_colour_code; break; } } assert(custom_colour_table[i].custom_colour_code!='\0'); // helplink_code now contains the '_' character unless it has been changed // allocate the brokenhelplink_code (the character used to specify unfound helplinks) for(i=0; custom_colour_table[i].custom_colour_code!='\0'; i++){ if(custom_colour_table[i].cc_code==CC_HELP_BROKENLINK){ brokenhelplink_code=custom_colour_table[i].custom_colour_code; break; } } assert(custom_colour_table[i].custom_colour_code!='\0'); // brokenhelplink_code now contains the '"' character unless it has been changed } char *pSrc, *pDest, *pLastNewLine, *baseCol,*col=""; // get setup for colour conversion if(!cm){ cm=static_cm; } // assign the defaults to connections without any if(cm->colour_template==NULL){ cm->colour_template=default_colour_template; } if(IS_NULLSTR(cm->custom_colour)){ cm->custom_colour=fread_custom_colours(NULL, true); } switch (cType){ default: case CT_NOCOLOUR: baseCol= colourTable[0].noColour; break; case CT_ANSI: baseCol= colourTable[0].ansi; break; case CT_IRC: baseCol= colourTable[0].irc; break; case CT_IRCWHITE: baseCol= colourTable[0].ircWhite; break; case CT_HTML: baseCol= colourTable[0].html; mxp_client=true; // have side effect of converting <'s into < etc break; case CT_AUTODETECT: if(d){ if(IS_IRCCON(d)){ baseCol= colourTable[0].ircWhite; }else{ baseCol= colourTable[0].ansi; } }else{ baseCol= colourTable[0].noColour; } break; } if(cm->in_help_link){ pSrc="`=_"; // we get a help link, if we are already in a help link, // switch pSrc over to raw_text when parsing the help link }else{ pSrc=(char *)&raw_text[0]; } pDest=result; pLastNewLine=pDest; if(mxp_secure_prefix_each_line){ // automatically put secure prefix for old clients sp=MXP_SECURE_LINE; while (*sp){ *pDest++=*sp++; } } // convert the colours while (*pSrc){ if (*pSrc==COLOURCODE){ // check for special codes if(colourTable[(unsigned char)*(++pSrc)].special){ if (*pSrc=='='){ // colour customisation pointer system unsigned char ccc; pSrc++; // If we are processing a custom helplink `=_ if(*pSrc==helplink_code && mxp_client){ unsigned char helpcol=0; pSrc++; // skip the helplink_code // check we dont have a helplink code without any help keyword // following cause of end of input... if so we prefix the `=_ // to the next infomation sent thru the colour system for this // colour memory... bit of a hack but efficient fix if(IS_NULLSTR(pSrc)){ if(cm->in_help_link){ // last time we had a help link code at the end of a string pSrc=(char *)&raw_text[0]; cm->in_help_link=false; }else{ cm->in_help_link=true; continue; } } // copy thru any white space directly after the help colour code while ( is_space(*pSrc) ){ *pDest++=*pSrc++; } // now get the help keyword char keyword[MIL]; pSrc=help_find_keyword(pSrc, keyword, ch); if(help_get_by_keyword(keyword, ch, false)){ ccc=resolve_custom_colour(helplink_code, cm); }else{ ccc=resolve_custom_colour(brokenhelplink_code, cm); } // find out what colour our helplink/broken helplink resolved to if (colourTable[(unsigned char)ccc].special) { // it isnt allow to be a special code except random if(ccc=='?'){ // random cm->current=randomColours[number_range(0, MAX_RANDOM)]; col=baseCol + ( sz * (int)cm->current ); }else{ col=""; } helpcol=cm->current; // dont want to trigger a resend }else{ // dont resend colours we have just sent if(cm->current==ccc && colourTable[(unsigned char)ccc].dont_repeat){ col=""; }else{ col=baseCol + ( sz * (unsigned char)ccc); // help colours dont affect the current colour since we revert to current after } helpcol=(unsigned char)ccc; } strcpy(pDest, col); strcat(pDest, "<help>"); // doesn't need to be mxp_tagify'ed cause in process_colour strcat(pDest, keyword); strcat(pDest, "</help>"); if(helpcol!=cm->current){ // if the help colour isnt the current colour, revert back strcat(pDest, baseCol + ( sz * (unsigned char)cm->current)); } pDest+=str_len(pDest); col=""; }else{ ccc=resolve_custom_colour(*pSrc, cm); // now process the Custom Colour Code (ccc) as if a normal code if (colourTable[(unsigned char)ccc].special) { // it isnt allow to be a special code except random if(ccc=='?'){ // random cm->current=randomColours[number_range(0, MAX_RANDOM)]; col=baseCol + ( sz * (int)cm->current ); }else{ pSrc++; continue; } }else{ // dont resend colours we have just sent if(cm->current==ccc && colourTable[(unsigned char)ccc].dont_repeat){ pSrc++; continue; } col=baseCol + ( sz * (unsigned char)ccc); cm->current=(unsigned char)ccc; } } }else if (*pSrc=='F'){ // flashing, players can turn it off if(!flashing_disabled){ if( colourTable[(int)*(pSrc)].dont_repeat) // can think of dont_repeat as is_colour { if(cm->current==*(pSrc)){ pSrc++; continue; } cm->current=*(pSrc); // record the current colour only if it is a colour } col=baseCol + ( sz * (int)*pSrc ); }else{ col=""; } }else if (*pSrc=='N'){ // game/mud Name if(++gamename_count<10){ col=game_settings->gamename; }else{ col=""; } }else if (*pSrc=='?'){ // random cm->current=randomColours[number_range(0, MAX_RANDOM)]; col=baseCol + ( sz * (int)cm->current ); }else if (*pSrc=='#'){ // save current colour using a save buffer ++cm->saved_index%=MAX_SAVED_COLOUR_ARRAY; cm->saved[cm->saved_index]=cm->current; col=""; }else if (*pSrc=='^'){ // restore colour, no rewind of save buffer cm->current=cm->saved[cm->saved_index]; col=baseCol + ( sz * ((int)cm->current)); }else if (*pSrc=='&'){ // restore colour and rewind of save buffer cm->current=cm->saved[cm->saved_index]; col=baseCol + ( sz * ((int)cm->current)); cm->saved_index=(cm->saved_index+(MAX_SAVED_COLOUR_ARRAY-1))%MAX_SAVED_COLOUR_ARRAY; }else if (*pSrc=='1' || *pSrc==/*{*/'}'){ // newline if(cType!=CT_HTML){ *pDest++='\r'; // all but html have the \r } *pDest++='\n'; // we back up the pointer to the character immediately following the last '\n' pLastNewLine=pDest; if(mxp_secure_prefix_each_line){ // automatically put secure prefix for old clients sp=MXP_SECURE_LINE; while (*sp){ *pDest++=*sp++; } } if(cType==CT_IRC || cType==CT_IRCWHITE){// irc has to have the previous col=baseCol + ( sz * ( (int)cm->current)); // lines colour resent }else{ col=""; } } }else{ // not a special code - (colourTable[(int)*(++pSrc)].special)=false // normal code // dont resend colours we have already changed to if( colourTable[(int)*(pSrc)].dont_repeat) // can think of dont_repeat as is_colour { if(cm->current==*(pSrc)){ pSrc++; continue; } cm->current=*(pSrc); // record the current colour only if it is a colour } col=baseCol + ( sz * (int)*pSrc ); } // by this stage, the colour code has been processed, and // 'char *col' is pointing at the result of the code // copy 'col' into the destination while (*col){ *pDest++=*col++; } if(*pSrc){ // move onto the next source character pSrc++;// (if we arent at the end of the string) } }else if (mxp_client){ // we didn't have a colour code, but checks for HTML coding switch (*pSrc){ default: *pDest++=*pSrc++; break; case '\r': // strip off \r in HTML if(cType==CT_HTML){ pSrc++; }else{ *pDest++=*pSrc++; } break; case '\n': // record where the end of the line is so we can insert stuff after it *pDest++=*pSrc++; pLastNewLine=pDest; if(mxp_secure_prefix_each_line){ // automatically put secure prefix for old clients sp=MXP_SECURE_LINE; while (*sp){ *pDest++=*sp++; } } break; case '&': // convert '&' symbol into correct html code *pDest++='&'; *pDest++='a'; *pDest++='m'; *pDest++='p'; *pDest++=';'; pSrc++; break; case '<': // convert '<' symbol into correct html code *pDest++='&'; *pDest++='l'; *pDest++='t'; *pDest++=';'; pSrc++; break; case '>': // convert '>' symbol into correct html code *pDest++='&'; *pDest++='g'; *pDest++='t'; *pDest++=';'; pSrc++; break; case MXP_AMPERSAND: // convert mxp_ampersand into symbol '&' *pDest++='&'; pSrc++; break; case MXP_BEGIN_TAG: // convert mxp_begin_tag into symbol '<' *pDest++='<'; pSrc++; break; case MXP_END_TAG: // convert mxp_end_tag into symbol '>' *pDest++='>'; pSrc++; break; #ifdef VALIDATE_HTML case ' ': // convert ' ' into a space in HTML *pDest++='&'; *pDest++='#'; *pDest++='1'; *pDest++='6'; *pDest++='0'; *pDest++=';'; pSrc++; break; #endif } }else if(*pSrc=='\n'){ // do special things at the end of the line? *pDest++=*pSrc++; // copy the '\n' character pLastNewLine=pDest; if(mxp_secure_prefix_each_line){ // automatically put secure prefix for old clients sp=MXP_SECURE_LINE; while (*sp){ *pDest++=*sp++; } } if (cType==CT_IRC || cType==CT_IRCWHITE){ // resend colour on new lines col=baseCol + ( sz * ( (int)cm->current)); while (*col){ *pDest++=*col++; } } }else{ *pDest++=*pSrc++; // copy plain characters to the destination } } // terminate the string *pDest='\0'; // return the length return (result); } /**************************************************************************/ // convertColour // returns the length of dest - the colour coded string // - This function is old, and was the original basis for the webserver // colour parsing system... Only the webhelp and // write_to_descriptor_colour() still use it... since I dont have time // to remove it from the source before the Dawn 1.7 release it remains... // - Kalahn, September 2000. int convertColour(const char *src, char *dest, COLOUR_TYPE cType, bool parital_html){ char *pSrc, *pDest, *baseCol,*col=""; char savedCol='x'; char currentCol='\0'; bool flashing_disabled=false; switch (cType){ default: case CT_NOCOLOUR: baseCol= colourTable[0].noColour; break; case CT_ANSI: baseCol= colourTable[0].ansi; break; case CT_IRC: baseCol= colourTable[0].irc; break; case CT_IRCWHITE: baseCol= colourTable[0].ircWhite; break; case CT_HTML: baseCol= colourTable[0].html; break; } // convert the colours pSrc=(char *)&src[0]; pDest=dest; while (*pSrc){ if (*pSrc==COLOURCODE){ // check for special codes if (colourTable[(int)*(++pSrc)].special){ if (*pSrc=='='){ // colour customisation pointer system // the character after the = is our pointer code unsigned char pointer_code=*(++pSrc); // find at what position the particular pointer // code is stored in the colour pointer table int custom_position=custom_colour_index[pointer_code]; // get the Custom Colour Code from the default template unsigned char ccc=default_colour_template->template_colour[custom_position]; // by this stage we have the default Custom Colour Code (ccc) // if Custom Colour Code is a number, it is a default // template colour, convert into the template value if(is_digit(ccc)){ // . marks no change from template int default_template=custom_colour_index[ccc]; ccc=default_colour_template->template_colour[default_template]; } // now process the Custom Colour Code (ccc) as if a normal code if (colourTable[(unsigned char)ccc].special) { // it isnt allow to be a special code except random if(ccc=='?'){ // random currentCol=randomColours[number_range(0, MAX_RANDOM)]; col=baseCol + ( sz * (int)currentCol); }else{ pSrc++; continue; } }else{ // dont resend colours we have just sent if(currentCol==ccc && colourTable[(unsigned char)ccc].dont_repeat){ pSrc++; continue; } col=baseCol + ( sz * (unsigned char)ccc); currentCol=(unsigned char)ccc; } }else if (*pSrc=='F'){ // flashing, players can turn it off if(!flashing_disabled){ if( colourTable[(int)*(pSrc)].dont_repeat) // can think of dont_repeat as is_colour { currentCol=*(pSrc); col=baseCol + ( sz * (int)currentCol ); } col=baseCol + ( sz * (int)*pSrc ); }else{ col=""; } }else if (*pSrc=='?'){ // random currentCol=randomColours[number_range(0, MAX_RANDOM)]; col=baseCol + ( sz * (int)currentCol ); }else // save if (*pSrc=='#'){ savedCol=currentCol; col=""; }else //restore if (*pSrc=='^'){ col=baseCol + ( sz * ( (int)savedCol )); currentCol=savedCol; }else if //{ (*pSrc=='1' || *pSrc=='}'){ // newline if(cType!=CT_HTML){ *pDest++='\r'; // all but html have the \r } *pDest++='\n'; // we back up the pointer to the character immediately following the last '\n' // pLastNewLine=pDest; if(cType==CT_IRC || cType==CT_IRCWHITE){// irc has to have the previous col=baseCol + ( sz * ( (int)savedCol)); // lines colour resent }else{ col=""; } } }else{ // normal code // dont repeat displayed codes if(colourTable[(int)*(pSrc)].dont_repeat && currentCol==*(pSrc)){ pSrc++; continue; } currentCol=*(pSrc); col=baseCol + ( sz * (int)currentCol ); } while (*col){ *pDest++=*col++; } if(*pSrc){ pSrc++; } }else if (cType==CT_HTML){ switch (*pSrc){ default: *pDest++=*pSrc++; break; case '\r': // strip off \r in HTML pSrc++; break; /* case '\n': // convert \n into <BR> in HTML *pDest++='<'; *pDest++='B'; *pDest++='R'; *pDest++='>'; #ifdef VALIDATE_HTML *pDest++='\n'; #endif pSrc++; break; */ case '&': // convert '&' symbol into correct html code if not parital html if(parital_html){ *pDest++=*pSrc++; }else{ *pDest++='&'; *pDest++='a'; *pDest++='m'; *pDest++='p'; *pDest++=';'; pSrc++; } break; case '>': // convert '>' symbol into correct html code if not parital html if(parital_html){ *pDest++=*pSrc++; }else{ *pDest++='&'; *pDest++='#'; *pDest++='6'; *pDest++='2'; *pDest++=';'; pSrc++; } break; case '<': // convert '<' symbol into correct html code if not parital html if(parital_html){ *pDest++=*pSrc++; }else{ *pDest++='&'; *pDest++='#'; *pDest++='6'; *pDest++='0'; *pDest++=';'; pSrc++; } break; #ifdef VALIDATE_HTML case ' ': // convert ' ' into a space in HTML *pDest++='&'; *pDest++='#'; *pDest++='1'; *pDest++='6'; *pDest++='0'; *pDest++=';'; pSrc++; break; #endif } }else if (cType==CT_IRC || cType==CT_IRCWHITE){ switch (*pSrc){ default: *pDest++=*pSrc++; break; case '\n': // resend colour on new lines *pDest++=*pSrc++; col=baseCol + ( sz * ( (int)currentCol )); while (*col){ *pDest++=*col++; } break; } }else{ *pDest++=*pSrc++; } } // terminate the string *pDest='\0'; // return the length return (int)(pDest-dest); } /**************************************************************************/ // Function: strip_colour() - Kal October 2000 // Notes: Uses convertColour to parse all colour codes out, pretty simple char *strip_colour(const char *coloured_text) { static int mri; // multi result index static char *multi_result[3]; // circular managed result buffer // nothing to do with empty strings if( IS_NULLSTR(coloured_text)){ return ""; } // rotate buffers ++mri%=3; manage_dynamic_buffer(&multi_result[mri], str_len(coloured_text)+MSL); // maintain result so always has enough space char *result=multi_result[mri]; // managed result buffer convertColour(coloured_text, result, CT_NOCOLOUR, false); return result; } /***************************************************************************/ const struct colour_table_type colour_table[]= { {"`x"}, // 0 {"`r"}, // 1 {"`g"}, // 2 {"`y"}, // 3 {"`b"}, // 4 {"`m"}, // 5 {"`c"}, // 6 {"`w"}, // 7 {"`s"}, // 8 {"`R"}, // 9 {"`G"}, // 10 {"`Y"}, // 11 {"`B"}, // 12 {"`M"}, // 13 {"`C"}, // 14 {"`W"}, // 15 }; /**************************************************************************/ // converts the use of { colour codes to ` in a string // writes into a result buffer which is returned char *colour_convert_code_format(char *text) { static char *result; // managed result buffer // nothing to do with empty strings if( IS_NULLSTR(text)){ return ""; } manage_dynamic_buffer(&result, str_len(text)*2+1); // maintain result so always has enough space // convert ` -> `` // convert {{ -> { // convert {` -> `? // convert {} -> `1 // convert {=x to `=x (where x represents any character but nul) // convert { -> ` char *d=result; for(char *p=text; *p; p++){ if(*p=='`'){ // convert ` into `` *d++='`'; *d++='`'; continue; }else if(*p!='{'){ // we haven't found an oldstyle colour code *d++=*p; continue; } // { oldstyle colour code discovered, work on conversion code p++; // skip to the character after the { code if(!*p){ // check that we aren't looking at a NULL break; // if we have terminate the loop } // convert {{ -> { if(*p=='{'){ *d++='{'; continue; } // convert {` -> `? if(*p=='`'){ *d++='`'; *d++='?'; continue; } // convert {} -> `1 if(*p=='}'){ // newline, new encouraged format *d++='`'; *d++='1'; continue; } // convert {=x -> `=x (where x is anything but null) if(*p=='='){ p++; // skip to the character after the = custom colour code character if(!*p){ // check that we aren't looking at a NULL break; // if we have terminate the loop } *d++='`'; *d++='='; *d++=*p; continue; } // not a special code, copy it over *d++='`'; *d++=*p; } *d='\0'; // terminate the result return result; } /**************************************************************************/ #define str_replace_colour_code(str) \ do{ char *t; \ if((str)!=NULL && (str)[0]!='\0'){ \ t=colour_convert_code_format(str); \ replace_string(str, t); \ } \ }while(0) /**************************************************************************/ void colour_convert_helps( helpfile_data *pHelpfile ) { if(colour_convert_disabled)return; if(pHelpfile->colourcode==COLOURCODE){ // no need to convert the colour codes for this help // since they have already been done return; } logf(" >>>colour_convert_helps(%s)", pHelpfile->file_name); // *** convert helps for ( help_data *pHelp = help_first; pHelp; pHelp = pHelp->next ) { if(pHelp->helpfile!=pHelpfile){ continue; } // help text str_replace_colour_code(pHelp->text); // help title str_replace_colour_code(pHelp->title); // help keywords str_replace_colour_code(pHelp->keyword); // now strip all colour from the keywords char *t=strip_colour(pHelp->keyword); replace_string(pHelp->keyword,t); } // mark the help as converted pHelpfile->colourcode=COLOURCODE; } /**************************************************************************/ extern bool fBootDb; /**************************************************************************/ void colour_convert_area( AREA_DATA *area) { if(colour_convert_disabled)return; int i; EXTRA_DESCR_DATA *pEd; if(area->colourcode==COLOURCODE){ // no need to convert the colour codes for this area // since they have already been done return; } logf(" >>>colour_convert_area(%s) [%d-%d]", area->name, area->min_vnum, area->max_vnum); // first set fBootDb to false to disable any logging of unfound // mobiles in get_mob_index() and rooms in get_room_index() bool backup_fBootDb=fBootDb; fBootDb=false; // *** convert all mobiles in an area for( i = area->min_vnum; i <= area->max_vnum; i++ ) { MOB_INDEX_DATA *pMob; if ( (pMob = get_mob_index( i )) ){ str_replace_colour_code(pMob->short_descr); str_replace_colour_code(pMob->long_descr ); str_replace_colour_code(pMob->description); str_replace_colour_code(pMob->material); } } // *** convert all objects in an area for( i = area->min_vnum; i <= area->max_vnum; i++ ) { OBJ_INDEX_DATA *pObj; if ( (pObj = get_obj_index( i )) ){ str_replace_colour_code(pObj->short_descr); str_replace_colour_code(pObj->description); str_replace_colour_code(pObj->material); // convert any object extra descriptions for(pEd=pObj->extra_descr; pEd; pEd=pEd->next){ str_replace_colour_code(pEd->description); } } } // *** convert all rooms in the area for( i = area->min_vnum; i <= area->max_vnum; i++ ){ ROOM_INDEX_DATA *pRoomIndex=get_room_index(i); if(pRoomIndex){ str_replace_colour_code(pRoomIndex->name); str_replace_colour_code(pRoomIndex->description); { // convert any room echo colour code room_echo_data *pRe; for(pRe=pRoomIndex->echoes; pRe; pRe=pRe->next){ str_replace_colour_code(pRe->echotext); } } // convert any room extra descriptions for(pEd=pRoomIndex->extra_descr; pEd; pEd=pEd->next){ str_replace_colour_code(pEd->description); } // convert any exits leading out of the room for( int exit= 0; exit<MAX_DIR; exit++) { EXIT_DATA *pExit; if (( pExit = pRoomIndex->exit[exit] ) && pExit->u1.to_room ) { if(!IS_NULLSTR(pExit->description)){ str_replace_colour_code(pExit->description); } } } } } // *** convert all mobprogs in the area { MPROG_CODE *pMprog; for( i = area->min_vnum; i <= area->max_vnum; i++ ){ if ( (pMprog = get_mprog_index(i) )){ str_replace_colour_code(pMprog->author); str_replace_colour_code(pMprog->last_editor); str_replace_colour_code(pMprog->code); str_replace_colour_code(pMprog->disabled_text); str_replace_colour_code(pMprog->title); } } } // *** convert colour codes in area header str_replace_colour_code(area->name); str_replace_colour_code(area->builders); str_replace_colour_code(area->short_name); str_replace_colour_code(area->credits); if(!IS_NULLSTR(area->lcomment)){ str_replace_colour_code(area->lcomment); } // mark the area as converted area->colourcode=COLOURCODE; // restore the logging fBootDb=backup_fBootDb; } /**************************************************************************/ void do_save_gamesettings(char_data *ch, char *); extern CClanType *clan_list; void save_clan_db( void ); /**************************************************************************/ void colour_convert_player_object( obj_data *obj) { if(colour_convert_disabled)return; EXTRA_DESCR_DATA *pEd; EXTRA_DESCR_DATA *pEdParent; if ( obj->next_content ){ colour_convert_player_object(obj->next_content); } if(obj->pIndexData){ str_replace_colour_code(obj->owner); if(str_cmp(obj->name, obj->pIndexData->name)){ str_replace_colour_code(obj->name); } if(str_cmp(obj->short_descr, obj->pIndexData->short_descr)){ str_replace_colour_code(obj->short_descr); } if(str_cmp(obj->description, obj->pIndexData->description)){ str_replace_colour_code(obj->description); } if(str_cmp(obj->material, obj->pIndexData->material)){ str_replace_colour_code(obj->material); } // convert any room extra descriptions bool found; for(pEd=obj->extra_descr; pEd; pEd=pEd->next){ found=false; for(pEdParent=obj->pIndexData->extra_descr; pEdParent; pEdParent=pEdParent->next){ if(!str_cmp(pEdParent->keyword, pEd->keyword)){ if(!str_cmp(pEdParent->description, pEd->description)){ found=true; // if we have a description that doesn't need converting } break; } } if(!found){ str_replace_colour_code(pEd->description); } } } if ( obj->contains ){ colour_convert_player_object(obj->contains); } } /**************************************************************************/ void colour_convert_player( char_data *ch) { if(colour_convert_disabled)return; int i; if(!ch || !ch->pcdata || ch->pcdata->colour_code==COLOURCODE){ return; } logf(" >>>colour_convert_player(%s)", ch->name); str_replace_colour_code(ch->short_descr); str_replace_colour_code(ch->long_descr); str_replace_colour_code(ch->description); str_replace_colour_code(ch->gprompt); str_replace_colour_code(ch->prompt); str_replace_colour_code(ch->olcprompt); str_replace_colour_code(ch->prefix); str_replace_colour_code(ch->wiznet_colour[0]); str_replace_colour_code(ch->wiznet_colour[1]); str_replace_colour_code(ch->wiznet_colour[2]); str_replace_colour_code(ch->wiznet_colour[3]); str_replace_colour_code(ch->material); str_replace_colour_code(ch->pcdata->bamfin); str_replace_colour_code(ch->pcdata->bamfout); str_replace_colour_code(ch->pcdata->fadein); str_replace_colour_code(ch->pcdata->fadeout); str_replace_colour_code(ch->pcdata->surname); str_replace_colour_code(ch->pcdata->birthplace); str_replace_colour_code(ch->pcdata->haircolour); str_replace_colour_code(ch->pcdata->eyecolour); for(i=0; i<9; i++){ str_replace_colour_code(ch->pcdata->trait[i]); } str_replace_colour_code(ch->pcdata->crest); for(i=0; i<MAX_ALIAS; i++){ str_replace_colour_code(ch->pcdata->alias[i]); str_replace_colour_code(ch->pcdata->alias_sub[i]); } str_replace_colour_code(ch->pcdata->webpage); str_replace_colour_code(ch->pcdata->charnotes); str_replace_colour_code(ch->pcdata->who_text); str_replace_colour_code(ch->pcdata->afk_message); str_replace_colour_code(ch->pcdata->title); str_replace_colour_code(ch->pcdata->immtitle); str_replace_colour_code(ch->pcdata->immtalk_name); // for morts with immtalk str_replace_colour_code(ch->pcdata->letter_workspace_text); // The text of a letter in progress // convert the objects they are carrying if(ch->carrying){ colour_convert_player_object(ch->carrying); } ch->pcdata->colour_code=COLOURCODE; } /**************************************************************************/ void colour_convert_prefix(char colcode, char *text) { char buf[MIL*2]; bool moved=false; char *src=text; char *dest=text; assert(colcode!=COLOURCODE); // it is a programming bug if we are converting for no reason for(; *src; ){ // we need to handle the case where we have to convert a ` character to `` if(*src==COLOURCODE){ if(!moved){ strcpy(buf, src); src=buf; moved=true; } *dest++=*src; *dest++=*src++; continue; } if(*src==colcode){ src++; // what comes after a players designated colour prefix is what counts // double up of that prefix convert to that prefix // make sure we dont have a nul after their colour prefix if(*src=='\0'){ *dest++=COLOURCODE; *dest='\0'; return; }; // handle the use of prefix double up to get a single character if(*src==colcode){ *dest++=*src++; continue; } if(*src=='}'){ // convert } -> 1 *dest++=COLOURCODE; *dest++='1'; src++; continue; } if(*src=='`'){ // convert old random code ` -> ? *dest++=COLOURCODE; *dest++='?'; src++; continue; } // normal use of colour code *dest++=COLOURCODE; *dest++=*src++; continue; } // normal character *dest++=*src++; } // terminate the string *dest='\0'; } /**************************************************************************/ // colour convert gamesettings void colour_convert_gamesettings( ) { if(colour_convert_disabled)return; if(IS_SET(game_settings->uneditable_flags,GAMESETUNEDIT_MANUAL_COLOUR_CONVERT_PERFORMED)){ // no need to convert the settings if they have already been done return; } log_string(" >>>colour_convert_gamesettings"); str_replace_colour_code(game_settings->gamename); str_replace_colour_code(game_settings->login_prompt); // mark the gamesettings as converted SET_BIT(game_settings->uneditable_flags,GAMESETUNEDIT_MANUAL_COLOUR_CONVERT_PERFORMED); do_save_gamesettings(NULL, ""); // resave so default vnums can be manually edited } /**************************************************************************/ void note_convert_colour_codes(); // in note.cpp /**************************************************************************/ void colour_convert_notes( ) { if(colour_convert_disabled)return; log_string(" >>>colour_convert_notes"); note_convert_colour_codes(); // notes are resaved within note_convert_colour_codes()'s code } /**************************************************************************/ void colour_convert_socials() { if(colour_convert_disabled)return; logf("===colour_convert_socials()"); // patch up the NULL pointers for str_dup(""); // One day might even sort the list alphabetically, but not today :) social_count=0; for(social_type *soc=social_list; soc; soc=soc->next){ social_count++; for(int i=0; i<SOCIAL_ATMAX; i++){ str_replace_colour_code(soc->acts[i]); } } // resave the socials save_socials(); } /**************************************************************************/ void colour_convert_clans( ) { if(colour_convert_disabled)return; log_string(" >>>colour_convert_clans"); CClanType *pClan; for(pClan=clan_list;pClan;pClan=pClan->next){ str_replace_colour_code(pClan->m_pColorStr); str_replace_colour_code(pClan->m_pWhoName); } // resave the clan database save_clan_db(); } /**************************************************************************/ int command_exact_lookup( const char *name ); /**************************************************************************/ // this function should only be run ONCE! void do_manual_colour_convert(char_data *ch, char *arg) { if(colour_convert_disabled)return; if(IS_SET(game_settings->uneditable_flags,GAMESETUNEDIT_MANUAL_COLOUR_CONVERT_PERFORMED)){ ch->println("It appears that manual_colour_convert has already been used."); return; } if(str_cmp(arg,"confirm")){ ch->println("manual_colour_convert should only be used by muds upgrading from 1.69p and lower!"); ch->println("Type 'manual_colour_convert confirm'"); return; } ch->println("Doing manual colour conversion of:"); logf("starting manual_colour_convert()"); ch->println("game settings"); colour_convert_gamesettings(); ch->println("---notes"); colour_convert_notes(); ch->println("---socials"); colour_convert_socials(); ch->println("---clans"); colour_convert_clans(); logf("finished manual_colour_convert()"); ch->println("completed conversion."); SET_BIT(game_settings->uneditable_flags,GAMESETUNEDIT_MANUAL_COLOUR_CONVERT_PERFORMED); do_save_gamesettings(NULL, ""); // resave so default vnums can be manually edited int i = command_exact_lookup( "manual_colour_convert"); if(i>=0){ ch->println("Setting manual_colour_convert command to above MAX_LEVEL."); cmd_table[i].level=MAX_LEVEL+2; do_write_commandtable(ch,""); ch->println("Finished removing the manual_colour_convert command."); } } /**************************************************************************/ /**************************************************************************/