diff --git a/GlowColors/scripting/GlowColors.sp b/GlowColors/scripting/GlowColors.sp index d48f8ca..280b52a 100644 --- a/GlowColors/scripting/GlowColors.sp +++ b/GlowColors/scripting/GlowColors.sp @@ -1,3 +1,6 @@ +#pragma semicolon 1 +#pragma newdecls required + #include #include #include @@ -7,9 +10,6 @@ #include #define REQUIRE_PLUGIN -#pragma semicolon 1 -#pragma newdecls required - public Plugin myinfo = { name = "GlowColors", @@ -334,12 +334,12 @@ public Action Timer_ApplyGlowColor(Handle timer, int serial) ApplyGlowColor(client); } -public int ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) +public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) { ApplyGlowColor(client); } -public int ZR_OnClientHumanPost(int client, bool respawn, bool protect) +public void ZR_OnClientHumanPost(int client, bool respawn, bool protect) { ApplyGlowColor(client); } diff --git a/KnifeAlert/scripting/KnifeAlert.sp b/KnifeAlert/scripting/KnifeAlert.sp index 00e875f..1afa7c7 100644 --- a/KnifeAlert/scripting/KnifeAlert.sp +++ b/KnifeAlert/scripting/KnifeAlert.sp @@ -1,9 +1,8 @@ #pragma semicolon 1 +#pragma newdecls required #include -#include "morecolors.inc" - -#pragma newdecls required +#include Handle g_hCVar_NotificationTime = INVALID_HANDLE; char g_sAttackerSID[MAXPLAYERS + 1][32]; diff --git a/SelfMute/scripting/SelfMute.sp b/SelfMute/scripting/SelfMute.sp index bace2f4..4d2c4c6 100644 --- a/SelfMute/scripting/SelfMute.sp +++ b/SelfMute/scripting/SelfMute.sp @@ -144,12 +144,12 @@ public void Event_TeamChange(Handle event, const char[] name, bool dontBroadcast UpdateSpecialMutesOtherClients(client); } -public int ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) +public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) { UpdateSpecialMutesOtherClients(client); } -public int ZR_OnClientHumanPost(int client, bool respawn, bool protect) +public void ZR_OnClientHumanPost(int client, bool respawn, bool protect) { UpdateSpecialMutesOtherClients(client); } diff --git a/StopSound/scripting/StopSound.sp b/StopSound/scripting/StopSound.sp index 4f66adb..633ca13 100644 --- a/StopSound/scripting/StopSound.sp +++ b/StopSound/scripting/StopSound.sp @@ -1,11 +1,10 @@ #pragma semicolon 1 +#pragma newdecls required #include #include -#include "morecolors.inc" -#undef REQUIRE_PLUGIN +#include -#pragma newdecls required #define PLUGIN_VERSION "1.3.0" bool g_bStopSound[MAXPLAYERS+1]; diff --git a/compile-all.py b/compile-all.py index 9a4b113..e73254d 100755 --- a/compile-all.py +++ b/compile-all.py @@ -10,7 +10,7 @@ if __name__ == "__main__": Plugins = [] Path, Directories, Files = next(os.walk(".")) for Directory in Directories: - if Directory != ".git" and Directory != "include" and Directory != "includes" and Directory != "plugins": + if not Directory.startswith(".") and Directory != "include" and Directory != "includes" and Directory != "plugins": Plugins.append(Directory) for Plugin in Plugins: diff --git a/custom-chatcolors/scripting/custom-chatcolors.sp b/custom-chatcolors/scripting/custom-chatcolors.sp index 3821ce1..94041bd 100644 --- a/custom-chatcolors/scripting/custom-chatcolors.sp +++ b/custom-chatcolors/scripting/custom-chatcolors.sp @@ -1,13 +1,11 @@ #pragma semicolon 1 +#pragma newdecls required #include #include -#include +#include //#undef REQUIRE_PLUGIN #include - -#pragma newdecls required - #include #define PLUGIN_VERSION "6.1.4" @@ -2589,7 +2587,7 @@ public Action Hook_UserMessage(UserMsg msg_id, Handle bf, const players[], int p if (!g_msgAuthor || HasFlag(g_msgAuthor, Admin_Generic)) { - CReplaceColorCodes(g_msgText, g_msgAuthor, false, sizeof(g_msgText)); + CFormatColor(g_msgText, sizeof(g_msgText), g_msgAuthor); } if (!bIsAction) diff --git a/includes/AsyncSocket.inc b/includes/AsyncSocket.inc new file mode 100644 index 0000000..a662238 --- /dev/null +++ b/includes/AsyncSocket.inc @@ -0,0 +1,63 @@ +#if defined _AsyncSocket_included + #endinput +#endif +#define _AsyncSocket_included + +typedef AsyncSocketConnectCallback = function void(AsyncSocket socket); + +typedef AsyncSocketErrorCallback = function void(AsyncSocket socket, int error, const char[] errorName); + +typedef AsyncSocketDataCallback = function void(AsyncSocket socket, const char[] data, const int size); + +methodmap AsyncSocket < Handle { + public native AsyncSocket(); + + public native bool Connect(const char[] host, const int port); + + public native bool Listen(const char[] host, const int port); + + public native bool Write(const char[] data, int length = -1); + + public bool WriteNull(const char[] data) + { + this.Write(data, strlen(data) + 1); + } + + public native bool SetConnectCallback(AsyncSocketConnectCallback callback); + + public native bool SetErrorCallback(AsyncSocketErrorCallback callback); + + public native bool SetDataCallback(AsyncSocketDataCallback callback); +} + +/** + * Do not edit below this line! + */ +public Extension __ext_AsyncSocket = +{ + name = "AsyncSocket", + file = "AsyncSocket.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public __ext_AsyncSocket_SetNTVOptional() +{ + MarkNativeAsOptional("AsyncSocket.AsyncSocket"); + MarkNativeAsOptional("AsyncSocket.Connect"); + MarkNativeAsOptional("AsyncSocket.Listen"); + MarkNativeAsOptional("AsyncSocket.Write"); + MarkNativeAsOptional("AsyncSocket.SetConnectCallback"); + MarkNativeAsOptional("AsyncSocket.SetErrorCallback"); + MarkNativeAsOptional("AsyncSocket.SetDataCallback"); +} +#endif diff --git a/includes/basic.inc b/includes/basic.inc new file mode 100644 index 0000000..982dcbb --- /dev/null +++ b/includes/basic.inc @@ -0,0 +1,116 @@ +/** + * ============================================================================= + * Dynamic for SourceMod (C)2016 Matthew J Dunn. All rights reserved. + * ============================================================================= + * + * 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 . + * + */ + +#if defined _dynamic_basic_included + #endinput +#endif +#define _dynamic_basic_included + +/* + This methodmap is based on the Dynamic methodmap while using a StringMap methodmap + for implementation. This methodmap doesn't implement the full features of the Dynamic + methodmap (type conversion, object naming, plugin sharing, ect). This methodmap can + be used for basic storage using the standard Dynamic methodmap Methods. + + Please see '\scripting\dynamic\examples\basic\' for an example usage of this methodmap +*/ + +methodmap Basic < StringMap +{ + public Basic() + { + return view_as(new StringMap()); + } + + public int GetInt(const char[] membername, int defaultvalue=-1) + { + int value; + if (this.GetValue(membername, value)) + return value; + + return defaultvalue; + } + + public void SetInt(const char[] membername, int value) + { + this.SetValue(membername, value); + } + + public bool GetBool(const char[] membername, bool defaultvalue=false) + { + bool value; + if (this.GetValue(membername, value)) + return value; + + return defaultvalue; + } + + public void SetBool(const char[] membername, bool value) + { + this.SetValue(membername, value); + } + + public float GetFloat(const char[] membername, float defaultvalue=-1.0) + { + float value; + if (this.GetValue(membername, value)) + return value; + + return defaultvalue; + } + + public void SetFloat(const char[] membername, float value) + { + this.SetValue(membername, value); + } + + public bool GetString(const char[] membername, char[] buffer, int length) + { + return this.GetString(membername, buffer, length); + } + + public void SetString(const char[] membername, const char[] value) + { + this.SetString(membername, value); + } + + public Handle GetHandle(const char[] membername) + { + Handle value; + if (this.GetValue(membername, value)) + return value; + + return null; + } + + public void SetHandle(const char[] membername, Handle value) + { + this.SetValue(membername, value); + } + + public bool GetVector(const char[] membername, float[3] vector) + { + return this.GetArray(membername, vector, sizeof(vector)); + } + + public void SetVector(const char[] membername, const float[3] value) + { + this.SetArray(membername, value, sizeof(value)); + } +} diff --git a/includes/colors.inc b/includes/colors.inc deleted file mode 100644 index 3d48924..0000000 --- a/includes/colors.inc +++ /dev/null @@ -1,539 +0,0 @@ -/************************************************************************** - * * - * Colored Chat Functions * - * Author: exvel, Editor: Popoklopsi, Powerlord, Bara * - * Version: 1.1.3 * - * * - **************************************************************************/ - - -#if defined _colors_included - #endinput -#endif -#define _colors_included - -#define MAX_MESSAGE_LENGTH 250 -#define MAX_COLORS 12 - -#define SERVER_INDEX 0 -#define NO_INDEX -1 -#define NO_PLAYER -2 - -enum 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 -} - -/* Colors' properties */ -new String:CTag[][] = {"{default}", "{darkred}", "{green}", "{lightgreen}", "{red}", "{blue}", "{olive}", "{lime}", "{lightred}", "{purple}", "{grey}", "{orange}"}; -new String:CTagCode[][] = {"\x01", "\x02", "\x04", "\x03", "\x03", "\x03", "\x05", "\x06", "\x07", "\x03", "\x08", "\x09"}; -new bool:CTagReqSayText2[] = {false, false, false, true, true, true, false, false, false, false, false, false}; -new bool:CEventIsHooked = false; -new bool:CSkipList[MAXPLAYERS+1] = {false,...}; - -/* Game default profile */ -new bool:CProfile_Colors[] = {true, false, true, false, false, false, false, false, false, false, false, false}; -new CProfile_TeamIndex[] = {NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX}; -new bool:CProfile_SayText2 = false; - -/** - * 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 CPrintToChat(client, const String:szMessage[], any:...) -{ - if (client <= 0 || client > MaxClients) - ThrowError("Invalid client index %d", client); - - if (!IsClientInGame(client)) - ThrowError("Client %d is not in game", client); - - decl String:szBuffer[MAX_MESSAGE_LENGTH]; - decl String:szCMessage[MAX_MESSAGE_LENGTH]; - - SetGlobalTransTarget(client); - - Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); - VFormat(szCMessage, sizeof(szCMessage), szBuffer, 3); - - new index = CFormat(szCMessage, sizeof(szCMessage)); - - if (index == NO_INDEX) - PrintToChat(client, "%s", szCMessage); - else - CSayText2(client, index, szCMessage); -} - -stock CReplyToCommand(client, const String:szMessage[], any:...) -{ - - decl String:szCMessage[MAX_MESSAGE_LENGTH]; - VFormat(szCMessage, sizeof(szCMessage), szMessage, 3); - - if (client == 0) - { - CRemoveTags(szCMessage, sizeof(szCMessage)); - PrintToServer("%s", szCMessage); - } - else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) - { - CRemoveTags(szCMessage, sizeof(szCMessage)); - PrintToConsole(client, "%s", szCMessage); - } - else - { - CPrintToChat(client, "%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 CPrintToChatAll(const String:szMessage[], any:...) -{ - decl String:szBuffer[MAX_MESSAGE_LENGTH]; - - for (new i = 1; i <= MaxClients; i++) - { - if (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 CPrintToChatEx(client, author, const String: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); - - decl String:szBuffer[MAX_MESSAGE_LENGTH]; - decl String:szCMessage[MAX_MESSAGE_LENGTH]; - - SetGlobalTransTarget(client); - - Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); - VFormat(szCMessage, sizeof(szCMessage), szBuffer, 4); - - new 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 CPrintToChatAllEx(author, const String:szMessage[], any:...) -{ - if (author < 0 || author > MaxClients) - ThrowError("Invalid client index %d", author); - - if (!IsClientInGame(author)) - ThrowError("Client %d is not in game", author); - - decl String:szBuffer[MAX_MESSAGE_LENGTH]; - - for (new i = 1; i <= MaxClients; i++) - { - if (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 CRemoveTags(String:szMessage[], maxlength) -{ - for (new i = 0; i < MAX_COLORS; i++) - ReplaceString(szMessage, maxlength, CTag[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 CColorAllowed(Colors:color) -{ - if (!CEventIsHooked) - { - CSetupProfile(); - - CEventIsHooked = true; - } - - return CProfile_Colors[color]; -} - -/** - * Replace the color with another color - * Handle with care! - * - * @param color color to replace. - * @param newColor color to replace with. - * @noreturn - */ -stock CReplaceColor(Colors:color, Colors:newColor) -{ - if (!CEventIsHooked) - { - CSetupProfile(); - - CEventIsHooked = true; - } - - CProfile_Colors[color] = CProfile_Colors[newColor]; - 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 CSkipNextClient(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 CFormat(String:szMessage[], maxlength, author=NO_INDEX) -{ - decl String:szGameName[30]; - - GetGameFolderName(szGameName, sizeof(szGameName)); - - /* Hook event for auto profile setup on map start */ - if (!CEventIsHooked) - { - CSetupProfile(); - HookEvent("server_spawn", CEvent_MapStart, EventHookMode_PostNoCopy); - - CEventIsHooked = true; - } - - new iRandomPlayer = NO_INDEX; - - // On CS:GO set invisible precolor - if (StrEqual(szGameName, "csgo", false)) - Format(szMessage, maxlength, " \x01\x0B\x01%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 (new i = 0; i < MAX_COLORS; i++) - { - /* If tag not found - skip */ - if (StrContains(szMessage, CTag[i], false) == -1) - continue; - - /* If tag is not supported by game replace it with green tag */ - else if (!CProfile_Colors[i]) - ReplaceString(szMessage, maxlength, CTag[i], CTagCode[Color_Green], false); - - /* 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 CFindRandomPlayerByTeam(color_team) -{ - if (color_team == SERVER_INDEX) - return 0; - else - { - for (new i = 1; i <= MaxClients; i++) - { - if (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 CSayText2(client, author, const String:szMessage[]) -{ - new 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 CSetupProfile() -{ - decl String:szGameName[30]; - GetGameFolderName(szGameName, sizeof(szGameName)); - - if (StrEqual(szGameName, "cstrike", false)) - { - CProfile_Colors[Color_Lightgreen] = true; - CProfile_Colors[Color_Red] = true; - CProfile_Colors[Color_Blue] = true; - CProfile_Colors[Color_Olive] = true; - CProfile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; - CProfile_TeamIndex[Color_Red] = 2; - CProfile_TeamIndex[Color_Blue] = 3; - CProfile_SayText2 = true; - } - else if (StrEqual(szGameName, "csgo", false)) - { - CProfile_Colors[Color_Red] = true; - CProfile_Colors[Color_Blue] = true; - CProfile_Colors[Color_Olive] = true; - CProfile_Colors[Color_Darkred] = true; - CProfile_Colors[Color_Lime] = true; - CProfile_Colors[Color_Lightred] = true; - CProfile_Colors[Color_Purple] = true; - CProfile_Colors[Color_Grey] = true; - CProfile_Colors[Color_Orange] = true; - CProfile_TeamIndex[Color_Red] = 2; - CProfile_TeamIndex[Color_Blue] = 3; - CProfile_SayText2 = true; - } - else if (StrEqual(szGameName, "tf", false)) - { - CProfile_Colors[Color_Lightgreen] = true; - CProfile_Colors[Color_Red] = true; - CProfile_Colors[Color_Blue] = true; - CProfile_Colors[Color_Olive] = true; - CProfile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; - CProfile_TeamIndex[Color_Red] = 2; - CProfile_TeamIndex[Color_Blue] = 3; - CProfile_SayText2 = true; - } - else if (StrEqual(szGameName, "left4dead", false) || StrEqual(szGameName, "left4dead2", false)) - { - CProfile_Colors[Color_Lightgreen] = true; - CProfile_Colors[Color_Red] = true; - CProfile_Colors[Color_Blue] = true; - CProfile_Colors[Color_Olive] = true; - CProfile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; - CProfile_TeamIndex[Color_Red] = 3; - CProfile_TeamIndex[Color_Blue] = 2; - CProfile_SayText2 = true; - } - else if (StrEqual(szGameName, "hl2mp", false)) - { - /* hl2mp profile is based on mp_teamplay convar */ - if (GetConVarBool(FindConVar("mp_teamplay"))) - { - CProfile_Colors[Color_Red] = true; - CProfile_Colors[Color_Blue] = true; - CProfile_Colors[Color_Olive] = true; - CProfile_TeamIndex[Color_Red] = 3; - CProfile_TeamIndex[Color_Blue] = 2; - CProfile_SayText2 = true; - } - else - { - CProfile_SayText2 = false; - CProfile_Colors[Color_Olive] = true; - } - } - else if (StrEqual(szGameName, "dod", false)) - { - CProfile_Colors[Color_Olive] = true; - CProfile_SayText2 = false; - } - /* Profile for other games */ - else - { - if (GetUserMessageId("SayText2") == INVALID_MESSAGE_ID) - { - CProfile_SayText2 = false; - } - else - { - CProfile_Colors[Color_Red] = true; - CProfile_Colors[Color_Blue] = true; - CProfile_TeamIndex[Color_Red] = 2; - CProfile_TeamIndex[Color_Blue] = 3; - CProfile_SayText2 = true; - } - } -} - -public Action:CEvent_MapStart(Handle:event, const String:name[], bool:dontBroadcast) -{ - CSetupProfile(); - - for (new i = 1; i <= MaxClients; i++) - CSkipList[i] = false; -} \ No newline at end of file diff --git a/includes/multicolors.inc b/includes/multicolors.inc new file mode 100644 index 0000000..e3d31c8 --- /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 0000000..17bf1b1 --- /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/morecolors.inc b/includes/multicolors/morecolors.inc similarity index 57% rename from includes/morecolors.inc rename to includes/multicolors/morecolors.inc index 97c32e9..ecf7413 100644 --- a/includes/morecolors.inc +++ b/includes/multicolors/morecolors.inc @@ -2,27 +2,29 @@ // By Dr. McKay // Inspired by: https://forums.alliedmods.net/showthread.php?t=96831 -#if defined _colors_included +#if defined _more_colors_included #endinput #endif -#define _colors_included +#define _more_colors_included #include -#define MORE_COLORS_VERSION "1.9.1" -#define MAX_MESSAGE_LENGTH 256 -#define MAX_BUFFER_LENGTH (MAX_MESSAGE_LENGTH * 4) +#define MORE_COLORS_VERSION "2.0.0-MC" +#define MC_MAX_MESSAGE_LENGTH 256 +#define MAX_BUFFER_LENGTH (MC_MAX_MESSAGE_LENGTH * 4) -#define COLOR_RED 0xFF4040 -#define COLOR_BLUE 0x99CCFF -#define COLOR_GRAY 0xCCCCCC -#define COLOR_GREEN 0x3EFF3E +#define MCOLOR_RED 0xFF4040 +#define MCOLOR_BLUE 0x99CCFF +#define MCOLOR_GRAY 0xCCCCCC +#define MCOLOR_GREEN 0x3EFF3E -#define GAME_DODS 0 +#define MC_GAME_DODS 0 -new bool:CSkipList[MAXPLAYERS + 1]; -new Handle:CTrie; -new CTeamColors[][] = {{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 +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. @@ -34,20 +36,20 @@ new CTeamColors[][] = {{0xCCCCCC, 0x4D7942, 0xFF4040}}; // Multi-dimensional arr * * On error/Errors: If the client is not connected an error will be thrown. */ -stock CPrintToChat(client, const String:message[], any:...) { - CCheckTrie(); +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); } - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; SetGlobalTransTarget(client); Format(buffer, sizeof(buffer), "\x01%s", message); VFormat(buffer2, sizeof(buffer2), buffer, 3); - CReplaceColorCodes(buffer2); - CSendMessage(client, buffer2); + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(client, buffer2); } /** @@ -58,19 +60,19 @@ stock CPrintToChat(client, const String:message[], any:...) { * @param message Message (formatting rules). * @noreturn */ -stock CPrintToChatAll(const String:message[], any:...) { - CCheckTrie(); - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; - for(new i = 1; i <= MaxClients; i++) { - if(!IsClientInGame(i) || CSkipList[i]) { - CSkipList[i] = false; +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); - CReplaceColorCodes(buffer2); - CSendMessage(i, buffer2); + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(i, buffer2); } } @@ -85,8 +87,8 @@ stock CPrintToChatAll(const String:message[], any:...) { * * On error/Errors: If the client or author are not connected an error will be thrown */ -stock CPrintToChatEx(client, author, const String:message[], any:...) { - CCheckTrie(); +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); } @@ -99,12 +101,12 @@ stock CPrintToChatEx(client, author, const String:message[], any:...) { if(!IsClientInGame(author)) { ThrowError("Client %i is not in game", author); } - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; SetGlobalTransTarget(client); Format(buffer, sizeof(buffer), "\x01%s", message); VFormat(buffer2, sizeof(buffer2), buffer, 4); - CReplaceColorCodes(buffer2, author); - CSendMessage(client, buffer2, author); + MC_ReplaceColorCodes(buffer2, author); + MC_SendMessage(client, buffer2, author); } /** @@ -117,25 +119,25 @@ stock CPrintToChatEx(client, author, const String:message[], any:...) { * * On error/Errors: If the author is not connected an error will be thrown. */ -stock CPrintToChatAllEx(author, const String:message[], any:...) { - CCheckTrie(); +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); } - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; - for(new i = 1; i <= MaxClients; i++) { - if(!IsClientInGame(i) || CSkipList[i]) { - CSkipList[i] = false; + 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); - CReplaceColorCodes(buffer2, author); - CSendMessage(i, buffer2, author); + MC_ReplaceColorCodes(buffer2, author); + MC_SendMessage(i, buffer2, author); } } @@ -146,29 +148,28 @@ stock CPrintToChatAllEx(author, const String:message[], any:...) { * @param message Message to send * @noreturn */ -stock CSendMessage(client, const String:message[], author=0) { +stock void MC_SendMessage(int client, const char[] message, int author = 0) { if(author == 0) { author = client; } - decl String:buffer[MAX_MESSAGE_LENGTH], String:game[16]; - GetGameFolderName(game, sizeof(game)); + char buffer[MC_MAX_MESSAGE_LENGTH]; strcopy(buffer, sizeof(buffer), message); - new UserMsg:index = GetUserMessageId("SayText2"); + UserMsg index = GetUserMessageId("SayText2"); if(index == INVALID_MESSAGE_ID) { - if(StrEqual(game, "dod")) { - new team = GetClientTeam(author); + if(GetEngineVersion() == Engine_DODS) { + int team = GetClientTeam(author); if(team == 0) { ReplaceString(buffer, sizeof(buffer), "\x03", "\x04", false); // Unassigned gets green } else { - decl String:temp[16]; - Format(temp, sizeof(temp), "\x07%06X", CTeamColors[GAME_DODS][team - 1]); + 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; } - new Handle:buf = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); + 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); @@ -187,18 +188,18 @@ stock CSendMessage(client, const String:message[], author=0) { /** * This function should only be used right in front of - * CPrintToChatAll or CPrintToChatAllEx. It causes those functions + * 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 CSkipNextClient(client) { +stock void MC_SkipNextClient(int client) { if(client <= 0 || client > MaxClients) { ThrowError("Invalid client index %i", client); } - CSkipList[client] = true; + MC_SkipList[client] = true; } /** @@ -206,25 +207,25 @@ stock CSkipNextClient(client) { * * @return No return */ -stock CCheckTrie() { - if(CTrie == INVALID_HANDLE) { - CTrie = InitColorTrie(); +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 CPrintToChat, CPrintToChatAll, CPrintToChatEx, and CPrintToChatAllEx + * 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 CRemoveTags - * @param maxlen Optional value for max buffer length, used by CRemoveTags + * @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 CReplaceColorCodes(String:buffer[], author=0, bool:removeTags=false, maxlen=MAX_BUFFER_LENGTH) { - CCheckTrie(); +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 { @@ -240,27 +241,29 @@ stock CReplaceColorCodes(String:buffer[], author=0, bool:removeTags=false, maxle } ReplaceString(buffer, maxlen, "{teamcolor}", "\x03", false); } - new cursor = 0; - new value; - decl String:tag[32], String:buff[32], String:output[maxlen]; + 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 - new Handle:regex = CompileRegex("{[a-zA-Z0-9]+}"); - for(new 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. + 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)); - CStrToLower(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(CTrie, buff, value)) { + if(!GetTrieValue(MC_Trie, buff, value)) { continue; } @@ -284,8 +287,8 @@ stock CReplaceColorCodes(String:buffer[], author=0, bool:removeTags=false, maxle * @param numChars Number of characters to return, or 0 for the end of the string * @noreturn */ -stock CSubString(const String:input[], String:output[], maxlen, start, numChars=0) { - new i = 0; +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'; @@ -302,9 +305,9 @@ stock CSubString(const String:input[], String:output[], maxlen, start, numChars= * @param buffer String to convert * @noreturn */ -stock CStrToLower(String:buffer[]) { - new len = strlen(buffer); - for(new i = 0; i < len; i++) { +stock void MC_StrToLower(char[] buffer) { + int len = strlen(buffer); + for(int i = 0; i < len; i++) { buffer[i] = CharToLower(buffer[i]); } } @@ -316,16 +319,16 @@ stock CStrToLower(String:buffer[]) { * @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:CAddColor(const String:name[], color) { - CCheckTrie(); - new value; - if(GetTrieValue(CTrie, name, value)) { +stock bool MC_AddColor(const char[] name, int color) { + MC_CheckTrie(); + int value; + if(GetTrieValue(MC_Trie, name, value)) { return false; } - decl String:newName[64]; + char newName[64]; strcopy(newName, sizeof(newName), name); - CStrToLower(newName); - SetTrieValue(CTrie, newName, color); + MC_StrToLower(newName); + SetTrieValue(MC_Trie, newName, color); return true; } @@ -336,8 +339,8 @@ stock bool:CAddColor(const String:name[], color) { * @param maxlen Maximum buffer length * @noreturn */ -stock CRemoveTags(String:message[], maxlen) { - CReplaceColorCodes(message, 0, true, maxlen); +stock void MC_RemoveTags(char[] message, int maxlen) { + MC_ReplaceColorCodes(message, 0, true, maxlen); } /** @@ -347,15 +350,15 @@ stock CRemoveTags(String:message[], maxlen) { * @param message Message (formatting rules) * @noreturn */ -stock CReplyToCommand(client, const String:message[], any:...) { - decl String:buffer[MAX_BUFFER_LENGTH]; +stock void MC_ReplyToCommand(int client, const char[] message, any ...) { + char buffer[MAX_BUFFER_LENGTH]; SetGlobalTransTarget(client); VFormat(buffer, sizeof(buffer), message, 3); - if(!client || GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { - CRemoveTags(buffer, sizeof(buffer)); + if(GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + MC_RemoveTags(buffer, sizeof(buffer)); PrintToConsole(client, "%s", buffer); } else { - CPrintToChat(client, "%s", buffer); + MC_PrintToChat(client, "%s", buffer); } } @@ -367,88 +370,364 @@ stock CReplyToCommand(client, const String:message[], any:...) { * @param message Message (formatting rules) * @noreturn */ -stock CReplyToCommandEx(client, author, const String:message[], any:...) { - decl String:buffer[MAX_BUFFER_LENGTH]; +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) { - CRemoveTags(buffer, sizeof(buffer)); + MC_RemoveTags(buffer, sizeof(buffer)); PrintToConsole(client, "%s", buffer); } else { - CPrintToChatEx(client, author, "%s", buffer); + MC_PrintToChatEx(client, author, "%s", buffer); } } /** - * Shows admin activity with colors - * - * @param client Client performing an action - * @param message Message (formatting rules) + * 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 CShowActivity(client, const String:message[], any:...) { - CCheckTrie(); - if(client < 0 || client > MaxClients) { - ThrowError("Invalid client index %d", client); +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; + } } - if(client != 0 && !IsClientInGame(client)) { - ThrowError("Client %d is not in game", client); + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); } - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; - Format(buffer, sizeof(buffer), "\x01%s", message); - VFormat(buffer2, sizeof(buffer2), buffer, 3); - CReplaceColorCodes(buffer2); - ShowActivity(client, "%s", buffer2); + + 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; } /** - * Shows admin activity with colors - * - * @param client Client performing an action - * @param tag Tag to prepend to the message (color tags supported) - * @param message Message (formatting rules) + * 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 CShowActivityEx(client, const String:tag[], const String:message[], any:...) { - CCheckTrie(); - if(client < 0 || client > MaxClients) { - ThrowError("Invalid client index %d", client); +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; + } } - if(client != 0 && !IsClientInGame(client)) { - ThrowError("Client %d is not in game", client); + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); } - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; - Format(buffer, sizeof(buffer), "\x01%s", message); - VFormat(buffer2, sizeof(buffer2), buffer, 4); - CReplaceColorCodes(buffer2); - strcopy(buffer, sizeof(buffer), tag); - CReplaceColorCodes(buffer); - ShowActivityEx(client, tag, "%s", buffer2); + + 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; } /** - * Shows admin activity with colors - * - * @param client Client performing an action - * @param tag Tag to prepend to the message (color tags supported) - * @param message Message (formatting rules) + * 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 CShowActivity2(client, const String:tag[], const String:message[], any:...) { - CCheckTrie(); - if(client < 0 || client > MaxClients) { - ThrowError("Invalid client index %d", client); +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); } - if(client != 0 && !IsClientInGame(client)) { - ThrowError("Client %d is not in game", client); + else + { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, szBuffer); } - decl String:buffer[MAX_BUFFER_LENGTH], String:buffer2[MAX_BUFFER_LENGTH]; - Format(buffer, sizeof(buffer), "\x01%s", message); - VFormat(buffer2, sizeof(buffer2), buffer, 4); - CReplaceColorCodes(buffer2); - strcopy(buffer, sizeof(buffer), tag); - CReplaceColorCodes(buffer); - ShowActivity2(client, buffer, "%s", buffer2); + + 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; } /** @@ -457,10 +736,10 @@ stock CShowActivity2(client, const String:tag[], const String:message[], any:... * @param color The color name to check * @return True if the color exists, false otherwise */ -stock bool:CColorExists(const String:color[]) { - CCheckTrie(); - new temp; - return GetTrieValue(CTrie, color, temp); +stock bool CColorExists(const char[] color) { + MC_CheckTrie(); + int temp; + return GetTrieValue(MC_Trie, color, temp); } /** @@ -470,33 +749,33 @@ stock bool:CColorExists(const String:color[]) { * @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 CGetTeamColor(client) { +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); } - new value; + int value; switch(GetClientTeam(client)) { case 1: { - value = COLOR_GRAY; + value = MCOLOR_GRAY; } case 2: { - value = COLOR_RED; + value = MCOLOR_RED; } case 3: { - value = COLOR_BLUE; + value = MCOLOR_BLUE; } default: { - value = COLOR_GREEN; + value = MCOLOR_GREEN; } } return value; } -stock Handle:InitColorTrie() { - new Handle:hTrie = CreateTrie(); +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 diff --git a/includes/nativevotes.inc b/includes/nativevotes.inc deleted file mode 100644 index c02c5bd..0000000 --- a/includes/nativevotes.inc +++ /dev/null @@ -1,915 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * NativeVotes - * Copyright (C) 2011-2013 Ross Bemrose (Powerlord). All rights reserved. - * ============================================================================= - * - * 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 . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include -#include - -// NativeVotes 0.8 series - -#if defined _nativevotes_included - #endinput -#endif -#define _nativevotes_included - -#define CLIENT_DISCONNECTED -1 - -#define NATIVEVOTES_EXTEND "Extend current Map" /** Defined in TF2, but doesn't appear to be localized */ - -#define NATIVEVOTES_ALL_TEAMS -1 // Defined by TF2, may be the same in L4D/L4D2 -#define NATIVEVOTES_TF2_ALL_TEAMS 0 // Defined by TF2, may be the same in L4D/L4D2 -#define NATIVEVOTES_TEAM_UNASSIGNED 0 // For completeness, do not otherwise use -#define NATIVEVOTES_TEAM_SPECTATOR 1 // Spectators -#define NATIVEVOTES_TEAM_1 2 // RED/Survivors/Terrorists -#define NATIVEVOTES_TEAM_2 3 // BLU/Infected/Counter-Terrorists - -#define NATIVEVOTES_SERVER_INDEX 99 // Defined by TF2, may be the same in L4D/L4D2 - -// These may seem backwards, but this is the order that the votes appear in the vote screen -#define NATIVEVOTES_VOTE_INVALID -1 /**< Vote was invalid, currently only valid internally */ -#define NATIVEVOTES_VOTE_YES 0 /**< Vote was yes */ -#define NATIVEVOTES_VOTE_NO 1 /**< Vote was no */ - -/* -The following MenuActions are supported. Arguments are also listed, as they differ slightly from the default -MenuAction_Start A menu has been started (nothing passed). Only exists for compat reasons. -MenuAction_Display A menu is about to be displayed (param1=client). If you choose to change the vote text, - To change the text, use RedrawVoteTitle() - If you do so, return 1 or _:Plugin_Changed Otherwise, return _:Plugin_Continue or 0. -MenuAction_Select An item was selected (param1=client, param2=item). For subplugin support. -MenuAction_End A vote has fully ended and the vote object is ready to be cleaned up - param1 is MenuEnd reason, either MenuEnd_VotingCancelled or MenuEnd_VotingDone -MenuAction_VoteEnd A vote sequence has succeeded (param1=chosen item) - This is not called if NativeVotes_SetResultCallback has been used on the vote. - You should call NativeVotes_DisplayPass or NativeVotes_DisplayPassEx after this -MenuAction_VoteStart A vote sequence has started (nothing passed). Use this instead of MenuAction_Start -MenuAction_VoteCancel A vote sequence has been cancelled (param1=reason) -MenuAction_DisplayItem Item text is being drawn to the display (param1=client, param2=item) - To change the text, use RedrawVoteItem(). - If you do so, return 1 or _:Plugin_Changed. Otherwise, return _:Plugin_Continue or 0. -*/ - -#define NATIVEVOTES_ACTIONS_DEFAULT MenuAction_VoteStart|MenuAction_VoteCancel|MenuAction_VoteEnd|MenuAction_End - -/** - * Vote types. These are mapped to translation strings and pass strings by VoteStart and VotePass handlers - */ -enum NativeVotesType -{ - NativeVotesType_None = 0, /** Special placeholder for callvote with no arguments for NativeVotes_OnCallVote */ - NativeVotesType_Custom_YesNo, /**< Yes/No, details are vote text. */ - NativeVotesType_Custom_Mult, /**< TF2/CS:GO: Multiple-choice, details are vote text. */ - NativeVotesType_ChgCampaign, /**< L4D/L4D2: Yes/No, details are campaign name */ - NativeVotesType_ChgDifficulty, /**< L4D/L4D2: Yes/No, details are difficulty number in L4D/L4D2 */ - NativeVotesType_ReturnToLobby, /**< L4D/L4D2: Yes/No, details are ignored */ - NativeVotesType_AlltalkOn, /**< L4D2: Yes/No, details are ignored (handled internally by extension) */ - NativeVotesType_AlltalkOff, /**< L4D2: Yes/No, details are ignored (handled internally by extension) */ - NativeVotesType_Restart, /**< Yes/No, details are ignored */ - NativeVotesType_Kick, /**< Yes/No, target is player userid, details are auto-set by target */ - NativeVotesType_KickIdle, /**< TF2/CS:GO: Yes/No, target is player userid, details are auto-set by target */ - NativeVotesType_KickScamming, /**< TF2/CS:GO: Yes/No, target is player userid, details are auto-set by target */ - NativeVotesType_KickCheating, /**< TF2/CS:GO: Yes/No, target is player userid, details are auto-set by target */ - NativeVotesType_ChgLevel, /**< Yes/No, details are level number in L4D/L4D2 or map name in TF2 */ - NativeVotesType_NextLevel, /**< TF2/CS:GO: Yes/No, details are map name */ - NativeVotesType_NextLevelMult, /**< TF2/CS:GO: Multiple-choice, details are ignored */ - NativeVotesType_ScrambleNow, /**< TF2/CS:GO: Yes/No, details are ignored */ - NativeVotesType_ScrambleEnd, /**< TF2: Yes/No, details are ignored */ - NativeVotesType_ChgMission, /**< TF2: Yes/No, details are popfile */ - NativeVotesType_SwapTeams, /**< CS:GO: Yes/No, details are ignored */ - NativeVotesType_Surrender, /**< CS:GO: Yes/No, details are ignored */ - NativeVotesType_Rematch, /**< CS:GO: Yes/No, details are ignored */ - NativeVotesType_Continue, /**< CS:GO: Yes/No, details are ignored */ - NativeVotesType_StartRound, /**< TF2: Yes/No, details are ignored */ - NativeVotesType_Eternaween, /**< TF2: Yes/No, details are ignored */ - NativeVotesType_AutoBalanceOn, /**< TF2: Yes/No, details are ignored */ - NativeVotesType_AutoBalanceOff, /**< TF2: Yes/No, details are ignored */ - NativeVotesType_ClassLimitsOn, /**< TF2: Yes/No, details are ignored */ - NativeVotesType_ClassLimitsOff, /**< TF2: Yes/No, details are ignored */ -}; - -enum NativeVotesPassType -{ - NativeVotesPass_None = 0, /**< Special placeholder for error value */ - NativeVotesPass_Custom, /**< Details are custom pass message */ - NativeVotesPass_ChgCampaign, /**< L4D/L4D2: Details are campaign name */ - NativeVotesPass_ChgDifficulty, /**< L4D/L4D2/TF2: Details are difficulty number in L4D/L4D2 and mission name in TF2 */ - NativeVotesPass_ReturnToLobby, /**< L4D/L4D2: Details are ignored */ - NativeVotesPass_AlltalkOn, /**< L4D2: Details are ignored */ - NativeVotesPass_AlltalkOff, /**< L4D2: Details are ignored */ - NativeVotesPass_Restart, /**< Details are ignored */ - NativeVotesPass_Kick, /**< Details are player name */ - NativeVotesPass_ChgLevel, /**< Details are level number in L4D/L4D2 or map name in TF2/CS:GO */ - NativeVotesPass_NextLevel, /**< TF2/CS:GO: Details are map name */ - NativeVotesPass_Extend, /**< TF2/CS:GO: Details are ignored */ - NativeVotesPass_Scramble, /**< TF2/CS:GO: Details are ignored */ - NativeVotesPass_ChgMission, /**< TF2: Details are popfile */ - NativeVotesPass_SwapTeams, /**< CS:GO: Details are ignored */ - NativeVotesPass_Surrender, /**< CS:GO: Details are ignored */ - NativeVotesPass_Rematch, /**< CS:GO: Details are ignored */ - NativeVotesPass_Continue, /**< CS:GO: Details are ignored */ - NativeVotesPass_StartRound, /**< TF2: Details are ignored */ - NativeVotesPass_Eternaween, /**< TF2: Details are ignored */ - NativeVotesPass_AutoBalanceOn, /**< TF2: Yes/No, details are ignored */ - NativeVotesPass_AutoBalanceOff, /**< TF2: Yes/No, details are ignored */ - NativeVotesPass_ClassLimitsOn, /**< TF2: Yes/No, details are ignored */ - NativeVotesPass_ClassLimitsOff, /**< TF2: Yes/No, details are ignored */ -}; - -/** - * Reasons a vote was canceled. Not used for L4D/L4D2, as they don't care - */ -enum NativeVotesFailType -{ - NativeVotesFail_Generic = 0, /**< Vote was generically cancelled. */ - NativeVotesFail_Loses = 3, /**< No votes outnumbered Yes votes */ - NativeVotesFail_NotEnoughVotes = 4, /**< Vote did not receive enough votes. */ -}; - -/** - * Reasons a callvote command failed. - * This is provided as a convenience to plugin authors as it's not strictly part of the vote system - */ -enum NativeVotesCallFailType -{ - NativeVotesCallFail_Generic = 0, /**< Generic fail. */ - NativeVotesCallFail_Loading = 1, /**< L4D/L4D2: Players are still loading. */ - NativeVotesCallFail_Recent = 2, /**< TF2/CS:GO: You can't call another vote yet: Argument is seconds until you can call another vote. */ - NativeVotesCallFail_Disabled = 5, /**< TF2/CS:GO: Server has disabled that issue. */ - NativeVotesCallFail_MapNotFound = 6, /**< TF2/CS:GO: Server does not have that map. */ - NativeVotesCallFail_SpecifyMap = 7, /**< TF2/CS:GO: You must specify a map. */ - NativeVotesCallFail_Failed = 8, /**< TF2/CS:GO: This vote failed recently. */ - NativeVotesCallFail_WrongTeam = 9, /**< TF2/CS:GO: Team can't call this vote. */ - NativeVotesCallFail_Waiting = 10, /**< TF2/CS:GO: Vote can't be called during Waiting For Players. */ - NativeVotesCallFail_PlayerNotFound = 11, /**< TF2/CS:GO: Player to kick can't be found. Buggy in TF2. */ - NativeVotesCallFail_Unknown = 11, - NativeVotesCallFail_CantKickAdmin = 12, /**< TF2/CS:GO: Can't kick server admin. */ - NativeVotesCallFail_ScramblePending = 13, /**< TF2/CS:GO: Team Scramble is pending.. */ - NativeVotesCallFail_Spectators = 14, /**< TF2/CS:GO: Spectators aren't allowed to call votes. */ - NativeVotesCallFail_LevelSet = 15, /**< TF2/CS:GO: Next level already set. */ - NativeVotesCallFail_MapNotValid = 16, /**< ???: Map is invalid. */ - NativeVotesCallFail_KickTime = 17, /**< ???: Cannot kick for time. */ - NativeVotesCallFail_KickDuringRound = 18, /**< ???: Cannot kick during a round. */ - NativeVotesCallFail_AlreadyActive = 19 /**< TF2: Cannot call vote because modification (Eternaween) is already active (may not work) */ -}; - -/* - * Is a specific vote type supported by this game? - * - * @param voteType Vote type - */ -native bool:NativeVotes_IsVoteTypeSupported(NativeVotesType:voteType); - -/** - * Creates a new, empty vote. - * - * @param handler Function which will receive vote actions. - * @param voteType Vote type, cannot be changed after set - * @param actions Optionally set which actions to receive. Start, - * Cancel, and End will always be received regardless - * of whether they are set or not. They are also - * the only default actions. - * @return A new vote Handle on INVALID_HANDLE if a vote type is unsupported by this game. - */ -native Handle:NativeVotes_Create(MenuHandler:handler, NativeVotesType:voteType, - MenuAction:actions=NATIVEVOTES_ACTIONS_DEFAULT); - -/** - * Frees all handles related to a vote. - * - * THIS MUST BE CALLED TO AVOID HANDLE LEAKS - * - * @param vote Vote handle - * @noreturn - */ -native Handle:NativeVotes_Close(Handle:vote); - -/** - * Appends a new item to the end of a vote. Only valid for Multiple Choice votes - * - * @param vote NativeVotes Handle. - * @param info Item information string. - * @return True on success, false on failure. - * @error Invalid Handle, item limit reached, or if the vote is not multiple choice. - */ -native bool:NativeVotes_AddItem(Handle:vote, const String:info[], const String:display[]); - -/** - * Inserts an item into the menu before a certain position; the new item will - * be at the given position and all next items pushed forward. - * - * @param vote Vote Handle. - * @param position Position, starting from 0. - * @param info Item information string. - * @return True on success, false on failure. - * @error Invalid Handle or vote position, or if the vote is not multiple choice. - */ -native bool:NativeVotes_InsertItem(Handle:vote, position, const String:info[], const String:display[]); - -/** - * Removes an item from the menu. - * - * @param vote Vote Handle. - * @param position Position, starting from 0. - * @return True on success, false on failure. - * @error Invalid Handle or vote position, or if the vote is not multiple choice. - */ -native bool:NativeVotes_RemoveItem(Handle:vote, position); - -/** - * Removes all items from a vote. - * - * @param vote Vote Handle. - * @noreturn - * @error Invalid Handle or vote position, or if the vote is not multiple choice. - */ -native NativeVotes_RemoveAllItems(Handle:vote); - -/** - * Retrieves information about a vote item. - * - * @param vote Vote Handle. - * @param position Position, starting from 0. - * @param infoBuf Info buffer. - * @param infoBufLen Maximum length of the info buffer. - * @return True on success, false if position is invalid. - * @error Invalid Handlem - */ -native bool:NativeVotes_GetItem(Handle:vote, - position, - String:infoBuf[], - infoBufLen, - String:dispBuf[]="", - dispBufLen=0); - -/** - * Returns the number of items in a vote. - * - * @param vote Vote Handle. - * @return Number of items in the vote. - * @error Invalid Handle. - */ -native NativeVotes_GetItemCount(Handle:vote); - -/** - * Sets the vote's details for votes that support details - * If this is a custom vote, use NativeVotes_SetTitle to set the vote's title. - * - * @param vote Vote Handle. - * @param argument Details string. See vote types for what details stands for. - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_SetDetails(Handle:vote, const String:argument[]); - -/** - * Returns the text of a vote's details if set. - * - * @param vote Vote Handle. - * @param buffer Buffer to store details. - * @param maxlength Maximum length of the buffer. - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_GetDetails(Handle:vote, String:buffer[], maxlength); - -/** - * Sets a custom vote's title - * - * @param vote Vote Handle. - * @param title Vote title string. - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_SetTitle(Handle:vote, const String:argument[]); - -/** - * Return the vote's Title. - * If not set, returns Details instead. - * This behavior is for compatibility with NativeVotes 0.8.0 and below. - * - * @param vote Vote Handle. - * @param buffer Buffer to store title. - * @param maxlength Maximum length of the buffer. - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_GetTitle(Handle:vote, String:buffer[], maxlength); - -/** - * Sets the target userid for vote - * This should be used instead of SetArgument for votes that target players - * - * Also sets target SteamID - * - * @param vote Vote Handle. - * @param userid Client index of target player - * @param setDetails If true, also sets vote details to client's name - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_SetTarget(Handle:vote, client, bool:setDetails=true); - -/** - * Returns the userid of a vote's target - * - * @param vote Vote Handle. - * @return Client index of target player or 0 for no target or target disconnected since vote started - * @error Invalid Handle. - */ -native NativeVotes_GetTarget(Handle:vote); - -/** - * Get the Steam ID of a vote's target - * Useful if the target has disconnect from the server during a vote. - * This was added in specifically for Kick/Ban votes - * - * @param vote Vote Handle. - * @param buffer Buffer to store steamId. Should be 19 characters or more.. - * @param maxlength Maximum length of the buffer. - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_GetTargetSteam(Handle:vote, String:buffer[], maxlength); - -/** - * Returns whether a vote is in progress. - * - * @return True if a NativeVotes vote is in progress, false otherwise. - */ -native bool:NativeVotes_IsVoteInProgress(); - -/** - * Returns a style's maximum items - * - * @return Maximum items - */ -native NativeVotes_GetMaxItems(); - -/** - * Sets a vote's option flags. - * - * If a certain bit is not supported, it will be stripped before being set. - * - * NOTE: This is currently unused, but reserved for future use. - * - * @param menu Builtin Vote Handle. - * @param flags A new bitstring of VOTEFLAG bits. - * @noreturn - * @error Invalid Handle. - */ -native NativeVotes_SetOptionFlags(Handle:vote, flags); - -/** - * Retrieves a menu's option flags. - * - * NOTE: This is currently unused, but reserved for future use. - * - * @param vote Builtin Vote Handle. - * @return A bitstring of VOTEFLAG bits. - * @error Invalid Handle. - */ -native NativeVotes_GetOptionFlags(Handle:vote); - -/** - * Cancels the vote in progress. - * - * @noreturn - * @error If no vote is in progress. - */ -native NativeVotes_Cancel(); - -/** - * Callback for when a vote has ended and results are available. - * - * Due to SourceMod Forward limitations in plugins, multi-dimension arrays can't be passed - * to forwards. This means we have to split the client_info and item_info arrays into - * their components. - * - * @param vote The vote being voted on. - * @param num_votes Number of votes tallied in total. - * @param num_clients Number of clients who could vote. - * @param client_indexes Array of client indexes. Parallel with client_votes. - * @param client_votes Array of client votes. Parallel with client_indexes. - * @param num_items Number of unique items that were selected. - * @param item_indexes Array of vote item indexes. Parallel with item_votes.. - * @param item_votes Array of vote vote counts. Parallel with item_indexes. - * @noreturn - */ -functag public NativeVotes_VoteHandler(Handle:vote, - num_votes, - num_clients, - const client_indexes[], - const client_votes[], - num_items, - const item_indexes[], - const item_votes[]); -/** - * Function to convert client/vote arrays into their two-dimensional versions, - * which can then be passed to a standard vote handler. - * - * client_info and item_info are the resulting arrays. - * - * Note: When declaring client_info and item_info, you'll probably want to declare them like this: - * new client_info[num_clients][2]; - * new item_info[num_items][2]; - * - * @param num_clients Number of clients who could vote. - * @param client_indexes Array of client indexes. Parallel with client_votes. - * @param client_votes Array of client votes. Parallel with client_indexes. - * @param num_items Number of unique items that were selected. - * @param item_indexes Array of vote item indexes. Parallel with item_votes.. - * @param item_votes Array of vote vote counts. Parallel with item_indexes. - * @param client_info Array of clients. Use VOTEINFO_CLIENT_ defines. - * @param item_info Array of items, sorted by count. Use VOTEINFO_ITEM - * defines. - * @noreturn - */ -stock NativeVotes_FixResults(num_clients, - const client_indexes[], - const client_votes[], - num_items, - const item_indexes[], - const item_votes[], - client_info[][], - item_info[][]) -{ - for (new i = 0; i < num_clients; ++i) - { - client_info[i][VOTEINFO_CLIENT_INDEX] = client_indexes[i]; - client_info[i][VOTEINFO_CLIENT_ITEM] = client_votes[i]; - } - - for (new i = 0; i < num_items; ++i) - { - item_info[i][VOTEINFO_ITEM_INDEX] = item_indexes[i]; - item_info[i][VOTEINFO_ITEM_VOTES] = item_votes[i]; - } -} - -/** - * Sets an advanced vote handling callback. If this callback is set, - * MenuAction_VoteEnd will not be called. - * - * @param vote NativeVotes Handle. - * @param callback Callback function. - * @noreturn - * @error Invalid Handle or callback. - */ -native NativeVotes_SetResultCallback(Handle:vote, NativeVotes_VoteHandler:callback); - -/** - * Returns the number of seconds you should "wait" before displaying - * a public vote. This number is the time remaining until - * (last_vote + sm_vote_delay). - * - * @return Number of seconds to wait, or 0 for none. - */ -native NativeVotes_CheckVoteDelay(); - -/** - * Returns whether a client is in the pool of clients allowed - * to participate in the current vote. This is determined by - * the client list passed to NativeVotes_Display(). - * - * @param client Client index. - * @return True if client is allowed to vote, false otherwise. - * @error If no vote is in progress or client index is invalid. - */ -native bool:NativeVotes_IsClientInVotePool(client); - -/** - * Redraws the current vote to a client in the voting pool. - * - * @param client Client index. - * @param revotes True to allow revotes, false otherwise. - * @return True on success, false if the client is in the vote pool - * but cannot vote again. - * @error No vote in progress, client is not in the voting pool, - * or client index is invalid. - */ -native bool:NativeVotes_RedrawClientVote(client, bool:revotes=true); - -/** - * Retrieve the vote type - * - * @param vote NativeVotes Handle. - * @return The built in vote type - * @error Invalid Handle - */ -native NativeVotesType:NativeVotes_GetType(Handle:vote); - -/** - * Set the team this vote is for, or NATIVEVOTES_ALL_TEAMS for all teams. - * - * Defaults to NATIVEVOTES_ALL_TEAMS if not explicitly set. - * - * @param vote NativeVotes Handle. - * @param team Team number this vote is for - * @noreturn - * @error Invalid Handle - */ -native NativeVotes_SetTeam(Handle:vote, team); - -/** - * Retrieve the team this vote is for - * - * @param vote NativeVotes Handle. - * @return Team index or NATIVEVOTES_ALL_TEAMS for all teams. - * @error Invalid Handle - */ -native NativeVotes_GetTeam(Handle:vote); - -/** - * Set the client index of the player who initiated the vote. - * Use NATIVEVOTES_SERVER_INDEX if initiated by the server itself. - * - * Defaults to NATIVEVOTES_SERVER_INDEX if not explicitly set. - * - * @param vote NativeVotes Handle. - * @param client Client who initiated the vote or NATIVEVOTES_SERVER_INDEX - * @noreturn - * @error Invalid Handle - */ -native NativeVotes_SetInitiator(Handle:vote, client); - -/** - * Retrieve the client index of the player who initiated the vote or NATIVEVOTES_SERVER_INDEX if - * initiated by the server itself. - * - * @param Vote handle - * @return Client index or NATIVEVOTES_SERVER_INDEX - * @error Invalid Handle - */ -native NativeVotes_GetInitiator(Handle:vote); - -/** - * Broadcasts a vote to a list of clients. The most selected item will be - * returned through MenuAction_VoteEnd. On a tie, a random item will be returned - * from a list of the tied items. - * - * Note that MenuAction_VoteStart, MenuAction_VoteCancel, MenuAction_VoteEnd, and MenuAction_End are all - * default callbacks and do not need to be enabled. - * - * @param vote Vote Handle. - * @param clients Array of clients to broadcast to. - * @param numClients Number of clients in the array. - * @param time Maximum time to leave menu on the screen. - * @return True on success, false if a vote is already in progress. - * @error Invalid Handle, or a vote is already in progress. - */ -native bool:NativeVotes_Display(Handle:vote, clients[], numClients, time); - -/** - * Sends a vote menu to all clients. See NativeVotes_Display() for more information. - * - * @param vote Vote Handle. - * @param time Maximum time to leave menu on the screen. - * @return True on success, false if this menu already has a vote session - * in progress. - * @error Invalid Handle, or a vote is already in progress. - */ -stock bool:NativeVotes_DisplayToAll(Handle:vote, time) -{ - new total = 0; - decl players[MaxClients]; - - for (new i=1; i<=MaxClients; i++) - { - if (!IsClientInGame(i) || IsFakeClient(i)) - { - continue; - } - players[total++] = i; - } - - return NativeVotes_Display(vote, players, total, time); -} - -/** - * Sends a vote menu to a single team. See NativeVotes_Display() for more information. - * - * @param vote Vote Handle. - * @param team Team to send vote to. 1 = spectators, 2 = RED/Survivors/Terrorists, 3 = BLU/Infected/Counter-Terrorists - * @param time Maximum time to leave menu on the screen. - * @return True on success, false if this menu already has a vote session - * in progress. - * @error Invalid Handle, or a vote is already in progress. - */ -stock bool:NativeVotes_DisplayToTeam(Handle:vote, team, time) -{ - NativeVotes_SetTeam(vote, team); - - new total; - decl players[MaxClients]; - - for (new i=1; i<=MaxClients; i++) - { - if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) != team)) - { - continue; - } - players[total++] = i; - } - - return NativeVotes_Display(vote, players, total, time); -} - -/** - * Sends a vote menu to all clients who are not spectators or waiting to choose a team. See NativeVotes_Display() for more information. - * - * @param vote Vote Handle. - * @param time Maximum time to leave menu on the screen. - * @return True on success, false if this menu already has a vote session - * in progress. - * @error Invalid Handle, or a vote is already in progress. - */ -stock bool:NativeVotes_DisplayToAllNonSpectators(Handle:vote, time) -{ - new total; - decl players[MaxClients]; - - for (new i=1; i<=MaxClients; i++) - { - if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) < 2)) - { - continue; - } - players[total++] = i; - } - - return NativeVotes_Display(vote, players, total, time); -} - -/** - * Display vote passed screen - * - * You MUST call one of the NativeVotesDisplayPass* or NativeVotes_DisplayFail functions - * to hide the vote screen for users who didn't vote, and to clear out their selection - * for the next vote. - * - * @param vote Vote handle - * @param details Normally the item that won the vote or format string. Also used for custom vote winners - * @param ... Variable number of format parameters. - * @noreturn - */ -native NativeVotes_DisplayPass(Handle:vote, const String:details[]=""); - -/** - * Display vote passed screen with custom text to a single user - * - * You MUST call one of the NativeVotesDisplayPass* or NativeVotes_DisplayFail functions - * to hide the vote screen for users who didn't vote, and to clear out their selection - * for the next vote. - * - * @param vote Vote handle - * @param client client to display to - * @param format A format string. - * @param any Variable number of format parameters - * @noreturn - */ -native NativeVotes_DisplayPassCustomToOne(Handle:vote, client, const String:format[], any:...); - -/** - * Display vote passed screen with custom text - * - * You MUST call one of the NativeVotesDisplayPass* or NativeVotes_DisplayFail functions - * to hide the vote screen for users who didn't vote, and to clear out their selection - * for the next vote. - * - * @param vote Vote handle - * @param format A format string. - * @param any Variable number of format parameters - * @noreturn - */ -stock NativeVotes_DisplayPassCustom(Handle:vote, const String:format[], any:...) -{ - decl String:buffer[192]; - - for (new i = 1; i <= MaxClients; ++i) - { - if (IsClientInGame(i)) - { - SetGlobalTransTarget(i); - VFormat(buffer, sizeof(buffer), format, 3); - NativeVotes_DisplayPassCustomToOne(vote, i, "%s", buffer); - } - } -} - -/** - * Display vote passed screen with a custom type. - * - * A sample usage of this would be if Extend won an RTV vote: NativeVotes_DisplayPassEx(vote, NativeVotesPass_Extend, map); - * - * You MUST call one of NativeVotes_DisplayPass, NativeVotes_DisplayPassEx, - * or NativeVotes_DisplayFail to hide the vote screen for users who didn't vote - * and to clear out their selection for the next vote. - * - * #param vote Vote handle - * @param passType The pass screen to display - * @param details Normally the item that won the vote. Also used for custom vote winners - * @noreturn - */ -native NativeVotes_DisplayPassEx(Handle:vote, NativeVotesPassType:passType, const String:details[]=""); - -/** - * Display failure screen. - * - * You MUST call one of NativeVotes_DisplayPass, NativeVotes_DisplayPassEx, - * or NativeVotes_DisplayFail to hide the vote screen for users who didn't vote, - * and to clear out their selection for the next vote. - * - * @param reason Vote failure reason from NativeVotesFailType enum - * @noreturn - */ -native NativeVotes_DisplayFail(Handle:vote, NativeVotesFailType:reason=NativeVotesFail_Generic); - -/** - * Quick stock to determine whether voting is allowed. This doesn't let you - * fine-tune a reason for not voting, so it's not recommended for lazily - * telling clients that voting isn't allowed. - * - * @return True if voting is allowed, false if voting is in progress - * or the cooldown is active. - */ -stock bool:NativeVotes_IsNewVoteAllowed() -{ - if (NativeVotes_IsVoteInProgress() || NativeVotes_CheckVoteDelay() != 0) - { - return false; - } - - return true; -} - -/** - * Used when callvote is called with no arguments. - * - * This is used to configure the VoteSetup usermessage on TF2 and CS:GO - * - * @param client Client, in case the votes are restricted by client - * @param voteTypes Populate this array with the vote types this server supports - * Custom and multiple choice votes are not supported from - * the GUI and are thus ignored. - * @return Plugin_Continue to allow the server itself (or another plugin) to process the callvote - * Plugin_Changed if you're changing the voteTypes, - * Plugin_Handled to return a blank VoteSetup usermessage - * Plugin_Stop to prevent VoteSetup usermessage (not recommended) - */ -//functag public Action:NativeVotes_CallVoteSetupHandler(client, NativeVotesType:voteTypes[]); - -/** - * Forward for "callvote" handling - * - * You should respond to this by starting a vote or by calling NativeVotes_DisplayCallVoteFail - * - * @param client Client - * @param voteType Type of vote being called. This will NEVER be a multiple-choice or custom vote. - * @param voteArgument Vote argument or blank if the vote type has no argument. - * @param target target userid for kick votes or 0 for all other votes - * @return Plugin_Continue to allow the server itself (or another plugin) to process the callvote - * Plugin_Handled if you processed this vote type - * Plugin_Stop to block the vote type (not recommended) - */ -//functag public Action:NativeVotes_CallVoteHandler(client, NativeVotesType:voteType, const String:voteArgument[], target); - -/** - * Register a plugin as a vote manager. - * This is used to abstract away the details of the callvote command. - * - * @param callHandler Handler for callvote commands. - * @param setupHandler Handler to override the which vote types your server supports. Only useful on TF2 and CS:GO. - * @noreturn - */ -//native NativeVotes_RegisterVoteManager(NativeVotes_CallVoteHandler:callHandler, NativeVotes_CallVoteSetupHandler:setupHandler=INVALID_FUNCTION); - -/** - * Send a call vote fail screen to a user - * Used to respond to a callvote with invalid arguments or for other reasons - * (such as trying to target an admin for a kick/ban vote) - * - * @param client The client to display the fail screen to - * @param reason A vote call fail reason - * @param time For NativeVotesCallFail_Recent, the number of seconds until the vote - * can be called again - */ -native NativeVotes_DisplayCallVoteFail(client, NativeVotesCallFailType:reason, time); - -/** - * Redraws the vote title from inside a MenuAction_Display callback - * Not supported on L4D - * - * @param text Vote title to draw - * @error If called from outside MenuAction_Display - * @return Plugin_Changed if the change is allowed, Plugin_Continue if it isn't. - */ -native Action:NativeVotes_RedrawVoteTitle(const String:text[]); - -/** - * Redraws the vote text from inside a MenuAction_DisplayItem callback. - * Only supported on multiple-choice votes - * - * @param text Vote text to draw. - * @error If called from outside MenuAction_DisplayItem - * @return Plugin_Changed if the change is allowed, Plugin_Continue if it isn't. - */ -native Action:NativeVotes_RedrawVoteItem(const String:text[]); - -/** - * Retrieves voting information from MenuAction_VoteEnd. - * - * @param param2 Second parameter of MenuAction_VoteEnd. - * @param winningVotes Number of votes received by the winning option. - * @param totalVotes Number of total votes received. - * @noreturn - */ -stock NativeVotes_GetInfo(param2, &winningVotes, &totalVotes) -{ - winningVotes = param2 & 0xFFFF; - totalVotes = param2 >> 16; -} - -/** - * Do not edit below this line! - */ -public SharedPlugin:__pl_nativevotes = -{ - name = "nativevotes", - file = "nativevotes.smx", -#if defined REQUIRE_PLUGINS - required = 1, -#else - required = 0, -#endif -}; - -public __pl_nativevotes_SetNTVOptional() -{ - MarkNativeAsOptional("NativeVotes_IsVoteTypeSupported"); - MarkNativeAsOptional("NativeVotes_Create"); - MarkNativeAsOptional("NativeVotes_Close"); - MarkNativeAsOptional("NativeVotes_AddItem"); - MarkNativeAsOptional("NativeVotes_InsertItem"); - MarkNativeAsOptional("NativeVotes_RemoveItem"); - MarkNativeAsOptional("NativeVotes_RemoveAllItems"); - MarkNativeAsOptional("NativeVotes_GetItem"); - MarkNativeAsOptional("NativeVotes_GetItemCount"); - MarkNativeAsOptional("NativeVotes_SetDetails"); - MarkNativeAsOptional("NativeVotes_GetDetails"); - MarkNativeAsOptional("NativeVotes_SetTitle"); - MarkNativeAsOptional("NativeVotes_GetTitle"); - MarkNativeAsOptional("NativeVotes_SetTarget"); - MarkNativeAsOptional("NativeVotes_GetTarget"); - MarkNativeAsOptional("NativeVotes_GetTargetSteam"); - MarkNativeAsOptional("NativeVotes_IsVoteInProgress"); - MarkNativeAsOptional("NativeVotes_GetMaxItems"); - MarkNativeAsOptional("NativeVotes_SetOptionFlags"); - MarkNativeAsOptional("NativeVotes_GetOptionFlags"); - MarkNativeAsOptional("NativeVotes_Cancel"); - MarkNativeAsOptional("NativeVotes_SetResultCallback"); - MarkNativeAsOptional("NativeVotes_CheckVoteDelay"); - MarkNativeAsOptional("NativeVotes_IsClientInVotePool"); - MarkNativeAsOptional("NativeVotes_RedrawClientVote"); - MarkNativeAsOptional("NativeVotes_RedrawClientVote"); - MarkNativeAsOptional("NativeVotes_GetType"); - MarkNativeAsOptional("NativeVotes_SetTeam"); - MarkNativeAsOptional("NativeVotes_GetTeam"); - MarkNativeAsOptional("NativeVotes_SetInitiator"); - MarkNativeAsOptional("NativeVotes_GetInitiator"); - MarkNativeAsOptional("NativeVotes_Display"); - MarkNativeAsOptional("NativeVotes_DisplayPass"); - MarkNativeAsOptional("NativeVotes_DisplayPassCustomToOne"); - MarkNativeAsOptional("NativeVotes_DisplayPassEx"); - MarkNativeAsOptional("NativeVotes_DisplayFail"); - MarkNativeAsOptional("NativeVotes_RegisterVoteManager"); - MarkNativeAsOptional("NativeVotes_DisplayCallVoteFail"); - MarkNativeAsOptional("NativeVotes_RedrawVoteTitle"); - MarkNativeAsOptional("NativeVotes_RedrawVoteItem"); -} diff --git a/includes/smjansson.inc b/includes/smjansson.inc new file mode 100644 index 0000000..1d7c9f8 --- /dev/null +++ b/includes/smjansson.inc @@ -0,0 +1,1763 @@ +#if defined _jansson_included_ + #endinput +#endif +#define _jansson_included_ + +/** + * --- Type + * + * The JSON specification (RFC 4627) defines the following data types: + * object, array, string, number, boolean, and null. + * JSON types are used dynamically; arrays and objects can hold any + * other data type, including themselves. For this reason, Jansson's + * type system is also dynamic in nature. There's one Handle type to + * represent all JSON values, and the referenced structure knows the + * type of the JSON value it holds. + * + */ +enum JSONType { + JSONType_Object, + JSONType_Array, + JSONType_String, + JSONType_Integer, + JSONType_Float, + JSONType_True, + JSONType_False, + JSONType_Null +}; + +/** + * Return the type of the JSON value. + * + * @param hObj Handle to the JSON value + * + * @return JSONType of the value. + */ +native JSONType json_typeof(JSONValue hObj); + +/** + * The type of a JSON value is queried and tested using these macros + * + * @param %1 Handle to the JSON value + * + * @return True if the value has the correct type. + */ +#define json_is_object(%1) ( json_typeof(%1) == JSONType_Object ) +#define json_is_array(%1) ( json_typeof(%1) == JSONType_Array ) +#define json_is_string(%1) ( json_typeof(%1) == JSONType_String ) +#define json_is_integer(%1) ( json_typeof(%1) == JSONType_Integer ) +#define json_is_real(%1) ( json_typeof(%1) == JSONType_Float ) +#define json_is_true(%1) ( json_typeof(%1) == JSONType_True ) +#define json_is_false(%1) ( json_typeof(%1) == JSONType_False ) +#define json_is_null(%1) ( json_typeof(%1) == JSONType_Null ) +#define json_is_number(%1) ( json_typeof(%1) == JSONType_Integer || json_typeof(%1) == JSONType_Float ) +#define json_is_boolean(%1) ( json_typeof(%1) == JSONType_True || json_typeof(%1) == JSONType_False ) + +/** + * Saves json_type as a String in output + * + * @param input json_type value to convert to string + * @param output Buffer to store the json_type value + * @param maxlength Maximum length of string buffer. + * + * @return False if the type does not exist. + */ +stock bool Stringify_json_type(JSONType input, char[] output, int maxlength) { + switch(input) { + case JSONType_Object: strcopy(output, maxlength, "Object"); + case JSONType_Array: strcopy(output, maxlength, "Array"); + case JSONType_String: strcopy(output, maxlength, "String"); + case JSONType_Integer: strcopy(output, maxlength, "Integer"); + case JSONType_Float: strcopy(output, maxlength, "Float"); + case JSONType_True: strcopy(output, maxlength, "True"); + case JSONType_False: strcopy(output, maxlength, "False"); + case JSONType_Null: strcopy(output, maxlength, "Null"); + default: return false; + } + + return true; +} + +/** + * --- Equality + * + * - Two integer or real values are equal if their contained numeric + * values are equal. An integer value is never equal to a real value, + * though. + * - Two strings are equal if their contained UTF-8 strings are equal, + * byte by byte. Unicode comparison algorithms are not implemented. + * - Two arrays are equal if they have the same number of elements and + * each element in the first array is equal to the corresponding + * element in the second array. + * - Two objects are equal if they have exactly the same keys and the + * value for each key in the first object is equal to the value of + * the corresponding key in the second object. + * - Two true, false or null values have no "contents", so they are + * equal if their types are equal. + * + */ + +/** + * Test whether two JSON values are equal. + * + * @param hObj Handle to the first JSON node + * @param hOther Handle to the second JSON node + * + * @return Returns false if they are inequal or one + * or both of the pointers are NULL. + */ +native bool json_equal(JSONValue hObj, JSONValue hOther); + + + + +/** + * --- Copying + * + * Jansson supports two kinds of copying: shallow and deep. There is + * a difference between these methods only for arrays and objects. + * + * Shallow copying only copies the first level value (array or object) + * and uses the same child values in the copied value. + * + * Deep copying makes a fresh copy of the child values, too. Moreover, + * all the child values are deep copied in a recursive fashion. + * + */ + +/** + * Get a shallow copy of the passed object + * + * @param hObj Handle to JSON object to be copied + * + * @return Returns a shallow copy of the object, + * or INVALID_HANDLE on error. + */ +native JSONValue json_copy(JSONValue hObj); + +/** + * Get a deep copy of the passed object + * + * @param hObj Handle to JSON object to be copied + * + * @return Returns a deep copy of the object, + * or INVALID_HANDLE on error. + */ +native JSONValue json_deep_copy(JSONValue hObj); + + + + +/** + * --- Objects + * + * A JSON object is a dictionary of key-value pairs, where the + * key is a Unicode string and the value is any JSON value. + * + */ + +/** + * Returns a handle to a new JSON object, or INVALID_HANDLE on error. + * Initially, the object is empty. + * + * @return Handle to a new JSON object. + */ +native JSONObject json_object(); + +/** + * Returns the number of elements in hObj + * + * @param hObj Handle to JSON object + * + * @return Number of elements in hObj, + * or 0 if hObj is not a JSON object. + */ +native int json_object_size(JSONObject hObj); + +/** + * Get a value corresponding to sKey from hObj + * + * @param hObj Handle to JSON object to get a value from + * @param sKey Key to retrieve + * + * @return Handle to a the JSON object or + * INVALID_HANDLE on error. + */ +native JSONValue json_object_get(JSONObject hObj, const char[] sKey); + +/** + * Set the value of sKey to hValue in hObj. + * If there already is a value for key, it is replaced by the new value. + * + * @param hObj Handle to JSON object to set a value on + * @param sKey Key to store in the object + * Must be a valid null terminated UTF-8 encoded + * Unicode string. + * @param hValue Value to store in the object + * + * @return True on success. + */ +native bool json_object_set(JSONObject hObj, const char[] sKey, JSONValue hValue); + +/** + * Set the value of sKey to hValue in hObj. + * If there already is a value for key, it is replaced by the new value. + * This function automatically closes the Handle to the value object. + * + * @param hObj Handle to JSON object to set a value on + * @param sKey Key to store in the object + * Must be a valid null terminated UTF-8 encoded + * Unicode string. + * @param hValue Value to store in the object + * + * @return True on success. + */ +native bool json_object_set_new(JSONObject hObj, const char[] sKey, JSONValue hValue); + +/** + * Delete sKey from hObj if it exists. + * + * @param hObj Handle to JSON object to delete a key from + * @param sKey Key to delete + * + * @return True on success. + */ +native bool json_object_del(JSONObject hObj, const char[] sKey); + +/** + * Remove all elements from hObj. + * + * @param hObj Handle to JSON object to remove all + * elements from. + * + * @return True on success. + */ +native bool json_object_clear(JSONObject hObj); + +/** + * Update hObj with the key-value pairs from hOther, overwriting + * existing keys. + * + * @param hObj Handle to JSON object to update + * @param hOther Handle to JSON object to get update + * keys/values from. + * + * @return True on success. + */ +native bool json_object_update(JSONObject hObj, JSONObject hOther); + +/** + * Like json_object_update(), but only the values of existing keys + * are updated. No new keys are created. + * + * @param hObj Handle to JSON object to update + * @param hOther Handle to JSON object to get update + * keys/values from. + * + * @return True on success. + */ +native bool json_object_update_existing(JSONObject hObj, JSONObject hOther); + +/** + * Like json_object_update(), but only new keys are created. + * The value of any existing key is not changed. + * + * @param hObj Handle to JSON object to update + * @param hOther Handle to JSON object to get update + * keys/values from. + * + * @return True on success. + */ +native bool json_object_update_missing(JSONObject hObj, JSONObject hOther); + + + + +/** + * Object iteration + * + * Example code: + * - We assume hObj is a Handle to a valid JSON object. + * + * + * new Handle:hIterator = json_object_iter(hObj); + * while(hIterator != INVALID_HANDLE) + * { + * new String:sKey[128]; + * json_object_iter_key(hIterator, sKey, sizeof(sKey)); + * + * new Handle:hValue = json_object_iter_value(hIterator); + * + * // Do something with sKey and hValue + * + * CloseHandle(hValue); + * + * hIterator = json_object_iter_next(hObj, hIterator); + * } + * + */ + +/** + * Returns a handle to an iterator which can be used to iterate over + * all key-value pairs in hObj. + * If you are not iterating to the end of hObj make sure to close the + * handle to the iterator manually. + * + * @param hObj Handle to JSON object to get an iterator + * for. + * + * @return Handle to JSON object iterator, + * or INVALID_HANDLE on error. + */ +native JSONObjectIterator json_object_iter(JSONObject hObj); + +/** + * Like json_object_iter(), but returns an iterator to the key-value + * pair in object whose key is equal to key. + * Iterating forward to the end of object only yields all key-value + * pairs of the object if key happens to be the first key in the + * underlying hash table. + * + * @param hObj Handle to JSON object to get an iterator + * for. + * @param sKey Start key for the iterator + * + * @return Handle to JSON object iterator, + * or INVALID_HANDLE on error. + */ +native JSONObjectIterator json_object_iter_at(JSONObject hObj, const char[] sKey); + +/** + * Returns an iterator pointing to the next key-value pair in object. + * This automatically closes the Handle to the iterator hIter. + * + * @param hObj Handle to JSON object. + * @param hIter Handle to JSON object iterator. + * + * @return Handle to JSON object iterator, + * or INVALID_HANDLE on error, or if the + * whole object has been iterated through. + */ +native JSONObjectIterator json_object_iter_next(JSONObject hObj, JSONObjectIterator hIter); + +/** + * Extracts the associated key of hIter as a null terminated UTF-8 + * encoded string in the passed buffer. + * + * @param hIter Handle to the JSON String object + * @param sKeyBuffer Buffer to store the value of the String. + * @param maxlength Maximum length of string buffer. + * @error Invalid JSON Object Iterator. + * @return Length of the returned string or -1 on error. + */ +native int json_object_iter_key(JSONObjectIterator hIter, char[] sKeyBuffer, int maxlength); + +/** + * Returns a handle to the value hIter is pointing at. + * + * @param hIter Handle to JSON object iterator. + * + * @return Handle to value or INVALID_HANDLE on error. + */ +native JSONValue json_object_iter_value(JSONObjectIterator hIter); + +/** + * Set the value of the key-value pair in hObj, that is pointed to + * by hIter, to hValue. + * + * @param hObj Handle to JSON object. + * @param hIter Handle to JSON object iterator. + * @param hValue Handle to JSON value. + * + * @return True on success. + */ +native bool json_object_iter_set(JSONObject hObj, JSONObjectIterator hIter, JSONValue hValue); + +/** + * Set the value of the key-value pair in hObj, that is pointed to + * by hIter, to hValue. + * This function automatically closes the Handle to the value object. + * + * @param hObj Handle to JSON object. + * @param hIter Handle to JSON object iterator. + * @param hValue Handle to JSON value. + * + * @return True on success. + */ +native bool json_object_iter_set_new(JSONObject hObj, JSONObjectIterator hIter, JSONValue hValue); + + + + +/** + * Arrays + * + * A JSON array is an ordered collection of other JSON values. + * + */ + +/** + * Returns a handle to a new JSON array, or INVALID_HANDLE on error. + * + * @return Handle to the new JSON array + */ +native JSONArray json_array(); + +/** + * Returns the number of elements in hArray + * + * @param hObj Handle to JSON array + * + * @return Number of elements in hArray, + * or 0 if hObj is not a JSON array. + */ +native int json_array_size(JSONArray hArray); + +/** + * Returns the element in hArray at position iIndex. + * + * @param hArray Handle to JSON array to get a value from + * @param iIndex Position to retrieve + * + * @return Handle to a the JSON object or + * INVALID_HANDLE on error. + */ +native JSONValue json_array_get(JSONArray hArray, int iIndex); + +/** + * Replaces the element in array at position iIndex with hValue. + * The valid range for iIndex is from 0 to the return value of + * json_array_size() minus 1. + * + * @param hArray Handle to JSON array + * @param iIndex Position to replace + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_set(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Replaces the element in array at position iIndex with hValue. + * The valid range for iIndex is from 0 to the return value of + * json_array_size() minus 1. + * This function automatically closes the Handle to the value object. + * + * @param hArray Handle to JSON array + * @param iIndex Position to replace + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_set_new(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Appends value to the end of array, growing the size of array by 1. + * + * @param hArray Handle to JSON array + * @param hValue Value to append to the array + * + * @return True on success. + */ +native bool json_array_append(JSONArray hArray, JSONValue hValue); + +/** + * Appends value to the end of array, growing the size of array by 1. + * This function automatically closes the Handle to the value object. + * + * @param hArray Handle to JSON array + * @param hValue Value to append to the array + * + * @return True on success. + */ +native bool json_array_append_new(JSONArray hArray, JSONValue hValue); + +/** + * Inserts value to hArray at position iIndex, shifting the elements at + * iIndex and after it one position towards the end of the array. + * + * @param hArray Handle to JSON array + * @param iIndex Position to insert at + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_insert(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Inserts value to hArray at position iIndex, shifting the elements at + * iIndex and after it one position towards the end of the array. + * This function automatically closes the Handle to the value object. + * + * @param hArray Handle to JSON array + * @param iIndex Position to insert at + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_insert_new(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Removes the element in hArray at position iIndex, shifting the + * elements after iIndex one position towards the start of the array. + * + * @param hArray Handle to JSON array + * @param iIndex Position to insert at + * + * @return True on success. + */ +native bool json_array_remove(JSONArray hArray, int iIndex); + +/** + * Removes all elements from hArray. + * + * @param hArray Handle to JSON array + * + * @return True on success. + */ +native bool json_array_clear(JSONArray hArray); + +/** + * Appends all elements in hOther to the end of hArray. + * + * @param hArray Handle to JSON array to be extended + * @param hOther Handle to JSON array, source to copy from + * + * @return True on success. + */ +native bool json_array_extend(JSONArray hArray, JSONArray hOther); + + + + +/** + * Booleans & NULL + * + */ + +/** + * Returns a handle to a new JSON Boolean with value true, + * or INVALID_HANDLE on error. + * + * @return Handle to the new Boolean object + */ +native JSONValue json_true(); + +/** + * Returns a handle to a new JSON Boolean with value false, + * or INVALID_HANDLE on error. + * + * @return Handle to the new Boolean object + */ +native JSONValue json_false(); + +/** + * Returns a handle to a new JSON Boolean with the value passed + * in bState or INVALID_HANDLE on error. + * + * @param bState Value for the new Boolean object + * @return Handle to the new Boolean object + */ +native JSONValue json_boolean(bool bState); + +/** + * Returns a handle to a new JSON NULL or INVALID_HANDLE on error. + * + * @return Handle to the new NULL object + */ +native JSONValue json_null(); + + + + +/** + * Strings + * + * Jansson uses UTF-8 as the character encoding. All JSON strings must + * be valid UTF-8 (or ASCII, as it's a subset of UTF-8). Normal null + * terminated C strings are used, so JSON strings may not contain + * embedded null characters. + * + */ + +/** + * Returns a handle to a new JSON string, or INVALID_HANDLE on error. + * + * @param sValue Value for the new String object + * Must be a valid UTF-8 encoded Unicode string. + * @return Handle to the new String object + */ +native JSONString json_string(const char[] sValue); + +/** + * Saves the associated value of hString as a null terminated UTF-8 + * encoded string in the passed buffer. + * + * @param hString Handle to the JSON String object + * @param sValueBuffer Buffer to store the value of the String. + * @param maxlength Maximum length of string buffer. + * @error Invalid JSON String Object. + * @return Length of the returned string or -1 on error. + */ +native int json_string_value(JSONString hString, char[] sValueBuffer, int maxlength); + +/** + * Sets the associated value of JSON String object to value. + * + * @param hString Handle to the JSON String object + * @param sValue Value to set the object to. + * Must be a valid UTF-8 encoded Unicode string. + * @error Invalid JSON String Object. + * @return True on success. + */ +native bool json_string_set(JSONString hString, const char[] sValue); + + + + +/** + * Numbers + * + * The JSON specification only contains one numeric type, 'number'. + * The C (and Pawn) programming language has distinct types for integer + * and floating-point numbers, so for practical reasons Jansson also has + * distinct types for the two. They are called 'integer' and 'real', + * respectively. (Whereas 'real' is a 'Float' for Pawn). + * Therefore a number is represented by either a value of the type + * JSONType_Integer or of the type JSONType_Float. + * + */ + +/** + * Returns a handle to a new JSON integer, or INVALID_HANDLE on error. + * + * @param iValue Value for the new Integer object + * @return Handle to the new Integer object + */ +native JSONInteger json_integer(int iValue); + +/** + * Returns the associated value of a JSON Integer Object. + * + * @param hInteger Handle to the JSON Integer object + * @error Invalid JSON Integer Object. + * @return Value of the hInteger, + * or 0 if hInteger is not a JSON integer. + */ +native int json_integer_value(JSONInteger hInteger); + +/** + * Sets the associated value of JSON Integer to value. + * + * @param hInteger Handle to the JSON Integer object + * @param iValue Value to set the object to. + * @error Invalid JSON Integer Object. + * @return True on success. + */ +native bool json_integer_set(JSONInteger hInteger, int iValue); + + + + +/** + * Returns a handle to a new JSON real, or INVALID_HANDLE on error. + * + * @param fValue Value for the new Real object + * @return Handle to the new String object + */ +native JSONFloat json_real(float fValue); + +/** + * Returns the associated value of a JSON Real. + * + * @param hReal Handle to the JSON Real object + * @error Invalid JSON Real Object. + * @return Float value of hReal, + * or 0.0 if hReal is not a JSON Real. + */ +native float json_real_value(JSONFloat hReal); + +/** + * Sets the associated value of JSON Real to fValue. + * + * @param hReal Handle to the JSON Integer object + * @param fValue Value to set the object to. + * @error Invalid JSON Real handle. + * @return True on success. + */ +native bool json_real_set(JSONFloat hReal, float value); + +/** + * Returns the associated value of a JSON integer or a + * JSON Real, cast to Float regardless of the actual type. + * + * @param hNumber Handle to the JSON Number + * @error Not a JSON Real or JSON Integer + * @return Float value of hNumber, + * or 0.0 on error. + */ +native float json_number_value(JSONNumber hNumber); + + + + +/** + * Decoding + * + * This sections describes the functions that can be used to decode JSON text + * to the Jansson representation of JSON data. The JSON specification requires + * that a JSON text is either a serialized array or object, and this + * requirement is also enforced with the following functions. In other words, + * the top level value in the JSON text being decoded must be either array or + * object. + * + */ + +/** + * Decodes the JSON string sJSON and returns the array or object it contains. + * Errors while decoding can be found in the sourcemod error log. + * + * @param sJSON String containing valid JSON + + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load(const char[] sJSON); + +/** + * Decodes the JSON string sJSON and returns the array or object it contains. + * This function provides additional error feedback and does not log errors + * to the sourcemod error log. + * + * @param sJSON String containing valid JSON + * @param sErrorText This buffer will be filled with the error + * message. + * @param maxlen Size of the buffer + * @param iLine This int will contain the line of the error + * @param iColumn This int will contain the column of the error + * + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load_ex(const char[] sJSON, char[] sErrorText, int maxlen, int &iLine, int &iColumn); + +/** + * Decodes the JSON text in file sFilePath and returns the array or object + * it contains. + * Errors while decoding can be found in the sourcemod error log. + * + * @param sFilePath Path to a file containing pure JSON + * + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load_file(const char sFilePath[PLATFORM_MAX_PATH]); + +/** + * Decodes the JSON text in file sFilePath and returns the array or object + * it contains. + * This function provides additional error feedback and does not log errors + * to the sourcemod error log. + * + * @param sFilePath Path to a file containing pure JSON + * @param sErrorText This buffer will be filled with the error + * message. + * @param maxlen Size of the buffer + * @param iLine This int will contain the line of the error + * @param iColumn This int will contain the column of the error + * + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load_file_ex(const char sFilePath[PLATFORM_MAX_PATH], char[] sErrorText, int maxlen, int &iLine, int &iColumn); + + + +/** + * Encoding + * + * This sections describes the functions that can be used to encode values + * to JSON. By default, only objects and arrays can be encoded directly, + * since they are the only valid root values of a JSON text. + * + */ + +/** + * Saves the JSON representation of hObject in sJSON. + * + * @param hObject String containing valid JSON + * @param sJSON Buffer to store the created JSON string. + * @param maxlength Maximum length of string buffer. + * @param iIndentWidth Indenting with iIndentWidth spaces. + * The valid range for this is between 0 and 31 (inclusive), + * other values result in an undefined output. If this is set + * to 0, no newlines are inserted between array and object items. + * @param bEnsureAscii If this is set, the output is guaranteed + * to consist only of ASCII characters. This is achieved + * by escaping all Unicode characters outside the ASCII range. + * @param bSortKeys If this flag is used, all the objects in output are sorted + * by key. This is useful e.g. if two JSON texts are diffed + * or visually compared. + * @param bPreserveOrder If this flag is used, object keys in the output are sorted + * into the same order in which they were first inserted to + * the object. For example, decoding a JSON text and then + * encoding with this flag preserves the order of object keys. + * @return Length of the returned string or -1 on error. + */ +native int json_dump(JSONValue hObject, char[] sJSON, int maxlength, int iIndentWidth = 4, bool bEnsureAscii = false, bool bSortKeys = false, bool bPreserveOrder = false); + +/** + * Write the JSON representation of hObject to the file sFilePath. + * If sFilePath already exists, it is overwritten. + * + * @param hObject String containing valid JSON + * @param sFilePath Buffer to store the created JSON string. + * @param iIndentWidth Indenting with iIndentWidth spaces. + * The valid range for this is between 0 and 31 (inclusive), + * other values result in an undefined output. If this is set + * to 0, no newlines are inserted between array and object items. + * @param bEnsureAscii If this is set, the output is guaranteed + * to consist only of ASCII characters. This is achieved + * by escaping all Unicode characters outside the ASCII range. + * @param bSortKeys If this flag is used, all the objects in output are sorted + * by key. This is useful e.g. if two JSON texts are diffed + * or visually compared. + * @param bPreserveOrder If this flag is used, object keys in the output are sorted + * into the same order in which they were first inserted to + * the object. For example, decoding a JSON text and then + * encoding with this flag preserves the order of object keys. + * @return Length of the returned string or -1 on error. + */ +native bool json_dump_file(JSONValue hObject, const char[] sFilePath, int iIndentWidth = 4, bool bEnsureAscii = false, bool bSortKeys = false, bool bPreserveOrder = false); + + + + +/** + * MethodMaps + * + * Again: EXPERIMENTAL! + * + */ + + +enum JSONObjectUpdateType { + Update_All = 0, + Update_Existing, + Update_Missing +}; + +/** + * Base methodmap for all of smjansson's handles + */ +methodmap JSONValue < Handle { + property JSONType Type { + public get() { + return json_typeof(this); + } + } + + property bool IsObject { + public get() { + return (this.Type == JSONType_Object); + } + } + + property bool IsArray { + public get() { + return (this.Type == JSONType_Array); + } + } + + property bool IsString { + public get() { + return (this.Type == JSONType_String); + } + } + + property bool IsInteger { + public get() { + return (this.Type == JSONType_Integer); + } + } + + property bool IsFloat { + public get() { + return (this.Type == JSONType_Float); + } + } + + property bool IsTrue { + public get() { + return (this.Type == JSONType_True); + } + } + + property bool IsFalse { + public get() { + return (this.Type == JSONType_False); + } + } + + property bool IsNull { + public get() { + return (this.Type == JSONType_Null); + } + } + + property bool IsNumber { + public get() { + return (this.Type == JSONType_Integer || this.Type == JSONType_Float); + } + } + + property bool IsBoolean { + public get() { + return (this.Type == JSONType_True || this.Type == JSONType_False); + } + } + + property any Value { + // not implemented + } + + public bool Equals(JSONValue other) { + return json_equal(this, other); + } + + public JSONValue Copy(bool deep = false) { + if (deep) { + return view_as(json_deep_copy(this)); + } else { + return view_as(json_copy(this)); + } + } + + public void TypeToString(char[] buffer, int maxlength) { + if (!Stringify_json_type(view_as(this.Type), buffer, maxlength)) { + ThrowError("Attempting to get type of a non-SMJansson handle"); + } + } +} + +methodmap JSONBoolean < JSONValue { + public JSONBoolean(bool value) { + return view_as(json_boolean(value)); + } + + property bool Value { + public get() { + if (this.Type == JSONType_True) { + return true; + } else if (this.Type == JSONType_False) { + return false; + } + ThrowError("Not a JSONBoolean value"); + return false; + } + } +} + +methodmap JSONNull < JSONValue { + public JSONNull() { + return view_as(json_null()); + } +} + +methodmap JSONString < JSONValue { + public JSONString(const char[] value) { + return view_as(json_string(value)); + } + + public static JSONString Format(int bufferSize = 4096, const char[] format, any ...) { + char[] buffer = new char[bufferSize]; + VFormat(buffer, bufferSize, format, 3); + return new JSONString(buffer); + } + + public int GetString(char[] buffer, int length) { + return json_string_value(this, buffer, length); + } + + public bool SetString(char[] value) { + return json_string_set(this, value); + } +} + +/** + * Base map inherited by JSONInteger and JSONFloat to get the value of either, cast to float. + */ +methodmap JSONNumber < JSONValue { + public float FloatValue() { + return json_number_value(this); + } +} + +methodmap JSONInteger < JSONNumber { + public JSONInteger(int value) { + return view_as(json_integer(value)); + } + + property int Value { + public get() { + return json_integer_value(this); + } + public set(int value) { + json_integer_set(this, value); + } + } +} + +methodmap JSONFloat < JSONNumber { + public JSONFloat(float value) { + return view_as(json_real(value)); + } + + property float Value { + public get() { + return json_real_value(this); + } + public set(float value) { + json_real_set(this, value); + } + } +} + +/** + * Provides a few functions for valid root nodes (JSONArray and JSONObject) + */ +methodmap JSONRootNode < JSONValue { + /** + * Dumps the contents of the given root node to a string. + * + * @return Number of characters written + */ + public int ToString(char[] buffer, int maxlength, int indentWidth = 4, + bool asciiOnly = false, bool sortKeys = false, bool preserveOrder = false) { + return json_dump(this, buffer, maxlength, indentWidth, asciiOnly, sortKeys, + preserveOrder); + } + + /** + * @return True on success + */ + public bool ToFile(const char[] filePath, int indentWidth = 4, bool asciiOnly = false, + bool sortKeys = false, bool preserveOrder = false) { + return json_dump_file(this, filePath, indentWidth, asciiOnly, sortKeys, preserveOrder); + } + + public static JSONRootNode FromFile(const char[] filePath) { + char path[PLATFORM_MAX_PATH]; + strcopy(path, sizeof(path), filePath); + return view_as(json_load_file(path)); + } + + public static JSONRootNode Pack(const char[] packString, ArrayList params) { + return json_pack(packString, params); + } + + public void DumpToServer() { + char sMsg[4096]; + this.ToString(sMsg, sizeof(sMsg)); + + PrintToServer(sMsg); + } +} + +methodmap JSONArray < JSONRootNode { + public JSONArray() { + return view_as(json_array()); + } + + property int Length { + public get() { + if (this.Type != JSONType_Array) { + ThrowError("Handle is not an array"); + } + return json_array_size(this); + } + } + + public JSONValue Get(int index) { + return view_as(json_array_get(this, index)); + } + + public bool Set(int index, JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_array_set_new(this, index, value); + } + return json_array_set(this, index, value); + } + + public bool Append(JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_array_append_new(this, value); + } + return json_array_append(this, value); + } + + public bool Insert(int index, JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_array_insert_new(this, index, value); + } + return json_array_insert(this, index, value); + } + + public bool Remove(int index) { + return json_array_remove(this, index); + } + + public bool Clear() { + return json_array_clear(this); + } + + public bool Extend(JSONArray other) { + return json_array_extend(this, other); + } + + /** + * Utility functions + */ + + /* Booleans */ + + public bool GetBool(int index, bool defValue = false) { + JSONValue value = this.Get(index); + if(!value) + return defValue; + + JSONType type = value.Type; + delete value; + + switch (type) { + case JSONType_True: { return true; } + case JSONType_False: { return false; } + } + return defValue; + } + + public bool SetBool(int index, bool value) { + return this.Set(index, new JSONBoolean(value)); + } + + public bool AppendBool(bool value) { + return this.Append(new JSONBoolean(value)); + } + + public bool InsertBool(int index, bool value) { + return this.Insert(index, new JSONBoolean(value)); + } + + /* Floats */ + + public float GetFloat(int index, float defValue = 0.0) { + JSONValue value = this.Get(index); + if(!value) + return defValue; + + float result = (json_is_number(value) ? + (view_as(value)).FloatValue() : defValue); + delete value; + + return result; + } + + public bool SetFloat(int index, float value) { + return this.Set(index, new JSONFloat(value)); + } + + public bool AppendFloat(float value) { + return this.Append(new JSONFloat(value)); + } + + public bool InsertFloat(int index, float value) { + return this.Insert(index, new JSONFloat(value)); + } + + /* Integers */ + + public int GetInt(int index, int defValue = 0) { + JSONValue value = this.Get(index); + if(!value) + return defValue; + + int result = value.Type == JSONType_Integer ? (view_as(value)).Value : 0; + delete value; + + return result; + } + + public bool SetInt(int index, int value) { + return this.Set(index, new JSONInteger(value)); + } + + public bool AppendInt(int value) { + return this.Append(new JSONInteger(value)); + } + + public bool InsertInt(int index, int value) { + return this.Insert(index, new JSONInteger(value)); + } + + /* Strings */ + + public int GetString(int index, char[] buffer, int maxlength) { + JSONValue value = this.Get(index); + if(!value) + return -1; + + int result = -1; + if (value.Type == JSONType_String) { + result = (view_as(value)).GetString(buffer, maxlength); + } + delete value; + return result; + } + + public bool SetString(int index, const char[] value) { + return this.Set(index, new JSONString(value)); + } + + public bool AppendString(const char[] value) { + return this.Append(new JSONString(value)); + } + + public bool InsertString(int index, const char[] value) { + return this.Insert(index, new JSONString(value)); + } + + /* Misc. functions */ + + public static JSONArray FromFile(const char[] filePath) { + JSONRootNode data = JSONRootNode.FromFile(filePath); + + if (data.Type == JSONType_Array) { + return view_as(data); + } else { + ThrowError("File loaded by JSONArray.FromFile was not an array"); + delete data; + return null; + } + } + + public static JSONArray Pack(const char[] packString, ArrayList params) { + int length = strlen(packString); + if (packString[0] == '[' && packString[length - 1] == ']') { + return view_as(JSONRootNode.Pack(packString, params)); + } else { + ThrowError("Pack string '%s' is not appropriate for creating a JSONArray", + packString); + return null; + } + } +} + +methodmap JSONObject < JSONRootNode { + public JSONObject() { + return view_as(json_object()); + } + + property int Size { + public get() { + return json_object_size(this); + } + } + + public JSONValue Get(const char[] key) { + return view_as(json_object_get(this, key)); + } + + public bool Set(const char[] key, JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_object_set_new(this, key, value); + } + return json_object_set(this, key, value); + } + + /** + * @return true on success + */ + public bool Remove(const char[] key) { + return json_object_del(this, key); + } + + public bool Clear() { + return json_object_clear(this); + } + + public bool Update(JSONObject other, JSONObjectUpdateType updateType = Update_All) { + switch (updateType) { + case Update_Existing: { + return json_object_update_existing(this, other); + } + case Update_Missing: { + return json_object_update_missing(this, other); + } + } + return json_object_update(this, other); + } + + /** + * Utility functions + */ + + public bool GetBool(const char[] key, bool defValue = false) { + JSONValue value = this.Get(key); + if(!value) + return defValue; + + JSONType type = value.Type; + delete value; + + switch (type) { + case JSONType_True: { return true; } + case JSONType_False: { return false; } + } + return defValue; + } + + public bool SetBool(const char[] key, bool value) { + return this.Set(key, new JSONBoolean(value)); + } + + /* Floats */ + + public float GetFloat(const char[] key, float defValue = 0.0) { + JSONValue value = this.Get(key); + if(!value) + return defValue; + + float result = (json_is_number(value) ? + (view_as(value)).FloatValue() : defValue); + delete value; + + return result; + } + + public bool SetFloat(const char[] key, float value) { + return this.Set(key, new JSONFloat(value)); + } + + /* Integers */ + + public int GetInt(const char[] key, int defValue = 0) { + JSONValue value = this.Get(key); + if(!value) + return defValue; + + int result = value.Type == JSONType_Integer ? + (view_as(value)).Value : defValue; + delete value; + + return result; + } + + public bool SetInt(const char[] key, int value) { + return this.Set(key, new JSONInteger(value)); + } + + /* Strings */ + + public int GetString(const char[] key, char[] buffer, int maxlength) { + JSONValue value = this.Get(key); + if(!value) + return -1; + + int result = -1; + if (value.Type == JSONType_String) { + result = (view_as(value)).GetString(buffer, maxlength); + } + delete value; + return result; + } + + public bool SetString(const char[] key, const char[] value) { + return this.Set(key, new JSONString(value)); + } + + /* Misc. functions */ + + public static JSONObject FromFile(const char[] filePath) { + JSONRootNode data = JSONRootNode.FromFile(filePath); + + if (data.Type == JSONType_Object) { + return view_as(data); + } else { + ThrowError("File loaded by JSONObject.FromFile was not an object"); + delete data; + return null; + } + } + + public static JSONObject Pack(const char[] packString, ArrayList params) { + int length = strlen(packString); + if (packString[0] == '{' && packString[length - 1] == '}') { + return view_as(JSONRootNode.Pack(packString, params)); + } else { + ThrowError("Pack string '%s' is not appropriate for creating a JSONObject", + packString); + return null; + } + } +} + +methodmap JSONObjectIterator < Handle { + public static JSONObjectIterator From(JSONObject obj, const char[] key = "") { + if (strlen(key) > 0) { + return view_as(json_object_iter_at(obj, key)); + } + return view_as(json_object_iter(obj)); + } + + public JSONObjectIterator Next(JSONObject obj) { + return view_as(json_object_iter_next(obj, this)); + } + + public int GetKey(char[] buffer, int maxlength) { + return json_object_iter_key(this, buffer, maxlength); + } + + public JSONValue GetValue() { + return view_as(json_object_iter_value(this)); + } + + public bool SetValue(JSONObject obj, JSONValue value, bool autoclose = true) { + if (autoclose) { + return json_object_iter_set_new(obj, this, value); + } + return json_object_iter_set(obj, this, value); + } +} + + +/** + * Some additional constructors + * + * + */ + +/** + * Returns a handle to a new JSON string, or INVALID_HANDLE on error. + * Formats the string according to the SourceMod format rules. + * The result must be a valid UTF-8 encoded Unicode string. + * + * @param sFormat Formatting rules. + * @param ... Variable number of format parameters. + * @return Handle to the new String object + */ +public JSONString JSONString_ByFormat(const char[] sFormat, ...) { + char sTmp[4096]; + VFormat(sTmp, sizeof(sTmp), sFormat, 2); + + return new JSONString(sTmp); +} + + +/** + * Returns a handle to a new JSON string, or INVALID_HANDLE on error. + * This stock allows to specify the size of the temporary buffer used + * to create the string. Use this if the default of 4096 is not enough + * for your string. + * Formats the string according to the SourceMod format rules. + * The result must be a valid UTF-8 encoded Unicode string. + * + * @param tmpBufferLength Size of the temporary buffer + * @param sFormat Formatting rules. + * @param ... Variable number of format parameters. + * @return Handle to the new String object + */ +public JSONString JSONString_ByFormatEx(int tmpBufferLength, const char[] sFormat, ...) { + char[] sTmp = new char[tmpBufferLength]; + VFormat(sTmp, tmpBufferLength, sFormat, 3); + + return new JSONString(sTmp); +} + + +/** + * Pack String Rules + * + * Here's the full list of format characters: + * n Output a JSON null value. No argument is consumed. + * s Output a JSON string, consuming one argument. + * b Output a JSON bool value, consuming one argument. + * i Output a JSON integer value, consuming one argument. + * f Output a JSON real value, consuming one argument. + * r Output a JSON real value, consuming one argument. + * [] Build an array with contents from the inner format string, + * recursive value building is supported. + * No argument is consumed. + * {} Build an array with contents from the inner format string. + * The first, third, etc. format character represent a key, + * and must be s (as object keys are always strings). The + * second, fourth, etc. format character represent a value. + * Recursive value building is supported. + * No argument is consumed. + * + */ + +/** + * This method can be used to create json objects/arrays directly + * without having to create the structure. + * See 'Pack String Rules' for more details. + * + * @param sPackString Pack string similiar to Format()s fmt. + * See 'Pack String Rules'. + * @param hParams ADT Array containing all keys and values + * in the order they appear in the pack string. + * + * @error Invalid pack string or pack string and + * ADT Array don't match up regarding type + * or size. + * @return Handle to JSON element. + */ +public JSONValue JSONValue_ByPack(const char[] sPackString, Handle hParams) { + int iPos = 0; + return json_pack_element_(sPackString, iPos, hParams); +} + + + + + +/** +* Internal stocks used by json_pack(). Don't use these directly! +* +*/ +public JSONArray json_pack_array_(const char[] sFormat, int &iPos, Handle hParams) { + JSONArray hObj = new JSONArray(); + int iStrLen = strlen(sFormat); + + for(; iPos < iStrLen;) { + int this_char = sFormat[iPos]; + + if(this_char == 32 || this_char == 58 || this_char == 44) { + // Skip whitespace, ',' and ':' + iPos++; + continue; + } + + if(this_char == 93) { + // array end + iPos++; + break; + } + + // Get the next entry as value + // This automatically increments the position! + JSONValue hValue = json_pack_element_(sFormat, iPos, hParams); + + // Append the value to the array. + hObj.Append(hValue); + } + + return hObj; +} + +public JSONObject json_pack_object_(const char[] sFormat, int &iPos, Handle hParams) { + JSONObject hObj = new JSONObject(); + int iStrLen = strlen(sFormat); + + for(; iPos < iStrLen;) { + int this_char = sFormat[iPos]; + + if(this_char == 32 || this_char == 58 || this_char == 44) { + // Skip whitespace, ',' and ':' + iPos++; + continue; + } + + if(this_char == 125) { + // } --> object end + iPos++; + break; + } + + if(this_char != 115) { + LogError("Object keys must be strings at %d.", iPos); + CloseHandle(hObj); + return view_as(INVALID_HANDLE); + } + + // Get the key string for this object from + // the hParams array. + char sKey[255]; + GetArrayString(hParams, 0, sKey, sizeof(sKey)); + RemoveFromArray(hParams, 0); + + // Advance one character in the pack string, + // because we've just read the Key string for + // this object. + iPos++; + + // Get the next entry as value + // This automatically increments the position! + JSONValue hValue = json_pack_element_(sFormat, iPos, hParams); + + // Insert into object + hObj.Set(sKey, hValue); + } + + return hObj; +} + +public JSONValue json_pack_element_(const char[] sFormat, int &iPos, Handle hParams) { + int this_char = sFormat[iPos]; + while(this_char == 32 || this_char == 58 || this_char == 44) { + iPos++; + this_char = sFormat[iPos]; + } + + // Advance one character in the pack string + iPos++; + + switch(this_char) { + case 91: { + // { --> Array + return json_pack_array_(sFormat, iPos, hParams); + } + + case 123: { + // { --> Object + return json_pack_object_(sFormat, iPos, hParams); + + } + + case 98: { + // b --> Boolean + int iValue = GetArrayCell(hParams, 0); + RemoveFromArray(hParams, 0); + + return json_boolean(view_as(iValue)); + } + + case 102, 114: { + // r,f --> Real (Float) + float fValue = GetArrayCell(hParams, 0); + RemoveFromArray(hParams, 0); + + return json_real(fValue); + } + + case 110: { + // n --> NULL + return json_null(); + } + + case 115: { + // s --> String + char sKey[255]; + GetArrayString(hParams, 0, sKey, sizeof(sKey)); + RemoveFromArray(hParams, 0); + + return json_string(sKey); + } + + case 105: { + // i --> Integer + int iValue = GetArrayCell(hParams, 0); + RemoveFromArray(hParams, 0); + + return json_integer(iValue); + } + } + + SetFailState("Invalid pack String '%s'. Type '%s' not supported at %i", sFormat, this_char, iPos); + return json_null(); +} + + +/** + * Not yet implemented + * + * native json_object_foreach(Handle:hObj, ForEachCallback:cb); + * native Handle:json_unpack(const String:sFormat[], ...); + * + */ + + + /** + * Do not edit below this line! + */ +public Extension __ext_smjansson = +{ + name = "SMJansson", + file = "smjansson.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public __ext_smjansson_SetNTVOptional() +{ + MarkNativeAsOptional("json_typeof"); + MarkNativeAsOptional("json_equal"); + + MarkNativeAsOptional("json_copy"); + MarkNativeAsOptional("json_deep_copy"); + + MarkNativeAsOptional("json_object"); + MarkNativeAsOptional("json_object_size"); + MarkNativeAsOptional("json_object_get"); + MarkNativeAsOptional("json_object_set"); + MarkNativeAsOptional("json_object_set_new"); + MarkNativeAsOptional("json_object_del"); + MarkNativeAsOptional("json_object_clear"); + MarkNativeAsOptional("json_object_update"); + MarkNativeAsOptional("json_object_update_existing"); + MarkNativeAsOptional("json_object_update_missing"); + + MarkNativeAsOptional("json_object_iter"); + MarkNativeAsOptional("json_object_iter_at"); + MarkNativeAsOptional("json_object_iter_next"); + MarkNativeAsOptional("json_object_iter_key"); + MarkNativeAsOptional("json_object_iter_value"); + MarkNativeAsOptional("json_object_iter_set"); + MarkNativeAsOptional("json_object_iter_set_new"); + + MarkNativeAsOptional("json_array"); + MarkNativeAsOptional("json_array_size"); + MarkNativeAsOptional("json_array_get"); + MarkNativeAsOptional("json_array_set"); + MarkNativeAsOptional("json_array_set_new"); + MarkNativeAsOptional("json_array_append"); + MarkNativeAsOptional("json_array_append_new"); + MarkNativeAsOptional("json_array_insert"); + MarkNativeAsOptional("json_array_insert_new"); + MarkNativeAsOptional("json_array_remove"); + MarkNativeAsOptional("json_array_clear"); + MarkNativeAsOptional("json_array_extend"); + + MarkNativeAsOptional("json_string"); + MarkNativeAsOptional("json_string_value"); + MarkNativeAsOptional("json_string_set"); + + MarkNativeAsOptional("json_integer"); + MarkNativeAsOptional("json_integer_value"); + MarkNativeAsOptional("json_integer_set"); + + MarkNativeAsOptional("json_real"); + MarkNativeAsOptional("json_real_value"); + MarkNativeAsOptional("json_real_set"); + MarkNativeAsOptional("json_number_value"); + + MarkNativeAsOptional("json_boolean"); + MarkNativeAsOptional("json_true"); + MarkNativeAsOptional("json_false"); + MarkNativeAsOptional("json_null"); + + MarkNativeAsOptional("json_load"); + MarkNativeAsOptional("json_load_file"); + + MarkNativeAsOptional("json_dump"); + MarkNativeAsOptional("json_dump_file"); +} +#endif diff --git a/includes/sourcetvmanager.inc b/includes/sourcetvmanager.inc new file mode 100644 index 0000000..4a0bf02 --- /dev/null +++ b/includes/sourcetvmanager.inc @@ -0,0 +1,543 @@ +#if defined _stvmngr_included + #endinput +#endif +#define _stvmngr_included + +// Some guidelines from the SDK about director camera shot durations +#define MIN_SHOT_LENGTH 4.0 // minimum time of a cut (seconds) +#define MAX_SHOT_LENGTH 8.0 // maximum time of a cut (seconds) +#define DEF_SHOT_LENGTH 6.0 // average time of a cut (seconds) + +enum SourceTVBroadcastTarget { + // Send message to all spectators including proxies. + BTarget_Everyone = 0, + // Send message only to locally connected spectators. + BTarget_OnlyLocal +}; + +/** + * Get the current amount of running SourceTV instances. + * Can usually only be 1 at max except for CSGO, which can have 2. + * + * @return SourceTV instance number count. + */ +native int SourceTV_GetServerInstanceCount(); + +/** + * Select a SourceTV instance to operate the rest of the natives on. + * The first SourceTV to connect will always be selected by default. + * Most games only have 1 instance, so this might only be useful in CS:GO, + * which can have 2 instances running. + * + * @param instance The SourceTV instance number. + * @error Invalid SourceTV instance number. + */ +native void SourceTV_SelectServerInstance(int instance); + +/** + * Get the index of the currently selected SourceTV server instance. + * + * @return Index of the selected SourceTV instance number or -1 if no SourceTV enabled. + */ +native int SourceTV_GetSelectedServerInstance(); + +/** + * Called when a SourceTV is initialized. + * + * @param instance The SourceTV instance number. + */ +forward void SourceTV_OnServerStart(int instance); + + /** + * Called when a SourceTV server instance is shutdown. + * + * @param instance The SourceTV instance number. + */ +forward void SourceTV_OnServerShutdown(int instance); + +/** + * Returns whether this SourceTV instance is currently broadcasting. + * + * @return True if SourceTV instance is broadcasting, false otherwise. + */ +native bool SourceTV_IsActive(); + +/** + * Returns whether this SourceTV instance is a master proxy or relay. + * + * @return True if SourceTV instance is master proxy, false otherwise. + */ +native bool SourceTV_IsMasterProxy(); + +/** + * Get the local ip of the SourceTV server. + * + * @param ip Buffer to save IP in. + * @param maxlen Maximum length of the buffer. + * @return True if IP written, false otherwise. + */ +native bool SourceTV_GetServerIP(char[] ip, int maxlen); + +/** + * Get the UDP port of the SourceTV server. + * This is the port clients use to connect. + * + * @return SourceTV server UDP port. + */ +native int SourceTV_GetServerPort(); + +/** + * Get the client index of the SourceTV bot. + * + * @return Client index of SourceTV bot. + */ +native int SourceTV_GetBotIndex(); + +/** + * Get stats of the local SourceTV instance. + * Returns only the stats of this server, don't include relays. + * + * You have to subtract the proxy count from the spectator count to + * get the real spectator count, because the proxies take one spectator slot + * on the SourceTV server. + * + * @param proxies Number of SourceTV proxies connected to this server. + * @param slots Number of maximal available SourceTV spectator slots. + * @param specs Number of currently connected SourceTV spectators. + * @return True if stats were retrieved, false otherwise. + */ +native bool SourceTV_GetLocalStats(int &proxies, int &slots, int &specs); + +/** + * Get stats of this SourceTV network. + * Only the current Master Proxy can give accurate numbers. + * Relay proxies only get updates from the master from time to time. + * + * You have to subtract the proxy count from the spectator count to + * get the real spectator count, because the proxies take one spectator slot + * on the SourceTV server. + * + * @param proxies Number of SourceTV proxies connected to all servers. + * @param slots Number of maximal available SourceTV spectator slots on all servers. + * @param specs Number of currently connected SourceTV spectators on all servers. + * @return True if stats were retrieved, false otherwise. + */ +native bool SourceTV_GetGlobalStats(int &proxies, int &slots, int &specs); + +/** + * Current broadcasted tick. Can be lower than the actual server tick, + * due to delay. + * + * @return Current broadcast tick from director. + */ +native int SourceTV_GetBroadcastTick(); + +/** + * Returns current delay in seconds. (tv_delay) + * + * @return Current delay in seconds. + */ +native float SourceTV_GetDelay(); + +/** + * Print a center message to all SourceTV spectators for ~2 seconds. + * Like the tv_msg command. + * + * @param target Send only to directly connected spectators or proxies as well? + * @param format The format string. + * @param ... Variable number of format string arguments. + * @return True if message was sent, false otherwise. + */ +native bool SourceTV_BroadcastScreenMessage(SourceTVBroadcastTarget target, const char[] format, any ...); + +/** + * Prints text to the console of all connected SourceTV spectators. + * + * @param format The format string. + * @param ... Variable number of format string arguments. + * @return True if message was sent, false otherwise. + */ +native bool SourceTV_BroadcastConsoleMessage(const char[] format, any ...); + +/** + * Print a chat message to all SourceTV spectators. + * + * @param target Send only to directly connected spectators or proxies as well? + * @param format The format string. + * @param ... Variable number of format string arguments. + * @return True if message was sent, false otherwise. + */ +native bool SourceTV_BroadcastChatMessage(SourceTVBroadcastTarget target, const char[] format, any ...); + + +/******************************************************************************** + * SourceTV Director control + ********************************************************************************/ + +/** + * Get entity index of current view entity (PVS) of the + * auto director. Check the view origin, if this returns 0. + * @see SourceTV_GetViewOrigin + * + * @return Current view entity index, 0 if coords are used. + */ +native int SourceTV_GetViewEntity(); + +/** + * Get origin of current view point if view entity is 0. + * + * @param view Vector to store view position in. + */ +native void SourceTV_GetViewOrigin(float view[3]); + +/** + * Force the auto director to show a certain camera angle. + * + * @param pos The camera position. + * @param angle The camera angles (roll is unused). + * @param iTarget Target entity to keep the camera pointed towards or 0 to use the angle. + * @param fow Field of view of the camera. + * @param fDuration Length of the shot in seconds. + * @return True if shot was created, false otherwise. + * @error Invalid target entity. + */ +native bool SourceTV_ForceFixedCameraShot(float[] pos, float[] angle, int iTarget, float fov, float fDuration = DEF_SHOT_LENGTH); + +/** + * Force the auto director to show a player. + * + * @param iTarget1 The target player to follow. + * @param iTarget2 The other player to keep the camera centered on or 0 to follow target1's view. + * @param distance Distance of camera behind the player. + * @param phi Up/down offset of view point. + * @param theta Left/right offset of view point. + * @param bInEye Show as in-eye camera of the target. Ignores all the other third-person settings. + * @param fDuration Length of the shot in seconds. + * @return True if shot was created, false otherwise. + * @error Invalid target1 or target2 entity + */ +native bool SourceTV_ForceChaseCameraShot(int iTarget1, int iTarget2, int distance, int phi, int theta, bool bInEye, float fDuration = DEF_SHOT_LENGTH); + + + + +/******************************************************************************** + * SourceTV demo recording + ********************************************************************************/ + +/** + * Starts recording a SourceTV demo into the specified file. + * Only the master proxy can record demos. + * + * @param sFilename Filename of the demo file. + * @return True if recording started, false otherwise. + */ +native bool SourceTV_StartRecording(const char[] sFilename); + +/** + * Stops recording a SourceTV demo. + * + * @return True if recording stopped, false otherwise. + */ +native bool SourceTV_StopRecording(); + +/** + * Returns whether the SourceTV server is currently recording a demo. + * + * @return True if currently recording a SourceTV demo, false otherwise. + */ +native bool SourceTV_IsRecording(); + +/** + * Get the filename of the currently recorded demo. + * + * @param sFilename Buffer to store the filename in. + * @param maxlen Maximal length of the buffer. + * @return True if filename was written, false otherwise. + */ +native bool SourceTV_GetDemoFileName(char[] sFilename, int maxlen); + +/** + * Get current tick in the demofile. + * + * @return Current recording tick in the demofle. + */ +native int SourceTV_GetRecordingTick(); + +/** + * Print text to the demo console. + * This will show up when playing the demo back in the client console later. + * + * @param format The format string. + * @param ... Variable number of format string arguments. + * + * @return True if message was printed, false otherwise. + */ +native bool SourceTV_PrintToDemoConsole(const char[] format, any ...); + +/** + * Called when a SourceTV demo starts being recorded. + * @see SourceTV_SelectServerInstance + * + * @param instance The SourceTV instance of server recording. + * @param filename The filename of the demo. + */ +forward void SourceTV_OnStartRecording(int instance, const char[] filename); + +/** + * Called when a SourceTV demo stops being recorded. + * @see SourceTV_SelectServerInstance + * + * @param instance The SourceTV instance of server recording. + * @param filename The filename of the demo. + * @param recordingtick The tick length of the demo. + */ +forward void SourceTV_OnStopRecording(int instance, const char[] filename, int recordingtick); + + + + +/******************************************************************************** + * SourceTV spectator client handling + ********************************************************************************/ + +/** + * Get currently connected SourcetV spectator count. + * + * @return SourceTV spectator count. + */ +native int SourceTV_GetSpectatorCount(); + +/** + * Get the current client limit. + * + * @return Maximal possible spectator count. + */ +native int SourceTV_GetMaxClients(); + +/** + * Get number of client slots (used & unused) + * Client slots are only allocated when they're needed. + * Use this when iterating spectators. + * + * @return Number of client slots (used & unused) + */ +native int SourceTV_GetClientCount(); + +/** + * Returns if the spectator is connected. + * + * @param client The spectator client index. + * @return True if client is connected, false otherwise. + * @error Invalid client index. + */ +native bool SourceTV_IsClientConnected(int client); + +/** + * Returns if the spectator is a relay proxy. + * + * @param client The spectator client index. + * @return True if client is a proxy, false otherwise. + * @error Invalid client index. + */ +native bool SourceTV_IsClientProxy(int client); + +/** + * Get the name of a SourceTV spectator client. + * + * @param client The spectator client index. + * @param name Buffer for the client name. + * @param maxlen Maximal length of the buffer. + * @error Invalid client index or not connected. + */ +native void SourceTV_GetClientName(int client, char[] name, int maxlen); + +/** + * Get the IP of a SourceTV spectator client. + * + * @param client The spectator client index. + * @param name Buffer for the client ip. + * @param maxlen Maximal length of the buffer. + * @error Invalid client index or not connected. + */ +native void SourceTV_GetClientIP(int client, char[] ip, int maxlen); + +/** + * Get the password of a SourceTV spectator client. + * The password the client tried to connect with. + * Ignores changes from the SourceTV_OnSpectatorPreConnect forward. + * + * @param client The spectator client index. + * @param name Buffer for the client ip. + * @param maxlen Maximal length of the buffer. + * @error Invalid client index or not connected. + */ +native void SourceTV_GetClientPassword(int client, char[] password, int maxlen); + +/** + * Kick a SourceTV spectator client. + * + * @param client The spectator client index. + * @param sReason The kick reason. + * @error Invalid client index or not connected. + */ +native void SourceTV_KickClient(int client, const char[] sReason); + +/** + * Print a message to a single client's chat. + * + * @param client The spectator client index. + * @param format The format string. + * @param ... Variable number of format string arguments. + * @error Invalid client index or not connected. + */ +native void SourceTV_PrintToChat(int client, const char[] format, any ...); + +/** + * Print a message to a single client's console. + * + * @param client The spectator client index. + * @param format The format string. + * @param ... Variable number of format string arguments. + * @error Invalid client index or not connected. + */ +native void SourceTV_PrintToConsole(int client, const char[] format, any ...); + +/** + * Change the stream title only for one spectator. + * This is like tv_title but for a single client. + * Gets overwritten when tv_title gets changed. + * + * @param client The spectator client index. + * @param format The format string. + * @param ... Variable number of format string arguments. + * @error Invalid client index or not connected. + */ +native void SourceTV_SetClientTVTitle(int client, const char[] format, any ...); + +/** + * Called when a spectator wants to connect to the SourceTV server. + * This is called before any other validation has happened. + * Similar to the OnClientPreConnectEx forward in the Connect extension by asherkin. + * + * @param name The player name. + * @param password The password the client used to connect. Can be overwritten. + * @param ip The ip address of the client. + * @param rejectReason Buffer to write the reject reason to, if you want to reject the client from connecting. + * @return True to allow the client to connect, false to reject him with the given reason. + */ +forward bool SourceTV_OnSpectatorPreConnect(const char[] name, char password[255], const char[] ip, char rejectReason[255]); + +/** + * Called when a spectator client connected to the SourceTV server. + * + * @param client The spectator client index. + */ +forward void SourceTV_OnSpectatorConnected(int client); + +/** + * Called when a spectator client is about to disconnect. + * + * @param client The spectator client index. + * @param reason The reason for the disconnect. Can be overwritten. + */ +forward void SourceTV_OnSpectatorDisconnect(int client, char reason[255]); + +/** + * Called after a spectator client disconnected. + * + * @param client The spectator client index. + * @param reason The reason for the disconnect. + */ +forward void SourceTV_OnSpectatorDisconnected(int client, const char reason[255]); + +/** + * Called when a spectator client is entering the game. + * + * @param client The spectator client index. + */ +forward void SourceTV_OnSpectatorPutInServer(int client); + +/** + * Called before a spectator's chat message is sent. + * The message and chat group can be changed. + * Only called for directly connected clients - no proxies. + * + * @param client The spectator client index. + * @param message The message the client typed. + * @param chatgroup The chatgroup this message is sent to (tv_chatgroup). + * @return >= Plugin_Handled to block the message, Plugin_Continue to let it through. + */ +forward Action SourceTV_OnSpectatorChatMessage(int client, char message[255], char chatgroup[255]); + +/** + * Called after a spectator wrote a chat message. + * Only called for directly connected clients - no proxies. + * + * @param client The spectator client index. + * @param message The message the client typed. + * @param chatgroup The chatgroup this message is sent to (tv_chatgroup). + */ +forward void SourceTV_OnSpectatorChatMessage_Post(int client, const char[] message, const char[] chatgroup); + +/** + * Do not edit below this line! + */ +public Extension __ext_stvmngr = +{ + name = "SourceTV Manager", + file = "sourcetvmanager.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public void __ext_stvmngr_SetNTVOptional() +{ + MarkNativeAsOptional("SourceTV_GetServerInstanceCount"); + MarkNativeAsOptional("SourceTV_SelectServerInstance"); + MarkNativeAsOptional("SourceTV_GetSelectedServerInstance"); + MarkNativeAsOptional("SourceTV_IsActive"); + MarkNativeAsOptional("SourceTV_IsMasterProxy"); + MarkNativeAsOptional("SourceTV_GetServerIP"); + MarkNativeAsOptional("SourceTV_GetServerPort"); + MarkNativeAsOptional("SourceTV_GetBotIndex"); + MarkNativeAsOptional("SourceTV_GetLocalStats"); + MarkNativeAsOptional("SourceTV_GetGlobalStats"); + MarkNativeAsOptional("SourceTV_GetBroadcastTick"); + MarkNativeAsOptional("SourceTV_GetDelay"); + MarkNativeAsOptional("SourceTV_BroadcastScreenMessage"); + MarkNativeAsOptional("SourceTV_BroadcastConsoleMessage"); + MarkNativeAsOptional("SourceTV_BroadcastChatMessage"); + MarkNativeAsOptional("SourceTV_GetViewEntity"); + MarkNativeAsOptional("SourceTV_GetViewOrigin"); + MarkNativeAsOptional("SourceTV_ForceFixedCameraShot"); + MarkNativeAsOptional("SourceTV_ForceChaseCameraShot"); + MarkNativeAsOptional("SourceTV_StartRecording"); + MarkNativeAsOptional("SourceTV_StopRecording"); + MarkNativeAsOptional("SourceTV_IsRecording"); + MarkNativeAsOptional("SourceTV_GetDemoFileName"); + MarkNativeAsOptional("SourceTV_GetRecordingTick"); + MarkNativeAsOptional("SourceTV_PrintToDemoConsole"); + MarkNativeAsOptional("SourceTV_GetSpectatorCount"); + MarkNativeAsOptional("SourceTV_GetMaxClients"); + MarkNativeAsOptional("SourceTV_GetClientCount"); + MarkNativeAsOptional("SourceTV_IsClientConnected"); + MarkNativeAsOptional("SourceTV_IsClientProxy"); + MarkNativeAsOptional("SourceTV_GetClientName"); + MarkNativeAsOptional("SourceTV_GetClientIP"); + MarkNativeAsOptional("SourceTV_GetClientPassword"); + MarkNativeAsOptional("SourceTV_KickClient"); + MarkNativeAsOptional("SourceTV_PrintToChat"); + MarkNativeAsOptional("SourceTV_PrintToConsole"); + MarkNativeAsOptional("SourceTV_SetClientTVTitle"); +} +#endif diff --git a/includes/updater.inc b/includes/updater.inc deleted file mode 100644 index f37bdf2..0000000 --- a/includes/updater.inc +++ /dev/null @@ -1,97 +0,0 @@ -#if defined _updater_included - #endinput -#endif -#define _updater_included - -/** - * Adds your plugin to the updater. The URL will be updated if - * your plugin was previously added. - * - * @param url URL to your plugin's update file. - * @noreturn - */ -native Updater_AddPlugin(const String:url[]); - -/** - * Removes your plugin from the updater. This does not need to - * be called during OnPluginEnd. - * - * @noreturn - */ -native Updater_RemovePlugin(); - -/** - * Forces your plugin to be checked for updates. The behaviour - * of the update is dependant on the server's configuration. - * - * @return True if an update was triggered. False otherwise. - * @error Plugin not found in updater. - */ -native bool:Updater_ForceUpdate(); - -/** - * Called when your plugin is about to be checked for updates. - * - * @return Plugin_Handled to prevent checking, Plugin_Continue to allow it. - */ -forward Action:Updater_OnPluginChecking(); - -/** - * Called when your plugin is about to begin downloading an available update. - * - * @return Plugin_Handled to prevent downloading, Plugin_Continue to allow it. - */ -forward Action:Updater_OnPluginDownloading(); - -/** - * Called when your plugin's update files have been fully downloaded - * and are about to write to their proper location. This should be used - * to free read-only resources that require write access for your update. - * - * @note OnPluginUpdated will be called later during the same frame. - * - * @noreturn - */ -forward Updater_OnPluginUpdating(); - -/** - * Called when your plugin's update has been completed. It is safe - * to reload your plugin at this time. - * - * @noreturn - */ -forward Updater_OnPluginUpdated(); - -/** - * @brief Reloads a plugin. - * - * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). - * @noreturn - */ -stock ReloadPlugin(Handle:plugin=INVALID_HANDLE) -{ - decl String:filename[64]; - GetPluginFilename(plugin, filename, sizeof(filename)); - ServerCommand("sm plugins reload %s", filename); -} - - -public SharedPlugin:__pl_updater = -{ - name = "updater", - file = "updater.smx", -#if defined REQUIRE_PLUGIN - required = 1, -#else - required = 0, -#endif -}; - -#if !defined REQUIRE_PLUGIN -public __pl_updater_SetNTVOptional() -{ - MarkNativeAsOptional("Updater_AddPlugin"); - MarkNativeAsOptional("Updater_RemovePlugin"); - MarkNativeAsOptional("Updater_ForceUpdate"); -} -#endif diff --git a/includes/webcon.inc b/includes/webcon.inc new file mode 100644 index 0000000..a89e75c --- /dev/null +++ b/includes/webcon.inc @@ -0,0 +1,315 @@ +#if defined _webcon_included +#endinput +#endif +#define _webcon_included + +#define WEB_CLIENT_ADDRESS_LENGTH 46 + +//const char WebMethod_Connect[] = "CONNECT"; +//const char WebMethod_Delete[] = "DELETE"; +//const char WebMethod_Get[] = "GET"; +//const char WebMethod_Head[] = "HEAD"; +//const char WebMethod_Options[] = "OPTIONS"; +//const char WebMethod_Post[] = "POST"; +//const char WebMethod_Put[] = "PUT"; +//const char WebMethod_Patch[] = "PATCH"; +//const char WebMethod_Trace[] = "TRACE"; + +#define WebMethod_Connect "CONNECT" +#define WebMethod_Delete "DELETE" +#define WebMethod_Get "GET" +#define WebMethod_Head "HEAD" +#define WebMethod_Options "OPTIONS" +#define WebMethod_Post "POST" +#define WebMethod_Put "PUT" +#define WebMethod_Patch "PATCH" +#define WebMethod_Trace "TRACE" + +enum WebStatus +{ + WebStatus_Continue = 100, + WebStatus_SwitchingProtocols = 101, + WebStatus_Processing = 102, + + WebStatus_OK = 200, + WebStatus_Created = 201, + WebStatus_Accepted = 202, + WebStatus_NonAuthoritativeInformation = 203, + WebStatus_NoContent = 204, + WebStatus_ResetContent = 205, + WebStatus_PartialContent = 206, + WebStatus_MultiStatus = 207, + + WebStatus_MultipleChoices = 300, + WebStatus_MovedPermanently = 301, + WebStatus_Found = 302, + WebStatus_SeeOther = 303, + WebStatus_NotModified = 304, + WebStatus_UseProxy = 305, + WebStatus_SwitchProxy = 306, + WebStatus_TemporaryRedirect = 307, + + WebStatus_BadRequest = 400, + WebStatus_Unauthorized = 401, + WebStatus_PaymentRequired = 402, + WebStatus_Forbidden = 403, + WebStatus_NotFound = 404, + WebStatus_MethodNotAllowed = 405, + WebStatus_NotAcceptable = 406, + WebStatus_ProxyAuthenticationRequired = 407, + WebStatus_RequestTimeout = 408, + WebStatus_Conflict = 409, + WebStatus_Gone = 410, + WebStatus_LengthRequired = 411, + WebStatus_PreconditionFailed = 412, + WebStatus_RequestEntityTooLarge = 413, + WebStatus_RequestUriTooLong = 414, + WebStatus_UnsupportedMediaType = 415, + WebStatus_RequestedRangeNotSatisfiable = 416, + WebStatus_ExpectationFailed = 417, + WebStatus_UnprocessableEntity = 422, + WebStatus_Locked = 423, + WebStatus_FailedDependency = 424, + WebStatus_UnorderedCollection = 425, + WebStatus_UpgradeRequired = 426, + WebStatus_NoResponse = 444, + WebStatus_RetryWith = 449, + WebStatus_BlockedByWindowsParentalControls = 450, + WebStatus_UnavailableForLegalReasons = 451, + + WebStatus_InternalServerError = 500, + WebStatus_NotImplemented = 501, + WebStatus_BadGateway = 502, + WebStatus_ServiceUnavailable = 503, + WebStatus_GatewayTimeout = 504, + WebStatus_HttpVersionNotSupported = 505, + WebStatus_VariantAlsoNegotiates = 506, + WebStatus_InsufficientStorage = 507, + WebStatus_BandwidthLimitExceeded = 509, + WebStatus_NotExtended = 510, +} + +#define WebHeader_Accept "Accept" +#define WebHeader_AcceptCharset "Accept-Charset" +#define WebHeader_AcceptEncoding "Accept-Encoding" +#define WebHeader_AcceptLanguage "Accept-Language" +#define WebHeader_AcceptRanges "Accept-Ranges" +#define WebHeader_Age "Age" +#define WebHeader_Allow "Allow" +#define WebHeader_Authorization "Authorization" +#define WebHeader_CacheControl "Cache-Control" +#define WebHeader_Connection "Connection" +#define WebHeader_ContentEncoding "Content-Encoding" +#define WebHeader_ContentLanguage "Content-Language" +#define WebHeader_ContentLength "Content-Length" +#define WebHeader_ContentLocation "Content-Location" +#define WebHeader_ContentMD5 "Content-MD5" +#define WebHeader_ContentRange "Content-Range" +#define WebHeader_ContentType "Content-Type" +#define WebHeader_Cookie "Cookie" +#define WebHeader_Date "Date" +#define WebHeader_ETag "ETag" +#define WebHeader_Expect "Expect" +#define WebHeader_Expires "Expires" +#define WebHeader_From "From" +#define WebHeader_Host "Host" +#define WebHeader_IfMatch "If-Match" +#define WebHeader_IfModifiedSince "If-Modified-Since" +#define WebHeader_IfNoneMatch "If-None-Match" +#define WebHeader_IfRange "If-Range" +#define WebHeader_IfUnmodifiedSince "If-Unmodified-Since" +#define WebHeader_LastModified "Last-Modified" +#define WebHeader_Location "Location" +#define WebHeader_MaxForwards "Max-Forwards" +#define WebHeader_Pragma "Pragma" +#define WebHeader_ProxyAuthenticate "Proxy-Authenticate" +#define WebHeader_ProxyAuthorization "Proxy-Authorization" +#define WebHeader_Range "Range" +#define WebHeader_Referer "Referer" +#define WebHeader_RetryAfter "Retry-After" +#define WebHeader_Server "Server" +#define WebHeader_SetCookie "Set-Cookie" +#define WebHeader_SetCookie2 "Set-Cookie2" +#define WebHeader_TE "TE" +#define WebHeader_Trailer "Trailer" +#define WebHeader_TransferEncoding "Transfer-Encoding" +#define WebHeader_Upgrade "Upgrade" +#define WebHeader_UserAgent "User-Agent" +#define WebHeader_Vary "Vary" +#define WebHeader_Via "Via" +#define WebHeader_Warning "Warning" +#define WebHeader_WWWAuthenticate "WWW-Authenticate" +#define WebHeader_AccessControlAllowOrigin "Access-Control-Allow-Origin" + +enum WebRequestDataType +{ + WebRequestDataType_Get, + WebRequestDataType_Post, + WebRequestDataType_Cookie, + WebRequestDataType_Header, +} + +methodmap WebResponse < Handle +{ + /// Add a HTTP header to a response. + /// + /// Multiple instances of the same header can be added to a response with different values. + /// This is only valid if the header is specified as a list, but the restriction is not enforced. + /// + /// @param header Name of HTTP header to add. `WebHeader_*` constants exist for standard headers. + /// @param content Value to send in response for this header. + /// @return `true` if the header was sucessfully added, `false` otherwise. + public native bool AddHeader(const char[] header, const char[] content); + + /// Remove an added HTTP header from a response. + /// + /// @param header Name of HTTP header to remove. `WebHeader_*` constants exist for standard headers. + /// @param content If specified, only remove a header matching this value. + /// @return `true` if any headers were removed, `false` otherwise. + public native bool RemoveHeader(const char[] header, const char[] content = NULL_STRING); +}; + +methodmap WebStringResponse < WebResponse +{ + /// Create a WebResponse from a character string. + /// + /// The response length is determined automatically and thus is not binary-safe. + /// Use `WebBinaryResponse` for binary data. + /// + /// @param content Content to use for response. + /// @return A new WebResponse instance with the specified content as the body. + public native WebStringResponse(const char[] content); +}; + +methodmap WebBinaryResponse < WebResponse +{ + /// Create a WebResponse from binary data. + /// + /// @param content Content to use for response. + /// @param length Length of content. + /// @return A new WebResponse instance with the specified content as the body. + public native WebBinaryResponse(const char[] content, int length); +}; + +methodmap WebFileResponse < WebResponse +{ + /// Create a WebResponse from a file path. + /// + /// This uses efficient kernel data transfer mechanisms where available, and avoids + /// reading the entire file into memory at once (or when not being sent to a client). + /// + /// @param path Path to response file. Should be constructed using `BuildPath`. + /// @return A new WebResponse instance with the specified file content as the body. + /// @error Unable to open file path for reading. + public native WebFileResponse(const char[] path); +}; + +typeset WebBodyDataReceived +{ + /// Callback for request body. + /// + /// @param connection WebConnection handle for the request. Must not be deleted. + /// @param data Raw request body data OR "" if `data_in_cb` = false. + /// @param length Size of `data`. + /// @param data1 Optional user data 1. + /// @param data2 Optional user data 2. + /// @return `true` if the request was handled, `false` will terminate the connection. + function bool(WebConnection connection, char[] data, int length); + function bool(WebConnection connection, char[] data, int length, any data1); + function bool(WebConnection connection, char[] data, int length, any data1, any data2); +}; + +methodmap WebConnection < Handle +{ + /// Get the remote client IP address. + /// + /// @param buffer Buffer to store the address in. Should be `WEB_CLIENT_ADDRESS_LENGTH` bytes in size. + /// @param length Size of `buffer`. + /// @return `true` if the client address was stored in `buffer`, `false` otherwise. + public native bool GetClientAddress(char[] buffer, int length); + + /// Get the length of the string that would be returned by GetRequestData(). + /// + /// @param key Paramater (GET or POST), Cookie, or Header to get data from. + /// @return int the size in bytes. + /// @error ParseRequestBody was not called for POST data. + public native int GetRequestDataLength(WebRequestDataType type, const char[] key); + + /// Get data sent by the client in the request. + /// Retrieving data from the body (aka. POST) will only work after ParseRequestBody() has been run. + /// + /// @param type Source of data. See `WebRequestDataType` for details. + /// @param key Paramater (GET or POST), Cookie, or Header to get data from. + /// @param buffer Buffer to store the data value in. + /// @param length Size of `buffer`. + /// @return `true` if the data exists in the request and was stored in `buffer`, `false` otherwise. + /// @error ParseRequestBody was not called for POST data. + public native bool GetRequestData(WebRequestDataType type, const char[] key, char[] buffer, int length); + + /// Load full request body into memory and call `callback` when done. + /// + /// @param callback WebBodyDataReceived callback that will be called when request body has been loaded. + /// @param data1 Optional user data 1. + /// @param data2 Optional user data 2. + /// @param data_in_cb Pass body through callback if true. + /// @return `true` on success + /// @error Function called more than once. + public native bool ReadRequestBody(WebBodyDataReceived callback, any data1 = 0, any data2 = 0, bool data_in_cb = true); + + /// Get request body, or part of, into buffer. + /// + /// @param start Start index in request body. + /// @param buffer Target buffer. + /// @param length Target buffer size. + /// @return `true` on success + /// @error Start exceeds data size. + public native bool GetRequestBody(int start, char[] buffer, int length); + + /// Detect endcoding of request body and parse into hashtable for use with GetRequestData. + /// Supports: "application/x-www-form-urlencoded", "multipart/form-data" + /// + /// @return `true` on success + /// @error ReadRequestBody() not called first. Function called twice. + public native bool ParseRequestBody(); + + /// Queue a response to send to the client. + /// + /// @param status HTTP status code to use for response. See `WebStatus`. + /// @param response WebResonse to queue. You are responsible for deleting the response. + /// @return `true` if the response was successfully queued, `false` otherwise. + /// @error Invalid response handle. + public native bool QueueResponse(WebStatus status, WebResponse response); +}; + +/// Callback for incoming requests. +/// +/// @param connection WebConnection handle for the request. Must not be deleted. +/// @param method HTTP method used for request. `WebMethod_*` constants exist for standard methods. +/// @param url URL requested by client. +/// @return `true` if the request was handled, `false` will terminate the connection. +typedef WebRequestHandler = function bool (WebConnection connection, const char[] method, const char[] url); + +/// Register a request handler. +/// +/// @param id Unique identifier for request handler. Used for virtual hosting. +/// @param handler WebRequestHandler callback for incoming requests. +/// @param name Optional name for handler on index page. +/// @param description Optional description for handler on index page. +/// @return `true` if the handler was sucessfully registered, `false` otherwise. +native bool Web_RegisterRequestHandler(const char[] id, WebRequestHandler handler, const char[] name = "", const char[] description = ""); + +public Extension __ext_Webcon = +{ + name = "Webcon", + file = "webcon.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +} \ No newline at end of file diff --git a/includes/zombiereloaded.inc b/includes/zombiereloaded.inc index dee73e4..c6bfef4 100644 --- a/includes/zombiereloaded.inc +++ b/includes/zombiereloaded.inc @@ -35,7 +35,7 @@ #include #include -public SharedPlugin:__pl_zombiereloaded = +public SharedPlugin __pl_zombiereloaded = { name = "zombiereloaded", file = "zombiereloaded.smx", @@ -47,7 +47,7 @@ public SharedPlugin:__pl_zombiereloaded = }; #if !defined REQUIRE_PLUGIN -public __pl_zombiereloaded_SetNTVOptional() +public void __pl_zombiereloaded_SetNTVOptional() { MarkNativeAsOptional("ZR_IsValidClassIndex"); MarkNativeAsOptional("ZR_GetActiveClass"); diff --git a/includes/zr/class.zr.inc b/includes/zr/class.zr.inc index ad6edcf..b77089d 100644 --- a/includes/zr/class.zr.inc +++ b/includes/zr/class.zr.inc @@ -52,7 +52,7 @@ enum ClassSelectResult * * @return True if valid, false otherwise. */ -native bool:ZR_IsValidClassIndex(classIndex); +native bool ZR_IsValidClassIndex(int classIndex); /** * Gets the currently active class index that the player is using. @@ -61,7 +61,7 @@ native bool:ZR_IsValidClassIndex(classIndex); * * @return The active class index. */ -native bool:ZR_GetActiveClass(client); +native bool ZR_GetActiveClass(int client); /** * Gets the current human class index that the player is using. @@ -70,7 +70,7 @@ native bool:ZR_GetActiveClass(client); * * @return The human class index. */ -native bool:ZR_GetHumanClass(client); +native bool ZR_GetHumanClass(int client); /** * Gets the current zombie class index that the player is using. @@ -79,7 +79,7 @@ native bool:ZR_GetHumanClass(client); * * @return The zombie class index. */ -native bool:ZR_GetZombieClass(client); +native bool ZR_GetZombieClass(int client); /** * Selects a class for a player. @@ -99,7 +99,7 @@ native bool:ZR_GetZombieClass(client); * * @return Class selection result. See enum ClassSelectResult. */ -native ClassSelectResult:ZR_SelectClientClass(client, classIndex, bool:applyIfPossible = true, bool:saveIfEnabled = true); +native ClassSelectResult ZR_SelectClientClass(int client, int classIndex, bool applyIfPossible = true, bool saveIfEnabled = true); /** * Gets the class index of the class with the specified name. @@ -112,7 +112,7 @@ native ClassSelectResult:ZR_SelectClientClass(client, classIndex, bool:applyIfPo * * @return Class index, or -1 if none found. */ -native ZR_GetClassByName(const String:className[], cacheType = ZR_CLASS_CACHE_MODIFIED); +native int ZR_GetClassByName(const char[] className, int cacheType = ZR_CLASS_CACHE_MODIFIED); /** * Gets the class name displayed in the class menu. @@ -124,4 +124,4 @@ native ZR_GetClassByName(const String:className[], cacheType = ZR_CLASS_CACHE_MO * @param cacheType Optional. Specifies which class cache to read from. * @return Number of cells written. -1 on error. */ -native ZR_GetClassDisplayName(index, String:buffer[], maxlen, cacheType = ZR_CLASS_CACHE_MODIFIED); +native int ZR_GetClassDisplayName(int index, char[] buffer, int maxlen, int cacheType = ZR_CLASS_CACHE_MODIFIED); diff --git a/includes/zr/infect.zr.inc b/includes/zr/infect.zr.inc index 9d45518..fd32ddf 100644 --- a/includes/zr/infect.zr.inc +++ b/includes/zr/infect.zr.inc @@ -33,7 +33,7 @@ * @return True if zombie, false if not. * @error Invalid client index, not connected or not alive. */ -native bool:ZR_IsClientZombie(client); +native bool ZR_IsClientZombie(int client); /** * Returns true if the player is a human, false if not. @@ -43,7 +43,7 @@ native bool:ZR_IsClientZombie(client); * @return True if human, false if not. * @error Invalid client index, not connected or not alive. */ -native bool:ZR_IsClientHuman(client); +native bool ZR_IsClientHuman(int client); /** * Infects a player. @@ -58,7 +58,7 @@ native bool:ZR_IsClientHuman(client); * * @error Invalid client index, not connected or not alive. */ -native ZR_InfectClient(client, attacker = -1, bool:motherInfect = false, bool:respawnOverride = false, bool:respawn = false); +native int ZR_InfectClient(int client, int attacker = -1, bool motherInfect = false, bool respawnOverride = false, bool respawn = false); /** * Turns a zombie back into a human. @@ -72,7 +72,7 @@ native ZR_InfectClient(client, attacker = -1, bool:motherInfect = false, bool:re * * @error Invalid client index, not connected or not alive. */ -native ZR_HumanClient(client, bool:respawn = false, bool:protect = false); +native int ZR_HumanClient(int client, bool respawn = false, bool protect = false); /** * Called when a player is about to become a zombie. @@ -87,7 +87,7 @@ native ZR_HumanClient(client, bool:respawn = false, bool:protect = false); * @return Plugin_Handled to block infection. Anything else * (like Plugin_Continue) to allow infection. */ -forward Action:ZR_OnClientInfect(&client, &attacker, &bool:motherInfect, &bool:respawnOverride, &bool:respawn); +forward Action ZR_OnClientInfect(int &client, int &attacker, bool &motherInfect, bool &respawnOverride, bool &respawn); /** * Called after a player has become a zombie. @@ -98,7 +98,7 @@ forward Action:ZR_OnClientInfect(&client, &attacker, &bool:motherInfect, &bool:r * @param respawnOverride True if the respawn cvar was overridden. * @param respawn The value that respawn was overridden with. */ -forward ZR_OnClientInfected(client, attacker, bool:motherInfect, bool:respawnOverride, bool:respawn); +forward void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn); /** * Called when a player is about to become a human. (Through an admin command). @@ -111,7 +111,7 @@ forward ZR_OnClientInfected(client, attacker, bool:motherInfect, bool:respawnOve * @return Plugin_Handled to block infection. Anything else * (like Plugin_Continue) to allow acion. */ -forward Action:ZR_OnClientHuman(&client, &bool:respawn, &bool:protect); +forward Action ZR_OnClientHuman(int &client, bool &respawn, bool &protect); /** * Called after a player has become a human. (Through an admin command.) @@ -120,4 +120,4 @@ forward Action:ZR_OnClientHuman(&client, &bool:respawn, &bool:protect); * @param respawn Whether the client was respawned. * @param protect Whether the client has spawn protection. */ -forward ZR_OnClientHumanPost(client, bool:respawn, bool:protect); +forward void ZR_OnClientHumanPost(int client, bool respawn, bool protect); diff --git a/includes/zr/respawn.zr.inc b/includes/zr/respawn.zr.inc index e6e8728..3cc2d55 100644 --- a/includes/zr/respawn.zr.inc +++ b/includes/zr/respawn.zr.inc @@ -44,7 +44,7 @@ enum ZR_RespawnCondition * ZR settings. See ZR_RespawnCondition for details. * @error Invalid client index, not connected or already alive. */ -native ZR_RespawnClient(client, ZR_RespawnCondition:condition = ZR_Repsawn_Default); +native void ZR_RespawnClient(int client, ZR_RespawnCondition condition = ZR_Repsawn_Default); /** * Called right before ZR is about to respawn a player. @@ -56,7 +56,7 @@ native ZR_RespawnClient(client, ZR_RespawnCondition:condition = ZR_Repsawn_Defau * * @return Plugin_Handled to block respawn. */ -forward Action:ZR_OnClientRespawn(&client, &ZR_RespawnCondition:condition); +forward Action ZR_OnClientRespawn(int &client, ZR_RespawnCondition &condition); /** * Called after ZR respawned a player. @@ -65,7 +65,7 @@ forward Action:ZR_OnClientRespawn(&client, &ZR_RespawnCondition:condition); * @param condition Current condition of the respawned player. See * ZR_RespawnCondition for details. */ -forward ZR_OnClientRespawned(client, ZR_RespawnCondition:condition); +forward void ZR_OnClientRespawned(int client, ZR_RespawnCondition condition); /** * Set if a player died by a suicide or world damage. @@ -79,7 +79,7 @@ forward ZR_OnClientRespawned(client, ZR_RespawnCondition:condition); * * @error Invalid client index or not connected. */ -native ZR_SetKilledByWorld(client, bool:suicide); +native void ZR_SetKilledByWorld(int client, bool suicide); /** * Get whether the player died by a suicide or world damage. @@ -92,4 +92,4 @@ native ZR_SetKilledByWorld(client, bool:suicide); * another player. * @error Invalid client index or not connected. */ -native bool:ZR_GetKilledByWorld(client); +native bool ZR_GetKilledByWorld(int client); diff --git a/mapchooser_extended/scripting/include/colors.inc b/mapchooser_extended/scripting/include/colors.inc deleted file mode 120000 index 27c6be6..0000000 --- a/mapchooser_extended/scripting/include/colors.inc +++ /dev/null @@ -1 +0,0 @@ -../../../includes/colors.inc \ No newline at end of file diff --git a/mapchooser_extended/scripting/include/mapchooser_extended.inc b/mapchooser_extended/scripting/include/mapchooser_extended.inc index 65c8773..b5bbc41 100644 --- a/mapchooser_extended/scripting/include/mapchooser_extended.inc +++ b/mapchooser_extended/scripting/include/mapchooser_extended.inc @@ -54,29 +54,29 @@ enum CanNominateResult * Called whenever warning timer starts * */ -forward OnMapVoteWarningStart(); +forward void OnMapVoteWarningStart(); /** * Called whenever runoff warning timer starts */ -forward OnMapVoteRunnoffWarningStart(); +forward void OnMapVoteRunnoffWarningStart(); /** * Called whenever the timer ticks */ -forward OnMapVoteWarningTick(time); +forward void OnMapVoteWarningTick(int time); /** * Called whenever vote starts * * @deprecated Will be removed in MapChooser 1.8. Use OnMapVoteStarted instead. */ -forward OnMapVoteStart(); +forward void OnMapVoteStart(); /** * Called whenever vote ends */ -forward OnMapVoteEnd(const char[] map); +forward void OnMapVoteEnd(const char[] map); /** * Is a map on the current game's official list? diff --git a/mapchooser_extended/scripting/include/nativevotes.inc b/mapchooser_extended/scripting/include/nativevotes.inc deleted file mode 120000 index 78253b7..0000000 --- a/mapchooser_extended/scripting/include/nativevotes.inc +++ /dev/null @@ -1 +0,0 @@ -../../../includes/nativevotes.inc \ No newline at end of file diff --git a/mapchooser_extended/scripting/include/nativevotes.inc b/mapchooser_extended/scripting/include/nativevotes.inc new file mode 100644 index 0000000..c02c5bd --- /dev/null +++ b/mapchooser_extended/scripting/include/nativevotes.inc @@ -0,0 +1,915 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * NativeVotes + * Copyright (C) 2011-2013 Ross Bemrose (Powerlord). All rights reserved. + * ============================================================================= + * + * 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 . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include + +// NativeVotes 0.8 series + +#if defined _nativevotes_included + #endinput +#endif +#define _nativevotes_included + +#define CLIENT_DISCONNECTED -1 + +#define NATIVEVOTES_EXTEND "Extend current Map" /** Defined in TF2, but doesn't appear to be localized */ + +#define NATIVEVOTES_ALL_TEAMS -1 // Defined by TF2, may be the same in L4D/L4D2 +#define NATIVEVOTES_TF2_ALL_TEAMS 0 // Defined by TF2, may be the same in L4D/L4D2 +#define NATIVEVOTES_TEAM_UNASSIGNED 0 // For completeness, do not otherwise use +#define NATIVEVOTES_TEAM_SPECTATOR 1 // Spectators +#define NATIVEVOTES_TEAM_1 2 // RED/Survivors/Terrorists +#define NATIVEVOTES_TEAM_2 3 // BLU/Infected/Counter-Terrorists + +#define NATIVEVOTES_SERVER_INDEX 99 // Defined by TF2, may be the same in L4D/L4D2 + +// These may seem backwards, but this is the order that the votes appear in the vote screen +#define NATIVEVOTES_VOTE_INVALID -1 /**< Vote was invalid, currently only valid internally */ +#define NATIVEVOTES_VOTE_YES 0 /**< Vote was yes */ +#define NATIVEVOTES_VOTE_NO 1 /**< Vote was no */ + +/* +The following MenuActions are supported. Arguments are also listed, as they differ slightly from the default +MenuAction_Start A menu has been started (nothing passed). Only exists for compat reasons. +MenuAction_Display A menu is about to be displayed (param1=client). If you choose to change the vote text, + To change the text, use RedrawVoteTitle() + If you do so, return 1 or _:Plugin_Changed Otherwise, return _:Plugin_Continue or 0. +MenuAction_Select An item was selected (param1=client, param2=item). For subplugin support. +MenuAction_End A vote has fully ended and the vote object is ready to be cleaned up + param1 is MenuEnd reason, either MenuEnd_VotingCancelled or MenuEnd_VotingDone +MenuAction_VoteEnd A vote sequence has succeeded (param1=chosen item) + This is not called if NativeVotes_SetResultCallback has been used on the vote. + You should call NativeVotes_DisplayPass or NativeVotes_DisplayPassEx after this +MenuAction_VoteStart A vote sequence has started (nothing passed). Use this instead of MenuAction_Start +MenuAction_VoteCancel A vote sequence has been cancelled (param1=reason) +MenuAction_DisplayItem Item text is being drawn to the display (param1=client, param2=item) + To change the text, use RedrawVoteItem(). + If you do so, return 1 or _:Plugin_Changed. Otherwise, return _:Plugin_Continue or 0. +*/ + +#define NATIVEVOTES_ACTIONS_DEFAULT MenuAction_VoteStart|MenuAction_VoteCancel|MenuAction_VoteEnd|MenuAction_End + +/** + * Vote types. These are mapped to translation strings and pass strings by VoteStart and VotePass handlers + */ +enum NativeVotesType +{ + NativeVotesType_None = 0, /** Special placeholder for callvote with no arguments for NativeVotes_OnCallVote */ + NativeVotesType_Custom_YesNo, /**< Yes/No, details are vote text. */ + NativeVotesType_Custom_Mult, /**< TF2/CS:GO: Multiple-choice, details are vote text. */ + NativeVotesType_ChgCampaign, /**< L4D/L4D2: Yes/No, details are campaign name */ + NativeVotesType_ChgDifficulty, /**< L4D/L4D2: Yes/No, details are difficulty number in L4D/L4D2 */ + NativeVotesType_ReturnToLobby, /**< L4D/L4D2: Yes/No, details are ignored */ + NativeVotesType_AlltalkOn, /**< L4D2: Yes/No, details are ignored (handled internally by extension) */ + NativeVotesType_AlltalkOff, /**< L4D2: Yes/No, details are ignored (handled internally by extension) */ + NativeVotesType_Restart, /**< Yes/No, details are ignored */ + NativeVotesType_Kick, /**< Yes/No, target is player userid, details are auto-set by target */ + NativeVotesType_KickIdle, /**< TF2/CS:GO: Yes/No, target is player userid, details are auto-set by target */ + NativeVotesType_KickScamming, /**< TF2/CS:GO: Yes/No, target is player userid, details are auto-set by target */ + NativeVotesType_KickCheating, /**< TF2/CS:GO: Yes/No, target is player userid, details are auto-set by target */ + NativeVotesType_ChgLevel, /**< Yes/No, details are level number in L4D/L4D2 or map name in TF2 */ + NativeVotesType_NextLevel, /**< TF2/CS:GO: Yes/No, details are map name */ + NativeVotesType_NextLevelMult, /**< TF2/CS:GO: Multiple-choice, details are ignored */ + NativeVotesType_ScrambleNow, /**< TF2/CS:GO: Yes/No, details are ignored */ + NativeVotesType_ScrambleEnd, /**< TF2: Yes/No, details are ignored */ + NativeVotesType_ChgMission, /**< TF2: Yes/No, details are popfile */ + NativeVotesType_SwapTeams, /**< CS:GO: Yes/No, details are ignored */ + NativeVotesType_Surrender, /**< CS:GO: Yes/No, details are ignored */ + NativeVotesType_Rematch, /**< CS:GO: Yes/No, details are ignored */ + NativeVotesType_Continue, /**< CS:GO: Yes/No, details are ignored */ + NativeVotesType_StartRound, /**< TF2: Yes/No, details are ignored */ + NativeVotesType_Eternaween, /**< TF2: Yes/No, details are ignored */ + NativeVotesType_AutoBalanceOn, /**< TF2: Yes/No, details are ignored */ + NativeVotesType_AutoBalanceOff, /**< TF2: Yes/No, details are ignored */ + NativeVotesType_ClassLimitsOn, /**< TF2: Yes/No, details are ignored */ + NativeVotesType_ClassLimitsOff, /**< TF2: Yes/No, details are ignored */ +}; + +enum NativeVotesPassType +{ + NativeVotesPass_None = 0, /**< Special placeholder for error value */ + NativeVotesPass_Custom, /**< Details are custom pass message */ + NativeVotesPass_ChgCampaign, /**< L4D/L4D2: Details are campaign name */ + NativeVotesPass_ChgDifficulty, /**< L4D/L4D2/TF2: Details are difficulty number in L4D/L4D2 and mission name in TF2 */ + NativeVotesPass_ReturnToLobby, /**< L4D/L4D2: Details are ignored */ + NativeVotesPass_AlltalkOn, /**< L4D2: Details are ignored */ + NativeVotesPass_AlltalkOff, /**< L4D2: Details are ignored */ + NativeVotesPass_Restart, /**< Details are ignored */ + NativeVotesPass_Kick, /**< Details are player name */ + NativeVotesPass_ChgLevel, /**< Details are level number in L4D/L4D2 or map name in TF2/CS:GO */ + NativeVotesPass_NextLevel, /**< TF2/CS:GO: Details are map name */ + NativeVotesPass_Extend, /**< TF2/CS:GO: Details are ignored */ + NativeVotesPass_Scramble, /**< TF2/CS:GO: Details are ignored */ + NativeVotesPass_ChgMission, /**< TF2: Details are popfile */ + NativeVotesPass_SwapTeams, /**< CS:GO: Details are ignored */ + NativeVotesPass_Surrender, /**< CS:GO: Details are ignored */ + NativeVotesPass_Rematch, /**< CS:GO: Details are ignored */ + NativeVotesPass_Continue, /**< CS:GO: Details are ignored */ + NativeVotesPass_StartRound, /**< TF2: Details are ignored */ + NativeVotesPass_Eternaween, /**< TF2: Details are ignored */ + NativeVotesPass_AutoBalanceOn, /**< TF2: Yes/No, details are ignored */ + NativeVotesPass_AutoBalanceOff, /**< TF2: Yes/No, details are ignored */ + NativeVotesPass_ClassLimitsOn, /**< TF2: Yes/No, details are ignored */ + NativeVotesPass_ClassLimitsOff, /**< TF2: Yes/No, details are ignored */ +}; + +/** + * Reasons a vote was canceled. Not used for L4D/L4D2, as they don't care + */ +enum NativeVotesFailType +{ + NativeVotesFail_Generic = 0, /**< Vote was generically cancelled. */ + NativeVotesFail_Loses = 3, /**< No votes outnumbered Yes votes */ + NativeVotesFail_NotEnoughVotes = 4, /**< Vote did not receive enough votes. */ +}; + +/** + * Reasons a callvote command failed. + * This is provided as a convenience to plugin authors as it's not strictly part of the vote system + */ +enum NativeVotesCallFailType +{ + NativeVotesCallFail_Generic = 0, /**< Generic fail. */ + NativeVotesCallFail_Loading = 1, /**< L4D/L4D2: Players are still loading. */ + NativeVotesCallFail_Recent = 2, /**< TF2/CS:GO: You can't call another vote yet: Argument is seconds until you can call another vote. */ + NativeVotesCallFail_Disabled = 5, /**< TF2/CS:GO: Server has disabled that issue. */ + NativeVotesCallFail_MapNotFound = 6, /**< TF2/CS:GO: Server does not have that map. */ + NativeVotesCallFail_SpecifyMap = 7, /**< TF2/CS:GO: You must specify a map. */ + NativeVotesCallFail_Failed = 8, /**< TF2/CS:GO: This vote failed recently. */ + NativeVotesCallFail_WrongTeam = 9, /**< TF2/CS:GO: Team can't call this vote. */ + NativeVotesCallFail_Waiting = 10, /**< TF2/CS:GO: Vote can't be called during Waiting For Players. */ + NativeVotesCallFail_PlayerNotFound = 11, /**< TF2/CS:GO: Player to kick can't be found. Buggy in TF2. */ + NativeVotesCallFail_Unknown = 11, + NativeVotesCallFail_CantKickAdmin = 12, /**< TF2/CS:GO: Can't kick server admin. */ + NativeVotesCallFail_ScramblePending = 13, /**< TF2/CS:GO: Team Scramble is pending.. */ + NativeVotesCallFail_Spectators = 14, /**< TF2/CS:GO: Spectators aren't allowed to call votes. */ + NativeVotesCallFail_LevelSet = 15, /**< TF2/CS:GO: Next level already set. */ + NativeVotesCallFail_MapNotValid = 16, /**< ???: Map is invalid. */ + NativeVotesCallFail_KickTime = 17, /**< ???: Cannot kick for time. */ + NativeVotesCallFail_KickDuringRound = 18, /**< ???: Cannot kick during a round. */ + NativeVotesCallFail_AlreadyActive = 19 /**< TF2: Cannot call vote because modification (Eternaween) is already active (may not work) */ +}; + +/* + * Is a specific vote type supported by this game? + * + * @param voteType Vote type + */ +native bool:NativeVotes_IsVoteTypeSupported(NativeVotesType:voteType); + +/** + * Creates a new, empty vote. + * + * @param handler Function which will receive vote actions. + * @param voteType Vote type, cannot be changed after set + * @param actions Optionally set which actions to receive. Start, + * Cancel, and End will always be received regardless + * of whether they are set or not. They are also + * the only default actions. + * @return A new vote Handle on INVALID_HANDLE if a vote type is unsupported by this game. + */ +native Handle:NativeVotes_Create(MenuHandler:handler, NativeVotesType:voteType, + MenuAction:actions=NATIVEVOTES_ACTIONS_DEFAULT); + +/** + * Frees all handles related to a vote. + * + * THIS MUST BE CALLED TO AVOID HANDLE LEAKS + * + * @param vote Vote handle + * @noreturn + */ +native Handle:NativeVotes_Close(Handle:vote); + +/** + * Appends a new item to the end of a vote. Only valid for Multiple Choice votes + * + * @param vote NativeVotes Handle. + * @param info Item information string. + * @return True on success, false on failure. + * @error Invalid Handle, item limit reached, or if the vote is not multiple choice. + */ +native bool:NativeVotes_AddItem(Handle:vote, const String:info[], const String:display[]); + +/** + * Inserts an item into the menu before a certain position; the new item will + * be at the given position and all next items pushed forward. + * + * @param vote Vote Handle. + * @param position Position, starting from 0. + * @param info Item information string. + * @return True on success, false on failure. + * @error Invalid Handle or vote position, or if the vote is not multiple choice. + */ +native bool:NativeVotes_InsertItem(Handle:vote, position, const String:info[], const String:display[]); + +/** + * Removes an item from the menu. + * + * @param vote Vote Handle. + * @param position Position, starting from 0. + * @return True on success, false on failure. + * @error Invalid Handle or vote position, or if the vote is not multiple choice. + */ +native bool:NativeVotes_RemoveItem(Handle:vote, position); + +/** + * Removes all items from a vote. + * + * @param vote Vote Handle. + * @noreturn + * @error Invalid Handle or vote position, or if the vote is not multiple choice. + */ +native NativeVotes_RemoveAllItems(Handle:vote); + +/** + * Retrieves information about a vote item. + * + * @param vote Vote Handle. + * @param position Position, starting from 0. + * @param infoBuf Info buffer. + * @param infoBufLen Maximum length of the info buffer. + * @return True on success, false if position is invalid. + * @error Invalid Handlem + */ +native bool:NativeVotes_GetItem(Handle:vote, + position, + String:infoBuf[], + infoBufLen, + String:dispBuf[]="", + dispBufLen=0); + +/** + * Returns the number of items in a vote. + * + * @param vote Vote Handle. + * @return Number of items in the vote. + * @error Invalid Handle. + */ +native NativeVotes_GetItemCount(Handle:vote); + +/** + * Sets the vote's details for votes that support details + * If this is a custom vote, use NativeVotes_SetTitle to set the vote's title. + * + * @param vote Vote Handle. + * @param argument Details string. See vote types for what details stands for. + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_SetDetails(Handle:vote, const String:argument[]); + +/** + * Returns the text of a vote's details if set. + * + * @param vote Vote Handle. + * @param buffer Buffer to store details. + * @param maxlength Maximum length of the buffer. + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_GetDetails(Handle:vote, String:buffer[], maxlength); + +/** + * Sets a custom vote's title + * + * @param vote Vote Handle. + * @param title Vote title string. + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_SetTitle(Handle:vote, const String:argument[]); + +/** + * Return the vote's Title. + * If not set, returns Details instead. + * This behavior is for compatibility with NativeVotes 0.8.0 and below. + * + * @param vote Vote Handle. + * @param buffer Buffer to store title. + * @param maxlength Maximum length of the buffer. + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_GetTitle(Handle:vote, String:buffer[], maxlength); + +/** + * Sets the target userid for vote + * This should be used instead of SetArgument for votes that target players + * + * Also sets target SteamID + * + * @param vote Vote Handle. + * @param userid Client index of target player + * @param setDetails If true, also sets vote details to client's name + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_SetTarget(Handle:vote, client, bool:setDetails=true); + +/** + * Returns the userid of a vote's target + * + * @param vote Vote Handle. + * @return Client index of target player or 0 for no target or target disconnected since vote started + * @error Invalid Handle. + */ +native NativeVotes_GetTarget(Handle:vote); + +/** + * Get the Steam ID of a vote's target + * Useful if the target has disconnect from the server during a vote. + * This was added in specifically for Kick/Ban votes + * + * @param vote Vote Handle. + * @param buffer Buffer to store steamId. Should be 19 characters or more.. + * @param maxlength Maximum length of the buffer. + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_GetTargetSteam(Handle:vote, String:buffer[], maxlength); + +/** + * Returns whether a vote is in progress. + * + * @return True if a NativeVotes vote is in progress, false otherwise. + */ +native bool:NativeVotes_IsVoteInProgress(); + +/** + * Returns a style's maximum items + * + * @return Maximum items + */ +native NativeVotes_GetMaxItems(); + +/** + * Sets a vote's option flags. + * + * If a certain bit is not supported, it will be stripped before being set. + * + * NOTE: This is currently unused, but reserved for future use. + * + * @param menu Builtin Vote Handle. + * @param flags A new bitstring of VOTEFLAG bits. + * @noreturn + * @error Invalid Handle. + */ +native NativeVotes_SetOptionFlags(Handle:vote, flags); + +/** + * Retrieves a menu's option flags. + * + * NOTE: This is currently unused, but reserved for future use. + * + * @param vote Builtin Vote Handle. + * @return A bitstring of VOTEFLAG bits. + * @error Invalid Handle. + */ +native NativeVotes_GetOptionFlags(Handle:vote); + +/** + * Cancels the vote in progress. + * + * @noreturn + * @error If no vote is in progress. + */ +native NativeVotes_Cancel(); + +/** + * Callback for when a vote has ended and results are available. + * + * Due to SourceMod Forward limitations in plugins, multi-dimension arrays can't be passed + * to forwards. This means we have to split the client_info and item_info arrays into + * their components. + * + * @param vote The vote being voted on. + * @param num_votes Number of votes tallied in total. + * @param num_clients Number of clients who could vote. + * @param client_indexes Array of client indexes. Parallel with client_votes. + * @param client_votes Array of client votes. Parallel with client_indexes. + * @param num_items Number of unique items that were selected. + * @param item_indexes Array of vote item indexes. Parallel with item_votes.. + * @param item_votes Array of vote vote counts. Parallel with item_indexes. + * @noreturn + */ +functag public NativeVotes_VoteHandler(Handle:vote, + num_votes, + num_clients, + const client_indexes[], + const client_votes[], + num_items, + const item_indexes[], + const item_votes[]); +/** + * Function to convert client/vote arrays into their two-dimensional versions, + * which can then be passed to a standard vote handler. + * + * client_info and item_info are the resulting arrays. + * + * Note: When declaring client_info and item_info, you'll probably want to declare them like this: + * new client_info[num_clients][2]; + * new item_info[num_items][2]; + * + * @param num_clients Number of clients who could vote. + * @param client_indexes Array of client indexes. Parallel with client_votes. + * @param client_votes Array of client votes. Parallel with client_indexes. + * @param num_items Number of unique items that were selected. + * @param item_indexes Array of vote item indexes. Parallel with item_votes.. + * @param item_votes Array of vote vote counts. Parallel with item_indexes. + * @param client_info Array of clients. Use VOTEINFO_CLIENT_ defines. + * @param item_info Array of items, sorted by count. Use VOTEINFO_ITEM + * defines. + * @noreturn + */ +stock NativeVotes_FixResults(num_clients, + const client_indexes[], + const client_votes[], + num_items, + const item_indexes[], + const item_votes[], + client_info[][], + item_info[][]) +{ + for (new i = 0; i < num_clients; ++i) + { + client_info[i][VOTEINFO_CLIENT_INDEX] = client_indexes[i]; + client_info[i][VOTEINFO_CLIENT_ITEM] = client_votes[i]; + } + + for (new i = 0; i < num_items; ++i) + { + item_info[i][VOTEINFO_ITEM_INDEX] = item_indexes[i]; + item_info[i][VOTEINFO_ITEM_VOTES] = item_votes[i]; + } +} + +/** + * Sets an advanced vote handling callback. If this callback is set, + * MenuAction_VoteEnd will not be called. + * + * @param vote NativeVotes Handle. + * @param callback Callback function. + * @noreturn + * @error Invalid Handle or callback. + */ +native NativeVotes_SetResultCallback(Handle:vote, NativeVotes_VoteHandler:callback); + +/** + * Returns the number of seconds you should "wait" before displaying + * a public vote. This number is the time remaining until + * (last_vote + sm_vote_delay). + * + * @return Number of seconds to wait, or 0 for none. + */ +native NativeVotes_CheckVoteDelay(); + +/** + * Returns whether a client is in the pool of clients allowed + * to participate in the current vote. This is determined by + * the client list passed to NativeVotes_Display(). + * + * @param client Client index. + * @return True if client is allowed to vote, false otherwise. + * @error If no vote is in progress or client index is invalid. + */ +native bool:NativeVotes_IsClientInVotePool(client); + +/** + * Redraws the current vote to a client in the voting pool. + * + * @param client Client index. + * @param revotes True to allow revotes, false otherwise. + * @return True on success, false if the client is in the vote pool + * but cannot vote again. + * @error No vote in progress, client is not in the voting pool, + * or client index is invalid. + */ +native bool:NativeVotes_RedrawClientVote(client, bool:revotes=true); + +/** + * Retrieve the vote type + * + * @param vote NativeVotes Handle. + * @return The built in vote type + * @error Invalid Handle + */ +native NativeVotesType:NativeVotes_GetType(Handle:vote); + +/** + * Set the team this vote is for, or NATIVEVOTES_ALL_TEAMS for all teams. + * + * Defaults to NATIVEVOTES_ALL_TEAMS if not explicitly set. + * + * @param vote NativeVotes Handle. + * @param team Team number this vote is for + * @noreturn + * @error Invalid Handle + */ +native NativeVotes_SetTeam(Handle:vote, team); + +/** + * Retrieve the team this vote is for + * + * @param vote NativeVotes Handle. + * @return Team index or NATIVEVOTES_ALL_TEAMS for all teams. + * @error Invalid Handle + */ +native NativeVotes_GetTeam(Handle:vote); + +/** + * Set the client index of the player who initiated the vote. + * Use NATIVEVOTES_SERVER_INDEX if initiated by the server itself. + * + * Defaults to NATIVEVOTES_SERVER_INDEX if not explicitly set. + * + * @param vote NativeVotes Handle. + * @param client Client who initiated the vote or NATIVEVOTES_SERVER_INDEX + * @noreturn + * @error Invalid Handle + */ +native NativeVotes_SetInitiator(Handle:vote, client); + +/** + * Retrieve the client index of the player who initiated the vote or NATIVEVOTES_SERVER_INDEX if + * initiated by the server itself. + * + * @param Vote handle + * @return Client index or NATIVEVOTES_SERVER_INDEX + * @error Invalid Handle + */ +native NativeVotes_GetInitiator(Handle:vote); + +/** + * Broadcasts a vote to a list of clients. The most selected item will be + * returned through MenuAction_VoteEnd. On a tie, a random item will be returned + * from a list of the tied items. + * + * Note that MenuAction_VoteStart, MenuAction_VoteCancel, MenuAction_VoteEnd, and MenuAction_End are all + * default callbacks and do not need to be enabled. + * + * @param vote Vote Handle. + * @param clients Array of clients to broadcast to. + * @param numClients Number of clients in the array. + * @param time Maximum time to leave menu on the screen. + * @return True on success, false if a vote is already in progress. + * @error Invalid Handle, or a vote is already in progress. + */ +native bool:NativeVotes_Display(Handle:vote, clients[], numClients, time); + +/** + * Sends a vote menu to all clients. See NativeVotes_Display() for more information. + * + * @param vote Vote Handle. + * @param time Maximum time to leave menu on the screen. + * @return True on success, false if this menu already has a vote session + * in progress. + * @error Invalid Handle, or a vote is already in progress. + */ +stock bool:NativeVotes_DisplayToAll(Handle:vote, time) +{ + new total = 0; + decl players[MaxClients]; + + for (new i=1; i<=MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i)) + { + continue; + } + players[total++] = i; + } + + return NativeVotes_Display(vote, players, total, time); +} + +/** + * Sends a vote menu to a single team. See NativeVotes_Display() for more information. + * + * @param vote Vote Handle. + * @param team Team to send vote to. 1 = spectators, 2 = RED/Survivors/Terrorists, 3 = BLU/Infected/Counter-Terrorists + * @param time Maximum time to leave menu on the screen. + * @return True on success, false if this menu already has a vote session + * in progress. + * @error Invalid Handle, or a vote is already in progress. + */ +stock bool:NativeVotes_DisplayToTeam(Handle:vote, team, time) +{ + NativeVotes_SetTeam(vote, team); + + new total; + decl players[MaxClients]; + + for (new i=1; i<=MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) != team)) + { + continue; + } + players[total++] = i; + } + + return NativeVotes_Display(vote, players, total, time); +} + +/** + * Sends a vote menu to all clients who are not spectators or waiting to choose a team. See NativeVotes_Display() for more information. + * + * @param vote Vote Handle. + * @param time Maximum time to leave menu on the screen. + * @return True on success, false if this menu already has a vote session + * in progress. + * @error Invalid Handle, or a vote is already in progress. + */ +stock bool:NativeVotes_DisplayToAllNonSpectators(Handle:vote, time) +{ + new total; + decl players[MaxClients]; + + for (new i=1; i<=MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) < 2)) + { + continue; + } + players[total++] = i; + } + + return NativeVotes_Display(vote, players, total, time); +} + +/** + * Display vote passed screen + * + * You MUST call one of the NativeVotesDisplayPass* or NativeVotes_DisplayFail functions + * to hide the vote screen for users who didn't vote, and to clear out their selection + * for the next vote. + * + * @param vote Vote handle + * @param details Normally the item that won the vote or format string. Also used for custom vote winners + * @param ... Variable number of format parameters. + * @noreturn + */ +native NativeVotes_DisplayPass(Handle:vote, const String:details[]=""); + +/** + * Display vote passed screen with custom text to a single user + * + * You MUST call one of the NativeVotesDisplayPass* or NativeVotes_DisplayFail functions + * to hide the vote screen for users who didn't vote, and to clear out their selection + * for the next vote. + * + * @param vote Vote handle + * @param client client to display to + * @param format A format string. + * @param any Variable number of format parameters + * @noreturn + */ +native NativeVotes_DisplayPassCustomToOne(Handle:vote, client, const String:format[], any:...); + +/** + * Display vote passed screen with custom text + * + * You MUST call one of the NativeVotesDisplayPass* or NativeVotes_DisplayFail functions + * to hide the vote screen for users who didn't vote, and to clear out their selection + * for the next vote. + * + * @param vote Vote handle + * @param format A format string. + * @param any Variable number of format parameters + * @noreturn + */ +stock NativeVotes_DisplayPassCustom(Handle:vote, const String:format[], any:...) +{ + decl String:buffer[192]; + + for (new i = 1; i <= MaxClients; ++i) + { + if (IsClientInGame(i)) + { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), format, 3); + NativeVotes_DisplayPassCustomToOne(vote, i, "%s", buffer); + } + } +} + +/** + * Display vote passed screen with a custom type. + * + * A sample usage of this would be if Extend won an RTV vote: NativeVotes_DisplayPassEx(vote, NativeVotesPass_Extend, map); + * + * You MUST call one of NativeVotes_DisplayPass, NativeVotes_DisplayPassEx, + * or NativeVotes_DisplayFail to hide the vote screen for users who didn't vote + * and to clear out their selection for the next vote. + * + * #param vote Vote handle + * @param passType The pass screen to display + * @param details Normally the item that won the vote. Also used for custom vote winners + * @noreturn + */ +native NativeVotes_DisplayPassEx(Handle:vote, NativeVotesPassType:passType, const String:details[]=""); + +/** + * Display failure screen. + * + * You MUST call one of NativeVotes_DisplayPass, NativeVotes_DisplayPassEx, + * or NativeVotes_DisplayFail to hide the vote screen for users who didn't vote, + * and to clear out their selection for the next vote. + * + * @param reason Vote failure reason from NativeVotesFailType enum + * @noreturn + */ +native NativeVotes_DisplayFail(Handle:vote, NativeVotesFailType:reason=NativeVotesFail_Generic); + +/** + * Quick stock to determine whether voting is allowed. This doesn't let you + * fine-tune a reason for not voting, so it's not recommended for lazily + * telling clients that voting isn't allowed. + * + * @return True if voting is allowed, false if voting is in progress + * or the cooldown is active. + */ +stock bool:NativeVotes_IsNewVoteAllowed() +{ + if (NativeVotes_IsVoteInProgress() || NativeVotes_CheckVoteDelay() != 0) + { + return false; + } + + return true; +} + +/** + * Used when callvote is called with no arguments. + * + * This is used to configure the VoteSetup usermessage on TF2 and CS:GO + * + * @param client Client, in case the votes are restricted by client + * @param voteTypes Populate this array with the vote types this server supports + * Custom and multiple choice votes are not supported from + * the GUI and are thus ignored. + * @return Plugin_Continue to allow the server itself (or another plugin) to process the callvote + * Plugin_Changed if you're changing the voteTypes, + * Plugin_Handled to return a blank VoteSetup usermessage + * Plugin_Stop to prevent VoteSetup usermessage (not recommended) + */ +//functag public Action:NativeVotes_CallVoteSetupHandler(client, NativeVotesType:voteTypes[]); + +/** + * Forward for "callvote" handling + * + * You should respond to this by starting a vote or by calling NativeVotes_DisplayCallVoteFail + * + * @param client Client + * @param voteType Type of vote being called. This will NEVER be a multiple-choice or custom vote. + * @param voteArgument Vote argument or blank if the vote type has no argument. + * @param target target userid for kick votes or 0 for all other votes + * @return Plugin_Continue to allow the server itself (or another plugin) to process the callvote + * Plugin_Handled if you processed this vote type + * Plugin_Stop to block the vote type (not recommended) + */ +//functag public Action:NativeVotes_CallVoteHandler(client, NativeVotesType:voteType, const String:voteArgument[], target); + +/** + * Register a plugin as a vote manager. + * This is used to abstract away the details of the callvote command. + * + * @param callHandler Handler for callvote commands. + * @param setupHandler Handler to override the which vote types your server supports. Only useful on TF2 and CS:GO. + * @noreturn + */ +//native NativeVotes_RegisterVoteManager(NativeVotes_CallVoteHandler:callHandler, NativeVotes_CallVoteSetupHandler:setupHandler=INVALID_FUNCTION); + +/** + * Send a call vote fail screen to a user + * Used to respond to a callvote with invalid arguments or for other reasons + * (such as trying to target an admin for a kick/ban vote) + * + * @param client The client to display the fail screen to + * @param reason A vote call fail reason + * @param time For NativeVotesCallFail_Recent, the number of seconds until the vote + * can be called again + */ +native NativeVotes_DisplayCallVoteFail(client, NativeVotesCallFailType:reason, time); + +/** + * Redraws the vote title from inside a MenuAction_Display callback + * Not supported on L4D + * + * @param text Vote title to draw + * @error If called from outside MenuAction_Display + * @return Plugin_Changed if the change is allowed, Plugin_Continue if it isn't. + */ +native Action:NativeVotes_RedrawVoteTitle(const String:text[]); + +/** + * Redraws the vote text from inside a MenuAction_DisplayItem callback. + * Only supported on multiple-choice votes + * + * @param text Vote text to draw. + * @error If called from outside MenuAction_DisplayItem + * @return Plugin_Changed if the change is allowed, Plugin_Continue if it isn't. + */ +native Action:NativeVotes_RedrawVoteItem(const String:text[]); + +/** + * Retrieves voting information from MenuAction_VoteEnd. + * + * @param param2 Second parameter of MenuAction_VoteEnd. + * @param winningVotes Number of votes received by the winning option. + * @param totalVotes Number of total votes received. + * @noreturn + */ +stock NativeVotes_GetInfo(param2, &winningVotes, &totalVotes) +{ + winningVotes = param2 & 0xFFFF; + totalVotes = param2 >> 16; +} + +/** + * Do not edit below this line! + */ +public SharedPlugin:__pl_nativevotes = +{ + name = "nativevotes", + file = "nativevotes.smx", +#if defined REQUIRE_PLUGINS + required = 1, +#else + required = 0, +#endif +}; + +public __pl_nativevotes_SetNTVOptional() +{ + MarkNativeAsOptional("NativeVotes_IsVoteTypeSupported"); + MarkNativeAsOptional("NativeVotes_Create"); + MarkNativeAsOptional("NativeVotes_Close"); + MarkNativeAsOptional("NativeVotes_AddItem"); + MarkNativeAsOptional("NativeVotes_InsertItem"); + MarkNativeAsOptional("NativeVotes_RemoveItem"); + MarkNativeAsOptional("NativeVotes_RemoveAllItems"); + MarkNativeAsOptional("NativeVotes_GetItem"); + MarkNativeAsOptional("NativeVotes_GetItemCount"); + MarkNativeAsOptional("NativeVotes_SetDetails"); + MarkNativeAsOptional("NativeVotes_GetDetails"); + MarkNativeAsOptional("NativeVotes_SetTitle"); + MarkNativeAsOptional("NativeVotes_GetTitle"); + MarkNativeAsOptional("NativeVotes_SetTarget"); + MarkNativeAsOptional("NativeVotes_GetTarget"); + MarkNativeAsOptional("NativeVotes_GetTargetSteam"); + MarkNativeAsOptional("NativeVotes_IsVoteInProgress"); + MarkNativeAsOptional("NativeVotes_GetMaxItems"); + MarkNativeAsOptional("NativeVotes_SetOptionFlags"); + MarkNativeAsOptional("NativeVotes_GetOptionFlags"); + MarkNativeAsOptional("NativeVotes_Cancel"); + MarkNativeAsOptional("NativeVotes_SetResultCallback"); + MarkNativeAsOptional("NativeVotes_CheckVoteDelay"); + MarkNativeAsOptional("NativeVotes_IsClientInVotePool"); + MarkNativeAsOptional("NativeVotes_RedrawClientVote"); + MarkNativeAsOptional("NativeVotes_RedrawClientVote"); + MarkNativeAsOptional("NativeVotes_GetType"); + MarkNativeAsOptional("NativeVotes_SetTeam"); + MarkNativeAsOptional("NativeVotes_GetTeam"); + MarkNativeAsOptional("NativeVotes_SetInitiator"); + MarkNativeAsOptional("NativeVotes_GetInitiator"); + MarkNativeAsOptional("NativeVotes_Display"); + MarkNativeAsOptional("NativeVotes_DisplayPass"); + MarkNativeAsOptional("NativeVotes_DisplayPassCustomToOne"); + MarkNativeAsOptional("NativeVotes_DisplayPassEx"); + MarkNativeAsOptional("NativeVotes_DisplayFail"); + MarkNativeAsOptional("NativeVotes_RegisterVoteManager"); + MarkNativeAsOptional("NativeVotes_DisplayCallVoteFail"); + MarkNativeAsOptional("NativeVotes_RedrawVoteTitle"); + MarkNativeAsOptional("NativeVotes_RedrawVoteItem"); +} diff --git a/mapchooser_extended/scripting/mapchooser_extended.sp b/mapchooser_extended/scripting/mapchooser_extended.sp index 3c3ec2e..e0ef15a 100644 --- a/mapchooser_extended/scripting/mapchooser_extended.sp +++ b/mapchooser_extended/scripting/mapchooser_extended.sp @@ -45,10 +45,10 @@ #include #include -#include "include/mapchooser_extended" +#include #include #include -#include +#include #undef REQUIRE_PLUGIN #include diff --git a/mapchooser_extended/scripting/nominations_extended.sp b/mapchooser_extended/scripting/nominations_extended.sp index 67c27e4..79af370 100644 --- a/mapchooser_extended/scripting/nominations_extended.sp +++ b/mapchooser_extended/scripting/nominations_extended.sp @@ -32,14 +32,14 @@ * Version: $Id$ */ -#include -#include -#include "include/mapchooser_extended" -#include - #pragma semicolon 1 #pragma newdecls required +#include +#include +#include +#include + #define MCE_VERSION "1.13.0" public Plugin myinfo = diff --git a/mapchooser_extended/scripting/rockthevote_extended.sp b/mapchooser_extended/scripting/rockthevote_extended.sp index b05bb75..9e76022 100644 --- a/mapchooser_extended/scripting/rockthevote_extended.sp +++ b/mapchooser_extended/scripting/rockthevote_extended.sp @@ -31,14 +31,14 @@ * Version: $Id$ */ +#pragma semicolon 1 +#pragma newdecls required + #include #include #include #include -#pragma semicolon 1 -#pragma newdecls required - #define MCE_VERSION "1.13.0" public Plugin myinfo =