roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * color.cpp
 *	 Functions to handle color.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "login.h"
#include "commands.h"
#include <sstream>

#define CLEAR		"\033[0m"		// Resets color
#define C_BLACK		"\033[0;30m"	// Normal colors
#define C_RED		"\033[0;31m"
#define C_GREEN		"\033[0;32m"
#define C_YELLOW	"\033[0;33m"
#define C_BLUE		"\033[0;34m"
#define C_MAGENTA	"\033[0;35m"
#define C_CYAN		"\033[0;36m"
#define C_WHITE		"\033[0;37m"
#define C_D_GREY	"\033[1;30m"  	// Light Colors
#define C_B_RED		"\033[1;31m"
#define C_B_GREEN	"\033[1;32m"
#define C_B_YELLOW	"\033[1;33m"
#define C_B_BLUE	"\033[1;34m"
#define C_B_MAGENTA	"\033[1;35m"
#define C_B_CYAN	"\033[1;36m"
#define C_B_WHITE	"\033[1;37m"
#define C_BOLD		"\033[1m"
#define C_BLINK		"\033[5m"

int Ansi[12] = { 30, 31, 32, 33, 34, 35, 36, 37, 1, 0, 5 };
int Mirc[9] = {  1,  4,  9,  8, 12, 13, 11, 15, 15 };

//***********************************************************************
//						nameToColorCode
//***********************************************************************

char nameToColorCode(bstring name) {
	name = name.toLower();
	if(name == "blink")
		return('!');
	if(name == "blue")
		return('b');
	if(name == "bold blue")
		return('B');
	if(name == "red")
		return('r');
	if(name == "bold red")
		return('R');
	if(name == "cyan")
		return('c');
	if(name == "bold cyan")
		return('C');
	if(name == "green")
		return('g');
	if(name == "bold green")
		return('G');
	if(name == "magenta")
		return('m');
	if(name == "bold magenta")
		return('M');
	if(name == "yellow")
		return('y');
	if(name == "bold yellow")
		return('Y');
	if(name == "white")
		return('w');
	if(name == "bold white")
		return('W');
	if(name == "black")
		return('d');
	if(name == "grey")
		return('D');
	if(name == "gold")
		return('l');
	if(name == "cerulean")
		return('e');
	if(name == "pink")
		return('p');
	if(name == "sky blue")
		return('s');
	if(name == "brown")
		return('o');
	return('x');
}

//***********************************************************************
//						getColor
//***********************************************************************

const char* colorCodeToColor(const char type) {
	switch(type) {
	case 'd':	return(C_BLACK);
	case 'b':	return(C_BLUE);
	case 'E':
	case 'c':	return(C_CYAN);
	case 'g':	return(C_GREEN);
	case 'm':	return(C_MAGENTA);
	case 'r':	return(C_RED);
	case 'w':	return(C_WHITE);
	case 'o':
	case 'y':	return(C_YELLOW);
	case 'B':	return(C_B_BLUE);
	case 'e':
	case 'C':	return(C_B_CYAN);
	case 'G':	return(C_B_GREEN);
	case 'M':	return(C_B_MAGENTA);
	case 'R':	return(C_B_RED);
	case 'W':	return(C_B_WHITE);
	case 'Y':	return(C_B_YELLOW);
	case 'D':	return(C_D_GREY);
	case '@':	return(C_BOLD);
	case '#':	return(C_BLINK);
	case '^':	return("^");
	case 'x':
	default:	return(CLEAR C_WHITE);
	}
}

//*********************************************************************
//						getCustomColor
//**********************************************************************

bstring Player::getCustomColor(CustomColor i, bool caret) const {
	char color;
	if(customColors[(int)i] != CUSTOM_COLOR_DEFAULT) {
		color = customColors[(int)i];
		if(color == '!')
			color = '#';
		return((bstring)(caret?"^":"") + color);
	}
	return(gConfig->getCustomColor(i, caret));
}

bstring Config::getCustomColor(CustomColor i, bool caret) const {
	if(customColors[(int)i] == CUSTOM_COLOR_DEFAULT)
		return((bstring)(caret?"^":"") + "x");
	return((bstring)(caret?"^":"") + customColors[(int)i]);
}

//*********************************************************************
//						customColorize
//**********************************************************************

const char* Monster::customColorize(bstring text, bool caret) const {
	if(following && following->isPlayer())
		text = following->getConstPlayer()->customColorize(text, caret);
	return(text.c_str());
}

const char* Player::customColorize(bstring text, bool caret) const {
	text.Replace("*CC:BROADCAST*", getCustomColor(CUSTOM_COLOR_BROADCAST, caret).c_str());
	text.Replace("*CC:GOSSIP*", getCustomColor(CUSTOM_COLOR_GOSSIP, caret).c_str());
	text.Replace("*CC:PTEST*", getCustomColor(CUSTOM_COLOR_PTEST, caret).c_str());
	text.Replace("*CC:NEWBIE*", getCustomColor(CUSTOM_COLOR_NEWBIE, caret).c_str());
	text.Replace("*CC:DM*", getCustomColor(CUSTOM_COLOR_DM, caret).c_str());
	text.Replace("*CC:ADMIN*", getCustomColor(CUSTOM_COLOR_ADMIN, caret).c_str());
	text.Replace("*CC:SEND*", getCustomColor(CUSTOM_COLOR_SEND, caret).c_str());
	text.Replace("*CC:MESSAGE*", getCustomColor(CUSTOM_COLOR_MESSAGE, caret).c_str());
	text.Replace("*CC:WATCHER*", getCustomColor(CUSTOM_COLOR_WATCHER, caret).c_str());
	text.Replace("*CC:CLASS*", getCustomColor(CUSTOM_COLOR_CLASS, caret).c_str());
	text.Replace("*CC:RACE*", getCustomColor(CUSTOM_COLOR_RACE, caret).c_str());
	text.Replace("*CC:CLAN*", getCustomColor(CUSTOM_COLOR_CLAN, caret).c_str());
	text.Replace("*CC:TELL*", getCustomColor(CUSTOM_COLOR_TELL, caret).c_str());
	text.Replace("*CC:GROUP*", getCustomColor(CUSTOM_COLOR_GROUP, caret).c_str());
	text.Replace("*CC:DAMAGE*", getCustomColor(CUSTOM_COLOR_DAMAGE, caret).c_str());
	text.Replace("*CC:SELF*", getCustomColor(CUSTOM_COLOR_SELF, caret).c_str());
	text.Replace("*CC:GUILD*", getCustomColor(CUSTOM_COLOR_GUILD, caret).c_str());
	return(text.c_str());
}

//*********************************************************************
//						resetCustomColors
//**********************************************************************

void Player::resetCustomColors() {
	memset(customColors, CUSTOM_COLOR_DEFAULT, sizeof(customColors));
	customColors[CUSTOM_COLOR_SIZE-1] = 0;
}

//***********************************************************************
//						cmdColors
//***********************************************************************
// this function demonstrates all the color options available
// Letters Remaining:
// :: a    f hijk  no q  tuv   z
// :: A    F HIJKL NOPQ STUV X Z

int cmdColors(Player* player, cmd* cmnd) {
	player->defineMXP();

	if(!strcmp(cmnd->str[1], "reset")) {
		player->print("Custom colors have been reset to defaults.\n");
		player->resetCustomColors();
		return(0);
	} else if(cmnd->num > 2) {
		CustomColor i;
		bstring type = cmnd->str[1];
		type = type.toLower();

		if(type == "broadcast")
			i = CUSTOM_COLOR_BROADCAST;
		else if((type == "ptest" || type == "p-test") && isPtester(player))
			i = CUSTOM_COLOR_PTEST;
		else if(type == "gossip")
			i = CUSTOM_COLOR_GOSSIP;
		else if(type == "newbie")
			i = CUSTOM_COLOR_NEWBIE;
		else if(type == "dm" && player->isDm())
			i = CUSTOM_COLOR_DM;
		else if(type == "admin" && player->isAdm())
			i = CUSTOM_COLOR_ADMIN;
		else if(type == "send" && player->isCt())
			i = CUSTOM_COLOR_SEND;
		else if(type == "message" && player->isStaff())
			i = CUSTOM_COLOR_MESSAGE;
		else if(type == "watcher" && player->isWatcher())
			i = CUSTOM_COLOR_WATCHER;
		else if(type == "class")
			i = CUSTOM_COLOR_CLASS;
		else if(type == "race")
			i = CUSTOM_COLOR_RACE;
		else if(type == "clan")
			i = CUSTOM_COLOR_CLAN;
		else if(type == "tell")
			i = CUSTOM_COLOR_TELL;
		else if(type == "group")
			i = CUSTOM_COLOR_GROUP;
		else if(type == "damage")
			i = CUSTOM_COLOR_DAMAGE;
		else if(type == "self")
			i = CUSTOM_COLOR_SELF;
		else if(type == "guild")
			i = CUSTOM_COLOR_GUILD;
		else {
			player->print("Custom color type choice not understood.\n");
			return(0);
		}

		char color = nameToColorCode(getFullstrText(cmnd->fullstr, 2));
		player->setCustomColor(i, color);
		if(color == '!')
			color = '#';
		player->printColor("The ^%ccustom color^x has been set.\n", color);
		return(0);
	}

	player->print("Colors:\n");
	player->printColor("   ^%cBlue       ^%cBold Blue\n", nameToColorCode("Blue"), nameToColorCode("Bold Blue"));
	player->printColor("   ^%cRed        ^%cBold Red\n", nameToColorCode("Red"), nameToColorCode("Bold Red"));
	player->printColor("   ^%cCyan       ^%cBold Cyan\n", nameToColorCode("Cyan"), nameToColorCode("Bold Cyan"));
	player->printColor("   ^%cGreen      ^%cBold Green\n", nameToColorCode("Green"), nameToColorCode("Bold Green"));
	player->printColor("   ^%cMagenta    ^%cBold Magenta\n", nameToColorCode("Magenta"), nameToColorCode("Bold Magenta"));
	player->printColor("   ^%cYellow     ^%cBold Yellow\n", nameToColorCode("Yellow"), nameToColorCode("Bold Yellow"));
	player->printColor("   ^%cWhite      ^%cBold White\n", nameToColorCode("White"), nameToColorCode("Bold White"));
	player->printColor("   ^%cBlack      ^%cGrey\n", nameToColorCode("Black"), nameToColorCode("Grey"));
	player->printColor("   ^x^#Blink\n");
	player->print("\n");

	player->print("New MXP Colors:\n");
	if(!player->flagIsSet(P_MXP_ENABLED))
		player->printColor("   ^yYou will need to type \"set mxpcolors\" to enable the following colors.\n");
	player->printColor("   ^%cGold       ^%cCerulean\n", nameToColorCode("Gold"), nameToColorCode("Cerulean"));
	player->printColor("   ^%cPink       ^%cSky Blue\n", nameToColorCode("Pink"), nameToColorCode("Sky Blue"));
	player->printColor("   ^%cBrown\n", nameToColorCode("Brown"));
	player->print("\n");
	player->printColor("Custom Colors:  type [color ^W<type> <color>^x]\n");
	player->printColor("                Choose ^Wtype^x from below, ^Wcolor^x from above.\n");
	player->printColor("                Type ^Wcolor reset^x to return to default colors.\n\n");

	std::map<bstring,bstring> options;
	std::map<bstring,bstring>::iterator it;
	options["Self: @"] = player->customColorize("*CC:SELF*");
	options["Broadcast"] = player->customColorize("*CC:BROADCAST*");
	options["Tell"] = player->customColorize("*CC:TELL*");
	options["Gossip"] = player->customColorize("*CC:GOSSIP*");
	options["Newbie"] = player->customColorize("*CC:NEWBIE*");
	options["Class"] = player->customColorize("*CC:CLASS*");
	options["Race"] = player->customColorize("*CC:RACE*");
	options["Clan"] = player->customColorize("*CC:CLAN*");
	options["Group"] = player->customColorize("*CC:GROUP*");
	options["Damage"] = player->customColorize("*CC:DAMAGE*");
	if(player->isDm())
		options["DM"] = player->customColorize("*CC:DM*");
	if(player->isAdm())
		options["Admin"] = player->customColorize("*CC:ADMIN*");
	if(player->isCt())
		options["Send"] = player->customColorize("*CC:SEND*");
	if(player->isStaff())
		options["Message"] = player->customColorize("*CC:MESSAGE*");
	if(player->isWatcher())
		options["Watcher"] = player->customColorize("*CC:WATCHER*");
	if(isPtester(player))
		options["P-Test"] = player->customColorize("*CC:PTEST*");
	if(player->getGuild())
		options["Guild"] = player->customColorize("*CC:GUILD*");

	for(it = options.begin() ; it != options.end() ; ) {
		for(int n=0; n<3; n++) {
			if(it != options.end()) {
				player->printColor("   ^x* %s%-10s", (*it).second.c_str(), (*it).first.c_str());
				it++;
			}
		}
		player->print("\n");
	}
	player->print("\n");

	return(0);
}

//***********************************************************************
//						defineColors
//***********************************************************************
// setup what color they want - called on new character and login of
// existing character

void Player::defineColors() {
	clearFlag(P_ANSI_COLOR);
	clearFlag(P_MXP_ENABLED);
	clearFlag(P_MIRC);
	clearFlag(P_NEWLINE_AFTER_PROMPT);

	if(mySock->color == WANTS_ANSI_COLOR)
		setFlag(P_ANSI_COLOR);
	else if(mySock->color == WANTS_MXP_COLOR) {
		setFlag(P_ANSI_COLOR);
		setFlag(P_MXP_ENABLED);
		defineMXP();
	} else if(mySock->color == WANTS_MIRC_COLOR) {
		setFlag(P_MIRC);
		setFlag(P_NEWLINE_AFTER_PROMPT);
	}
}

//***********************************************************************
//						defineMXP
//***********************************************************************

void Player::defineMXP() {
	if(!flagIsSet(P_MXP_ENABLED) || !mySock->getMxp())
		return;
	print("%c[1z", 27);
	print("<!ELEMENT c1 '<COLOR #FFD700>'>");	// gold
	print("<!ELEMENT c2 '<COLOR #009CFF>'>");	// cerulean
	print("<!ELEMENT c3 '<COLOR #FF5ADE>'>");	// pink
	print("<!ELEMENT c4 '<COLOR #82E6FF>'>");	// sky blue
	print("<!ELEMENT c5 '<COLOR #484848>'>");	// dark grey
	print("<!ELEMENT c6 '<COLOR #95601A>'>");	// brown
	printColor("%c[3z^x", 27);
}

//***********************************************************************
//						ANSI
//***********************************************************************

void ANSI(Socket* sock, int color) {
	if(sock && sock->getPlayer()) {
		if(sock->getPlayer()->flagIsSet(P_ANSI_COLOR)) {
			if(color & BOLD)			sock->print("%c[%dm", 27, Ansi[COLOR_BOLD]);
			if(color & BLINK)			sock->print("%c[%dm", 27, Ansi[COLOR_BLINK]);
			if(color & NORMAL)			sock->print("%c[%dm", 27, Ansi[COLOR_NORMAL]);

				 if(color & RED)		sock->print("%c[%dm", 27, Ansi[COLOR_RED]);
			else if(color & GREEN)		sock->print("%c[%dm", 27, Ansi[COLOR_GREEN]);
			else if(color & YELLOW)		sock->print("%c[%dm", 27, Ansi[COLOR_YELLOW]);
			else if(color & BLUE)		sock->print("%c[%dm", 27, Ansi[COLOR_BLUE]);
			else if(color & MAGENTA)	sock->print("%c[%dm", 27, Ansi[COLOR_MAGENTA]);
			else if(color & CYAN)		sock->print("%c[%dm", 27, Ansi[COLOR_CYAN]);
			else if(color & BLACK)		sock->print("%c[%dm", 27, Ansi[COLOR_BLACK]);
			else if(color & WHITE)		sock->print("%c[%dm", 27, Ansi[COLOR_WHITE]);

		} else if(sock->getPlayer()->flagIsSet(P_MIRC) && color != BLINK) {
			if(color & BOLD)			sock->print("%c", 2);
			if(color & UNDERLINE)		sock->print("%c", 31);
			if(color & NORMAL)			sock->print("%c%c", 3, 3);

				 if(color & RED)		sock->print("%c%d", 3, Mirc[COLOR_RED]);
			else if(color & GREEN)		sock->print("%c%d", 3, Mirc[COLOR_GREEN]);
			else if(color & YELLOW)		sock->print("%c%d", 3, Mirc[COLOR_YELLOW]);
			else if(color & BLUE)		sock->print("%c%d", 3, Mirc[COLOR_BLUE]);
			else if(color & MAGENTA)	sock->print("%c%d", 3, Mirc[COLOR_MAGENTA]);
			else if(color & CYAN)		sock->print("%c%d", 3, Mirc[COLOR_CYAN]);
			else if(color & BLACK)		sock->print("%c%d", 3, Mirc[COLOR_BLACK]);
			else if(color & WHITE)		sock->print("%c%d", 3, Mirc[COLOR_WHITE]);
		}
	}
}

//***********************************************************************
//						getMXPColor
//***********************************************************************

const char* getMXPColor(const char type, Player* player) {
	// max length from getColor is 9, ending active MXP is 4,
	// so 15 storage will be enough
	static char r[15];
	r[0] = 0;

	// mxp specific color tags
	switch(type) {
	case 'l':
	case 'e':
	case 'p':
	case 's':
	case 'E':
	case 'o':
		// start mxp
		sprintf(r, "%c[4z", 27);
		player->setFlag(P_MXP_ACTIVE);

		// grab the color
		switch(type) {
		case 'l':	strcat(r, "<c1>");	break;
		case 'e':	strcat(r, "<c2>");	break;
		case 'p':	strcat(r, "<c3>");	break;
		case 's':	strcat(r, "<c4>");	break;
		case 'E':	strcat(r, "<c5>");	break;
		case 'o':	strcat(r, "<c6>");	break;
		default:	break;
		}
		return(r);
	default:
		break;
	}

	// dont deactivate color for carets!
	if(type == '^')
		return("^");

	if(player->flagIsSet(P_MXP_ACTIVE)) {
		// end mxp
		sprintf(r, "%c[3z", 27);
		player->clearFlag(P_MXP_ACTIVE);
	}

	strcat(r, colorCodeToColor(type));
	return(r);
}

//***********************************************************************
//						stripColor
//***********************************************************************

bstring stripColor(bstring color) {
	std::ostringstream str;
	unsigned int i=0, max = color.getLength();
	for(; i < max ; i++) {
		if(color.getAt(i) == '^')
			i++;
		else
			str << color.getAt(i);
	}
	return(str.str());
}

//***********************************************************************
//						escapeColor
//***********************************************************************

bstring escapeColor(bstring color) {
	color.Replace("^","^^");
	return(color);
}

//***********************************************************************
//						colorize
//***********************************************************************

bstring colorize(const char* txt, int option, Player* player) {
	const char* point;
	char last = '0';
	std::ostringstream coloredStr;

	if(option) {
		for(point = txt; *point; point++) {
			if(*point == '^') {
				point++;
				// If we're trying to send out the same color as before
				// no point wasting the extra space
				if(*point != last || last == '^') {
					if(player && player->flagIsSet(P_MXP_ENABLED))
						coloredStr << getMXPColor(*point, player);
					else
						coloredStr << colorCodeToColor(*point);
				}
				last = *point;
				continue;
			}
			coloredStr << *point;
		}
		// Now set the color back to normal
		if(player && player->flagIsSet(P_MXP_ENABLED))
			coloredStr << getMXPColor('x', player);
		else
			coloredStr << colorCodeToColor('x');
	} else {
		for(point=txt; *point; point++ ) {
			if(*point == '^') {
				point++;
				if(*point == '^')
					coloredStr << "^";
				continue;
			}
			coloredStr << *point;
		}
	}
	return(coloredStr.str());
}