From 59875f1378dca6605cd0426eff89f850d8743c92 Mon Sep 17 00:00:00 2001
From: /dev/humancontroller <devhc@example.com>
Date: Sun, 13 Jul 2014 17:15:05 +0200
Subject: fix noclipping players affecting other players

notably, other players were able to stand on the "center" of a noclipped player

set an r.contents value of 0 for noclipping clients, backing up the r.contents value in the new ent->client->cliprcontents field
---
 src/game/g_client.c |  9 +++++++--
 src/game/g_cmds.c   | 10 ++++++++++
 src/game/g_combat.c |  5 ++++-
 src/game/g_local.h  |  1 +
 src/game/g_team.c   |  6 +++++-
 5 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/src/game/g_client.c b/src/game/g_client.c
index 76078040..548ec963 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1199,7 +1199,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
   int                 i;
   clientPersistant_t  saved;
   clientSession_t     savedSess;
-  qboolean            savedNoclip;
+  qboolean            savedNoclip, savedCliprcontents;
   int                 persistant[ MAX_PERSISTANT ];
   gentity_t           *spawnPoint = NULL;
   int                 flags;
@@ -1283,6 +1283,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
   savedSess = client->sess;
   savedPing = client->ps.ping;
   savedNoclip = client->noclip;
+  savedCliprcontents = client->cliprcontents;
 
   for( i = 0; i < MAX_PERSISTANT; i++ )
     persistant[ i ] = client->ps.persistant[ i ];
@@ -1294,6 +1295,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
   client->sess = savedSess;
   client->ps.ping = savedPing;
   client->noclip = savedNoclip;
+  client->cliprcontents = savedCliprcontents;
   client->lastkilled_client = -1;
 
   for( i = 0; i < MAX_PERSISTANT; i++ )
@@ -1316,7 +1318,10 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
   ent->client = &level.clients[ index ];
   ent->takedamage = qtrue;
   ent->classname = "player";
-  ent->r.contents = CONTENTS_BODY;
+  if( client->noclip )
+    client->cliprcontents = CONTENTS_BODY;
+  else
+    ent->r.contents = CONTENTS_BODY;
   ent->clipmask = MASK_PLAYERSOLID;
   ent->die = player_die;
   ent->waterlevel = 0;
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 8ad781ab..caa5f990 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -544,12 +544,22 @@ void Cmd_Noclip_f( gentity_t *ent )
   char  *msg;
 
   if( ent->client->noclip )
+  {
     msg = "noclip OFF\n";
+    ent->r.contents = ent->client->cliprcontents;
+  }
   else
+  {
     msg = "noclip ON\n";
+    ent->client->cliprcontents = ent->r.contents;
+    ent->r.contents = 0;
+  }
 
   ent->client->noclip = !ent->client->noclip;
 
+  if( ent->r.linked )
+    trap_LinkEntity( ent );
+
   trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
 }
 
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index 527e3068..0b61ce59 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -344,7 +344,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
   self->takedamage = qfalse; // can still be gibbed
 
   self->s.weapon = WP_NONE;
-  self->r.contents = CONTENTS_CORPSE;
+  if( self->client->noclip )
+    self->client->cliprcontents = CONTENTS_CORPSE;
+  else
+    self->r.contents = CONTENTS_CORPSE;
 
   self->s.angles[ PITCH ] = 0;
   self->s.angles[ ROLL ] = 0;
diff --git a/src/game/g_local.h b/src/game/g_local.h
index d319a5c2..081c47b8 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -362,6 +362,7 @@ struct gclient_s
   qboolean            readyToExit;    // wishes to leave the intermission
 
   qboolean            noclip;
+  int                 cliprcontents;  // the backup layer of ent->r.contents for when noclipping
 
   int                 lastCmdTime;    // level.time of last usercmd_t, for EF_CONNECTION
                                       // we can't just use pers.lastCommand.time, because
diff --git a/src/game/g_team.c b/src/game/g_team.c
index f3ca0f84..ad29beaf 100644
--- a/src/game/g_team.c
+++ b/src/game/g_team.c
@@ -222,7 +222,11 @@ void G_ChangeTeam( gentity_t *ent, team_t newTeam )
 
   if( !g_cheats.integer )
   {
-    ent->client->noclip = qfalse;
+    if( ent->client->noclip )
+    {
+      ent->client->noclip = qfalse;
+      ent->r.contents = ent->client->cliprcontents;
+    }
     ent->flags &= ~( FL_GODMODE | FL_NOTARGET );
   }
 
-- 
cgit