/**************************************************************************/
// 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.");
}
}
/**************************************************************************/
/**************************************************************************/