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
This commit is contained in:
RGreenlees 2024-04-04 13:57:04 +01:00 committed by pierow
parent 019045c5c7
commit 4f32271532
7 changed files with 85 additions and 68 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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)
{
@ -270,46 +272,55 @@ void CBasePlayer::Observer_SetMode( int iMode )
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);
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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"