hlsdk-xash3d/dlls/aghl/agspectator.cpp

548 lines
12 KiB
C++

//++ BulliT
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
extern int gmsgTeamInfo;
extern int gmsgSetFOV;
extern int gmsgSplash;
extern int gmsgGamemode;
extern int g_teamplay;
void CBasePlayer::Spectate_Init()
{
m_fSpectateTime = AgTime();
m_iSpot = 0;
m_hSpectateTarget = NULL;
m_iSpectateWeapon = 0;
m_iSpectateAmmoClip = 0;
}
//Spectate code with parts from Robin Walkers Tutorial.
void CBasePlayer::Spectate_Spectate()
{
ASSERT(NULL != pev);
if (!pev)
return;
if (IsSpectator())
Spectate_Stop();
else
Spectate_Start();
}
bool CBasePlayer::Spectate_HLTV()
{
g_pGameRules->m_bProxyConnected = true;
//This is the valve proxy.
if (g_pGameRules->IsTeamplay())
{
strcpy(m_szTeamName,"");
g_engfuncs.pfnSetClientKeyValue( entindex(), g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "model", m_szTeamName );
g_engfuncs.pfnSetClientKeyValue( entindex(), g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "team", m_szTeamName );
g_pGameRules->RecountTeams();
}
g_pGameRules->UpdateGameMode(this);
g_pGameRules->ResendScoreBoard();
return true;
}
void CBasePlayer::Spectate_Start(bool bResetScore)
{
ASSERT(NULL != pev);
if (!pev)
return;
if (IsSpectator()) //Don't start it if already spectator or if its a player in the arena.
return;
if (IsProxy())
return;
//CTF
if (CTF == AgGametype())
g_pGameRules->m_CTF.PlayerDropFlag(this);
//Reset.
Spectate_Init();
//Set player as spectator.
pev->iuser1 = OBS_ROAMING;
pev->iuser2 = 0;
m_hSpectateTarget = NULL;
//Remove spectators from this player
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer* pPlayerLoop = AgPlayerByIndex(i);
if (pPlayerLoop && this != pPlayerLoop )
{
if ((CBaseEntity*)pPlayerLoop->m_hSpectateTarget == (CBaseEntity*)this)
{
//Move to next player.
pPlayerLoop->Spectate_Nextplayer(false);
}
}
}
// 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();
pev->health = 1; //Remove clientside screentilt. If you find this one helpful - give me credit because I spent 3 hours a friday night figuring it out!
EnableControl(TRUE);
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);
RemoveAllItemsNoClientMessage();
pev->deadflag = DEAD_DEAD;
pev->flags |= FL_SPECTATOR;
pev->flags |= FL_NOTARGET;
ClearBits( m_afPhysicsFlags, PFLAG_DUCKING );
ClearBits( pev->flags, FL_DUCKING );
SetBits(m_afPhysicsFlags, PFLAG_OBSERVER);
UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX);
pev->fixangle = TRUE;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
pev->movetype = MOVETYPE_NOCLIP;
pev->effects |= EF_NODRAW;
pev->view_ofs = g_vecZero;
m_hSpectateTarget = 0;
// clear attack/use commands from player
m_afButtonPressed = 0;
pev->button = 0;
m_afButtonReleased = 0;
m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH;
// reset FOV
pev->fov = m_iFOV = m_iClientFOV = 0;
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
MESSAGE_BEGIN(MSG_ALL,gmsgSpectator);
WRITE_BYTE( ENTINDEX(edict()) );
WRITE_BYTE(1);
MESSAGE_END();
//Change teamname
if (g_pGameRules->IsTeamplay())
{
MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
WRITE_BYTE( entindex() );
WRITE_STRING( TeamID() );
MESSAGE_END();
}
//Reset score
if (bResetScore)
ResetScore();
pev->nextthink = gpGlobals->time + 0.1f;
//Tell clients
UTIL_ClientPrintAll(HUD_PRINTNOTIFY, UTIL_VarArgs("%s entered spectator mode\n",GetName()));
//Put up splash screen for 10 secs :)
#ifndef AG_NO_CLIENT_DLL
MESSAGE_BEGIN( MSG_ONE_UNRELIABLE, gmsgSplash, NULL, pev );
WRITE_BYTE(10);
MESSAGE_END();
#endif
}
void CBasePlayer::Spectate_Stop(bool bIntermediateSpawn)
{
ASSERT(NULL != pev);
if (!pev)
return;
if (!IsSpectator())
return;
if (IsProxy())
return;
if (!g_pGameRules->FPlayerCanRespawn( this))
return;
EnableControl(TRUE);
//Reset flags.
Spectate_Init();
pev->flags &= ~FL_SPECTATOR;
pev->flags &= ~FL_NOTARGET;
pev->deadflag = DEAD_RESPAWNABLE;
pev->button = 0;
pev->iuser1 = OBS_NONE;
pev->iuser2 = 0;
pev->effects &= ~EF_NODRAW;
pev->movetype = MOVETYPE_WALK;
m_flRespawnTimer = 0;
m_bDoneFirstSpawn = !bIntermediateSpawn;
m_iHideHUD &= ~HIDEHUD_WEAPONS;
m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
m_iHideHUD &= ~HIDEHUD_HEALTH;
//Reset fov
pev->fov = m_iFOV = m_iClientFOV = 0;
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
//Remove spec
MESSAGE_BEGIN(MSG_ALL,gmsgSpectator);
WRITE_BYTE(ENTINDEX(edict()));
WRITE_BYTE(0);
MESSAGE_END();
//Change teamname
if (g_pGameRules->IsTeamplay())
{
MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
WRITE_BYTE( entindex() );
WRITE_STRING( TeamID() );
MESSAGE_END();
}
//Force data to be resent.
m_fKnownItem = FALSE; // Force weaponinit messages.
//Tell client(s)
UTIL_ClientPrintAll(HUD_PRINTNOTIFY, UTIL_VarArgs("%s left spectator mode\n",GetName()));
Spawn();
#ifndef AG_NO_CLIENT_DLL
//Remove splash screen
MESSAGE_BEGIN( MSG_ONE, gmsgSplash, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
#endif
}
// Find the next client in the game for this player to spectate
void CBasePlayer::Spectate_Nextplayer( bool bReverse )
{
ASSERT(NULL != pev);
if (!pev)
return;
if (IsProxy())
return;
// 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_hSpectateTarget != 0 )
iStart = ENTINDEX( m_hSpectateTarget->edict() );
else
iStart = ENTINDEX( edict() );
int iCurrent = iStart;
m_hSpectateTarget = 0;
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 = AgPlayerByIndex( iCurrent );
if ( !pEnt )
continue;
if ( pEnt == this )
continue;
// Don't spec observers or invisible players
if ( ((CBasePlayer*)pEnt)->IsSpectator() || (pEnt->pev->effects == EF_NODRAW) )
continue;
if (0 < ag_spec_enable_disable.value && ((CBasePlayer*)pEnt)->DisableSpecs())
continue;
m_hSpectateTarget = pEnt;
break;
}
while ( iCurrent != iStart );
// Did we find a target?
if (m_hSpectateTarget != 0 && m_hSpectateTarget->pev != 0)
{
// Store the target in pev so the physics DLL can get to it
pev->iuser2 = ENTINDEX( m_hSpectateTarget->edict() );
// Move to the target
UTIL_SetOrigin( pev, m_hSpectateTarget->pev->origin );
//ClientPrint(m_hSpectateTarget->pev, HUD_PRINTNOTIFY, UTIL_VarArgs("You are being watched by %s\n",STRING(pev->netname)));
}
else
{
//Go roaming.
Spectate_SetMode(OBS_ROAMING);
}
}
// Handle buttons in spectate mode
void CBasePlayer::Spectate_HandleButtons()
{
ASSERT(NULL != pev);
if (!pev)
return;
if (IsProxy())
return;
// Slow down mouse clicks
if ( m_fSpectateTime > AgTime() )
return;
pev->impulse = 0;
// Jump changes from modes: Chase to Roaming
if ( m_afButtonPressed & IN_JUMP )
{
//Reset fov
pev->fov = m_iFOV = m_iClientFOV = 0;
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
if ( pev->iuser1 == OBS_ROAMING )
Spectate_SetMode( OBS_IN_EYE );
else if ( pev->iuser1 == OBS_IN_EYE )
Spectate_SetMode( OBS_CHASE_LOCKED );
else if ( pev->iuser1 == OBS_CHASE_LOCKED )
Spectate_SetMode( OBS_CHASE_FREE );
else if ( pev->iuser1 == OBS_CHASE_FREE )
Spectate_SetMode( OBS_MAP_CHASE );
else if ( pev->iuser1 == OBS_MAP_CHASE)
Spectate_SetMode( OBS_MAP_FREE );
else if ( pev->iuser1 == OBS_MAP_FREE )
Spectate_SetMode( OBS_ROAMING );
else
Spectate_SetMode( OBS_ROAMING );
}
// Attack moves to the next player
if ( m_afButtonPressed & IN_ATTACK)
{
//Reset fov
pev->fov = m_iFOV = m_iClientFOV = 0;
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
if (pev->iuser2 != 0)
Spectate_Nextplayer(false);
else
Spectate_Nextspot(false);
m_fSpectateTime = AgTime() + 0.2;
}
// Attack2 moves to the prev player
if ( m_afButtonPressed & IN_ATTACK2)
{
//Reset fov
pev->fov = m_iFOV = m_iClientFOV = 0;
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
if (pev->iuser2 != 0)
Spectate_Nextplayer(true);
else
Spectate_Nextspot(true);
m_fSpectateTime = AgTime() + 0.2;
}
}
void CBasePlayer::Spectate_UpdatePosition()
{
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer* pPlayerLoop = AgPlayerByIndex(i);
if (pPlayerLoop && this != pPlayerLoop && pPlayerLoop->IsSpectator())
{
if ((CBaseEntity*)pPlayerLoop->m_hSpectateTarget == (CBaseEntity*)this)
{
if (pPlayerLoop->m_hSpectateTarget->pev)
{
//Update the spectators position
//pPlayerLoop->m_hSpectateTarget = (CBaseEntity*)this;
UTIL_SetOrigin( pPlayerLoop->pev, pev->origin );
}
}
}
}
}
// Attempt to change the spectate mode
void CBasePlayer::Spectate_SetMode( int iMode )
{
ASSERT(NULL != pev);
if (!pev)
return;
if (IsProxy() || !IsSpectator())
return;
// Just abort if we're changing to the mode we're already in
if ( iMode == pev->iuser1 )
return;
// Changing to Roaming or Map Free?
if ( iMode == OBS_ROAMING || iMode == OBS_MAP_FREE)
{
// MOD AUTHORS: If you don't want to allow roaming observers at all in your mod, just abort here.
pev->iuser1 = iMode;
pev->iuser2 = 0;
m_hSpectateTarget = NULL;
pev->weapons &= ~WEAPON_ALLWEAPONS;
m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH;
return;
}
// Changing to Chase Lock, Chase Freelook, Map Chase?
if (iMode == OBS_CHASE_FREE || iMode == OBS_MAP_CHASE || iMode == OBS_CHASE_LOCKED)
{
// If changing from Roaming, or starting observing, make sure there is a target
if ( m_hSpectateTarget == 0 )
Spectate_Nextplayer( false );
if( m_hSpectateTarget != 0 )
{
pev->iuser1 = iMode;
pev->iuser2 = ENTINDEX( m_hSpectateTarget->edict() );
pev->maxspeed = 0;
pev->weapons |= (1<<WEAPON_SUIT);
m_iHideHUD |= HIDEHUD_WEAPONS;
m_iHideHUD |= HIDEHUD_FLASHLIGHT;
m_iHideHUD &= ~HIDEHUD_HEALTH;
}
else
{
Spectate_SetMode(OBS_ROAMING);
}
return;
}
// Changing to in-eye?
if ( iMode == OBS_IN_EYE)
{
// If changing from Roaming, or starting observing, make sure there is a target
if ( m_hSpectateTarget == 0 )
Spectate_Nextplayer( false );
if (m_hSpectateTarget != 0)
{
pev->iuser1 = iMode;
pev->iuser2 = ENTINDEX( m_hSpectateTarget->edict() );
pev->maxspeed = 0;
pev->weapons |= (1<<WEAPON_SUIT);
m_iHideHUD &= ~HIDEHUD_WEAPONS;
m_iHideHUD |= HIDEHUD_FLASHLIGHT;
m_iHideHUD &= ~HIDEHUD_HEALTH;
}
else
{
Spectate_SetMode(OBS_ROAMING);
}
return;
}
}
bool CBasePlayer::Spectate_Think()
{
ASSERT(NULL != pev);
if (!pev)
return false;
if (IsProxy())
return false;
if (IsSpectator())
{
Spectate_HandleButtons();
return true;
}
return false;
}
// Find the next info intermission spot
void CBasePlayer::Spectate_Nextspot(bool bReverse)
{
ASSERT(NULL != pev);
if (!pev || !g_pGameRules)
return;
if (IsProxy())
return;
m_iSpot += bReverse ? -1 : 1;
//Check if out of bounds.
if (0 > m_iSpot)
m_iSpot = g_pGameRules->m_InfoInterMission.GetCount() - 1;
else if (m_iSpot >= g_pGameRules->m_InfoInterMission.GetCount())
m_iSpot = 0;
//Move the dude
edict_t* pSpot = g_pGameRules->m_InfoInterMission.GetSpot(m_iSpot);
if (pSpot)
MoveToInfoIntermission(pSpot);
}
bool CBasePlayer::Spectate_Follow(EHANDLE& pPlayer,int iMode)
{
if (IsProxy())
return true;
m_hSpectateTarget = pPlayer;
Spectate_SetMode(iMode);
return true;
}
//-- Martin Webrant