ddnet/src/game/client/components/voting.cpp

360 lines
9 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2010-05-29 07:25:38 +00:00
#include <engine/shared/config.h>
#include "voting.h"
#include <game/client/components/sounds.h>
2010-05-29 07:25:38 +00:00
#include <game/client/render.h>
#include <game/generated/protocol.h>
2010-05-29 07:25:38 +00:00
2021-07-12 09:29:59 +00:00
#include <game/client/gameclient.h>
void CVoting::ConCallvote(IConsole::IResult *pResult, void *pUserData)
2010-05-29 07:25:38 +00:00
{
CVoting *pSelf = (CVoting *)pUserData;
pSelf->Callvote(pResult->GetString(0), pResult->GetString(1), pResult->NumArguments() > 2 ? pResult->GetString(2) : "");
2010-05-29 07:25:38 +00:00
}
void CVoting::ConVote(IConsole::IResult *pResult, void *pUserData)
2010-05-29 07:25:38 +00:00
{
CVoting *pSelf = (CVoting *)pUserData;
if(str_comp_nocase(pResult->GetString(0), "yes") == 0)
pSelf->Vote(1);
else if(str_comp_nocase(pResult->GetString(0), "no") == 0)
pSelf->Vote(-1);
}
void CVoting::Callvote(const char *pType, const char *pValue, const char *pReason)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_CallVote Msg = {0};
Msg.m_pType = pType;
Msg.m_pValue = pValue;
Msg.m_pReason = pReason;
Client()->SendPackMsgActive(&Msg, MSGFLAG_VITAL);
2008-09-24 14:47:03 +00:00
}
void CVoting::CallvoteSpectate(int ClientID, const char *pReason, bool ForceVote)
2008-09-24 14:47:03 +00:00
{
if(ForceVote)
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "set_team %d -1", ClientID);
Client()->Rcon(aBuf);
}
else
{
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "%d", ClientID);
Callvote("spectate", aBuf, pReason);
}
}
2011-03-25 11:06:45 +00:00
void CVoting::CallvoteKick(int ClientID, const char *pReason, bool ForceVote)
2008-09-24 14:47:03 +00:00
{
2011-03-25 11:06:45 +00:00
if(ForceVote)
2010-05-29 07:25:38 +00:00
{
2011-03-25 11:06:45 +00:00
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "force_vote kick %d %s", ClientID, pReason);
Client()->Rcon(aBuf);
2010-05-29 07:25:38 +00:00
}
else
2011-03-25 11:06:45 +00:00
{
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "%d", ClientID);
2011-03-25 11:06:45 +00:00
Callvote("kick", aBuf, pReason);
}
2008-09-24 14:47:03 +00:00
}
2008-09-25 12:23:44 +00:00
void CVoting::CallvoteOption(int OptionID, const char *pReason, bool ForceVote)
{
2011-03-26 16:44:34 +00:00
CVoteOptionClient *pOption = m_pFirst;
while(pOption && OptionID >= 0)
2010-05-29 07:25:38 +00:00
{
if(OptionID == 0)
2010-05-29 07:25:38 +00:00
{
2011-03-25 11:06:45 +00:00
if(ForceVote)
{
char aBuf[128];
2022-07-09 16:14:56 +00:00
str_copy(aBuf, "force_vote option \"");
char *pDst = aBuf + str_length(aBuf);
str_escape(&pDst, pOption->m_aDescription, aBuf + sizeof(aBuf));
str_append(aBuf, "\" \"", sizeof(aBuf));
pDst = aBuf + str_length(aBuf);
str_escape(&pDst, pReason, aBuf + sizeof(aBuf));
str_append(aBuf, "\"", sizeof(aBuf));
2011-03-25 11:06:45 +00:00
Client()->Rcon(aBuf);
}
else
Callvote("option", pOption->m_aDescription, pReason);
2010-05-29 07:25:38 +00:00
break;
}
OptionID--;
2010-05-29 07:25:38 +00:00
pOption = pOption->m_pNext;
}
}
void CVoting::RemovevoteOption(int OptionID)
{
CVoteOptionClient *pOption = m_pFirst;
while(pOption && OptionID >= 0)
2008-11-08 12:50:46 +00:00
{
if(OptionID == 0)
2008-11-08 12:50:46 +00:00
{
char aBuf[128];
2022-07-09 16:14:56 +00:00
str_copy(aBuf, "remove_vote \"");
char *pDst = aBuf + str_length(aBuf);
str_escape(&pDst, pOption->m_aDescription, aBuf + sizeof(aBuf));
str_append(aBuf, "\"", sizeof(aBuf));
Client()->Rcon(aBuf);
2008-11-08 12:50:46 +00:00
break;
}
OptionID--;
2010-05-29 07:25:38 +00:00
pOption = pOption->m_pNext;
2008-11-08 12:50:46 +00:00
}
}
void CVoting::AddvoteOption(const char *pDescription, const char *pCommand)
{
char aBuf[128];
2022-07-09 16:14:56 +00:00
str_copy(aBuf, "add_vote \"");
char *pDst = aBuf + str_length(aBuf);
str_escape(&pDst, pDescription, aBuf + sizeof(aBuf));
str_append(aBuf, "\" \"", sizeof(aBuf));
pDst = aBuf + str_length(aBuf);
str_escape(&pDst, pCommand, aBuf + sizeof(aBuf));
str_append(aBuf, "\"", sizeof(aBuf));
Client()->Rcon(aBuf);
}
2010-05-29 07:25:38 +00:00
void CVoting::Vote(int v)
2008-09-25 12:23:44 +00:00
{
m_Voted = v;
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_Vote Msg = {v};
Client()->SendPackMsgActive(&Msg, MSGFLAG_VITAL);
2008-09-25 12:23:44 +00:00
}
2010-05-29 07:25:38 +00:00
CVoting::CVoting()
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
ClearOptions();
2015-07-09 00:08:14 +00:00
m_Closetime = 0;
m_aDescription[0] = 0;
m_aReason[0] = 0;
m_Yes = m_No = m_Pass = m_Total = 0;
m_Voted = 0;
2008-09-24 14:47:03 +00:00
}
void CVoting::AddOption(const char *pDescription)
{
CVoteOptionClient *pOption;
if(m_pRecycleFirst)
{
pOption = m_pRecycleFirst;
m_pRecycleFirst = m_pRecycleFirst->m_pNext;
if(m_pRecycleFirst)
m_pRecycleFirst->m_pPrev = 0;
else
m_pRecycleLast = 0;
}
else
pOption = (CVoteOptionClient *)m_Heap.Allocate(sizeof(CVoteOptionClient));
pOption->m_pNext = 0;
pOption->m_pPrev = m_pLast;
if(pOption->m_pPrev)
pOption->m_pPrev->m_pNext = pOption;
m_pLast = pOption;
if(!m_pFirst)
m_pFirst = pOption;
2022-07-09 16:14:56 +00:00
str_copy(pOption->m_aDescription, pDescription);
++m_NumVoteOptions;
}
2008-11-08 12:50:46 +00:00
2010-05-29 07:25:38 +00:00
void CVoting::ClearOptions()
2008-11-08 12:50:46 +00:00
{
2010-05-29 07:25:38 +00:00
m_Heap.Reset();
2011-03-26 16:44:34 +00:00
m_NumVoteOptions = 0;
2010-05-29 07:25:38 +00:00
m_pFirst = 0;
m_pLast = 0;
2011-03-25 10:49:35 +00:00
m_pRecycleFirst = 0;
m_pRecycleLast = 0;
2008-11-08 12:50:46 +00:00
}
2010-05-29 07:25:38 +00:00
void CVoting::OnReset()
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
m_Closetime = 0;
m_aDescription[0] = 0;
m_aReason[0] = 0;
2010-05-29 07:25:38 +00:00
m_Yes = m_No = m_Pass = m_Total = 0;
m_Voted = 0;
2008-09-24 14:47:03 +00:00
}
2010-05-29 07:25:38 +00:00
void CVoting::OnConsoleInit()
2008-09-24 14:47:03 +00:00
{
Console()->Register("callvote", "s['kick'|'spectate'|'option'] s[id|option text] ?r[reason]", CFGFLAG_CLIENT, ConCallvote, this, "Call vote");
Console()->Register("vote", "r['yes'|'no']", CFGFLAG_CLIENT, ConVote, this, "Vote yes/no");
2008-09-24 14:47:03 +00:00
}
2010-05-29 07:25:38 +00:00
void CVoting::OnMessage(int MsgType, void *pRawMsg)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
if(MsgType == NETMSGTYPE_SV_VOTESET)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_VoteSet *pMsg = (CNetMsg_Sv_VoteSet *)pRawMsg;
2020-12-18 11:58:01 +00:00
OnReset();
2010-05-29 07:25:38 +00:00
if(pMsg->m_Timeout)
2008-09-24 14:47:03 +00:00
{
2022-07-09 16:14:56 +00:00
str_copy(m_aDescription, pMsg->m_pDescription);
str_copy(m_aReason, pMsg->m_pReason);
m_Closetime = time() + time_freq() * pMsg->m_Timeout;
2020-12-18 11:58:01 +00:00
if(Client()->RconAuthed())
{
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "%s (%s)", m_aDescription, m_aReason);
Client()->Notify("DDNet Vote", aBuf);
2021-07-12 09:43:56 +00:00
m_pClient->m_Sounds.Play(CSounds::CHN_GUI, SOUND_CHAT_HIGHLIGHT, 0);
2020-12-18 11:58:01 +00:00
}
2008-09-24 14:47:03 +00:00
}
}
2010-05-29 07:25:38 +00:00
else if(MsgType == NETMSGTYPE_SV_VOTESTATUS)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_VoteStatus *pMsg = (CNetMsg_Sv_VoteStatus *)pRawMsg;
m_Yes = pMsg->m_Yes;
m_No = pMsg->m_No;
m_Pass = pMsg->m_Pass;
m_Total = pMsg->m_Total;
}
2010-05-29 07:25:38 +00:00
else if(MsgType == NETMSGTYPE_SV_VOTECLEAROPTIONS)
2008-11-08 12:50:46 +00:00
{
2010-05-29 07:25:38 +00:00
ClearOptions();
2008-11-08 12:50:46 +00:00
}
else if(MsgType == NETMSGTYPE_SV_VOTEOPTIONLISTADD)
2008-11-08 12:50:46 +00:00
{
CNetMsg_Sv_VoteOptionListAdd *pMsg = (CNetMsg_Sv_VoteOptionListAdd *)pRawMsg;
int NumOptions = pMsg->m_NumOptions;
for(int i = 0; i < NumOptions; ++i)
2011-03-25 10:49:35 +00:00
{
switch(i)
{
case 0: AddOption(pMsg->m_pDescription0); break;
case 1: AddOption(pMsg->m_pDescription1); break;
case 2: AddOption(pMsg->m_pDescription2); break;
case 3: AddOption(pMsg->m_pDescription3); break;
case 4: AddOption(pMsg->m_pDescription4); break;
case 5: AddOption(pMsg->m_pDescription5); break;
case 6: AddOption(pMsg->m_pDescription6); break;
case 7: AddOption(pMsg->m_pDescription7); break;
case 8: AddOption(pMsg->m_pDescription8); break;
case 9: AddOption(pMsg->m_pDescription9); break;
case 10: AddOption(pMsg->m_pDescription10); break;
case 11: AddOption(pMsg->m_pDescription11); break;
case 12: AddOption(pMsg->m_pDescription12); break;
case 13: AddOption(pMsg->m_pDescription13); break;
case 14: AddOption(pMsg->m_pDescription14);
}
2011-03-25 10:49:35 +00:00
}
}
else if(MsgType == NETMSGTYPE_SV_VOTEOPTIONADD)
{
CNetMsg_Sv_VoteOptionAdd *pMsg = (CNetMsg_Sv_VoteOptionAdd *)pRawMsg;
AddOption(pMsg->m_pDescription);
2008-11-08 12:50:46 +00:00
}
2011-03-25 10:49:35 +00:00
else if(MsgType == NETMSGTYPE_SV_VOTEOPTIONREMOVE)
{
CNetMsg_Sv_VoteOptionRemove *pMsg = (CNetMsg_Sv_VoteOptionRemove *)pRawMsg;
2011-03-26 16:44:34 +00:00
for(CVoteOptionClient *pOption = m_pFirst; pOption; pOption = pOption->m_pNext)
2011-03-25 10:49:35 +00:00
{
if(str_comp(pOption->m_aDescription, pMsg->m_pDescription) == 0)
{
// remove it from the list
if(m_pFirst == pOption)
m_pFirst = m_pFirst->m_pNext;
if(m_pLast == pOption)
m_pLast = m_pLast->m_pPrev;
if(pOption->m_pPrev)
pOption->m_pPrev->m_pNext = pOption->m_pNext;
if(pOption->m_pNext)
pOption->m_pNext->m_pPrev = pOption->m_pPrev;
2011-03-26 16:44:34 +00:00
--m_NumVoteOptions;
2008-11-08 12:50:46 +00:00
2011-03-25 10:49:35 +00:00
// add it to recycle list
pOption->m_pNext = 0;
pOption->m_pPrev = m_pRecycleLast;
if(pOption->m_pPrev)
pOption->m_pPrev->m_pNext = pOption;
m_pRecycleLast = pOption;
if(!m_pRecycleFirst)
m_pRecycleLast = pOption;
break;
}
}
2008-11-08 12:50:46 +00:00
}
2008-09-24 14:47:03 +00:00
}
2010-05-29 07:25:38 +00:00
void CVoting::OnRender()
2008-09-24 14:47:03 +00:00
{
}
2010-05-29 07:25:38 +00:00
void CVoting::RenderBars(CUIRect Bars, bool Text)
{
Bars.Draw(ColorRGBA(0.8f, 0.8f, 0.8f, 0.5f), IGraphics::CORNER_ALL, Bars.h / 3);
2010-05-29 07:25:38 +00:00
CUIRect Splitter = Bars;
Splitter.x = Splitter.x + Splitter.w / 2;
Splitter.w = Splitter.h / 2.0f;
Splitter.x -= Splitter.w / 2;
Splitter.Draw(ColorRGBA(0.4f, 0.4f, 0.4f, 0.5f), IGraphics::CORNER_ALL, Splitter.h / 4);
2010-05-29 07:25:38 +00:00
if(m_Total)
{
2010-05-29 07:25:38 +00:00
CUIRect PassArea = Bars;
if(m_Yes)
{
2010-05-29 07:25:38 +00:00
CUIRect YesArea = Bars;
YesArea.w *= m_Yes / (float)m_Total;
YesArea.Draw(ColorRGBA(0.2f, 0.9f, 0.2f, 0.85f), IGraphics::CORNER_ALL, Bars.h / 3);
2010-05-29 07:25:38 +00:00
if(Text)
{
2021-09-13 09:47:47 +00:00
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%d", m_Yes);
UI()->DoLabel(&YesArea, aBuf, Bars.h * 0.75f, TEXTALIGN_CENTER);
}
2010-05-29 07:25:38 +00:00
PassArea.x += YesArea.w;
PassArea.w -= YesArea.w;
}
2010-05-29 07:25:38 +00:00
if(m_No)
{
2010-05-29 07:25:38 +00:00
CUIRect NoArea = Bars;
NoArea.w *= m_No / (float)m_Total;
NoArea.x = (Bars.x + Bars.w) - NoArea.w;
NoArea.Draw(ColorRGBA(0.9f, 0.2f, 0.2f, 0.85f), IGraphics::CORNER_ALL, Bars.h / 3);
2010-05-29 07:25:38 +00:00
if(Text)
{
2021-09-13 09:47:47 +00:00
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%d", m_No);
UI()->DoLabel(&NoArea, aBuf, Bars.h * 0.75f, TEXTALIGN_CENTER);
}
2010-05-29 07:25:38 +00:00
PassArea.w -= NoArea.w;
}
2010-05-29 07:25:38 +00:00
if(Text && m_Pass)
{
2021-09-13 09:47:47 +00:00
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%d", m_Pass);
UI()->DoLabel(&PassArea, aBuf, Bars.h * 0.75f, TEXTALIGN_CENTER);
}
}
}