Skip to content

Instantly share code, notes, and snippets.

@shanapu
Created January 12, 2019 11:19
Show Gist options
  • Save shanapu/29a67a0bc2379d35080d268d26d369f6 to your computer and use it in GitHub Desktop.
Save shanapu/29a67a0bc2379d35080d268d26d369f6 to your computer and use it in GitHub Desktop.
/**************************************************************************
* *
* Colored Chat Functions for CS:GO *
* Author: exvel, Editor: Popoklopsi, Powerlord, Zipcore, Bara *
* Version: 2.0.1 *
* *
**************************************************************************/
#if defined _csgocolors_included
#endinput
#endif
#define _csgocolors_included
#define MAX_MESSAGE_LENGTH 250
#define SERVER_INDEX 0
#define NO_INDEX -1
#define NO_PLAYER -2
#define MAX_COLORS 18
enum CColors
{
Color_Default = 0,
Color_White,
Color_Darkred,
Color_Green,
Color_LightYellow,
Color_LightBlue,
Color_Olive,
Color_Lime,
Color_Red,
Color_Purple,
Color_Grey,
Color_Yellow,
Color_Silver,
Color_Blue,
Color_DarkBlue,
Color_BlueGrey,
Color_Magenta,
Color_LightRed
}
/* CColors' properties */
char CTag[][] = {
"{default}",
"{white}",
"{darkred}",
"{green}",
"{lightyellow}",
"{lightblue}",
"{olive}",
"{lime}",
"{red}",
"{purple}",
"{grey}",
"{yellow}",
"{silver}",
"{blue}",
"{darkblue}",
"{bluegrey}",
"{magenta}",
"{lightred}"
};
char CTagCode[][] = {
"\x01",
"\x01",
"\x02",
"\x04",
"\x03",
"\x03",
"\x05",
"\x06",
"\x07",
"\x03",
"\x08",
"\x09",
"\x0A",
"\x0B",
"\x0C",
"\x0D",
"\x0E",
"\x0F"
};
bool CTagReqSayText2[] = {
false,
false,
false,
false,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
};
bool CEventIsHooked = false;
bool CSkipList[MAXPLAYERS+1] = {false,...};
int CProfile_TeamIndex[MAX_COLORS] = {NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, 2, 3, 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 CProfile_SayText2 = true;
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 CPrintToChat(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 = CFormat(szCMessage, sizeof(szCMessage));
if (index == NO_INDEX)
PrintToChat(client, "%s", szCMessage);
else CSayText2(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, CPrintToChat() 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 CReplyToCommand(int client, const char[] szMessage, any ...)
{
char szCMessage[MAX_MESSAGE_LENGTH];
SetGlobalTransTarget(client);
VFormat(szCMessage, sizeof(szCMessage), szMessage, 3);
if (client == 0 || GetCmdReplySource() == SM_REPLY_TO_CONSOLE)
CRemoveTags(szCMessage, sizeof(szCMessage));
if (client == 0)
PrintToServer("%s", szCMessage);
else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE)
PrintToConsole(client, "%s", szCMessage);
else CPrintToChat(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, CPrintToChat() 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 CReplyToCommandEx(int client, int author, const char[] szMessage, any ...)
{
char szCMessage[MAX_MESSAGE_LENGTH];
SetGlobalTransTarget(client);
VFormat(szCMessage, sizeof(szCMessage), szMessage, 4);
if (client == 0 || GetCmdReplySource() == SM_REPLY_TO_CONSOLE)
CRemoveTags(szCMessage, sizeof(szCMessage));
if (client == 0)
PrintToServer("%s", szCMessage);
else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE)
PrintToConsole(client, "%s", szCMessage);
else CPrintToChatEx(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 CPrintToChatAll(const char[] szMessage, any ...)
{
char szBuffer[MAX_MESSAGE_LENGTH];
for(int i = 1; i <= MaxClients; i++)
{
if (i > 0 && IsClientInGame(i) && !IsFakeClient(i) && !CSkipList[i])
{
SetGlobalTransTarget(i);
VFormat(szBuffer, sizeof(szBuffer), szMessage, 2);
CPrintToChat(i, "%s", szBuffer);
}
CSkipList[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 CPrintToChatEx(int client, int author, const char[] szMessage, any ...)
{
if (client <= 0 || client > MaxClients)
ThrowError("Invalid client index %d", client);
if (author < 0 || author > MaxClients)
ThrowError("Invalid author index %d", author);
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, 4);
int index = CFormat(szCMessage, sizeof(szCMessage), author);
if (index == NO_INDEX)
PrintToChat(client, "%s", szCMessage);
else CSayText2(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 CPrintToChatAllEx(int author, const char[] szMessage, any ...)
{
if (author < 0 || author > MaxClients)
ThrowError("Invalid author index %d", author);
if (!IsClientInGame(author))
ThrowError("Client %d is not in game", author);
char szBuffer[MAX_MESSAGE_LENGTH];
for(int i = 1; i <= MaxClients; i++)
{
if (i > 0 && IsClientInGame(i) && !IsFakeClient(i) && !CSkipList[i])
{
SetGlobalTransTarget(i);
VFormat(szBuffer, sizeof(szBuffer), szMessage, 3);
CPrintToChatEx(i, author, "%s", szBuffer);
}
CSkipList[i] = false;
}
}
/**
* Removes color tags from the string.
*
* @param szMessage String.
* @return No return
*/
stock void CRemoveTags(char[] szMessage, int maxlength)
{
for (int i = 0; i < MAX_COLORS; i++)
ReplaceString(szMessage, maxlength, CTag[i], "", false);
ReplaceString(szMessage, maxlength, "{teamcolor}", "", false);
}
/**
* Replace the color with another color
* Handle with care!
*
* @param color color to replace.
* @param newColor color to replace with.
* @noreturn
*/
stock void CReplaceColor(CColors color, CColors newColor)
{
if (!CEventIsHooked)
{
CSetupProfile();
CEventIsHooked = true;
}
CProfile_TeamIndex[color] = CProfile_TeamIndex[newColor];
CTagReqSayText2[color] = CTagReqSayText2[newColor];
Format(CTagCode[color], sizeof(CTagCode[]), CTagCode[newColor]);
}
/**
* This function should only be used right in front of
* CPrintToChatAll or CPrintToChatAllEx 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 CSkipNextClient(int client)
{
if (client <= 0 || client > MaxClients)
ThrowError("Invalid client index %d", client);
CSkipList[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 CFormat(char[] szMessage, int maxlength, int author = NO_INDEX)
{
/* Hook event for auto profile setup on map start */
if (!CEventIsHooked)
{
HookEvent("server_spawn", CEvent_MapStart, EventHookMode_PostNoCopy);
CEventIsHooked = true;
}
int iRandomPlayer = NO_INDEX;
// On CS:GO set invisible precolor
Format(szMessage, maxlength, " %s", szMessage);
/* If author was specified replace {teamcolor} tag */
if (author != NO_INDEX)
{
if (CProfile_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}", CTagCode[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, CTag[i], false) == -1)
continue;
/* If tag doesn't need saytext2 simply replace */
else if (!CTagReqSayText2[i])
ReplaceString(szMessage, maxlength, CTag[i], CTagCode[i], false);
/* Tag needs saytext2 */
else
{
/* If saytext2 is not supported by game replace tag with green tag */
if (!CProfile_SayText2)
ReplaceString(szMessage, maxlength, CTag[i], CTagCode[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 = CFindRandomPlayerByTeam(CProfile_TeamIndex[i]);
/* If player not found replace tag with green color tag */
if (iRandomPlayer == NO_PLAYER)
ReplaceString(szMessage, maxlength, CTag[i], CTagCode[Color_Green], false);
/* If player was found simply replace */
else ReplaceString(szMessage, maxlength, CTag[i], CTagCode[i], false);
}
/* If found another team color tag throw error */
else
{
//ReplaceString(szMessage, maxlength, CTag[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 CFindRandomPlayerByTeam(int color_team)
{
if (color_team == SERVER_INDEX)
return 0;
else for(int i = 1; i <= MaxClients; 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 CSayText2(int client, int author, const char[] szMessage)
{
Handle hBuffer = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS);
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", "");
EndMessage();
}
public Action CEvent_MapStart(Event event, const char[] name, bool dontBroadcast)
{
for(int i = 1; i <= MaxClients; i++)
CSkipList[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,
* 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 int CShowActivity(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);
CRemoveTags(szBuffer, sizeof(szBuffer));
PrintToConsole(client, "%s%s\n", tag, szBuffer);
display_in_chat = true;
}
}
else
{
SetGlobalTransTarget(LANG_SERVER);
VFormat(szBuffer, sizeof(szBuffer), format, 3);
CRemoveTags(szBuffer, sizeof(szBuffer));
PrintToServer("%s%s\n", tag, szBuffer);
}
if (!value)
{
return 1;
}
for(int i = 1; i <= MaxClients; 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);
CPrintToChatEx(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);
CPrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer);
}
}
}
return 1;
}
/**
* Same as CShowActivity(), 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 CShowActivityEx(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);
CRemoveTags(szBuffer, sizeof(szBuffer));
PrintToConsole(client, "%s%s\n", tag, szBuffer);
display_in_chat = true;
}
}
else
{
SetGlobalTransTarget(LANG_SERVER);
VFormat(szBuffer, sizeof(szBuffer), format, 4);
CRemoveTags(szBuffer, sizeof(szBuffer));
PrintToServer("%s%s\n", tag, szBuffer);
}
if (!value)
return 1;
for(int i = 1; i <= MaxClients; 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);
CPrintToChatEx(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);
CPrintToChatEx(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 CShowActivity2(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.
*/
CPrintToChatEx(client, client, "%s%s", tag, szBuffer);
}
else
{
SetGlobalTransTarget(LANG_SERVER);
VFormat(szBuffer, sizeof(szBuffer), format, 4);
CRemoveTags(szBuffer, sizeof(szBuffer));
PrintToServer("%s%s\n", tag, szBuffer);
}
if (!value)
return 1;
for(int i = 1; i <= MaxClients; 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);
CPrintToChatEx(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);
CPrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer);
}
}
}
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment