1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player-driven Voting System for Multiplayer Source games (currently implemented for TF2)
//
// $NoKeywords: $
//=============================================================================//
#ifndef VOTE_CONTROLLER_H
#define VOTE_CONTROLLER_H
#ifdef _WIN32
#pragma once
#endif
#include "shareddefs.h"
#define MAX_COMMAND_LENGTH 64
#define MAX_CREATE_ERROR_STRING 96
class CBaseIssue // Base class concept for vote issues (i.e. Kick Player). Created per level-load and destroyed by CVoteController's dtor.
{
public:
CBaseIssue( const char *typeString );
virtual ~CBaseIssue();
const char *GetTypeString( void ); // Connection between console command and specific type of issue
virtual const char *GetTypeStringLocalized( void ) { return ""; } // When empty, the client uses the classname string and prepends "#Vote_"
virtual const char *GetDetailsString( void );
virtual void SetIssueDetails( const char *pszDetails ); // We need to know the details part of the con command for later
virtual void OnVoteFailed( int iEntityHoldingVote ); // The moment the vote fails, also has some time for feedback before the window goes away
virtual void OnVoteStarted( void ) {} // Called as soon as the vote starts
virtual bool IsEnabled( void ) { return false; } // Query the issue to see if it's enabled
virtual bool CanTeamCallVote( int iTeam ) const; // Can someone on the given team call this vote?
virtual bool CanCallVote( int nEntIndex, const char *pszDetails, vote_create_failed_t &nFailCode, int &nTime ); // Can this guy hold a vote on this issue?
virtual bool IsTeamRestrictedVote( void ); // Restrict access and visibility of this vote to a specific team?
virtual const char *GetDisplayString( void ) = 0; // The string that will be passed to the client for display
virtual void ExecuteCommand( void ) = 0; // Where the magic happens. Do your thing.
virtual void ListIssueDetails( CBasePlayer *pForWhom ) = 0; // Someone would like to know all your valid details
virtual const char *GetVotePassedString( void ); // Get the string an issue would like to display when it passes.
virtual int CountPotentialVoters( void );
virtual int GetNumberVoteOptions( void ); // How many choices this vote will have. i.e. Returns 2 on a Yes/No issue (the default).
virtual bool IsYesNoVote( void );
virtual void SetYesNoVoteCount( int iNumYesVotes, int iNumNoVotes, int iNumPotentialVotes );
virtual bool GetVoteOptions( CUtlVector <const char*> &vecNames ); // We use this to generate options for voting
virtual bool BRecordVoteFailureEventForEntity( int iVoteCallingEntityIndex ) const { return iVoteCallingEntityIndex != DEDICATED_SERVER; }
void SetIssueCooldownDuration( float flDuration ) { m_flNextCallTime = gpGlobals->curtime + flDuration; } // The issue can not be raised again for this period of time (in seconds)
virtual float GetQuorumRatio( void ); // Each issue can decide the required ratio of voted-vs-abstained
CHandle< CBasePlayer > m_hPlayerTarget; // If the target of the issue is a player, we should store them here
protected:
static void ListStandardNoArgCommand( CBasePlayer *forWhom, const char *issueString ); // List a Yes vote command
struct FailedVote
{
char szFailedVoteParameter[MAX_VOTE_DETAILS_LENGTH];
float flLockoutTime;
};
CUtlVector< FailedVote* > m_FailedVotes;
char m_szTypeString[MAX_COMMAND_LENGTH];
char m_szDetailsString[MAX_VOTE_DETAILS_LENGTH];
int m_iNumYesVotes;
int m_iNumNoVotes;
int m_iNumPotentialVotes;
float m_flNextCallTime;
};
class CVoteController : public CBaseEntity
{
DECLARE_CLASS( CVoteController, CBaseEntity );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
virtual ~CVoteController();
enum TryCastVoteResult
{
CAST_OK,
CAST_FAIL_SERVER_DISABLE,
CAST_FAIL_NO_ACTIVE_ISSUE,
CAST_FAIL_TEAM_RESTRICTED,
CAST_FAIL_NO_CHANGES,
CAST_FAIL_DUPLICATE,
CAST_FAIL_VOTE_CLOSED,
CAST_FAIL_SYSTEM_ERROR
};
virtual void Spawn( void );
virtual int UpdateTransmitState( void );
virtual bool IsVoteSystemEnabled( void );
bool SetupVote( int iEntIndex ); // This creates a list of issues for the UI
bool CreateVote( int iEntIndex, const char *pszTypeString, const char *pszDetailString ); // This is what the UI passes in
TryCastVoteResult TryCastVote( int iEntIndex, const char *pszVoteString );
void RegisterIssue( CBaseIssue *pNewIssue );
void ListIssues( CBasePlayer *pForWhom );
bool IsValidVoter( CBasePlayer *pWhom );
bool CanTeamCastVote( int iTeam ) const;
void SendVoteCreationFailedMessage( vote_create_failed_t nReason, CBasePlayer *pVoteCaller, int nTime = -1 );
void SendVoteFailedToPassMessage( vote_create_failed_t nReason );
void VoteChoice_Increment( int nVoteChoice );
void VoteChoice_Decrement( int nVoteChoice );
int GetVoteIssueIndexWithHighestCount( void );
void TrackVoteCaller( CBasePlayer *pPlayer );
bool CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown, vote_create_failed_t &nErrorCode );
bool IsVoteActive( void ) { return m_iActiveIssueIndex != INVALID_ISSUE; }
int GetNumVotesCast( void );
void AddPlayerToKickWatchList( CSteamID steamID, float flDuration ); // Band-aid until we figure out how player's avoid kick votes
void AddPlayerToNameLockedList( CSteamID steamID, float flDuration, int nUserID );
bool IsPlayerBeingKicked( CBasePlayer *pPlayer );
protected:
void ResetData( void );
void VoteControllerThink( void );
void CheckForEarlyVoteClose( void ); // If everyone has voted (and changing votes is not allowed) then end early
CNetworkVar( int, m_iActiveIssueIndex ); // Type of thing being voted on
CNetworkVar( int, m_iOnlyTeamToVote ); // If an Ally restricted vote, the team number that is allowed to vote
CNetworkArray( int, m_nVoteOptionCount, MAX_VOTE_OPTIONS ); // Vote options counter
CNetworkVar( int, m_nPotentialVotes ); // How many votes could come in, so we can close ballot early
CNetworkVar( bool, m_bIsYesNoVote ); // Is the current issue Yes/No?
CountdownTimer m_acceptingVotesTimer; // How long from vote start until we count the ballots
CountdownTimer m_executeCommandTimer; // How long after end of vote time until we execute a passed vote
CountdownTimer m_resetVoteTimer; // when the current vote will end
int m_nVotesCast[MAX_PLAYERS + 1]; // arrays are zero-based and player indices are one-based
int m_iEntityHoldingVote;
CUtlVector <CBaseIssue *> m_potentialIssues;
CUtlVector <const char *> m_VoteOptions;
CUtlMap <uint64, float> m_VoteCallers; // History of SteamIDs that have tried to call votes.
friend class CVoteControllerSystem;
};
extern CVoteController *g_voteController;
#endif // VOTE_CONTROLLER_H
|