Custom callvotes

I have a shuffle_teams function for CTF that I wrote. How would I go about initiating a custom callvote in the server code?

I already have the code written to check if the player typed /callvote shuffle_teams — but no way of actually activating the callvote.

Alright. So I’ve been searching through all of the code trying to figure out how I can do this.

This is what I’ve come up with so far:

static void SV_Test(void) {
char buffer[15];
int value = svs.time;
snprintf(buffer, 15, “%d”, value);
SV_SetConfigstring( CS_VOTE_STRING, “shuffle_teams” );
SV_SetConfigstring( CS_VOTE_TIME, buffer );
SV_SetConfigstring( CS_VOTE_NO, “0” );
SV_SetConfigstring( CS_VOTE_YES, “1” );
}

This will actually have a vote come up on the screen with the 30 second countdown and the shuffle_teams string. However, it stays on the screen indefinitely and when a player attempts to vote it says “no vote in progress.”

Any ideas on why it’s not recognizing it?

You either have to recreate all of the game vote code in the server because the config strings only affect CGame or override an existing vote. Like make the server run callvote map_restart shuffle_teams, then set the custom CS_VOTE_STRING config string, then intercept the map_restart shuffle_teams command in Cmd_ExecuteString() to do your shuffle_teams command.

You should use sv.time (level time) instead of svs.time (total server uptime). Though, if you let game handle the vote logic you don’t need to set CS_VOTE_TIME/YES/NO.

1 Like

zturtleman, perfect! I’ll do it via overriding an existing vote. Thank you so much!

I followed your method exactly and got it working fully. Thank you, zturtleman.

For anyone else trying to do this in the future, hopefully this will help you:

/server/server.h

extern	cvar_t	*skipVote;

/qcommon/cmd.c

void Cbuf_ExecuteText
	// Custom callvote
	int skipVote = (int)Cvar_Get("sv_skipVote", "0", 0)->integer;
	if( skipVote == 1) {
		Cvar_Set("sv_skipVote", "0");
		return;
	}

/server/sv_game.c

void SV_GameSendServerCommand( int clientNum, const char *text ) {
	if ( clientNum == -1 ) {
		if( strcmp(first,"print") == 0 ) {
			if( strcmp(second,"\"^2Vote") == 0 && strcmp(third,"FAILED!") == 0 ) {
				SV_SendServerCommand(NULL, "chat \"^2Vote FAILED!\n\"");
			}

			// print "^5Vote passed!\n"
			else if( strcmp(second,"\"^5Vote") == 0 && strcmp(last,"passed!\"") == 0 ) {
				SV_SendServerCommand(NULL, "chat \"^5Vote passed!\n\"");
			}

intptr_t SV_GameSystemCalls( intptr_t *args ) {
	case G_PRINT:
		Com_Printf( "%s", (const char*)VMA(1) );
		SV_ParsePrint( (const char*)VMA(1) );

void SV_ParsePrint( const char *Msg ) {
	// Vote Passed: map_restart shuffle_teams
	  if( strcmp(first,"Vote_Passed") == 0 ){
	 	
	 	if( strcmp(last,"shuffle_teams") == 0 ) {
	 			// Custom callvote function
	 			Cvar_Set("sv_skipVote", "1");
	 	}

/server/sv_client.c

static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) {
if( strcmp(first,"callvote") == 0 ){
		// Disable spectators from callvoting
		if( ps->persistant[PERS_TEAM] != 0 ){
			if( intermission[0] == '1' ){
				SV_SendServerCommand( cl, "print \"^3You're not allowed to callvote during intermission.\n\"" );
				proceed = 0;
			} else {
				if( strncmp(last,"callvote",8) == 0 ) {
					proceed = 0;
					SV_SendServerCommand( cl, "print \"\n^7Valid ^3callvote ^7commands are:\n^3----------------------------\n   ^5map\n   ^5map_restart\n   ^5nextmap\n   ^5promode\n   ^5shuffle_teams\n\n\"" );
					SV_SendServerCommand( cl, "print \"^7Usage: ^3/callvote <command> <params>\n^7For help type: ^3/callvote <command>\n\n\"" );
				} else if( strncmp(first,"callvote",8) == 0 && strncmp(last,"callvote",8) != 0 ) {
					if( strcmp(second,"map") != 0 && strcmp(second,"map_restart") != 0 && strcmp(second,"nextmap") != 0 && strcmp(second,"promode") != 0 && strcmp(second,"shuffle_teams") != 0 ){
						proceed = 0;
					}
					else if(strcmp(second,"shuffle_teams")==0) {
						int clientID = cl - svs.clients;
						Cbuf_ExecuteText( EXEC_NOW, va( "spoof %i callvote map_restart shuffle_teams\n", clientID ) );
						SV_SetConfigstring( CS_VOTE_STRING, "shuffle_teams" );
						proceed = 0;
					}
				}
			}
		}
1 Like