327 lines
7.8 KiB
C++
327 lines
7.8 KiB
C++
|
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
|
||
|
//
|
||
|
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||
|
// The contents may be used and/or copied only with the written permission of
|
||
|
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||
|
// the agreement/contract under which the contents have been supplied.
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $Workfile: $
|
||
|
// $Date: $
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// $Log: $
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================
|
||
|
// observer.cpp
|
||
|
//
|
||
|
#include "extdll.h"
|
||
|
#include "util.h"
|
||
|
#include "cbase.h"
|
||
|
#include "player.h"
|
||
|
#include "weapons.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 != 0 )
|
||
|
{
|
||
|
m_pTank->Use( this, this, USE_OFF, 0 );
|
||
|
m_pTank = NULL;
|
||
|
}
|
||
|
|
||
|
// clear out the suit message cache so we don't keep chattering
|
||
|
SetSuitUpdate(NULL, FALSE, 0);
|
||
|
|
||
|
// 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
|
||
|
m_iHideHUD = (HIDEHUD_HEALTH | HIDEHUD_WEAPONS);
|
||
|
m_afPhysicsFlags |= PFLAG_OBSERVER;
|
||
|
pev->effects = EF_NODRAW;
|
||
|
pev->view_ofs = g_vecZero;
|
||
|
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
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
|
||
|
WRITE_BYTE( ENTINDEX(edict()) );
|
||
|
WRITE_STRING( "" );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
// Remove all the player's stuff
|
||
|
RemoveAllItems( FALSE );
|
||
|
|
||
|
// Move them to the new position
|
||
|
UTIL_SetOrigin( pev, vecPosition );
|
||
|
|
||
|
// Find a player to watch
|
||
|
m_flNextObserverInput = 0;
|
||
|
Observer_SetMode(OBS_ROAMING);
|
||
|
|
||
|
// Tell all clients this player is now a spectator
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgSpectator );
|
||
|
WRITE_BYTE( ENTINDEX( edict() ) );
|
||
|
WRITE_BYTE( 1 );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
pev->angles = pev->v_angle = vecViewAngle;
|
||
|
pev->fixangle = TRUE;
|
||
|
}
|
||
|
|
||
|
// 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_fWeapon = FALSE; // force weapon send
|
||
|
m_iHideHUD = 0;
|
||
|
}
|
||
|
|
||
|
// 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() );
|
||
|
pev->groupinfo = m_hObserverTarget->pev->groupinfo;
|
||
|
|
||
|
// Move to the target
|
||
|
if ( pev->iuser1 != OBS_LOCKEDVIEW )
|
||
|
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" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CBasePlayer::ObserverInput_ChangeMode()
|
||
|
{
|
||
|
if ( pev->iuser1 == OBS_ROAMING )
|
||
|
Observer_SetMode( OBS_CHASE_FREE );
|
||
|
else if ( pev->iuser1 == OBS_CHASE_FREE )
|
||
|
Observer_SetMode( OBS_LOCKEDVIEW );
|
||
|
else
|
||
|
Observer_SetMode( OBS_ROAMING );
|
||
|
}
|
||
|
|
||
|
void CBasePlayer::ObserverInput_NextPlayer()
|
||
|
{
|
||
|
if ( pev->iuser1 != OBS_ROAMING )
|
||
|
Observer_FindNextPlayer( false );
|
||
|
}
|
||
|
|
||
|
void CBasePlayer::ObserverInput_PrevPlayer()
|
||
|
{
|
||
|
if ( pev->iuser1 != OBS_ROAMING )
|
||
|
Observer_FindNextPlayer( true );
|
||
|
}
|
||
|
|
||
|
// Handle buttons in observer mode
|
||
|
void CBasePlayer::Observer_HandleButtons()
|
||
|
{
|
||
|
|
||
|
if ( m_flChangeAngles != -1 && m_flChangeAngles <= gpGlobals->time )
|
||
|
{
|
||
|
if ( pev->iuser1 == OBS_LOCKEDVIEW )
|
||
|
{
|
||
|
pev->angles = m_vecHitVelocity;
|
||
|
pev->fixangle = TRUE;
|
||
|
}
|
||
|
|
||
|
m_flChangeAngles = -1;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
|
||
|
// 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_FREE );
|
||
|
else if ( pev->iuser1 == OBS_CHASE_FREE )
|
||
|
Observer_SetMode( OBS_LOCKEDVIEW );
|
||
|
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;
|
||
|
pev->maxspeed = 320;
|
||
|
|
||
|
ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode3" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( iMode == OBS_LOCKEDVIEW )
|
||
|
{
|
||
|
// Find the spectator spawn position
|
||
|
CBaseEntity *pSpot = UTIL_FindEntityByClassname( NULL, "info_player_spectator");
|
||
|
|
||
|
if ( pSpot )
|
||
|
{
|
||
|
// Move them to the new position
|
||
|
UTIL_SetOrigin( pev, pSpot->pev->origin );
|
||
|
|
||
|
pev->iuser1 = OBS_LOCKEDVIEW;
|
||
|
|
||
|
m_flChangeAngles = gpGlobals->time + 0.1;
|
||
|
m_vecHitVelocity = pSpot->pev->v_angle;
|
||
|
pev->iuser2 = 0;
|
||
|
pev->maxspeed = 1;
|
||
|
}
|
||
|
|
||
|
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 == 0 )
|
||
|
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 = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" );
|
||
|
Observer_SetMode(OBS_ROAMING);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|