You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
416 lines
13 KiB
416 lines
13 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include <stdarg.h> |
|
#include "gamerules.h" |
|
#include "player.h" |
|
#include "model_types.h" |
|
#include "movehelper_server.h" |
|
#include "shake.h" // For screen fade constants |
|
#include "engine/IEngineSound.h" |
|
|
|
//============================================================================= |
|
// HPE_BEGIN |
|
// [dwenger] Necessary for stats tracking |
|
//============================================================================= |
|
#ifdef CSTRIKE_DLL |
|
|
|
#include "cs_gamestats.h" |
|
#include "cs_achievement_constants.h" |
|
|
|
#endif |
|
//============================================================================= |
|
// HPE_END |
|
//============================================================================= |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
extern IPhysicsCollision *physcollision; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Implementation of the movehelper on the server |
|
//----------------------------------------------------------------------------- |
|
|
|
class CMoveHelperServer : public IMoveHelperServer |
|
{ |
|
public: |
|
CMoveHelperServer( void ); |
|
virtual ~CMoveHelperServer(); |
|
|
|
// Methods associated with a particular entity |
|
virtual char const* GetName( EntityHandle_t handle ) const; |
|
|
|
// Touch list... |
|
virtual void ResetTouchList( void ); |
|
virtual bool AddToTouched( const trace_t &tr, const Vector& impactvelocity ); |
|
virtual void ProcessImpacts( void ); |
|
|
|
virtual bool PlayerFallingDamage( void ); |
|
virtual void PlayerSetAnimation( PLAYER_ANIM eAnim ); |
|
|
|
// Numbered line printf |
|
virtual void Con_NPrintf( int idx, char const* fmt, ... ); |
|
|
|
// These have separate server vs client impementations |
|
virtual void StartSound( const Vector& origin, int channel, char const* sample, float volume, soundlevel_t soundlevel, int fFlags, int pitch ); |
|
virtual void StartSound( const Vector& origin, const char *soundname ); |
|
|
|
virtual void PlaybackEventFull( int flags, int clientindex, unsigned short eventindex, float delay, Vector& origin, Vector& angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); |
|
virtual IPhysicsSurfaceProps *GetSurfaceProps( void ); |
|
|
|
void SetHost( CBasePlayer *host ); |
|
|
|
virtual bool IsWorldEntity( const CBaseHandle &handle ); |
|
|
|
private: |
|
CBasePlayer* m_pHostPlayer; |
|
|
|
// results, tallied on client and server, but only used by server to run SV_Impact. |
|
// we store off our velocity in the trace_t structure so that we can determine results |
|
// of shoving boxes etc. around. |
|
struct touchlist_t |
|
{ |
|
Vector deltavelocity; |
|
trace_t trace; |
|
}; |
|
|
|
CUtlVector<touchlist_t> m_TouchList; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Singleton |
|
//----------------------------------------------------------------------------- |
|
|
|
IMPLEMENT_MOVEHELPER(); |
|
|
|
IMoveHelperServer* MoveHelperServer() |
|
{ |
|
static CMoveHelperServer s_MoveHelperServer; |
|
return &s_MoveHelperServer; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Converts the entity handle into a edict_t |
|
//----------------------------------------------------------------------------- |
|
|
|
static inline edict_t* GetEdict( EntityHandle_t handle ) |
|
{ |
|
return gEntList.GetEdict( handle ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Constructor |
|
//----------------------------------------------------------------------------- |
|
|
|
CMoveHelperServer::CMoveHelperServer( void ) : m_TouchList( 0, 128 ) |
|
{ |
|
m_pHostPlayer = 0; |
|
SetSingleton( this ); |
|
} |
|
|
|
CMoveHelperServer::~CMoveHelperServer( void ) |
|
{ |
|
SetSingleton( 0 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Indicates which player we're going to move |
|
//----------------------------------------------------------------------------- |
|
|
|
void CMoveHelperServer::SetHost( CBasePlayer *host ) |
|
{ |
|
m_pHostPlayer = host; |
|
|
|
// In case any stuff is ever left over, sigh... |
|
ResetTouchList(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the name for debugging purposes |
|
//----------------------------------------------------------------------------- |
|
char const* CMoveHelperServer::GetName( EntityHandle_t handle ) const |
|
{ |
|
// This ain't pertickulerly fast, but it's for debugging anyways |
|
edict_t* pEdict = GetEdict(handle); |
|
CBaseEntity *ent = CBaseEntity::Instance( pEdict ); |
|
|
|
// Is it the world? |
|
if (ENTINDEX(pEdict) == 0) |
|
return STRING(gpGlobals->mapname); |
|
|
|
// Is it a model? |
|
if ( ent && ent->GetModelName() != NULL_STRING ) |
|
return STRING( ent->GetModelName() ); |
|
|
|
if ( ent->GetClassname() != NULL ) |
|
{ |
|
return ent->GetClassname(); |
|
} |
|
|
|
return "?"; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// When we do a collision test, we report everything we hit.. |
|
//----------------------------------------------------------------------------- |
|
|
|
void CMoveHelperServer::ResetTouchList( void ) |
|
{ |
|
m_TouchList.RemoveAll(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// When a collision occurs, we add it to the touched list |
|
//----------------------------------------------------------------------------- |
|
|
|
bool CMoveHelperServer::AddToTouched( const trace_t &tr, const Vector& impactvelocity ) |
|
{ |
|
Assert( m_pHostPlayer ); |
|
|
|
// Trace missed |
|
if ( !tr.m_pEnt ) |
|
return false; |
|
|
|
if ( tr.m_pEnt == m_pHostPlayer ) |
|
{ |
|
Assert( !"CMoveHelperServer::AddToTouched: Tried to add self to touchlist!!!" ); |
|
return false; |
|
} |
|
|
|
// Check for duplicate entities |
|
for ( int j = m_TouchList.Size(); --j >= 0; ) |
|
{ |
|
if ( m_TouchList[j].trace.m_pEnt == tr.m_pEnt ) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
int i = m_TouchList.AddToTail(); |
|
m_TouchList[i].trace = tr; |
|
VectorCopy( impactvelocity, m_TouchList[i].deltavelocity ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// After we built the touch list, deal with all the impacts... |
|
//----------------------------------------------------------------------------- |
|
void CMoveHelperServer::ProcessImpacts( void ) |
|
{ |
|
Assert( m_pHostPlayer ); |
|
|
|
// Relink in order to build absorigin and absmin/max to reflect any changes |
|
// from prediction. Relink will early out on SOLID_NOT |
|
m_pHostPlayer->PhysicsTouchTriggers(); |
|
|
|
// Don't bother if the player ain't solid |
|
if ( m_pHostPlayer->IsSolidFlagSet( FSOLID_NOT_SOLID ) ) |
|
return; |
|
|
|
// Save off the velocity, cause we need to temporarily reset it |
|
Vector vel = m_pHostPlayer->GetAbsVelocity(); |
|
|
|
// Touch other objects that were intersected during the movement. |
|
for (int i = 0 ; i < m_TouchList.Size(); i++) |
|
{ |
|
CBaseHandle entindex = m_TouchList[i].trace.m_pEnt->GetRefEHandle(); |
|
|
|
// We should have culled negative indices by now |
|
Assert( entindex.IsValid() ); |
|
|
|
edict_t* ent = GetEdict( entindex ); |
|
if (!ent) |
|
continue; |
|
|
|
// Run the impact function as if we had run it during movement. |
|
CBaseEntity *entity = GetContainingEntity( ent ); |
|
if ( !entity ) |
|
continue; |
|
|
|
Assert( entity != m_pHostPlayer ); |
|
// Don't ever collide with self!!!! |
|
if ( entity == m_pHostPlayer ) |
|
continue; |
|
|
|
// Reconstruct trace results. |
|
m_TouchList[i].trace.m_pEnt = CBaseEntity::Instance( ent ); |
|
|
|
// Use the velocity we had when we collided, so boxes will move, etc. |
|
m_pHostPlayer->SetAbsVelocity( m_TouchList[i].deltavelocity ); |
|
|
|
entity->PhysicsImpact( m_pHostPlayer, m_TouchList[i].trace ); |
|
} |
|
|
|
// Restore the velocity |
|
m_pHostPlayer->SetAbsVelocity( vel ); |
|
|
|
// So no stuff is ever left over, sigh... |
|
ResetTouchList(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : origin - |
|
// *soundname - |
|
//----------------------------------------------------------------------------- |
|
void CMoveHelperServer::StartSound( const Vector& origin, const char *soundname ) |
|
{ |
|
//MDB - Changing this to send to PAS, as the overloaded function below has done. |
|
//Also removed the UsePredictionRules, client does not yet play the equivalent sound |
|
|
|
CRecipientFilter filter; |
|
filter.AddRecipientsByPAS( origin ); |
|
|
|
CBaseEntity::EmitSound( filter, m_pHostPlayer->entindex(), soundname ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// plays a sound |
|
//----------------------------------------------------------------------------- |
|
void CMoveHelperServer::StartSound( const Vector& origin, int channel, char const* sample, |
|
float volume, soundlevel_t soundlevel, int fFlags, int pitch ) |
|
{ |
|
|
|
CRecipientFilter filter; |
|
filter.AddRecipientsByPAS( origin ); |
|
// FIXME, these sounds should not go to the host entity ( SND_NOTHOST ) |
|
if ( gpGlobals->maxClients == 1 ) |
|
{ |
|
// Always send sounds down in SP |
|
|
|
EmitSound_t ep; |
|
ep.m_nChannel = channel; |
|
ep.m_pSoundName = sample; |
|
ep.m_flVolume = volume; |
|
ep.m_SoundLevel = soundlevel; |
|
ep.m_nFlags = fFlags; |
|
ep.m_nPitch = pitch; |
|
ep.m_pOrigin = &origin; |
|
|
|
CBaseEntity::EmitSound( filter, m_pHostPlayer->entindex(), ep ); |
|
} |
|
else |
|
{ |
|
filter.UsePredictionRules(); |
|
|
|
EmitSound_t ep; |
|
ep.m_nChannel = channel; |
|
ep.m_pSoundName = sample; |
|
ep.m_flVolume = volume; |
|
ep.m_SoundLevel = soundlevel; |
|
ep.m_nFlags = fFlags; |
|
ep.m_nPitch = pitch; |
|
ep.m_pOrigin = &origin; |
|
|
|
CBaseEntity::EmitSound( filter, m_pHostPlayer->entindex(), ep ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Umm... |
|
//----------------------------------------------------------------------------- |
|
void CMoveHelperServer::PlaybackEventFull( int flags, int clientindex, unsigned short eventindex, float delay, Vector& origin, Vector& angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) |
|
{ |
|
// FIXME, Redo with new event system parameter stuff |
|
} |
|
|
|
IPhysicsSurfaceProps *CMoveHelperServer::GetSurfaceProps( void ) |
|
{ |
|
extern IPhysicsSurfaceProps *physprops; |
|
return physprops; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Note that this only works on a listen server (since it requires graphical output) |
|
// *pFormat - |
|
// ... - |
|
//----------------------------------------------------------------------------- |
|
void CMoveHelperServer::Con_NPrintf( int idx, char const* pFormat, ...) |
|
{ |
|
va_list marker; |
|
char msg[8192]; |
|
|
|
va_start(marker, pFormat); |
|
Q_vsnprintf(msg, sizeof( msg ), pFormat, marker); |
|
va_end(marker); |
|
|
|
engine->Con_NPrintf( idx, msg ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when the player falls onto a surface fast enough to take |
|
// damage, according to the rules in CGameMovement::CheckFalling. |
|
// Output : Returns true if the player survived the fall, false if they died. |
|
//----------------------------------------------------------------------------- |
|
bool CMoveHelperServer::PlayerFallingDamage( void ) |
|
{ |
|
float flFallDamage = g_pGameRules->FlPlayerFallDamage( m_pHostPlayer ); |
|
if ( flFallDamage > 0 ) |
|
{ |
|
m_pHostPlayer->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), flFallDamage, DMG_FALL ) ); |
|
StartSound( m_pHostPlayer->GetAbsOrigin(), "Player.FallDamage" ); |
|
|
|
//============================================================================= |
|
// HPE_BEGIN: |
|
// [dwenger] Needed for fun-fact implementation |
|
//============================================================================= |
|
|
|
#ifdef CSTRIKE_DLL |
|
|
|
// Increment the stat for fall damage |
|
CCSPlayer* pPlayer = ToCSPlayer(m_pHostPlayer); |
|
|
|
if ( pPlayer ) |
|
{ |
|
CCS_GameStats.IncrementStat( pPlayer, CSSTAT_FALL_DAMAGE, (int)flFallDamage ); |
|
} |
|
|
|
#endif |
|
//============================================================================= |
|
// HPE_END |
|
//============================================================================= |
|
|
|
} |
|
|
|
if ( m_pHostPlayer->m_iHealth <= 0 ) |
|
{ |
|
if ( g_pGameRules->FlPlayerFallDeathDoesScreenFade( m_pHostPlayer ) ) |
|
{ |
|
color32 black = {0, 0, 0, 255}; |
|
UTIL_ScreenFade( m_pHostPlayer, black, 0, 9999, FFADE_OUT | FFADE_STAYOUT ); |
|
} |
|
return(false); |
|
} |
|
|
|
return(true); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets an animation in the player. |
|
// Input : eAnim - Animation to set. |
|
//----------------------------------------------------------------------------- |
|
void CMoveHelperServer::PlayerSetAnimation( PLAYER_ANIM eAnim ) |
|
{ |
|
m_pHostPlayer->SetAnimation( eAnim ); |
|
} |
|
|
|
bool CMoveHelperServer::IsWorldEntity( const CBaseHandle &handle ) |
|
{ |
|
return handle == CBaseEntity::Instance( 0 ); |
|
}
|
|
|