From 4f32271532dd91919f644e2e67debcd80673b672 Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Thu, 4 Apr 2024 13:57:04 +0100 Subject: [PATCH] Fix broken roaming spectator mode * Added server cvar (mp_freespectatormode) which controls when a player can enter a free spectator mode (orbit cam, or free roaming). 0 = never, 1 = only when spectator, 2 = Always * Free roaming will now be part of the cycle when pressing the jump key * The overlay is now toggled with the crouch button * Strafing in free roaming no longer snaps to different players * Fixed bug that would break spectating completely if returning to the ready room while in free roam * You can no longer enter free roaming using the "specmode" and "spec_mode" console commands if it's disabled by the server --- main/source/cl_dll/hud_spectator.cpp | 101 ++++++++++++++------------- main/source/dlls/client.cpp | 4 +- main/source/dlls/game.cpp | 2 + main/source/dlls/observer.cpp | 41 +++++++---- main/source/dlls/player.cpp | 2 +- main/source/mod/AvHGamerules.cpp | 2 + main/source/mod/AvHServerVariables.h | 1 + 7 files changed, 85 insertions(+), 68 deletions(-) diff --git a/main/source/cl_dll/hud_spectator.cpp b/main/source/cl_dll/hud_spectator.cpp index 4be35534..e051b150 100644 --- a/main/source/cl_dll/hud_spectator.cpp +++ b/main/source/cl_dll/hud_spectator.cpp @@ -853,58 +853,41 @@ void CHudSpectator::HandleButtonsDown( int ButtonPressed ) int theNewMainMode = g_iUser1; - // Jump changes main window modes + // Crouch toggles the overview mode + if (gHUD.GetIsNSMode() && ButtonPressed & IN_DUCK) + { + bool theInOverviewMode = gHUD.m_Spectator.IsInOverviewMode(); + gHUD.m_Spectator.SetOverviewMode(!theInOverviewMode); + } + + // Jump changes spectator modes if ( ButtonPressed & IN_JUMP ) { - bool theFirstPerson = (g_iUser1 == OBS_IN_EYE); - bool theInOverviewMode = gHUD.m_Spectator.IsInOverviewMode(); + theNewMainMode++; - // NS - if(gHUD.GetIsNSMode()) - { - // First-person full -> chase camera full -> firstperson with overview -> chase camera with overview - if(theFirstPerson && !theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - //gHUD.m_Spectator.SetOverviewMode(false); - } - else if(!theFirstPerson && !theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(true); - } - else if(theFirstPerson && theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - //gHUD.m_Spectator.SetOverviewMode(true); - } - else if(!theFirstPerson && theInOverviewMode) - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(false); - } - } - // Combat - else - { - // First-person full -> chase camera full - if(theFirstPerson) - { - gHUD.m_Spectator.SetMode(OBS_CHASE_LOCKED); - gHUD.m_Spectator.SetOverviewMode(false); - } - else - { - gHUD.m_Spectator.SetMode(OBS_IN_EYE); - gHUD.m_Spectator.SetOverviewMode(false); - } - } + AvHPlayMode CurrPlayMode = gHUD.GetPlayMode(); + + float FreeSpecMode = gHUD.GetServerVariableFloat("mp_freespectatormode"); + if (FreeSpecMode == 0 || (FreeSpecMode == 1 && gHUD.GetPlayMode() != PLAYMODE_OBSERVER)) + { + while (theNewMainMode == OBS_CHASE_FREE || theNewMainMode == OBS_ROAMING) + { + theNewMainMode++; + } + } + + if (theNewMainMode > OBS_IN_EYE) + { + theNewMainMode = OBS_CHASE_LOCKED; + } + + gHUD.m_Spectator.SetMode(theNewMainMode); } //g_iUser1 = theNewMainMode; // Attack moves to the next player - if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + if (g_iUser1 != OBS_ROAMING && ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) { FindNextPlayer( (ButtonPressed & IN_MOVELEFT) ? true:false ); @@ -1037,25 +1020,43 @@ void CHudSpectator::HandleButtonsUp( int ButtonPressed ) void CHudSpectator::SetMode(int iNewMainMode) { + int NewMode = iNewMainMode; + + if (NewMode == OBS_CHASE_FREE || NewMode == OBS_ROAMING) + { + float FreeSpecMode = gHUD.GetServerVariableFloat("mp_freespectatormode"); + if (FreeSpecMode == 0 || (FreeSpecMode == 1 && gHUD.GetPlayMode() != PLAYMODE_OBSERVER)) + { + if (g_iUser1 != OBS_CHASE_FREE && g_iUser1 != OBS_ROAMING) + { + NewMode = g_iUser1; + } + else + { + NewMode = OBS_IN_EYE; + } + } + } + // if value == -1 keep old value - if ( iNewMainMode == -1 ) - iNewMainMode = g_iUser1; + if (NewMode == -1 ) + NewMode = g_iUser1; // main modes ettings will override inset window settings - if ( iNewMainMode != g_iUser1 ) + if (NewMode != g_iUser1 ) { // if we are NOT in HLTV mode, main spectator mode is set on server if ( !gEngfuncs.IsSpectateOnly() ) { char cmdstring[32]; // forward command to server - sprintf(cmdstring,"specmode %i",iNewMainMode ); + sprintf(cmdstring,"specmode %i", NewMode); gEngfuncs.pfnServerCmd(cmdstring); return; } else { - if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target + if ( !g_iUser2 && (NewMode != OBS_ROAMING ) ) // make sure we have a target { // choose last Director object if still available if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) @@ -1069,7 +1070,7 @@ void CHudSpectator::SetMode(int iNewMainMode) } } - switch ( iNewMainMode ) + switch (NewMode) { case OBS_CHASE_LOCKED: g_iUser1 = OBS_CHASE_LOCKED; diff --git a/main/source/dlls/client.cpp b/main/source/dlls/client.cpp index 1e7b295a..318d8b1e 100644 --- a/main/source/dlls/client.cpp +++ b/main/source/dlls/client.cpp @@ -670,7 +670,7 @@ void ClientCommand( edict_t *pEntity ) else if (FStrEq( pcmd, "follow")) // follow a specific player { CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) + if ( pPlayer->IsObserver() && pPlayer->pev->iuser1 != OBS_ROAMING ) { pPlayer->Observer_SpectatePlayer(atoi( CMD_ARGV(1) )); pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); @@ -679,7 +679,7 @@ void ClientCommand( edict_t *pEntity ) else if ( FStrEq( pcmd, "follownext" ) ) // follow next player { CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - if ( pPlayer->IsObserver() ) + if ( pPlayer->IsObserver() && pPlayer->pev->iuser1 != OBS_ROAMING) { pPlayer->Observer_FindNextPlayer(atoi( CMD_ARGV(1) )); pPlayer->SetDefaultSpectatingSettings(pPlayer->pev->iuser1, pPlayer->pev->iuser2); diff --git a/main/source/dlls/game.cpp b/main/source/dlls/game.cpp index d5fdfcf8..64547055 100644 --- a/main/source/dlls/game.cpp +++ b/main/source/dlls/game.cpp @@ -125,6 +125,7 @@ cvar_t avh_jumpmode = {kvJumpMode, "1", FCVAR_SERVER}; cvar_t avh_version = {kvVersion, "330", FCVAR_SERVER}; cvar_t avh_widescreenclamp = {kvWidescreenClamp, "0", FCVAR_SERVER}; cvar_t avh_randomrfk = {kvRandomRfk, "0", FCVAR_SERVER}; +cvar_t avh_freespectatormode = {kvFreeSpectatorMode, "1", FCVAR_SERVER }; // AI Player Settings cvar_t avh_botsenabled = { kvBotsEnabled,"0", FCVAR_SERVER }; // Bots can be added to the server Y/N @@ -285,6 +286,7 @@ void GameDLLInit( void ) // TODO: Remove CVAR_REGISTER (&avh_ironman); CVAR_REGISTER (&avh_ironmantime); + CVAR_REGISTER (&avh_freespectatormode); #ifdef DEBUG CVAR_REGISTER (&avh_spawninvulnerabletime); diff --git a/main/source/dlls/observer.cpp b/main/source/dlls/observer.cpp index ec2e9082..c659e4e9 100644 --- a/main/source/dlls/observer.cpp +++ b/main/source/dlls/observer.cpp @@ -25,6 +25,8 @@ const float kNextTargetInterval = .2f; +extern cvar_t avh_freespectatormode; + // Find the next client in the game for this player to spectate bool CBasePlayer::Observer_FindNextPlayer(bool inReverse) { @@ -269,47 +271,56 @@ void CBasePlayer::Observer_SetMode( int iMode ) ASSERT(thePlayer); bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); - - if(!theIsObserving) + + int NewMode = iMode; + + float FreeSpecMode = avh_freespectatormode.value; + + if (FreeSpecMode == 0 || (FreeSpecMode == 1 && !theIsObserving)) { - if((iMode == OBS_ROAMING) /*|| (iMode == OBS_MAP_FREE) || (iMode == OBS_MAP_CHASE)*/) + if (NewMode == OBS_CHASE_FREE || NewMode == OBS_ROAMING) { - return; + NewMode = (pev->iuser1 == OBS_CHASE_LOCKED || pev->iuser1 == OBS_IN_EYE) ? pev->iuser1 : OBS_IN_EYE; } } // Just abort if we're changing to the mode we're already in - if ( iMode == pev->iuser1 ) + if (NewMode == pev->iuser1 ) return; // Removed by mmcguire. // is valid mode ? - if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_IN_EYE ) - iMode = OBS_IN_EYE; // now it is + if (NewMode < OBS_CHASE_LOCKED || NewMode > OBS_IN_EYE ) + NewMode = OBS_IN_EYE; // now it is // if we are not roaming, we need a valid target to track - if ( (iMode != OBS_ROAMING) && (m_hObserverTarget == NULL) ) + if ( (NewMode != OBS_ROAMING) && (m_hObserverTarget == NULL) ) { Observer_FindNextPlayer(); // if we didn't find a valid target switch to roaming if (m_hObserverTarget == NULL) { - iMode = OBS_ROAMING; + NewMode = OBS_ROAMING; } } // set spectator mode - pev->iuser1 = iMode; + pev->iuser1 = NewMode; // set target if not roaming - if (iMode == OBS_ROAMING) + if (NewMode == OBS_ROAMING) + { pev->iuser2 = 0; + } else - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); + { + pev->iuser2 = ENTINDEX(m_hObserverTarget->edict()); + // Make sure our target is valid (go backward then forward) + Observer_FindNextPlayer(true); + Observer_FindNextPlayer(false); + } - // Make sure our target is valid (go backward then forward) - Observer_FindNextPlayer(true); - Observer_FindNextPlayer(false); + } \ No newline at end of file diff --git a/main/source/dlls/player.cpp b/main/source/dlls/player.cpp index 0c62d51b..dfe32500 100644 --- a/main/source/dlls/player.cpp +++ b/main/source/dlls/player.cpp @@ -1694,7 +1694,7 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) pev->deadflag = DEAD_RESPAWNABLE; // Tell the physics code that this player's now in observer mode - Observer_SetMode(this->GetDefaultSpectatingMode()); + Observer_SetMode(OBS_IN_EYE); Observer_SpectatePlayer(this->GetDefaultSpectatingTarget()); m_flNextObserverInput = 0; } diff --git a/main/source/mod/AvHGamerules.cpp b/main/source/mod/AvHGamerules.cpp index 00a6a472..1221acb5 100644 --- a/main/source/mod/AvHGamerules.cpp +++ b/main/source/mod/AvHGamerules.cpp @@ -231,6 +231,7 @@ extern cvar_t avh_ironman; extern cvar_t avh_mapvoteratio; extern cvar_t avh_structurelimit; extern cvar_t avh_version; +extern cvar_t avh_freespectatormode; extern cvar_t avh_botsenabled; extern cvar_t avh_botautomode; @@ -348,6 +349,7 @@ AvHGamerules::AvHGamerules() : mTeamA(TEAM_ONE), mTeamB(TEAM_TWO) RegisterServerVariable(&avh_structurelimit); RegisterServerVariable(&avh_version); RegisterServerVariable(&avh_widescreenclamp); + RegisterServerVariable(&avh_freespectatormode); //playtest cvars RegisterServerVariable(&avh_fastjp); diff --git a/main/source/mod/AvHServerVariables.h b/main/source/mod/AvHServerVariables.h index 7a452031..220af569 100644 --- a/main/source/mod/AvHServerVariables.h +++ b/main/source/mod/AvHServerVariables.h @@ -142,6 +142,7 @@ float ns_cvar_float(const cvar_t *cvar); #define kvPerformance "mp_performance" #define kvIronMan "mp_ironman" #define kvIronManTime "mp_ironmantime" +#define kvFreeSpectatorMode "mp_freespectatormode" #define kvBotsEnabled "mp_botsenabled" #define kvBotMinPlayers "mp_botminplayers"