diff --git a/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.dll b/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.dll index 574ed1c78..b4e06953f 100644 Binary files a/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.dll and b/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.dll differ diff --git a/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.so b/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.so index 4606f5a6d..613982413 100644 Binary files a/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.so and b/addons/sourcemod/extensions/builtinvotes.ext.2.l4d2.so differ diff --git a/addons/sourcemod/scripting/dev_plugins/builtinvotes_test.sp b/addons/sourcemod/scripting/dev_plugins/builtinvotes_test.sp new file mode 100644 index 000000000..89dadeefa --- /dev/null +++ b/addons/sourcemod/scripting/dev_plugins/builtinvotes_test.sp @@ -0,0 +1,279 @@ +#pragma semicolon 1 +#pragma newdecls required + +#include +#include + +DataPack + g_hCallBackPack = null; + +Handle + g_hVoteHandler = null; + +ConVar + g_hCvarBlockBVote = null, + g_hCvarDisplayBVoteResult = null; + +enum +{ + eBlockNone = 0, + eBlockOnCreation, + eBlockAtStart +}; + +enum +{ + eVoteFail = 0, + eVotePass +}; + +stock const char g_sBuiltinVoteCreateError[][] = +{ + "eBuiltinVoteErrorNone", + "eBlockedWithForward", + "eInvalidParamBuiltinVoteType" +}; + +public Plugin myinfo = +{ + name = "[L4D2] BuiltinVotes test", + author = "A1m`", + description = "Plugin to test the extension 'builtinvotes'", + version = "2.5", + url = "https://github.com/L4D-Community/builtinvotes" +}; + +public void OnPluginStart() +{ + g_hCvarBlockBVote = CreateConVar("sm_block_builtinvotes", \ + "0", \ + "Block all votes from extension 'builtinvotes' (used for debugging). 1 - block voting on creation, 2 - block voting at start.", \ + _, true, 0.0, true, 2.0 \ + ); + + g_hCvarDisplayBVoteResult = CreateConVar("sm_display_builtinvotes_result", \ + "1", \ + "Display the result of voting at the end of voting. 0 - not display, 1 - display.", \ + _, true, 0.0, true, 1.0 \ + ); + + RegAdminCmd("sm_bv_test", Cmd_BuiltinVotesTest, ADMFLAG_GENERIC); + RegAdminCmd("sm_bv_close_data", Cmd_BuiltinVotesCloseData, ADMFLAG_GENERIC); + RegAdminCmd("sm_getvotecontroller", Cmd_GetGameVoteController, ADMFLAG_GENERIC); +} + +Action Cmd_GetGameVoteController(int iClient, int iArgs) +{ + int iEntIndex = Game_GetVoteController(); + + char sEntityName[64]; + FormatEx(sEntityName, sizeof(sEntityName), "Unknown entity"); + + if (iEntIndex > MaxClients && IsValidEntity(iEntIndex)) { + GetEntityClassname(iEntIndex, sEntityName, sizeof(sEntityName)); + } + + PrintToChat(iClient, "Entity name: %s, entity index: %d!", sEntityName, iEntIndex); + + return Plugin_Handled; +} + +public Action OnBuiltinVoteCreate(Handle hPlugin, const char[] sPluginName) +{ + PrintToChatAll("[OnBuiltinVoteCreate] hPlugin: %x, sPluginName: %s", hPlugin, sPluginName); + + if (hPlugin != null) { + char sPlName[32], sPlAuthor[32], sPlDescription[64], sPlVersion[16], sPlUrl[256]; + + GetPluginInfo(hPlugin, PlInfo_Name, sPlName, sizeof(sPlName)); + GetPluginInfo(hPlugin, PlInfo_Author, sPlAuthor, sizeof(sPlAuthor)); + GetPluginInfo(hPlugin, PlInfo_Description, sPlDescription, sizeof(sPlDescription)); + GetPluginInfo(hPlugin, PlInfo_Version, sPlVersion, sizeof(sPlVersion)); + GetPluginInfo(hPlugin, PlInfo_URL, sPlUrl, sizeof(sPlUrl)); + + PrintToChatAll("[OnBuiltinVoteCreate] Plugin name: %s ", sPlName); + PrintToChatAll("[OnBuiltinVoteCreate] Plugin author: %s ", sPlAuthor); + PrintToChatAll("[OnBuiltinVoteCreate] Plugin description: %s ", sPlDescription); + PrintToChatAll("[OnBuiltinVoteCreate] Plugin version: %s ", sPlVersion); + PrintToChatAll("[OnBuiltinVoteCreate] Plugin url: %s ", sPlUrl); + PrintToChatAll("[OnBuiltinVoteCreate] Plugin status: %d", GetPluginStatus(hPlugin)); + } + + return (g_hCvarBlockBVote.IntValue == eBlockOnCreation) ? Plugin_Handled : Plugin_Continue; +} + +public Action OnBuiltinVoteStart(Handle hVote, Handle hPlugin, const char[] sPluginName) +{ + int iInitiator = GetBuiltinVoteInitiator(hVote); + + char sInitiatorName[32] = "Unknown"; + + // Server (0) and clients (1-32) + if (iInitiator >= 0 && iInitiator <= MaxClients && IsClientInGame(iInitiator)) { + GetClientName(iInitiator, sInitiatorName, sizeof(sInitiatorName)); + } + + PrintToChatAll("[OnBuiltinVoteStart] Initiator: %s (%d), hPlugin: %x, sPluginName: %s", sInitiatorName, iInitiator, hPlugin, sPluginName); + + if (hPlugin != null) { + char sPlName[32], sPlAuthor[32], sPlDescription[64], sPlVersion[16], sPlUrl[256]; + + GetPluginInfo(hPlugin, PlInfo_Name, sPlName, sizeof(sPlName)); + GetPluginInfo(hPlugin, PlInfo_Author, sPlAuthor, sizeof(sPlAuthor)); + GetPluginInfo(hPlugin, PlInfo_Description, sPlDescription, sizeof(sPlDescription)); + GetPluginInfo(hPlugin, PlInfo_Version, sPlVersion, sizeof(sPlVersion)); + GetPluginInfo(hPlugin, PlInfo_URL, sPlUrl, sizeof(sPlUrl)); + + PrintToChatAll("[OnBuiltinVoteStart] Plugin name: %s ", sPlName); + PrintToChatAll("[OnBuiltinVoteStart] Plugin author: %s ", sPlAuthor); + PrintToChatAll("[OnBuiltinVoteStart] Plugin description: %s ", sPlDescription); + PrintToChatAll("[OnBuiltinVoteStart] Plugin version: %s ", sPlVersion); + PrintToChatAll("[OnBuiltinVoteStart] Plugin url: %s ", sPlUrl); + PrintToChatAll("[OnBuiltinVoteStart] Plugin status: %d", GetPluginStatus(hPlugin)); + } + + return (g_hCvarBlockBVote.IntValue == eBlockAtStart) ? Plugin_Handled : Plugin_Continue; +} + +Action Cmd_BuiltinVotesCloseData(int iClient, int iArgs) +{ + if (g_hCallBackPack == null) { + PrintToChat(iClient, "User data was not passed to the callback!"); + return Plugin_Handled; + } + + delete g_hCallBackPack; + g_hCallBackPack = null; + + PrintToChat(iClient, "User data was successfully deleted!"); + + return Plugin_Handled; +} + +Action Cmd_BuiltinVotesTest(int iClient, int iArgs) +{ + StartBuiltinVote(iClient, (iArgs == 1)); + + return Plugin_Handled; +} + +void StartBuiltinVote(const int iInitiator, bool bPassData = false) +{ + if (!IsNewBuiltinVoteAllowed()) { + PrintToChat(iInitiator, "Builtinvote cannot be started now."); + return; + } + + int iNumPlayers; + int[] iPlayers = new int[MaxClients]; + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i)) { + continue; + } + + iPlayers[iNumPlayers++] = i; + } + + eBuiltinVoteCreateError iError; + g_hVoteHandler = CreateBuiltinVoteEx(VoteActionHandler, BuiltinVoteType_Custom_YesNo, BuiltinVoteAction_Cancel | BuiltinVoteAction_VoteEnd | BuiltinVoteAction_End, iError); + if (g_hVoteHandler == null) { + PrintToChatAll("Failed to create vote. Reason %s (%d)!", g_sBuiltinVoteCreateError[iError], iError); + return; + } + + char sBuffer[64]; + Format(sBuffer, sizeof(sBuffer), "Builtinvote test!"); + SetBuiltinVoteArgument(g_hVoteHandler, sBuffer); + SetBuiltinVoteInitiator(g_hVoteHandler, iInitiator); + + if (bPassData) { + g_hCallBackPack = new DataPack(); + + g_hCallBackPack.WriteString("UserData 1"); + g_hCallBackPack.WriteString("UserData 2"); + g_hCallBackPack.WriteCell(1); + g_hCallBackPack.WriteCell(2); + + SetBuiltinVoteResultCallback(g_hVoteHandler, VoteResultHandlerUserData, g_hCallBackPack, BV_DATA_HNDL_CLOSE); + } else { + SetBuiltinVoteResultCallback(g_hVoteHandler, VoteResultHandler); + } + + DisplayBuiltinVote(g_hVoteHandler, iPlayers, iNumPlayers, 20); + //FakeClientCommand(iInitiator, "Vote Yes"); +} + +void VoteActionHandler(Handle hVote, BuiltinVoteAction iAction, int iParam1, int iParam2) +{ + switch (iAction) { + case BuiltinVoteAction_End: { + g_hVoteHandler = null; + g_hCallBackPack = null; + delete hVote; + } + case BuiltinVoteAction_Cancel: { + DisplayBVoteResult(hVote, eVoteFail); + } + } +} + +void VoteResultHandlerUserData(Handle hVote, int iNumVotes, int iNumClients, \ + const int[][] iClientInfo, int iNumItems, const int[][] iItemInfo, DataPack hPack) +{ + for (int i = 0; i < iNumItems; i++) { + if (iItemInfo[i][BUILTINVOTEINFO_ITEM_INDEX] != BUILTINVOTES_VOTE_YES) { + continue; + } + + if (iItemInfo[i][BUILTINVOTEINFO_ITEM_VOTES] > (iNumClients / 2)) { + hPack.Reset(); + + char sBuffer1[32], sBuffer2[32]; + hPack.ReadString(sBuffer1, sizeof(sBuffer1)); + hPack.ReadString(sBuffer2, sizeof(sBuffer2)); + + int iBuff1 = hPack.ReadCell(); + int iBuff2 = hPack.ReadCell(); + PrintToChatAll("String1: %s, String2: %s, int1: %d, int2: %d", sBuffer1, sBuffer2, iBuff1, iBuff2); + + DisplayBVoteResult(hVote, eVotePass, "Builtinvote test end..."); + + return; + } + } + + DisplayBVoteResult(hVote, eVoteFail); +} + +void VoteResultHandler(Handle hVote, int iNumVotes, int iNumClients, \ + const int[][] iClientInfo, int iNumItems, const int[][] iItemInfo) +{ + for (int i = 0; i < iNumItems; i++) { + if (iItemInfo[i][BUILTINVOTEINFO_ITEM_INDEX] != BUILTINVOTES_VOTE_YES) { + continue; + } + + if (iItemInfo[i][BUILTINVOTEINFO_ITEM_VOTES] > (iNumClients / 2)) { + DisplayBVoteResult(hVote, eVotePass, "Builtinvote test end..."); + + return; + } + } + + DisplayBVoteResult(hVote, eVoteFail); +} + +void DisplayBVoteResult(Handle hVote, int iResultType, char[] sPassArg = "") +{ + if (!g_hCvarDisplayBVoteResult.BoolValue) { + return; + } + + if (iResultType == eVotePass) { + DisplayBuiltinVotePass(hVote, sPassArg); + + return; + } + + DisplayBuiltinVoteFail(hVote, BuiltinVoteFail_Loses); +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/include/builtinvotes.inc b/addons/sourcemod/scripting/include/builtinvotes.inc index b0e674205..2a450fbe2 100644 --- a/addons/sourcemod/scripting/include/builtinvotes.inc +++ b/addons/sourcemod/scripting/include/builtinvotes.inc @@ -31,15 +31,21 @@ */ #if defined _builtinvotes_included - #endinput + #endinput #endif #define _builtinvotes_included +#include "builtinvotes_stocks.inc" + +/* Source: https://github.com/L4D-Community/builtinvotes/blob/master/extra/include/builtinvotes.inc */ + #define BUILTINVOTES_EXTEND "Extend current Map" /** Defined in TF2, but doesn't appear to be localized */ #define BUILTINVOTES_ALL_TEAMS -1 // Defined by TF2, may be the same in L4D/L4D2 #define BUILTINVOTES_SERVER_INDEX 99 // Defined by TF2, may be the same in L4D/L4D2 +#define BV_DATA_HNDL_CLOSE (1 << 0) + /** * Reasons a vote can end. */ @@ -70,7 +76,6 @@ enum BuiltinVoteType BuiltinVoteType_ScrambleEnd = 13, /**< TF2: Yes/No, argument ignored */ BuiltinVoteType_Custom_Mult = 14, /**< TF2: Multiple-choice, argument is vote text. */ BuiltinVoteType_Alltalk = 15, /**< L4D2: Yes/No, argument ignored (handled internally by extension) */ - } /** @@ -169,9 +174,38 @@ enum BuiltinVoteFailReason { BuiltinVoteFail_Generic = 0, /**< Vote was generically cancelled. */ BuiltinVoteFail_Loses = 3, /**< No votes outnumbered Yes votes */ - BuiltinVoteFail_NotEnoughVotes = 4, /**< Vote did not receive enough votes. */ + BuiltinVoteFail_NotEnoughVotes = 4, /**< Vote did not receive enough votes. */ } +enum eBuiltinVoteCreateError +{ + eBuiltinVoteErrorNone = 0, // Vote was created + eBlockedWithForward, // Vote blocked with forward 'OnBuiltinVoteCreated' + eInvalidParamBuiltinVoteType // Invalid parameter 'BuiltinVoteType' passed to native 'CreateBuiltinVote' or not available in this game +}; + +/** + * Called at the start of creating a vote, at this moment information such as argument, initiator, etc. is not available. + * NOTE: When using this forward, you need to add a check to the plugin for the vote handle, + * otherwise there will be errors in the logs of the sourcemod, because the vote handle will not be set after blocking the forward. + * + * @param hPlugin Handle to the plugin from which the vote was created. + * @param sPluginName The name of the plugin from which the vote was created. + * @return 'Plugin_Continue' to allow voting, otherwise voting will be blocked. + */ +forward Action OnBuiltinVoteCreate(Handle hPlugin, const char[] sPluginName); + +/** + * Called when a vote is created and the vote panel has not yet been sent to the players, + * at this moment information such as argument, initiator, etc. is available. + * + * @param hVote Vote Handle. + * @param hPlugin Handle to the plugin from which the vote was created. + * @param sPluginName The saved name of the plugin from which the vote was created. + * @return 'Plugin_Continue' to allow voting, otherwise voting will be blocked. + */ +forward Action OnBuiltinVoteStart(Handle hVote, Handle hPlugin, const char[] sPluginName); + /** * Called when a vote action is completed. * Based on MenuHandler @@ -193,9 +227,25 @@ typedef BuiltinVoteActionHandler = function void(Handle vote, BuiltinVoteAction * 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. + * + * @return A new vote Handle or null if vote was not created. + */ +native Handle CreateBuiltinVote(BuiltinVoteActionHandler handler, BuiltinVoteType voteType, BuiltinVoteAction actions = BUILTINVOTE_ACTIONS_DEFAULT); + +/** + * 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. + * @param error The reason why the vote was not created. + * + * @return A new vote Handle or null if vote was not created. */ -native Handle CreateBuiltinVote(BuiltinVoteActionHandler handler, BuiltinVoteType voteType, BuiltinVoteAction actions=BUILTINVOTE_ACTIONS_DEFAULT); +native Handle CreateBuiltinVoteEx(BuiltinVoteActionHandler handler, BuiltinVoteType voteType, BuiltinVoteAction actions = BUILTINVOTE_ACTIONS_DEFAULT, eBuiltinVoteCreateError &error); /** * Broadcasts a vote to a list of clients. The most selected item will be @@ -214,31 +264,6 @@ native Handle CreateBuiltinVote(BuiltinVoteActionHandler handler, BuiltinVoteTyp */ native bool DisplayBuiltinVote(Handle vote, int[] clients, int numClients, int time); -/** - * Sends a vote menu to all clients. See DisplayBuiltinVote() 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. - */ -stock bool DisplayBuiltinVoteToAll(Handle vote, int time) -{ - int iNumPlayers; - int[] iPlayers = new int[MaxClients]; - - for (int i = 1; i <= MaxClients; i++) { - if (!IsClientInGame(i) || IsFakeClient(i)) { - continue; - } - - iPlayers[iNumPlayers++] = i; - } - - return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); -} - /** * Appends a new item to the end of a vote. Only valid for Multiple Choice votes * @@ -383,8 +408,11 @@ native void CancelBuiltinVote(); * defines. * @noreturn */ -typedef BuiltinVoteHandler = function void(Handle vote, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info); -//typedef BuiltinVoteHandler = function void(Handle vote, int num_votes, int num_clients, const int[][2] client_info, int num_items, const int[][2] item_info); +typeset BuiltinVoteHandler +{ + function void(Handle vote, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info); + function void(Handle vote, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info, any data); +}; /** * Sets an advanced vote handling callback. If this callback is set, @@ -392,10 +420,16 @@ typedef BuiltinVoteHandler = function void(Handle vote, int num_votes, int num_c * * @param vote BuiltinVote Handle. * @param callback Callback function. + * @param data Handle or value to pass through to the BuiltinVoteHandler callback function. + * @param dataFlags 'BV_DATA_HNDL_CLOSE' for the data handle to be destroyed after the vote or 0. + * If you are passing in parameter 'data' a handle (for example - DataPack) here that was supposed to be closed, + * you must pass the constant 'BV_DATA_HNDL_CLOSE' to parameter 'dataFlags'. + * If you pass a constant 'BV_DATA_HNDL_CLOSE' to parameter 'dataFlags', + * then extension will destroy it or you have to close it yourself to avoid getting a memory leak. * @noreturn * @error Invalid Handle or callback. */ -native void SetBuiltinVoteResultCallback(Handle vote, BuiltinVoteHandler callback); +native void SetBuiltinVoteResultCallback(Handle vote, BuiltinVoteHandler callback, any data = 0, int dataFlags = 0); /** * Returns the number of seconds you should "wait" before displaying @@ -508,23 +542,9 @@ native void DisplayBuiltinVotePass2(Handle vote, char[] translation, char[] para */ native void DisplayBuiltinVoteFail(Handle vote, BuiltinVoteFailReason reason=BuiltinVoteFail_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. - * Checks if a game or builtinvote vote is in progress - * - * @return True if voting is allowed, false if voting is in progress - * or the cooldown is active. - */ -stock bool IsNewBuiltinVoteAllowed() -{ - return (!(IsBuiltinVoteInProgress() || CheckBuiltinVoteDelay() != 0)); -} - /** * Checks if the BuiltinVote is in progress - * By default this is already built into the native IsBuiltinVoteInProgress(), + * By default this is already built into the native IsBuiltinVoteInProgress(), * you can use this for something else * * @return True if BuiltinVote vote in progress, otherwise false @@ -533,7 +553,7 @@ native bool BuiltinVote_IsVoteInProgress(); /** * Checks if the in-game voting is in progress - * By default this is already built into the native IsBuiltinVoteInProgress(), + * By default this is already built into the native IsBuiltinVoteInProgress(), * you can use this for something else * * @return True if game vote in progress, otherwise false @@ -545,148 +565,17 @@ native bool Game_IsVoteInProgress(); * @remarks Team number: 1 - spectators, 2 - survivors, 3 - infected * @remarks It hardly works for a team of spectators * - * @returns -1 if no vote in progress or vote is for everyone, + * @returns -1 if no vote in progress or vote is for everyone, * otherwise the command number */ native int Game_GetVoteTeam(); /** - * Retrieves voting information from BuiltinVoteAction_VoteEnd. - * - * @param param2 Second parameter of BuiltinVoteAction_VoteEnd. - * @param winningVotes Number of votes received by the winning option. - * @param totalVotes Number of total votes received. - * @noreturn - */ -stock void GetBuiltinVoteInfo(int param2, int &winningVotes, int &totalVotes) -{ - winningVotes = param2 & 0xFFFF; - totalVotes = param2 >> 16; -} - -/** - * Sends a vote menu to a single team. See DisplayBuiltinVote() for more information. - * - * @param vote Vote Handle. - * @param team Team to send vote to. 1 = spectators, 2 = RED/Survivors, 3 = BLU/Infected - * @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. - */ -stock bool DisplayBuiltinVoteToTeam(Handle vote, int team, int time) -{ - SetBuiltinVoteTeam(vote, team); - - int iNumPlayers; - int[] iPlayers = new int[MaxClients]; - - for (int i = 1; i <= MaxClients; i++) { - if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) != team)) { - continue; - } - - iPlayers[iNumPlayers++] = i; - } - - return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); -} - -/** - * Sends a vote menu to all clients except one. See DisplayBuiltinVote() for more information. - * Useful for kick/ban votes - * - * @param vote Vote Handle. - * @param client Client index not to send vote to - * @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 or if the client isn't in the game. - * @error Invalid Handle. - */ -stock bool DisplayBuiltinVoteToAllButOne(Handle vote, int client, int time) -{ - if (!IsClientInGame(client)) { - return false; - } - - int iNumPlayers; - int[] iPlayers = new int[MaxClients]; - - for (int i = 1; i <= MaxClients; i++) { - if (!IsClientInGame(i) || IsFakeClient(i) || (i == client)) { - continue; - } - - iPlayers[iNumPlayers++] = i; - } - - return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); -} - -/** - * Sends a vote menu to a single team except one player. See DisplayBuiltinVote() for more information. - * - * @param vote Vote Handle. - * @param client Client index not to send vote to. Team is derived from this client. - * @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 or the client isn't in the game. - * @error Invalid Handle. - */ -stock bool DisplayBuiltinVoteToTeamButOne(Handle vote, int client, int time) -{ - if (!IsClientInGame(client)) { - return false; - } - - int team = GetClientTeam(client); - -#if 0 - if (team < 2) { - return false; - } -#endif - - SetBuiltinVoteTeam(vote, team); - - int iNumPlayers; - int[] iPlayers = new int[MaxClients]; - - for (int i = 1; i <= MaxClients; i++) { - if (!IsClientInGame(i) || IsFakeClient(i) || (i == client) || (GetClientTeam(i) != team)) { - continue; - } - - iPlayers[iNumPlayers++] = i; - } - - return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); -} - -/** - * Sends a vote menu to all clients who are not spectators or waiting to choose a team. See DisplayBuiltinVote() for more information. + * Return entity index 'CVoteController' * - * @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. + * @return int -1 if 'CVoteController' not found, otherwise entity index */ -stock bool DisplayBuiltinVoteToAllNonSpectators(Handle vote, int time) -{ - int iNumPlayers; - int[] iPlayers = new int[MaxClients]; - - for (int i = 1; i <= MaxClients; i++) { - if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) < 2)) { - continue; - } - - iPlayers[iNumPlayers++] = i; - } - - return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); -} +native int Game_GetVoteController(); /** * Do not edit below this line! @@ -711,6 +600,7 @@ public Extension __ext_builtinvotes = public void __ext_builtinvotes_SetNTVOptional() { MarkNativeAsOptional("CreateBuiltinVote"); + MarkNativeAsOptional("CreateBuiltinVoteEx"); MarkNativeAsOptional("DisplayBuiltinVote"); MarkNativeAsOptional("AddBuiltinVoteItem"); MarkNativeAsOptional("InsertBuiltinVoteItem"); @@ -739,5 +629,6 @@ public void __ext_builtinvotes_SetNTVOptional() MarkNativeAsOptional("BuiltinVote_IsVoteInProgress"); MarkNativeAsOptional("Game_IsVoteInProgress"); MarkNativeAsOptional("Game_GetVoteTeam"); + MarkNativeAsOptional("Game_GetVoteController"); } #endif diff --git a/addons/sourcemod/scripting/include/builtinvotes_stocks.inc b/addons/sourcemod/scripting/include/builtinvotes_stocks.inc new file mode 100644 index 000000000..bed65778d --- /dev/null +++ b/addons/sourcemod/scripting/include/builtinvotes_stocks.inc @@ -0,0 +1,247 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * BuiltinVotes (C)2011 Ross Bemrose (Powerlord). All rights reserved. + * ============================================================================= + * + * This file is part of the BuiltinVotes addon. + * + * 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$ + */ + +#if defined _builtinvotes_included_stocks + #endinput +#endif +#define _builtinvotes_included_stocks + +// Does not support direct inclusion +#if !defined _builtinvotes_included + #endinput +#endif + +/* Source: https://github.com/L4D-Community/builtinvotes/blob/master/extra/include/builtinvotes_stocks.inc */ + +enum eVoteType +{ + eVoteNone = -1, + eBuiltinVote = 0, + eGameVote = 1 +}; + +/** + * Sends a vote menu to all clients. See DisplayBuiltinVote() 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. + */ +stock bool DisplayBuiltinVoteToAll(Handle vote, int time) +{ + int iNumPlayers; + int[] iPlayers = new int[MaxClients]; + + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i)) { + continue; + } + + iPlayers[iNumPlayers++] = i; + } + + return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); +} + +/** + * 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. + * Checks if a game or builtinvote vote is in progress + * + * @return True if voting is allowed, false if voting is in progress + * or the cooldown is active. + */ +stock bool IsNewBuiltinVoteAllowed() +{ + return (!(IsBuiltinVoteInProgress() || CheckBuiltinVoteDelay() != 0)); +} + +/** + * Returns the type of vote currently in progress + * + * @return eVoteType eVoteNone (-1) - if the vote is not in progress now, + * eBuiltinVote (0) - if 'builtinvote' voting is in progress, + * eGameVote (1) - if in-game voting is in progress. + */ +stock eVoteType GetVoteType_InProgress() +{ + if (BuiltinVote_IsVoteInProgress()) { + return eBuiltinVote; + } + + if (Game_IsVoteInProgress()) { + return eGameVote; + } + + return eVoteNone; +} + +/** + * Retrieves voting information from BuiltinVoteAction_VoteEnd. + * + * @param param2 Second parameter of BuiltinVoteAction_VoteEnd. + * @param winningVotes Number of votes received by the winning option. + * @param totalVotes Number of total votes received. + * @noreturn + */ +stock void GetBuiltinVoteInfo(int param2, int &winningVotes, int &totalVotes) +{ + winningVotes = param2 & 0xFFFF; + totalVotes = param2 >> 16; +} + +/** + * Sends a vote menu to a single team. See DisplayBuiltinVote() for more information. + * + * @param vote Vote Handle. + * @param team Team to send vote to. 1 = spectators, 2 = RED/Survivors, 3 = BLU/Infected + * @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. + */ +stock bool DisplayBuiltinVoteToTeam(Handle vote, int team, int time) +{ + SetBuiltinVoteTeam(vote, team); + + int iNumPlayers; + int[] iPlayers = new int[MaxClients]; + + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) != team)) { + continue; + } + + iPlayers[iNumPlayers++] = i; + } + + return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); +} + +/** + * Sends a vote menu to all clients except one. See DisplayBuiltinVote() for more information. + * Useful for kick/ban votes + * + * @param vote Vote Handle. + * @param client Client index not to send vote to + * @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 or if the client isn't in the game. + * @error Invalid Handle. + */ +stock bool DisplayBuiltinVoteToAllButOne(Handle vote, int client, int time) +{ + if (!IsClientInGame(client)) { + return false; + } + + int iNumPlayers; + int[] iPlayers = new int[MaxClients]; + + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i) || (i == client)) { + continue; + } + + iPlayers[iNumPlayers++] = i; + } + + return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); +} + +/** + * Sends a vote menu to a single team except one player. See DisplayBuiltinVote() for more information. + * + * @param vote Vote Handle. + * @param client Client index not to send vote to. Team is derived from this client. + * @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 or the client isn't in the game. + * @error Invalid Handle. + */ +stock bool DisplayBuiltinVoteToTeamButOne(Handle vote, int client, int time) +{ + if (!IsClientInGame(client)) { + return false; + } + + int team = GetClientTeam(client); + +#if 0 + if (team < 2) { + return false; + } +#endif + + SetBuiltinVoteTeam(vote, team); + + int iNumPlayers; + int[] iPlayers = new int[MaxClients]; + + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i) || (i == client) || (GetClientTeam(i) != team)) { + continue; + } + + iPlayers[iNumPlayers++] = i; + } + + return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); +} + +/** + * Sends a vote menu to all clients who are not spectators or waiting to choose a team. See DisplayBuiltinVote() 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. + */ +stock bool DisplayBuiltinVoteToAllNonSpectators(Handle vote, int time) +{ + int iNumPlayers; + int[] iPlayers = new int[MaxClients]; + + for (int i = 1; i <= MaxClients; i++) { + if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) < 2)) { + continue; + } + + iPlayers[iNumPlayers++] = i; + } + + return DisplayBuiltinVote(vote, iPlayers, iNumPlayers, time); +}