From 3e0b6eba5b5e95fb6564e360c766c1cfbee30fb8 Mon Sep 17 00:00:00 2001 From: zaCade Date: Sat, 8 Dec 2018 18:02:39 +0100 Subject: [PATCH] Add Includes. --- includes/multicolors.inc | 403 ++++++++++++ includes/multicolors/colors.inc | 944 +++++++++++++++++++++++++++ includes/multicolors/morecolors.inc | 953 ++++++++++++++++++++++++++++ 3 files changed, 2300 insertions(+) create mode 100644 includes/multicolors.inc create mode 100644 includes/multicolors/colors.inc create mode 100644 includes/multicolors/morecolors.inc diff --git a/includes/multicolors.inc b/includes/multicolors.inc new file mode 100644 index 00000000..e3d31c88 --- /dev/null +++ b/includes/multicolors.inc @@ -0,0 +1,403 @@ +#if defined _mutlicolors_included + #endinput +#endif +#define _mutlicolors_included + +#define MuCo_VERSION "2.0.1" +#define MuCo_LoopClients(%1) for(int %1 = 1; %1 <= MaxClients; %1++) + +#include +#include + +/* +* +* Credits: +* - Popoklopsi +* - Powerlord +* - exvel +* - Dr. McKay +* +* Based on stamm-colors +* - https://github.com/popoklopsi/Stamm/blob/master/include/stamm/stamm-colors.inc +* +*/ + + + +/* Global var to check whether colors are fixed or not */ +bool g_bCFixColors = false; + + + +/** + * Writes a message to a client with the correct stock for the game. + * + * @param client Client index. + * @param message Message (formatting rules). + * + * @noreturn + * @error If the client is not connected an error will be thrown. + */ +stock void CPrintToChat(int client, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_PrintToChat(client, "%s", buffer); + else + MC_PrintToChat(client, "%s", buffer); +} + + + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules) + * @return No return + */ +stock void CPrintToChatAll(const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 2); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_PrintToChatAll("%s", buffer); + else + MC_PrintToChatAll("%s", buffer); +} + +/** + * Writes a message to all of a client's observers. + * + * @param target Client index. + * @param message Message (formatting rules). + * + * @noreturn + */ +stock void CPrintToChatObservers(int target, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) + CFixColors(); + + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && !IsPlayerAlive(client) && !IsFakeClient(client)) + { + int observee = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + int ObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if(observee == target && (ObserverMode == 4 || ObserverMode == 5)) + { + CPrintToChat(client, buffer); + } + } + } +} + + +/** + * Writes a message to a client with the correct stock for the game. + * + * @param client Client index. + * @param author Author index. + * @param message Message (formatting rules). + * + * @noreturn + * @error If the client is not connected an error will be thrown. + */ +stock void CPrintToChatEx(int client, int author, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_PrintToChatEx(client, author, "%s", buffer); + else + MC_PrintToChatEx(client, author, "%s", buffer); +} + +/** + * Writes a message to all clients with the correct stock for the game. + * + * @param author Author index. + * @param message Message (formatting rules). + * + * @noreturn + */ +stock void CPrintToChatAllEx(int author, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_PrintToChatAllEx(author, "%s", buffer); + else + MC_PrintToChatAllEx(author, "%s", buffer); +} + +/** + * Writes a message to all of a client's observers with the correct + * game stock. + * + * @param target Client index. + * @param message Message (formatting rules). + * + * @noreturn + */ +stock void CPrintToChatObserversEx(int target, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) + CFixColors(); + + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && !IsPlayerAlive(client) && !IsFakeClient(client)) + { + int observee = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + int ObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if(observee == target && (ObserverMode == 4 || ObserverMode == 5)) + { + CPrintToChatEx(client, target, buffer); + } + } + } +} + + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param message Message (formatting rules) + * @noreturn + */ +stock void CReplyToCommand(int author, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_ReplyToCommand(author, "%s", buffer); + else + MC_ReplyToCommand(author, "%s", buffer); +} + + + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param author Client to use for {teamcolor} + * @param message Message (formatting rules) + * @noreturn + */ + stock void CReplyToCommandEx(int client, int author, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_ReplyToCommandEx(client, author, "%s", buffer); + else + MC_ReplyToCommandEx(client, author, "%s", buffer); +} + + + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * CShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock void CShowActivity(int author, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_ShowActivity(author, "%s", buffer); + else + MC_ShowActivity(author, "%s", buffer); +} + + +/** + * Same as C_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock void CShowActivityEx(int author, const char[] tag, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_ShowActivityEx(author, tag, "%s", buffer); + else + MC_ShowActivityEx(author, tag, "%s", buffer); +} + + + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ + stock void CShowActivity2(int author, const char[] tag, const char[] message, any ...) +{ + char buffer[MAX_MESSAGE_LENGTH]; + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + C_ShowActivity2(author, tag, "%s", buffer); + else + MC_ShowActivity2(author, tag, "%s", buffer); +} + + + +/** + * Replaces color tags in a string with color codes + * + * @param message String. + * @param maxlength Maximum length of the string buffer. + * + * @noreturn + */ +stock void CFormatColor(char[] message, int maxlength, int author = -1) +{ + if (!g_bCFixColors) + CFixColors(); + + if (!IsSource2009()) + { + if (author == 0) + author = -1; + + C_Format(message, maxlength, author); + } + else + { + if (author == -1) + author = 0; + + MC_ReplaceColorCodes(message, author, false, maxlength); + } +} + + + +/** + * Removes color tags from a message + * + * @param message Message to remove tags from + * @param maxlen Maximum buffer length + * @noreturn + */ +stock void CRemoveTags(char[] message, int maxlen) +{ + if (!IsSource2009()) + { + C_RemoveTags(message, maxlen); + } + else + { + MC_RemoveTags(message, maxlen); + } +} + + + +/** + * Fixes missing Lightgreen color. + * + * @noreturn + */ +stock void CFixColors() +{ + g_bCFixColors = true; + + // Replace lightgreen if not exists + if (!C_ColorAllowed(Color_Lightgreen)) + { + if (C_ColorAllowed(Color_Lime)) + C_ReplaceColor(Color_Lightgreen, Color_Lime); + else if (C_ColorAllowed(Color_Olive)) + C_ReplaceColor(Color_Lightgreen, Color_Olive); + } +} + +stock bool IsSource2009() +{ + if(GetEngineVersion() == Engine_CSS || GetEngineVersion() == Engine_HL2DM || GetEngineVersion() == Engine_DODS || GetEngineVersion() == Engine_TF2) + { + return true; + } + return false; +} diff --git a/includes/multicolors/colors.inc b/includes/multicolors/colors.inc new file mode 100644 index 00000000..17bf1b18 --- /dev/null +++ b/includes/multicolors/colors.inc @@ -0,0 +1,944 @@ +/************************************************************************** + * * + * Colored Chat Functions * + * Author: exvel, Editor: Popoklopsi, Powerlord, Bara * + * Version: 2.0.0-MC * + * * + **************************************************************************/ + + +#if defined _colors_included + #endinput +#endif +#define _colors_included + +#define MAX_MESSAGE_LENGTH 250 +#define MAX_COLORS 18 + +#define SERVER_INDEX 0 +#define NO_INDEX -1 +#define NO_PLAYER -2 + +enum C_Colors +{ + Color_Default = 0, + Color_Darkred, + Color_Green, + Color_Lightgreen, + Color_Red, + Color_Blue, + Color_Olive, + Color_Lime, + Color_Lightred, + Color_Purple, + Color_Grey, + Color_Orange, + Color_Bluegrey, + Color_Lightblue, + Color_Darkblue, + Color_Grey2, + Color_Orchid, + Color_Lightred2 +} + +/* C_Colors' properties */ +char C_Tag[][] = {"{default}", "{darkred}", "{green}", "{lightgreen}", "{red}", "{blue}", "{olive}", "{lime}", "{lightred}", "{purple}", "{grey}", "{orange}", "{bluegrey}", "{lightblue}", "{darkblue}", "{grey2}", "{orchid}", "{lightred2}"}; +char C_TagCode[][] = {"\x01", "\x02", "\x04", "\x03", "\x03", "\x03", "\x05", "\x06", "\x07", "\x03", "\x08", "\x09", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F"}; +bool C_TagReqSayText2[] = {false, false, false, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false}; +bool C_EventIsHooked = false; +bool C_SkipList[MAXPLAYERS+1] = {false,...}; + +/* Game default profile */ +bool C_Profile_Colors[] = {true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; +int C_Profile_TeamIndex[] = {NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX}; +bool C_Profile_SayText2 = false; + +static Handle sm_show_activity = null; + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param szMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the client is not connected an error will be thrown. + */ +stock void C_PrintToChat(int client, const char[] szMessage, any ...) +{ + if (client <= 0 || client > MaxClients) + ThrowError("Invalid client index %d", client); + + if (!IsClientInGame(client)) + ThrowError("Client %d is not in game", client); + + char szBuffer[MAX_MESSAGE_LENGTH]; + char szCMessage[MAX_MESSAGE_LENGTH]; + + SetGlobalTransTarget(client); + + Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); + VFormat(szCMessage, sizeof(szCMessage), szBuffer, 3); + + int index = C_Format(szCMessage, sizeof(szCMessage)); + + if (index == NO_INDEX) + PrintToChat(client, "%s", szCMessage); + else + C_SayText2(client, index, szCMessage); +} + +/** + * Reples to a message in a command. A client index of 0 will use PrintToServer(). + * If the command was from the console, PrintToConsole() is used. If the command was from chat, C_PrintToChat() is used. + * Supports color tags. + * + * @param client Client index, or 0 for server. + * @param szMessage Formatting rules. + * @param ... Variable number of format parameters. + * @return No return + * + * On error/Errors: If the client is not connected or invalid. + */ +stock void C_ReplyToCommand(int client, const char[] szMessage, any ...) +{ + char szCMessage[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(szCMessage, sizeof(szCMessage), szMessage, 3); + + if (client == 0) + { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToServer("%s", szCMessage); + } + else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) + { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToConsole(client, "%s", szCMessage); + } + else + { + C_PrintToChat(client, "%s", szCMessage); + } +} + +/** + * Reples to a message in a command. A client index of 0 will use PrintToServer(). + * If the command was from the console, PrintToConsole() is used. If the command was from chat, C_PrintToChat() is used. + * Supports color tags. + * + * @param client Client index, or 0 for server. + * @param author Author index whose color will be used for teamcolor tag. + * @param szMessage Formatting rules. + * @param ... Variable number of format parameters. + * @return No return + * + * On error/Errors: If the client is not connected or invalid. + */ +stock void C_ReplyToCommandEx(int client, int author, const char[] szMessage, any ...) +{ + char szCMessage[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(szCMessage, sizeof(szCMessage), szMessage, 4); + + if (client == 0) + { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToServer("%s", szCMessage); + } + else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) + { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToConsole(client, "%s", szCMessage); + } + else + { + C_PrintToChatEx(client, author, "%s", szCMessage); + } +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param szMessage Message (formatting rules) + * @return No return + */ +stock void C_PrintToChatAll(const char[] szMessage, any ...) +{ + char szBuffer[MAX_MESSAGE_LENGTH]; + + MuCo_LoopClients(i) + { + if (i > 0 && IsClientInGame(i) && !IsFakeClient(i) && !C_SkipList[i]) + { + SetGlobalTransTarget(i); + VFormat(szBuffer, sizeof(szBuffer), szMessage, 2); + + C_PrintToChat(i, "%s", szBuffer); + } + + C_SkipList[i] = false; + } +} + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags and teamcolor tag. + * + * @param client Client index. + * @param author Author index whose color will be used for teamcolor tag. + * @param szMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the client or author are not connected an error will be thrown. + */ +stock void C_PrintToChatEx(int client, int author, const char[] szMessage, any ...) +{ + if (client <= 0 || client > MaxClients) + ThrowError("Invalid client index %d", client); + + if (!IsClientInGame(client)) + ThrowError("Client %d is not in game", client); + + if (author < 0 || author > MaxClients) + ThrowError("Invalid client index %d", author); + + char szBuffer[MAX_MESSAGE_LENGTH]; + char szCMessage[MAX_MESSAGE_LENGTH]; + + SetGlobalTransTarget(client); + + Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); + VFormat(szCMessage, sizeof(szCMessage), szBuffer, 4); + + int index = C_Format(szCMessage, sizeof(szCMessage), author); + + if (index == NO_INDEX) + PrintToChat(client, "%s", szCMessage); + else + C_SayText2(client, author, szCMessage); +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags and teamcolor tag. + * + * @param author Author index whos color will be used for teamcolor tag. + * @param szMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the author is not connected an error will be thrown. + */ +stock void C_PrintToChatAllEx(int author, const char[] szMessage, any ...) +{ + if (author < 0 || author > MaxClients) + ThrowError("Invalid client index %d", author); + + if (!IsClientInGame(author)) + ThrowError("Client %d is not in game", author); + + char szBuffer[MAX_MESSAGE_LENGTH]; + + MuCo_LoopClients(i) + { + if (i > 0 && IsClientInGame(i) && !IsFakeClient(i) && !C_SkipList[i]) + { + SetGlobalTransTarget(i); + VFormat(szBuffer, sizeof(szBuffer), szMessage, 3); + + C_PrintToChatEx(i, author, "%s", szBuffer); + } + + C_SkipList[i] = false; + } +} + +/** + * Removes color tags from the string. + * + * @param szMessage String. + * @return No return + */ +stock void C_RemoveTags(char[] szMessage, int maxlength) +{ + for (int i = 0; i < MAX_COLORS; i++) + ReplaceString(szMessage, maxlength, C_Tag[i], "", false); + + ReplaceString(szMessage, maxlength, "{teamcolor}", "", false); +} + +/** + * Checks whether a color is allowed or not + * + * @param tag Color Tag. + * @return True when color is supported, otherwise false + */ +stock bool C_ColorAllowed(C_Colors color) +{ + if (!C_EventIsHooked) + { + C_SetupProfile(); + + C_EventIsHooked = true; + } + + return C_Profile_Colors[color]; +} + +/** + * Replace the color with another color + * Handle with care! + * + * @param color color to replace. + * @param newColor color to replace with. + * @noreturn + */ +stock void C_ReplaceColor(C_Colors color, C_Colors newColor) +{ + if (!C_EventIsHooked) + { + C_SetupProfile(); + + C_EventIsHooked = true; + } + + C_Profile_Colors[color] = C_Profile_Colors[newColor]; + C_Profile_TeamIndex[color] = C_Profile_TeamIndex[newColor]; + + C_TagReqSayText2[color] = C_TagReqSayText2[newColor]; + Format(C_TagCode[color], sizeof(C_TagCode[]), C_TagCode[newColor]); +} + +/** + * This function should only be used right in front of + * C_PrintToChatAll or C_PrintToChatAllEx and it tells + * to those funcions to skip specified client when printing + * message to all clients. After message is printed client will + * no more be skipped. + * + * @param client Client index + * @return No return + */ +stock void C_SkipNextClient(int client) +{ + if (client <= 0 || client > MaxClients) + ThrowError("Invalid client index %d", client); + + C_SkipList[client] = true; +} + +/** + * Replaces color tags in a string with color codes + * + * @param szMessage String. + * @param maxlength Maximum length of the string buffer. + * @return Client index that can be used for SayText2 author index + * + * On error/Errors: If there is more then one team color is used an error will be thrown. + */ +stock int C_Format(char[] szMessage, int maxlength, int author = NO_INDEX) +{ + /* Hook event for auto profile setup on map start */ + if (!C_EventIsHooked) + { + C_SetupProfile(); + HookEvent("server_spawn", C_Event_MapStart, EventHookMode_PostNoCopy); + + C_EventIsHooked = true; + } + + int iRandomPlayer = NO_INDEX; + + // On CS:GO set invisible precolor + if (GetEngineVersion() == Engine_CSGO) + { + Format(szMessage, maxlength, " %s", szMessage); + } + + /* If author was specified replace {teamcolor} tag */ + if (author != NO_INDEX) + { + if (C_Profile_SayText2) + { + ReplaceString(szMessage, maxlength, "{teamcolor}", "\x03", false); + + iRandomPlayer = author; + } + /* If saytext2 is not supported by game replace {teamcolor} with green tag */ + else + ReplaceString(szMessage, maxlength, "{teamcolor}", C_TagCode[Color_Green], false); + } + else + ReplaceString(szMessage, maxlength, "{teamcolor}", "", false); + + /* For other color tags we need a loop */ + for (int i = 0; i < MAX_COLORS; i++) + { + /* If tag not found - skip */ + if (StrContains(szMessage, C_Tag[i], false) == -1) + continue; + + /* If tag is not supported by game replace it with green tag */ + else if (!C_Profile_Colors[i]) + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[Color_Green], false); + + /* If tag doesn't need saytext2 simply replace */ + else if (!C_TagReqSayText2[i]) + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[i], false); + + /* Tag needs saytext2 */ + else + { + /* If saytext2 is not supported by game replace tag with green tag */ + if (!C_Profile_SayText2) + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[Color_Green], false); + + /* Game supports saytext2 */ + else + { + /* If random player for tag wasn't specified replace tag and find player */ + if (iRandomPlayer == NO_INDEX) + { + /* Searching for valid client for tag */ + iRandomPlayer = C_FindRandomPlayerByTeam(C_Profile_TeamIndex[i]); + + /* If player not found replace tag with green color tag */ + if (iRandomPlayer == NO_PLAYER) + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[Color_Green], false); + + /* If player was found simply replace */ + else + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[i], false); + + } + /* If found another team color tag throw error */ + else + { + //ReplaceString(szMessage, maxlength, C_Tag[i], ""); + ThrowError("Using two team colors in one message is not allowed"); + } + } + + } + } + + return iRandomPlayer; +} + +/** + * Founds a random player with specified team + * + * @param color_team Client team. + * @return Client index or NO_PLAYER if no player found + */ +stock int C_FindRandomPlayerByTeam(int color_team) +{ + if (color_team == SERVER_INDEX) + return 0; + else + { + MuCo_LoopClients(i) + { + if (i > 0 && IsClientInGame(i) && GetClientTeam(i) == color_team) + return i; + } + } + + return NO_PLAYER; +} + +/** + * Sends a SayText2 usermessage to a client + * + * @param szMessage Client index + * @param maxlength Author index + * @param szMessage Message + * @return No return. + */ +stock void C_SayText2(int client, int author, const char[] szMessage) +{ + Handle hBuffer = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); + + if(GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) + { + PbSetInt(hBuffer, "ent_idx", author); + PbSetBool(hBuffer, "chat", true); + PbSetString(hBuffer, "msg_name", szMessage); + PbAddString(hBuffer, "params", ""); + PbAddString(hBuffer, "params", ""); + PbAddString(hBuffer, "params", ""); + PbAddString(hBuffer, "params", ""); + } + else + { + BfWriteByte(hBuffer, author); + BfWriteByte(hBuffer, true); + BfWriteString(hBuffer, szMessage); + } + + EndMessage(); +} + +/** + * Creates game color profile + * This function must be edited if you want to add more games support + * + * @return No return. + */ +stock void C_SetupProfile() +{ + EngineVersion engine = GetEngineVersion(); + + if (engine == Engine_CSS) + { + C_Profile_Colors[Color_Lightgreen] = true; + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + else if (engine == Engine_CSGO) + { + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_Colors[Color_Darkred] = true; + C_Profile_Colors[Color_Lime] = true; + C_Profile_Colors[Color_Lightred] = true; + C_Profile_Colors[Color_Purple] = true; + C_Profile_Colors[Color_Grey] = true; + C_Profile_Colors[Color_Orange] = true; + C_Profile_Colors[Color_Bluegrey] = true; + C_Profile_Colors[Color_Lightblue] = true; + C_Profile_Colors[Color_Darkblue] = true; + C_Profile_Colors[Color_Grey2] = true; + C_Profile_Colors[Color_Orchid] = true; + C_Profile_Colors[Color_Lightred2] = true; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + else if (engine == Engine_TF2) + { + C_Profile_Colors[Color_Lightgreen] = true; + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + else if (engine == Engine_Left4Dead || engine == Engine_Left4Dead2) + { + C_Profile_Colors[Color_Lightgreen] = true; + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; + C_Profile_TeamIndex[Color_Red] = 3; + C_Profile_TeamIndex[Color_Blue] = 2; + C_Profile_SayText2 = true; + } + else if (engine == Engine_HL2DM) + { + /* hl2mp profile is based on mp_teamplay convar */ + if (GetConVarBool(FindConVar("mp_teamplay"))) + { + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Red] = 3; + C_Profile_TeamIndex[Color_Blue] = 2; + C_Profile_SayText2 = true; + } + else + { + C_Profile_SayText2 = false; + C_Profile_Colors[Color_Olive] = true; + } + } + else if (engine == Engine_DODS) + { + C_Profile_Colors[Color_Olive] = true; + C_Profile_SayText2 = false; + } + /* Profile for other games */ + else + { + if (GetUserMessageId("SayText2") == INVALID_MESSAGE_ID) + { + C_Profile_SayText2 = false; + } + else + { + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + } +} + +public Action C_Event_MapStart(Event event, const char[] name, bool dontBroadcast) +{ + C_SetupProfile(); + + MuCo_LoopClients(i) + C_SkipList[i] = false; +} + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * C_ShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int C_ShowActivity(int client, const char[] format, any ...) +{ + if (sm_show_activity == null) + sm_show_activity = FindConVar("sm_show_activity"); + + char tag[] = "[SM] "; + + char szBuffer[MAX_MESSAGE_LENGTH]; + //char szCMessage[MAX_MESSAGE_LENGTH]; + int value = GetConVarInt(sm_show_activity); + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) + { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) + { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s\n", tag, szBuffer); + display_in_chat = true; + } + } + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); + } + + if (!value) + { + return 1; + } + + MuCo_LoopClients(i) + { + if (i == 0 + || !IsClientInGame(i) + || IsFakeClient(i) + || (display_in_chat && i == client)) + { + continue; + } + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 2) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else + { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) + || (value & 8) + || ((value & 16) && is_root)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 8) || ((value & 16) && is_root) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Same as C_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int C_ShowActivityEx(int client, const char[] tag, const char[] format, any ...) +{ + if (sm_show_activity == null) + sm_show_activity = FindConVar("sm_show_activity"); + + char szBuffer[MAX_MESSAGE_LENGTH]; + //char szCMessage[MAX_MESSAGE_LENGTH]; + int value = GetConVarInt(sm_show_activity); + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) + { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) + { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s\n", tag, szBuffer); + display_in_chat = true; + } + } + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); + } + + if (!value) + { + return 1; + } + + MuCo_LoopClients(i) + { + if (i == 0 + || !IsClientInGame(i) + || IsFakeClient(i) + || (display_in_chat && i == client)) + { + continue; + } + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 2) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else + { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) + || (value & 8) + || ((value & 16) && is_root)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 8) || ((value & 16) && is_root) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int C_ShowActivity2(int client, const char[] tag, const char[] format, any ...) +{ + if (sm_show_activity == null) + sm_show_activity = FindConVar("sm_show_activity"); + + char szBuffer[MAX_MESSAGE_LENGTH]; + //char szCMessage[MAX_MESSAGE_LENGTH]; + int value = GetConVarInt(sm_show_activity); + // ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + if (client != 0) + { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + sign = "PLAYER"; + } + + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + /* We don't display directly to the console because the chat text + * simply gets added to the console, so we don't want it to print + * twice. + */ + C_PrintToChatEx(client, client, "%s%s", tag, szBuffer); + } + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); + } + + if (!value) + { + return 1; + } + + MuCo_LoopClients(i) + { + if (i == 0 + || !IsClientInGame(i) + || IsFakeClient(i) + || i == client) + { + continue; + } + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 2)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else + { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) + || (value & 8) + || ((value & 16) && is_root)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 8) || ((value & 16) && is_root)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} diff --git a/includes/multicolors/morecolors.inc b/includes/multicolors/morecolors.inc new file mode 100644 index 00000000..ecf74136 --- /dev/null +++ b/includes/multicolors/morecolors.inc @@ -0,0 +1,953 @@ +// MOAR COLORS +// By Dr. McKay +// Inspired by: https://forums.alliedmods.net/showthread.php?t=96831 + +#if defined _more_colors_included + #endinput +#endif +#define _more_colors_included + +#include + +#define MORE_COLORS_VERSION "2.0.0-MC" +#define MC_MAX_MESSAGE_LENGTH 256 +#define MAX_BUFFER_LENGTH (MC_MAX_MESSAGE_LENGTH * 4) + +#define MCOLOR_RED 0xFF4040 +#define MCOLOR_BLUE 0x99CCFF +#define MCOLOR_GRAY 0xCCCCCC +#define MCOLOR_GREEN 0x3EFF3E + +#define MC_GAME_DODS 0 + +bool MC_SkipList[MAXPLAYERS + 1]; +Handle MC_Trie; +int MC_TeamColors[][] = {{0xCCCCCC, 0x4D7942, 0xFF4040}}; // Multi-dimensional array for games that don't support SayText2. First index is the game index (as defined by the GAME_ defines), second index is team. 0 = spectator, 1 = team1, 2 = team2 + +static Handle sm_show_activity = INVALID_HANDLE; + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules). + * @noreturn + * + * On error/Errors: If the client is not connected an error will be thrown. + */ +stock void MC_PrintToChat(int client, const char[] message, any ...) { + MC_CheckTrie(); + if(client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + if(!IsClientInGame(client)) { + ThrowError("Client %i is not in game", client); + } + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 3); + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(client, buffer2); +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules). + * @noreturn + */ +stock void MC_PrintToChatAll(const char[] message, any ...) { + MC_CheckTrie(); + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; + MuCo_LoopClients(i) { + if(i == 0 || !IsClientInGame(i) || MC_SkipList[i]) { + MC_SkipList[i] = false; + continue; + } + SetGlobalTransTarget(i); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 2); + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(i, buffer2); + } +} + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags and teamcolor tag. + * + * @param client Client index. + * @param author Author index whose color will be used for teamcolor tag. + * @param message Message (formatting rules). + * @noreturn + * + * On error/Errors: If the client or author are not connected an error will be thrown + */ +stock void MC_PrintToChatEx(int client, int author, const char[] message, any ...) { + MC_CheckTrie(); + if(client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + if(!IsClientInGame(client)) { + ThrowError("Client %i is not in game", client); + } + if(author <= 0 || author > MaxClients) { + ThrowError("Invalid client index %i", author); + } + if(!IsClientInGame(author)) { + ThrowError("Client %i is not in game", author); + } + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 4); + MC_ReplaceColorCodes(buffer2, author); + MC_SendMessage(client, buffer2, author); +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags and teamcolor tag. + * + * @param author Author index whose color will be used for teamcolor tag. + * @param message Message (formatting rules). + * @noreturn + * + * On error/Errors: If the author is not connected an error will be thrown. + */ +stock void MC_PrintToChatAllEx(int author, const char[] message, any ...) { + MC_CheckTrie(); + if(author <= 0 || author > MaxClients) { + ThrowError("Invalid client index %i", author); + } + if(!IsClientInGame(author)) { + ThrowError("Client %i is not in game", author); + } + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; + MuCo_LoopClients(i) { + if(i == 0 || !IsClientInGame(i) || MC_SkipList[i]) { + MC_SkipList[i] = false; + continue; + } + SetGlobalTransTarget(i); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 3); + MC_ReplaceColorCodes(buffer2, author); + MC_SendMessage(i, buffer2, author); + } +} + +/** + * Sends a SayText2 usermessage + * + * @param client Client to send usermessage to + * @param message Message to send + * @noreturn + */ +stock void MC_SendMessage(int client, const char[] message, int author = 0) { + if(author == 0) { + author = client; + } + char buffer[MC_MAX_MESSAGE_LENGTH]; + strcopy(buffer, sizeof(buffer), message); + UserMsg index = GetUserMessageId("SayText2"); + if(index == INVALID_MESSAGE_ID) { + if(GetEngineVersion() == Engine_DODS) { + int team = GetClientTeam(author); + if(team == 0) { + ReplaceString(buffer, sizeof(buffer), "\x03", "\x04", false); // Unassigned gets green + } else { + char temp[16]; + Format(temp, sizeof(temp), "\x07%06X", MC_TeamColors[MC_GAME_DODS][team - 1]); + ReplaceString(buffer, sizeof(buffer), "\x03", temp, false); + } + } + PrintToChat(client, "%s", buffer); + return; + } + Handle buf = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); + if(GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) { + PbSetInt(buf, "ent_idx", author); + PbSetBool(buf, "chat", true); + PbSetString(buf, "msg_name", buffer); + PbAddString(buf, "params", ""); + PbAddString(buf, "params", ""); + PbAddString(buf, "params", ""); + PbAddString(buf, "params", ""); + } else { + BfWriteByte(buf, author); // Message author + BfWriteByte(buf, true); // Chat message + BfWriteString(buf, buffer); // Message text + } + EndMessage(); +} + +/** + * This function should only be used right in front of + * MC_PrintToChatAll or MC_PrintToChatAllEx. It causes those functions + * to skip the specified client when printing the message. + * After printing the message, the client will no longer be skipped. + * + * @param client Client index + * @noreturn + */ +stock void MC_SkipNextClient(int client) { + if(client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + MC_SkipList[client] = true; +} + +/** + * Checks if the colors trie is initialized and initializes it if it's not (used internally) + * + * @return No return + */ +stock void MC_CheckTrie() { + if(MC_Trie == INVALID_HANDLE) { + MC_Trie = MC_InitColorTrie(); + } +} + +/** + * Replaces color tags in a string with color codes (used internally by MC_PrintToChat, MC_PrintToChatAll, MC_PrintToChatEx, and MC_PrintToChatAllEx + * + * @param buffer String. + * @param author Optional client index to use for {teamcolor} tags, or 0 for none + * @param removeTags Optional boolean value to determine whether we're replacing tags with colors, or just removing tags, used by MC_RemoveTags + * @param maxlen Optional value for max buffer length, used by MC_RemoveTags + * @noreturn + * + * On error/Errors: If the client index passed for author is invalid or not in game. + */ +stock void MC_ReplaceColorCodes(char[] buffer, int author = 0, bool removeTags = false, int maxlen = MAX_BUFFER_LENGTH) { + MC_CheckTrie(); + if(!removeTags) { + ReplaceString(buffer, maxlen, "{default}", "\x01", false); + } else { + ReplaceString(buffer, maxlen, "{default}", "", false); + ReplaceString(buffer, maxlen, "{teamcolor}", "", false); + } + if(author != 0 && !removeTags) { + if(author < 0 || author > MaxClients) { + ThrowError("Invalid client index %i", author); + } + if(!IsClientInGame(author)) { + ThrowError("Client %i is not in game", author); + } + ReplaceString(buffer, maxlen, "{teamcolor}", "\x03", false); + } + int cursor = 0; + int value; + char tag[32], buff[32]; + char[] output = new char[maxlen]; + + strcopy(output, maxlen, buffer); + // Since the string's size is going to be changing, output will hold the replaced string and we'll search buffer + + Handle regex = CompileRegex("{[a-zA-Z0-9]+}"); + for(int i = 0; i < 1000; i++) { // The RegEx extension is quite flaky, so we have to loop here :/. This loop is supposed to be infinite and broken by return, but conditions have been added to be safe. + if(MatchRegex(regex, buffer[cursor]) < 1) { + CloseHandle(regex); + strcopy(buffer, maxlen, output); + return; + } + GetRegexSubString(regex, 0, tag, sizeof(tag)); + MC_StrToLower(tag); + cursor = StrContains(buffer[cursor], tag, false) + cursor + 1; + strcopy(buff, sizeof(buff), tag); + ReplaceString(buff, sizeof(buff), "{", ""); + ReplaceString(buff, sizeof(buff), "}", ""); + + if(!GetTrieValue(MC_Trie, buff, value)) { + continue; + } + + if(removeTags) { + ReplaceString(output, maxlen, tag, "", false); + } else { + Format(buff, sizeof(buff), "\x07%06X", value); + ReplaceString(output, maxlen, tag, buff, false); + } + } + LogError("[MORE COLORS] Infinite loop broken."); +} + +/** + * Gets a part of a string + * + * @param input String to get the part from + * @param output Buffer to write to + * @param maxlen Max length of output buffer + * @param start Position to start at + * @param numChars Number of characters to return, or 0 for the end of the string + * @noreturn + */ +stock void CSubString(const char[] input, char[] output, int maxlen, int start, int numChars = 0) { + int i = 0; + for(;;) { + if(i == maxlen - 1 || i >= numChars || input[start + i] == '\0') { + output[i] = '\0'; + return; + } + output[i] = input[start + i]; + i++; + } +} + +/** + * Converts a string to lowercase + * + * @param buffer String to convert + * @noreturn + */ +stock void MC_StrToLower(char[] buffer) { + int len = strlen(buffer); + for(int i = 0; i < len; i++) { + buffer[i] = CharToLower(buffer[i]); + } +} + +/** + * Adds a color to the colors trie + * + * @param name Color name, without braces + * @param color Hexadecimal representation of the color (0xRRGGBB) + * @return True if color was added successfully, false if a color already exists with that name + */ +stock bool MC_AddColor(const char[] name, int color) { + MC_CheckTrie(); + int value; + if(GetTrieValue(MC_Trie, name, value)) { + return false; + } + char newName[64]; + strcopy(newName, sizeof(newName), name); + MC_StrToLower(newName); + SetTrieValue(MC_Trie, newName, color); + return true; +} + +/** + * Removes color tags from a message + * + * @param message Message to remove tags from + * @param maxlen Maximum buffer length + * @noreturn + */ +stock void MC_RemoveTags(char[] message, int maxlen) { + MC_ReplaceColorCodes(message, 0, true, maxlen); +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param message Message (formatting rules) + * @noreturn + */ +stock void MC_ReplyToCommand(int client, const char[] message, any ...) { + char buffer[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 3); + if(GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + MC_RemoveTags(buffer, sizeof(buffer)); + PrintToConsole(client, "%s", buffer); + } else { + MC_PrintToChat(client, "%s", buffer); + } +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param author Client to use for {teamcolor} + * @param message Message (formatting rules) + * @noreturn + */ +stock void MC_ReplyToCommandEx(int client, int author, const char[] message, any ...) { + char buffer[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 4); + if(GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + MC_RemoveTags(buffer, sizeof(buffer)); + PrintToConsole(client, "%s", buffer); + } else { + MC_PrintToChatEx(client, author, "%s", buffer); + } +} + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * MC_ShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int MC_ShowActivity(int client, const char[] format, any ...) +{ + if (sm_show_activity == INVALID_HANDLE) + sm_show_activity = FindConVar("sm_show_activity"); + + char tag[] = "[SM] "; + + char szBuffer[MC_MAX_MESSAGE_LENGTH]; + //char szCMessage[MC_MAX_MESSAGE_LENGTH]; + int value = GetConVarInt(sm_show_activity); + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) + { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) + { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s\n", tag, szBuffer); + display_in_chat = true; + } + } + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); + } + + if (!value) + { + return 1; + } + + MuCo_LoopClients(i) + { + if (i == 0 + || !IsClientInGame(i) + || IsFakeClient(i) + || (display_in_chat && i == client)) + { + continue; + } + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 2) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else + { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) + || (value & 8) + || ((value & 16) && is_root)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 8) || ((value & 16) && is_root) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Same as MC_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int MC_ShowActivityEx(int client, const char[] tag, const char[] format, any ...) +{ + if (sm_show_activity == INVALID_HANDLE) + sm_show_activity = FindConVar("sm_show_activity"); + + char szBuffer[MC_MAX_MESSAGE_LENGTH]; + //char szCMessage[MC_MAX_MESSAGE_LENGTH]; + int value = GetConVarInt(sm_show_activity); + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) + { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) + { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s\n", tag, szBuffer); + display_in_chat = true; + } + } + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); + } + + if (!value) + { + return 1; + } + + MuCo_LoopClients(i) + { + if (i == 0 + || !IsClientInGame(i) + || IsFakeClient(i) + || (display_in_chat && i == client)) + { + continue; + } + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 2) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else + { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) + || (value & 8) + || ((value & 16) && is_root)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 8) || ((value & 16) && is_root) || (i == client)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int MC_ShowActivity2(int client, const char[] tag, const char[] format, any ...) +{ + if (sm_show_activity == INVALID_HANDLE) + sm_show_activity = FindConVar("sm_show_activity"); + + char szBuffer[MC_MAX_MESSAGE_LENGTH]; + //char szCMessage[MC_MAX_MESSAGE_LENGTH]; + int value = GetConVarInt(sm_show_activity); + // ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + if (client != 0) + { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + sign = "PLAYER"; + } + + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + /* We don't display directly to the console because the chat text + * simply gets added to the console, so we don't want it to print + * twice. + */ + MC_PrintToChatEx(client, client, "%s%s", tag, szBuffer); + } + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); + } + + if (!value) + { + return 1; + } + + MuCo_LoopClients(i) + { + if (i == 0 + || !IsClientInGame(i) + || IsFakeClient(i) + || i == client) + { + continue; + } + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) + { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 2)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else + { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) + || (value & 8) + || ((value & 16) && is_root)) + { + char newsign[MAX_NAME_LENGTH]; + newsign = sign; + if ((value & 8) || ((value & 16) && is_root)) + { + newsign = name; + } + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Determines whether a color name exists + * + * @param color The color name to check + * @return True if the color exists, false otherwise + */ +stock bool CColorExists(const char[] color) { + MC_CheckTrie(); + int temp; + return GetTrieValue(MC_Trie, color, temp); +} + +/** + * Returns the hexadecimal representation of a client's team color (will NOT initialize the trie) + * + * @param client Client to get the team color for + * @return Client's team color in hexadecimal, or green if unknown + * On error/Errors: If the client index passed is invalid or not in game. + */ +stock int CGetTeamColor(int client) { + if(client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + if(!IsClientInGame(client)) { + ThrowError("Client %i is not in game", client); + } + int value; + switch(GetClientTeam(client)) { + case 1: { + value = MCOLOR_GRAY; + } + case 2: { + value = MCOLOR_RED; + } + case 3: { + value = MCOLOR_BLUE; + } + default: { + value = MCOLOR_GREEN; + } + } + return value; +} + +stock Handle MC_InitColorTrie() { + Handle hTrie = CreateTrie(); + SetTrieValue(hTrie, "aliceblue", 0xF0F8FF); + SetTrieValue(hTrie, "allies", 0x4D7942); // same as Allies team in DoD:S + SetTrieValue(hTrie, "ancient", 0xEB4B4B); // same as Ancient item rarity in Dota 2 + SetTrieValue(hTrie, "antiquewhite", 0xFAEBD7); + SetTrieValue(hTrie, "aqua", 0x00FFFF); + SetTrieValue(hTrie, "aquamarine", 0x7FFFD4); + SetTrieValue(hTrie, "arcana", 0xADE55C); // same as Arcana item rarity in Dota 2 + SetTrieValue(hTrie, "axis", 0xFF4040); // same as Axis team in DoD:S + SetTrieValue(hTrie, "azure", 0x007FFF); + SetTrieValue(hTrie, "beige", 0xF5F5DC); + SetTrieValue(hTrie, "bisque", 0xFFE4C4); + SetTrieValue(hTrie, "black", 0x000000); + SetTrieValue(hTrie, "blanchedalmond", 0xFFEBCD); + SetTrieValue(hTrie, "blue", 0x99CCFF); // same as BLU/Counter-Terrorist team color + SetTrieValue(hTrie, "blueviolet", 0x8A2BE2); + SetTrieValue(hTrie, "brown", 0xA52A2A); + SetTrieValue(hTrie, "burlywood", 0xDEB887); + SetTrieValue(hTrie, "cadetblue", 0x5F9EA0); + SetTrieValue(hTrie, "chartreuse", 0x7FFF00); + SetTrieValue(hTrie, "chocolate", 0xD2691E); + SetTrieValue(hTrie, "collectors", 0xAA0000); // same as Collector's item quality in TF2 + SetTrieValue(hTrie, "common", 0xB0C3D9); // same as Common item rarity in Dota 2 + SetTrieValue(hTrie, "community", 0x70B04A); // same as Community item quality in TF2 + SetTrieValue(hTrie, "coral", 0xFF7F50); + SetTrieValue(hTrie, "cornflowerblue", 0x6495ED); + SetTrieValue(hTrie, "cornsilk", 0xFFF8DC); + SetTrieValue(hTrie, "corrupted", 0xA32C2E); // same as Corrupted item quality in Dota 2 + SetTrieValue(hTrie, "crimson", 0xDC143C); + SetTrieValue(hTrie, "cyan", 0x00FFFF); + SetTrieValue(hTrie, "darkblue", 0x00008B); + SetTrieValue(hTrie, "darkcyan", 0x008B8B); + SetTrieValue(hTrie, "darkgoldenrod", 0xB8860B); + SetTrieValue(hTrie, "darkgray", 0xA9A9A9); + SetTrieValue(hTrie, "darkgrey", 0xA9A9A9); + SetTrieValue(hTrie, "darkgreen", 0x006400); + SetTrieValue(hTrie, "darkkhaki", 0xBDB76B); + SetTrieValue(hTrie, "darkmagenta", 0x8B008B); + SetTrieValue(hTrie, "darkolivegreen", 0x556B2F); + SetTrieValue(hTrie, "darkorange", 0xFF8C00); + SetTrieValue(hTrie, "darkorchid", 0x9932CC); + SetTrieValue(hTrie, "darkred", 0x8B0000); + SetTrieValue(hTrie, "darksalmon", 0xE9967A); + SetTrieValue(hTrie, "darkseagreen", 0x8FBC8F); + SetTrieValue(hTrie, "darkslateblue", 0x483D8B); + SetTrieValue(hTrie, "darkslategray", 0x2F4F4F); + SetTrieValue(hTrie, "darkslategrey", 0x2F4F4F); + SetTrieValue(hTrie, "darkturquoise", 0x00CED1); + SetTrieValue(hTrie, "darkviolet", 0x9400D3); + SetTrieValue(hTrie, "deeppink", 0xFF1493); + SetTrieValue(hTrie, "deepskyblue", 0x00BFFF); + SetTrieValue(hTrie, "dimgray", 0x696969); + SetTrieValue(hTrie, "dimgrey", 0x696969); + SetTrieValue(hTrie, "dodgerblue", 0x1E90FF); + SetTrieValue(hTrie, "exalted", 0xCCCCCD); // same as Exalted item quality in Dota 2 + SetTrieValue(hTrie, "firebrick", 0xB22222); + SetTrieValue(hTrie, "floralwhite", 0xFFFAF0); + SetTrieValue(hTrie, "forestgreen", 0x228B22); + SetTrieValue(hTrie, "frozen", 0x4983B3); // same as Frozen item quality in Dota 2 + SetTrieValue(hTrie, "fuchsia", 0xFF00FF); + SetTrieValue(hTrie, "fullblue", 0x0000FF); + SetTrieValue(hTrie, "fullred", 0xFF0000); + SetTrieValue(hTrie, "gainsboro", 0xDCDCDC); + SetTrieValue(hTrie, "genuine", 0x4D7455); // same as Genuine item quality in TF2 + SetTrieValue(hTrie, "ghostwhite", 0xF8F8FF); + SetTrieValue(hTrie, "gold", 0xFFD700); + SetTrieValue(hTrie, "goldenrod", 0xDAA520); + SetTrieValue(hTrie, "gray", 0xCCCCCC); // same as spectator team color + SetTrieValue(hTrie, "grey", 0xCCCCCC); + SetTrieValue(hTrie, "green", 0x3EFF3E); + SetTrieValue(hTrie, "greenyellow", 0xADFF2F); + SetTrieValue(hTrie, "haunted", 0x38F3AB); // same as Haunted item quality in TF2 + SetTrieValue(hTrie, "honeydew", 0xF0FFF0); + SetTrieValue(hTrie, "hotpink", 0xFF69B4); + SetTrieValue(hTrie, "immortal", 0xE4AE33); // same as Immortal item rarity in Dota 2 + SetTrieValue(hTrie, "indianred", 0xCD5C5C); + SetTrieValue(hTrie, "indigo", 0x4B0082); + SetTrieValue(hTrie, "ivory", 0xFFFFF0); + SetTrieValue(hTrie, "khaki", 0xF0E68C); + SetTrieValue(hTrie, "lavender", 0xE6E6FA); + SetTrieValue(hTrie, "lavenderblush", 0xFFF0F5); + SetTrieValue(hTrie, "lawngreen", 0x7CFC00); + SetTrieValue(hTrie, "legendary", 0xD32CE6); // same as Legendary item rarity in Dota 2 + SetTrieValue(hTrie, "lemonchiffon", 0xFFFACD); + SetTrieValue(hTrie, "lightblue", 0xADD8E6); + SetTrieValue(hTrie, "lightcoral", 0xF08080); + SetTrieValue(hTrie, "lightcyan", 0xE0FFFF); + SetTrieValue(hTrie, "lightgoldenrodyellow", 0xFAFAD2); + SetTrieValue(hTrie, "lightgray", 0xD3D3D3); + SetTrieValue(hTrie, "lightgrey", 0xD3D3D3); + SetTrieValue(hTrie, "lightgreen", 0x99FF99); + SetTrieValue(hTrie, "lightpink", 0xFFB6C1); + SetTrieValue(hTrie, "lightsalmon", 0xFFA07A); + SetTrieValue(hTrie, "lightseagreen", 0x20B2AA); + SetTrieValue(hTrie, "lightskyblue", 0x87CEFA); + SetTrieValue(hTrie, "lightslategray", 0x778899); + SetTrieValue(hTrie, "lightslategrey", 0x778899); + SetTrieValue(hTrie, "lightsteelblue", 0xB0C4DE); + SetTrieValue(hTrie, "lightyellow", 0xFFFFE0); + SetTrieValue(hTrie, "lime", 0x00FF00); + SetTrieValue(hTrie, "limegreen", 0x32CD32); + SetTrieValue(hTrie, "linen", 0xFAF0E6); + SetTrieValue(hTrie, "magenta", 0xFF00FF); + SetTrieValue(hTrie, "maroon", 0x800000); + SetTrieValue(hTrie, "mediumaquamarine", 0x66CDAA); + SetTrieValue(hTrie, "mediumblue", 0x0000CD); + SetTrieValue(hTrie, "mediumorchid", 0xBA55D3); + SetTrieValue(hTrie, "mediumpurple", 0x9370D8); + SetTrieValue(hTrie, "mediumseagreen", 0x3CB371); + SetTrieValue(hTrie, "mediumslateblue", 0x7B68EE); + SetTrieValue(hTrie, "mediumspringgreen", 0x00FA9A); + SetTrieValue(hTrie, "mediumturquoise", 0x48D1CC); + SetTrieValue(hTrie, "mediumvioletred", 0xC71585); + SetTrieValue(hTrie, "midnightblue", 0x191970); + SetTrieValue(hTrie, "mintcream", 0xF5FFFA); + SetTrieValue(hTrie, "mistyrose", 0xFFE4E1); + SetTrieValue(hTrie, "moccasin", 0xFFE4B5); + SetTrieValue(hTrie, "mythical", 0x8847FF); // same as Mythical item rarity in Dota 2 + SetTrieValue(hTrie, "navajowhite", 0xFFDEAD); + SetTrieValue(hTrie, "navy", 0x000080); + SetTrieValue(hTrie, "normal", 0xB2B2B2); // same as Normal item quality in TF2 + SetTrieValue(hTrie, "oldlace", 0xFDF5E6); + SetTrieValue(hTrie, "olive", 0x9EC34F); + SetTrieValue(hTrie, "olivedrab", 0x6B8E23); + SetTrieValue(hTrie, "orange", 0xFFA500); + SetTrieValue(hTrie, "orangered", 0xFF4500); + SetTrieValue(hTrie, "orchid", 0xDA70D6); + SetTrieValue(hTrie, "palegoldenrod", 0xEEE8AA); + SetTrieValue(hTrie, "palegreen", 0x98FB98); + SetTrieValue(hTrie, "paleturquoise", 0xAFEEEE); + SetTrieValue(hTrie, "palevioletred", 0xD87093); + SetTrieValue(hTrie, "papayawhip", 0xFFEFD5); + SetTrieValue(hTrie, "peachpuff", 0xFFDAB9); + SetTrieValue(hTrie, "peru", 0xCD853F); + SetTrieValue(hTrie, "pink", 0xFFC0CB); + SetTrieValue(hTrie, "plum", 0xDDA0DD); + SetTrieValue(hTrie, "powderblue", 0xB0E0E6); + SetTrieValue(hTrie, "purple", 0x800080); + SetTrieValue(hTrie, "rare", 0x4B69FF); // same as Rare item rarity in Dota 2 + SetTrieValue(hTrie, "red", 0xFF4040); // same as RED/Terrorist team color + SetTrieValue(hTrie, "rosybrown", 0xBC8F8F); + SetTrieValue(hTrie, "royalblue", 0x4169E1); + SetTrieValue(hTrie, "saddlebrown", 0x8B4513); + SetTrieValue(hTrie, "salmon", 0xFA8072); + SetTrieValue(hTrie, "sandybrown", 0xF4A460); + SetTrieValue(hTrie, "seagreen", 0x2E8B57); + SetTrieValue(hTrie, "seashell", 0xFFF5EE); + SetTrieValue(hTrie, "selfmade", 0x70B04A); // same as Self-Made item quality in TF2 + SetTrieValue(hTrie, "sienna", 0xA0522D); + SetTrieValue(hTrie, "silver", 0xC0C0C0); + SetTrieValue(hTrie, "skyblue", 0x87CEEB); + SetTrieValue(hTrie, "slateblue", 0x6A5ACD); + SetTrieValue(hTrie, "slategray", 0x708090); + SetTrieValue(hTrie, "slategrey", 0x708090); + SetTrieValue(hTrie, "snow", 0xFFFAFA); + SetTrieValue(hTrie, "springgreen", 0x00FF7F); + SetTrieValue(hTrie, "steelblue", 0x4682B4); + SetTrieValue(hTrie, "strange", 0xCF6A32); // same as Strange item quality in TF2 + SetTrieValue(hTrie, "tan", 0xD2B48C); + SetTrieValue(hTrie, "teal", 0x008080); + SetTrieValue(hTrie, "thistle", 0xD8BFD8); + SetTrieValue(hTrie, "tomato", 0xFF6347); + SetTrieValue(hTrie, "turquoise", 0x40E0D0); + SetTrieValue(hTrie, "uncommon", 0xB0C3D9); // same as Uncommon item rarity in Dota 2 + SetTrieValue(hTrie, "unique", 0xFFD700); // same as Unique item quality in TF2 + SetTrieValue(hTrie, "unusual", 0x8650AC); // same as Unusual item quality in TF2 + SetTrieValue(hTrie, "valve", 0xA50F79); // same as Valve item quality in TF2 + SetTrieValue(hTrie, "vintage", 0x476291); // same as Vintage item quality in TF2 + SetTrieValue(hTrie, "violet", 0xEE82EE); + SetTrieValue(hTrie, "wheat", 0xF5DEB3); + SetTrieValue(hTrie, "white", 0xFFFFFF); + SetTrieValue(hTrie, "whitesmoke", 0xF5F5F5); + SetTrieValue(hTrie, "yellow", 0xFFFF00); + SetTrieValue(hTrie, "yellowgreen", 0x9ACD32); + return hTrie; +} \ No newline at end of file