From 5097748e7b51a85e46047659a429532793d3fc93 Mon Sep 17 00:00:00 2001
From: Tim Angus <tim@ngus.net>
Date: Sat, 2 Jul 2005 19:29:17 +0000
Subject: * Fixed the PTRC system interfering with the observer mode *
 Refactored observer mode code * Fixed poison cloud being distorted in
 observer mode (by not rendering it) * Fixed walking wall smoothing being
 distorted in observer mode (by not performing any smoothing)

---
 src/cgame/cg_view.c |  20 ++++++--
 src/game/bg_misc.c  |   2 +-
 src/game/g_active.c |  22 ++------
 src/game/g_client.c |   3 +-
 src/game/g_cmds.c   | 142 +++++++++++++++++++++++++---------------------------
 src/game/g_combat.c |  12 +++++
 src/game/g_local.h  |   7 +--
 src/ui/ui_shared.h  |   3 ++
 8 files changed, 111 insertions(+), 100 deletions(-)

(limited to 'src')

diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c
index e88bb8f8..12772a3d 100644
--- a/src/cgame/cg_view.c
+++ b/src/cgame/cg_view.c
@@ -577,7 +577,8 @@ static void CG_OffsetFirstPersonView( void )
       cg.upMoveTime = cg.time;
   }
 
-  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED )
+  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
+      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
   {
     float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY );
     float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY );
@@ -788,7 +789,8 @@ static int CG_CalcFov( void )
     inwater = qfalse;
 
   if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
-      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
+      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
+      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
   {
     phase = cg.time / 1000.0 * PCLOUD_ZOOM_FREQUENCY * M_PI * 2;
     v = PCLOUD_ZOOM_AMPLITUDE * sin( phase );
@@ -948,6 +950,12 @@ static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t o
   qboolean  performed = qfalse;
   vec3_t    inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ];
 
+  if( cg.snap->ps.pm_flags & PMF_FOLLOW )
+  {
+    VectorCopy( in, out );
+    return;
+  }
+
   //set surfNormal
   if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) )
     VectorCopy( ps->grapplePoint, surfNormal );
@@ -990,7 +998,7 @@ static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t o
 
       timeMod = 1.0f;
     }
-          
+    
     //add the op
     CG_addSmoothOp( rotAxis, rotAngle, timeMod );
   }
@@ -1042,6 +1050,12 @@ static void CG_smoothWJTransitions( playerState_t *ps, const vec3_t in, vec3_t o
   qboolean  performed = qfalse;
   vec3_t    inAxis[ 3 ], outAxis[ 3 ];
 
+  if( cg.snap->ps.pm_flags & PMF_FOLLOW )
+  {
+    VectorCopy( in, out );
+    return;
+  }
+
   AnglesToAxis( in, inAxis );
 
   //iterate through ops
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 83d509dd..b22a94e8 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -208,7 +208,7 @@ buildableAttributes_t bg_buildableList[ ] =
     TR_GRAVITY,            //trType_t  traj;
     0.0,                   //float     bounce;
     TRAPPER_BP,            //int       buildPoints;
-    ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int  stages
+    ( 1 << S2 )|( 1 << S3 ), //int  stages //NEEDS ADV BUILDER SO S2 AND UP
     TRAPPER_HEALTH,        //int       health;
     TRAPPER_REGEN,         //int       regenRate;
     TRAPPER_SPLASHDAMAGE,  //int       splashDamage;
diff --git a/src/game/g_active.c b/src/game/g_active.c
index ee5d1aa3..d22a8b2b 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1398,40 +1398,24 @@ SpectatorClientEndFrame
 void SpectatorClientEndFrame( gentity_t *ent )
 {
   gclient_t *cl;
+  int       clientNum, flags;
 
   // if we are doing a chase cam or a remote view, grab the latest info
   if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
   {
-    int   clientNum, flags;
-
     clientNum = ent->client->sess.spectatorClient;
 
-    // team follow1 and team follow2 go to whatever clients are playing
-    if( clientNum == -1 )
-      clientNum = level.follow1;
-    else if( clientNum == -2 )
-      clientNum = level.follow2;
-
     if( clientNum >= 0 )
     {
       cl = &level.clients[ clientNum ];
       
       if( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR )
       {
-        flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) | ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );
+        flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) |
+          ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );
         ent->client->ps = cl->ps;
         ent->client->ps.pm_flags |= PMF_FOLLOW;
         ent->client->ps.eFlags = flags;
-        return;
-      }
-      else
-      {
-        // drop them to free spectators unless they are dedicated camera followers
-        if( ent->client->sess.spectatorClient >= 0 )
-        {
-          ent->client->sess.spectatorState = SPECTATOR_FREE;
-          ClientBegin( ent->client - level.clients );
-        }
       }
     }
   }
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 24b7900c..e5c90d70 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1559,7 +1559,8 @@ void ClientDisconnect( int clientNum )
         level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW &&
         level.clients[ i ].sess.spectatorClient == clientNum )
     {
-      G_StopFollowing( &g_entities[ i ] );
+      if( !G_FollowNewClient( &g_entities[ i ], 1 ) )
+        G_StopFollowing( &g_entities[ i ] );
     }
   }
 
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 47e5b3ba..619989c7 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -1991,6 +1991,7 @@ void G_StopFollowing( gentity_t *ent )
   ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR; 
   ent->client->sess.sessionTeam = TEAM_SPECTATOR; 
   ent->client->sess.spectatorState = SPECTATOR_FREE;
+  ent->client->sess.spectatorClient = -1;
   ent->client->ps.pm_flags &= ~PMF_FOLLOW;
 
   ent->client->ps.stats[ STAT_STATE ] &= ~SS_WALLCLIMBING;
@@ -2002,6 +2003,69 @@ void G_StopFollowing( gentity_t *ent )
   ent->client->ps.clientNum = ent - g_entities;
 }
 
+/*
+=================
+G_FollowNewClient
+
+This was a really nice, elegant function. Then I fucked it up.
+=================
+*/
+qboolean G_FollowNewClient( gentity_t *ent, int dir )
+{
+  int       clientnum = ent->client->sess.spectatorClient;
+  int       original = clientnum;
+  qboolean  selectAny = qfalse;
+  
+  if( dir > 1 )
+    dir = 1;
+  else if( dir < -1 )
+    dir = -1;
+  else if( dir == 0 )
+    return qtrue;
+
+  // select any if no target exists
+  if( clientnum < 0 || clientnum >= level.maxclients )
+  {
+    clientnum = original = 0;
+    selectAny = qtrue;
+  }
+  
+  do
+  {
+    clientnum += dir;
+    
+    if( clientnum >= level.maxclients )
+      clientnum = 0;
+    
+    if( clientnum < 0 )
+      clientnum = level.maxclients - 1;
+
+    // avoid selecting existing follow target
+    if( clientnum == original && !selectAny )
+      continue; //effectively break;
+    
+    // can't follow self
+    if( &level.clients[ clientnum ] == ent->client )
+      continue;
+
+    // can only follow connected clients
+    if( level.clients[ clientnum ].pers.connected != CON_CONNECTED )
+      continue;
+
+    // can't follow another spectator
+    if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR )
+      continue;
+
+    // this is good, we can use it
+    ent->client->sess.spectatorClient = clientnum;
+    ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
+    return qtrue;
+    
+  } while( clientnum != original );
+
+  return qfalse;
+}
+
 /*
 =================
 Cmd_Follow_f
@@ -2016,43 +2080,10 @@ void Cmd_Follow_f( gentity_t *ent, qboolean toggle )
   {
     if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
       G_StopFollowing( ent );
-    else
-    {
-      //follow somebody, anybody
-      int clientnum = ent->client->sess.spectatorClient;
-      int original = clientnum;
-      
-      do
-      {
-        clientnum++;
-        
-        if( clientnum >= level.maxclients )
-          clientnum = 0;
-        
-        if( clientnum < 0 )
-          clientnum = level.maxclients - 1;
-
-        // can't follow self
-        if( &level.clients[ clientnum ] == ent->client )
-          continue;
-
-        // can only follow connected clients
-        if( level.clients[ clientnum ].pers.connected != CON_CONNECTED )
-          continue;
-
-        // can't follow another spectator
-        if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR )
-          continue;
-
-        // this is good, we can use it
-        ent->client->sess.spectatorClient = clientnum;
-        ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
-        break;
-        
-      } while( clientnum != original );
-    }
+    else if( ent->client->sess.spectatorState == SPECTATOR_FREE )
+      G_FollowNewClient( ent, 1 );
   }
-  else
+  else if( ent->client->sess.spectatorState == SPECTATOR_FREE )
   {
     trap_Argv( 1, arg, sizeof( arg ) );
     i = G_ClientNumberFromString( ent, arg );
@@ -2084,49 +2115,14 @@ Cmd_FollowCycle_f
 */
 void Cmd_FollowCycle_f( gentity_t *ent, int dir )
 {
-  int clientnum;
-  int original;
-
-  // first set them to spectator
+  // won't work unless spectating
   if( ent->client->sess.spectatorState == SPECTATOR_NOT )
     return;
 
   if( dir != 1 && dir != -1 )
     G_Error( "Cmd_FollowCycle_f: bad dir %i", dir );
 
-  clientnum = ent->client->sess.spectatorClient;
-  original = clientnum;
-  
-  do
-  {
-    clientnum += dir;
-    
-    if( clientnum >= level.maxclients )
-      clientnum = 0;
-    
-    if( clientnum < 0 )
-      clientnum = level.maxclients - 1;
-
-    // can't follow self
-    if( &level.clients[ clientnum ] == ent->client )
-      continue;
-
-    // can only follow connected clients
-    if( level.clients[ clientnum ].pers.connected != CON_CONNECTED )
-      continue;
-
-    // can't follow another spectator
-    if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR )
-      continue;
-
-    // this is good, we can use it
-    ent->client->sess.spectatorClient = clientnum;
-    ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
-    return;
-    
-  } while( clientnum != original );
-
-  // leave it where it was
+  G_FollowNewClient( ent, dir );
 }
 
 /*
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index 0bf8b1b8..515ecfe7 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -163,6 +163,18 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
   if( level.intermissiontime )
     return;
 
+  // stop any following clients
+  for( i = 0; i < level.maxclients; i++ )
+  {
+    if( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR &&
+        level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW &&
+        level.clients[ i ].sess.spectatorClient == self->client->ps.clientNum )
+    {
+      if( !G_FollowNewClient( &g_entities[ i ], 1 ) )
+        G_StopFollowing( &g_entities[ i ] );
+    }
+  }
+
   self->client->ps.pm_type = PM_DEAD;
   self->suicideTime = 0;
 
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 00b38bbe..2db714f2 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -600,9 +600,10 @@ char      *G_NewString( const char *string );
 //
 // g_cmds.c
 //
-void Cmd_Score_f( gentity_t *ent );
-void G_StopFollowing( gentity_t *ent );
-void Cmd_Follow_f( gentity_t *ent, qboolean toggle );
+void      Cmd_Score_f( gentity_t *ent );
+void      G_StopFollowing( gentity_t *ent );
+qboolean  G_FollowNewClient( gentity_t *ent, int dir );
+void      Cmd_Follow_f( gentity_t *ent, qboolean toggle );
 
 //
 // g_physics.c
diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h
index 51f6eac0..d0864c02 100644
--- a/src/ui/ui_shared.h
+++ b/src/ui/ui_shared.h
@@ -443,4 +443,7 @@ int			trap_PC_FreeSource( int handle );
 int			trap_PC_ReadToken( int handle, pc_token_t *pc_token );
 int			trap_PC_SourceFileAndLine( int handle, char *filename, int *line );
 
+void    BindingFromName( const char *cvar );
+extern char g_nameBind1[ 32 ];
+extern char g_nameBind2[ 32 ];
 #endif
-- 
cgit