From 1c6463253885c31ab09c4f1bfeb537646505f273 Mon Sep 17 00:00:00 2001
From: IronClawTrem <louie.nutman@gmail.com>
Date: Tue, 28 Apr 2020 21:13:54 +0100
Subject: Discard players' votes when they leave.

---
 src/game/bg_public.h |  2 --
 src/game/g_active.c  |  3 +--
 src/game/g_client.c  | 19 +++++++++++++++-
 src/game/g_cmds.c    | 61 +++++++++++++++++++++++++++++++---------------------
 src/game/g_local.h   |  2 ++
 5 files changed, 58 insertions(+), 29 deletions(-)

diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 69967a1..4fb63bf 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -292,8 +292,6 @@ typedef enum
 #define EF_MOVER_STOP       0x00001000    // will push otherwise
 #define EF_TALK             0x00002000    // draw a talk balloon
 #define EF_CONNECTION       0x00004000    // draw a connection trouble sprite
-#define EF_VOTED            0x00008000    // already cast a vote
-#define EF_TEAMVOTED        0x00010000    // already cast a vote
 #define EF_BLOBLOCKED       0x00020000    // TA: caught by a trapper
 #define EF_REAL_LIGHT       0x00040000    // TA: light sprites according to ambient light
 #define EF_DBUILDER         0x00080000    // designated builder protection
diff --git a/src/game/g_active.c b/src/game/g_active.c
index ac0717e..d184750 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -2008,8 +2008,7 @@ void SpectatorClientEndFrame( gentity_t *ent )
  
     if( cl -> sess.spectatorState != SPECTATOR_FOLLOW ) 
     {
-          flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) |
-            ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );
+          flags = cl->ps.eFlags | ent->client->ps.eFlags;
           score = ent->client->ps.persistant[ PERS_SCORE ];
           ping = ent->client->ps.ping;
           ent->client->ps = cl->ps;
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 871bacb..f4b1611 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1825,7 +1825,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
   client->pers.teamState.state = TEAM_ACTIVE;
 
   // toggle the teleport bit so the client knows to not lerp
-  flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED );
+  flags = ent->client->ps.eFlags & EF_TELEPORT_BIT;
   flags ^= EF_TELEPORT_BIT;
   G_UnlaggedClear( ent );
 
@@ -2090,6 +2090,23 @@ void ClientDisconnect( int clientNum )
   if( !ent->client )
     return;
 
+  // discard this player's vote
+  if( level.voteTime && level.votedHow[ clientNum ] )
+  {
+     if( level.votedHow[ clientNum ] > 0 )
+     {
+       level.voteYes--;
+       trap_SetConfigstring( CS_VOTE_YES, va( "%i", level.voteYes ) );
+     }
+     else
+     {
+       level.voteNo--;
+       trap_SetConfigstring( CS_VOTE_NO, va( "%i", level.voteNo ) );
+     }
+
+     level.votedHow[ clientNum ] = 0;
+  }
+
   // look through the bhist and readjust it if the referenced ent has left
   for( ptr = level.buildHistory; ptr; ptr = ptr->next )
   {
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 4855ed1..3f38305 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -604,7 +604,9 @@ void G_LeaveTeam( gentity_t *self )
 {
   pTeam_t   team = self->client->pers.teamSelection;
   gentity_t *ent;
-  int       i;
+  int       i, clientNum;
+
+  clientNum = self->client->ps.clientNum;
 
   if( team == PTE_ALIENS )
     G_RemoveFromSpawnQueue( &level.alienSpawnQueue, self->client->ps.clientNum );
@@ -645,6 +647,24 @@ void G_LeaveTeam( gentity_t *self )
         ent->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
     }
   }
+
+  if( level.teamVoteTime[ team ] && level.teamVotedHow[ team ][ clientNum ] )
+  {
+     int cs_offset = (team == PTE_ALIENS ? 1 : 0);
+
+     if( level.teamVotedHow[ team ][ clientNum ] > 0 )
+     {
+       level.teamVoteYes[ team ]--;
+       trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va( "%i", level.teamVoteYes[ team ] ) );
+     }
+     else
+     {
+       level.teamVoteNo[ team ]--;
+       trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va( "%i", level.teamVoteNo[ team ] ) );
+     }
+
+     level.teamVotedHow[ team ][ clientNum ] = 0;
+  }
 }
 
 /*
@@ -2086,8 +2106,7 @@ void Cmd_CallVote_f( gentity_t *ent )
   level.voteTime = level.time;
   level.voteNo = 0;
 
-  for( i = 0 ; i < level.maxclients ; i++ )
-    level.clients[i].ps.eFlags &= ~EF_VOTED;
+  memset( level.votedHow, 0, sizeof( level.votedHow ) );
 
   if( !Q_stricmp( arg1, "poll" ) )
   {
@@ -2095,8 +2114,8 @@ void Cmd_CallVote_f( gentity_t *ent )
   }
   else
   {
-   level.voteYes = 1;
-   ent->client->ps.eFlags |= EF_VOTED;
+    level.votedHow[ ent - g_entities ] = 1;
+    level.voteYes = 1;
   }
 
   trap_SetConfigstring( CS_VOTE_TIME, va( "%i", level.voteTime ) );
@@ -2137,38 +2156,36 @@ void Cmd_Vote_f( gentity_t *ent )
       if( ent->client->pers.teamSelection == PTE_ALIENS )
         cs_offset = 1;
     
-      if( level.teamVoteTime[ cs_offset ] )
+      if( level.teamVoteTime[ cs_offset ] &&
+          !level.teamVotedHow[ cs_offset ][ g_entities - ent ] )
       {
-         if( !(ent->client->ps.eFlags & EF_TEAMVOTED ) )
-        {
-          Cmd_TeamVote_f(ent); 
-          return;
-        }
+        Cmd_TeamVote_f(ent); 
+        return;
       }
     }
     trap_SendServerCommand( ent-g_entities, "print \"No vote in progress\n\"" );
     return;
   }
 
-  if( ent->client->ps.eFlags & EF_VOTED )
+  if( level.votedHow[ ent - g_entities ] )
   {
     trap_SendServerCommand( ent-g_entities, "print \"Vote already cast\n\"" );
     return;
   }
 
-  ent->client->ps.eFlags |= EF_VOTED;
-
   trap_Argv( 1, msg, sizeof( msg ) );
 
   if( msg[ 0 ] == 'y' || msg[ 1 ] == 'Y' || msg[ 1 ] == '1' )
   {
     level.voteYes++;
+	level.votedHow[ ent - g_entities ] = 1;
     trap_SetConfigstring( CS_VOTE_YES, va( "%i", level.voteYes ) );
     trap_SendServerCommand( ent-g_entities, "print \"^3/vote: ^7vote cast: ^ZYes\n\"" );
   }
   else
   {
     level.voteNo++;
+	level.votedHow[ ent - g_entities ] = -1;
     trap_SetConfigstring( CS_VOTE_NO, va( "%i", level.voteNo ) );
     trap_SendServerCommand( ent-g_entities, "print \"^3/vote: ^7vote cast: ^ANo\n\"" );
   }
@@ -2560,11 +2577,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
   level.teamVoteTime[ cs_offset ] = level.time;
   level.teamVoteNo[ cs_offset ] = 0;
 
-  for( i = 0 ; i < level.maxclients ; i++ )
-  {
-    if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team )
-      level.clients[ i ].ps.eFlags &= ~EF_TEAMVOTED;
-  }
+  memset( level.teamVotedHow[ cs_offset ], 0, sizeof( level.teamVotedHow[ 0 ] ));
 
   if( !Q_stricmp( arg1, "poll" ) )
   {
@@ -2572,8 +2585,8 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
   }
   else
   {
-   level.teamVoteYes[ cs_offset ] = 1;
-   ent->client->ps.eFlags |= EF_TEAMVOTED;
+    level.teamVotedHow[ cs_offset ][ ent - g_entities ] = 1;
+    level.teamVoteYes[ cs_offset ] = 1;
   }
 
   trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va( "%i", level.teamVoteTime[ cs_offset ] ) );
@@ -2602,24 +2615,24 @@ void Cmd_TeamVote_f( gentity_t *ent )
     return;
   }
 
-  if( ent->client->ps.eFlags & EF_TEAMVOTED )
+  if( level.teamVotedHow[ cs_offset ][ ent - g_entities ] )
   {
     trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast\n\"" );
     return;
   }
 
-  ent->client->ps.eFlags |= EF_TEAMVOTED;
-
   trap_Argv( 1, msg, sizeof( msg ) );
 
   if( msg[ 0 ] == 'y' || msg[ 1 ] == 'Y' || msg[ 1 ] == '1' )
   {
+    level.teamVotedHow[ cs_offset ][ ent - g_entities ] = 1;
     level.teamVoteYes[ cs_offset ]++;
     trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va( "%i", level.teamVoteYes[ cs_offset ] ) );
     trap_SendServerCommand( ent-g_entities, "print \"^3/teamvote: ^7vote cast: ^ZYes\n\"" );
   }
   else
   {
+    level.teamVotedHow[ cs_offset ][ ent - g_entities ] = -1;
     level.teamVoteNo[ cs_offset ]++;
     trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va( "%i", level.teamVoteNo[ cs_offset ] ) );
     trap_SendServerCommand( ent-g_entities, "print \"^3/teamvote: ^7vote cast: ^ANo\n\"" );
diff --git a/src/game/g_local.h b/src/game/g_local.h
index af29793..e5463c5 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -713,6 +713,7 @@ typedef struct
   int               voteYes;
   int               voteNo;
   int               numVotingClients;             // set by CalculateRanks
+  int               votedHow[MAX_CLIENTS];       // 0 is "hasn't voted", 1 is "voted yes", -1 is voted "no"
 
   // team voting state
   char              teamVoteString[ 2 ][ MAX_STRING_CHARS ];
@@ -721,6 +722,7 @@ typedef struct
   int               teamVoteYes[ 2 ];
   int               teamVoteNo[ 2 ];
   int               numteamVotingClients[ 2 ];    // set by CalculateRanks
+  int               teamVotedHow[ 2 ][ MAX_CLIENTS ];
 
   // spawn variables
   qboolean          spawning;                     // the G_Spawn*() functions are valid
-- 
cgit