Chat plugin rewrite. (#436)

This commit is contained in:
shavitush 2017-08-01 19:13:07 +03:00
parent 066f60c057
commit 8ff72fed0a
10 changed files with 658 additions and 985 deletions

View File

@ -17,6 +17,12 @@ Zones are trigger based and are very lightweight.
The zones plugin includes some less common features such as: Multiple tracks (main/bonus), zone editing (after setup), snapping zones to walls/corners/grid, zone setup using the cursor's position, configurable sprite/colors for zone types, zone tracks (main/bonus - can be extended), manual adjustments of coordinates before confirmations, teleport zones, glitch zones, no-limit zones (for styles like 400-velocity), flat/3D boxes for zone rendering, an API and more. The zones plugin includes some less common features such as: Multiple tracks (main/bonus), zone editing (after setup), snapping zones to walls/corners/grid, zone setup using the cursor's position, configurable sprite/colors for zone types, zone tracks (main/bonus - can be extended), manual adjustments of coordinates before confirmations, teleport zones, glitch zones, no-limit zones (for styles like 400-velocity), flat/3D boxes for zone rendering, an API and more.
#### shavit-chat
The chat plugin manipulates chat messages sent by players.
It includes custom chat names, tags, colors and all can be defined by the players/admins.
Admins need the chat flag, or the "shavit_chat" override (good for a donator perk).
There's a user-friendly command named !cchelp so the users can easily understand what's going on.
#### shavit-hud #### shavit-hud
The HUD plugin is `bhoptimer`'s OSD frontend. The HUD plugin is `bhoptimer`'s OSD frontend.
It shows most (if not all) of the information that the player needs to see. It shows most (if not all) of the information that the player needs to see.

View File

@ -22,6 +22,7 @@ Including a records system, map zones (start/end marks etc), bonuses, HUD with u
* [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.0/) - required for 250/260 runspeed for all weapons. * [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.0/) - required for 250/260 runspeed for all weapons.
* [Bunnyhop Statistics](https://forums.alliedmods.net/showthread.php?t=286135) - to show amount of scrolls for non-auto styles in the key display. CS:S only! * [Bunnyhop Statistics](https://forums.alliedmods.net/showthread.php?t=286135) - to show amount of scrolls for non-auto styles in the key display. CS:S only!
* [SteamWorks](https://forums.alliedmods.net/showthread.php?t=229556) - for the `{serverip}` advertisement variable. * [SteamWorks](https://forums.alliedmods.net/showthread.php?t=229556) - for the `{serverip}` advertisement variable.
* [Chat-Processor](https://github.com/Drixevel/Chat-Processor) - if you're enabling the `shavit-chat` module.
# Installation: # Installation:
1. If you want to use MySQL (**VERY RECOMMENDED**) add a database entry in addons/sourcemod/configs/databases.cfg, call it "shavit". The plugin also supports the "sqlite" driver. You can also skip this step and not modify databases.cfg. 1. If you want to use MySQL (**VERY RECOMMENDED**) add a database entry in addons/sourcemod/configs/databases.cfg, call it "shavit". The plugin also supports the "sqlite" driver. You can also skip this step and not modify databases.cfg.

View File

@ -1,110 +0,0 @@
// Use SteamID3 for a value if you want a per-client setting.
// "Custom" is for per-client settings.
// "Ranks" is for rank range settings. It is limited to 64 entries and the way you sort this file will be also sorted in-game when a player uses /ranks.
//
// Available settings:
// "rank_from" - rank range to start with
// "rank_to" - rank range to end with; you can use "infinity" if it's for every player below "rank_from".
//
// "prefix" - prefix before the name (don't add a space after it)
// "name" - custom name appearance (color from prefix will be applied here too)
// "message" - the message itself
// "clantag" - custom clan tag
//
// Global variables:
// {default} - default color
// {team} - team color
// {green} - green color
// {name} - player name
// {clan} - clan tag
// {message} - message text
//
// If you use variables that aren't compatible with the game, it might break some stuff.
// The default config will work with both CS:S and CS:GO, you can modify it for your needs.
// Use `sm_reloadchat` in your server to reload this config.
//
// For CS:S, you have the following variables available: (NOTE: The format for colors is like HTML. RRGGBBAA)
// {RGB} - like \x07, usage: "{RGB}FF0000" for red
// {RGBA} - like \x08, usage: "{RGBA}FF0000FE" for 254 alpha red
// {RGBX} - random rgb color
// {RGBAX} - random rgba color
//
// CS:GO colors:
// {team} will become purple for spectators
// {blue}
// {bluegrey}
// {darkblue}
// {darkred}
// {gold}
// {grey}
// {grey2}
// {lightgreen}
// {lightred}
// {lime}
// {orchid}
// {yellow}
//
"Chat"
{
"[U:1:204506329]" // my steamid for example, use steamid3
{
"prefix" "{green}/dev/"
"name" "{default}{team}{clan}{name}"
"clantag" "shave"
}
"-1" // lookup is due, shouldn't happen unless there's some error!
{
"rank_from" "-1"
"rank_to" "-1"
"prefix" ""
"name" "{team}{name}"
"message" "{message}"
}
"0" // unranked
{
"rank_from" "0"
"rank_to" "0"
"prefix" "[Unranked]"
"name" "{team}{name}"
"message" "{message}"
}
"1"
{
"rank_from" "1"
"rank_to" "1"
"prefix" "{green}ONE TRUE GOD"
"name" "{clan}{team}{name}"
}
"2"
{
"rank_from" "2"
"rank_to" "2"
"prefix" "LEGENDARY"
"name" "{name}"
}
"3"
{
"rank_from" "3"
"rank_to" "3"
"prefix" "HERO"
"name" "{team}{name}"
}
"4"
{
"rank_from" "4"
"rank_to" "infinity"
"prefix" "scrub!"
}
}

View File

@ -1,857 +0,0 @@
/*
* shavit's Timer - Chat
* by: shavit
*
* This file is part of shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <cstrike>
#undef REQUIRE_PLUGIN
#include <basecomm>
#include <rtler>
#include <chat-processor>
#define USES_CHAT_COLORS
#include <shavit>
#pragma newdecls required
#pragma semicolon 1
#pragma dynamic 131072
// cache
float gF_LastMessage[MAXPLAYERS+1];
char gS_Cached_Prefix[MAXPLAYERS+1][32];
char gS_Cached_Name[MAXPLAYERS+1][MAX_NAME_LENGTH*2];
char gS_Cached_Message[MAXPLAYERS+1][255];
char gS_Cached_ClanTag[MAXPLAYERS+1][32];
StringMap gSM_Custom_Prefix = null;
StringMap gSM_Custom_Name = null;
StringMap gSM_Custom_Message = null;
StringMap gSM_Custom_ClanTag = null;
int gI_TotalChatRanks = 0;
int gI_UnassignedTitle = -1;
int gI_UnrankedTitle = -1;
Dynamic gD_ChatRanks[64]; // limited to 64 chat ranks right now, i really don't think there's a need for more.
// modules
bool gB_BaseComm = false;
bool gB_RTLer = false;
bool gB_ChatProcessor = false;
// game-related
EngineVersion gEV_Type = Engine_Unknown;
public Plugin myinfo =
{
name = "[shavit] Chat",
author = "shavit",
description = "Chat handler for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "https://github.com/shavitush/bhoptimer"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
// natives
CreateNative("Shavit_FormatChat", Native_FormatChat);
// registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
RegPluginLibrary("shavit-chat");
return APLRes_Success;
}
public void OnAllPluginsLoaded()
{
if(!LibraryExists("shavit-rankings"))
{
SetFailState("shavit-rankings is required for the plugin to work.");
}
// modules
gB_BaseComm = LibraryExists("basecomm");
gB_RTLer = LibraryExists("rtler");
gB_ChatProcessor = LibraryExists("chat-processor");
}
public void OnPluginStart()
{
LoadTranslations("shavit-chat.phrases");
// game specific
gEV_Type = GetEngineVersion();
// commands
RegAdminCmd("sm_reloadchat", Command_ReloadChat, ADMFLAG_ROOT, "Reload chat config.");
RegConsoleCmd("sm_chatranks", Command_ChatRanks, "Shows a list of all the possible chat ranks.");
RegConsoleCmd("sm_ranks", Command_ChatRanks, "Shows a list of all the possible chat ranks. Alias for sm_chatranks.");
// hooks
HookEvent("player_spawn", Player_Spawn);
}
public void OnPluginEnd()
{
ResetCache();
}
public void OnMapStart()
{
LoadConfig();
}
public void OnClientPutInServer(int client)
{
gF_LastMessage[client] = GetEngineTime();
if(gI_TotalChatRanks >= 1 && gD_ChatRanks[0].IsValid)
{
gD_ChatRanks[0].GetString("prefix", gS_Cached_Prefix[client], 32);
gD_ChatRanks[0].GetString("name", gS_Cached_Name[client], MAX_NAME_LENGTH*2);
gD_ChatRanks[0].GetString("message", gS_Cached_Message[client], 255);
gD_ChatRanks[0].GetString("clantag", gS_Cached_ClanTag[client], 32);
UpdateClanTag(client);
}
}
public void OnClientSettingsChanged(int client)
{
UpdateClanTag(client);
}
void UpdateClanTag(int client)
{
if(IsValidClient(client) && strlen(gS_Cached_ClanTag[client]) > 0)
{
CS_SetClientClanTag(client, gS_Cached_ClanTag[client]);
}
}
public void OnClientAuthorized(int client, const char[] auth)
{
LoadChatCache(client);
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "basecomm"))
{
gB_BaseComm = true;
}
else if(StrEqual(name, "rtler"))
{
gB_RTLer = true;
}
else if(StrEqual(name, "chat-processor"))
{
gB_ChatProcessor = true;
}
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "basecomm"))
{
gB_BaseComm = false;
}
else if(StrEqual(name, "rtler"))
{
gB_RTLer = false;
}
else if(StrEqual(name, "chat-processor"))
{
gB_ChatProcessor = false;
}
}
public void Shavit_OnRankUpdated(int client)
{
LoadChatCache(client);
}
void LoadChatCache(int client)
{
// assign rank properties
int iRank = Shavit_GetRank(client);
int iTitle = (iRank == -1)? gI_UnassignedTitle:gI_UnrankedTitle;
if(iRank <= 0)
{
gD_ChatRanks[iTitle].GetString("prefix", gS_Cached_Prefix[client], 32);
gD_ChatRanks[iTitle].GetString("name", gS_Cached_Name[client], MAX_NAME_LENGTH*2);
gD_ChatRanks[iTitle].GetString("message", gS_Cached_Message[client], 255);
gD_ChatRanks[iTitle].GetString("clantag", gS_Cached_ClanTag[client], 255);
}
else
{
for(int i = 0; i < gI_TotalChatRanks; i++)
{
if(gD_ChatRanks[i].IsValid)
{
int iFrom = gD_ChatRanks[i].GetInt("rank_from");
int iTo = gD_ChatRanks[i].GetInt("rank_to");
if(iRank < iFrom || (iRank > iTo && iTo != -3))
{
continue;
}
gD_ChatRanks[i].GetString("prefix", gS_Cached_Prefix[client], 32);
gD_ChatRanks[i].GetString("name", gS_Cached_Name[client], MAX_NAME_LENGTH*2);
gD_ChatRanks[i].GetString("message", gS_Cached_Message[client], 255);
gD_ChatRanks[i].GetString("clantag", gS_Cached_ClanTag[client], 255);
}
}
}
char[] sAuthID = new char[32];
if(GetClientAuthId(client, AuthId_Steam3, sAuthID, 32))
{
char[] sBuffer = new char[255];
if(gSM_Custom_Prefix.GetString(sAuthID, sBuffer, 255))
{
strcopy(gS_Cached_Prefix[client], 32, sBuffer);
}
if(gSM_Custom_Name.GetString(sAuthID, sBuffer, 255))
{
strcopy(gS_Cached_Name[client], MAX_NAME_LENGTH*2, sBuffer);
}
if(gSM_Custom_Message.GetString(sAuthID, sBuffer, 255))
{
strcopy(gS_Cached_Message[client], 255, sBuffer);
}
if(gSM_Custom_ClanTag.GetString(sAuthID, sBuffer, 255))
{
strcopy(gS_Cached_ClanTag[client], 32, sBuffer);
}
}
UpdateClanTag(client);
}
void ResetCache()
{
for(int i = 0; i < 64; i++)
{
if(gD_ChatRanks[i].IsValid)
{
gD_ChatRanks[i].Dispose();
}
}
gI_TotalChatRanks = 0;
gI_UnassignedTitle = -1;
gI_UnrankedTitle = -1;
}
void LoadConfig()
{
delete gSM_Custom_Prefix;
delete gSM_Custom_Name;
delete gSM_Custom_Message;
delete gSM_Custom_ClanTag;
gSM_Custom_Prefix = new StringMap();
gSM_Custom_Name = new StringMap();
gSM_Custom_Message = new StringMap();
gSM_Custom_ClanTag = new StringMap();
ResetCache();
KeyValues kvConfig = new KeyValues("Chat");
char[] sFile = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-chat.cfg");
if(!kvConfig.ImportFromFile(sFile))
{
SetFailState("File %s could not be found or accessed.", sFile);
}
if(kvConfig.GotoFirstSubKey())
{
char[] sBuffer = new char[255];
do
{
kvConfig.GetSectionName(sBuffer, 255);
char[] sPrefix = new char[32];
kvConfig.GetString("prefix", sPrefix, 32);
char[] sName = new char[MAX_NAME_LENGTH*2];
kvConfig.GetString("name", sName, MAX_NAME_LENGTH*2);
char[] sMessage = new char[255];
kvConfig.GetString("message", sMessage, 255);
char[] sCustomClanTag = new char[32];
kvConfig.GetString("clantag", sCustomClanTag, 32);
// custom
if(StrContains(sBuffer[0], "[U:") != -1)
{
if(strlen(sPrefix) > 0)
{
gSM_Custom_Prefix.SetString(sBuffer, sPrefix);
}
if(strlen(sName) > 0)
{
gSM_Custom_Name.SetString(sBuffer, sName);
}
if(strlen(sMessage) > 0)
{
gSM_Custom_Message.SetString(sBuffer, sMessage);
}
if(strlen(sCustomClanTag) > 0)
{
gSM_Custom_ClanTag.SetString(sBuffer, sCustomClanTag);
}
}
// ranks
else
{
int iFrom = kvConfig.GetNum("rank_from", -2);
if(iFrom == -2)
{
LogError("Invalid \"rank_from\" value for \"%s\": %d or non-existant.", sBuffer, iFrom);
continue;
}
char[] sTo = new char[16];
kvConfig.GetString("rank_to", sTo, 16, "-2");
int iTo = StrEqual(sTo, "infinity", false)? -3:StringToInt(sTo);
if(iTo == -2)
{
LogError("Invalid \"rank_to\" value for \"%s\": %d or non-existant.", sBuffer, iTo);
continue;
}
gD_ChatRanks[gI_TotalChatRanks] = Dynamic();
gD_ChatRanks[gI_TotalChatRanks].SetInt("rank_from", iFrom);
gD_ChatRanks[gI_TotalChatRanks].SetInt("rank_to", iTo);
gD_ChatRanks[gI_TotalChatRanks].SetString("prefix", sPrefix, 32);
gD_ChatRanks[gI_TotalChatRanks].SetString("name", (strlen(sName) > 0)? sName:"{name}", MAX_NAME_LENGTH*2);
gD_ChatRanks[gI_TotalChatRanks].SetString("message", (strlen(sMessage) > 0)? sMessage:"{message}", 255);
gD_ChatRanks[gI_TotalChatRanks].SetString("clantag", (strlen(sCustomClanTag) > 0)? sCustomClanTag:"", 32);
if(iFrom == -1 && gI_UnassignedTitle == -1)
{
gI_UnassignedTitle = gI_TotalChatRanks;
}
else if(iFrom == 0 && gI_UnrankedTitle == -1)
{
gI_UnrankedTitle = gI_TotalChatRanks;
}
gI_TotalChatRanks++;
}
}
while(kvConfig.GotoNextKey());
}
else
{
LogError("File %s might be empty?", sFile);
}
delete kvConfig;
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i)) // late loading
{
OnClientPutInServer(i);
char[] sAuth = new char[32];
if(GetClientAuthId(i, AuthId_Steam3, sAuth, 32))
{
OnClientAuthorized(i, sAuth);
}
}
}
}
public Action Command_ChatRanks(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
// dummies
// char[] sExample = "Example."; // I tried using this variable, but it seemed to pick up "List of Chat ranks:" instead, I wonder why..
int[] clients = new int[1];
clients[0] = client;
char[] sChatMessage = new char[64];
FormatEx(sChatMessage, 64, "\x01%T", "ChatRankList", client);
ChatMessage(client, clients, 1, sChatMessage);
for(int i = gI_TotalChatRanks - 1; i >= 0; i--)
{
if(gD_ChatRanks[i].IsValid)
{
int iFrom = gD_ChatRanks[i].GetInt("rank_from");
if(iFrom <= 0)
{
continue; // don't show unranked/due-lookup 'chat ranks'
}
int iTo = gD_ChatRanks[i].GetInt("rank_to");
char[] sRankText = new char[16];
if(iFrom == iTo)
{
FormatEx(sRankText, 16, "#%d", iFrom);
}
else
{
PrintToConsole(client, "%d", iTo);
if(iTo == -3)
{
FormatEx(sRankText, 16, "#%d - ∞", iFrom, iTo);
}
else
{
FormatEx(sRankText, 16, "#%d - #%d", iFrom, iTo);
}
}
char[] sExampleMessage = new char[32];
FormatEx(sExampleMessage, 64, "\x01%T", "ExampleMessage", client);
char[] sPrefix = new char[32];
gD_ChatRanks[i].GetString("prefix", sPrefix, 32);
FormatVariables(client, sPrefix, 32, sPrefix, sExampleMessage);
char[] sName = new char[MAX_NAME_LENGTH*2];
gD_ChatRanks[i].GetString("name", sName, MAX_NAME_LENGTH*2);
FormatVariables(client, sName, MAX_NAME_LENGTH*2, sName, sExampleMessage);
char[] sMessage = new char[255];
gD_ChatRanks[i].GetString("message", sMessage, 255);
FormatVariables(client, sMessage, 255, sMessage, sExampleMessage);
char[] sBuffer = new char[300];
FormatEx(sBuffer, 300, "%s\x04[%s]\x01 %s%s %s %s %s", gEV_Type == Engine_CSGO? " ":"", sRankText, strlen(sPrefix) == 0? "\x03":"", sPrefix, sName, gEV_Type == Engine_CSGO? ":\x01":"\x01:", sMessage);
ChatMessage(client, clients, 1, sBuffer);
}
}
return Plugin_Handled;
}
public Action Command_ReloadChat(int client, int args)
{
LoadConfig();
ReplyToCommand(client, "%T", "ReloadChat", client);
return Plugin_Handled;
}
public Action OnChatMessage(int &author, ArrayList recipients, eChatFlags &flag, char[] name, char[] message, bool &bProcessColors, bool &bRemoveColors)
{
if(!gB_ChatProcessor)
{
return Plugin_Continue;
}
char[] sBuffer = new char[255];
char[] sPrefix = new char[32];
if(strlen(gS_Cached_Prefix[author]) > 0)
{
FormatVariables(author, sBuffer, 255, gS_Cached_Prefix[author], message);
int iLen = strlen(sBuffer);
sBuffer[iLen] = (iLen > 0)? ' ':'\0';
strcopy(sPrefix, 32, sBuffer);
}
char[] sName = new char[MAX_NAME_LENGTH*2];
if(strlen(gS_Cached_Name[author]) > 0)
{
FormatVariables(author, sBuffer, 255, gS_Cached_Name[author], message);
strcopy(sName, MAX_NAME_LENGTH*2, sBuffer);
}
else
{
FormatEx(sName, MAX_NAME_LENGTH*2, "\x03%N", author);
}
char[] sFormattedText = new char[MAXLENGTH_MESSAGE];
strcopy(sFormattedText, MAXLENGTH_MESSAGE, message);
// solve shitty exploits
ReplaceString(sFormattedText, MAXLENGTH_MESSAGE, "\n", "");
ReplaceString(sFormattedText, MAXLENGTH_MESSAGE, "\t", "");
ReplaceString(sFormattedText, MAXLENGTH_MESSAGE, " ", " ");
TrimString(sFormattedText);
if(strlen(gS_Cached_Message[author]) > 0)
{
FormatVariables(author, sBuffer, 255, gS_Cached_Message[author], sFormattedText);
strcopy(sFormattedText, 255, sBuffer);
}
else
{
strcopy(sFormattedText, 255, message);
}
FormatEx(name, MAXLENGTH_NAME, "%s%s%s", (gEV_Type == Engine_CSGO)? " ":"", sPrefix, sName);
strcopy(message, MAXLENGTH_MESSAGE, sFormattedText);
return Plugin_Changed;
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
if(gB_ChatProcessor || !IsValidClient(client) || !IsClientAuthorized(client) || (gB_BaseComm && BaseComm_IsClientGagged(client)))
{
return Plugin_Continue;
}
if(GetEngineTime() - gF_LastMessage[client] < 0.70)
{
return Plugin_Handled;
}
bool bTeam = StrEqual(command, "say_team");
if(bTeam || (CheckCommandAccess(client, "sm_say", ADMFLAG_CHAT) && sArgs[0] == '@'))
{
return Plugin_Handled;
}
char[] sMessage = new char[300];
strcopy(sMessage, 300, sArgs);
if(ReplaceString(sMessage[0], 4, "!", "sm_") > 0 || ReplaceString(sMessage[0], 4, "/", "sm_") > 0)
{
bool bCmd = false;
Handle hCon = FindFirstConCommand(sMessage, 300, bCmd);
if(hCon != null)
{
FindNextConCommand(hCon, sMessage, 300, bCmd);
delete hCon;
if(bCmd)
{
return Plugin_Handled;
}
}
}
gF_LastMessage[client] = GetEngineTime();
int iTeam = GetClientTeam(client);
FormatChatLine(client, sArgs, IsPlayerAlive(client), iTeam, bTeam, sMessage, 300);
int[] clients = new int[MaxClients];
int count = 0;
PrintToServer("%N: %s", client, sArgs);
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
{
if(GetClientTeam(i) == iTeam || !bTeam)
{
clients[count++] = i;
PrintToConsole(i, "%N: %s", client, sArgs);
}
}
}
ChatMessage(client, clients, count, sMessage);
return Plugin_Handled;
}
void FormatChatLine(int client, const char[] sMessage, bool bAlive, int iTeam, bool bTeam, char[] buffer, int maxlen)
{
char[] sTeam = new char[32];
char[] sTeamName = new char[32];
if(!bTeam)
{
if(iTeam == CS_TEAM_SPECTATOR)
{
FormatEx(sTeamName, 32, "%T", "TeamSpec", client);
strcopy(sTeam, 32, sTeamName);
}
}
else
{
switch(iTeam)
{
case CS_TEAM_SPECTATOR:
{
FormatEx(sTeamName, 32, "%T", "TeamSpectator", client);
strcopy(sTeam, 32, sTeamName);
}
case CS_TEAM_T:
{
FormatEx(sTeamName, 32, "%T", "TeamT", client);
strcopy(sTeam, 32, sTeamName);
}
case CS_TEAM_CT:
{
FormatEx(sTeamName, 32, "%T", "TeamCT", client);
strcopy(sTeam, 32, sTeamName);
}
}
}
char[] sAuthID = new char[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
char[] sBuffer = new char[255];
char[] sNewPrefix = new char[32];
if(strlen(gS_Cached_Prefix[client]) > 0)
{
FormatVariables(client, sBuffer, 255, gS_Cached_Prefix[client], sMessage);
int iLen = strlen(sBuffer);
sBuffer[iLen] = (iLen > 0)? ' ':'\0';
strcopy(sNewPrefix, 32, sBuffer);
}
char[] sNewName = new char[MAX_NAME_LENGTH*2];
if(strlen(gS_Cached_Name[client]) > 0)
{
FormatVariables(client, sBuffer, 255, gS_Cached_Name[client], sMessage);
strcopy(sNewName, MAX_NAME_LENGTH*2, sBuffer);
}
else
{
FormatEx(sNewName, MAX_NAME_LENGTH*2, "\x03%N", client);
}
char[] sFormattedText = new char[maxlen];
strcopy(sFormattedText, maxlen, sMessage);
// solve shitty exploits
ReplaceString(sFormattedText, maxlen, "\n", "");
ReplaceString(sFormattedText, maxlen, "\t", "");
ReplaceString(sFormattedText, maxlen, " ", " ");
TrimString(sFormattedText);
if(gB_RTLer)
{
char[][] sExploded = new char[96][96]; // fixed size from RTLer
ExplodeString(sFormattedText, " ", sExploded, 96, 96);
bool bRTLify = true;
for(int i = 0; i < 96; i++)
{
if(strlen(sExploded[i]) > 32)
{
bRTLify = false;
break;
}
}
if(bRTLify)
{
RTLify(sFormattedText, maxlen, sFormattedText);
}
}
if(strlen(gS_Cached_Message[client]) > 0)
{
FormatVariables(client, sBuffer, 255, gS_Cached_Message[client], sFormattedText);
strcopy(sFormattedText, 255, sBuffer);
}
FormatEx(buffer, maxlen, "\x01%s%s%s\x03%s%s %s %s", gEV_Type == Engine_CSGO? " ":"", (bAlive || iTeam == CS_TEAM_SPECTATOR)? "":"*DEAD* ", sTeam, sNewPrefix, sNewName, gEV_Type == Engine_CSGO? ":\x01":"\x01:", sFormattedText);
}
void FormatVariables(int client, char[] buffer, int maxlen, const char[] formattingrules, const char[] message)
{
char[] sTempFormattingRules = new char[maxlen];
strcopy(sTempFormattingRules, maxlen, formattingrules);
for(int i = 0; i < sizeof(gS_GlobalColorNames); i++)
{
ReplaceString(sTempFormattingRules, maxlen, gS_GlobalColorNames[i], gS_GlobalColors[i]);
}
if(gEV_Type == Engine_CSS)
{
ReplaceString(sTempFormattingRules, maxlen, "{RGB}", "\x07");
ReplaceString(sTempFormattingRules, maxlen, "{RGBA}", "\x08");
char[] sColorBuffer = new char[16];
do
{
Format(sColorBuffer, 16, "\x07%x%x%x", RealRandomInt(1, 255), RealRandomInt(1, 255), RealRandomInt(1, 255));
}
while(ReplaceStringEx(sTempFormattingRules, maxlen, "{RGBX}", sColorBuffer) > 0);
do
{
Format(sColorBuffer, 16, "\x08%x%x%x%x", RealRandomInt(1, 255), RealRandomInt(1, 255), RealRandomInt(1, 255), RealRandomInt(1, 255));
}
while(ReplaceStringEx(sTempFormattingRules, maxlen, "{RGBAX}", sColorBuffer) > 0);
}
else
{
for(int i = 0; i < sizeof(gS_CSGOColorNames); i++)
{
ReplaceString(sTempFormattingRules, maxlen, gS_CSGOColorNames[i], gS_CSGOColors[i]);
}
}
char[] sName = new char[MAX_NAME_LENGTH];
GetClientName(client, sName, MAX_NAME_LENGTH);
ReplaceString(sTempFormattingRules, maxlen, "{name}", sName);
char[] sCustomClanTag = new char[32];
CS_GetClientClanTag(client, sCustomClanTag, 32);
int iLen = strlen(sCustomClanTag);
sCustomClanTag[iLen] = (iLen > 0)? ' ':'\0';
ReplaceString(sTempFormattingRules, maxlen, "{clan}", sCustomClanTag);
ReplaceString(sTempFormattingRules, maxlen, "{message}", message);
strcopy(buffer, maxlen, sTempFormattingRules);
}
void ChatMessage(int from, int[] clients, int count, const char[] sMessage)
{
Handle hSayText2 = StartMessage("SayText2", clients, count);
if(hSayText2 != null)
{
if(gEV_Type == Engine_CSGO)
{
PbSetInt(hSayText2, "ent_idx", from);
PbSetBool(hSayText2, "chat", true);
PbSetString(hSayText2, "msg_name", sMessage);
for(int i = 1; i <= 4; i++)
{
PbAddString(hSayText2, "params", "");
}
}
else
{
BfWriteByte(hSayText2, from);
BfWriteByte(hSayText2, true);
BfWriteString(hSayText2, sMessage);
}
EndMessage();
}
}
public void Player_Spawn(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if(!IsFakeClient(client))
{
LoadChatCache(client);
}
}
public int Native_FormatChat(Handle handler, int numParams)
{
int client = GetNativeCell(1);
if(!IsValidClient(client))
{
ThrowNativeError(200, "Invalid client index %d", client);
return -1;
}
char[] sMessage = new char[255];
GetNativeString(2, sMessage, 255);
char[] sBuffer = new char[300];
FormatChatLine(client, sMessage, IsPlayerAlive(client), GetClientTeam(client), view_as<bool>(GetNativeCell(3)), sBuffer, 300);
int maxlength = GetNativeCell(5);
return SetNativeString(6, sBuffer, maxlength);
}
// from SMLib
int RealRandomInt(int min, int max)
{
int random = GetURandomInt();
if(random == 0)
{
random++;
}
return RoundToCeil(float(random) / (float(2147483647) / float(max - min + 1))) + min - 1;
}

View File

@ -0,0 +1,79 @@
#if defined _chat_processor_included
#endinput
#endif
#define _chat_processor_included
//Globals
#define MAXLENGTH_FLAG 32
#define MAXLENGTH_NAME 128
#define MAXLENGTH_MESSAGE 128
#define MAXLENGTH_BUFFER 255
//Natives
/**
* Retrieves the current format string assigned from a flag string.
* Example: "Cstrike_Chat_All" = "{1} : {2}"
* You can find the config formats in either the translations or the configs.
*
* param sFlag Flag string to retrieve the format string from.
* param sBuffer Format string from the flag string.
* param iSize Size of the format string buffer.
*
* noreturn
**/
native void ChatProcessor_GetFlagFormatString(const char[] sFlag, char[] sBuffer, int iSize);
//Forwards
/**
* Called while sending a chat message before It's sent.
* Limits on the name and message strings can be found above.
*
* param author Author that created the message.
* param recipients Array of clients who will receive the message.
* param flagstring Flag string to determine the type of message.
* param name Name string of the author to be pushed.
* param message Message string from the author to be pushed.
* param processcolors Toggle to process colors in the buffer strings.
* param removecolors Toggle to remove colors in the buffer strings. (Requires bProcessColors = true)
*
* return types
* - Plugin_Continue Stops the message.
* - Plugin_Stop Stops the message.
* - Plugin_Changed Fires the post-forward below and prints out a message.
* - Plugin_Handled Fires the post-forward below but doesn't print a message.
**/
forward Action CP_OnChatMessage(int& author, ArrayList recipients, char[] flagstring, char[] name, char[] message, bool& processcolors, bool& removecolors);
/**
* Called after the chat message is sent to the designated clients by the author.
*
* param author Author that sent the message.
* param recipients Array of clients who received the message.
* param flagstring Flag string to determine the type of message.
* param formatstring Format string used in the message based on the flag string.
* param name Name string of the author.
* param message Message string from the author.
* param processcolors Check if colors were processed in the buffer strings.
* param removecolors Check if colors were removed from the buffer strings.
*
* noreturn
**/
forward void CP_OnChatMessagePost(int author, ArrayList recipients, const char[] flagstring, const char[] formatstring, const char[] name, const char[] message, bool processcolors, bool removecolors);
#if !defined REQUIRE_PLUGIN
public __pl_chat_processor_SetNTVOptional()
{
MarkNativeAsOptional("ChatProcessor_GetFlagFormatString");
}
#endif
public SharedPlugin __pl_chat_processor =
{
name = "chat-processor",
file = "chat-processor.smx",
#if defined REQUIRE_PLUGIN
required = 1
#else
required = 0
#endif
};

View File

@ -803,21 +803,6 @@ native int Shavit_GetRankedPlayers();
*/ */
native int Shavit_ForceHUDUpdate(int client, bool spectators); native int Shavit_ForceHUDUpdate(int client, bool spectators);
/**
* Formats chats exactly like the chat handler does.
* Takes team, alive status, rank and all those stuff into account.
* Called from shavit-chat
*
* @param client Client index.
* @param message Message to use.
* @param team Simulate a team chat message?
* @param buffer Buffer to store the formatted line on.
* @param maxlen Length of 'buffer'
* @error Error code 200 if client isn't valid.
* @return -1 on error, SP_ERROR_NONE on success.
*/
native int Shavit_FormatChat(int client, const char[] message, const bool team, char[] buffer, int maxlen);
/** /**
* Opens the stats menu for a client. * Opens the stats menu for a client.
* *

507
scripting/shavit-chat.sp Normal file
View File

@ -0,0 +1,507 @@
/*
* shavit's Timer - Chat
* by: shavit
*
* This file is part of shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Note: For donator perks, give donators a custom flag and then override it to have "shavit_chat".
#include <sourcemod>
#include <chat-processor>
#undef REQUIRE_PLUGIN
#define USES_CHAT_COLORS
#include <shavit>
// database
Database gH_SQL = null;
char gS_MySQLPrefix[32];
// cache
EngineVersion gEV_Type = Engine_Unknown;
bool gB_AllowCustom[MAXPLAYERS+1];
bool gB_NameEnabled[MAXPLAYERS+1];
char gS_CustomName[MAXPLAYERS+1][128];
bool gB_MessageEnabled[MAXPLAYERS+1];
char gS_CustomMessage[MAXPLAYERS+1][16];
public void OnPluginStart()
{
gEV_Type = GetEngineVersion();
LoadTranslations("shavit-common.phrases");
LoadTranslations("shavit-chat.phrases");
RegConsoleCmd("sm_cchelp", Command_CCHelp, "Provides help with setting a custom chat name/message color.");
RegConsoleCmd("sm_ccname", Command_CCName, "Toggles/sets a custom chat name. Usage: sm_ccname <text> or sm_ccname \"off\" to disable.");
RegConsoleCmd("sm_ccmsg", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmsg <color> or sm_ccmsg \"off\" to disable.");
RegConsoleCmd("sm_ccmessage", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmessage <color> or sm_ccmessage \"off\" to disable.");
RegAdminCmd("sm_cclist", Command_CCList, ADMFLAG_CHAT, "Print the custom chat setting of all online players.");
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && !IsFakeClient(i))
{
OnClientPostAdminCheck(i);
}
}
if(LibraryExists("shavit"))
{
Shavit_GetDB(gH_SQL);
SQL_SetPrefix();
SetSQLInfo();
}
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "shavit"))
{
Shavit_GetDB(gH_SQL);
SQL_SetPrefix();
SetSQLInfo();
}
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "shavit"))
{
gH_SQL = null;
}
}
public void Shavit_OnDatabaseLoaded(Database db)
{
gH_SQL = db;
}
public Action CheckForSQLInfo(Handle Timer)
{
return SetSQLInfo();
}
Action SetSQLInfo()
{
if(gH_SQL == null)
{
Shavit_GetDB(gH_SQL);
CreateTimer(0.5, CheckForSQLInfo);
}
else
{
SQL_DBConnect();
return Plugin_Stop;
}
return Plugin_Continue;
}
void SQL_SetPrefix()
{
char[] sFile = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt");
File fFile = OpenFile(sFile, "r");
if(fFile == null)
{
SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it.");
}
char[] sLine = new char[PLATFORM_MAX_PATH*2];
while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH*2))
{
TrimString(sLine);
strcopy(gS_MySQLPrefix, 32, sLine);
break;
}
delete fFile;
}
public void OnClientDisconnect(int client)
{
gB_AllowCustom[client] = false;
}
public void OnClientPutInServer(int client)
{
gB_AllowCustom[client] = false;
gB_NameEnabled[client] = false;
strcopy(gS_CustomName[client], 128, "");
gB_MessageEnabled[client] = false;
strcopy(gS_CustomMessage[client], 128, "");
}
public void OnClientPostAdminCheck(int client)
{
gB_AllowCustom[client] = CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT);
if(gH_SQL != null)
{
LoadFromDatabase(client);
}
}
public Action Command_CCHelp(int client, int args)
{
if(client == 0)
{
ReplyToCommand(client, "%t", "NoConsole");
return Plugin_Handled;
}
Shavit_PrintToChat(client, "%T", "CheckConsole", client);
PrintToConsole(client, "%T\n", "CCHelp_Intro", client);
PrintToConsole(client, "%T", "CCHelp_Generic", client);
PrintToConsole(client, "%T", "CCHelp_GenericVariables", client);
if(gEV_Type == Engine_CSS)
{
PrintToConsole(client, "%T", "CCHelp_CSS_1", client);
PrintToConsole(client, "%T", "CCHelp_CSS_2", client);
}
else
{
PrintToConsole(client, "%T", "CCHelp_CSGO_1", client);
}
return Plugin_Handled;
}
public Action Command_CCName(int client, int args)
{
if(client == 0)
{
ReplyToCommand(client, "%t", "NoConsole");
return Plugin_Handled;
}
if(!gB_AllowCustom[client])
{
Shavit_PrintToChat(client, "%T", "NoCommandAccess", client);
return Plugin_Handled;
}
char[] sArgs = new char[128];
GetCmdArgString(sArgs, 128);
TrimString(sArgs);
FormatColors(sArgs, 128, true, true);
if(args == 0 || strlen(sArgs) == 0)
{
Shavit_PrintToChat(client, "%T", "ArgumentsMissing", client, "sm_ccname <text>");
Shavit_PrintToChat(client, "%T", "ChatCurrent", client, sArgs);
return Plugin_Handled;
}
else if(StrEqual(sArgs, "off"))
{
Shavit_PrintToChat(client, "%T", "NameOff", client, sArgs);
gB_NameEnabled[client] = false;
SaveToDatabase(client);
return Plugin_Handled;
}
Shavit_PrintToChat(client, "%T", "ChatUpdated", client);
gB_NameEnabled[client] = true;
strcopy(gS_CustomName[client], 128, sArgs);
SaveToDatabase(client);
return Plugin_Handled;
}
public Action Command_CCMessage(int client, int args)
{
if(client == 0)
{
ReplyToCommand(client, "%t", "NoConsole");
return Plugin_Handled;
}
if(!gB_AllowCustom[client])
{
Shavit_PrintToChat(client, "%T", "NoCommandAccess", client);
return Plugin_Handled;
}
char[] sArgs = new char[32];
GetCmdArgString(sArgs, 32);
TrimString(sArgs);
FormatColors(sArgs, 32, true, true);
if(args == 0 || strlen(sArgs) == 0)
{
Shavit_PrintToChat(client, "%T", "ArgumentsMissing", client, "sm_ccmsg <text>");
Shavit_PrintToChat(client, "%T", "ChatCurrent", client, sArgs);
return Plugin_Handled;
}
else if(StrEqual(sArgs, "off"))
{
Shavit_PrintToChat(client, "%T", "MessageOff", client, sArgs);
gB_MessageEnabled[client] = false;
SaveToDatabase(client);
return Plugin_Handled;
}
Shavit_PrintToChat(client, "%T", "ChatUpdated", client);
gB_MessageEnabled[client] = true;
strcopy(gS_CustomMessage[client], 16, sArgs);
SaveToDatabase(client);
return Plugin_Handled;
}
public Action Command_CCList(int client, int args)
{
ReplyToCommand(client, "%T", "CheckConsole", client);
for(int i = 1; i <= MaxClients; i++)
{
if(gB_AllowCustom[i])
{
PrintToConsole(client, "%N (%d/%d) (name: \"%s\"; message: \"%s\")", i, i, GetClientUserId(i), gS_CustomName[i], gS_CustomMessage[i])
}
}
return Plugin_Handled;
}
public Action CP_OnChatMessage(int &author, ArrayList recipients, char[] flagstring, char[] name, char[] message, bool &processcolors, bool &removecolors)
{
if(!gB_AllowCustom[author])
{
return Plugin_Continue;
}
Action retvalue = Plugin_Continue;
if(gB_NameEnabled[author] && strlen(gS_CustomName[author]) > 0)
{
char[] sName = new char[MAX_NAME_LENGTH];
GetClientName(author, sName, MAX_NAME_LENGTH);
ReplaceString(gS_CustomName[author], MAXLENGTH_NAME, "{name}", sName);
strcopy(name, MAXLENGTH_NAME, gS_CustomName[author]);
FormatRandom(name, MAXLENGTH_NAME);
retvalue = Plugin_Changed;
}
if(gB_MessageEnabled[author] && strlen(gS_CustomMessage[author]) > 0)
{
Format(message, MAXLENGTH_MESSAGE, "%s%s", gS_CustomMessage[author], message);
FormatRandom(message, MAXLENGTH_MESSAGE);
retvalue = Plugin_Changed;
}
removecolors = true;
processcolors = false;
return retvalue;
}
void FormatColors(char[] buffer, int size, bool colors, bool escape)
{
if(colors)
{
for(int i = 0; i < sizeof(gS_GlobalColorNames); i++)
{
ReplaceString(buffer, size, gS_GlobalColorNames[i], gS_GlobalColors[i]);
}
for(int i = 0; i < sizeof(gS_CSGOColorNames); i++)
{
ReplaceString(buffer, size, gS_CSGOColorNames[i], gS_CSGOColors[i]);
}
ReplaceString(buffer, size, "^", "\x07");
ReplaceString(buffer, size, "{RGB}", "\x07");
ReplaceString(buffer, size, "&", "\x08");
ReplaceString(buffer, size, "{RGBA}", "\x08");
}
if(escape)
{
ReplaceString(buffer, size, "%%", "");
}
}
void FormatRandom(char[] buffer, int size)
{
char[] temp = new char[8];
do
{
int color = ((RealRandomInt(0, 255) & 0xFF) << 16);
color |= ((RealRandomInt(0, 255) & 0xFF) << 8);
color |= (RealRandomInt(0, 255) & 0xFF);
FormatEx(temp, 16, "\x07%06X", color);
}
while(ReplaceStringEx(buffer, size, "{rand}", temp) > 0);
}
int RealRandomInt(int min, int max)
{
int random = GetURandomInt();
if(random == 0)
{
random++;
}
return (RoundToCeil(float(random) / (float(2147483647) / float(max - min + 1))) + min - 1);
}
void SQL_DBConnect()
{
if(gH_SQL != null)
{
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%schat` (`auth` VARCHAR(32) NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128), `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16), PRIMARY KEY (`auth`));", gS_MySQLPrefix);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
}
}
public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer error! Chat table creation failed. Reason: %s", error);
return;
}
for(int i = 1; i <= MaxClients; i++)
{
if(gB_AllowCustom[i])
{
LoadFromDatabase(i);
}
}
}
void SaveToDatabase(int client)
{
char[] sAuthID3 = new char[32];
if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
{
return;
}
int iLength = ((strlen(gS_CustomName[client]) * 2) + 1);
char[] sEscapedName = new char[iLength];
gH_SQL.Escape(gS_CustomName[client], sEscapedName, iLength);
iLength = ((strlen(gS_CustomMessage[client]) * 2) + 1);
char[] sEscapedMessage = new char[iLength];
gH_SQL.Escape(gS_CustomMessage[client], sEscapedMessage, iLength);
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "REPLACE INTO %schat (auth, name, ccname, message, ccmessage) VALUES ('%s', %d, '%s', %d, '%s');", gS_MySQLPrefix, sAuthID3, gB_NameEnabled[client], sEscapedName, gB_MessageEnabled[client], sEscapedMessage);
gH_SQL.Query(SQL_UpdateUser_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_UpdateUser_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer error! Failed to insert chat data. Reason: %s", error);
return;
}
}
void LoadFromDatabase(int client)
{
char[] sAuthID3 = new char[32];
if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
{
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "SELECT name, ccname, message, ccmessage FROM %schat WHERE auth = '%s';", gS_MySQLPrefix, sAuthID3);
gH_SQL.Query(SQL_GetChat_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
}
public void SQL_GetChat_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (Chat cache update) SQL query failed. Reason: %s", error);
return;
}
int client = GetClientFromSerial(data);
if(client == 0)
{
return;
}
while(results.FetchRow())
{
gB_NameEnabled[client] = view_as<bool>(results.FetchInt(0));
results.FetchString(1, gS_CustomName[client], 128);
gB_MessageEnabled[client] = view_as<bool>(results.FetchInt(2));
results.FetchString(3, gS_CustomMessage[client], 16);
}
}

View File

@ -190,9 +190,6 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
public void OnPluginStart() public void OnPluginStart()
{ {
LoadTranslations("shavit-common.phrases");
LoadTranslations("shavit-misc.phrases");
// cache // cache
gEV_Type = GetEngineVersion(); gEV_Type = GetEngineVersion();
@ -262,6 +259,8 @@ public void OnPluginStart()
// phrases // phrases
LoadTranslations("common.phrases"); LoadTranslations("common.phrases");
LoadTranslations("shavit-common.phrases");
LoadTranslations("shavit-misc.phrases");
// advertisements // advertisements
gA_Advertisements = new ArrayList(300); gA_Advertisements = new ArrayList(300);

View File

@ -0,0 +1,49 @@
"Phrases"
{
// ---------- Commands ---------- //
"ChatUpdated"
{
"en" "Setting updated."
}
"ChatCurrent"
{
"#format" "{1:s}"
"en" "Current setting: {1}"
}
"NameOff"
{
"en" "Custom chat name is now off."
}
"MessageOff"
{
"en" "Custom chat text color is now off."
}
"CheckConsole"
{
"en" "Check your console."
}
"CCHelp_Intro"
{
"en" "- You have access to custom chat.\nUsage information:"
}
"CCHelp_Generic"
{
"en" "- !ccname can be used to change your custom chat name. Use \"!ccname off\" to toggle it off.\n- !ccmsg can be used to change your custom message prefix/color. Use \"!ccmsgg off\" to toggle it off.\nThere are custom variables, such as:"
}
"CCHelp_GenericVariables"
{
"en" "- {name} - your in-game name.\n- {rand} - a random color.\n- {team} - your team color.\n- {green} - green color."
}
"CCHelp_CSS_1"
{
"en" "- To use a custom color, write ^RRGGBB (HEX/HTML colors). For example, ^FFFFFF is white and ^000000 is black."
}
"CCHelp_CSS_2"
{
"en" "- You can also use a set alpha (opacity in HEX, where FF is 255). &RRGGBBAA. For example, &FFFFFF7F is 127 alpha, so all text after the color will have 50% opacity."
}
"CCHelp_CSGO_1"
{
"en" "- The following colors are also available: {blue}, {bluegrey}, {darkblue}, {darkred}, {gold}, {grey}, {grey2}, {lightgreen}, {lightred}, {lime}, {orchid}, {yellow} and {palered}."
}
}

View File

@ -17,4 +17,18 @@
{ {
"en" "Bonus" "en" "Bonus"
} }
// ---------- Commands ---------- //
"NoCommandAccess"
{
"en" "You do not have access to this command."
}
"NoConsole"
{
"en" "Run this command from inside the game."
}
"ArgumentsMissing"
{
"#format" "{1:s}"
"en" "Usage: {1}"
}
} }