Index: src/game/g_local.h =================================================================== --- src/game/g_local.h (revision 895) +++ src/game/g_local.h (working copy) @@ -322,6 +322,7 @@ qboolean localClient; // true if "ip" info key is "localhost" qboolean initialSpawn; // the first spawn should be at a cool location qboolean predictItemPickup; // based on cg_predictItems userinfo + qboolean stickySpec; // sticky spectator qboolean pmoveFixed; // char netname[ MAX_NETNAME ]; int maxHealth; // for handicapping Index: src/game/g_combat.c =================================================================== --- src/game/g_combat.c (revision 895) +++ src/game/g_combat.c (working copy) @@ -148,7 +148,7 @@ // stop any following clients for( i = 0; i < level.maxclients; i++ ) - { + if(!(level.clients[i].pers.stickySpec)) { //Lakitu7: Made R1CH's stickyspec mod controllable per-client via cg_sticySpec. Thanks Kevlarman, vcxzet, and R1CH if( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR && level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW && level.clients[ i ].sess.spectatorClient == self->client->ps.clientNum ) Index: src/game/g_active.c =================================================================== --- src/game/g_active.c (revision 895) +++ src/game/g_active.c (working copy) @@ -375,19 +375,31 @@ { pmove_t pm; gclient_t *client; + qboolean doPmove = qtrue; client = ent->client; client->oldbuttons = client->buttons; client->buttons = ucmd->buttons; - if( client->sess.spectatorState != SPECTATOR_FOLLOW ) + if( client->sess.spectatorState == SPECTATOR_LOCKED || client->sess.spectatorState == SPECTATOR_FOLLOW ) + client->ps.pm_type = PM_FREEZE; + else + client->ps.pm_type = PM_SPECTATOR; + + if ( client->sess.spectatorState == SPECTATOR_FOLLOW ) { - if( client->sess.spectatorState == SPECTATOR_LOCKED ) - client->ps.pm_type = PM_FREEZE; - else - client->ps.pm_type = PM_SPECTATOR; + gclient_t *cl; + if ( client->sess.spectatorClient >= 0 ) + { + cl = &level.clients[ client->sess.spectatorClient ]; + if ( cl->sess.sessionTeam != TEAM_SPECTATOR ) + doPmove = qfalse; + } + } + if (doPmove) + { client->ps.speed = BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] ); client->ps.stats[ STAT_STAMINA ] = 0; @@ -1754,13 +1766,14 @@ { cl = &level.clients[ clientNum ]; - if( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) + if( cl->pers.connected == CON_CONNECTED ) { flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) | ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) ); ent->client->ps = cl->ps; + ent->client->ps.eFlags = flags; ent->client->ps.pm_flags |= PMF_FOLLOW; - ent->client->ps.eFlags = flags; + ent->client->ps.pm_flags &= ~PMF_QUEUED; } } } Index: src/game/g_client.c =================================================================== --- src/game/g_client.c (revision 895) +++ src/game/g_client.c (working copy) @@ -982,6 +982,16 @@ else client->pers.predictItemPickup = qtrue; + + // stickyspec toggle + s = Info_ValueForKey( userinfo, "cg_stickySpec" ); + + if( !atoi( s ) ) + client->pers.stickySpec = qfalse; + else + client->pers.stickySpec = qtrue; + + // set name Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) ); s = Info_ValueForKey( userinfo, "name" ); Index: src/game/g_cmds.c =================================================================== --- src/game/g_cmds.c (revision 895) +++ src/game/g_cmds.c (working copy) @@ -2468,7 +2468,7 @@ continue; // can't follow another spectator - if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) + if( level.clients[ clientnum ].pers.teamSelection == PTE_NONE ) continue; // this is good, we can use it @@ -2483,7 +2483,7 @@ /* ================= -Cmd_Follow_f +Cmd_Follow_f ================= */ void Cmd_Follow_f( gentity_t *ent, qboolean toggle ) @@ -2524,7 +2524,7 @@ return; // can't follow another spectator - if( ent->client->pers.teamSelection != PTE_NONE ) + if( level.clients[ i ].pers.teamSelection == PTE_NONE) return; ent->client->sess.spectatorState = SPECTATOR_FOLLOW; Index: src/cgame/cg_local.h =================================================================== --- src/cgame/cg_local.h (revision 895) +++ src/cgame/cg_local.h (working copy) @@ -1487,6 +1487,8 @@ extern vmCvar_t cg_painBlendScale; extern vmCvar_t cg_painBlendZoom; +extern vmCvar_t cg_stickySpec; + //TA: hack to get class an carriage through to UI module extern vmCvar_t ui_currentClass; extern vmCvar_t ui_carriage; Index: src/cgame/cg_main.c =================================================================== --- src/cgame/cg_main.c (revision 895) +++ src/cgame/cg_main.c (working copy) @@ -224,6 +224,8 @@ vmCvar_t cg_painBlendScale; vmCvar_t cg_painBlendZoom; +vmCvar_t cg_stickySpec; + //TA: hack to get class and carriage through to UI module vmCvar_t ui_currentClass; vmCvar_t ui_carriage; @@ -341,6 +343,8 @@ { &cg_painBlendScale, "cg_painBlendScale", "7.0", 0 }, { &cg_painBlendZoom, "cg_painBlendZoom", "0.65", 0 }, + { &cg_stickySpec, "cg_stickySpec", "1", CVAR_ARCHIVE|CVAR_USERINFO }, + { &ui_currentClass, "ui_currentClass", "0", 0 }, { &ui_carriage, "ui_carriage", "", 0 }, { &ui_stages, "ui_stages", "0 0", 0 },