/*** * * Copyright (C) 2002 The Wastes Project, All Rights Reserved. * * This product contains software technology from Valve Software, LLC, * Copyright © 1996-2001, Valve LLC, All rights reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * The Wastes Project. All other use, distribution, or modification is prohibited * without written permission from The Wastes Project. * ***/ #include "extdll.h" #include "util.h" #include "cbase.h" #include "player.h" #include "weapons.h" #include "pm_shared.h" extern int gmsgCurWeapon; extern int gmsgSetFOV; extern int gmsgTeamInfo; extern int gmsgSpectator; // Player has become a spectator. Set it up. // This was moved from player.cpp. void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { // clear any clientside entities attached to this player MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_KILLPLAYERATTACHMENTS ); WRITE_BYTE( (BYTE)entindex() ); MESSAGE_END(); // Holster weapon immediately, to allow it to cleanup if (m_pActiveItem) m_pActiveItem->Holster( ); if ( m_pTank != NULL ) { m_pTank->Use( this, this, USE_OFF, 0 ); m_pTank = NULL; } // Tell Ammo Hud that the player is dead MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); WRITE_BYTE(0); WRITE_BYTE(0XFF); WRITE_BYTE(0xFF); MESSAGE_END(); // reset FOV m_iFOV = m_iClientFOV = 0; pev->fov = m_iFOV; MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); WRITE_BYTE(0); MESSAGE_END(); // Setup flags pev->classname = MAKE_STRING("observer"); m_iHideHUD = (HIDEHUD_HEALTH | HIDEHUD_WEAPONS); m_afPhysicsFlags |= PFLAG_OBSERVER; pev->effects = EF_NODRAW; pev->view_ofs = g_vecZero; pev->angles = pev->v_angle = vecViewAngle; pev->fixangle = TRUE; pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; pev->movetype = MOVETYPE_NONE; ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); ClearBits( pev->flags, FL_DUCKING ); pev->deadflag = DEAD_RESPAWNABLE; pev->health = 1; // Clear out the status bar m_fInitHUD = TRUE; // Update Team Status pev->team = 0; MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); WRITE_BYTE( ENTINDEX(edict()) ); WRITE_STRING( "" ); MESSAGE_END(); // Remove all the player's stuff RemoveAllItems(); // Move them to the new position UTIL_SetOrigin( pev, vecPosition ); // Find a player to watch m_flNextObserverInput = 0; Observer_SetMode(OBS_CHASE_LOCKED); // Tell all clients this player is now a spectator MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); WRITE_BYTE( ENTINDEX( edict() ) ); WRITE_BYTE( 1 ); MESSAGE_END(); } // Leave observer mode void CBasePlayer::StopObserver( void ) { // Turn off spectator if ( pev->iuser1 || pev->iuser2 ) { // Tell all clients this player is not a spectator anymore MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); WRITE_BYTE( ENTINDEX( edict() ) ); WRITE_BYTE( 0 ); MESSAGE_END(); pev->iuser1 = pev->iuser2 = 0; m_hObserverTarget = NULL; } m_iHideHUD = 0; m_afPhysicsFlags &= ~PFLAG_OBSERVER; pev->effects = 0; pev->fixangle = FALSE; pev->solid = SOLID_SLIDEBOX; pev->takedamage = DAMAGE_AIM; pev->movetype = MOVETYPE_WALK; pev->deadflag = DEAD_NO; } // Find the next client in the game for this player to spectate void CBasePlayer::Observer_FindNextPlayer( bool bReverse ) { // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching // only a subset of the players. e.g. Make it check the target's team. int iStart; if ( m_hObserverTarget ) iStart = ENTINDEX( m_hObserverTarget->edict() ); else iStart = ENTINDEX( edict() ); int iCurrent = iStart; m_hObserverTarget = NULL; int iDir = bReverse ? -1 : 1; do { iCurrent += iDir; // Loop through the clients if (iCurrent > gpGlobals->maxClients) iCurrent = 1; if (iCurrent < 1) iCurrent = gpGlobals->maxClients; CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); if ( !pEnt ) continue; if ( pEnt == this ) continue; // Don't spec observers or invisible players if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW) ) continue; // MOD AUTHORS: Add checks on target here. m_hObserverTarget = pEnt; break; } while ( iCurrent != iStart ); // Did we find a target? if ( m_hObserverTarget ) { // Store the target in pev so the physics DLL can get to it pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); // Move to the target UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->netname ) ); } else { ALERT( at_console, "No observer targets.\n" ); } } // Handle buttons in observer mode void CBasePlayer::Observer_HandleButtons() { // Slow down mouse clicks if ( m_flNextObserverInput > gpGlobals->time ) return; // Jump changes from modes: Chase to Roaming if ( m_afButtonPressed & IN_JUMP ) { if ( pev->iuser1 == OBS_ROAMING ) Observer_SetMode( OBS_CHASE_LOCKED ); else if ( pev->iuser1 == OBS_CHASE_LOCKED ) Observer_SetMode( OBS_CHASE_FREE ); else Observer_SetMode( OBS_ROAMING ); m_flNextObserverInput = gpGlobals->time + 0.2; } // Attack moves to the next player if ( m_afButtonPressed & IN_ATTACK && pev->iuser1 != OBS_ROAMING ) { Observer_FindNextPlayer( false ); m_flNextObserverInput = gpGlobals->time + 0.2; } // Attack2 moves to the prev player if ( m_afButtonPressed & IN_ATTACK2 && pev->iuser1 != OBS_ROAMING ) { Observer_FindNextPlayer( true ); m_flNextObserverInput = gpGlobals->time + 0.2; } } // Attempt to change the observer mode void CBasePlayer::Observer_SetMode( int iMode ) { // Just abort if we're changing to the mode we're already in if ( iMode == pev->iuser1 ) return; // Changing to Roaming? if ( iMode == OBS_ROAMING ) { // MOD AUTHORS: If you don't want to allow roaming observers at all in your mod, just abort here. pev->iuser1 = OBS_ROAMING; pev->iuser2 = 0; ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode3" ); pev->maxspeed = 320; return; } // Changing to Chase Lock? if ( iMode == OBS_CHASE_LOCKED ) { // If changing from Roaming, or starting observing, make sure there is a target if ( m_hObserverTarget == NULL ) Observer_FindNextPlayer( false ); if (m_hObserverTarget) { pev->iuser1 = OBS_CHASE_LOCKED; pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode1" ); pev->maxspeed = 0; } else { ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" ); Observer_SetMode(OBS_ROAMING); } return; } // Changing to Chase Freelook? if ( iMode == OBS_CHASE_FREE ) { // If changing from Roaming, or starting observing, make sure there is a target if ( m_hObserverTarget == NULL ) Observer_FindNextPlayer( false ); if (m_hObserverTarget) { pev->iuser1 = OBS_CHASE_FREE; pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode2" ); pev->maxspeed = 0; } else { ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" ); Observer_SetMode(OBS_ROAMING); } return; } }