diff --git a/core/MenuManager.cpp b/core/MenuManager.cpp index 23733e95..8a0e589c 100644 --- a/core/MenuManager.cpp +++ b/core/MenuManager.cpp @@ -692,3 +692,8 @@ void MenuManager::CancelVoting() { s_VoteHandler.CancelVoting(); } + +unsigned int MenuManager::GetRemainingVoteDelay() +{ + return s_VoteHandler.GetRemainingVoteDelay(); +} diff --git a/core/MenuManager.h b/core/MenuManager.h index 86c87759..74c2622b 100644 --- a/core/MenuManager.h +++ b/core/MenuManager.h @@ -89,6 +89,7 @@ public: unsigned int flags=0); bool IsVoteInProgress(); void CancelVoting(); + unsigned int GetRemainingVoteDelay(); public: //IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); public: diff --git a/core/MenuVoting.cpp b/core/MenuVoting.cpp index 1d1b34ca..f63da673 100644 --- a/core/MenuVoting.cpp +++ b/core/MenuVoting.cpp @@ -36,6 +36,49 @@ #include "PlayerManager.h" #include "sourcemm_api.h" +float g_next_vote = 0.0f; + +void OnVoteDelayChange(ConVar *cvar, const char *value); +ConVar sm_vote_delay("sm_vote_delay", + "30", + 0, + "Sets the recommended time in between public votes", + false, + 0.0, + false, + 0.0, + OnVoteDelayChange); + +void OnVoteDelayChange(ConVar *cvar, const char *value) +{ + /* See if the new vote delay isn't something we need to account for */ + if (sm_vote_delay.GetFloat() < 1.0f) + { + g_next_vote = 0.0f; + return; + } + + /* If there was never a last vote, ignore this change */ + if (g_next_vote < 0.1f) + { + return; + } + + /* Subtract the original value, then add the new one. */ + g_next_vote -= (float)atof(value); + g_next_vote += sm_vote_delay.GetFloat(); +} + +unsigned int VoteMenuHandler::GetRemainingVoteDelay() +{ + if (g_next_vote <= gpGlobals->curtime) + { + return 0; + } + + return (unsigned int)(g_next_vote - gpGlobals->curtime); +} + void VoteMenuHandler::OnSourceModAllInitialized() { g_Players.AddClientListener(this); @@ -46,6 +89,11 @@ void VoteMenuHandler::OnSourceModShutdown() g_Players.RemoveClientListener(this); } +void VoteMenuHandler::OnSourceModLevelChange(const char *mapName) +{ + g_next_vote = 0.0f; +} + unsigned int VoteMenuHandler::GetMenuAPIVersion2() { return m_pHandler->GetMenuAPIVersion2(); @@ -81,6 +129,18 @@ bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int c return false; } + float fVoteDelay = sm_vote_delay.GetFloat(); + if (fVoteDelay < 1.0) + { + g_next_vote = 0.0; + } else { + /* This little trick breaks for infinite votes! + * However, we just ignore that since those 1) shouldn't exist and + * 2) people must be checking IsVoteInProgress() beforehand anyway. + */ + g_next_vote = gpGlobals->curtime + fVoteDelay + (float)max_time; + } + for (unsigned int i=0; iDisplay(clients[i], max_time, this); @@ -177,6 +237,18 @@ int SortVoteItems(const void *item1, const void *item2) void VoteMenuHandler::EndVoting() { + /* Set when the next delay ends. We ignore cancellation because a menu + * was, at one point, displayed, which is all that counts. However, we + * do re-calculate the time just in case the menu had no time limit. + */ + float fVoteDelay = sm_vote_delay.GetFloat(); + if (fVoteDelay < 1.0) + { + g_next_vote = 0.0; + } else { + g_next_vote = gpGlobals->curtime + fVoteDelay; + } + if (m_bCancelled) { /* If we were cancelled, don't bother tabulating anything. diff --git a/core/MenuVoting.h b/core/MenuVoting.h index 6b0a1a8d..c0d44ccd 100644 --- a/core/MenuVoting.h +++ b/core/MenuVoting.h @@ -49,6 +49,7 @@ class VoteMenuHandler : public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); + void OnSourceModLevelChange(const char *mapName); public: //IClientListener void OnClientDisconnected(int client); public: //IMenuHandler @@ -70,6 +71,7 @@ public: void CancelVoting(); IBaseMenu *GetCurrentMenu(); bool IsCancelling(); + unsigned int GetRemainingVoteDelay(); private: void Reset(IMenuHandler *mh); void DecrementPlayerCount(); diff --git a/core/smn_menus.cpp b/core/smn_menus.cpp index 9e70a386..7ec21eff 100644 --- a/core/smn_menus.cpp +++ b/core/smn_menus.cpp @@ -39,6 +39,7 @@ #include "HandleSys.h" #include "PluginSys.h" #include "sm_stringutil.h" +#include "sourcemm_api.h" #if defined MENU_DEBUG #include "Logger.h" #endif @@ -1324,6 +1325,11 @@ static cell_t SetVoteResultCallback(IPluginContext *pContext, const cell_t *para return 1; } +static cell_t CheckVoteDelay(IPluginContext *pContext, const cell_t *params) +{ + return g_Menus.GetRemainingVoteDelay(); +} + REGISTER_NATIVES(menuNatives) { {"AddMenuItem", AddMenuItem}, @@ -1331,6 +1337,7 @@ REGISTER_NATIVES(menuNatives) {"CancelClientMenu", CancelClientMenu}, {"CancelMenu", CancelMenu}, {"CancelVote", CancelVote}, + {"CheckVoteDelay", CheckVoteDelay}, {"CreateMenu", CreateMenu}, {"CreateMenuEx", CreateMenuEx}, {"CreatePanel", CreatePanel}, diff --git a/plugins/include/menus.inc b/plugins/include/menus.inc index 53b464d0..bbfdd9d0 100644 --- a/plugins/include/menus.inc +++ b/plugins/include/menus.inc @@ -458,6 +458,15 @@ functag VoteHandler public(Handle:menu, */ native SetVoteResultCallback(Handle:menu, VoteHandler:callback); +/** + * Returns the number of seconds you should "wait" before displaying + * a publicly invocable menu. This number is the time remaining until + * (last_vote + sm_vote_delay). + * + * @return Number of seconds to wait, or 0 for none. + */ +native CheckVoteDelay(); + /** * Returns a style's global Handle. * diff --git a/public/IMenuManager.h b/public/IMenuManager.h index 99622d48..ce12fa0e 100644 --- a/public/IMenuManager.h +++ b/public/IMenuManager.h @@ -807,6 +807,14 @@ namespace SourceMod * @brief Cancels the vote in progress. This calls IBaseMenu::Cancel(). */ virtual void CancelVoting() =0; + + /** + * @brief Returns the remaining vote delay from the last menu. This delay is + * a suggestion for all public votes, and is not enforced. + * + * @return Number of seconds to wait. + */ + virtual unsigned int GetRemainingVoteDelay() =0; }; }