From acba87ae46df76ae2f8c6fb2fec05a537fed19ac Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 17 Sep 2009 18:54:40 +1200 Subject: [PATCH] Added voting output (bug 1997, r=dvander) --- core/HalfLife2.cpp | 20 ++++ core/HalfLife2.h | 1 + core/MenuVoting.cpp | 208 +++++++++++++++++++++++++++++++-- core/MenuVoting.h | 13 ++- core/msvc9/sourcemod_mm.vcproj | 2 + translations/core.phrases.txt | 18 +++ 6 files changed, 253 insertions(+), 9 deletions(-) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index a4e327c6e..e7432118e 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -437,6 +437,26 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg) return true; } +bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg) +{ + bf_write *pBitBuf = NULL; + + if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) + { + return false; + } + + const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte"); + if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0) + { + pBitBuf->WriteByte(1); + } + pBitBuf->WriteString(msg); + g_UserMsgs.EndMessage(); + + return true; +} + bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show) { bf_write *pBitBuf = NULL; diff --git a/core/HalfLife2.h b/core/HalfLife2.h index adf396eef..f42a40eec 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -117,6 +117,7 @@ public: //IGameHelpers void SetEdictStateChanged(edict_t *pEdict, unsigned short offset); bool TextMsg(int client, int dest, const char *msg); bool HintTextMsg(int client, const char *msg); + bool HintTextMsg(cell_t *players, int count, const char *msg); bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show); bool IsLANServer(); bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL); diff --git a/core/MenuVoting.cpp b/core/MenuVoting.cpp index 534340707..a8641b5e7 100644 --- a/core/MenuVoting.cpp +++ b/core/MenuVoting.cpp @@ -34,9 +34,55 @@ #include "MenuVoting.h" #include "PlayerManager.h" #include "sourcemm_api.h" +#include +#include +#include +#include +#include +#include float g_next_vote = 0.0f; +#define VOTE_NOT_VOTING -2 +#define VOTE_PENDING -1 + +ConVar sm_vote_hintbox("sm_vote_progress_hintbox", + "0", + 0, + "Show current vote progress in a hint box", + true, + 0.0, + true, + 1.0); + +ConVar sm_vote_chat("sm_vote_progress_chat", + "0", + 0, + "Show current vote progress as chat messages", + true, + 0.0, + true, + 1.0); + +ConVar sm_vote_console("sm_vote_progress_console", + "0", + 0, + "Show current vote progress as console messages", + true, + 0.0, + true, + 1.0); + +ConVar sm_vote_client_console("sm_vote_progress_client_console", + "0", + 0, + "Show current vote progress as console messages to clients", + true, + 0.0, + true, + 1.0); + + #if SOURCE_ENGINE >= SE_ORANGEBOX void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue); #else @@ -117,7 +163,7 @@ void VoteMenuHandler::OnClientDisconnected(int client) * newly connected client is not allowed to vote. */ int item; - if ((item = m_ClientVotes[client]) >= -1) + if ((item = m_ClientVotes[client]) >= VOTE_PENDING) { if (item >= 0) { @@ -125,7 +171,7 @@ void VoteMenuHandler::OnClientDisconnected(int client) assert(m_Votes[item] > 0); m_Votes[item]--; } - m_ClientVotes[client] = -2; + m_ClientVotes[client] = VOTE_NOT_VOTING; } } @@ -189,13 +235,13 @@ bool VoteMenuHandler::IsClientInVotePool(int client) return false; } - return (m_ClientVotes[client] > -2); + return (m_ClientVotes[client] > VOTE_NOT_VOTING); } bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem) { if (!IsClientInVotePool(client) - || m_ClientVotes[client] == -1) + || m_ClientVotes[client] == VOTE_PENDING) { return false; } @@ -223,7 +269,9 @@ bool VoteMenuHandler::RedrawToClient(int client, bool revotes) assert((unsigned)m_ClientVotes[client] < m_Items); assert(m_Votes[m_ClientVotes[client]] > 0); m_Votes[m_ClientVotes[client]]--; - m_ClientVotes[client] = -1; + m_ClientVotes[client] = VOTE_PENDING; + m_Revoting[client] = true; + m_NumVotes--; } if (m_nMenuTime == MENU_TIME_FOREVER) @@ -259,7 +307,8 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu, /* Mark all clients as not voting */ for (int i=1; i<=gpGlobals->maxClients; i++) { - m_ClientVotes[i] = -2; + m_ClientVotes[i] = VOTE_NOT_VOTING; + m_Revoting[i] = false; } m_Items = menu->GetItemCount(); @@ -303,6 +352,8 @@ void VoteMenuHandler::StartVoting() m_pHandler->OnMenuVoteStart(m_pCurMenu); + m_displayTimer = g_Timers.CreateTimer(this, 1.0, NULL, TIMER_FLAG_REPEAT|TIMER_FLAG_NO_MAPCHANGE); + /* By now we know how many clients were set. * If there are none, we should end IMMEDIATELY. */ @@ -310,6 +361,8 @@ void VoteMenuHandler::StartVoting() { EndVoting(); } + + m_TotalClients = m_Clients; } void VoteMenuHandler::DecrementPlayerCount() @@ -346,6 +399,11 @@ void VoteMenuHandler::EndVoting() g_next_vote = gpGlobals->curtime + fVoteDelay; } + if (m_displayTimer) + { + g_Timers.KillTimer(m_displayTimer); + } + if (m_bCancelled) { /* If we were cancelled, don't bother tabulating anything. @@ -392,7 +450,7 @@ void VoteMenuHandler::EndVoting() /* Build the client list */ for (int i=1; i<=gpGlobals->maxClients; i++) { - if (m_ClientVotes[i] >= -1) + if (m_ClientVotes[i] >= VOTE_PENDING) { client_vote[vote.num_clients].client = i; client_vote[vote.num_clients].item = m_ClientVotes[i]; @@ -436,7 +494,7 @@ void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display) { - m_ClientVotes[client] = -1; + m_ClientVotes[client] = VOTE_PENDING; m_pHandler->OnMenuDisplay(menu, client, display); } @@ -458,6 +516,55 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite m_ClientVotes[client] = item; m_Votes[item]++; m_NumVotes++; + + if (sm_vote_chat.GetBool() || sm_vote_console.GetBool()) + { + static char buffer[1024]; + ItemDrawInfo dr; + menu->GetItemInfo(item, &dr); + + if (sm_vote_console.GetBool()) + { + int target = SOURCEMOD_SERVER_LANGUAGE; + CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For", &target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display); + Engine_LogPrintWrapper(buffer); + } + + if (sm_vote_chat.GetBool() || sm_vote_client_console.GetBool()) + { + int maxclients = g_Players.GetMaxClients(); + for (int i=1; i<=maxclients; i++) + { + CPlayer *pPlayer = g_Players.GetPlayerByIndex(i); + assert(pPlayer); + + if (pPlayer->IsInGame()) + { + if (m_Revoting[client]) + { + CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote", &i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display); + } + else + { + CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For", &i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display); + } + + if (sm_vote_chat.GetBool()) + { + g_HL2.TextMsg(i, HUD_PRINTTALK, buffer); + } + + if (sm_vote_client_console.GetBool()) + { + engine->ClientPrintf(pPlayer->GetEdict(), buffer); + } + } + } + } + } + + BuildVoteLeaders(); + DrawHintProgress(); } m_pHandler->OnMenuSelect(menu, client, item); @@ -480,6 +587,9 @@ void VoteMenuHandler::InternalReset() m_NumVotes = 0; m_bCancelled = false; m_pHandler = NULL; + m_leaderList[0] = '\0'; + m_displayTimer = NULL; + m_TotalClients = 0; } void VoteMenuHandler::CancelVoting() @@ -502,3 +612,85 @@ bool VoteMenuHandler::IsCancelling() return m_bCancelled; } +void VoteMenuHandler::DrawHintProgress() +{ + if (!sm_vote_hintbox.GetBool()) + { + return; + } + + static char buffer[1024]; + + float timeRemaining = (m_fStartTime + m_nMenuTime) - gpGlobals->curtime; + if (timeRemaining < 0) + { + timeRemaining = 0.0; + } + + int iTimeRemaining = RoundFloatToInt(timeRemaining); + + int maxclients = g_Players.GetMaxClients(); + for (int i=1; i<=maxclients; i++) + { + if (g_Players.GetPlayerByIndex(i)->IsInGame()) + { + CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count", &i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList); + g_HL2.HintTextMsg(i, buffer); + } + } +} + +void VoteMenuHandler::BuildVoteLeaders() +{ + if (m_NumVotes == 0 || !sm_vote_hintbox.GetBool()) + { + return; + } + + menu_vote_result_t vote; + menu_vote_result_t::menu_item_vote_t item_vote[256]; + + memset(&vote, 0, sizeof(vote)); + + /* Build the item list */ + for (unsigned int i=0; i 0) + { + item_vote[vote.num_items].count = m_Votes[i]; + item_vote[vote.num_items].item = i; + vote.num_votes += m_Votes[i]; + vote.num_items++; + } + } + vote.item_list = item_vote; + assert(vote.num_votes); + + /* Sort the item list descending */ + qsort(item_vote, + vote.num_items, + sizeof(menu_vote_result_t::menu_item_vote_t), + SortVoteItems); + + /* Take the top 3 (if applicable) and draw them */ + int len = 0; + for (unsigned int i=0; iGetItemInfo(curItem, &dr); + len += g_SourceMod.Format(m_leaderList + len, sizeof(m_leaderList) - len, "\n%i. %s: (%i)", i+1, dr.display, vote.item_list[i].count); + } +} + +SourceMod::ResultType VoteMenuHandler::OnTimer(ITimer *pTimer, void *pData) +{ + DrawHintProgress(); + + return Pl_Continue; +} + +void VoteMenuHandler::OnTimerEnd(ITimer *pTimer, void *pData) +{ + m_displayTimer = NULL; +} diff --git a/core/MenuVoting.h b/core/MenuVoting.h index cef98280f..7660b2943 100644 --- a/core/MenuVoting.h +++ b/core/MenuVoting.h @@ -36,6 +36,7 @@ #include #include #include "sm_globals.h" +#include using namespace SourceHook; using namespace SourceMod; @@ -43,7 +44,8 @@ using namespace SourceMod; class VoteMenuHandler : public IMenuHandler, public SMGlobalClass, - public IClientListener + public IClientListener, + public ITimedEvent { public: //SMGlobalClass void OnSourceModAllInitialized(); @@ -61,6 +63,9 @@ public: //IMenuHandler void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason); void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style); unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr); +public: //ITimedEvent + ResultType OnTimer(ITimer *pTimer, void *pData); + void OnTimerEnd(ITimer *pTimer, void *pData); public: bool StartVote(IBaseMenu *menu, unsigned int num_clients, @@ -85,9 +90,12 @@ private: unsigned int time, unsigned int flags); void StartVoting(); + void DrawHintProgress(); + void BuildVoteLeaders(); private: IMenuHandler *m_pHandler; unsigned int m_Clients; + unsigned int m_TotalClients; unsigned int m_Items; CVector m_Votes; IBaseMenu *m_pCurMenu; @@ -99,6 +107,9 @@ private: float m_fStartTime; unsigned int m_nMenuTime; int m_ClientVotes[256+1]; + bool m_Revoting[256+1]; + char m_leaderList[1024]; + ITimer *m_displayTimer; }; #endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_ diff --git a/core/msvc9/sourcemod_mm.vcproj b/core/msvc9/sourcemod_mm.vcproj index e3c5d2dd9..fb6feb9e7 100644 --- a/core/msvc9/sourcemod_mm.vcproj +++ b/core/msvc9/sourcemod_mm.vcproj @@ -1448,6 +1448,7 @@ EnableEnhancedInstructionSet="0" RuntimeTypeInfo="false" UsePrecompiledHeader="0" + AssemblerOutput="0" WarningLevel="3" Detect64BitPortabilityProblems="false" DebugInformationFormat="3" @@ -1458,6 +1459,7 @@