From e2c4860a39dc9683bd626c270d62a0ee48c595e9 Mon Sep 17 00:00:00 2001 From: wootguy Date: Tue, 10 Sep 2024 21:49:31 -0700 Subject: [PATCH] tweak spectator mode and disabled spawns handling - players first entering the server, or trying to respawn, enter spectate mode if there are no enabled spawn points. Players spawn as soon as a spawn point is available. - leaving spectate mode is instant (no more falling to the floor) - trigger_respawn and player_respawn_zone ignore spectators Also fixed "game_playerjoin" being triggered on spawns instead of when the player first entered the server. --- dlls/CBaseDMStart.cpp | 4 ++-- dlls/CBaseDMStart.h | 2 +- dlls/CBasePlayer.cpp | 34 +++++++++++++++++++++++----- dlls/CBasePlayer.h | 1 + dlls/client.cpp | 10 +++++++- dlls/client_commands.cpp | 16 +++++++++---- dlls/gamerules.cpp | 3 +-- dlls/triggers/CPlayerRespawnZone.cpp | 8 +++++-- dlls/triggers/CTriggerRespawn.cpp | 5 ++++ 9 files changed, 65 insertions(+), 18 deletions(-) diff --git a/dlls/CBaseDMStart.cpp b/dlls/CBaseDMStart.cpp index d052a757..c25fd73c 100644 --- a/dlls/CBaseDMStart.cpp +++ b/dlls/CBaseDMStart.cpp @@ -48,7 +48,7 @@ EntSelectSpawnPoint Returns the entity to spawn at ============ */ -edict_t* EntSelectSpawnPoint(CBaseEntity* pPlayer) +edict_t* EntSelectSpawnPoint(CBaseEntity* pPlayer, bool includeDisabledSpawns) { CBaseEntity* pSpot; @@ -69,7 +69,7 @@ edict_t* EntSelectSpawnPoint(CBaseEntity* pPlayer) for (int i = 0; i < SPAWN_ENT_TYPES; i++) { pSpot = NULL; while (!FNullEnt(pSpot = UTIL_FindEntityByClassname(pSpot, spawn_ent_names[i]))) { - if (pSpot->IsTriggered(pPlayer)) { + if (pSpot->IsTriggered(pPlayer) || includeDisabledSpawns) { if (i == 0) { legacySpawns.push_back(pSpot); continue; diff --git a/dlls/CBaseDMStart.h b/dlls/CBaseDMStart.h index 7fbf75e1..6866cfce 100644 --- a/dlls/CBaseDMStart.h +++ b/dlls/CBaseDMStart.h @@ -1,6 +1,6 @@ #pragma once -edict_t* EntSelectSpawnPoint(CBaseEntity* pPlayer); +edict_t* EntSelectSpawnPoint(CBaseEntity* pPlayer, bool includeDisabledSpawns=false); BOOL IsSpawnPointClear(CBaseEntity* pPlayer, CBaseEntity* pSpot); diff --git a/dlls/CBasePlayer.cpp b/dlls/CBasePlayer.cpp index f89c09dd..8fbbbb10 100644 --- a/dlls/CBasePlayer.cpp +++ b/dlls/CBasePlayer.cpp @@ -1703,6 +1703,12 @@ void CBasePlayer::LeaveObserver() WRITE_SHORT(0); WRITE_SHORT(GetNameColor()); MESSAGE_END(); + + // fixes scoreboard + m_fInitHUD = true; + m_fGameHUDInitialized = false; + + Spawn(); } // @@ -2238,6 +2244,22 @@ void CBasePlayer::PreThink(void) Observer_CheckTarget(); Observer_CheckProperties(); pev->impulse = 0; + + static float lastCheck = 0; + + if (m_wantToExitObserver && (lastCheck > gpGlobals->time || gpGlobals->time - lastCheck > 1.0f)) { + lastCheck = gpGlobals->time; + edict_t* pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot(this); + + if (!FNullEnt(pentSpawnSpot)) { + LeaveObserver(); + m_wantToExitObserver = false; + } + else { + UTIL_ClientPrint(edict(), print_center, "Waiting to spawn...\n"); + } + } + return; } @@ -3243,8 +3265,13 @@ void CBasePlayer::Spawn( void ) SET_VIEW(edict(), edict()); } + g_pGameRules->PlayerSpawn(this); - g_pGameRules->PlayerSpawn( this ); + if (FNullEnt(pentSpawnSpot)) { + edict_t* anySpawnPoint = EntSelectSpawnPoint(this, true); + StartObserver(anySpawnPoint->v.origin, anySpawnPoint->v.angles); + m_wantToExitObserver = true; + } } void CBasePlayer :: Precache( void ) @@ -4207,11 +4234,6 @@ void CBasePlayer :: UpdateClientData( void ) m_fGameHUDInitialized = TRUE; m_iObserverLastMode = OBS_ROAMING; - - if ( g_pGameRules->IsMultiplayer() ) - { - FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); - } } FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); diff --git a/dlls/CBasePlayer.h b/dlls/CBasePlayer.h index c31a4103..faf4432e 100644 --- a/dlls/CBasePlayer.h +++ b/dlls/CBasePlayer.h @@ -107,6 +107,7 @@ class EXPORT CBasePlayer : public CBaseMonster int m_iObserverLastMode;// last used observer mode bool m_isObserver; float m_lastObserverSwitch; + bool m_wantToExitObserver; // set to true if the player should spawn as soon as a spawn point is available int IsObserver() { return m_isObserver; }; BOOL IsFirstPerson() { return m_hViewEntity.GetEdict() == edict(); } virtual int GetEntindexPriority() { return ENTIDX_PRIORITY_HIGH; } diff --git a/dlls/client.cpp b/dlls/client.cpp index 9a26b142..54ebb826 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -177,6 +177,9 @@ void respawn(entvars_t* pev, BOOL fCopyCorpse) } if (FNullEnt(spawnSpot)) { + plr->StartObserver(plr->pev->origin, plr->pev->angles); + plr->m_wantToExitObserver = true; + if (gpGlobals->time - plr->m_lastSpawnMessage > 0.5f) { CLIENT_PRINTF(plr->edict(), print_center, "No spawn points available"); plr->m_lastSpawnMessage = gpGlobals->time; @@ -272,7 +275,12 @@ void ClientPutInServer( edict_t *pEntity ) pPlayer->pev->effects |= EF_NOINTERP; pPlayer->pev->iuser1 = 0; // disable any spec modes - pPlayer->pev->iuser2 = 0; + pPlayer->pev->iuser2 = 0; + + if (g_pGameRules->IsMultiplayer()) + { + FireTargets("game_playerjoin", pPlayer, pPlayer, USE_TOGGLE, 0); + } } /* diff --git a/dlls/client_commands.cpp b/dlls/client_commands.cpp index 3c778a3b..f13495ff 100644 --- a/dlls/client_commands.cpp +++ b/dlls/client_commands.cpp @@ -467,13 +467,21 @@ void ClientCommand(edict_t* pEntity) // notify other clients of player switching to spectator mode UTIL_ClientPrintAll(print_chat, UTIL_VarArgs("%s switched to spectator mode\n", - (pev->netname && STRING(pev->netname)[0] != 0) ? STRING(pev->netname) : "unconnected")); + (pev->netname && STRING(pev->netname)[0] != 0) ? STRING(pev->netname) : "\\disconnected\\")); } else { - UTIL_ClientPrintAll(print_chat, UTIL_VarArgs("%s stopped spectating\n", - (pev->netname && STRING(pev->netname)[0] != 0) ? STRING(pev->netname) : "unconnected")); - pPlayer->LeaveObserver(); + edict_t* pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot(pPlayer); + + if (FNullEnt(pentSpawnSpot)) { + pPlayer->m_wantToExitObserver = true; + UTIL_ClientPrint(pPlayer->edict(), print_chat, "Can't stop spectating. No spawn points are available.\n"); + } + else { + pPlayer->LeaveObserver(); + UTIL_ClientPrintAll(print_chat, UTIL_VarArgs("%s stopped spectating\n", + (pev->netname&& STRING(pev->netname)[0] != 0) ? STRING(pev->netname) : "\\disconnected\\")); + } } } else diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index d0e7d636..2b70dcfa 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -28,6 +28,7 @@ #include "CBasePlayerItem.h" #include "PluginManager.h" #include "game.h" +#include "CBaseDMStart.h" #include #include @@ -37,8 +38,6 @@ using namespace std; -extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); - DLL_GLOBAL CGameRules* g_pGameRules = NULL; extern DLL_GLOBAL BOOL g_fGameOver; extern int gmsgDeathMsg; // client dll messages diff --git a/dlls/triggers/CPlayerRespawnZone.cpp b/dlls/triggers/CPlayerRespawnZone.cpp index 02f6c46c..37c282d6 100644 --- a/dlls/triggers/CPlayerRespawnZone.cpp +++ b/dlls/triggers/CPlayerRespawnZone.cpp @@ -51,17 +51,21 @@ void CPlayerRespawnZone::KeyValue(KeyValueData* pkvd) void CPlayerRespawnZone::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) { - CBaseEntity* pPlayer = NULL; + CBasePlayer* pPlayer = NULL; bool respawnInside = zoneType == ZONE_RESPAWN_INSIDE; for (int i = 1; i <= gpGlobals->maxClients; i++) { - pPlayer = UTIL_PlayerByIndex(i); + pPlayer = (CBasePlayer*)UTIL_PlayerByIndex(i); if (!pPlayer) continue; + if (pPlayer->IsObserver()) { + continue; + } + TraceResult trace; int hullNumber = (pPlayer->pev->flags & FL_DUCKING) ? head_hull : human_hull; diff --git a/dlls/triggers/CTriggerRespawn.cpp b/dlls/triggers/CTriggerRespawn.cpp index a4bcfcf1..060e8cc9 100644 --- a/dlls/triggers/CTriggerRespawn.cpp +++ b/dlls/triggers/CTriggerRespawn.cpp @@ -32,6 +32,11 @@ void CTriggerRespawn::RespawnTarget(CBaseEntity* target) { return; } + CBasePlayer* plr = (CBasePlayer*)target; + if (target->IsPlayer() && plr->IsObserver()) { + return; + } + // always move player entity, dead or alive edict_t* spawnPoint = EntSelectSpawnPoint(target); if (!FNullEnt(spawnPoint)) {