From c82de6b4ac7812a75e7454009e5762af8724f848 Mon Sep 17 00:00:00 2001
From: "Tony J. White" <tjw@tjw.org>
Date: Thu, 28 Sep 2006 19:23:39 +0000
Subject: * (bugs 2677, 2849) SPECTATOR_FOLLOW mode would give the spectating
 client   the credits/kills of the client he was following.

---
 src/game/g_cmds.c  | 81 ++++++++++++++++++++++++++++--------------------------
 src/game/g_local.h |  4 +++
 2 files changed, 46 insertions(+), 39 deletions(-)

diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 10ef878d..b181086f 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -586,57 +586,60 @@ G_ChangeTeam
 void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam )
 {
   pTeam_t oldTeam = ent->client->pers.teamSelection;
+ 
+  if( oldTeam == newTeam )
+    return;
 
   ent->client->pers.teamSelection = newTeam;
 
-  if( oldTeam != newTeam )
-  {
-    //if the client is in a queue make sure they are removed from it before changing
-    if( oldTeam == PTE_ALIENS )
-      G_RemoveFromSpawnQueue( &level.alienSpawnQueue, ent->client->ps.clientNum );
-    else if( oldTeam == PTE_HUMANS )
-      G_RemoveFromSpawnQueue( &level.humanSpawnQueue, ent->client->ps.clientNum );
+  if( oldTeam == PTE_ALIENS )
+    G_RemoveFromSpawnQueue( &level.alienSpawnQueue, ent->client->ps.clientNum );
+  else if( oldTeam == PTE_HUMANS )
+    G_RemoveFromSpawnQueue( &level.humanSpawnQueue, ent->client->ps.clientNum );
 
-    if( G_admin_permission( ent, ADMF_TEAMCHANGEFREE ) )
+  // under certain circumstances, clients can keep their kills and credits
+  // when switching teams
+  if( G_admin_permission( ent, ADMF_TEAMCHANGEFREE ) ||
+    ( ( oldTeam == PTE_HUMANS || oldTeam == PTE_ALIENS )
+    && ( level.time - ent->client->pers.teamChangeTime ) > 60000 ) )
+  {
+    if( oldTeam == PTE_NONE )
+    {
+      // ps.persistant[] from a spectator cannot be trusted
+      ent->client->ps.persistant[ PERS_SCORE ] = ent->client->pers.savedScore;
+      ent->client->ps.persistant[ PERS_CREDIT ] = ent->client->pers.savedCredit;
+    }
+    else if( oldTeam == PTE_ALIENS )
     {
       // always save in human credtis
-      if( oldTeam == PTE_ALIENS )
-      {
-        ent->client->ps.persistant[ PERS_CREDIT ] *=
-          (float)FREEKILL_HUMAN / FREEKILL_ALIEN;
-      }
-      if( newTeam == PTE_ALIENS )
-      {
-        ent->client->ps.persistant[ PERS_CREDIT ] *=
-          (float)FREEKILL_ALIEN / FREEKILL_HUMAN;
-      }
+      ent->client->ps.persistant[ PERS_CREDIT ] *=
+        (float)FREEKILL_HUMAN / FREEKILL_ALIEN;
     }
-    else if( ( oldTeam == PTE_HUMANS || oldTeam == PTE_ALIENS )
-      && ( level.time - ent->client->pers.teamChangeTime ) > 60000 ) 
+
+    if( newTeam == PTE_NONE )
     {
-      // Tranfer credits and kills as long as this player has been on the
-      // same team for at least 1 minute. This is done to provide
-      // a penalty for switching teams for reconnaissance.
-      if( oldTeam == PTE_HUMANS )
-      {
-        ent->client->ps.persistant[ PERS_CREDIT ] *=
-          (float)FREEKILL_ALIEN / FREEKILL_HUMAN;
-      }
-      else if( oldTeam == PTE_ALIENS )
-      {
-        ent->client->ps.persistant[ PERS_CREDIT ] *=
-          (float)FREEKILL_HUMAN / FREEKILL_ALIEN;
-      }
+      // save values before the client enters the spectator team and their
+      // ps.persistant[] values become trashed
+      ent->client->pers.savedScore = ent->client->ps.persistant[ PERS_SCORE ];
+      ent->client->pers.savedCredit = ent->client->ps.persistant[ PERS_CREDIT ];
     }
-    else
+    else if( newTeam == PTE_ALIENS )
     {
-      ent->client->ps.persistant[ PERS_CREDIT ] = 0;
-      ent->client->ps.persistant[ PERS_SCORE ] = 0;
+      // convert to alien currency
+      ent->client->ps.persistant[ PERS_CREDIT ] *=
+        (float)FREEKILL_ALIEN / FREEKILL_HUMAN;
     }
-
-    ent->client->pers.classSelection = PCL_NONE;
-    ClientSpawn( ent, NULL, NULL, NULL );
   }
+  else
+  {
+    ent->client->ps.persistant[ PERS_CREDIT ] = 0;
+    ent->client->ps.persistant[ PERS_SCORE ] = 0;
+    ent->client->pers.savedScore = 0;
+    ent->client->pers.savedCredit = 0;
+  }
+
+  ent->client->pers.classSelection = PCL_NONE;
+  ClientSpawn( ent, NULL, NULL, NULL );
 
   ent->client->pers.joinedATeam = qtrue;
   ent->client->pers.teamChangeTime = level.time;
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 8020ac08..25f31ad6 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -340,6 +340,10 @@ typedef struct
   int                 nameChangeTime;
   int                 nameChanges;
 
+  // used to save persistant[] values while in SPECTATOR_FOLLOW mode
+  int                 savedScore;
+  int                 savedCredit;
+
   vec3_t              lastDeathLocation;
   char                guid[ 33 ];
   char                ip[ 16 ];
-- 
cgit