initial
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Drops particles where the entity was.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "entityparticletrail_shared.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Default values
|
||||
//-----------------------------------------------------------------------------
|
||||
EntityParticleTrailInfo_t::EntityParticleTrailInfo_t()
|
||||
{
|
||||
m_strMaterialName = NULL_STRING;
|
||||
m_flLifetime = 4.0f;
|
||||
m_flStartSize = 2.0f;
|
||||
m_flEndSize = 3.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Save/load
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
BEGIN_SIMPLE_DATADESC( EntityParticleTrailInfo_t )
|
||||
|
||||
DEFINE_KEYFIELD( m_strMaterialName, FIELD_STRING, "ParticleTrailMaterial" ),
|
||||
DEFINE_KEYFIELD( m_flLifetime, FIELD_FLOAT, "ParticleTrailLifetime" ),
|
||||
DEFINE_KEYFIELD( m_flStartSize, FIELD_FLOAT, "ParticleTrailStartSize" ),
|
||||
DEFINE_KEYFIELD( m_flEndSize, FIELD_FLOAT, "ParticleTrailEndSize" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Networking
|
||||
//-----------------------------------------------------------------------------
|
||||
BEGIN_NETWORK_TABLE_NOBASE( EntityParticleTrailInfo_t, DT_EntityParticleTrailInfo )
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropFloat( RECVINFO( m_flLifetime ) ),
|
||||
RecvPropFloat( RECVINFO( m_flStartSize ) ),
|
||||
RecvPropFloat( RECVINFO( m_flEndSize ) ),
|
||||
#else
|
||||
SendPropFloat( SENDINFO( m_flLifetime ), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO( m_flStartSize ), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO( m_flEndSize ), 0, SPROP_NOSCALE ),
|
||||
#endif
|
||||
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
//========= Copyright (c) 1996-2006, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef GAME_EVENT_LISTENER_H
|
||||
#define GAME_EVENT_LISTENER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "igameevents.h"
|
||||
extern IGameEventManager2 *gameeventmanager;
|
||||
|
||||
// A safer method than inheriting straight from IGameEventListener2.
|
||||
// Avoids requiring the user to remove themselves as listeners in
|
||||
// their deconstructor, and sets the serverside variable based on
|
||||
// our dll location.
|
||||
class CGameEventListener : public IGameEventListener2
|
||||
{
|
||||
public:
|
||||
CGameEventListener() : m_bRegisteredForEvents(false)
|
||||
{
|
||||
m_nDebugID = EVENT_DEBUG_ID_INIT;
|
||||
}
|
||||
|
||||
~CGameEventListener()
|
||||
{
|
||||
m_nDebugID = EVENT_DEBUG_ID_SHUTDOWN;
|
||||
StopListeningForAllEvents();
|
||||
}
|
||||
|
||||
void ListenForGameEvent( const char *name )
|
||||
{
|
||||
m_bRegisteredForEvents = true;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool bServerSide = false;
|
||||
#else
|
||||
bool bServerSide = true;
|
||||
#endif
|
||||
|
||||
gameeventmanager->AddListener( this, name, bServerSide );
|
||||
}
|
||||
|
||||
void ListenForAllGameEvents()
|
||||
{
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool bServerSide = false;
|
||||
#else
|
||||
bool bServerSide = true;
|
||||
#endif
|
||||
|
||||
gameeventmanager->AddListenerGlobal( this, bServerSide );
|
||||
}
|
||||
|
||||
|
||||
void StopListeningForAllEvents()
|
||||
{
|
||||
// remove me from list
|
||||
if ( m_bRegisteredForEvents )
|
||||
{
|
||||
if ( gameeventmanager )
|
||||
gameeventmanager->RemoveListener( this );
|
||||
|
||||
m_bRegisteredForEvents = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Intentionally abstract
|
||||
virtual void FireGameEvent( IGameEvent *event ) = 0;
|
||||
int m_nDebugID;
|
||||
virtual int GetEventDebugID( void ) { return m_nDebugID; }
|
||||
|
||||
private:
|
||||
|
||||
// Have we registered for any events?
|
||||
bool m_bRegisteredForEvents;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,480 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GAMESTATS_H
|
||||
#define GAMESTATS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utldict.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "igamesystem.h"
|
||||
|
||||
const int GAMESTATS_VERSION = 1;
|
||||
|
||||
enum StatSendType_t
|
||||
{
|
||||
STATSEND_LEVELSHUTDOWN,
|
||||
STATSEND_APPSHUTDOWN
|
||||
};
|
||||
|
||||
struct StatsBufferRecord_t
|
||||
{
|
||||
float m_flFrameRate; // fps
|
||||
float m_flServerPing; // client ping to server
|
||||
float m_flMainThreadTimeMS; // time in ms taken by the main thread
|
||||
float m_flMainThreadWaitTimeMS; // time in ms the main thread is waiting for the render thread (cf EndFrame)
|
||||
float m_flRenderThreadTimeMS; // time in ms taken by the render thread
|
||||
float m_flRenderThreadWaitTimeMS; // time in ms waiting for the gpu (time spent in ForceHardwareSync)
|
||||
|
||||
bool operator< ( const StatsBufferRecord_t &a) const
|
||||
{
|
||||
return m_flFrameRate < a.m_flFrameRate;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CFpsHistory
|
||||
{
|
||||
public:
|
||||
enum FpsEnum_t
|
||||
{
|
||||
FPS_120,
|
||||
FPS_90,
|
||||
FPS_60,
|
||||
FPS_45,
|
||||
FPS_30,
|
||||
FPS_20,
|
||||
FPS_10,
|
||||
FPS_LOW,
|
||||
FPS_BIN_COUNT
|
||||
};
|
||||
|
||||
enum HistoryBufSizeEnum_t { HISTORY_BUF_SIZE = 32 };
|
||||
struct Rec_t
|
||||
{
|
||||
float m_flFps;
|
||||
float m_flCpuWait;
|
||||
};
|
||||
|
||||
CFpsHistory()
|
||||
{
|
||||
V_memset( this, 0, sizeof( *this ) );
|
||||
}
|
||||
|
||||
uint8 Update( float flFps, float flCpuWait );
|
||||
|
||||
uint8 operator []( int i ) const
|
||||
{
|
||||
return m_History[ ( m_nNext + HISTORY_BUF_SIZE - 1 - i ) % HISTORY_BUF_SIZE ];
|
||||
}
|
||||
|
||||
|
||||
int m_nNext;
|
||||
uint8 m_History[ HISTORY_BUF_SIZE ];
|
||||
|
||||
};
|
||||
|
||||
|
||||
class CFpsHistogram
|
||||
{
|
||||
public:
|
||||
enum FpsEnum_t
|
||||
{
|
||||
FPS_BIN_COUNT = CFpsHistory::FPS_BIN_COUNT
|
||||
};
|
||||
|
||||
CFpsHistogram()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
void Reset()
|
||||
{
|
||||
V_memset( this, 0, sizeof( *this ) );
|
||||
}
|
||||
void Update( uint8 nBin )
|
||||
{
|
||||
m_nFps[ nBin & ( FPS_BIN_COUNT - 1 ) ]++;
|
||||
m_nCpuWaits[ nBin & ( FPS_BIN_COUNT - 1 ) ] += ( nBin >> 7 );
|
||||
}
|
||||
int64 Encode()const;
|
||||
protected:
|
||||
uint32 m_nFps[ FPS_BIN_COUNT ];
|
||||
uint32 m_nCpuWaits[ FPS_BIN_COUNT ];
|
||||
};
|
||||
|
||||
|
||||
class CFpsSelectiveHistogram: public CFpsHistogram
|
||||
{
|
||||
public:
|
||||
CFpsSelectiveHistogram()
|
||||
{
|
||||
m_nLookAhead = 0;
|
||||
m_nLookBack = 0;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
V_memset( this, 0, sizeof( *this ) );
|
||||
}
|
||||
|
||||
void Fire( int nLookAhead, int nLookBack, const CFpsHistory &history )
|
||||
{
|
||||
// get the prerecorded stats
|
||||
if ( m_nLookAhead < nLookAhead )
|
||||
{
|
||||
m_nLookAhead = nLookAhead;
|
||||
}
|
||||
int nCatchUp = MIN( nLookBack, m_nLookBack );
|
||||
// exhaust back-stats buffer
|
||||
for ( int i = 0; i < nCatchUp; ++i )
|
||||
{
|
||||
CFpsHistogram::Update( history[ i ] );
|
||||
}
|
||||
|
||||
m_nLookBack = 0;
|
||||
}
|
||||
|
||||
void Update( uint8 nBin )
|
||||
{
|
||||
if ( m_nLookAhead > 0 )
|
||||
{
|
||||
m_nLookAhead--;
|
||||
CFpsHistogram::Update( nBin );
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_nLookBack;
|
||||
}
|
||||
}
|
||||
int GetInactiveCount() const { return m_nLookBack; }
|
||||
void ResetInactiveCount() { m_nLookBack = 0; }
|
||||
|
||||
protected:
|
||||
int m_nLookAhead; // this is how many more frames we need to collect statistics (stay active)
|
||||
int m_nLookBack; // this is how many frames we skipped (did not collect statistics)
|
||||
};
|
||||
|
||||
|
||||
enum PerfStatsEventEnum_t
|
||||
{
|
||||
PERF_STATS_SMOKE,
|
||||
PERF_STATS_BULLET,
|
||||
PERF_STATS_PLAYER,
|
||||
PERF_STATS_PLAYER_SPAWN,
|
||||
PERF_STATS_EVENT_COUNT
|
||||
};
|
||||
|
||||
#define STATS_WINDOW_SIZE ( 60 * 10 ) // # of records to hold
|
||||
#define STATS_TRAILING_WINDOW_SIZE ( 30 ) // # of records to hold in trailing window prior to stat recording
|
||||
#define STATS_RECORD_INTERVAL 1 // # of seconds between data grabs. 2 * 300 = every 10 minutes
|
||||
|
||||
class CGameStats;
|
||||
|
||||
void UpdatePerfStats( void );
|
||||
void FirePerfStatsEvent( PerfStatsEventEnum_t nEvent, int nLookAhead = CFpsHistory::HISTORY_BUF_SIZE, int nLookBack = CFpsHistory::HISTORY_BUF_SIZE );
|
||||
void SetGameStatsHandler( CGameStats *pGameStats );
|
||||
|
||||
class CBasePlayer;
|
||||
class CPropVehicleDriveable;
|
||||
class CTakeDamageInfo;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
#define GAMESTATS_STANDARD_NOT_SAVED 0xFEEDBEEF
|
||||
|
||||
enum GameStatsVersions_t
|
||||
{
|
||||
GAMESTATS_FILE_VERSION_OLD = 001,
|
||||
GAMESTATS_FILE_VERSION_OLD2,
|
||||
GAMESTATS_FILE_VERSION_OLD3,
|
||||
GAMESTATS_FILE_VERSION_OLD4,
|
||||
GAMESTATS_FILE_VERSION_OLD5,
|
||||
GAMESTATS_FILE_VERSION
|
||||
};
|
||||
|
||||
struct BasicGameStatsRecord_t
|
||||
{
|
||||
public:
|
||||
BasicGameStatsRecord_t() :
|
||||
m_nCount( 0 ),
|
||||
m_nSeconds( 0 ),
|
||||
m_nCommentary( 0 ),
|
||||
m_nHDR( 0 ),
|
||||
m_nCaptions( 0 ),
|
||||
m_bSteam( true ),
|
||||
m_bCyberCafe( false ),
|
||||
m_nDeaths( 0 )
|
||||
{
|
||||
Q_memset( m_nSkill, 0, sizeof( m_nSkill ) );
|
||||
}
|
||||
|
||||
void Clear();
|
||||
|
||||
void SaveToBuffer( CUtlBuffer& buf );
|
||||
bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion );
|
||||
|
||||
// Data
|
||||
public:
|
||||
int m_nCount;
|
||||
int m_nSeconds;
|
||||
|
||||
int m_nCommentary;
|
||||
int m_nHDR;
|
||||
int m_nCaptions;
|
||||
int m_nSkill[ 3 ];
|
||||
bool m_bSteam;
|
||||
bool m_bCyberCafe;
|
||||
int m_nDeaths;
|
||||
};
|
||||
|
||||
struct BasicGameStats_t
|
||||
{
|
||||
public:
|
||||
BasicGameStats_t() :
|
||||
m_nSecondsToCompleteGame( 0 ),
|
||||
m_bSteam( true ),
|
||||
m_bCyberCafe( false ),
|
||||
m_nDXLevel( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void Clear();
|
||||
|
||||
void SaveToBuffer( CUtlBuffer& buf );
|
||||
bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion );
|
||||
|
||||
BasicGameStatsRecord_t *FindOrAddRecordForMap( char const *mapname );
|
||||
|
||||
// Data
|
||||
public:
|
||||
int m_nSecondsToCompleteGame; // 0 means they haven't finished playing yet
|
||||
|
||||
BasicGameStatsRecord_t m_Summary; // Summary record
|
||||
CUtlDict< BasicGameStatsRecord_t, unsigned short > m_MapTotals;
|
||||
bool m_bSteam;
|
||||
bool m_bCyberCafe;
|
||||
int m_nDXLevel;
|
||||
};
|
||||
#endif // GAME_DLL
|
||||
|
||||
class CBaseGameStats
|
||||
{
|
||||
public:
|
||||
CBaseGameStats();
|
||||
|
||||
// override this to declare what format you want to send. New products should use new format.
|
||||
virtual bool UseOldFormat()
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
return true; // servers by default send old format for backward compat
|
||||
#else
|
||||
return false; // clients never used old format so no backward compat issues, they use new format by default
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implement this if you support new format gamestats.
|
||||
// Return true if you added data to KeyValues, false if you have no data to report
|
||||
virtual bool AddDataForSend( KeyValues *pKV, StatSendType_t sendType ) { return false; }
|
||||
|
||||
// These methods used for new format gamestats only and control when data gets sent.
|
||||
virtual bool ShouldSendDataOnLevelShutdown()
|
||||
{
|
||||
// by default, servers send data at every level change and clients don't
|
||||
#ifdef GAME_DLL
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
virtual bool ShouldSendDataOnAppShutdown()
|
||||
{
|
||||
// by default, clients send data at app shutdown and servers don't
|
||||
#ifdef GAME_DLL
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void Event_Init( void );
|
||||
virtual void Event_Shutdown( void );
|
||||
virtual void Event_MapChange( const char *szOldMapName, const char *szNewMapName );
|
||||
virtual void Event_LevelInit( void );
|
||||
virtual void Event_LevelShutdown( float flElapsed );
|
||||
virtual void Event_SaveGame( void );
|
||||
virtual void Event_LoadGame( void );
|
||||
|
||||
void StatsLog( PRINTF_FORMAT_STRING char const *fmt, ... );
|
||||
|
||||
// This is the first call made, so that we can "subclass" the CBaseGameStats based on gamedir as needed (e.g., ep2 vs. episodic)
|
||||
virtual CBaseGameStats *OnInit( CBaseGameStats *pCurrentGameStats, char const *gamedir ) { return pCurrentGameStats; }
|
||||
|
||||
// Frees up data from gamestats and resets it to a clean state.
|
||||
virtual void Clear( void );
|
||||
|
||||
virtual bool StatTrackingEnabledForMod( void ) { return false; } //Override this to turn on the system. Stat tracking is disabled by default and will always be disabled at the user's request
|
||||
static bool StatTrackingAllowed( void ); //query whether stat tracking is possible and warranted by the user
|
||||
virtual bool HaveValidData( void ) { return true; } // whether we currently have an interesting enough data set to upload. Called at upload time; if false, data is not uploaded.
|
||||
|
||||
virtual bool ShouldTrackStandardStats( void ) { return true; } //exactly what was tracked for EP1 release
|
||||
|
||||
//Get mod specific strings used for tracking, defaults should work fine for most cases
|
||||
virtual const char *GetStatSaveFileName( void );
|
||||
virtual const char *GetStatUploadRegistryKeyName( void );
|
||||
const char *GetUserPseudoUniqueID( void );
|
||||
|
||||
virtual bool UserPlayedAllTheMaps( void ) { return false; } //be sure to override this to determine user completion time
|
||||
|
||||
#ifdef GAME_DLL
|
||||
virtual void Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info );
|
||||
virtual void Event_PlayerConnected( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_PlayerDisconnected( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info );
|
||||
virtual void Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info );
|
||||
virtual void Event_Credits();
|
||||
virtual void Event_Commentary();
|
||||
virtual void Event_CrateSmashed();
|
||||
virtual void Event_Punted( CBaseEntity *pObject );
|
||||
virtual void Event_PlayerTraveled( CBasePlayer *pBasePlayer, float distanceInInches, bool bInVehicle, bool bSprinting );
|
||||
virtual void Event_WeaponFired( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName );
|
||||
virtual void Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info );
|
||||
virtual void Event_FlippedVehicle( CBasePlayer *pDriver, CPropVehicleDriveable *pVehicle );
|
||||
virtual void Event_PreSaveGameLoaded( char const *pSaveName, bool bInGame );
|
||||
virtual void Event_PlayerEnteredGodMode( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_PlayerEnteredNoClip( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_DecrementPlayerEnteredNoClip( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_IncrementCountedStatistic( const Vector& vecAbsOrigin, char const *pchStatisticName, float flIncrementAmount );
|
||||
virtual void Event_WindowShattered( CBasePlayer *pPlayer );
|
||||
|
||||
//custom data to tack onto existing stats if you're not doing a complete overhaul
|
||||
virtual void AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer ) { } //custom data you want thrown into the default save and upload path
|
||||
virtual void LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer ) { }; //when loading the saved stats file, this will point to where you started saving data to the save buffer
|
||||
|
||||
virtual void LoadingEvent_PlayerIDDifferentThanLoadedStats( void ); //Only called if you use the base SaveToFileNOW() and LoadFromFile() functions. Used in case you want to keep/invalidate data that was just loaded.
|
||||
|
||||
virtual bool LoadFromFile( void ); //called just before Event_Init()
|
||||
virtual bool SaveToFileNOW( bool bForceSyncWrite = false ); //saves buffers to their respective files now, returns success or failure
|
||||
virtual bool UploadStatsFileNOW( void ); //uploads data to the CSER now, returns success or failure
|
||||
|
||||
static bool AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData );
|
||||
static bool GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive = false );
|
||||
static void LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData );
|
||||
|
||||
//default save behavior is to save on level shutdown, and game shutdown
|
||||
virtual bool AutoSave_OnInit( void ) { return false; }
|
||||
virtual bool AutoSave_OnShutdown( void ) { return true; }
|
||||
virtual bool AutoSave_OnMapChange( void ) { return false; }
|
||||
virtual bool AutoSave_OnLevelInit( void ) { return false; }
|
||||
virtual bool AutoSave_OnLevelShutdown( void ) { return true; }
|
||||
|
||||
//default upload behavior is to upload on game shutdown
|
||||
virtual bool AutoUpload_OnInit( void ) { return false; }
|
||||
virtual bool AutoUpload_OnShutdown( void ) { return true; }
|
||||
virtual bool AutoUpload_OnMapChange( void ) { return false; }
|
||||
virtual bool AutoUpload_OnLevelInit( void ) { return false; }
|
||||
virtual bool AutoUpload_OnLevelShutdown( void ) { return false; }
|
||||
|
||||
// Helper for builtin stuff
|
||||
void SetSteamStatistic( bool bUsingSteam );
|
||||
void SetCyberCafeStatistic( bool bIsCyberCafeUser );
|
||||
void SetHDRStatistic( bool bHDREnabled );
|
||||
void SetCaptionsStatistic( bool bClosedCaptionsEnabled );
|
||||
void SetSkillStatistic( int iSkillSetting );
|
||||
void SetDXLevelStatistic( int iDXLevel );
|
||||
#endif // GAMEDLL
|
||||
public:
|
||||
#ifdef GAME_DLL
|
||||
BasicGameStats_t m_BasicStats; //exposed in case you do a complete overhaul and still want to save it
|
||||
#endif
|
||||
bool m_bLogging : 1;
|
||||
bool m_bLoggingToFile : 1;
|
||||
};
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &SaveBuffer -
|
||||
// iLump -
|
||||
// iLumpCount -
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CBaseGameStats::AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData )
|
||||
{
|
||||
// Verify the lump index.
|
||||
Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) );
|
||||
|
||||
if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) )
|
||||
return false;
|
||||
|
||||
// Check to see if we have any elements to save.
|
||||
if ( iLumpCount <= 0 )
|
||||
return false;
|
||||
|
||||
// Write the lump id and element count.
|
||||
SaveBuffer.PutUnsignedShort( iLump );
|
||||
SaveBuffer.PutUnsignedShort( iLumpCount );
|
||||
|
||||
size_t nTotalSize = iLumpCount * nSize;
|
||||
SaveBuffer.Put( pData, nTotalSize );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &LoadBuffer -
|
||||
// &iLump -
|
||||
// &iLumpCount -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CBaseGameStats::GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive /*= false*/ )
|
||||
{
|
||||
// Get the lump id and element count.
|
||||
iLump = LoadBuffer.GetUnsignedShort();
|
||||
if ( !LoadBuffer.IsValid() )
|
||||
{
|
||||
// check for EOF
|
||||
return false;
|
||||
}
|
||||
iLumpCount = LoadBuffer.GetUnsignedShort();
|
||||
|
||||
if ( bPermissive )
|
||||
return true;
|
||||
|
||||
// Verify the lump index.
|
||||
Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) );
|
||||
if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if we have any elements to save.
|
||||
if ( iLumpCount <= 0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Loads 1 or more lumps of raw data
|
||||
// Input : &LoadBuffer - buffer to be read from
|
||||
// iLumpCount - # of lumps to read
|
||||
// nSize - size of each lump
|
||||
// pData - where to store the data
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CBaseGameStats::LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData )
|
||||
{
|
||||
LoadBuffer.Get( pData, iLumpCount * nSize );
|
||||
}
|
||||
|
||||
#endif // GAME_DLL
|
||||
|
||||
extern CBaseGameStats *gamestats; //starts out pointing at a singleton of the class above, overriding this in any constructor should work for replacing it
|
||||
|
||||
#endif // GAMESTATS_H
|
||||
@@ -0,0 +1,82 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client-server neutral effects interface
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef IEFFECTS_H
|
||||
#define IEFFECTS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "interface.h"
|
||||
#include "ipredictionsystem.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
enum ShakeCommand_t;
|
||||
class Vector;
|
||||
class CGameTrace;
|
||||
typedef CGameTrace trace_t;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Client-server neutral effects interface
|
||||
//-----------------------------------------------------------------------------
|
||||
#define IEFFECTS_INTERFACE_VERSION "IEffects001"
|
||||
abstract_class IEffects : public IPredictionSystem
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Particle effects
|
||||
//
|
||||
virtual void Beam( const Vector &Start, const Vector &End, int nModelIndex,
|
||||
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
|
||||
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
|
||||
unsigned char noise, unsigned char red, unsigned char green,
|
||||
unsigned char blue, unsigned char brightness, unsigned char speed) = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Emits smoke sprites.
|
||||
// Input : origin - Where to emit the sprites.
|
||||
// scale - Sprite scale * 10.
|
||||
// framerate - Framerate at which to animate the smoke sprites.
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual void Smoke( const Vector &origin, int modelIndex, float scale, float framerate ) = 0;
|
||||
|
||||
virtual void Sparks( const Vector &position, int nMagnitude = 1, int nTrailLength = 1, const Vector *pvecDir = NULL ) = 0;
|
||||
|
||||
virtual void Dust( const Vector &pos, const Vector &dir, float size, float speed ) = 0;
|
||||
|
||||
virtual void MuzzleFlash( const Vector &vecOrigin, const QAngle &vecAngles, float flScale, int iType ) = 0;
|
||||
|
||||
// like ricochet, but no sound
|
||||
virtual void MetalSparks( const Vector &position, const Vector &direction ) = 0;
|
||||
|
||||
virtual void EnergySplash( const Vector &position, const Vector &direction, bool bExplosive = false ) = 0;
|
||||
|
||||
virtual void Ricochet( const Vector &position, const Vector &direction ) = 0;
|
||||
|
||||
// FIXME: Should these methods remain in this interface? Or go in some
|
||||
// other client-server neutral interface?
|
||||
virtual float Time() = 0;
|
||||
virtual bool IsServer() = 0;
|
||||
|
||||
// Used by the playback system to suppress sounds
|
||||
virtual void SuppressEffectsSounds( bool bSuppress ) = 0;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Client-server neutral effects interface accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
extern IEffects *g_pEffects;
|
||||
|
||||
|
||||
#endif // IEFFECTS_H
|
||||
@@ -0,0 +1,47 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef IVEHICLE_H
|
||||
#define IVEHICLE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "baseplayer_shared.h"
|
||||
|
||||
class CUserCmd;
|
||||
class IMoveHelper;
|
||||
class CMoveData;
|
||||
class CBaseCombatCharacter;
|
||||
|
||||
// This is used by the player to access vehicles. It's an interface so the
|
||||
// vehicles are not restricted in what they can derive from.
|
||||
abstract_class IVehicle
|
||||
{
|
||||
public:
|
||||
// Get and set the current driver. Use PassengerRole_t enum in shareddefs.h for adding passengers
|
||||
virtual CBaseCombatCharacter* GetPassenger( int nRole = VEHICLE_ROLE_DRIVER ) = 0;
|
||||
virtual int GetPassengerRole( CBaseCombatCharacter *pPassenger ) = 0;
|
||||
|
||||
// Where is the passenger seeing from?
|
||||
virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL ) = 0;
|
||||
|
||||
// Does the player use his normal weapons while in this mode?
|
||||
virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) = 0;
|
||||
|
||||
// Process movement
|
||||
virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) = 0;
|
||||
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ) = 0;
|
||||
virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) = 0;
|
||||
|
||||
// Process input
|
||||
virtual void ItemPostFrame( CBasePlayer *pPlayer ) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // IVEHICLE_H
|
||||
@@ -0,0 +1,222 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "ModelSoundsCache.h"
|
||||
#include "studio.h"
|
||||
#include "eventlist.h"
|
||||
#include "scriptevent.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
extern ISoundEmitterSystemBase *soundemitterbase;
|
||||
|
||||
CStudioHdr *ModelSoundsCache_LoadModel( char const *filename );
|
||||
void ModelSoundsCache_PrecacheScriptSound( const char *soundname );
|
||||
void ModelSoundsCache_FinishModel( CStudioHdr *hdr );
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *hdr -
|
||||
// Output : static void
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void VerifySequenceIndex( CStudioHdr *pstudiohdr );
|
||||
|
||||
// HACK: This must match the #define in cl_animevent.h in the client .dll code!!!
|
||||
#define CL_EVENT_SOUND 5004
|
||||
#define CL_EVENT_FOOTSTEP_LEFT 6004
|
||||
#define CL_EVENT_FOOTSTEP_RIGHT 6005
|
||||
#define CL_EVENT_MFOOTSTEP_LEFT 6006
|
||||
#define CL_EVENT_MFOOTSTEP_RIGHT 6007
|
||||
|
||||
|
||||
extern ISoundEmitterSystemBase *soundemitterbase;
|
||||
|
||||
CModelSoundsCache::CModelSoundsCache()
|
||||
{
|
||||
}
|
||||
|
||||
CModelSoundsCache::CModelSoundsCache( const CModelSoundsCache& src )
|
||||
{
|
||||
sounds = src.sounds;
|
||||
}
|
||||
|
||||
char const *CModelSoundsCache::GetSoundName( int index )
|
||||
{
|
||||
return soundemitterbase->GetSoundName( sounds[ index ] );
|
||||
}
|
||||
|
||||
void CModelSoundsCache::Save( CUtlBuffer& buf )
|
||||
{
|
||||
buf.PutShort( sounds.Count() );
|
||||
|
||||
for ( int i = 0; i < sounds.Count(); ++i )
|
||||
{
|
||||
buf.PutString( GetSoundName( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
void CModelSoundsCache::Restore( CUtlBuffer& buf )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
unsigned short c;
|
||||
|
||||
c = (unsigned short)buf.GetShort();
|
||||
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
char soundname[ 512 ];
|
||||
|
||||
buf.GetString( soundname, sizeof( soundname ) );
|
||||
|
||||
int idx = soundemitterbase->GetSoundIndex( soundname );
|
||||
if ( soundemitterbase->IsValidIndex( idx ) )
|
||||
{
|
||||
if ( sounds.Find( idx ) == sounds.InvalidIndex() )
|
||||
{
|
||||
sounds.Insert( idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CModelSoundsCache::Rebuild( char const *filename )
|
||||
{
|
||||
sounds.RemoveAll();
|
||||
|
||||
CStudioHdr *hdr = ModelSoundsCache_LoadModel( filename );
|
||||
|
||||
if ( hdr )
|
||||
{
|
||||
// Precache all sounds referenced in animation events
|
||||
BuildAnimationEventSoundList( hdr, sounds );
|
||||
ModelSoundsCache_FinishModel( hdr );
|
||||
}
|
||||
}
|
||||
|
||||
void CModelSoundsCache::PrecacheSoundList()
|
||||
{
|
||||
for ( int i = 0; i < sounds.Count(); ++i )
|
||||
{
|
||||
ModelSoundsCache_PrecacheScriptSound( GetSoundName( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Static method
|
||||
// Input : sounds -
|
||||
// *soundname -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CModelSoundsCache::FindOrAddScriptSound( CUtlSortVector< int, CModelSoundsCacheListLess >& sounds, char const *soundname )
|
||||
{
|
||||
int soundindex = soundemitterbase->GetSoundIndex( soundname );
|
||||
if ( soundemitterbase->IsValidIndex( soundindex ) )
|
||||
{
|
||||
// Only add it once per model...
|
||||
if ( sounds.Find( soundindex ) == sounds.InvalidIndex() )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
sounds.Insert( soundindex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Static method
|
||||
// Input : *hdr -
|
||||
// sounds -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CModelSoundsCache::BuildAnimationEventSoundList( CStudioHdr *hdr, CUtlSortVector< int, CModelSoundsCacheListLess >& sounds )
|
||||
{
|
||||
Assert( hdr );
|
||||
|
||||
// force animation event resolution!!!
|
||||
VerifySequenceIndex( hdr );
|
||||
|
||||
// Find all animation events which fire off sound script entries...
|
||||
for ( int iSeq=0; iSeq < hdr->GetNumSeq(); iSeq++ )
|
||||
{
|
||||
mstudioseqdesc_t *pSeq = &hdr->pSeqdesc( iSeq );
|
||||
|
||||
// Now read out all the sound events with their timing
|
||||
for ( int iEvent=0; iEvent < (int)pSeq->numevents; iEvent++ )
|
||||
{
|
||||
mstudioevent_t *pEvent = (mstudioevent_for_client_server_t*)pSeq->pEvent( iEvent );
|
||||
|
||||
int nEvent = pEvent->Event();
|
||||
|
||||
switch ( nEvent )
|
||||
{
|
||||
default:
|
||||
{
|
||||
if ( pEvent->type & AE_TYPE_NEWEVENTSYSTEM )
|
||||
{
|
||||
if ( nEvent == AE_SV_PLAYSOUND )
|
||||
{
|
||||
FindOrAddScriptSound( sounds, pEvent->pszOptions() );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Old-style client .dll animation event
|
||||
case CL_EVENT_SOUND:
|
||||
{
|
||||
FindOrAddScriptSound( sounds, pEvent->pszOptions() );
|
||||
}
|
||||
break;
|
||||
case CL_EVENT_FOOTSTEP_LEFT:
|
||||
case CL_EVENT_FOOTSTEP_RIGHT:
|
||||
{
|
||||
char soundname[256];
|
||||
char const *options = pEvent->pszOptions();
|
||||
if ( !options || !options[0] )
|
||||
{
|
||||
options = "NPC_CombineS";
|
||||
}
|
||||
|
||||
Q_snprintf( soundname, 256, "%s.RunFootstepLeft", options );
|
||||
FindOrAddScriptSound( sounds, soundname );
|
||||
Q_snprintf( soundname, 256, "%s.RunFootstepRight", options );
|
||||
FindOrAddScriptSound( sounds, soundname );
|
||||
Q_snprintf( soundname, 256, "%s.FootstepLeft", options );
|
||||
FindOrAddScriptSound( sounds, soundname );
|
||||
Q_snprintf( soundname, 256, "%s.FootstepRight", options );
|
||||
FindOrAddScriptSound( sounds, soundname );
|
||||
}
|
||||
break;
|
||||
case AE_CL_PLAYSOUND:
|
||||
{
|
||||
if ( !( pEvent->type & AE_TYPE_CLIENT ) )
|
||||
break;
|
||||
|
||||
if ( pEvent->pszOptions()[0] )
|
||||
{
|
||||
FindOrAddScriptSound( sounds, pEvent->pszOptions() );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "-- Error --: empty soundname, .qc error on AE_CL_PLAYSOUND in model %s, sequence %s, animevent # %i\n",
|
||||
hdr->pszName(), pSeq->pszLabel(), iEvent+1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SCRIPT_EVENT_SOUND:
|
||||
{
|
||||
FindOrAddScriptSound( sounds, pEvent->pszOptions() );
|
||||
}
|
||||
break;
|
||||
|
||||
case SCRIPT_EVENT_SOUND_VOICE:
|
||||
{
|
||||
FindOrAddScriptSound( sounds, pEvent->pszOptions() );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MODELSOUNDSCACHE_H
|
||||
#define MODELSOUNDSCACHE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "UtlCachedFileData.h"
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
|
||||
#define MODELSOUNDSCACHE_VERSION 5
|
||||
|
||||
class CStudioHdr;
|
||||
|
||||
|
||||
class CModelSoundsCacheListLess
|
||||
{
|
||||
public:
|
||||
bool Less( const int &lhs, const int &rhs, void *pCtx )
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
class CModelSoundsCache : public IBaseCacheInfo
|
||||
{
|
||||
public:
|
||||
CUtlSortVector< int, CModelSoundsCacheListLess > sounds;
|
||||
|
||||
CModelSoundsCache();
|
||||
CModelSoundsCache( const CModelSoundsCache& src );
|
||||
|
||||
void PrecacheSoundList();
|
||||
|
||||
virtual void Save( CUtlBuffer& buf );
|
||||
virtual void Restore( CUtlBuffer& buf );
|
||||
virtual void Rebuild( char const *filename );
|
||||
|
||||
static void FindOrAddScriptSound( CUtlSortVector< int, CModelSoundsCacheListLess >& sounds, char const *soundname );
|
||||
static void BuildAnimationEventSoundList( CStudioHdr *hdr, CUtlSortVector< int, CModelSoundsCacheListLess >& sounds );
|
||||
private:
|
||||
char const *GetSoundName( int index );
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#endif // MODELSOUNDSCACHE_H
|
||||
@@ -0,0 +1,133 @@
|
||||
//====== Copyright © 1996-2007, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "SceneCache.h"
|
||||
#include "choreoscene.h"
|
||||
#include "choreoevent.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
extern ISoundEmitterSystemBase *soundemitterbase;
|
||||
CChoreoScene *BlockingLoadScene( const char *filename );
|
||||
|
||||
CSceneCache::CSceneCache()
|
||||
{
|
||||
msecs = 0;
|
||||
}
|
||||
|
||||
//CSceneCache::CSceneCache( const CSceneCache& src )
|
||||
//{
|
||||
// msecs = src.msecs;
|
||||
// sounds = src.sounds;
|
||||
//}
|
||||
|
||||
int CSceneCache::GetSoundCount() const
|
||||
{
|
||||
return sounds.Count();
|
||||
}
|
||||
|
||||
char const *CSceneCache::GetSoundName( int index )
|
||||
{
|
||||
return soundemitterbase->GetSoundName( sounds[ index ] );
|
||||
}
|
||||
|
||||
void CSceneCache::Save( CUtlBuffer& buf )
|
||||
{
|
||||
buf.PutUnsignedInt( msecs );
|
||||
|
||||
unsigned short c = GetSoundCount();
|
||||
buf.PutShort( c );
|
||||
|
||||
Assert( sounds.Count() <= 65536 );
|
||||
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
buf.PutString( GetSoundName( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
void CSceneCache::Restore( CUtlBuffer& buf )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
|
||||
msecs = buf.GetUnsignedInt();
|
||||
|
||||
unsigned short c = (unsigned short)buf.GetShort();
|
||||
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
char soundname[ 512 ];
|
||||
buf.GetString( soundname, sizeof( soundname ) );
|
||||
|
||||
int idx = soundemitterbase->GetSoundIndex( soundname );
|
||||
if ( soundemitterbase->IsValidIndex( idx ) )
|
||||
{
|
||||
if ( sounds.Find( idx ) == sounds.InvalidIndex() )
|
||||
{
|
||||
sounds.Insert( idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Static method
|
||||
// Input : *event -
|
||||
// soundlist -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSceneCache::PrecacheSceneEvent( CChoreoEvent *event, CUtlSortVector< int, CSceneCacheListLess > &soundlist )
|
||||
{
|
||||
if ( !event || event->GetType() != CChoreoEvent::SPEAK )
|
||||
return;
|
||||
|
||||
int idx = soundemitterbase->GetSoundIndex( event->GetParameters() );
|
||||
if ( soundemitterbase->IsValidIndex( idx ) )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
soundlist.Insert( idx );
|
||||
}
|
||||
|
||||
if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
|
||||
{
|
||||
char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
|
||||
if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
|
||||
{
|
||||
int idx = soundemitterbase->GetSoundIndex( tok );
|
||||
if ( soundemitterbase->IsValidIndex( idx ) && soundlist.Find( idx ) == soundlist.InvalidIndex() )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
soundlist.Insert( idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSceneCache::Rebuild( char const *filename )
|
||||
{
|
||||
msecs = 0;
|
||||
sounds.RemoveAll();
|
||||
|
||||
CChoreoScene *scene = BlockingLoadScene( filename );
|
||||
if ( scene )
|
||||
{
|
||||
// Walk all events looking for SPEAK events
|
||||
CChoreoEvent *event;
|
||||
int c = scene->GetNumEvents();
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
event = scene->GetEvent( i );
|
||||
PrecacheSceneEvent( event, sounds );
|
||||
}
|
||||
|
||||
// Update scene duration, too
|
||||
msecs = (int)( scene->FindStopTime() * 1000.0f + 0.5f );
|
||||
|
||||
delete scene;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef SCENECACHE_H
|
||||
#define SCENECACHE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "UtlCachedFileData.h"
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
|
||||
class CChoreoEvent;
|
||||
|
||||
#define SCENECACHE_VERSION 7
|
||||
|
||||
|
||||
class CSceneCacheListLess
|
||||
{
|
||||
public:
|
||||
bool Less( const int &lhs, const int &rhs, void *pCtx )
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
class CSceneCache : public IBaseCacheInfo
|
||||
{
|
||||
public:
|
||||
unsigned int msecs;
|
||||
CUtlSortVector< int, CSceneCacheListLess > sounds;
|
||||
|
||||
CSceneCache();
|
||||
// CSceneCache( const CSceneCache& src );
|
||||
|
||||
int GetSoundCount() const;
|
||||
char const *GetSoundName( int index );
|
||||
|
||||
virtual void Save( CUtlBuffer& buf );
|
||||
virtual void Restore( CUtlBuffer& buf );
|
||||
virtual void Rebuild( char const *filename );
|
||||
|
||||
static unsigned int ComputeSoundScriptFileTimestampChecksum();
|
||||
static void PrecacheSceneEvent( CChoreoEvent *event, CUtlSortVector< int, CSceneCacheListLess > &soundlist );
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#endif // SCENECACHE_H
|
||||
@@ -0,0 +1,84 @@
|
||||
// SharedFunctorUtils.cpp
|
||||
// Useful functors
|
||||
// Copyright 2006 Turtle Rock Studios, Inc.
|
||||
|
||||
#include "cbase.h"
|
||||
#include "SharedFunctorUtils.h"
|
||||
#include "collisionutils.h"
|
||||
// #ifdef CLIENT_DLL
|
||||
// #include "ClientTerrorPlayer.h"
|
||||
// #else
|
||||
// #include "TerrorPlayer.h"
|
||||
// #endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#if 0
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
bool AvoidActors::operator()( CBaseCombatCharacter *obj )
|
||||
{
|
||||
if ( !obj || ( obj == m_owner ) || ( obj->GetTeamNumber() != m_owner->GetTeamNumber() ) )
|
||||
return true;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
if ( obj->IsDormant() )
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if ( obj->IsSolidFlagSet( FSOLID_NOT_SOLID ) )
|
||||
return true;
|
||||
|
||||
CTerrorPlayer *player = ToTerrorPlayer( obj );
|
||||
if ( !player )
|
||||
return true;
|
||||
|
||||
if ( player->IsIncapacitatedRevivable() )
|
||||
return true;
|
||||
|
||||
if ( player->IsGhost() )
|
||||
return true;
|
||||
|
||||
Vector objOrigin = obj->GetAbsOrigin();
|
||||
Vector vObjMins = objOrigin + obj->WorldAlignMins();
|
||||
Vector vObjMaxs = objOrigin + obj->WorldAlignMaxs();
|
||||
Vector vOwnerMins = *m_dest + m_owner->WorldAlignMins();
|
||||
Vector vOwnerMaxs = *m_dest + m_owner->WorldAlignMaxs();
|
||||
if ( !IsBoxIntersectingBox( vOwnerMins, vOwnerMaxs, vObjMins, vObjMaxs ) )
|
||||
return true;
|
||||
|
||||
float objWidth = vObjMaxs.x - vObjMins.x;
|
||||
float ownerWidth = vOwnerMaxs.x - vOwnerMins.x;
|
||||
float idealDistance = (objWidth + ownerWidth) * 0.5f * m_scale;
|
||||
|
||||
Vector vDelta = objOrigin - *m_dest;
|
||||
vDelta.z = 0;
|
||||
float fDist = vDelta.NormalizeInPlace();
|
||||
if ( fDist > idealDistance )
|
||||
return true;
|
||||
|
||||
Vector rayOrigin = m_origin;
|
||||
Vector rayDelta = *m_dest - m_origin;
|
||||
Vector sphereCenter = objOrigin;
|
||||
float sphereRadius = idealDistance;
|
||||
rayOrigin.z = rayDelta.z = sphereCenter.z = 0.0f;
|
||||
float t1, t2;
|
||||
if ( IntersectRayWithSphere( rayOrigin, rayDelta, sphereCenter, sphereRadius, &t1, &t2 ) )
|
||||
{
|
||||
Vector sphereToDest = *m_dest - sphereCenter;
|
||||
sphereToDest.z = 0.0f;
|
||||
if ( !sphereToDest.IsZero() )
|
||||
{
|
||||
float radius = sphereToDest.NormalizeInPlace();
|
||||
sphereToDest *= (idealDistance - radius);
|
||||
*m_dest += sphereToDest;
|
||||
m_avoidedActors.AddToTail( obj );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
#endif
|
||||
@@ -0,0 +1,156 @@
|
||||
// SharedFunctorUtils.h
|
||||
// Useful functors for client and server
|
||||
// Author: Graham Smallwood, August 2006, Copyright 2006 Turtle Rock Studios, Inc.
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* NOTE: The functors in this file should ideally be game-independant,
|
||||
* and work for any Source based game
|
||||
*/
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
#ifndef _SHARED_FUNCTOR_UTILS_H_
|
||||
#define _SHARED_FUNCTOR_UTILS_H_
|
||||
|
||||
#include "debugoverlay_shared.h"
|
||||
#include "vprof.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Finds visible player on given team that we are pointing at.
|
||||
* "team" can be TEAM_ANY
|
||||
* Use with ForEachPlayer()
|
||||
*/
|
||||
template < class PlayerType >
|
||||
class TargetScan
|
||||
{
|
||||
public:
|
||||
TargetScan( PlayerType *me, int team, float aimTolerance = 0.01f, float maxRange = 2000.0f, float closestPointTestDistance = 50.0f, bool debug = false )
|
||||
{
|
||||
m_me = me;
|
||||
AngleVectors( m_me->EyeAngles(), &m_viewForward );
|
||||
m_team = team;
|
||||
m_closeDot = 1.0f - aimTolerance;
|
||||
m_bestDot = m_closeDot;
|
||||
m_maxRange = maxRange;
|
||||
m_target = NULL;
|
||||
m_closestPointTestDistance = closestPointTestDistance;
|
||||
m_debug = debug;
|
||||
}
|
||||
|
||||
|
||||
virtual bool operator() ( PlayerType *them )
|
||||
{
|
||||
VPROF( "TargetScan()" );
|
||||
if ( them != m_me &&
|
||||
them->IsAlive() &&
|
||||
(m_team == TEAM_ANY || them->GetTeamNumber() == m_team) &&
|
||||
IsPotentialTarget( them ) )
|
||||
{
|
||||
// move the start point out for determining closestPos, to help with close-in checks (healing, etc)
|
||||
Vector closestPos;
|
||||
Vector start = m_me->EyePosition();
|
||||
Vector end = start + m_viewForward * m_closestPointTestDistance;
|
||||
Vector testPos;
|
||||
CalcClosestPointOnLineSegment( them->WorldSpaceCenter(), start, end, testPos );
|
||||
|
||||
start = them->GetAbsOrigin();
|
||||
end = start;
|
||||
end.z += them->CollisionProp()->OBBMaxs().z;
|
||||
CalcClosestPointOnLineSegment( testPos, start, end, closestPos );
|
||||
if ( m_debug )
|
||||
{
|
||||
NDebugOverlay::Cross3D( closestPos, 1, 255, 255, 255, true, -1.0f );
|
||||
NDebugOverlay::Line( end, start, 255, 0, 0, true, -1.0f );
|
||||
}
|
||||
|
||||
Vector to = closestPos - m_me->EyePosition();
|
||||
to.NormalizeInPlace();
|
||||
|
||||
Vector meRangePoint, themRangePoint;
|
||||
m_me->CollisionProp()->CalcNearestPoint( closestPos, &meRangePoint );
|
||||
them->CollisionProp()->CalcNearestPoint( meRangePoint, &themRangePoint );
|
||||
float range = meRangePoint.DistTo( themRangePoint );
|
||||
|
||||
if ( range > m_maxRange )
|
||||
{
|
||||
// too far away
|
||||
return true;
|
||||
}
|
||||
|
||||
float dot = ViewDot( to );
|
||||
if ( dot > m_closeDot )
|
||||
{
|
||||
// target is within angle cone, check visibility
|
||||
if ( IsTargetVisible( them ) )
|
||||
{
|
||||
if ( dot >= m_bestDot )
|
||||
{
|
||||
m_target = them;
|
||||
m_bestDot = dot;
|
||||
}
|
||||
|
||||
m_allTargets.AddToTail( them );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerType *GetTarget( void ) const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
const CUtlVector< PlayerType * > &GetAllTargets( void ) const
|
||||
{
|
||||
return m_allTargets;
|
||||
}
|
||||
|
||||
float GetTargetDot( void ) const
|
||||
{
|
||||
return m_bestDot;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Is the point in our FOV?
|
||||
*/
|
||||
virtual float ViewDot( const Vector &dir ) const
|
||||
{
|
||||
return DotProduct( m_viewForward, dir );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given actor a visible target?
|
||||
*/
|
||||
virtual bool IsTargetVisible( PlayerType *them ) const
|
||||
{
|
||||
// The default check is a straight-up IsAbleToSee
|
||||
return m_me->IsAbleToSee( them, CBaseCombatCharacter::DISREGARD_FOV ); // already have a dot product checking FOV
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given player a possible target at all?
|
||||
*/
|
||||
virtual bool IsPotentialTarget( PlayerType *them ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerType *m_me;
|
||||
Vector m_viewForward;
|
||||
int m_team;
|
||||
|
||||
float m_closeDot;
|
||||
float m_bestDot;
|
||||
float m_maxRange;
|
||||
float m_closestPointTestDistance;
|
||||
bool m_debug;
|
||||
|
||||
PlayerType *m_target;
|
||||
CUtlVector< PlayerType * > m_allTargets;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,899 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "Sprite.h"
|
||||
#include "model_types.h"
|
||||
#include "engine/ivmodelinfo.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "enginesprite.h"
|
||||
#include "iclientmode.h"
|
||||
#include "c_baseviewmodel.h"
|
||||
#else
|
||||
#include "baseviewmodel.h"
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
const float MAX_SPRITE_SCALE = 64.0f;
|
||||
const float MAX_GLOW_PROXY_SIZE = 64.0f;
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
LINK_ENTITY_TO_CLASS( env_glow, CSprite ); // For backwards compatibility, remove when no longer needed.
|
||||
LINK_ENTITY_TO_CLASS( env_sprite_clientside, CSprite );
|
||||
#endif
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
BEGIN_DATADESC( CSprite )
|
||||
|
||||
DEFINE_FIELD( m_flLastTime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_flMaxFrame, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_hAttachedToEntity, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( m_nAttachment, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flDieTime, FIELD_TIME ),
|
||||
|
||||
DEFINE_FIELD( m_nBrightness, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flBrightnessTime, FIELD_FLOAT ),
|
||||
|
||||
DEFINE_KEYFIELD( m_flSpriteScale, FIELD_FLOAT, "scale" ),
|
||||
DEFINE_KEYFIELD( m_flSpriteFramerate, FIELD_FLOAT, "framerate" ),
|
||||
DEFINE_KEYFIELD( m_flFrame, FIELD_FLOAT, "frame" ),
|
||||
DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ),
|
||||
|
||||
DEFINE_KEYFIELD( m_flGlowProxySize, FIELD_FLOAT, "GlowProxySize" ),
|
||||
|
||||
DEFINE_FIELD( m_flScaleTime, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flStartScale, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flDestScale, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flScaleTimeStart, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_nStartBrightness, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nDestBrightness, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flBrightnessTimeStart, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_bWorldSpaceScale, FIELD_BOOLEAN ),
|
||||
|
||||
// Function Pointers
|
||||
DEFINE_FUNCTION( AnimateThink ),
|
||||
DEFINE_FUNCTION( ExpandThink ),
|
||||
DEFINE_FUNCTION( AnimateUntilDead ),
|
||||
DEFINE_FUNCTION( BeginFadeOutThink ),
|
||||
|
||||
// Inputs
|
||||
DEFINE_INPUT( m_flSpriteScale, FIELD_FLOAT, "SetScale" ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "HideSprite", InputHideSprite ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ShowSprite", InputShowSprite ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ToggleSprite", InputToggleSprite ),
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "ColorRedValue", InputColorRedValue ),
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "ColorGreenValue", InputColorGreenValue ),
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "ColorBlueValue", InputColorBlueValue ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
#else
|
||||
|
||||
BEGIN_PREDICTION_DATA( CSprite )
|
||||
|
||||
// Networked
|
||||
DEFINE_PRED_FIELD( m_hAttachedToEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_nAttachment, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flScaleTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flSpriteScale, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flSpriteFramerate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flFrame, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flBrightnessTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_nBrightness, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
|
||||
DEFINE_FIELD( m_flLastTime, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flMaxFrame, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flDieTime, FIELD_FLOAT ),
|
||||
|
||||
// DEFINE_FIELD( m_flHDRColorScale, FIELD_FLOAT ),
|
||||
// DEFINE_FIELD( m_flStartScale, FIELD_FLOAT ), //Starting scale
|
||||
// DEFINE_FIELD( m_flDestScale, FIELD_FLOAT ), //Destination scale
|
||||
// DEFINE_FIELD( m_flScaleTimeStart, FIELD_FLOAT ), //Real time for start of scale
|
||||
// DEFINE_FIELD( m_nStartBrightness, FIELD_INTEGER ), //Starting brightness
|
||||
// DEFINE_FIELD( m_nDestBrightness, FIELD_INTEGER ), //Destination brightness
|
||||
// DEFINE_FIELD( m_flBrightnessTimeStart, FIELD_FLOAT ), //Real time for brightness
|
||||
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
#endif
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( Sprite, DT_Sprite );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
static void RecvProxy_SpriteScale( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
((CSprite*)pStruct)->SetSpriteScale( pData->m_Value.m_Float );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BEGIN_NETWORK_TABLE( CSprite, DT_Sprite )
|
||||
#if !defined( CLIENT_DLL )
|
||||
SendPropEHandle( SENDINFO(m_hAttachedToEntity )),
|
||||
SendPropInt( SENDINFO(m_nAttachment ), 8 ),
|
||||
SendPropFloat( SENDINFO(m_flScaleTime ), 0, SPROP_NOSCALE ),
|
||||
|
||||
#ifdef HL2_DLL
|
||||
SendPropFloat( SENDINFO(m_flSpriteScale ), 0, SPROP_NOSCALE),
|
||||
#else
|
||||
SendPropFloat( SENDINFO(m_flSpriteScale ), 8, SPROP_ROUNDUP, 0.0f, MAX_SPRITE_SCALE),
|
||||
#endif
|
||||
SendPropFloat( SENDINFO(m_flGlowProxySize ), 6, SPROP_ROUNDUP, 0.0f, MAX_GLOW_PROXY_SIZE),
|
||||
|
||||
SendPropFloat( SENDINFO(m_flHDRColorScale ), 0, SPROP_NOSCALE, 0.0f, 100.0f),
|
||||
|
||||
SendPropFloat( SENDINFO(m_flSpriteFramerate ), 8, SPROP_ROUNDUP, 0, 60.0f),
|
||||
SendPropFloat( SENDINFO(m_flFrame), 20, SPROP_ROUNDDOWN, 0.0f, 256.0f),
|
||||
SendPropFloat( SENDINFO(m_flBrightnessTime ), 0, SPROP_NOSCALE ),
|
||||
SendPropInt( SENDINFO(m_nBrightness), 8, SPROP_UNSIGNED ),
|
||||
SendPropBool( SENDINFO(m_bWorldSpaceScale) ),
|
||||
#else
|
||||
RecvPropEHandle(RECVINFO(m_hAttachedToEntity)),
|
||||
RecvPropInt(RECVINFO(m_nAttachment)),
|
||||
RecvPropFloat(RECVINFO(m_flScaleTime)),
|
||||
RecvPropFloat(RECVINFO(m_flSpriteScale), 0, RecvProxy_SpriteScale),
|
||||
RecvPropFloat(RECVINFO(m_flSpriteFramerate)),
|
||||
RecvPropFloat(RECVINFO(m_flGlowProxySize)),
|
||||
|
||||
RecvPropFloat( RECVINFO(m_flHDRColorScale )),
|
||||
|
||||
RecvPropFloat(RECVINFO(m_flFrame)),
|
||||
RecvPropFloat(RECVINFO(m_flBrightnessTime)),
|
||||
RecvPropInt(RECVINFO(m_nBrightness)),
|
||||
RecvPropBool( RECVINFO(m_bWorldSpaceScale) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS_ALIASED( env_sprite, Sprite );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
extern CUtlVector< CSprite * > g_ClientsideSprites;
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
CSprite::CSprite()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
m_bClientOnly = false;
|
||||
#endif // CLIENT_DLL
|
||||
m_flGlowProxySize = 2.0f;
|
||||
m_flHDRColorScale = 1.0f;
|
||||
}
|
||||
|
||||
CSprite::~CSprite()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if ( m_bClientOnly )
|
||||
{
|
||||
g_ClientsideSprites.FindAndFastRemove( this );
|
||||
}
|
||||
#endif // CLIENT_DLL
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::Spawn( void )
|
||||
{
|
||||
SetSolid( SOLID_NONE );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
m_flFrame = 0;
|
||||
|
||||
Precache();
|
||||
SetModel( STRING( GetModelName() ) );
|
||||
CollisionProp()->SetSurroundingBoundsType( USE_GAME_CODE );
|
||||
|
||||
m_flMaxFrame = (float)modelinfo->GetModelFrameCount( GetModel() ) - 1;
|
||||
AddEffects( EF_NOSHADOW | EF_NORECEIVESHADOW );
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
if ( m_flGlowProxySize > MAX_GLOW_PROXY_SIZE )
|
||||
{
|
||||
// Clamp on Spawn to prevent per-frame spew
|
||||
DevWarning( "env_sprite at setpos %0.0f %0.0f %0.0f has invalid glow size %f - clamping to %f\n",
|
||||
GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z, m_flGlowProxySize.Get(), MAX_GLOW_PROXY_SIZE );
|
||||
m_flGlowProxySize = MAX_GLOW_PROXY_SIZE;
|
||||
}
|
||||
if ( GetEntityName() != NULL_STRING && !(m_spawnflags & SF_SPRITE_STARTON) )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
TurnOn();
|
||||
}
|
||||
|
||||
// Worldcraft only sets y rotation, copy to Z
|
||||
if ( GetLocalAngles().y != 0 && GetLocalAngles().z == 0 )
|
||||
{
|
||||
QAngle angles = GetLocalAngles();
|
||||
|
||||
angles.z = angles.y;
|
||||
angles.y = 0;
|
||||
|
||||
SetLocalAngles( angles );
|
||||
}
|
||||
|
||||
// Clamp our scale if necessary
|
||||
float scale = m_flSpriteScale;
|
||||
|
||||
if ( scale < 0 || scale > MAX_SPRITE_SCALE )
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
DevMsg( "LEVEL DESIGN ERROR: Sprite %s with bad scale %f [0..%f]\n", GetDebugName(), m_flSpriteScale.Get(), MAX_SPRITE_SCALE );
|
||||
#endif
|
||||
scale = clamp( m_flSpriteScale.Get(), 0, MAX_SPRITE_SCALE );
|
||||
}
|
||||
|
||||
//Set our state
|
||||
SetBrightness( GetRenderAlpha() );
|
||||
SetScale( scale );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
m_flStartScale = m_flDestScale = m_flSpriteScale;
|
||||
m_nStartBrightness = m_nDestBrightness = m_nBrightness;
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// Server has no use for client-only entities.
|
||||
// Seems like a waste to create the entity, only to UTIL_Remove it on Spawn, but this pattern works safely...
|
||||
if ( FClassnameIs( this, "env_sprite_clientside" ) )
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
#endif // !CLIENT_DLL
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize absmin & absmax to the appropriate box
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::EnableWorldSpaceScale( bool bEnable )
|
||||
{
|
||||
m_bWorldSpaceScale = bEnable;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize absmin & absmax to the appropriate box
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
|
||||
{
|
||||
float flScale = m_flSpriteScale * 0.5f;
|
||||
|
||||
if ( m_bWorldSpaceScale == false )
|
||||
{
|
||||
// Find the height and width of the source of the sprite
|
||||
float width = modelinfo->GetModelSpriteWidth( GetModel() );
|
||||
float height = modelinfo->GetModelSpriteHeight( GetModel() );
|
||||
flScale *= MAX( width, height );
|
||||
}
|
||||
|
||||
pVecWorldMins->Init( -flScale, -flScale, -flScale );
|
||||
pVecWorldMaxs->Init( flScale, flScale, flScale );
|
||||
*pVecWorldMins += GetAbsOrigin();
|
||||
*pVecWorldMaxs += GetAbsOrigin();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *szModelName -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::SetModel( const char *szModelName )
|
||||
{
|
||||
int index = modelinfo->GetModelIndex( szModelName );
|
||||
const model_t *model = modelinfo->GetModel( index );
|
||||
if ( model && modelinfo->GetModelType( model ) != mod_sprite )
|
||||
{
|
||||
Msg( "Setting CSprite to non-sprite model %s\n", szModelName?szModelName:"NULL" );
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
UTIL_SetModel( this, szModelName );
|
||||
#else
|
||||
BaseClass::SetModel( szModelName );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::Precache( void )
|
||||
{
|
||||
if ( GetModelName() != NULL_STRING )
|
||||
{
|
||||
PrecacheModel( STRING( GetModelName() ) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pSpriteName -
|
||||
// &origin -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin )
|
||||
{
|
||||
SetModelName( MAKE_STRING(pSpriteName) );
|
||||
SetLocalOrigin( origin );
|
||||
Spawn();
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
int CSprite::UpdateTransmitState( void )
|
||||
{
|
||||
if ( GetMoveParent() )
|
||||
{
|
||||
// we must call ShouldTransmit() if we have a move parent
|
||||
return SetTransmitState( FL_EDICT_FULLCHECK );
|
||||
}
|
||||
else
|
||||
{
|
||||
return SetTransmitState( FL_EDICT_ALWAYS );
|
||||
}
|
||||
}
|
||||
|
||||
int CSprite::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
// Certain entities like sprites and ropes are strewn throughout the level and they rarely change.
|
||||
// For these entities, it's more efficient to transmit them once and then always leave them on
|
||||
// the client. Otherwise, the server will have to send big bursts of data with the entity states
|
||||
// as they come in and out of the PVS.
|
||||
|
||||
if ( GetMoveParent() )
|
||||
{
|
||||
CBaseViewModel *pViewModel = ToBaseViewModel( GetMoveParent() );
|
||||
|
||||
if ( pViewModel )
|
||||
{
|
||||
return pViewModel->ShouldTransmit( pInfo );
|
||||
}
|
||||
}
|
||||
|
||||
return FL_EDICT_ALWAYS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fixup parent after restore
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::OnRestore()
|
||||
{
|
||||
BaseClass::OnRestore();
|
||||
|
||||
// Reset attachment after save/restore
|
||||
if ( GetFollowedEntity() )
|
||||
{
|
||||
SetAttachment( GetFollowedEntity(), m_nAttachment );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear attachment
|
||||
m_hAttachedToEntity = NULL;
|
||||
m_nAttachment = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pSpriteName -
|
||||
// &origin -
|
||||
// animate -
|
||||
// Output : CSprite
|
||||
//-----------------------------------------------------------------------------
|
||||
CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, bool animate )
|
||||
{
|
||||
CSprite *pSprite = CREATE_ENTITY( CSprite, "env_sprite" );
|
||||
pSprite->SpriteInit( pSpriteName, origin );
|
||||
pSprite->SetSolid( SOLID_NONE );
|
||||
UTIL_SetSize( pSprite, vec3_origin, vec3_origin );
|
||||
pSprite->SetMoveType( MOVETYPE_NONE );
|
||||
if ( animate )
|
||||
pSprite->TurnOn();
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pSpriteName -
|
||||
// &origin -
|
||||
// animate -
|
||||
// Output : CSprite
|
||||
//-----------------------------------------------------------------------------
|
||||
CSprite *CSprite::SpriteCreatePredictable( const char *module, int line, const char *pSpriteName, const Vector &origin, bool animate )
|
||||
{
|
||||
CSprite *pSprite = ( CSprite * )CBaseEntity::CreatePredictedEntityByName( "env_sprite", module, line );
|
||||
if ( pSprite )
|
||||
{
|
||||
pSprite->SpriteInit( pSpriteName, origin );
|
||||
pSprite->SetSolid( SOLID_NONE );
|
||||
pSprite->SetSize( vec3_origin, vec3_origin );
|
||||
pSprite->SetMoveType( MOVETYPE_NONE );
|
||||
if ( animate )
|
||||
pSprite->TurnOn();
|
||||
}
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::AnimateThink( void )
|
||||
{
|
||||
Animate( m_flSpriteFramerate * (gpGlobals->curtime - m_flLastTime) );
|
||||
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
m_flLastTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::AnimateUntilDead( void )
|
||||
{
|
||||
if ( gpGlobals->curtime > m_flDieTime )
|
||||
{
|
||||
Remove( );
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimateThink();
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : scaleSpeed -
|
||||
// fadeSpeed -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::Expand( float scaleSpeed, float fadeSpeed )
|
||||
{
|
||||
m_flSpeed = scaleSpeed;
|
||||
m_iHealth = fadeSpeed;
|
||||
SetThink( &CSprite::ExpandThink );
|
||||
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
m_flLastTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::ExpandThink( void )
|
||||
{
|
||||
float frametime = gpGlobals->curtime - m_flLastTime;
|
||||
SetSpriteScale( m_flSpriteScale + m_flSpeed * frametime );
|
||||
|
||||
int sub = (int)(m_iHealth * frametime);
|
||||
if ( sub > GetRenderAlpha() )
|
||||
{
|
||||
SetRenderAlpha( 0 );
|
||||
Remove( );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRenderAlpha( GetRenderAlpha() - sub );
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
m_flLastTime = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : frames -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::Animate( float frames )
|
||||
{
|
||||
m_flFrame += frames;
|
||||
if ( m_flFrame > m_flMaxFrame )
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
if ( m_spawnflags & SF_SPRITE_ONCE )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if ( m_flMaxFrame > 0 )
|
||||
m_flFrame = fmod( m_flFrame, m_flMaxFrame );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::SetBrightness( int brightness, float time )
|
||||
{
|
||||
m_nBrightness = brightness; //Take our current position as our starting position
|
||||
m_flBrightnessTime = time;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::SetSpriteScale( float scale )
|
||||
{
|
||||
if ( scale != m_flSpriteScale )
|
||||
{
|
||||
m_flSpriteScale = scale; //Take our current position as our new starting position
|
||||
// The surrounding box is based on sprite scale... it changes, box is dirty
|
||||
CollisionProp()->MarkSurroundingBoundsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void CSprite::SetScale( float scale, float time )
|
||||
{
|
||||
m_flScaleTime = time;
|
||||
SetSpriteScale( scale );
|
||||
// The surrounding box is based on sprite scale... it changes, box is dirty
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::TurnOff( void )
|
||||
{
|
||||
AddEffects( EF_NODRAW );
|
||||
SetNextThink( TICK_NEVER_THINK );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::TurnOn( void )
|
||||
{
|
||||
RemoveEffects( EF_NODRAW );
|
||||
if ( (m_flSpriteFramerate && m_flMaxFrame > 1.0)
|
||||
#if !defined( CLIENT_DLL )
|
||||
|| (m_spawnflags & SF_SPRITE_ONCE)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
SetThink( &CSprite::AnimateThink );
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
m_flLastTime = gpGlobals->curtime;
|
||||
}
|
||||
m_flFrame = 0;
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
// DVS TODO: Obsolete Use handler
|
||||
void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
int on = !IsEffectActive( EF_NODRAW );
|
||||
if ( ShouldToggle( useType, on ) )
|
||||
{
|
||||
if ( on )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
TurnOn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Input handler that hides the sprite.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::InputHideSprite( inputdata_t &inputdata )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Input handler that hides the sprite.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::InputShowSprite( inputdata_t &inputdata )
|
||||
{
|
||||
TurnOn();
|
||||
}
|
||||
|
||||
void CSprite::InputColorRedValue( inputdata_t &inputdata )
|
||||
{
|
||||
int nNewColor = clamp( inputdata.value.Float(), 0, 255 );
|
||||
SetColor( nNewColor, m_clrRender->g, m_clrRender->b );
|
||||
}
|
||||
|
||||
void CSprite::InputColorGreenValue( inputdata_t &inputdata )
|
||||
{
|
||||
int nNewColor = clamp( inputdata.value.Float(), 0, 255 );
|
||||
SetColor( m_clrRender->r, nNewColor, m_clrRender->b );
|
||||
}
|
||||
|
||||
void CSprite::InputColorBlueValue( inputdata_t &inputdata )
|
||||
{
|
||||
int nNewColor = clamp( inputdata.value.Float(), 0, 255 );
|
||||
SetColor( m_clrRender->r, m_clrRender->g, nNewColor );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Input handler that toggles the sprite between hidden and shown.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::InputToggleSprite( inputdata_t &inputdata )
|
||||
{
|
||||
if ( !IsEffectActive( EF_NODRAW ) )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
TurnOn();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
float CSprite::GetRenderScale( void )
|
||||
{
|
||||
//See if we're done scaling
|
||||
if ( ( m_flScaleTime == 0 ) || ( (m_flScaleTimeStart+m_flScaleTime) < gpGlobals->curtime ) )
|
||||
return m_flSpriteScale;
|
||||
|
||||
//Get our percentage
|
||||
float timeDelta = ( gpGlobals->curtime - m_flScaleTimeStart ) / m_flScaleTime;
|
||||
|
||||
//Return the result
|
||||
return ( m_flStartScale + ( ( m_flDestScale - m_flStartScale ) * timeDelta ) );
|
||||
}
|
||||
|
||||
float CSprite::GetMaxRenderScale( void )
|
||||
{
|
||||
//See if we're done scaling
|
||||
if ( m_flScaleTime == 0 )
|
||||
return m_flSpriteScale;
|
||||
|
||||
// return the max scale over the interval
|
||||
return MAX(m_flStartScale, m_flDestScale);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the rendered extents of the sprite
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::GetRenderBounds( Vector &vecMins, Vector &vecMaxs )
|
||||
{
|
||||
// NOTE: Don't call GetRenderScale here because the bounds will get cached
|
||||
// if we don't blow away that cache every time the interpolant (curtime) changes
|
||||
// then it will be wrong as long as this is animating.
|
||||
// instead while animating just use the
|
||||
float flScale = GetMaxRenderScale() * 0.5f;
|
||||
|
||||
// If our scale is normalized we need to convert that to actual world units
|
||||
if ( m_bWorldSpaceScale == false )
|
||||
{
|
||||
CEngineSprite *psprite = (CEngineSprite *) modelinfo->GetModelExtraData( GetModel() );
|
||||
if ( psprite )
|
||||
{
|
||||
float flSize = MAX( psprite->GetWidth(), psprite->GetHeight() );
|
||||
flScale *= flSize;
|
||||
}
|
||||
}
|
||||
|
||||
vecMins.Init( -flScale, -flScale, -flScale );
|
||||
vecMaxs.Init( flScale, flScale, flScale );
|
||||
|
||||
#if 0
|
||||
// Visualize the bounds
|
||||
debugoverlay->AddBoxOverlay( GetRenderOrigin(), vecMins, vecMaxs, GetRenderAngles(), 255, 255, 255, 0, 0.01f );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CSprite::GetRenderBrightness( void )
|
||||
{
|
||||
//See if we're done scaling
|
||||
if ( ( m_flBrightnessTime == 0 ) || ( (m_flBrightnessTimeStart+m_flBrightnessTime) < gpGlobals->curtime ) )
|
||||
{
|
||||
return m_nBrightness;
|
||||
}
|
||||
|
||||
//Get our percentage
|
||||
float timeDelta = ( gpGlobals->curtime - m_flBrightnessTimeStart ) / m_flBrightnessTime;
|
||||
|
||||
float brightness = ( (float) m_nStartBrightness + ( (float) ( m_nDestBrightness - m_nStartBrightness ) * timeDelta ) );
|
||||
|
||||
//Return the result
|
||||
return (int) brightness;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSprite::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
m_flStartScale = m_flDestScale = m_flSpriteScale;
|
||||
m_nStartBrightness = m_nDestBrightness = m_nBrightness;
|
||||
}
|
||||
|
||||
UpdateVisibility();
|
||||
|
||||
if ( m_flSpriteScale != m_flDestScale || m_nBrightness != m_nDestBrightness )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_NEVER );
|
||||
}
|
||||
}
|
||||
|
||||
void CSprite::ClientThink( void )
|
||||
{
|
||||
bool bDisableThink = true;
|
||||
// Module render colors over time
|
||||
if ( m_flSpriteScale != m_flDestScale )
|
||||
{
|
||||
m_flStartScale = m_flDestScale;
|
||||
m_flDestScale = m_flSpriteScale;
|
||||
m_flScaleTimeStart = gpGlobals->curtime;
|
||||
bDisableThink = false;
|
||||
}
|
||||
|
||||
if ( m_nBrightness != m_nDestBrightness )
|
||||
{
|
||||
m_nStartBrightness = m_nDestBrightness;
|
||||
m_nDestBrightness = m_nBrightness;
|
||||
m_flBrightnessTimeStart = gpGlobals->curtime;
|
||||
bDisableThink = false;
|
||||
}
|
||||
|
||||
// changed bounds
|
||||
InvalidatePhysicsRecursive(BOUNDS_CHANGED);
|
||||
if ( bDisableThink )
|
||||
{
|
||||
SetNextClientThink(CLIENT_THINK_NEVER);
|
||||
}
|
||||
}
|
||||
|
||||
extern bool g_bRenderingScreenshot;
|
||||
extern ConVar r_drawviewmodel;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : flags -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CSprite::DrawModel( int flags, const RenderableInstance_t &instance )
|
||||
{
|
||||
VPROF_BUDGET( "CSprite::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
||||
//See if we should draw
|
||||
if ( !IsVisible() || ( m_bReadyToDraw == false ) )
|
||||
return 0;
|
||||
|
||||
// Tracker 16432: If rendering a savegame screenshot then don't draw sprites
|
||||
// who have viewmodels as their moveparent
|
||||
if ( g_bRenderingScreenshot || !r_drawviewmodel.GetBool() )
|
||||
{
|
||||
C_BaseViewModel *vm = ToBaseViewModel( GetMoveParent() );
|
||||
if ( vm )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Must be a sprite
|
||||
if ( modelinfo->GetModelType( GetModel() ) != mod_sprite )
|
||||
{
|
||||
const char *modelName = modelinfo->GetModelName( GetModel() );
|
||||
char msg[256];
|
||||
V_snprintf( msg, 256, "Sprite %d has non-mod_sprite model %s (type %d)\n",
|
||||
entindex(), modelName, modelinfo->GetModelType( GetModel() ) );
|
||||
AssertMsgOnce( 0, msg );
|
||||
return 0;
|
||||
}
|
||||
|
||||
float renderscale = GetRenderScale();
|
||||
if ( m_bWorldSpaceScale )
|
||||
{
|
||||
CEngineSprite *psprite = ( CEngineSprite * )modelinfo->GetModelExtraData( GetModel() );
|
||||
float flMinSize = MIN( psprite->GetWidth(), psprite->GetHeight() );
|
||||
renderscale /= flMinSize;
|
||||
}
|
||||
|
||||
//Draw it
|
||||
int drawn = DrawSprite(
|
||||
this,
|
||||
GetModel(),
|
||||
GetAbsOrigin(),
|
||||
GetAbsAngles(),
|
||||
m_flFrame, // sprite frame to render
|
||||
m_hAttachedToEntity, // attach to
|
||||
m_nAttachment, // attachment point
|
||||
GetRenderMode(), // rendermode
|
||||
GetRenderFX(),
|
||||
(float)( GetRenderBrightness() * instance.m_nAlpha ) * ( 1.0f / 255.0f ) + 0.5f, // alpha
|
||||
GetRenderColorR(),
|
||||
GetRenderColorG(),
|
||||
GetRenderColorB(),
|
||||
renderscale, // sprite scale
|
||||
GetHDRColorScale() // HDR Color Scale
|
||||
);
|
||||
|
||||
return drawn;
|
||||
}
|
||||
|
||||
|
||||
const Vector& CSprite::GetRenderOrigin()
|
||||
{
|
||||
static Vector vOrigin;
|
||||
vOrigin = GetAbsOrigin();
|
||||
|
||||
if ( m_hAttachedToEntity )
|
||||
{
|
||||
C_BaseEntity *ent = m_hAttachedToEntity->GetBaseEntity();
|
||||
if ( ent )
|
||||
{
|
||||
QAngle dummyAngles;
|
||||
ent->GetAttachment( m_nAttachment, vOrigin, dummyAngles );
|
||||
}
|
||||
}
|
||||
|
||||
return vOrigin;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: oriented sprites
|
||||
// CSprites swap the roll and yaw angle inputs, and rotate the yaw 180 degrees
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
IMPLEMENT_SERVERCLASS_ST( CSpriteOriented, DT_SpriteOriented )
|
||||
END_SEND_TABLE()
|
||||
#else
|
||||
#undef CSpriteOriented
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_SpriteOriented, DT_SpriteOriented, CSpriteOriented)
|
||||
#define CSpriteOriented C_SpriteOriented
|
||||
END_RECV_TABLE()
|
||||
#endif
|
||||
LINK_ENTITY_TO_CLASS_ALIASED( env_sprite_oriented, SpriteOriented );
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
void CSpriteOriented::Spawn( void )
|
||||
{
|
||||
// save a copy of the angles, CSprite swaps the yaw and roll
|
||||
QAngle angles = GetAbsAngles();
|
||||
BaseClass::Spawn();
|
||||
// ORIENTED sprites "forward" vector points in the players "view" direction, not the direction "out" from the sprite (gah)
|
||||
angles.y = anglemod( angles.y + 180 );
|
||||
SetAbsAngles( angles );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
RenderableTranslucencyType_t CSpriteOriented::ComputeTranslucencyType()
|
||||
{
|
||||
return RENDERABLE_IS_TRANSLUCENT;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,310 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "predictable_entity.h"
|
||||
#include "baseentity_shared.h"
|
||||
|
||||
#define SF_SPRITE_STARTON 0x0001
|
||||
#define SF_SPRITE_ONCE 0x0002
|
||||
#define SF_SPRITE_TEMPORARY 0x8000
|
||||
|
||||
class CBasePlayer;
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CSprite C_Sprite
|
||||
#define CSpriteOriented C_SpriteOriented
|
||||
#include "c_pixel_visibility.h"
|
||||
class CEngineSprite;
|
||||
|
||||
class C_SpriteRenderer
|
||||
{
|
||||
public:
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sprite orientations
|
||||
// WARNING! Change these in common/MaterialSystem/Sprite.cpp if you change them here!
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef enum
|
||||
{
|
||||
SPR_VP_PARALLEL_UPRIGHT = 0,
|
||||
SPR_FACING_UPRIGHT = 1,
|
||||
SPR_VP_PARALLEL = 2,
|
||||
SPR_ORIENTED = 3,
|
||||
SPR_VP_PARALLEL_ORIENTED = 4
|
||||
} SPRITETYPE;
|
||||
|
||||
// Determine sprite orientation
|
||||
static void GetSpriteAxes( SPRITETYPE type,
|
||||
const Vector& origin,
|
||||
const QAngle& angles,
|
||||
Vector& forward,
|
||||
Vector& right,
|
||||
Vector& up );
|
||||
|
||||
// Sprites can alter blending amount
|
||||
virtual float GlowBlend( CEngineSprite *psprite, const Vector& entorigin, int rendermode, int renderfx, int alpha, float *scale );
|
||||
|
||||
// Draws tempent as a sprite
|
||||
int DrawSprite(
|
||||
IClientEntity *entity,
|
||||
const model_t *model,
|
||||
const Vector& origin,
|
||||
const QAngle& angles,
|
||||
float frame,
|
||||
IClientEntity *attachedto,
|
||||
int attachmentindex,
|
||||
int rendermode,
|
||||
int renderfx,
|
||||
int alpha,
|
||||
int r,
|
||||
int g,
|
||||
int b,
|
||||
float scale,
|
||||
float flHDRColorScale = 1.0f
|
||||
);
|
||||
|
||||
protected:
|
||||
pixelvis_handle_t m_queryHandle;
|
||||
float m_flGlowProxySize;
|
||||
float m_flHDRColorScale;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class CSprite : public CBaseEntity
|
||||
#if defined( CLIENT_DLL )
|
||||
, public C_SpriteRenderer
|
||||
#endif
|
||||
{
|
||||
DECLARE_CLASS( CSprite, CBaseEntity );
|
||||
public:
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_NETWORKCLASS();
|
||||
|
||||
CSprite();
|
||||
virtual ~CSprite();
|
||||
|
||||
virtual void SetModel( const char *szModelName );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
virtual bool IsSprite( void ) const
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
bool IsClientOnly() const { return m_bClientOnly; }
|
||||
#endif
|
||||
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
void SetGlowProxySize( float flSize ) { m_flGlowProxySize = flSize; }
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
virtual int UpdateTransmitState( void );
|
||||
|
||||
void SetAsTemporary( void ) { AddSpawnFlags( SF_SPRITE_TEMPORARY ); }
|
||||
bool IsTemporary( void ) { return ( HasSpawnFlags( SF_SPRITE_TEMPORARY ) ); }
|
||||
|
||||
int ObjectCaps( void )
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if ( IsTemporary() )
|
||||
{
|
||||
flags = FCAP_DONT_SAVE;
|
||||
}
|
||||
|
||||
return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
|
||||
}
|
||||
|
||||
void OnRestore();
|
||||
#endif
|
||||
|
||||
void AnimateThink( void );
|
||||
void ExpandThink( void );
|
||||
void Animate( float frames );
|
||||
void Expand( float scaleSpeed, float fadeSpeed );
|
||||
void SpriteInit( const char *pSpriteName, const Vector &origin );
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
// Input handlers
|
||||
void InputHideSprite( inputdata_t &inputdata );
|
||||
void InputShowSprite( inputdata_t &inputdata );
|
||||
void InputToggleSprite( inputdata_t &inputdata );
|
||||
void InputColorRedValue( inputdata_t &inputdata );
|
||||
void InputColorBlueValue( inputdata_t &inputdata );
|
||||
void InputColorGreenValue( inputdata_t &inputdata );
|
||||
#endif
|
||||
|
||||
inline void SetAttachment( CBaseEntity *pEntity, int attachment )
|
||||
{
|
||||
if ( pEntity )
|
||||
{
|
||||
m_hAttachedToEntity = pEntity;
|
||||
m_nAttachment = attachment;
|
||||
FollowEntity( pEntity );
|
||||
}
|
||||
}
|
||||
|
||||
void TurnOff( void );
|
||||
void TurnOn( void );
|
||||
bool IsOn() { return !IsEffectActive( EF_NODRAW ); }
|
||||
|
||||
inline float Frames( void ) { return m_flMaxFrame; }
|
||||
inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx )
|
||||
{
|
||||
SetRenderMode( (RenderMode_t)rendermode );
|
||||
SetColor( r, g, b );
|
||||
SetBrightness( a );
|
||||
SetRenderFX( (RenderFx_t)fx );
|
||||
}
|
||||
inline void SetTexture( int spriteIndex ) { SetModelIndex( spriteIndex ); }
|
||||
inline void SetColor( int r, int g, int b ) { SetRenderColor( r, g, b ); }
|
||||
|
||||
void SetBrightness( int brightness, float duration = 0.0f );
|
||||
void SetScale( float scale, float duration = 0.0f );
|
||||
void SetSpriteScale( float scale );
|
||||
void EnableWorldSpaceScale( bool bEnable );
|
||||
|
||||
float GetScale( void ) { return m_flSpriteScale; }
|
||||
int GetBrightness( void ) { return m_nBrightness; }
|
||||
float GetHDRColorScale( void ) { return m_flHDRColorScale; }
|
||||
|
||||
inline void FadeAndDie( float duration )
|
||||
{
|
||||
SetBrightness( 0, duration );
|
||||
SetThink(&CSprite::AnimateUntilDead);
|
||||
m_flDieTime = gpGlobals->curtime + duration;
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
inline void AnimateAndDie( float framerate )
|
||||
{
|
||||
SetThink(&CSprite::AnimateUntilDead);
|
||||
m_flSpriteFramerate = framerate;
|
||||
m_flDieTime = gpGlobals->curtime + (m_flMaxFrame / m_flSpriteFramerate);
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
inline void AnimateForTime( float framerate, float time )
|
||||
{
|
||||
SetThink(&CSprite::AnimateUntilDead);
|
||||
m_flSpriteFramerate = framerate;
|
||||
m_flDieTime = gpGlobals->curtime + time;
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
// FIXME: This completely blows.
|
||||
// Surely there's gotta be a better way.
|
||||
void FadeOutFromSpawn( )
|
||||
{
|
||||
SetThink(&CSprite::BeginFadeOutThink);
|
||||
SetNextThink( gpGlobals->curtime + 0.01f );
|
||||
}
|
||||
|
||||
void BeginFadeOutThink( )
|
||||
{
|
||||
FadeAndDie( 0.25f );
|
||||
}
|
||||
|
||||
void AnimateUntilDead( void );
|
||||
#if !defined( CLIENT_DLL )
|
||||
DECLARE_DATADESC();
|
||||
|
||||
static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, bool animate );
|
||||
#endif
|
||||
static CSprite *SpriteCreatePredictable( const char *module, int line, const char *pSpriteName, const Vector &origin, bool animate );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
float GetRenderScale( void );
|
||||
float GetMaxRenderScale( void );
|
||||
int GetRenderBrightness( void );
|
||||
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual const Vector& GetRenderOrigin();
|
||||
virtual void GetRenderBounds( Vector &vecMins, Vector &vecMaxs );
|
||||
virtual float GlowBlend( CEngineSprite *psprite, const Vector& entorigin, int rendermode, int renderfx, int alpha, float *scale );
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
virtual void ClientThink( void );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
static void RecreateAllClientside();
|
||||
static void DestroyAllClientside();
|
||||
static void ParseAllClientsideEntities(const char *pMapData);
|
||||
static const char *ParseClientsideEntity( const char *pEntData );
|
||||
|
||||
bool InitializeClientside();
|
||||
|
||||
virtual bool KeyValue( const char *szKeyName, const char *szValue ) ;
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
public:
|
||||
CNetworkHandle( CBaseEntity, m_hAttachedToEntity );
|
||||
CNetworkVar( int, m_nAttachment );
|
||||
CNetworkVar( float, m_flSpriteFramerate );
|
||||
CNetworkVar( float, m_flFrame );
|
||||
|
||||
float m_flDieTime;
|
||||
|
||||
private:
|
||||
|
||||
CNetworkVar( int, m_nBrightness );
|
||||
CNetworkVar( float, m_flBrightnessTime );
|
||||
|
||||
CNetworkVar( float, m_flSpriteScale );
|
||||
CNetworkVar( float, m_flScaleTime );
|
||||
CNetworkVar( bool, m_bWorldSpaceScale );
|
||||
CNetworkVar( float, m_flGlowProxySize );
|
||||
CNetworkVar( float, m_flHDRColorScale );
|
||||
|
||||
float m_flLastTime;
|
||||
float m_flMaxFrame;
|
||||
|
||||
float m_flStartScale;
|
||||
float m_flDestScale; //Destination scale
|
||||
float m_flScaleTimeStart; //Real time for start of scale
|
||||
int m_nStartBrightness;
|
||||
int m_nDestBrightness; //Destination brightness
|
||||
float m_flBrightnessTimeStart;//Real time for brightness
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool m_bClientOnly;
|
||||
#endif // CLIENT_DLL
|
||||
};
|
||||
|
||||
|
||||
class CSpriteOriented : public CSprite
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSpriteOriented, CSprite );
|
||||
#if !defined( CLIENT_DLL )
|
||||
DECLARE_SERVERCLASS();
|
||||
void Spawn( void );
|
||||
#else
|
||||
DECLARE_CLIENTCLASS();
|
||||
virtual RenderableTranslucencyType_t ComputeTranslucencyType();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Macro to wrap creation
|
||||
#define SPRITE_CREATE_PREDICTABLE( name, origin, animate ) \
|
||||
CSprite::SpriteCreatePredictable( __FILE__, __LINE__, name, origin, animate )
|
||||
|
||||
#endif // SPRITE_H
|
||||
@@ -0,0 +1,586 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "SpriteTrail.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "clientsideeffects.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "mathlib/vmatrix.h"
|
||||
#include "view.h"
|
||||
#include "beamdraw.h"
|
||||
#include "enginesprite.h"
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
extern CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode );
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constants
|
||||
//-----------------------------------------------------------------------------
|
||||
#define SCREEN_SPACE_TRAILS 0
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Save/Restore
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
BEGIN_SIMPLE_DATADESC( TrailPoint_t )
|
||||
// DEFINE_FIELD( m_vecScreenPos, FIELD_CLASSCHECK_IGNORE ) // do this or else we get a warning about multiply-defined fields
|
||||
#if SCREEN_SPACE_TRAILS
|
||||
DEFINE_FIELD( m_vecScreenPos, FIELD_VECTOR ),
|
||||
#else
|
||||
DEFINE_FIELD( m_vecScreenPos, FIELD_POSITION_VECTOR ),
|
||||
#endif
|
||||
|
||||
DEFINE_FIELD( m_flDieTime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_flTexCoord, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flWidthVariance,FIELD_FLOAT ),
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
BEGIN_DATADESC( CSpriteTrail )
|
||||
|
||||
DEFINE_KEYFIELD( m_flLifeTime, FIELD_FLOAT, "lifetime" ),
|
||||
DEFINE_KEYFIELD( m_flStartWidth, FIELD_FLOAT, "startwidth" ),
|
||||
DEFINE_KEYFIELD( m_flEndWidth, FIELD_FLOAT, "endwidth" ),
|
||||
DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "spritename" ),
|
||||
DEFINE_KEYFIELD( m_bAnimate, FIELD_BOOLEAN, "animate" ),
|
||||
DEFINE_FIELD( m_flStartWidthVariance, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flTextureRes, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flMinFadeLength, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_vecSkyboxOrigin, FIELD_POSITION_VECTOR ),
|
||||
DEFINE_FIELD( m_flSkyboxScale, FIELD_FLOAT ),
|
||||
|
||||
// These are client-only
|
||||
#if defined( CLIENT_DLL )
|
||||
DEFINE_EMBEDDED_AUTO_ARRAY( m_vecSteps ),
|
||||
DEFINE_FIELD( m_nFirstStep, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nStepCount, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flUpdateTime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_vecPrevSkyboxOrigin, FIELD_POSITION_VECTOR ),
|
||||
DEFINE_FIELD( m_flPrevSkyboxScale, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_vecRenderMins, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( m_vecRenderMaxs, FIELD_VECTOR ),
|
||||
#endif
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Networking
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( SpriteTrail, DT_SpriteTrail );
|
||||
|
||||
BEGIN_NETWORK_TABLE( CSpriteTrail, DT_SpriteTrail )
|
||||
#if !defined( CLIENT_DLL )
|
||||
SendPropFloat( SENDINFO(m_flLifeTime), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flStartWidth), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flEndWidth), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flStartWidthVariance), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flTextureRes), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flMinFadeLength), 0, SPROP_NOSCALE ),
|
||||
SendPropVector( SENDINFO(m_vecSkyboxOrigin),0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flSkyboxScale), 0, SPROP_NOSCALE ),
|
||||
#else
|
||||
RecvPropFloat( RECVINFO(m_flLifeTime)),
|
||||
RecvPropFloat( RECVINFO(m_flStartWidth)),
|
||||
RecvPropFloat( RECVINFO(m_flEndWidth)),
|
||||
RecvPropFloat( RECVINFO(m_flStartWidthVariance)),
|
||||
RecvPropFloat( RECVINFO(m_flTextureRes)),
|
||||
RecvPropFloat( RECVINFO(m_flMinFadeLength)),
|
||||
RecvPropVector( RECVINFO(m_vecSkyboxOrigin)),
|
||||
RecvPropFloat( RECVINFO(m_flSkyboxScale)),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS_ALIASED( env_spritetrail, SpriteTrail );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prediction
|
||||
//-----------------------------------------------------------------------------
|
||||
BEGIN_PREDICTION_DATA( CSpriteTrail )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CSpriteTrail::CSpriteTrail( void )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
m_nFirstStep = 0;
|
||||
m_nStepCount = 0;
|
||||
#endif
|
||||
|
||||
m_flStartWidthVariance = 0;
|
||||
m_vecSkyboxOrigin.Init( 0, 0, 0 );
|
||||
m_flSkyboxScale = 1.0f;
|
||||
m_flEndWidth = -1.0f;
|
||||
}
|
||||
|
||||
void CSpriteTrail::Spawn( void )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
BaseClass::Spawn();
|
||||
#else
|
||||
|
||||
if ( GetModelName() != NULL_STRING )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
return;
|
||||
}
|
||||
|
||||
SetModelName( m_iszSpriteName );
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetSolid( SOLID_NONE );
|
||||
SetMoveType( MOVETYPE_NOCLIP );
|
||||
|
||||
SetCollisionBounds( vec3_origin, vec3_origin );
|
||||
TurnOn();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets parameters of the sprite trail
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
if ( m_iszSpriteName != NULL_STRING )
|
||||
{
|
||||
PrecacheModel( STRING(m_iszSpriteName) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets parameters of the sprite trail
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::SetLifeTime( float time )
|
||||
{
|
||||
m_flLifeTime = time;
|
||||
}
|
||||
|
||||
void CSpriteTrail::SetStartWidth( float flStartWidth )
|
||||
{
|
||||
m_flStartWidth = flStartWidth;
|
||||
m_flStartWidth /= m_flSkyboxScale;
|
||||
}
|
||||
|
||||
void CSpriteTrail::SetStartWidthVariance( float flStartWidthVariance )
|
||||
{
|
||||
m_flStartWidthVariance = flStartWidthVariance;
|
||||
m_flStartWidthVariance /= m_flSkyboxScale;
|
||||
}
|
||||
|
||||
void CSpriteTrail::SetEndWidth( float flEndWidth )
|
||||
{
|
||||
m_flEndWidth = flEndWidth;
|
||||
m_flEndWidth /= m_flSkyboxScale;
|
||||
}
|
||||
|
||||
void CSpriteTrail::SetTextureResolution( float flTexelsPerInch )
|
||||
{
|
||||
m_flTextureRes = flTexelsPerInch;
|
||||
m_flTextureRes *= m_flSkyboxScale;
|
||||
}
|
||||
|
||||
void CSpriteTrail::SetMinFadeLength( float flMinFadeLength )
|
||||
{
|
||||
m_flMinFadeLength = flMinFadeLength;
|
||||
m_flMinFadeLength /= m_flSkyboxScale;
|
||||
}
|
||||
|
||||
void CSpriteTrail::SetSkybox( const Vector &vecSkyboxOrigin, float flSkyboxScale )
|
||||
{
|
||||
m_flTextureRes /= m_flSkyboxScale;
|
||||
m_flMinFadeLength *= m_flSkyboxScale;
|
||||
m_flStartWidth *= m_flSkyboxScale;
|
||||
m_flEndWidth *= m_flSkyboxScale;
|
||||
m_flStartWidthVariance *= m_flSkyboxScale;
|
||||
|
||||
m_vecSkyboxOrigin = vecSkyboxOrigin;
|
||||
m_flSkyboxScale = flSkyboxScale;
|
||||
|
||||
m_flTextureRes *= m_flSkyboxScale;
|
||||
m_flMinFadeLength /= m_flSkyboxScale;
|
||||
m_flStartWidth /= m_flSkyboxScale;
|
||||
m_flEndWidth /= m_flSkyboxScale;
|
||||
m_flStartWidthVariance /= m_flSkyboxScale;
|
||||
|
||||
if ( IsInSkybox() )
|
||||
{
|
||||
AddEFlags( EFL_IN_SKYBOX );
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveEFlags( EFL_IN_SKYBOX );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is the trail in the skybox?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSpriteTrail::IsInSkybox() const
|
||||
{
|
||||
return (m_flSkyboxScale != 1.0f) || (m_vecSkyboxOrigin != vec3_origin);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// On data update
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::OnPreDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnPreDataChanged( updateType );
|
||||
m_vecPrevSkyboxOrigin = m_vecSkyboxOrigin;
|
||||
m_flPrevSkyboxScale = m_flSkyboxScale;
|
||||
}
|
||||
|
||||
void CSpriteTrail::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_flPrevSkyboxScale != m_flSkyboxScale) || (m_vecPrevSkyboxOrigin != m_vecSkyboxOrigin))
|
||||
{
|
||||
ConvertSkybox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compute position + bounding box
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::ClientThink()
|
||||
{
|
||||
// Update the trail + bounding box
|
||||
UpdateTrail();
|
||||
UpdateBoundingBox();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Render bounds
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::GetRenderBounds( Vector& mins, Vector& maxs )
|
||||
{
|
||||
mins = m_vecRenderMins;
|
||||
maxs = m_vecRenderMaxs;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Converts the trail when it changes skyboxes
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::ConvertSkybox()
|
||||
{
|
||||
for ( int i = 0; i < m_nStepCount; ++i )
|
||||
{
|
||||
// This makes it so that we're always drawing to the current location
|
||||
TrailPoint_t *pPoint = GetTrailPoint(i);
|
||||
|
||||
VectorSubtract( pPoint->m_vecScreenPos, m_vecPrevSkyboxOrigin, pPoint->m_vecScreenPos );
|
||||
pPoint->m_vecScreenPos *= m_flPrevSkyboxScale / m_flSkyboxScale;
|
||||
VectorSubtract( pPoint->m_vecScreenPos, m_vecSkyboxOrigin, pPoint->m_vecScreenPos );
|
||||
pPoint->m_flWidthVariance *= m_flPrevSkyboxScale / m_flSkyboxScale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets at the nth item in the list
|
||||
//-----------------------------------------------------------------------------
|
||||
TrailPoint_t *CSpriteTrail::GetTrailPoint( int n )
|
||||
{
|
||||
Assert( n < MAX_SPRITE_TRAIL_POINTS );
|
||||
COMPILE_TIME_ASSERT( (MAX_SPRITE_TRAIL_POINTS & (MAX_SPRITE_TRAIL_POINTS-1)) == 0 );
|
||||
int nIndex = (n + m_nFirstStep) & MAX_SPRITE_TRAIL_MASK;
|
||||
return &m_vecSteps[nIndex];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::ComputeScreenPosition( Vector *pScreenPos )
|
||||
{
|
||||
#if SCREEN_SPACE_TRAILS
|
||||
VMatrix viewMatrix;
|
||||
materials->GetMatrix( MATERIAL_VIEW, &viewMatrix );
|
||||
*pScreenPos = viewMatrix * GetRenderOrigin();
|
||||
#else
|
||||
*pScreenPos = GetRenderOrigin();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compute position + bounding box
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::UpdateBoundingBox( void )
|
||||
{
|
||||
Vector vecRenderOrigin = GetRenderOrigin();
|
||||
m_vecRenderMins = vecRenderOrigin;
|
||||
m_vecRenderMaxs = vecRenderOrigin;
|
||||
|
||||
float flMaxWidth = m_flStartWidth;
|
||||
if (( m_flEndWidth >= 0.0f ) && ( m_flEndWidth > m_flStartWidth ))
|
||||
{
|
||||
flMaxWidth = m_flEndWidth;
|
||||
}
|
||||
|
||||
Vector mins, maxs;
|
||||
for ( int i = 0; i < m_nStepCount; ++i )
|
||||
{
|
||||
TrailPoint_t *pPoint = GetTrailPoint(i);
|
||||
|
||||
float flActualWidth = (flMaxWidth + pPoint->m_flWidthVariance) * 0.5f;
|
||||
Vector size( flActualWidth, flActualWidth, flActualWidth );
|
||||
VectorSubtract( pPoint->m_vecScreenPos, size, mins );
|
||||
VectorAdd( pPoint->m_vecScreenPos, size, maxs );
|
||||
|
||||
VectorMin( m_vecRenderMins, mins, m_vecRenderMins );
|
||||
VectorMax( m_vecRenderMaxs, maxs, m_vecRenderMaxs );
|
||||
}
|
||||
|
||||
m_vecRenderMins -= vecRenderOrigin;
|
||||
m_vecRenderMaxs -= vecRenderOrigin;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSpriteTrail::UpdateTrail( void )
|
||||
{
|
||||
// Can't update too quickly
|
||||
if ( m_flUpdateTime > gpGlobals->curtime )
|
||||
return;
|
||||
|
||||
Vector screenPos;
|
||||
ComputeScreenPosition( &screenPos );
|
||||
TrailPoint_t *pLast = m_nStepCount ? GetTrailPoint( m_nStepCount-1 ) : NULL;
|
||||
if ( ( pLast == NULL ) || ( pLast->m_vecScreenPos.DistToSqr( screenPos ) > 4.0f ) )
|
||||
{
|
||||
// If we're over our limit, steal the last point and put it up front
|
||||
if ( m_nStepCount >= MAX_SPRITE_TRAIL_POINTS )
|
||||
{
|
||||
--m_nStepCount;
|
||||
++m_nFirstStep;
|
||||
}
|
||||
|
||||
// Save off its screen position, not its world position
|
||||
TrailPoint_t *pNewPoint = GetTrailPoint( m_nStepCount );
|
||||
pNewPoint->m_vecScreenPos = screenPos;
|
||||
pNewPoint->m_flDieTime = gpGlobals->curtime + m_flLifeTime;
|
||||
pNewPoint->m_flWidthVariance = random->RandomFloat( -m_flStartWidthVariance, m_flStartWidthVariance );
|
||||
if (pLast)
|
||||
{
|
||||
pNewPoint->m_flTexCoord = pLast->m_flTexCoord + pLast->m_vecScreenPos.DistTo( screenPos ) * m_flTextureRes;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewPoint->m_flTexCoord = 0.0f;
|
||||
}
|
||||
|
||||
++m_nStepCount;
|
||||
}
|
||||
|
||||
// Don't update again for a bit
|
||||
m_flUpdateTime = gpGlobals->curtime + ( m_flLifeTime / (float) MAX_SPRITE_TRAIL_POINTS );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CSpriteTrail::DrawModel( int flags, const RenderableInstance_t &instance )
|
||||
{
|
||||
VPROF_BUDGET( "CSpriteTrail::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
||||
|
||||
// Must have at least one point
|
||||
if ( m_nStepCount < 1 )
|
||||
return 1;
|
||||
|
||||
//See if we should draw
|
||||
if ( !IsVisible() || ( m_bReadyToDraw == false ) )
|
||||
return 0;
|
||||
|
||||
CEngineSprite *pSprite = Draw_SetSpriteTexture( GetModel(), m_flFrame, GetRenderMode() );
|
||||
if ( pSprite == NULL )
|
||||
return 0;
|
||||
|
||||
// Specify all the segments.
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
CBeamSegDraw segDraw;
|
||||
segDraw.Start( pRenderContext, m_nStepCount + 1, pSprite->GetMaterial( GetRenderMode() ) );
|
||||
|
||||
// Setup the first point, always emanating from the attachment point
|
||||
TrailPoint_t *pLast = GetTrailPoint( m_nStepCount-1 );
|
||||
TrailPoint_t currentPoint;
|
||||
currentPoint.m_flDieTime = gpGlobals->curtime + m_flLifeTime;
|
||||
ComputeScreenPosition( ¤tPoint.m_vecScreenPos );
|
||||
currentPoint.m_flTexCoord = pLast->m_flTexCoord + currentPoint.m_vecScreenPos.DistTo(pLast->m_vecScreenPos) * m_flTextureRes;
|
||||
currentPoint.m_flWidthVariance = 0.0f;
|
||||
|
||||
#if SCREEN_SPACE_TRAILS
|
||||
VMatrix viewMatrix;
|
||||
materials->GetMatrix( MATERIAL_VIEW, &viewMatrix );
|
||||
viewMatrix = viewMatrix.InverseTR();
|
||||
#endif
|
||||
|
||||
TrailPoint_t *pPrevPoint = NULL;
|
||||
float flTailAlphaDist = m_flMinFadeLength;
|
||||
for ( int i = 0; i <= m_nStepCount; ++i )
|
||||
{
|
||||
// This makes it so that we're always drawing to the current location
|
||||
TrailPoint_t *pPoint = (i != m_nStepCount) ? GetTrailPoint(i) : ¤tPoint;
|
||||
|
||||
float flLifePerc = (pPoint->m_flDieTime - gpGlobals->curtime) / m_flLifeTime;
|
||||
flLifePerc = clamp( flLifePerc, 0.0f, 1.0f );
|
||||
|
||||
color24 c = GetRenderColor();
|
||||
BeamSeg_t curSeg;
|
||||
curSeg.m_color.r = c.r; curSeg.m_color.g = c.g; curSeg.m_color.b = c.b;
|
||||
|
||||
float flAlphaFade = flLifePerc;
|
||||
if ( flTailAlphaDist > 0.0f )
|
||||
{
|
||||
if ( pPrevPoint )
|
||||
{
|
||||
float flDist = pPoint->m_vecScreenPos.DistTo( pPrevPoint->m_vecScreenPos );
|
||||
flTailAlphaDist -= flDist;
|
||||
}
|
||||
|
||||
if ( flTailAlphaDist > 0.0f )
|
||||
{
|
||||
float flTailFade = Lerp( (m_flMinFadeLength - flTailAlphaDist) / m_flMinFadeLength, 0.0f, 1.0f );
|
||||
if ( flTailFade < flAlphaFade )
|
||||
{
|
||||
flAlphaFade = flTailFade;
|
||||
}
|
||||
}
|
||||
}
|
||||
curSeg.m_color.a = GetRenderBrightness() * flAlphaFade;
|
||||
|
||||
#if SCREEN_SPACE_TRAILS
|
||||
curSeg.m_vPos = viewMatrix * pPoint->m_vecScreenPos;
|
||||
#else
|
||||
curSeg.m_vPos = pPoint->m_vecScreenPos;
|
||||
#endif
|
||||
|
||||
if ( m_flEndWidth >= 0.0f )
|
||||
{
|
||||
curSeg.m_flWidth = Lerp( flLifePerc, m_flEndWidth.Get(), m_flStartWidth.Get() );
|
||||
}
|
||||
else
|
||||
{
|
||||
curSeg.m_flWidth = m_flStartWidth.Get();
|
||||
}
|
||||
curSeg.m_flWidth += pPoint->m_flWidthVariance;
|
||||
if ( curSeg.m_flWidth < 0.0f )
|
||||
{
|
||||
curSeg.m_flWidth = 0.0f;
|
||||
}
|
||||
|
||||
curSeg.m_flTexCoord = pPoint->m_flTexCoord;
|
||||
|
||||
segDraw.NextSeg( &curSeg );
|
||||
|
||||
// See if we're done with this bad boy
|
||||
if ( pPoint->m_flDieTime <= gpGlobals->curtime )
|
||||
{
|
||||
// Push this back onto the top for use
|
||||
++m_nFirstStep;
|
||||
--i;
|
||||
--m_nStepCount;
|
||||
}
|
||||
|
||||
pPrevPoint = pPoint;
|
||||
}
|
||||
|
||||
segDraw.End();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Vector const&
|
||||
//-----------------------------------------------------------------------------
|
||||
const Vector &CSpriteTrail::GetRenderOrigin( void )
|
||||
{
|
||||
static Vector vOrigin;
|
||||
vOrigin = GetAbsOrigin();
|
||||
|
||||
if ( m_hAttachedToEntity )
|
||||
{
|
||||
C_BaseEntity *ent = m_hAttachedToEntity->GetBaseEntity();
|
||||
if ( ent )
|
||||
{
|
||||
QAngle dummyAngles;
|
||||
ent->GetAttachment( m_nAttachment, vOrigin, dummyAngles );
|
||||
}
|
||||
}
|
||||
|
||||
return vOrigin;
|
||||
}
|
||||
|
||||
const QAngle &CSpriteTrail::GetRenderAngles( void )
|
||||
{
|
||||
return vec3_angle;
|
||||
}
|
||||
|
||||
#endif //CLIENT_DLL
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pSpriteName -
|
||||
// &origin -
|
||||
// animate -
|
||||
// Output : CSpriteTrail
|
||||
//-----------------------------------------------------------------------------
|
||||
CSpriteTrail *CSpriteTrail::SpriteTrailCreate( const char *pSpriteName, const Vector &origin, bool animate )
|
||||
{
|
||||
CSpriteTrail *pSprite = CREATE_ENTITY( CSpriteTrail, "env_spritetrail" );
|
||||
|
||||
pSprite->SpriteInit( pSpriteName, origin );
|
||||
pSprite->SetSolid( SOLID_NONE );
|
||||
pSprite->SetMoveType( MOVETYPE_NOCLIP );
|
||||
|
||||
UTIL_SetSize( pSprite, vec3_origin, vec3_origin );
|
||||
|
||||
if ( animate )
|
||||
{
|
||||
pSprite->TurnOn();
|
||||
}
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
#endif //CLIENT_DLL == false
|
||||
@@ -0,0 +1,111 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef SPRITETRAIL_H
|
||||
#define SPRITETRAIL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "Sprite.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CSpriteTrail C_SpriteTrail
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sprite trail
|
||||
//-----------------------------------------------------------------------------
|
||||
struct TrailPoint_t
|
||||
{
|
||||
DECLARE_SIMPLE_DATADESC();
|
||||
|
||||
Vector m_vecScreenPos;
|
||||
float m_flDieTime;
|
||||
float m_flTexCoord;
|
||||
float m_flWidthVariance;
|
||||
};
|
||||
|
||||
class CSpriteTrail : public CSprite
|
||||
{
|
||||
DECLARE_CLASS( CSpriteTrail, CSprite );
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
public:
|
||||
CSpriteTrail( void );
|
||||
|
||||
// Sets parameters of the sprite trail
|
||||
void SetLifeTime( float time );
|
||||
void SetStartWidth( float flStartWidth );
|
||||
void SetEndWidth( float flEndWidth );
|
||||
void SetStartWidthVariance( float flStartWidthVariance );
|
||||
void SetTextureResolution( float flTexelsPerInch );
|
||||
void SetMinFadeLength( float flMinFadeLength );
|
||||
void SetSkybox( const Vector &vecSkyboxOrigin, float flSkyboxScale );
|
||||
|
||||
// Is the trail in the skybox?
|
||||
bool IsInSkybox() const;
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
// Client only code
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual const Vector &GetRenderOrigin( void );
|
||||
virtual const QAngle &GetRenderAngles( void );
|
||||
|
||||
// On data update
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
|
||||
virtual void ClientThink();
|
||||
#else
|
||||
// Server only code
|
||||
static CSpriteTrail *SpriteTrailCreate( const char *pSpriteName, const Vector &origin, bool animate );
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined( CLIENT_DLL )
|
||||
enum
|
||||
{
|
||||
// NOTE: # of points max must be a power of two!
|
||||
MAX_SPRITE_TRAIL_POINTS = 64,
|
||||
MAX_SPRITE_TRAIL_MASK = 0x3F,
|
||||
};
|
||||
|
||||
TrailPoint_t *GetTrailPoint( int n );
|
||||
void UpdateTrail( void );
|
||||
void ComputeScreenPosition( Vector *pScreenPos );
|
||||
void ConvertSkybox();
|
||||
void UpdateBoundingBox( void );
|
||||
|
||||
TrailPoint_t m_vecSteps[MAX_SPRITE_TRAIL_POINTS];
|
||||
int m_nFirstStep;
|
||||
int m_nStepCount;
|
||||
float m_flUpdateTime;
|
||||
Vector m_vecPrevSkyboxOrigin;
|
||||
float m_flPrevSkyboxScale;
|
||||
Vector m_vecRenderMins;
|
||||
Vector m_vecRenderMaxs;
|
||||
#endif
|
||||
|
||||
CNetworkVar( float, m_flLifeTime ); // Amount of time before a new trail segment fades away
|
||||
CNetworkVar( float, m_flStartWidth ); // The starting scale
|
||||
CNetworkVar( float, m_flEndWidth ); // The ending scale
|
||||
CNetworkVar( float, m_flStartWidthVariance ); // The starting scale
|
||||
CNetworkVar( float, m_flTextureRes ); // Texture resolution along the trail
|
||||
CNetworkVar( float, m_flMinFadeLength ); // The end of the trail must fade out for this many units
|
||||
CNetworkVector( m_vecSkyboxOrigin ); // What's our skybox origin?
|
||||
CNetworkVar( float, m_flSkyboxScale ); // What's our skybox scale?
|
||||
|
||||
string_t m_iszSpriteName;
|
||||
bool m_bAnimate;
|
||||
};
|
||||
|
||||
#endif // SPRITETRAIL_H
|
||||
@@ -0,0 +1,160 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
#include "isaverestore.h"
|
||||
#include "saverestore_utlvector.h"
|
||||
#include "achievement_saverestore.h"
|
||||
#include "achievementmgr.h"
|
||||
#include "baseachievement.h"
|
||||
#include "utlmap.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static short ACHIEVEMENT_SAVE_RESTORE_VERSION = 2;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CAchievementSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
|
||||
{
|
||||
public:
|
||||
const char *GetBlockName()
|
||||
{
|
||||
return "Achievement";
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
|
||||
void Save( ISave *pSave )
|
||||
{
|
||||
CAchievementMgr *pAchievementMgr = CAchievementMgr::GetInstance();
|
||||
if ( !pAchievementMgr )
|
||||
return;
|
||||
|
||||
// save global achievement mgr state to separate file if there have been any changes, so in case of a crash
|
||||
// the global state is consistent with last save game
|
||||
pAchievementMgr->SaveGlobalStateIfDirty();
|
||||
|
||||
pSave->StartBlock( "Achievements" );
|
||||
int iTotalAchievements = pAchievementMgr->GetAchievementCount();
|
||||
short nSaveCount = 0;
|
||||
// count how many achievements should be saved.
|
||||
for ( int i = 0; i < iTotalAchievements; i++ )
|
||||
{
|
||||
// We only save games in SP games so the assumption of SINGLE_PLAYER_SLOT is valid
|
||||
IAchievement *pAchievement = pAchievementMgr->GetAchievementByIndex( i, SINGLE_PLAYER_SLOT );
|
||||
if ( pAchievement->ShouldSaveWithGame() )
|
||||
{
|
||||
nSaveCount++;
|
||||
}
|
||||
}
|
||||
// Write # of saved achievements
|
||||
pSave->WriteShort( &nSaveCount );
|
||||
// Write out each achievement
|
||||
for ( int i = 0; i < iTotalAchievements; i++ )
|
||||
{
|
||||
// We only save games in SP games so the assumption of SINGLE_PLAYER_SLOT is valid
|
||||
IAchievement *pAchievement = pAchievementMgr->GetAchievementByIndex( i, SINGLE_PLAYER_SLOT );
|
||||
if ( pAchievement->ShouldSaveWithGame() )
|
||||
{
|
||||
CBaseAchievement *pBaseAchievement = dynamic_cast< CBaseAchievement * >( pAchievement );
|
||||
if ( pBaseAchievement )
|
||||
{
|
||||
short iAchievementID = (short) pBaseAchievement->GetAchievementID();
|
||||
// write the achievement ID
|
||||
pSave->WriteShort( &iAchievementID );
|
||||
// write the achievement data
|
||||
pSave->WriteAll( pBaseAchievement, pBaseAchievement->GetDataDescMap() );
|
||||
}
|
||||
}
|
||||
}
|
||||
pSave->EndBlock();
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
|
||||
void WriteSaveHeaders( ISave *pSave )
|
||||
{
|
||||
pSave->WriteShort( &ACHIEVEMENT_SAVE_RESTORE_VERSION );
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
|
||||
void ReadRestoreHeaders( IRestore *pRestore )
|
||||
{
|
||||
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
|
||||
short version;
|
||||
pRestore->ReadShort( &version );
|
||||
// only load if version matches and if we are loading a game, not a transition
|
||||
m_fDoLoad = ( ( version == ACHIEVEMENT_SAVE_RESTORE_VERSION ) &&
|
||||
( ( MapLoad_LoadGame == gpGlobals->eLoadType ) || ( MapLoad_NewGame == gpGlobals->eLoadType ) )
|
||||
);
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
|
||||
void Restore( IRestore *pRestore, bool createPlayers )
|
||||
{
|
||||
CAchievementMgr *pAchievementMgr = CAchievementMgr::GetInstance();
|
||||
if ( !pAchievementMgr )
|
||||
return;
|
||||
|
||||
if ( m_fDoLoad )
|
||||
{
|
||||
pAchievementMgr->PreRestoreSavedGame();
|
||||
|
||||
pRestore->StartBlock();
|
||||
// read # of achievements
|
||||
int nSavedAchievements = pRestore->ReadShort();
|
||||
|
||||
while ( nSavedAchievements-- )
|
||||
{
|
||||
// read achievement ID
|
||||
int iAchievementID = pRestore->ReadShort();
|
||||
// find the corresponding achievement object
|
||||
// We only save games in SP games so the assumption of SINGLE_PLAYER_SLOT is valid
|
||||
CBaseAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievementID, SINGLE_PLAYER_SLOT );
|
||||
Assert( pAchievement ); // It's a bug if we don't understand this achievement
|
||||
if ( pAchievement )
|
||||
{
|
||||
// read achievement data
|
||||
pRestore->ReadAll( pAchievement, pAchievement->GetDataDescMap() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we don't recognize the achievement for some reason, read and discard the data and keep going
|
||||
CBaseAchievement ignored;
|
||||
pRestore->ReadAll( &ignored, ignored.GetDataDescMap() );
|
||||
}
|
||||
}
|
||||
pRestore->EndBlock();
|
||||
|
||||
pAchievementMgr->PostRestoreSavedGame();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_fDoLoad;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CAchievementSaveRestoreBlockHandler g_AchievementSaveRestoreBlockHandler;
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
ISaveRestoreBlockHandler *GetAchievementSaveRestoreBlockHandler()
|
||||
{
|
||||
return &g_AchievementSaveRestoreBlockHandler;
|
||||
}
|
||||
|
||||
|
||||
#endif // GAME_DLL
|
||||
@@ -0,0 +1,17 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ACHIEVEMENT_SAVERESTORE_H
|
||||
#define ACHIEVEMENT_SAVERESTORE_H
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
ISaveRestoreBlockHandler *GetAchievementSaveRestoreBlockHandler();
|
||||
|
||||
#endif // ACHIEVEMENT_SAVERESTORE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,230 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ACHIEVEMENTMGR_H
|
||||
#define ACHIEVEMENTMGR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
#include "matchmaking/imatchframework.h"
|
||||
#include "baseachievement.h"
|
||||
#include "GameEventListener.h"
|
||||
#include "iachievementmgr.h"
|
||||
#include "utlmap.h"
|
||||
#include "usermessages.h"
|
||||
|
||||
#ifndef NO_STEAM
|
||||
#include "steam/steam_api.h"
|
||||
#endif
|
||||
|
||||
#define THINK_CLEAR -1
|
||||
|
||||
enum SyncAchievementValueDirection_t
|
||||
{
|
||||
ACHIEVEMENT_WRITE_ACHIEVEMENT,
|
||||
ACHIEVEMENT_READ_ACHIEVEMENT
|
||||
};
|
||||
|
||||
typedef void* AsyncHandle_t;
|
||||
|
||||
class CAchievementMgr : public CAutoGameSystemPerFrame, public CGameEventListener, public IMatchEventsSink
|
||||
{
|
||||
public:
|
||||
CAchievementMgr();
|
||||
static CAchievementMgr * GetInstance();
|
||||
static IAchievementMgr * GetInstanceInterface();
|
||||
|
||||
virtual bool Init();
|
||||
virtual void PostInit();
|
||||
virtual void Shutdown();
|
||||
virtual void LevelInitPreEntity();
|
||||
virtual void LevelShutdownPreEntity();
|
||||
virtual void InitializeAchievements( );
|
||||
virtual void Update( float frametime );
|
||||
virtual bool IsPerFrame( void ) { return true; }
|
||||
|
||||
void OnMapEvent( const char *pchEventName, int nUserSlot );
|
||||
|
||||
// Interfaces exported to other dlls for achievement list queries
|
||||
IAchievement* GetAchievementByIndex( int index, int nUserSlot );
|
||||
IAchievement* GetAchievementByDisplayOrder( int orderIndex, int nUserSlot );
|
||||
IAchievement* GetAwardByDisplayOrder( int orderIndex, int nUserSlot );
|
||||
int GetAchievementCount( bool bAssets=false );
|
||||
|
||||
CBaseAchievement *GetAchievementByID( int iAchievementID, int nUserSlot );
|
||||
CUtlMap<int, CBaseAchievement *> &GetAchievements( int nUserSlot ) { return m_mapAchievement[nUserSlot]; }
|
||||
|
||||
CBaseAchievement *GetAchievementByName( const char *pchName, int nUserSlot );
|
||||
|
||||
void UploadUserData( int nUserSlot );
|
||||
void UserConnected( int nUserSlot );
|
||||
void UserDisconnected( int nUserSlot );
|
||||
bool IsUserConnected( int nUserSlot ) { return m_bUserSlotActive[nUserSlot]; }
|
||||
void ReadAchievementsFromTitleData( int iController, int iSlot );
|
||||
void SaveGlobalState();
|
||||
void SaveGlobalStateIfDirty();
|
||||
bool IsAchievementAllowedInGame( int iAchievementID );
|
||||
bool HasAchieved( const char *pchName, int nUserSlot );
|
||||
void AwardAchievement( int iAchievementID, int nUserSlot );
|
||||
#if defined ( _X360 )
|
||||
void AwardXBoxAchievement( int iAchievementID, int iXBoxAchievementID, int nUserSlot );
|
||||
#endif
|
||||
void UpdateAchievement( int iAchievementID, int nData, int nUserSlot );
|
||||
#if defined( CLIENT_DLL ) && !defined( NO_STEAM )
|
||||
void UpdateStateFromSteam_Internal( int nUserSlot );
|
||||
#endif
|
||||
void PreRestoreSavedGame();
|
||||
void PostRestoreSavedGame();
|
||||
void ResetAchievements();
|
||||
void ClearAchievements( int nUserSlot );
|
||||
void ResetAchievement( int iAchievementID );
|
||||
void PrintAchievementStatus();
|
||||
float GetLastClassChangeTime( int nUserSlot ) { return m_flLastClassChangeTime[nUserSlot]; }
|
||||
float GetTeamplayStartTime( int nUserSlot ) { return m_flTeamplayStartTime[nUserSlot]; }
|
||||
int GetMiniroundsCompleted( int nUserSlot ) { return m_iMiniroundsCompleted[nUserSlot]; }
|
||||
const char *GetMapName() { return m_szMap; }
|
||||
bool IsCurrentMap( const char *pszMapName );
|
||||
void OnAchievementEvent( int iAchievementID, int nUserSlot );
|
||||
void SetDirty( bool bDirty, int nUserSlot ) { m_bDirty[nUserSlot] = bDirty; }
|
||||
bool CheckAchievementsEnabled();
|
||||
|
||||
void CheckSignInState( bool bCheck ) { m_bCheckSigninState = bCheck; }
|
||||
|
||||
// IMatchEventsSink
|
||||
virtual void OnEvent( KeyValues *pEvent );
|
||||
|
||||
#if defined( CLIENT_DLL ) && !defined( NO_STEAM )
|
||||
bool LoggedIntoSteam() { return ( steamapicontext->SteamUser() && steamapicontext->SteamUserStats() && steamapicontext->SteamUser()->BLoggedOn() ); }
|
||||
#else
|
||||
bool LoggedIntoSteam() { return false; }
|
||||
#endif
|
||||
|
||||
float GetTimeLastUpload() { return m_flTimeLastUpload; } // time we last uploaded to Steam
|
||||
bool WereCheatsEverOn( void ) { return m_bCheatsEverOn; }
|
||||
|
||||
#if !defined(NO_STEAM)
|
||||
STEAM_CALLBACK( CAchievementMgr, Steam_OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored );
|
||||
#endif
|
||||
const CUtlVector<int>& GetAchievedDuringCurrentGame( int nPlayerSlot );
|
||||
void ResetAchievedDuringCurrentGame( int nPlayerSlot );
|
||||
|
||||
// [sbodenbender] brought over from orange box
|
||||
void SetAchievementThink( CBaseAchievement *pAchievement, float flThinkTime );
|
||||
|
||||
bool SyncAchievementsToTitleData( int iController, SyncAchievementValueDirection_t eOp );
|
||||
|
||||
void SendWriteProfileEvent();
|
||||
void SendResetProfileEvent();
|
||||
UIProfileInfo* GetUIProfileInfo() { return &m_UIProfileInfo; };
|
||||
void ResetProfileInfo();
|
||||
|
||||
bool GetWriteProfileResult() { return m_writeProfileResult; }
|
||||
void SetWriteProfileResult(bool result) { m_writeProfileResult = result; }
|
||||
|
||||
CUserMessageBinder m_UMCMsgAchievementEvent;
|
||||
|
||||
private:
|
||||
void FireGameEvent( IGameEvent *event );
|
||||
|
||||
// [sbodenbender] gobetween for UI and profile data
|
||||
UIProfileInfo m_UIProfileInfo;
|
||||
bool m_writeProfileResult;
|
||||
|
||||
void OnKillEvent( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event );
|
||||
void ResetAchievement_Internal( CBaseAchievement *pAchievement );
|
||||
|
||||
CUtlMap<int, CBaseAchievement *> m_mapAchievement[MAX_SPLITSCREEN_PLAYERS]; // map of all achievements
|
||||
CUtlVector<CBaseAchievement *> m_vecAchievement[MAX_SPLITSCREEN_PLAYERS]; // vector of all achievements for accessing by index
|
||||
CUtlVector<CBaseAchievement *> m_vecAward[MAX_SPLITSCREEN_PLAYERS]; // vector of all asset award achievements for accessing by index
|
||||
CUtlVector<CBaseAchievement *> m_vecKillEventListeners[MAX_SPLITSCREEN_PLAYERS]; // vector of achievements that are listening for kill events
|
||||
CUtlVector<CBaseAchievement *> m_vecMapEventListeners[MAX_SPLITSCREEN_PLAYERS]; // vector of achievements that are listening for map events
|
||||
CUtlVector<CBaseAchievement *> m_vecComponentListeners[MAX_SPLITSCREEN_PLAYERS]; // vector of achievements that are listening for components that make up an achievement
|
||||
CUtlVector<CBaseAchievement *> m_vecAchievementInOrder[MAX_SPLITSCREEN_PLAYERS]; // vector of all achievements for accessing by display order
|
||||
CUtlVector<CBaseAchievement *> m_vecAwardInOrder[MAX_SPLITSCREEN_PLAYERS]; // vector of all asset award achievements for accessing by display order
|
||||
|
||||
// [sbodenbender] brought over from orange box
|
||||
struct achievementthink_t
|
||||
{
|
||||
float m_flThinkTime;
|
||||
CBaseAchievement *pAchievement;
|
||||
};
|
||||
CUtlVector<achievementthink_t> m_vecThinkListeners; // vector of achievements that are actively thinking
|
||||
|
||||
float m_flLevelInitTime[MAX_SPLITSCREEN_PLAYERS];
|
||||
float m_flLastClassChangeTime[MAX_SPLITSCREEN_PLAYERS]; // Time when player last changed class
|
||||
float m_flTeamplayStartTime[MAX_SPLITSCREEN_PLAYERS]; // Time when player joined a non-spectating team. Not updated if she switches game teams; cleared if she joins spectator
|
||||
float m_iMiniroundsCompleted[MAX_SPLITSCREEN_PLAYERS]; // # of minirounds played since game start (for maps that have minirounds)
|
||||
char m_szMap[MAX_PATH]; // file base of map name, cached since we access it frequently in this form
|
||||
bool m_bDirty[MAX_SPLITSCREEN_PLAYERS]; // do we have interesting state that needs to be saved
|
||||
bool m_bUserSlotActive[MAX_SPLITSCREEN_PLAYERS];
|
||||
bool m_bCheatsEverOn; // have cheats ever been turned on in this level
|
||||
float m_flTimeLastUpload; // last time we uploaded to Steam
|
||||
|
||||
bool m_bCheckSigninState;
|
||||
bool m_bReadingFromTitleData;
|
||||
|
||||
#ifdef _X360
|
||||
struct PendingAchievementInfo_t {
|
||||
int nAchievementID; // Achievement we're waiting to check the status of
|
||||
int nUserSlot; // Which user is being awarded the achievement
|
||||
AsyncHandle_t pOverlappedResult; // Result we'll check again
|
||||
};
|
||||
|
||||
CUtlVector<PendingAchievementInfo_t> m_pendingAchievementState;
|
||||
#endif
|
||||
|
||||
CUtlVector<int> m_AchievementsAwarded[MAX_SPLITSCREEN_PLAYERS];
|
||||
CUtlVector<int> m_AchievementsAwardedDuringCurrentGame[MAX_SPLITSCREEN_PLAYERS];
|
||||
void ClearAchievementData( int nUserSlot );
|
||||
};
|
||||
|
||||
class CAchievementMgrDelegateIAchievementMgr : public IAchievementMgr
|
||||
{
|
||||
public:
|
||||
virtual IAchievement* GetAchievementByIndex( int index, int nPlayerSlot ) { return m_pDelegate->CAchievementMgr::GetAchievementByIndex( index, nPlayerSlot ); }
|
||||
virtual IAchievement* GetAchievementByDisplayOrder( int orderIndex, int nPlayerSlot ) { return m_pDelegate->CAchievementMgr::GetAchievementByDisplayOrder( orderIndex, nPlayerSlot ); }
|
||||
virtual IAchievement* GetAwardByDisplayOrder( int orderIndex, int nPlayerSlot ) { return m_pDelegate->CAchievementMgr::GetAwardByDisplayOrder( orderIndex, nPlayerSlot ); }
|
||||
virtual CBaseAchievement* GetAchievementByID ( int id, int nPlayerSlot ) { return m_pDelegate->CAchievementMgr::GetAchievementByID( id, nPlayerSlot ); }
|
||||
virtual int GetAchievementCount( bool bAssets = false ) { return m_pDelegate->CAchievementMgr::GetAchievementCount( bAssets ); }
|
||||
virtual void InitializeAchievements( ) { m_pDelegate->CAchievementMgr::InitializeAchievements(); }
|
||||
virtual void AwardAchievement( int nAchievementID, int nPlayerSlot ) { m_pDelegate->CAchievementMgr::AwardAchievement( nAchievementID, nPlayerSlot ); }
|
||||
virtual void OnMapEvent( const char *pchEventName, int nPlayerSlot ) { m_pDelegate->CAchievementMgr::OnMapEvent( pchEventName, nPlayerSlot ); }
|
||||
virtual void SaveGlobalStateIfDirty( ) { m_pDelegate->CAchievementMgr::SaveGlobalState(); }
|
||||
virtual bool HasAchieved( const char *pchName, int nPlayerSlot ) { return m_pDelegate->CAchievementMgr::HasAchieved( pchName, nPlayerSlot ); }
|
||||
virtual const CUtlVector<int>& GetAchievedDuringCurrentGame( int nPlayerSlot ) { return m_pDelegate->CAchievementMgr::GetAchievedDuringCurrentGame( nPlayerSlot ); }
|
||||
virtual bool WereCheatsEverOn() { return m_pDelegate->CAchievementMgr::WereCheatsEverOn(); }
|
||||
|
||||
virtual UIProfileInfo* GetUIProfileInfo() { return m_pDelegate->CAchievementMgr::GetUIProfileInfo(); }
|
||||
virtual void ResetProfileInfo() { m_pDelegate->CAchievementMgr::ResetProfileInfo(); }
|
||||
virtual void SendWriteProfileEvent() { m_pDelegate->CAchievementMgr::SendWriteProfileEvent(); }
|
||||
virtual void SendResetProfileEvent() { m_pDelegate->CAchievementMgr::SendResetProfileEvent(); }
|
||||
virtual bool GetWriteProfileResult() { return m_pDelegate->CAchievementMgr::GetWriteProfileResult(); }
|
||||
|
||||
explicit CAchievementMgrDelegateIAchievementMgr( CAchievementMgr *pDelegate ) : m_pDelegate( pDelegate ) {}
|
||||
|
||||
protected:
|
||||
CAchievementMgr *m_pDelegate;
|
||||
};
|
||||
|
||||
// helper functions
|
||||
const char *GetModelName( CBaseEntity *pBaseEntity );
|
||||
#if defined ( _X360 )
|
||||
bool IsXboxFriends( int userID, int entityIndex );
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool CalcPlayersOnFriendsList( int iMinPlayers );
|
||||
bool CalcHasNumClanPlayers( int iClanTeammates );
|
||||
int CalcPlayerCount();
|
||||
int CalcTeammateCount();
|
||||
#endif // CLIENT
|
||||
|
||||
extern ConVar cc_achievement_debug;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool MsgFunc_AchievementEvent( const CCSUsrMsg_AchievementEvent &msg );
|
||||
#endif // CLIENT_DLL
|
||||
#endif // ACHIEVEMENTMGR_H
|
||||
@@ -0,0 +1,17 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ACHIEVEMENT_SAVERESTORE_H
|
||||
#define ACHIEVEMENT_SAVERESTORE_H
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
ISaveRestoreBlockHandler *GetAchievementSaveRestoreBlockHandler();
|
||||
|
||||
#endif // ACHIEVEMENT_SAVERESTORE_H
|
||||
@@ -0,0 +1,50 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ACHIEVEMENTSANDSTATSINTERFACE_H
|
||||
#define ACHIEVEMENTSANDSTATSINTERFACE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "vgui_controls/Panel.h"
|
||||
#include "vgui_controls/Panel.h"
|
||||
#include "vgui_controls/PHandle.h"
|
||||
#include "vgui_controls/MenuItem.h"
|
||||
#include "vgui_controls/MessageDialog.h"
|
||||
#include "vgui/ISurface.h"
|
||||
|
||||
class AchievementsAndStatsInterface
|
||||
{
|
||||
public:
|
||||
AchievementsAndStatsInterface() { }
|
||||
|
||||
virtual void CreatePanel( vgui::Panel* pParent ) {}
|
||||
virtual void DisplayPanel() {}
|
||||
virtual void ReleasePanel() {}
|
||||
virtual int GetAchievementsPanelMinWidth( void ) const { return 0; }
|
||||
|
||||
protected:
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Positions a dialog on screen.
|
||||
//-----------------------------------------------------------------------------
|
||||
void PositionDialog(vgui::PHandle dlg)
|
||||
{
|
||||
if (!dlg.Get())
|
||||
return;
|
||||
|
||||
int x, y, ww, wt, wide, tall;
|
||||
vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
|
||||
dlg->GetSize(wide, tall);
|
||||
|
||||
// Center it, keeping requested size
|
||||
dlg->SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // ACHIEVEMENTSANDSTATSINTERFACE_H
|
||||
@@ -0,0 +1,257 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
// this gets compiled in for HL2 + Ep(X) only
|
||||
#if ( defined( HL2_DLL ) || defined( HL2_EPISODIC ) ) && ( !defined ( PORTAL ) )
|
||||
|
||||
#include "matchmaking/imatchframework.h"
|
||||
#include "baseachievement.h"
|
||||
#include "prop_combine_ball.h"
|
||||
#include "combine_mine.h"
|
||||
#include "basegrenade_shared.h"
|
||||
#include "basehlcombatweapon_shared.h"
|
||||
#include "ammodef.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
class CAchievementHLXKillWithPhysicsObjects : public CBaseAchievement
|
||||
{
|
||||
void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_WITH_GAME );
|
||||
SetInflictorFilter( "prop_physics" );
|
||||
SetGoal( 30 );
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// only in Ep2 for PC. (Shared across HLX for X360.)
|
||||
SetGameDirFilter( "ep2" );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
int iDamageBits = event->GetInt( "damagebits" );
|
||||
// was victim killed with crushing damage?
|
||||
if ( iDamageBits & DMG_CRUSH )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementHLXKillWithPhysicsObjects, ACHIEVEMENT_HLX_KILL_ENEMIES_WITHPHYSICS, "HLX_KILL_ENEMIES_WITHPHYSICS", 5 );
|
||||
|
||||
class CAchievementHLXKillWithHopper : public CBaseAchievement
|
||||
{
|
||||
void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_KILL_ENEMY_EVENTS | ACH_SAVE_WITH_GAME );
|
||||
SetAttackerFilter( "combine_mine" );
|
||||
SetGoal( 1 );
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// only in Ep2 for PC. (Shared across HLX for X360.)
|
||||
SetGameDirFilter( "ep2" );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
// If we get here, a combine mine has killed a player enemy. Now check and see if the player planted it
|
||||
CBounceBomb *pBounceBomb = dynamic_cast<CBounceBomb *>( pAttacker );
|
||||
if ( pBounceBomb && pBounceBomb->IsPlayerPlaced() )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementHLXKillWithHopper, ACHIEVEMENT_HLX_KILL_ENEMY_WITHHOPPERMINE, "HLX_KILL_ENEMY_WITHHOPPERMINE", 5 );
|
||||
|
||||
class CAchievementHLXKillWithManhack : public CBaseAchievement
|
||||
{
|
||||
void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_WITH_GAME );
|
||||
SetInflictorFilter( "npc_manhack" );
|
||||
SetGoal( 5 );
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// only in HL2 for PC. (Shared across HLX for X360.)
|
||||
SetGameDirFilter( "hl2" );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
// We've already filtered to only get called when a player enemy gets killed with a manhack. Now just check for the
|
||||
// case of player smashing manhack into something, in which case the manhack is both the victim and inflictor.
|
||||
// If that's not the case, this is a player kill w/manhack.
|
||||
if ( pVictim != pInflictor )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementHLXKillWithManhack, ACHIEVEMENT_HLX_KILL_ENEMIES_WITHMANHACK, "HLX_KILL_ENEMIES_WITHMANHACK", 5 );
|
||||
|
||||
class CAchievementHLXKillSoldierWithOwnGrenade : public CBaseAchievement
|
||||
{
|
||||
protected:
|
||||
void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_KILL_ENEMY_EVENTS | ACH_SAVE_WITH_GAME );
|
||||
SetInflictorFilter( "npc_grenade_frag" );
|
||||
SetVictimFilter( "npc_combine_s" );
|
||||
SetGoal( 1 );
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// only in Ep2 for PC. (Shared across HLX for X360.)
|
||||
SetGameDirFilter( "ep2" );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
CBaseGrenade *pGrenade = dynamic_cast<CBaseGrenade *>( pInflictor );
|
||||
if ( pGrenade )
|
||||
{
|
||||
CBaseEntity *pThrower = pGrenade->GetThrower();
|
||||
CBaseEntity *pOriginalThrower = pGrenade->GetOriginalThrower();
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
// check if player was most recent thrower, but the victim was the original thrower
|
||||
if ( ( pPlayer == pThrower ) && ( pOriginalThrower == pVictim ) )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementHLXKillSoldierWithOwnGrenade, ACHIEVEMENT_HLX_KILL_SOLDIER_WITHHISGRENADE, "HLX_KILL_SOLDIER_WITHHISGRENADE", 10 );
|
||||
|
||||
class CAchievementHLXKillWithOneEnergyBall : public CBaseAchievement
|
||||
{
|
||||
protected:
|
||||
virtual void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_WITH_GAME );
|
||||
SetInflictorFilter( "prop_combine_ball" );
|
||||
SetGoal( 1 );
|
||||
m_pLastInflictor = NULL;
|
||||
m_iLocalCount = 0;
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// only in Ep1 for PC. (Shared across HLX for X360.)
|
||||
SetGameDirFilter( "episodic" );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
// to count # of kills with same energy ball, keep track of previous inflictor
|
||||
if ( m_pLastInflictor != NULL && pInflictor != m_pLastInflictor )
|
||||
{
|
||||
// new inflictor, start the count over at 1
|
||||
m_iLocalCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// same inflictor, keep counting
|
||||
m_iLocalCount++;
|
||||
if ( 5 == m_iLocalCount )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
// keep track of last inflictor
|
||||
m_pLastInflictor = pInflictor;
|
||||
}
|
||||
CBaseEntity *m_pLastInflictor;
|
||||
int m_iLocalCount;
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementHLXKillWithOneEnergyBall, ACHIEVEMENT_HLX_KILL_ENEMIES_WITHONEENERGYBALL, "HLX_KILL_ENEMIES_WITHONEENERGYBALL", 5 );
|
||||
|
||||
class CAchievementHLXKillEliteSoldierWithOwnEnergyBall : public CBaseAchievement
|
||||
{
|
||||
protected:
|
||||
virtual void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_WITH_GAME );
|
||||
SetInflictorFilter( "prop_combine_ball" );
|
||||
SetVictimFilter( "npc_combine_s" );
|
||||
SetGoal( 1 );
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// only in Ep2 for PC. (Shared across HLX for X360.)
|
||||
SetGameDirFilter( "episodic" );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
CPropCombineBall *pBall = dynamic_cast<CPropCombineBall *>( pInflictor );
|
||||
if ( pBall )
|
||||
{
|
||||
// determine original owner of this ball
|
||||
CBaseEntity *pOriginalOwner = pBall->GetOriginalOwner();
|
||||
// see if original owner is the victim
|
||||
if ( pOriginalOwner && ( pOriginalOwner == pVictim ) )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementHLXKillEliteSoldierWithOwnEnergyBall, ACHIEVEMENT_HLX_KILL_ELITESOLDIER_WITHHISENERGYBALL, "HLX_KILL_ELITESOLDIER_WITHHISENERGYBALL", 10 );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Counts the accumulated # of primary and secondary attacks from all
|
||||
// weapons (except grav gun). If bBulletOnly is true, only counts
|
||||
// attacks with ammo that does bullet damage.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CalcPlayerAttacks( bool bBulletOnly )
|
||||
{
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
CAmmoDef *pAmmoDef = GetAmmoDef();
|
||||
if ( !pPlayer || !pAmmoDef )
|
||||
return 0;
|
||||
|
||||
int iTotalAttacks = 0;
|
||||
int iWeapons = pPlayer->WeaponCount();
|
||||
for ( int i = 0; i < iWeapons; i++ )
|
||||
{
|
||||
CBaseHLCombatWeapon *pWeapon = dynamic_cast<CBaseHLCombatWeapon *>( pPlayer->GetWeapon( i ) );
|
||||
if ( pWeapon )
|
||||
{
|
||||
// add primary attacks if we were asked for all attacks, or only if it uses bullet ammo if we were asked to count bullet attacks
|
||||
if ( !bBulletOnly || ( pAmmoDef->m_AmmoType[pWeapon->GetPrimaryAmmoType()].nDamageType == DMG_BULLET ) )
|
||||
{
|
||||
iTotalAttacks += pWeapon->m_iPrimaryAttacks;
|
||||
}
|
||||
// add secondary attacks if we were asked for all attacks, or only if it uses bullet ammo if we were asked to count bullet attacks
|
||||
if ( !bBulletOnly || ( pAmmoDef->m_AmmoType[pWeapon->GetSecondaryAmmoType()].nDamageType == DMG_BULLET ) )
|
||||
{
|
||||
iTotalAttacks += pWeapon->m_iSecondaryAttacks;
|
||||
}
|
||||
}
|
||||
}
|
||||
return iTotalAttacks;
|
||||
}
|
||||
|
||||
#endif // ( defined( HL2_DLL ) || defined( HL2_EPISODIC ) ) && ( !defined ( PORTAL ) )
|
||||
|
||||
#endif // GAME_DLL
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ACTIVITYLIST_H
|
||||
#define ACTIVITYLIST_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <keyvalues.h>
|
||||
|
||||
typedef struct activityentry_s activityentry_t;
|
||||
|
||||
class CActivityRemap
|
||||
{
|
||||
public:
|
||||
|
||||
CActivityRemap()
|
||||
{
|
||||
pExtraBlock = NULL;
|
||||
}
|
||||
|
||||
void SetExtraKeyValueBlock ( KeyValues *pKVBlock )
|
||||
{
|
||||
pExtraBlock = pKVBlock;
|
||||
}
|
||||
|
||||
KeyValues *GetExtraKeyValueBlock ( void ) { return pExtraBlock; }
|
||||
|
||||
Activity activity;
|
||||
Activity mappedActivity;
|
||||
|
||||
private:
|
||||
|
||||
KeyValues *pExtraBlock;
|
||||
};
|
||||
|
||||
|
||||
class CActivityRemapCache
|
||||
{
|
||||
public:
|
||||
|
||||
CActivityRemapCache()
|
||||
{
|
||||
}
|
||||
|
||||
CActivityRemapCache( const CActivityRemapCache& src )
|
||||
{
|
||||
int c = src.m_cachedActivityRemaps.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
m_cachedActivityRemaps.AddToTail( src.m_cachedActivityRemaps[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
CActivityRemapCache& operator = ( const CActivityRemapCache& src )
|
||||
{
|
||||
if ( this == &src )
|
||||
return *this;
|
||||
|
||||
int c = src.m_cachedActivityRemaps.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
m_cachedActivityRemaps.AddToTail( src.m_cachedActivityRemaps[ i ] );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CUtlVector< CActivityRemap > m_cachedActivityRemaps;
|
||||
};
|
||||
|
||||
void UTIL_LoadActivityRemapFile( const char *filename, const char *section, CUtlVector <CActivityRemap> &entries );
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
extern void ActivityList_Init( void );
|
||||
extern void ActivityList_Free( void );
|
||||
extern bool ActivityList_RegisterSharedActivity( const char *pszActivityName, int iActivityIndex );
|
||||
extern Activity ActivityList_RegisterPrivateActivity( const char *pszActivityName );
|
||||
extern int ActivityList_IndexForName( const char *pszActivityName );
|
||||
extern const char *ActivityList_NameForIndex( int iActivityIndex );
|
||||
extern int ActivityList_HighestIndex();
|
||||
|
||||
// This macro guarantees that the names of each activity and the constant used to
|
||||
// reference it in the code are identical.
|
||||
#define REGISTER_SHARED_ACTIVITY( _n ) ActivityList_RegisterSharedActivity(#_n, _n);
|
||||
#define REGISTER_PRIVATE_ACTIVITY( _n ) _n = ActivityList_RegisterPrivateActivity( #_n );
|
||||
|
||||
// Implemented in shared code
|
||||
extern void ActivityList_RegisterSharedActivities( void );
|
||||
|
||||
class ISaveRestoreOps;
|
||||
extern ISaveRestoreOps* ActivityDataOps();
|
||||
|
||||
#endif // ACTIVITYLIST_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef AI_DEBUG_SHARED_H
|
||||
#define AI_DEBUG_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
|
||||
// This uses VPROF to profile
|
||||
//#define VPROF_AI 1
|
||||
|
||||
|
||||
#ifdef VPROF_AI
|
||||
inline void AI_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask,
|
||||
const IHandleEntity *ignore, int collisionGroup, trace_t *ptr )
|
||||
{
|
||||
VPROF( "AI_TraceLine" );
|
||||
UTIL_TraceLine( vecAbsStart, vecAbsEnd, mask, ignore, collisionGroup, ptr );
|
||||
}
|
||||
|
||||
inline void AI_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask,
|
||||
ITraceFilter *pFilter, trace_t *ptr )
|
||||
{
|
||||
VPROF( "AI_TraceLine" );
|
||||
UTIL_TraceLine( vecAbsStart, vecAbsEnd, mask, pFilter, ptr );
|
||||
}
|
||||
|
||||
inline void AI_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin,
|
||||
const Vector &hullMax, unsigned int mask, const IHandleEntity *ignore,
|
||||
int collisionGroup, trace_t *ptr )
|
||||
{
|
||||
VPROF( "AI_TraceHull" );
|
||||
UTIL_TraceHull( vecAbsStart, vecAbsEnd, hullMin, hullMax, mask, ignore, collisionGroup, ptr );
|
||||
}
|
||||
|
||||
inline void AI_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin,
|
||||
const Vector &hullMax, unsigned int mask, ITraceFilter *pFilter, trace_t *ptr )
|
||||
{
|
||||
VPROF( "AI_TraceHull" );
|
||||
UTIL_TraceHull( vecAbsStart, vecAbsEnd, hullMin, hullMax, mask, pFilter, ptr );
|
||||
}
|
||||
|
||||
inline void AI_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr )
|
||||
{
|
||||
VPROF( "AI_TraceEntity" );
|
||||
UTIL_TraceEntity( pEntity, vecAbsStart, vecAbsEnd, mask, ptr );
|
||||
}
|
||||
|
||||
#else
|
||||
#define AI_TraceLine UTIL_TraceLine
|
||||
#define AI_TraceHull UTIL_TraceHull
|
||||
#define AI_TraceEntity UTIL_TraceEntity
|
||||
#endif
|
||||
|
||||
|
||||
#endif // AI_DEBUG_SHARED_H
|
||||
@@ -0,0 +1,344 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Base combat character with no AI
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "ammodef.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return a pointer to the Ammo at the Index passed in
|
||||
//-----------------------------------------------------------------------------
|
||||
Ammo_t *CAmmoDef::GetAmmoOfIndex(int nAmmoIndex)
|
||||
{
|
||||
if ( nAmmoIndex >= m_nAmmoIndex )
|
||||
return NULL;
|
||||
|
||||
return &m_AmmoType[ nAmmoIndex ];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::Index(const char *psz)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!psz)
|
||||
return -1;
|
||||
|
||||
for (i = 1; i < m_nAmmoIndex; i++)
|
||||
{
|
||||
if (stricmp( psz, m_AmmoType[i].pName ) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::PlrDamage(int nAmmoIndex)
|
||||
{
|
||||
if ( nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex )
|
||||
return 0;
|
||||
|
||||
if ( m_AmmoType[nAmmoIndex].pPlrDmg == USE_CVAR )
|
||||
{
|
||||
if ( m_AmmoType[nAmmoIndex].pPlrDmgCVar )
|
||||
{
|
||||
return m_AmmoType[nAmmoIndex].pPlrDmgCVar->GetFloat();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_AmmoType[nAmmoIndex].pPlrDmg;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::NPCDamage(int nAmmoIndex)
|
||||
{
|
||||
if ( nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex )
|
||||
return 0;
|
||||
|
||||
if ( m_AmmoType[nAmmoIndex].pNPCDmg == USE_CVAR )
|
||||
{
|
||||
if ( m_AmmoType[nAmmoIndex].pNPCDmgCVar )
|
||||
{
|
||||
return m_AmmoType[nAmmoIndex].pNPCDmgCVar->GetFloat();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_AmmoType[nAmmoIndex].pNPCDmg;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::MaxCarry(int nAmmoIndex, const CBaseCombatCharacter *owner)
|
||||
{
|
||||
if ( nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex )
|
||||
return 0;
|
||||
|
||||
if ( m_AmmoType[nAmmoIndex].pMaxCarry == USE_CVAR )
|
||||
{
|
||||
if ( m_AmmoType[nAmmoIndex].pMaxCarryCVar )
|
||||
return m_AmmoType[nAmmoIndex].pMaxCarryCVar->GetInt();
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_AmmoType[nAmmoIndex].pMaxCarry;
|
||||
}
|
||||
}
|
||||
|
||||
bool CAmmoDef::CanCarryInfiniteAmmo(int nAmmoIndex)
|
||||
{
|
||||
if ( nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex )
|
||||
return false;
|
||||
|
||||
int maxCarry = m_AmmoType[nAmmoIndex].pMaxCarry;
|
||||
if ( maxCarry == USE_CVAR )
|
||||
{
|
||||
if ( m_AmmoType[nAmmoIndex].pMaxCarryCVar )
|
||||
{
|
||||
maxCarry = m_AmmoType[nAmmoIndex].pMaxCarryCVar->GetInt();
|
||||
}
|
||||
}
|
||||
return maxCarry == INFINITE_AMMO ? true : false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::DamageType(int nAmmoIndex)
|
||||
{
|
||||
if (nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex)
|
||||
return 0;
|
||||
|
||||
return m_AmmoType[nAmmoIndex].nDamageType;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::Flags(int nAmmoIndex)
|
||||
{
|
||||
if (nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex)
|
||||
return 0;
|
||||
|
||||
return m_AmmoType[nAmmoIndex].nFlags;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::MinSplashSize(int nAmmoIndex)
|
||||
{
|
||||
if (nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex)
|
||||
return 4;
|
||||
|
||||
return m_AmmoType[nAmmoIndex].nMinSplashSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::MaxSplashSize(int nAmmoIndex)
|
||||
{
|
||||
if (nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex)
|
||||
return 8;
|
||||
|
||||
return m_AmmoType[nAmmoIndex].nMaxSplashSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAmmoDef::TracerType(int nAmmoIndex)
|
||||
{
|
||||
if (nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex)
|
||||
return 0;
|
||||
|
||||
return m_AmmoType[nAmmoIndex].eTracerType;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Figure out the damage force for a certian ammo type.
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
float CAmmoDef::DamageForce(int nAmmoIndex)
|
||||
{
|
||||
const float DEFAULT_IMPULSE = 1.0f;
|
||||
|
||||
if ( nAmmoIndex < 1 || nAmmoIndex >= m_nAmmoIndex )
|
||||
return DEFAULT_IMPULSE;
|
||||
|
||||
if ( m_AmmoType[nAmmoIndex].pPhysicsForceImpulse == USE_CVAR )
|
||||
{
|
||||
if ( m_AmmoType[nAmmoIndex].pPhysicsForceImpulseCVar )
|
||||
return m_AmmoType[nAmmoIndex].pPhysicsForceImpulseCVar->GetFloat();
|
||||
|
||||
return DEFAULT_IMPULSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (float)m_AmmoType[nAmmoIndex].pPhysicsForceImpulse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create an Ammo type with the name, decal, and tracer.
|
||||
// Does not increment m_nAmmoIndex because the functions below do so and
|
||||
// are the only entry point.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAmmoDef::AddAmmoType(char const* name, int damageType, int tracerType, int nFlags, int minSplashSize, int maxSplashSize )
|
||||
{
|
||||
if (m_nAmmoIndex == MAX_AMMO_TYPES)
|
||||
return false;
|
||||
|
||||
int len = strlen(name);
|
||||
m_AmmoType[m_nAmmoIndex].pName = new char[len+1];
|
||||
Q_strncpy(m_AmmoType[m_nAmmoIndex].pName, name,len+1);
|
||||
m_AmmoType[m_nAmmoIndex].nDamageType = damageType;
|
||||
m_AmmoType[m_nAmmoIndex].eTracerType = tracerType;
|
||||
m_AmmoType[m_nAmmoIndex].nMinSplashSize = minSplashSize;
|
||||
m_AmmoType[m_nAmmoIndex].nMaxSplashSize = maxSplashSize;
|
||||
m_AmmoType[m_nAmmoIndex].nFlags = nFlags;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add an ammo type with it's damage & carrying capability specified via cvars
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAmmoDef::AddAmmoType(char const* name, int damageType, int tracerType,
|
||||
char const* plr_cvar, char const* npc_cvar, char const* carry_cvar,
|
||||
char const* impulse_cvar, int nFlags, int minSplashSize, int maxSplashSize)
|
||||
{
|
||||
if ( AddAmmoType( name, damageType, tracerType, nFlags, minSplashSize, maxSplashSize ) == false )
|
||||
return;
|
||||
|
||||
if (plr_cvar)
|
||||
{
|
||||
m_AmmoType[m_nAmmoIndex].pPlrDmgCVar = cvar->FindVar(plr_cvar);
|
||||
if (!m_AmmoType[m_nAmmoIndex].pPlrDmgCVar)
|
||||
{
|
||||
Msg("ERROR: Ammo (%s) found no CVar named (%s)\n",name,plr_cvar);
|
||||
}
|
||||
m_AmmoType[m_nAmmoIndex].pPlrDmg = USE_CVAR;
|
||||
}
|
||||
if (npc_cvar)
|
||||
{
|
||||
m_AmmoType[m_nAmmoIndex].pNPCDmgCVar = cvar->FindVar(npc_cvar);
|
||||
if (!m_AmmoType[m_nAmmoIndex].pNPCDmgCVar)
|
||||
{
|
||||
Msg("ERROR: Ammo (%s) found no CVar named (%s)\n",name,npc_cvar);
|
||||
}
|
||||
m_AmmoType[m_nAmmoIndex].pNPCDmg = USE_CVAR;
|
||||
}
|
||||
if (carry_cvar)
|
||||
{
|
||||
m_AmmoType[m_nAmmoIndex].pMaxCarryCVar= cvar->FindVar(carry_cvar);
|
||||
if (!m_AmmoType[m_nAmmoIndex].pMaxCarryCVar)
|
||||
{
|
||||
Msg("ERROR: Ammo (%s) found no CVar named (%s)\n",name,carry_cvar);
|
||||
}
|
||||
m_AmmoType[m_nAmmoIndex].pMaxCarry = USE_CVAR;
|
||||
}
|
||||
if (impulse_cvar)
|
||||
{
|
||||
m_AmmoType[m_nAmmoIndex].pPhysicsForceImpulseCVar = cvar->FindVar(impulse_cvar);
|
||||
if (!m_AmmoType[m_nAmmoIndex].pPhysicsForceImpulseCVar)
|
||||
{
|
||||
Msg("ERROR: Ammo (%s) found no CVar named (%s)\n",name,impulse_cvar);
|
||||
}
|
||||
else
|
||||
{
|
||||
// By default, use whatever value is in the convar at load time.
|
||||
// To enable real-time updating of the ammo impulse values, execute "tweak_ammo_impulse" which will set pPhysicsForceImpulse to USE_CVAR.
|
||||
m_AmmoType[m_nAmmoIndex].pPhysicsForceImpulse = m_AmmoType[m_nAmmoIndex].pPhysicsForceImpulseCVar->GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
m_nAmmoIndex++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add an ammo type with it's damage & carrying capability specified via integers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAmmoDef::AddAmmoType(char const* name, int damageType, int tracerType,
|
||||
int plr_dmg, int npc_dmg, int carry, int impulse,
|
||||
int nFlags, int minSplashSize, int maxSplashSize )
|
||||
{
|
||||
if ( AddAmmoType( name, damageType, tracerType, nFlags, minSplashSize, maxSplashSize ) == false )
|
||||
return;
|
||||
|
||||
m_AmmoType[m_nAmmoIndex].pPlrDmg = plr_dmg;
|
||||
m_AmmoType[m_nAmmoIndex].pNPCDmg = npc_dmg;
|
||||
m_AmmoType[m_nAmmoIndex].pMaxCarry = carry;
|
||||
m_AmmoType[m_nAmmoIndex].pPhysicsForceImpulse = impulse;
|
||||
|
||||
m_nAmmoIndex++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
CAmmoDef::CAmmoDef(void)
|
||||
{
|
||||
// Start with an index of 1. Client assumes 0 is an invalid ammo type
|
||||
m_nAmmoIndex = 1;
|
||||
memset( m_AmmoType, 0, sizeof( m_AmmoType ) );
|
||||
}
|
||||
|
||||
CAmmoDef::~CAmmoDef( void )
|
||||
{
|
||||
for ( int i = 1; i < MAX_AMMO_TYPES; i++ )
|
||||
{
|
||||
delete[] m_AmmoType[ i ].pName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds defintion for game ammo types
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef AI_AMMODEF_H
|
||||
#define AI_AMMODEF_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class ConVar;
|
||||
|
||||
struct Ammo_t
|
||||
{
|
||||
char *pName;
|
||||
int nDamageType;
|
||||
int eTracerType;
|
||||
int nMinSplashSize;
|
||||
int nMaxSplashSize;
|
||||
|
||||
int nFlags;
|
||||
|
||||
// Values for player/NPC damage and carrying capability
|
||||
// If the integers are set, they override the CVars
|
||||
int pPlrDmg; // CVar for player damage amount
|
||||
int pNPCDmg; // CVar for NPC damage amount
|
||||
int pMaxCarry; // CVar for maximum number can carry
|
||||
int pPhysicsForceImpulse; // CVar for the physics impulse
|
||||
const ConVar* pPlrDmgCVar; // CVar for player damage amount
|
||||
const ConVar* pNPCDmgCVar; // CVar for NPC damage amount
|
||||
const ConVar* pMaxCarryCVar; // CVar for maximum number can carry
|
||||
const ConVar* pPhysicsForceImpulseCVar; // CVar for maximum number can carry
|
||||
};
|
||||
|
||||
// Used to tell AmmoDef to use the cvars, not the integers
|
||||
#define USE_CVAR -1
|
||||
// Ammo is infinite
|
||||
#define INFINITE_AMMO -2
|
||||
|
||||
enum AmmoTracer_t
|
||||
{
|
||||
TRACER_NONE,
|
||||
TRACER_LINE,
|
||||
TRACER_RAIL,
|
||||
TRACER_BEAM,
|
||||
TRACER_LINE_AND_WHIZ,
|
||||
};
|
||||
|
||||
enum AmmoFlags_t
|
||||
{
|
||||
AMMO_FORCE_DROP_IF_CARRIED = 0x1,
|
||||
AMMO_INTERPRET_PLRDAMAGE_AS_DAMAGE_TO_PLAYER = 0x2,
|
||||
};
|
||||
|
||||
|
||||
#include "shareddefs.h"
|
||||
|
||||
//=============================================================================
|
||||
// >> CAmmoDef
|
||||
//=============================================================================
|
||||
class CAmmoDef
|
||||
{
|
||||
|
||||
public:
|
||||
int m_nAmmoIndex;
|
||||
|
||||
Ammo_t m_AmmoType[MAX_AMMO_TYPES];
|
||||
|
||||
Ammo_t *GetAmmoOfIndex(int nAmmoIndex);
|
||||
int Index(const char *psz);
|
||||
int PlrDamage(int nAmmoIndex);
|
||||
int NPCDamage(int nAmmoIndex);
|
||||
int MaxCarry(int nAmmoIndex, const CBaseCombatCharacter *owner);
|
||||
bool CanCarryInfiniteAmmo(int nAmmoIndex);
|
||||
int DamageType(int nAmmoIndex);
|
||||
int TracerType(int nAmmoIndex);
|
||||
float DamageForce(int nAmmoIndex);
|
||||
int MinSplashSize(int nAmmoIndex);
|
||||
int MaxSplashSize(int nAmmoIndex);
|
||||
int Flags(int nAmmoIndex);
|
||||
|
||||
void AddAmmoType(char const* name, int damageType, int tracerType, int plr_dmg, int npc_dmg, int carry, int impulse, int nFlags, int minSplashSize = 4, int maxSplashSize = 8 );
|
||||
void AddAmmoType(char const* name, int damageType, int tracerType, char const* plr_cvar, char const* npc_var, char const* carry_cvar, char const* impulse_cvar, int nFlags, int minSplashSize = 4, int maxSplashSize = 8 );
|
||||
int NumAmmoTypes() { return m_nAmmoIndex; }
|
||||
|
||||
CAmmoDef(void);
|
||||
virtual ~CAmmoDef( void );
|
||||
|
||||
private:
|
||||
bool AddAmmoType(char const* name, int damageType, int tracerType, int nFlags, int minSplashSize, int maxSplashSize );
|
||||
};
|
||||
|
||||
|
||||
// Get the global ammodef object. This is usually implemented in each mod's game rules file somewhere,
|
||||
// so the mod can setup custom ammo types.
|
||||
CAmmoDef* GetAmmoDef();
|
||||
|
||||
|
||||
#endif // AI_AMMODEF_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
#ifndef ANIMATION_H
|
||||
#define ANIMATION_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define ACTIVITY_NOT_AVAILABLE -1
|
||||
|
||||
struct animevent_t;
|
||||
struct studiohdr_t;
|
||||
class CStudioHdr;
|
||||
struct mstudioseqdesc_t;
|
||||
|
||||
int ExtractBbox( CStudioHdr *pstudiohdr, int sequence, Vector& mins, Vector& maxs );
|
||||
|
||||
void IndexModelSequences( CStudioHdr *pstudiohdr );
|
||||
void ResetActivityIndexes( CStudioHdr *pstudiohdr );
|
||||
void VerifySequenceIndex( CStudioHdr *pstudiohdr );
|
||||
int SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence = -1 );
|
||||
int SelectHeaviestSequence( CStudioHdr *pstudiohdr, int activity );
|
||||
void SetEventIndexForSequence( mstudioseqdesc_t &seqdesc );
|
||||
void BuildAllAnimationEventIndexes( CStudioHdr *pstudiohdr );
|
||||
void ResetEventIndexes( CStudioHdr *pstudiohdr );
|
||||
float GetSequenceLinearMotionAndDuration( CStudioHdr *pstudiohdr, int iSequence, const float poseParameter[], Vector *pVec );
|
||||
|
||||
void GetEyePosition( CStudioHdr *pstudiohdr, Vector &vecEyePosition );
|
||||
|
||||
int LookupActivity( CStudioHdr *pstudiohdr, const char *label );
|
||||
int LookupSequence( CStudioHdr *pstudiohdr, const char *label );
|
||||
|
||||
#define NOMOTION 99999
|
||||
void GetSequenceLinearMotion( CStudioHdr *pstudiohdr, int iSequence, const float poseParameter[], Vector *pVec );
|
||||
|
||||
const char *GetSequenceName( CStudioHdr *pstudiohdr, int sequence );
|
||||
const char *GetSequenceActivityName( CStudioHdr *pstudiohdr, int iSequence );
|
||||
|
||||
int GetSequenceFlags( CStudioHdr *pstudiohdr, int sequence );
|
||||
int GetAnimationEvent( CStudioHdr *pstudiohdr, int sequence, animevent_t *pNPCEvent, float flStart, float flEnd, int index );
|
||||
bool HasAnimationEventOfType( CStudioHdr *pstudiohdr, int sequence, int type );
|
||||
|
||||
int FindTransitionSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, int iGoalSequence, int *piDir );
|
||||
bool GotoSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &nNextSequence, float &flNextCycle, int &iNextDir );
|
||||
|
||||
void SetBodygroup( CStudioHdr *pstudiohdr, int& body, int iGroup, int iValue );
|
||||
int GetBodygroup( CStudioHdr *pstudiohdr, int body, int iGroup );
|
||||
void SetBodygroupPreset( CStudioHdr *pstudiohdr, int& body, char const *szName );
|
||||
|
||||
const char *GetBodygroupName( CStudioHdr *pstudiohdr, int iGroup );
|
||||
int FindBodygroupByName( CStudioHdr *pstudiohdr, const char *name );
|
||||
const char *GetBodygroupPartName( CStudioHdr *pstudiohdr, int iGroup, int iPart );
|
||||
int GetBodygroupCount( CStudioHdr *pstudiohdr, int iGroup );
|
||||
int GetNumBodyGroups( CStudioHdr *pstudiohdr );
|
||||
|
||||
int GetSequenceActivity( CStudioHdr *pstudiohdr, int sequence, int *pweight = NULL );
|
||||
|
||||
void GetAttachmentLocalSpace( CStudioHdr *pstudiohdr, int attachIndex, matrix3x4_t &pLocalToWorld );
|
||||
|
||||
float SetBlending( CStudioHdr *pstudiohdr, int sequence, int *pblendings, int iBlender, float flValue );
|
||||
|
||||
int FindHitboxSetByName( CStudioHdr *pstudiohdr, const char *name );
|
||||
const char *GetHitboxSetName( CStudioHdr *pstudiohdr, int setnumber );
|
||||
int GetHitboxSetCount( CStudioHdr *pstudiohdr );
|
||||
|
||||
enum animtag_indices
|
||||
{
|
||||
ANIMTAG_INVALID = -1,
|
||||
ANIMTAG_UNINITIALIZED = 0,
|
||||
ANIMTAG_STARTCYCLE_N,
|
||||
ANIMTAG_STARTCYCLE_NE,
|
||||
ANIMTAG_STARTCYCLE_E,
|
||||
ANIMTAG_STARTCYCLE_SE,
|
||||
ANIMTAG_STARTCYCLE_S,
|
||||
ANIMTAG_STARTCYCLE_SW,
|
||||
ANIMTAG_STARTCYCLE_W,
|
||||
ANIMTAG_STARTCYCLE_NW,
|
||||
ANIMTAG_AIMLIMIT_YAWMIN_IDLE,
|
||||
ANIMTAG_AIMLIMIT_YAWMAX_IDLE,
|
||||
ANIMTAG_AIMLIMIT_YAWMIN_WALK,
|
||||
ANIMTAG_AIMLIMIT_YAWMAX_WALK,
|
||||
ANIMTAG_AIMLIMIT_YAWMIN_RUN,
|
||||
ANIMTAG_AIMLIMIT_YAWMAX_RUN,
|
||||
ANIMTAG_AIMLIMIT_YAWMIN_CROUCHIDLE,
|
||||
ANIMTAG_AIMLIMIT_YAWMAX_CROUCHIDLE,
|
||||
ANIMTAG_AIMLIMIT_YAWMIN_CROUCHWALK,
|
||||
ANIMTAG_AIMLIMIT_YAWMAX_CROUCHWALK,
|
||||
ANIMTAG_AIMLIMIT_PITCHMIN_IDLE,
|
||||
ANIMTAG_AIMLIMIT_PITCHMAX_IDLE,
|
||||
ANIMTAG_AIMLIMIT_PITCHMIN_WALKRUN,
|
||||
ANIMTAG_AIMLIMIT_PITCHMAX_WALKRUN,
|
||||
ANIMTAG_AIMLIMIT_PITCHMIN_CROUCH,
|
||||
ANIMTAG_AIMLIMIT_PITCHMAX_CROUCH,
|
||||
ANIMTAG_AIMLIMIT_PITCHMIN_CROUCHWALK,
|
||||
ANIMTAG_AIMLIMIT_PITCHMAX_CROUCHWALK,
|
||||
ANIMTAG_WEAPON_POSTLAYER,
|
||||
ANIMTAG_FLASHBANG_PASSABLE,
|
||||
ANIMTAG_COUNT
|
||||
};
|
||||
|
||||
float GetFirstSequenceAnimTag( CStudioHdr *pstudiohdr, int sequence, int nDesiredTag, float flStart = 0, float flEnd = 1 );
|
||||
|
||||
float GetAnySequenceAnimTag( CStudioHdr *pstudiohdr, int sequence, int nDesiredTag, float flDefault );
|
||||
|
||||
#endif //ANIMATION_H
|
||||
@@ -0,0 +1,74 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef APPARENT_VELOCITY_HELPER_H
|
||||
#define APPARENT_VELOCITY_HELPER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
inline float CalcDistance( float x, float y )
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
|
||||
inline float CalcDistance( const Vector &a, const Vector &b )
|
||||
{
|
||||
return a.DistTo( b );
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
class CDefaultCalcDistance
|
||||
{
|
||||
public:
|
||||
static inline float CalcDistance( const T &a, const T &b )
|
||||
{
|
||||
return ::CalcDistance( a, b );
|
||||
}
|
||||
};
|
||||
|
||||
class CCalcDistance2D
|
||||
{
|
||||
public:
|
||||
static inline float CalcDistance( const Vector &a, const Vector &b )
|
||||
{
|
||||
return (a-b).Length2D();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template< class T, class Functor=CDefaultCalcDistance<T> >
|
||||
class CApparentVelocity
|
||||
{
|
||||
public:
|
||||
CApparentVelocity()
|
||||
{
|
||||
m_LastTime = -1;
|
||||
}
|
||||
|
||||
float AddSample( float time, T value )
|
||||
{
|
||||
float flRet = 0;
|
||||
if ( m_LastTime != -1 )
|
||||
{
|
||||
flRet = Functor::CalcDistance(value, m_LastValue) / (time - m_LastTime);
|
||||
}
|
||||
|
||||
m_LastTime = time;
|
||||
m_LastValue = value;
|
||||
|
||||
return flRet;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_LastValue;
|
||||
float m_LastTime;
|
||||
};
|
||||
|
||||
|
||||
#endif // APPARENT_VELOCITY_HELPER_H
|
||||
@@ -0,0 +1,230 @@
|
||||
//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: Implementation of China Government Censorship enforced on all user-generated strings
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
//
|
||||
// Pre-compiled header (cbase.h in the game branch; none in Steam Client branch)
|
||||
//
|
||||
#include "cbase.h"
|
||||
|
||||
//
|
||||
// Custom implementations for sharing code verbatim between Steam Client and the game branch
|
||||
//
|
||||
#ifdef CSTRIKE15
|
||||
static bool BannedWords_LoadFileIntoBuffer( char const *szFilename, CUtlBuffer &buf )
|
||||
{
|
||||
return g_pFullFileSystem->ReadFile( szFilename, "MOD", buf );
|
||||
}
|
||||
#else
|
||||
#include "utlbuffer.h"
|
||||
#include "utlmap.h"
|
||||
#include "filesystem.h"
|
||||
#include "filesystem_helpers.h"
|
||||
#include "tier1/fileio.h"
|
||||
static bool BannedWords_LoadFileIntoBuffer( char const *szFilename, CUtlBuffer &buf )
|
||||
{
|
||||
return LoadFileIntoBuffer( szFilename, buf, false );
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "bannedwords.h"
|
||||
#include "utlmemory.h"
|
||||
#include "utlbuffer.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Banned words dictionary
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CBannedWordsDictionary
|
||||
{
|
||||
public:
|
||||
~CBannedWordsDictionary() { m_mapExternalStrings.PurgeAndDeleteElements(); }
|
||||
bool InitFromFile( char const *szFilename );
|
||||
int CensorBannedWordsInplace( wchar_t *wsz ) const;
|
||||
char const * CensorExternalString( uint64 ullKey, char const *szExternalString );
|
||||
|
||||
public:
|
||||
CUtlBuffer m_buf;
|
||||
struct ExternalStringCache_t
|
||||
{
|
||||
char m_chExternalString[256];
|
||||
char m_chCensoredString[256];
|
||||
};
|
||||
typedef CUtlMap< uint64, ExternalStringCache_t *, int, CDefLess< uint64 > > KeyStringMap_t;
|
||||
KeyStringMap_t m_mapExternalStrings;
|
||||
};
|
||||
|
||||
bool CBannedWordsDictionary::InitFromFile( char const *szFilename )
|
||||
{
|
||||
if ( !BannedWords_LoadFileIntoBuffer( szFilename, m_buf ) )
|
||||
return false;
|
||||
if ( m_buf.TellPut() % 2 )
|
||||
return false;
|
||||
if ( m_buf.TellPut() <= 0x10000 )
|
||||
return false;
|
||||
if ( V_memcmp( m_buf.Base(), "BDR1", 4 ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int CBannedWordsDictionary::CensorBannedWordsInplace( wchar_t *wsz ) const
|
||||
{
|
||||
wchar_t const * const wszStartOfInput = wsz;
|
||||
int numReplaced = 0;
|
||||
for ( ; *wsz; ++ wsz )
|
||||
{
|
||||
wchar_t wchThisLetter = *wsz;
|
||||
if ( ( wchThisLetter >= 'A' ) && ( wchThisLetter <= 'Z' ) )
|
||||
wchThisLetter += 'a' - 'A'; // ensure input is also lowercase
|
||||
|
||||
int32 nOffset = reinterpret_cast< int32 const * >( m_buf.Base() )[ wchThisLetter ];
|
||||
if ( !nOffset ) continue; // no banned words start with this char
|
||||
for ( wchar_t const *pwchBan = ( wchar_t const * ) ( ( byte const * )( m_buf.Base() ) + nOffset );
|
||||
pwchBan[1] == wchThisLetter; pwchBan += 1 + *pwchBan + 1 ) // (len wchar) + (actual number of wchars) + wnull-terminator
|
||||
{
|
||||
bool bWordBanned = true;
|
||||
bool bWordIsAllAlpha = true;
|
||||
{ // if ( wcsncmp( wsz, pwchBan + 1, *pwchBan ) ) continue;
|
||||
wchar_t const *x = wsz;
|
||||
wchar_t const *y = pwchBan + 1; // dictionary word, compiled as lowercase
|
||||
for ( wchar_t numChecksRemaining = *pwchBan;
|
||||
numChecksRemaining -- > 0;
|
||||
++ x, ++ y )
|
||||
{
|
||||
wchar_t wchx = *x;
|
||||
if ( ( wchx >= 'A' ) && ( wchx <= 'Z' ) )
|
||||
wchx += 'a' - 'A'; // ensure input is also lowercase
|
||||
if ( wchx != *y )
|
||||
{
|
||||
bWordBanned = false;
|
||||
break;
|
||||
}
|
||||
if ( !( ( wchx >= 'a' ) && ( wchx <= 'z' ) ) )
|
||||
bWordIsAllAlpha = false;
|
||||
}
|
||||
}
|
||||
if ( bWordBanned && bWordIsAllAlpha )
|
||||
{
|
||||
bool bBannedSequenceStartsWord = ( ( wsz <= wszStartOfInput ) || ( wsz[ -1 ] >= 0xFF ) || !V_isalpha( wsz[ -1 ] ) );
|
||||
bool bBannedSequenceEndsWord = ( !wsz[ *pwchBan ] || ( wsz[ *pwchBan ] >= 0xFF ) || !V_isalpha( wsz[ *pwchBan ] ) );
|
||||
|
||||
// Must match the full word, not substring in English word (otherwise banned words like
|
||||
// "ri", "mb", "sm" cause censoring all around)
|
||||
if ( *pwchBan < 4 )
|
||||
bWordBanned = bBannedSequenceStartsWord && bBannedSequenceEndsWord;
|
||||
// Otherwise require that the banned word appears at the start or end of a word
|
||||
// so that it censored words like "bullshit" or "shitshow", but didn't censor
|
||||
// pro player name "pashaBiceps" containing "shabi"
|
||||
else
|
||||
bWordBanned = bBannedSequenceStartsWord || bBannedSequenceEndsWord;
|
||||
}
|
||||
if ( !bWordBanned )
|
||||
continue;
|
||||
// BANNED WORD!
|
||||
for ( int kk = *pwchBan; kk -- > 0; ++ wsz )
|
||||
{
|
||||
*wsz = L'*';
|
||||
++ numReplaced;
|
||||
}
|
||||
-- wsz; // already advanced by number of asterisks inserted (-1 because the loop will ++)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return numReplaced;
|
||||
}
|
||||
|
||||
char const * CBannedWordsDictionary::CensorExternalString( uint64 ullKey, char const *szExternalString )
|
||||
{
|
||||
KeyStringMap_t::IndexType_t idx = m_mapExternalStrings.Find( ullKey );
|
||||
if ( idx == m_mapExternalStrings.InvalidIndex() )
|
||||
{
|
||||
ExternalStringCache_t *pNewEntry = new ExternalStringCache_t;
|
||||
V_memset( pNewEntry, 0, sizeof( ExternalStringCache_t ) );
|
||||
idx = m_mapExternalStrings.InsertOrReplace( ullKey, pNewEntry );
|
||||
}
|
||||
|
||||
ExternalStringCache_t *pEntry = m_mapExternalStrings.Element( idx );
|
||||
if ( V_strcmp( pEntry->m_chExternalString, szExternalString ) )
|
||||
{
|
||||
V_strcpy_safe( pEntry->m_chExternalString, szExternalString );
|
||||
|
||||
wchar_t *wch = ( wchar_t * ) stackalloc( sizeof(pEntry->m_chExternalString)*sizeof( wchar_t ) );
|
||||
V_UTF8ToUnicode( pEntry->m_chExternalString, wch, sizeof(pEntry->m_chExternalString)*sizeof( wchar_t ) );
|
||||
if ( CensorBannedWordsInplace( wch ) )
|
||||
V_UnicodeToUTF8( wch, pEntry->m_chCensoredString, sizeof( pEntry->m_chCensoredString ) );
|
||||
else
|
||||
V_strcpy_safe( pEntry->m_chCensoredString, pEntry->m_chExternalString );
|
||||
}
|
||||
|
||||
return pEntry->m_chCensoredString;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Banned words interface exposed to clients
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CBannedWords::~CBannedWords()
|
||||
{
|
||||
delete m_pDictionary;
|
||||
m_pDictionary = NULL;
|
||||
}
|
||||
|
||||
bool CBannedWords::InitFromFile( char const *szFilename )
|
||||
{
|
||||
CBannedWordsDictionary *pDictionary = new CBannedWordsDictionary;
|
||||
if ( pDictionary->InitFromFile( szFilename ) )
|
||||
{
|
||||
delete m_pDictionary;
|
||||
m_pDictionary = pDictionary;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pDictionary;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int CBannedWords::CensorBannedWordsInplace( wchar_t *wsz ) const
|
||||
{
|
||||
return ( m_pDictionary && wsz && *wsz ) ? m_pDictionary->CensorBannedWordsInplace( wsz ) : 0;
|
||||
}
|
||||
|
||||
int CBannedWords::CensorBannedWordsInplace( char *sz ) const
|
||||
{
|
||||
if ( !m_pDictionary )
|
||||
return 0;
|
||||
|
||||
if ( !sz || !*sz )
|
||||
return 0;
|
||||
|
||||
int nLen = V_strlen( sz );
|
||||
wchar_t *wch = ( wchar_t * ) stackalloc( ( 1 + nLen )*sizeof( wchar_t ) );
|
||||
V_UTF8ToUnicode( sz, wch, ( 1 + nLen )*sizeof( wchar_t ) );
|
||||
int numCensored = m_pDictionary->CensorBannedWordsInplace( wch );
|
||||
if ( !numCensored )
|
||||
return 0;
|
||||
|
||||
V_UnicodeToUTF8( wch, sz, nLen + 1 );
|
||||
return numCensored;
|
||||
}
|
||||
|
||||
char const * CBannedWords::CensorExternalString( uint64 ullKey, char const *szExternalString ) const
|
||||
{
|
||||
return ( m_pDictionary && szExternalString && *szExternalString ) ? m_pDictionary->CensorExternalString( ullKey, szExternalString ) : szExternalString;
|
||||
}
|
||||
|
||||
CBannedWords g_BannedWords;
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef BANNEDWORDS_H
|
||||
#define BANNEDWORDS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// Implements censoring of bad words
|
||||
//
|
||||
class CBannedWordsDictionary;
|
||||
class CBannedWords
|
||||
{
|
||||
public:
|
||||
CBannedWords() { m_pDictionary = NULL; }
|
||||
~CBannedWords();
|
||||
|
||||
// Initializes dictionary from a buffer
|
||||
bool InitFromFile( char const *szFilename );
|
||||
bool BInitialized() const { return m_pDictionary != NULL; }
|
||||
|
||||
// Censors banned words in the buffer, returns number of characters censored
|
||||
int CensorBannedWordsInplace( wchar_t *wsz ) const;
|
||||
int CensorBannedWordsInplace( char *sz ) const;
|
||||
|
||||
// Censors external string that cannot be stomped, stores the censored version
|
||||
char const * CensorExternalString( uint64 ullKey, char const *szExternalString ) const;
|
||||
|
||||
private:
|
||||
// Private implementation details
|
||||
CBannedWordsDictionary *m_pDictionary;
|
||||
};
|
||||
|
||||
extern CBannedWords g_BannedWords;
|
||||
|
||||
#endif // BANNEDWORDS_H
|
||||
@@ -0,0 +1,925 @@
|
||||
//====== Copyright 1996-2010, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: The file defines our Google Protocol Buffers which are used in over
|
||||
// the wire messages between servers as well as between the TF GC and TF gameservers
|
||||
// and clients.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
// We care more about speed than code size
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// We don't use the service generation functionality
|
||||
option cc_generic_services = false;
|
||||
|
||||
|
||||
//
|
||||
// STYLE NOTES:
|
||||
//
|
||||
// Use CamelCase CMsgMyMessageName style names for messages.
|
||||
//
|
||||
// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
|
||||
// but plays nice with the Google formatted code generation.
|
||||
//
|
||||
// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
|
||||
// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
|
||||
// your message and wants to remove or rename fields.
|
||||
//
|
||||
// Use fixed64 for JobId_t, GID_t, or SteamID. This is appropriate for any field that is normally
|
||||
// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
|
||||
// than 2^56 as it will safe space on the wire in those cases.
|
||||
//
|
||||
// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
|
||||
// 2^28. It will save space in those cases, otherwise use int32 which will safe space for smaller values.
|
||||
// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
|
||||
// time.
|
||||
//
|
||||
|
||||
import "steammessages.proto";
|
||||
|
||||
// Messages
|
||||
enum EGCBaseMsg
|
||||
{
|
||||
k_EMsgGCSystemMessage = 4001; // broadcast announcements from the GC
|
||||
k_EMsgGCReplicateConVars = 4002; // GC => client
|
||||
k_EMsgGCConVarUpdated = 4003; // GC => client
|
||||
k_EMsgGCInQueue = 4008; // GC => client
|
||||
|
||||
// !GROSS! These have ben moved to gcsystemmsgs.proto. But I didn't reassign their number
|
||||
//k_EMsgGCClientWelcome = 4004; // GC => client
|
||||
//k_EMsgGCServerWelcome = 4005; // GC => server
|
||||
//k_EMsgGCClientHello = 4006; // client => GC
|
||||
//k_EMsgGCServerHello = 4007; // server => GC
|
||||
//k_EMsgGCClientConnectionStatus = 4009; // GC => client
|
||||
//k_EMsgGCServerConnectionStatus = 4010; // GC => server
|
||||
|
||||
// Matchmaking messages
|
||||
k_EMsgGCInviteToParty = 4501; // inviting another player to your party
|
||||
k_EMsgGCInvitationCreated = 4502; // sent from GC to sender
|
||||
k_EMsgGCPartyInviteResponse = 4503; // client accepting a party invite
|
||||
k_EMsgGCKickFromParty = 4504; // sent from party leader to GC to kick a player from the party
|
||||
k_EMsgGCLeaveParty = 4505; // sent from party member to GC to leave a party
|
||||
k_EMsgGCServerAvailable = 4506; // send from a dedicated server when its ready
|
||||
k_EMsgGCClientConnectToServer = 4507; // sent to a client to connect to a server
|
||||
k_EMsgGCGameServerInfo = 4508; // send from a dedicated server for server address information
|
||||
k_EMsgGCError = 4509; // sent from GC to client telling client about an error
|
||||
k_EMsgGCReplay_UploadedToYouTube = 4510; // client => GC
|
||||
k_EMsgGCLANServerAvailable = 4511; // send from a listen server when its ready
|
||||
|
||||
};
|
||||
|
||||
//enum EGCSharedMsg = 7001-7006
|
||||
|
||||
enum EGCBaseProtoObjectTypes
|
||||
{
|
||||
k_EProtoObjectPartyInvite = 1001;
|
||||
k_EProtoObjectLobbyInvite = 1002;
|
||||
};
|
||||
|
||||
// Econ
|
||||
message CGCStorePurchaseInit_LineItem
|
||||
{
|
||||
optional uint32 item_def_id = 1; // DefIndex of the item to purchase
|
||||
optional uint32 quantity = 2; // quantity to purchase
|
||||
optional uint32 cost_in_local_currency = 3; // cost in cents of the local currency the user thinks he should pay (if you change this update item_price_t!)
|
||||
optional uint32 purchase_type = 4; // is this a regular purchase? a rental? maps to ECartItemType
|
||||
};
|
||||
|
||||
// k_EMsgGCStorePurchaseInit
|
||||
message CMsgGCStorePurchaseInit
|
||||
{
|
||||
optional string country = 1; // Country the purchase is being made from (obtained from Steam)
|
||||
optional int32 language = 2; // Client's language
|
||||
optional int32 currency = 3; // Currency the purchase is in (obtained from Steam)
|
||||
|
||||
repeated CGCStorePurchaseInit_LineItem line_items = 4;
|
||||
};
|
||||
|
||||
// k_EMsgGCStorePurchaseInitResponse
|
||||
message CMsgGCStorePurchaseInitResponse
|
||||
{
|
||||
optional int32 result = 1; // Result of the operation
|
||||
optional uint64 txn_id = 2; // Transaction ID of the new transaction
|
||||
optional string url = 3; // URL that the client will open to follow up
|
||||
repeated uint64 item_ids = 4; // ItemIDs for immediately finalized txn
|
||||
};
|
||||
|
||||
|
||||
// Shared objects
|
||||
|
||||
//
|
||||
// CSOPartyInvite - sent from the GC to possible new party member
|
||||
//
|
||||
message CSOPartyInvite
|
||||
{
|
||||
optional uint64 group_id = 1 [ (key_field) = true ];
|
||||
optional fixed64 sender_id = 2;
|
||||
optional string sender_name = 3;
|
||||
};
|
||||
|
||||
// Sent from the GC to possible new lobby member
|
||||
//
|
||||
message CSOLobbyInvite
|
||||
{
|
||||
optional uint64 group_id = 1 [ (key_field) = true ];
|
||||
optional fixed64 sender_id = 2;
|
||||
optional string sender_name = 3;
|
||||
// TODO: Game mode, etc.
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgSystemBroadcast
|
||||
//
|
||||
message CMsgSystemBroadcast
|
||||
{
|
||||
optional string message = 1; // the message to display on the client
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgInviteToParty - sent from party leader to the GC
|
||||
//
|
||||
message CMsgInviteToParty
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
optional uint32 client_version = 2;
|
||||
optional uint32 team_invite = 3;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CMsgInvitationCreated - sent from GC to the party leader
|
||||
//
|
||||
message CMsgInvitationCreated
|
||||
{
|
||||
optional uint64 group_id = 1;
|
||||
optional fixed64 steam_id = 2;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CMsgPartyInviteResponse - sent from client to GC when accepting/rejecting a CMsgPartyInvite
|
||||
//
|
||||
message CMsgPartyInviteResponse
|
||||
{
|
||||
optional uint64 party_id = 1;
|
||||
optional bool accept = 2;
|
||||
optional uint32 client_version = 3;
|
||||
optional uint32 team_invite = 4;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CMsgKickFromParty - sent from party leader to the GC
|
||||
//
|
||||
message CMsgKickFromParty
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgLeaveParty - sent from party member to the GC
|
||||
//
|
||||
message CMsgLeaveParty
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgServerAvailable - send from a dedicated server to the GC to indicate availability
|
||||
//
|
||||
message CMsgServerAvailable
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgLANServerAvailable - send from a listen server to the GC to indicate availability
|
||||
//
|
||||
message CMsgLANServerAvailable
|
||||
{
|
||||
optional fixed64 lobby_id = 1;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Used by CEconGameAccountClient
|
||||
//
|
||||
message CSOEconGameAccountClient
|
||||
{
|
||||
optional uint32 additional_backpack_slots = 1 [ default = 0 ]; // the number of backpack slots this user has on top of DEFAULT_NUM_BACKPACK_SLOTS
|
||||
// optional bool trial_account = 2 [ default = false ];
|
||||
// optional bool eligible_for_online_play = 3 [ default = true ];
|
||||
// optional bool need_to_choose_most_helpful_friend = 4;
|
||||
// optional bool in_coaches_list = 5;
|
||||
// optional fixed32 trade_ban_expiration = 6;
|
||||
// optional fixed32 duel_ban_expiration = 7;
|
||||
// optional uint32 preview_item_def = 8 [ default = 0 ];
|
||||
// optional bool made_first_purchase = 9 [ default = false ];
|
||||
// optional bool eligible_for_community_market = 10;
|
||||
// optional uint32 mission_refuse_allowed = 11;
|
||||
optional fixed32 bonus_xp_timestamp_refresh = 12;
|
||||
optional uint32 bonus_xp_usedflags = 13;
|
||||
optional uint32 elevated_state = 14; // represents the state up to <= k_EGameAccountElevatedState_Elevated
|
||||
optional uint32 elevated_timestamp = 15; // when applicable is the timestamp (e.g. elevation cooldown expiry, or time when became elevated, etc.)
|
||||
};
|
||||
|
||||
//
|
||||
// Used by CEconCraftingRecipe
|
||||
//
|
||||
message CSOItemCriteriaCondition
|
||||
{
|
||||
optional int32 op = 1;
|
||||
optional string field = 2;
|
||||
optional bool required = 3;
|
||||
optional float float_value = 4;
|
||||
optional string string_value = 5;
|
||||
}
|
||||
|
||||
|
||||
message CSOItemCriteria
|
||||
{
|
||||
optional uint32 item_level = 1;
|
||||
optional int32 item_quality = 2;
|
||||
|
||||
optional bool item_level_set = 3;
|
||||
optional bool item_quality_set = 4;
|
||||
optional uint32 initial_inventory = 5;
|
||||
optional uint32 initial_quantity = 6;
|
||||
// optional bool forced_quality_match__DEPRECATED = 7;
|
||||
optional bool ignore_enabled_flag = 8;
|
||||
|
||||
repeated CSOItemCriteriaCondition conditions = 9;
|
||||
|
||||
optional int32 item_rarity = 10;
|
||||
optional bool item_rarity_set = 11;
|
||||
|
||||
optional bool recent_only = 12;
|
||||
};
|
||||
|
||||
|
||||
message CSOItemRecipe
|
||||
{
|
||||
optional uint32 def_index = 1;
|
||||
optional string name = 2;
|
||||
optional string n_a = 3;
|
||||
optional string desc_inputs = 4;
|
||||
optional string desc_outputs = 5;
|
||||
optional string di_a = 6;
|
||||
optional string di_b = 7;
|
||||
optional string di_c = 8;
|
||||
optional string do_a = 9;
|
||||
optional string do_b = 10;
|
||||
optional string do_c = 11;
|
||||
optional bool requires_all_same_class = 12;
|
||||
optional bool requires_all_same_slot = 13;
|
||||
optional int32 class_usage_for_output = 14;
|
||||
optional int32 slot_usage_for_output = 15;
|
||||
optional int32 set_for_output = 16;
|
||||
|
||||
repeated CSOItemCriteria input_items_criteria = 20;
|
||||
repeated CSOItemCriteria output_items_criteria = 21;
|
||||
repeated uint32 input_item_dupe_counts = 22;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCDev_NewItemRequest
|
||||
//
|
||||
message CMsgDevNewItemRequest
|
||||
{
|
||||
//using fixed64 since steamids have lots of entropy in their bits
|
||||
optional fixed64 receiver = 1;
|
||||
optional CSOItemCriteria criteria = 2;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCIncrementKillCountAttribute
|
||||
//
|
||||
message CMsgIncrementKillCountAttribute
|
||||
{
|
||||
optional fixed32 killer_account_id = 1;
|
||||
optional fixed32 victim_account_id = 2;
|
||||
optional uint64 item_id = 3;
|
||||
optional uint32 event_type = 4;
|
||||
optional uint32 amount = 5;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCApplySticker
|
||||
//
|
||||
message CMsgApplySticker
|
||||
{
|
||||
optional uint64 sticker_item_id = 1; // which sticker are attaching?
|
||||
optional uint64 item_item_id = 2; // what item are we sticking it on to?
|
||||
optional uint32 sticker_slot = 3; // which sticker slot are we modifying? When attaching a sticker replace slot, when 0-sticker just applies wear.
|
||||
optional uint32 baseitem_defidx = 4; // If not sticking it on existing item support sticking it on base item
|
||||
optional float sticker_wear = 5; // when applying sticker wear this field specifies current wear as seen by client (to prevent double-scraping in case message reaches GC multiple times)
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// k_EMsgGStatTrakSwap
|
||||
//
|
||||
|
||||
message CMsgApplyStatTrakSwap
|
||||
{
|
||||
optional uint64 tool_item_id = 1; // item id of the xfer tool
|
||||
optional uint64 item_1_item_id = 2;
|
||||
optional uint64 item_2_item_id = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCApplyStrangePart
|
||||
//
|
||||
message CMsgApplyStrangePart
|
||||
{
|
||||
optional uint64 strange_part_item_id = 1; // which part are we "inserting"?
|
||||
optional uint64 item_item_id = 2; // what strange item are we inserting this new part into?
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCApplyPennantUpgrade
|
||||
//
|
||||
message CMsgApplyPennantUpgrade
|
||||
{
|
||||
optional uint64 upgrade_item_id = 1; // pennant upgrade
|
||||
optional uint64 pennant_item_id = 2; // what pennant are we upgrading?
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCApplyEggEssence
|
||||
//
|
||||
message CMsgApplyEggEssence
|
||||
{
|
||||
optional uint64 essence_item_id = 1; // essence we are using
|
||||
optional uint64 egg_item_id = 2; // egg target
|
||||
};
|
||||
|
||||
//
|
||||
// Used by CEconItem
|
||||
//
|
||||
message CSOEconItemAttribute
|
||||
{
|
||||
optional uint32 def_index = 1;
|
||||
optional uint32 value = 2; // DEPRECATED -- see value_bytes
|
||||
optional bytes value_bytes = 3;
|
||||
}
|
||||
|
||||
message CSOEconItemEquipped
|
||||
{
|
||||
optional uint32 new_class = 1;
|
||||
optional uint32 new_slot = 2;
|
||||
}
|
||||
|
||||
message CSOEconItem
|
||||
{
|
||||
optional uint64 id = 1;
|
||||
optional uint32 account_id = 2;
|
||||
optional uint32 inventory = 3;
|
||||
optional uint32 def_index = 4;
|
||||
optional uint32 quantity = 5; // [ default = 1 ]; - Uncomment after 5/16 the client/server will have backwards compat with this change by that point
|
||||
optional uint32 level = 6; // [ default = 1 ]; - Uncomment after 5/16 the client/server will have backwards compat with this change by that point
|
||||
optional uint32 quality = 7;
|
||||
optional uint32 flags = 8 [ default = 0 ];
|
||||
optional uint32 origin = 9;
|
||||
optional string custom_name = 10;
|
||||
optional string custom_desc = 11;
|
||||
repeated CSOEconItemAttribute attribute = 12;
|
||||
optional CSOEconItem interior_item = 13;
|
||||
optional bool in_use = 14 [ default = false ];
|
||||
optional uint32 style = 15 [default = 0 ];
|
||||
optional uint64 original_id = 16 [ default = 0 ];
|
||||
// optional bool contains_equipped_state = 17;
|
||||
repeated CSOEconItemEquipped equipped_state = 18;
|
||||
optional uint32 rarity = 19;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgGCAdjustItemEquippedState
|
||||
//
|
||||
message CMsgAdjustItemEquippedState
|
||||
{
|
||||
optional uint64 item_id = 1;
|
||||
optional uint32 new_class = 2;
|
||||
optional uint32 new_slot = 3; // will be -1 if not equipped on this class any longer
|
||||
optional bool swap = 4;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgGCSortItems
|
||||
//
|
||||
message CMsgSortItems
|
||||
{
|
||||
optional uint32 sort_type = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Used by CEconClaimCode
|
||||
//
|
||||
message CSOEconClaimCode
|
||||
{
|
||||
optional uint32 account_id = 1;
|
||||
optional uint32 code_type = 2;
|
||||
optional uint32 time_acquired = 3;
|
||||
optional string code = 4;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgGCStoreGetUserData
|
||||
//
|
||||
message CMsgStoreGetUserData
|
||||
{
|
||||
optional fixed32 price_sheet_version = 1;
|
||||
optional int32 currency = 2; // Currency that the user is requesting for pricesheet (pre-negotiated during welcome)
|
||||
// 14-November-2014: for backwards compatibility with older clients only new clients request user data with currency,
|
||||
// the new clients don't expect to get response as a reply to msg, but rather want a multiplexed standalone pricesheet.
|
||||
// old clients still want a reply to msg.
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EMsgGCStoreGetUserDataResponse
|
||||
//
|
||||
message CMsgStoreGetUserDataResponse
|
||||
{
|
||||
optional int32 result = 1; // Result of the call
|
||||
// 14-Nov-2014: pricesheet response is now multiplexed, no personal data included
|
||||
optional int32 currency_deprecated = 2; // Currency to display to the user
|
||||
optional string country_deprecated = 3; // Country the purchase is being made from (Send back in k_EMsgGCStorePurchaseInit)
|
||||
|
||||
optional fixed32 price_sheet_version = 4; // Version of the current price sheet on the GC
|
||||
|
||||
// experiments
|
||||
// 14-Nov-2014: pricesheet response is now multiplexed, no personal data included
|
||||
// optional uint64 experiment_data = 5 [ default = 0 ]; // top 32 bits = experiment id, bottom 32 bits = experiment group number
|
||||
// optional int32 featured_item_idx = 6;
|
||||
// optional bool show_hat_descriptions = 7 [ default = true ];
|
||||
|
||||
// Serialized KV representing the price sheet menu
|
||||
optional bytes price_sheet = 8;
|
||||
|
||||
// optional int32 default_item_sort = 9 [ default = 0 ];
|
||||
|
||||
// popular items by def
|
||||
// repeated uint32 popular_items = 10;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCUpdateItemSchema
|
||||
//
|
||||
message CMsgUpdateItemSchema
|
||||
{
|
||||
optional bytes items_game = 1; // actual contents of items_game.txt (only used on dev)
|
||||
optional fixed32 item_schema_version = 2; // Version of the items_game.txt we're using
|
||||
optional string items_game_url_DEPRECATED2013 = 3; // HTTP URL where they can use to fetch the one we're using, if theirs is out of date and we don't send the contents (deprecated in January 2014, new schema format, actual URL in field#4 now)
|
||||
optional string items_game_url = 4; // HTTP URL where they can use to fetch the one we're using, if theirs is out of date and we don't send the contents (rev'd to 4 for new schema format to not explode old clients/servers)
|
||||
};
|
||||
|
||||
// sent from the GC to a client telling him about a GC error
|
||||
message CMsgGCError
|
||||
{
|
||||
optional string error_text = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCRequestInventoryRefresh
|
||||
//
|
||||
message CMsgRequestInventoryRefresh
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCConvarUpdated
|
||||
//
|
||||
message CMsgConVarValue
|
||||
{
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCReplicateConVars
|
||||
//
|
||||
message CMsgReplicateConVars
|
||||
{
|
||||
repeated CMsgConVarValue convars = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCUseItemRequest
|
||||
//
|
||||
message CMsgUseItem
|
||||
{
|
||||
optional uint64 item_id = 1;
|
||||
optional fixed64 target_steam_id = 2; // 64-bit field left over from original message
|
||||
|
||||
repeated uint32 gift__potential_targets = 3;
|
||||
optional uint32 duel__class_lock = 4;
|
||||
optional fixed64 initiator_steam_id = 5;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCReplay_UploadedToYouTube
|
||||
//
|
||||
message CMsgReplayUploadedToYouTube
|
||||
{
|
||||
optional string youtube_url = 1;
|
||||
optional string youtube_account_name = 2;
|
||||
optional uint64 session_id = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCConsumableExhausted
|
||||
//
|
||||
message CMsgConsumableExhausted
|
||||
{
|
||||
optional int32 item_def_id = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCItemAcknowledged__DEPRECATED
|
||||
//
|
||||
message CMsgItemAcknowledged__DEPRECATED
|
||||
{
|
||||
optional uint32 account_id = 1;
|
||||
optional uint32 inventory = 2;
|
||||
optional uint32 def_index = 3;
|
||||
optional uint32 quality = 4;
|
||||
optional uint32 rarity = 5;
|
||||
optional uint32 origin = 6;
|
||||
optional uint64 item_id = 7;
|
||||
};
|
||||
|
||||
//
|
||||
// OBSOLETE: CMsgSetPresetItemPosition
|
||||
//
|
||||
// message CMsgSetPresetItemPosition
|
||||
// {
|
||||
// optional uint32 class_id = 1;
|
||||
// optional uint32 preset_id = 2;
|
||||
// optional uint32 slot_id = 3;
|
||||
// optional uint64 item_id = 4;
|
||||
// };
|
||||
|
||||
//
|
||||
// CMsgSetItemPositions
|
||||
//
|
||||
message CMsgSetItemPositions
|
||||
{
|
||||
message ItemPosition
|
||||
{
|
||||
optional uint32 legacy_item_id = 1;
|
||||
optional uint32 position = 2;
|
||||
optional uint64 item_id = 3;
|
||||
}
|
||||
|
||||
repeated ItemPosition item_positions = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// OBSOLETE: CSOEconItemPresetInstance - The preset, class and slot ID's are all marked key fields, so that those
|
||||
// fields will always be networked down to clients, even if only the item ID is modified. This is so that
|
||||
// when CSharedObjectTypeCache::BUpdateFromMsg() calls its FindSharedObject(), it will have the necessary
|
||||
// key data for CEconItemPresetInstance::BIsKeyLess() to be able to function. Without these, FindSharedObject()
|
||||
// fails and no object is updated.
|
||||
//
|
||||
// message CSOEconItemPresetInstance
|
||||
// {
|
||||
// // optional uint32 account_id = 1; // NOTE: Never use id '1' again - but we don't need to transmit the account id here
|
||||
// optional uint32 class_id = 2 [ (key_field) = true ];
|
||||
// optional uint32 preset_id = 3 [ (key_field) = true ];
|
||||
// optional uint32 slot_id = 4 [ (key_field) = true ];
|
||||
// optional uint64 item_id = 5;
|
||||
// };
|
||||
|
||||
//
|
||||
// OBSOLETE: CMsgSelectItemPresetForClass
|
||||
//
|
||||
// message CMsgSelectItemPresetForClass
|
||||
// {
|
||||
// optional uint32 class_id = 1;
|
||||
// optional uint32 preset_id = 2;
|
||||
// };
|
||||
|
||||
//
|
||||
// OBSOLETE: CMsgSelectItemPresetForClassReply
|
||||
//
|
||||
// message CMsgSelectItemPresetForClassReply
|
||||
// {
|
||||
// optional bool success = 1;
|
||||
// };
|
||||
|
||||
//
|
||||
// OBSOLETE: CSOSelectedItemPreset
|
||||
//
|
||||
// message CSOSelectedItemPreset
|
||||
// {
|
||||
// optional uint32 account_id = 1 [ (key_field) = true ];
|
||||
// optional uint32 class_id = 2 [ (key_field) = true ];
|
||||
// optional uint32 preset_id = 3;
|
||||
// };
|
||||
|
||||
//
|
||||
// k_EMsgGC_ReportAbuse
|
||||
//
|
||||
message CMsgGCReportAbuse
|
||||
{
|
||||
optional fixed64 target_steam_id = 1; // who is the user accusing?
|
||||
|
||||
optional string description = 4; // in the user's own words
|
||||
optional uint64 gid = 5; // meaning depends on content type
|
||||
|
||||
// If accusing a player:
|
||||
optional uint32 abuse_type = 2; // EAbuseReportType
|
||||
optional uint32 content_type = 3; // ECommunityContentType
|
||||
|
||||
// If accusing a game server:
|
||||
optional fixed32 target_game_server_ip = 6;
|
||||
optional uint32 target_game_server_port = 7;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGC_ReportAbuseResponse
|
||||
//
|
||||
message CMsgGCReportAbuseResponse
|
||||
{
|
||||
optional fixed64 target_steam_id = 1; // target to which this reply is in reference
|
||||
optional uint32 result = 2; // EResult
|
||||
optional string error_message = 3; // Diagnostic error message (not localized, for debugging purposes only)
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCNameItemNotification
|
||||
//
|
||||
message CMsgGCNameItemNotification
|
||||
{
|
||||
optional fixed64 player_steamid = 1;
|
||||
optional uint32 item_def_index = 2;
|
||||
optional string item_name_custom = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCClientDisplayNotification
|
||||
//
|
||||
message CMsgGCClientDisplayNotification
|
||||
{
|
||||
optional string notification_title_localization_key = 1;
|
||||
optional string notification_body_localization_key = 2;
|
||||
repeated string body_substring_keys = 3;
|
||||
repeated string body_substring_values = 4;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCShowItemsPickedUp
|
||||
//
|
||||
message CMsgGCShowItemsPickedUp
|
||||
{
|
||||
optional fixed64 player_steamid = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCIncrementKillCountResponse
|
||||
//
|
||||
message CMsgGCIncrementKillCountResponse // was CMsgTFIncrementKillCountResponse
|
||||
{
|
||||
optional uint32 killer_account_id = 1 [ (key_field) = true ]; // name of the user who got the kill
|
||||
optional uint32 num_kills = 2; // number of kills (or: ubers released; or gifts given out; etc.)
|
||||
optional uint32 item_def = 3; // id of the item in question
|
||||
optional uint32 level_type = 4; // what sort of rank is this? (ie., kills, gifts, etc.) used for looking up strings
|
||||
};
|
||||
|
||||
message CSOEconItemDropRateBonus
|
||||
{
|
||||
optional uint32 account_id = 1;
|
||||
optional fixed32 expiration_date = 2;
|
||||
optional float bonus = 3;
|
||||
optional uint32 bonus_count = 4;
|
||||
optional uint64 item_id = 5;
|
||||
optional uint32 def_index = 6;
|
||||
};
|
||||
|
||||
message CSOEconItemLeagueViewPass
|
||||
{
|
||||
optional uint32 account_id = 1 [ (key_field) = true ];
|
||||
optional uint32 league_id = 2 [ (key_field) = true ];
|
||||
optional uint32 admin = 3;
|
||||
optional uint32 itemindex = 4;
|
||||
};
|
||||
|
||||
message CSOEconItemEventTicket
|
||||
{
|
||||
optional uint32 account_id = 1;
|
||||
optional uint32 event_id = 2;
|
||||
optional uint64 item_id = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCItemPreviewItemBoughtNotification
|
||||
//
|
||||
message CMsgGCItemPreviewItemBoughtNotification
|
||||
{
|
||||
optional uint32 item_def_index = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCStorePurchaseCancel
|
||||
//
|
||||
message CMsgGCStorePurchaseCancel
|
||||
{
|
||||
optional uint64 txn_id = 1; // Transaction ID for the the transaction
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCStorePurchaseCancelResponse
|
||||
//
|
||||
message CMsgGCStorePurchaseCancelResponse
|
||||
{
|
||||
optional uint32 result = 1; // Result of the operation
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCStorePurchaseFinalize
|
||||
//
|
||||
message CMsgGCStorePurchaseFinalize
|
||||
{
|
||||
optional uint64 txn_id = 1; // Transaction ID for the the transaction
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCStorePurchaseFinalizeResponse
|
||||
//
|
||||
message CMsgGCStorePurchaseFinalizeResponse
|
||||
{
|
||||
optional uint32 result = 1; // Result of the operation
|
||||
repeated uint64 item_ids = 2; // If successful, list of uint64's that represent the purchased items
|
||||
};
|
||||
|
||||
// k_EMsgGCBannedWordListRequest
|
||||
message CMsgGCBannedWordListRequest
|
||||
{
|
||||
optional uint32 ban_list_group_id = 1; // The group code to request the word list from (English, Chinese, etc)
|
||||
optional uint32 word_id = 2; // The most recent word ID that we want to request (the response will include this ID if present)
|
||||
};
|
||||
|
||||
// k_EMsgGCRequestAnnouncements
|
||||
message CMsgGCRequestAnnouncements
|
||||
{
|
||||
};
|
||||
|
||||
// k_EMsgGCRequestAnnouncementsResponse
|
||||
message CMsgGCRequestAnnouncementsResponse
|
||||
{
|
||||
optional string announcement_title = 1; // title of the announcement
|
||||
optional string announcement = 2; // announcement
|
||||
optional string nextmatch_title = 3; // nextmatch title
|
||||
optional string nextmatch = 4; // nextmatch
|
||||
|
||||
};
|
||||
|
||||
enum GC_BannedWordType
|
||||
{
|
||||
GC_BANNED_WORD_DISABLE_WORD = 0; // This word is disabled. It may be followed by an enable later
|
||||
GC_BANNED_WORD_ENABLE_WORD = 1; // This word is enabled
|
||||
};
|
||||
|
||||
message CMsgGCBannedWord
|
||||
{
|
||||
optional uint32 word_id = 1; // The ID of this word
|
||||
optional GC_BannedWordType word_type = 2; // Enable, disable, or what
|
||||
optional string word = 3; // The actual text of the word
|
||||
};
|
||||
|
||||
// k_EMsgGCBannedWordListResponse
|
||||
message CMsgGCBannedWordListResponse
|
||||
{
|
||||
optional uint32 ban_list_group_id = 1; // The ban list group code to request the word list from (English, Chinese, etc)
|
||||
repeated CMsgGCBannedWord word_list = 2; // The list of banned word updates relevant for this group
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCBannedWordListBroadcast
|
||||
message CMsgGCToGCBannedWordListBroadcast
|
||||
{
|
||||
optional CMsgGCBannedWordListResponse broadcast = 1; // The banned word message to broadcast
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCBannedWordListUpdated
|
||||
message CMsgGCToGCBannedWordListUpdated
|
||||
{
|
||||
optional uint32 group_id = 1; // The id of the group that has been updated
|
||||
};
|
||||
|
||||
message CSOEconDefaultEquippedDefinitionInstanceClient
|
||||
{
|
||||
optional uint32 account_id = 1 [ (key_field) = true ];
|
||||
optional uint32 item_definition = 2;
|
||||
optional uint32 class_id = 3 [ (key_field) = true ];
|
||||
optional uint32 slot_id = 4 [ (key_field) = true ];
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCDirtySDOCache
|
||||
message CMsgGCToGCDirtySDOCache
|
||||
{
|
||||
optional uint32 sdo_type = 1; // the type of the cache to dirty
|
||||
optional uint64 key_uint64 = 2; // a 64 bit key type
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCDirtyMultipleSDOCache
|
||||
message CMsgGCToGCDirtyMultipleSDOCache
|
||||
{
|
||||
optional uint32 sdo_type = 1; // the type of the cache to dirty
|
||||
repeated uint64 key_uint64 = 2; // a 64 bit key type
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCCollectItem
|
||||
//
|
||||
message CMsgGCCollectItem
|
||||
{
|
||||
optional uint64 collection_item_id = 1;
|
||||
optional uint64 subject_item_id = 2;
|
||||
};
|
||||
|
||||
// No ID - Used for SDO objects that don't make use of memcached and therefore don't need to serialize into a proto object
|
||||
message CMsgSDONoMemcached
|
||||
{
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCUpdateSQLKeyValue
|
||||
message CMsgGCToGCUpdateSQLKeyValue
|
||||
{
|
||||
optional string key_name = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCIsTrustedServer
|
||||
message CMsgGCToGCIsTrustedServer
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCIsTrustedServerResponse
|
||||
message CMsgGCToGCIsTrustedServerResponse
|
||||
{
|
||||
optional bool is_trusted = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCBroadcastConsoleCommand
|
||||
message CMsgGCToGCBroadcastConsoleCommand
|
||||
{
|
||||
optional string con_command = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCServerVersionUpdated
|
||||
message CMsgGCServerVersionUpdated
|
||||
{
|
||||
optional uint32 server_version = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCClientVersionUpdated
|
||||
message CMsgGCClientVersionUpdated
|
||||
{
|
||||
optional uint32 client_version = 1;
|
||||
};
|
||||
|
||||
// k_EMsgGCToGCWebAPIAccountChanged
|
||||
message CMsgGCToGCWebAPIAccountChanged
|
||||
{
|
||||
};
|
||||
|
||||
// k_EMsgGCRequestPassportItemGrant
|
||||
message CMsgGCToGCRequestPassportItemGrant
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
optional uint32 league_id = 2;
|
||||
optional int32 reward_flag = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgGameServerInfo - server address information
|
||||
//
|
||||
message CMsgGameServerInfo
|
||||
{
|
||||
optional fixed32 server_public_ip_addr = 1;
|
||||
optional fixed32 server_private_ip_addr = 2;
|
||||
optional uint32 server_port = 3;
|
||||
optional uint32 server_tv_port = 4;
|
||||
optional string server_key = 5;
|
||||
optional bool server_hibernation = 6;
|
||||
enum ServerType
|
||||
{
|
||||
UNSPECIFIED = 0; // We haven't received the type yet
|
||||
GAME = 1; // Game server
|
||||
PROXY = 2; // Source TV proxy relay
|
||||
}
|
||||
optional ServerType server_type = 7 [ default = UNSPECIFIED ];
|
||||
optional uint32 server_region = 8; // Region value that matches regions.txt in the GC
|
||||
optional float server_loadavg = 9; // current load average
|
||||
optional float server_tv_broadcast_time = 10; // This may be negative if the game hasn't started broadcasting
|
||||
optional float server_game_time = 11; // Current game clock time
|
||||
optional fixed64 server_relay_connected_steam_id = 12; // SteamID of the game or relay server this relay is connected to
|
||||
optional uint32 relay_slots_max = 13; // slots total on relay
|
||||
optional int32 relays_connected = 14; // count of relays connected
|
||||
optional int32 relay_clients_connected = 15; // count of clients connected (all types)
|
||||
optional fixed64 relayed_game_server_steam_id = 16; // SteamID of the game server this relay is relaying
|
||||
optional uint32 parent_relay_count = 17; // The count of parent relays above this relay
|
||||
optional fixed64 tv_secret_code = 18; // The randomly generated ID for this server that requesting connections must use to hash the connecting steam ID to create a unique connection code
|
||||
};
|
||||
|
||||
// Do not remove this comment due to a bug on the Mac OS X protobuf compiler - lol
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
$MacroRequired PROTOBUF_BUILDER_INCLUDED
|
||||
|
||||
$Project
|
||||
{
|
||||
$Folder "Protobuf Files"
|
||||
{
|
||||
$File "$SRCDIR\game\shared\base_gcmessages.proto"
|
||||
$DynamicFile "$GENERATED_PROTO_DIR\base_gcmessages.pb.h"
|
||||
$DynamicFile "$GENERATED_PROTO_DIR\base_gcmessages.pb.cc"
|
||||
{
|
||||
$Configuration
|
||||
{
|
||||
$Compiler [$WINDOWS]
|
||||
{
|
||||
$Create/UsePrecompiledHeader "Not Using Precompiled Headers"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
//====== Copyright 1996-2010, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: The file defines our Google Protocol Buffers which are used in over
|
||||
// the wire messages between servers as well as between the TF GC and TF gameservers
|
||||
// and clients.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
// We care more about speed than code size
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// We don't use the service generation functionality
|
||||
option cc_generic_services = false;
|
||||
|
||||
|
||||
//
|
||||
// STYLE NOTES:
|
||||
//
|
||||
// Use CamelCase CMsgMyMessageName style names for messages.
|
||||
//
|
||||
// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
|
||||
// but plays nice with the Google formatted code generation.
|
||||
//
|
||||
// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
|
||||
// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
|
||||
// your message and wants to remove or rename fields.
|
||||
//
|
||||
// Use fixed64 for JobId_t, GID_t, or SteamID. This is appropriate for any field that is normally
|
||||
// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
|
||||
// than 2^56 as it will safe space on the wire in those cases.
|
||||
//
|
||||
// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
|
||||
// 2^28. It will save space in those cases, otherwise use int32 which will safe space for smaller values.
|
||||
// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
|
||||
// time.
|
||||
//
|
||||
|
||||
import "steammessages_ps3.proto";
|
||||
|
||||
// Shared objects
|
||||
|
||||
//
|
||||
// CSOPartyInvite - sent from the GC to possible new party member
|
||||
//
|
||||
message CSOPartyInvite
|
||||
{
|
||||
optional uint64 group_id = 1;
|
||||
optional fixed64 sender_id = 2;
|
||||
optional string sender_name = 3;
|
||||
};
|
||||
|
||||
// Sent from the GC to possible new lobby member
|
||||
//
|
||||
message CSOLobbyInvite
|
||||
{
|
||||
optional uint64 group_id = 1;
|
||||
optional fixed64 sender_id = 2;
|
||||
optional string sender_name = 3;
|
||||
// TODO: Game mode, etc.
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgSystemBroadcast
|
||||
//
|
||||
message CMsgSystemBroadcast
|
||||
{
|
||||
optional string message = 1; // the message to display on the client
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgInviteToParty - sent from party leader to the GC
|
||||
//
|
||||
message CMsgInviteToParty
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CMsgInvitationCreated - sent from GC to the party leader
|
||||
//
|
||||
message CMsgInvitationCreated
|
||||
{
|
||||
optional uint64 group_id = 1;
|
||||
optional fixed64 steam_id = 2;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CMsgPartyInviteResponse - sent from client to GC when accepting/rejecting a CMsgPartyInvite
|
||||
//
|
||||
message CMsgPartyInviteResponse
|
||||
{
|
||||
optional uint64 party_id = 1;
|
||||
optional bool accept = 2;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CMsgKickFromParty - sent from party leader to the GC
|
||||
//
|
||||
message CMsgKickFromParty
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgLeaveParty - sent from party member to the GC
|
||||
//
|
||||
message CMsgLeaveParty
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgGameServerInfo - server address information
|
||||
//
|
||||
message CMsgGameServerInfo
|
||||
{
|
||||
optional fixed32 server_public_ip_addr = 1;
|
||||
optional fixed32 server_private_ip_addr = 2;
|
||||
optional uint32 server_port = 3;
|
||||
optional uint32 server_tv_port = 4;
|
||||
optional string server_key = 5;
|
||||
optional bool server_hibernation = 6;
|
||||
enum ServerType
|
||||
{
|
||||
UNSPECIFIED = 0; // We haven't received the type yet
|
||||
GAME = 1; // Game server
|
||||
PROXY = 2; // Source TV proxy relay
|
||||
CONTROLLER = 3; // Game server/proxy controller/spawner
|
||||
}
|
||||
optional ServerType server_type = 7 [ default = UNSPECIFIED ];
|
||||
optional uint32 server_region = 8; // Region value that matches regions.txt in the GC
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgServerAvailable - send from a dedicated server to the GC to indicate availability
|
||||
//
|
||||
message CMsgServerAvailable
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Used by CEconGameAccountClient
|
||||
//
|
||||
message CSOEconGameAccountClient
|
||||
{
|
||||
optional uint32 additional_backpack_slots = 1 [ default = 0 ]; // the number of backpack slots this user has on top of DEFAULT_NUM_BACKPACK_SLOTS
|
||||
optional bool trial_account = 2 [ default = false ];
|
||||
optional bool eligible_for_online_play = 3 [ default = true ];
|
||||
optional bool need_to_choose_most_helpful_friend = 4;
|
||||
optional bool in_coaches_list = 5;
|
||||
optional fixed32 trade_ban_expiration = 6;
|
||||
optional fixed32 duel_ban_expiration = 7;
|
||||
optional uint32 preview_item_def = 8 [ default = 0 ];
|
||||
};
|
||||
|
||||
//
|
||||
// Used by CEconCraftingRecipe
|
||||
//
|
||||
message CSOItemCriteriaCondition
|
||||
{
|
||||
optional int32 op = 1;
|
||||
optional string field = 2;
|
||||
optional bool required = 3;
|
||||
optional float float_value = 4;
|
||||
optional string string_value = 5;
|
||||
}
|
||||
|
||||
|
||||
message CSOItemCriteria
|
||||
{
|
||||
optional uint32 item_level = 1;
|
||||
optional int32 item_quality = 2;
|
||||
|
||||
optional bool item_level_set = 3;
|
||||
optional bool item_quality_set = 4;
|
||||
optional uint32 initial_inventory = 5;
|
||||
optional uint32 initial_quantity = 6;
|
||||
optional bool forced_quality_match = 7;
|
||||
optional bool ignore_enabled_flag = 8;
|
||||
|
||||
repeated CSOItemCriteriaCondition conditions = 9;
|
||||
};
|
||||
|
||||
|
||||
message CSOItemRecipe
|
||||
{
|
||||
optional uint32 def_index = 1;
|
||||
optional string name = 2;
|
||||
optional string n_a = 3;
|
||||
optional string desc_inputs = 4;
|
||||
optional string desc_outputs = 5;
|
||||
optional string di_a = 6;
|
||||
optional string di_b = 7;
|
||||
optional string di_c = 8;
|
||||
optional string do_a = 9;
|
||||
optional string do_b = 10;
|
||||
optional string do_c = 11;
|
||||
optional bool requires_all_same_class = 12;
|
||||
optional bool requires_all_same_slot = 13;
|
||||
optional int32 class_usage_for_output = 14;
|
||||
optional int32 slot_usage_for_output = 15;
|
||||
optional int32 set_for_output = 16;
|
||||
|
||||
repeated CSOItemCriteria input_items_criteria = 20;
|
||||
repeated CSOItemCriteria output_items_criteria = 21;
|
||||
repeated uint32 input_item_dupe_counts = 22;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCDev_NewItemRequest
|
||||
//
|
||||
message CMsgDevNewItemRequest
|
||||
{
|
||||
//using fixed64 since steamids have lots of entropy in their bits
|
||||
optional fixed64 receiver = 1;
|
||||
optional CSOItemCriteria criteria = 2;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCIncrementKillCountAttribute
|
||||
//
|
||||
message CMsgIncrementKillCountAttribute
|
||||
{
|
||||
optional uint64 killer_steam_id = 1;
|
||||
optional uint64 victim_steam_id = 2;
|
||||
optional uint64 item_id = 3;
|
||||
|
||||
optional uint32 event_type = 4;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Used by CEconItem
|
||||
//
|
||||
message CSOEconItemAttribute
|
||||
{
|
||||
optional uint32 def_index = 1;
|
||||
optional uint32 value = 2;
|
||||
}
|
||||
|
||||
message CSOEconItemEquipped
|
||||
{
|
||||
optional uint32 new_class = 1;
|
||||
optional uint32 new_slot = 2;
|
||||
}
|
||||
|
||||
message CSOEconItem
|
||||
{
|
||||
optional uint64 id = 1;
|
||||
optional uint32 account_id = 2;
|
||||
optional uint32 inventory = 3;
|
||||
optional uint32 def_index = 4;
|
||||
optional uint32 quantity = 5;
|
||||
optional uint32 level = 6;
|
||||
optional uint32 quality = 7;
|
||||
optional uint32 flags = 8 [ default = 0 ];
|
||||
optional uint32 origin = 9;
|
||||
optional string custom_name = 10;
|
||||
optional string custom_desc = 11;
|
||||
repeated CSOEconItemAttribute attribute = 12;
|
||||
optional CSOEconItem interior_item = 13;
|
||||
optional bool in_use = 14 [ default = false ];
|
||||
optional uint32 style = 15 [default = 0 ];
|
||||
optional uint64 original_id = 16 [ default = 0 ];
|
||||
optional bool contains_equipped_state = 17;
|
||||
repeated CSOEconItemEquipped equipped_state = 18;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgGCAdjustItemEquippedState
|
||||
//
|
||||
message CMsgAdjustItemEquippedState
|
||||
{
|
||||
optional uint64 item_id = 1;
|
||||
optional uint32 new_class = 2;
|
||||
optional uint32 new_slot = 3; // will be -1 if not equipped on this class any longer
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgGCSortItems
|
||||
//
|
||||
message CMsgSortItems
|
||||
{
|
||||
optional uint32 sort_type = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Used by CEconClaimCode
|
||||
//
|
||||
message CSOEconClaimCode
|
||||
{
|
||||
optional uint32 account_id = 1;
|
||||
optional uint32 code_type = 2;
|
||||
optional uint32 time_acquired = 3;
|
||||
optional string code = 4;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgGCStoreGetUserData
|
||||
//
|
||||
message CMsgStoreGetUserData
|
||||
{
|
||||
optional fixed32 price_sheet_version = 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EMsgGCStoreGetUserDataResponse
|
||||
//
|
||||
message CMsgStoreGetUserDataResponse
|
||||
{
|
||||
optional int32 result = 1; // Result of the call
|
||||
optional int32 currency = 2; // Currency to display to the user
|
||||
optional string country = 3; // Country the purchase is being made from (Send back in k_EMsgGCStorePurchaseInit)
|
||||
|
||||
optional fixed32 price_sheet_version = 4; // Version of the current price sheet on the GC
|
||||
|
||||
// experiments
|
||||
optional uint64 experiment_data = 5 [ default = 0 ]; // top 32 bits = experiment id, bottom 32 bits = experiment group number
|
||||
optional int32 featured_item_idx = 6;
|
||||
optional bool show_hat_descriptions = 7 [ default = true ];
|
||||
|
||||
// Serialized KV representing the price sheet menu
|
||||
optional bytes price_sheet = 8;
|
||||
|
||||
optional int32 default_item_sort = 9 [ default = 0 ];
|
||||
|
||||
// popular items by def
|
||||
repeated uint32 popular_items = 10;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCUpdateItemSchema
|
||||
//
|
||||
message CMsgUpdateItemSchema
|
||||
{
|
||||
optional bytes items_game = 1; // actual contents of items_game.txt (only used on dev)
|
||||
optional fixed32 item_schema_version = 2; // Version of the items_game.txt we're using
|
||||
optional string items_game_url = 3; // HTTP URL where they can use to fetch the one we're using, if theirs is out of date and we don't send the contents
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCRequestItemSchemaData
|
||||
//
|
||||
message CMsgRequestItemSchemaData
|
||||
{
|
||||
};
|
||||
|
||||
// sent from the GC to a client telling him about a GC error
|
||||
message CMsgGCError
|
||||
{
|
||||
optional string error_text = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCRequestInventoryRefresh
|
||||
//
|
||||
message CMsgRequestInventoryRefresh
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCConvarUpdated
|
||||
//
|
||||
message CMsgConVarValue
|
||||
{
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCReplicateConVars
|
||||
//
|
||||
message CMsgReplicateConVars
|
||||
{
|
||||
repeated CMsgConVarValue convars = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCUseItemRequest
|
||||
//
|
||||
message CMsgUseItem
|
||||
{
|
||||
optional uint64 item_id = 1;
|
||||
optional fixed64 target_steam_id = 2; // 64-bit field left over from original message
|
||||
|
||||
repeated uint32 gift__potential_targets = 3;
|
||||
optional uint32 duel__class_lock = 4;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCReplay_UploadedToYouTube
|
||||
//
|
||||
message CMsgReplayUploadedToYouTube
|
||||
{
|
||||
optional string youtube_url = 1;
|
||||
optional string youtube_account_name = 2;
|
||||
optional uint64 session_id = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// k_EMsgGCItemAcknowledged
|
||||
//
|
||||
message CMsgItemAcknowledged
|
||||
{
|
||||
optional uint32 account_id = 1;
|
||||
optional uint32 inventory = 2;
|
||||
optional uint32 def_index = 3;
|
||||
optional uint32 quality = 4;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgSelectItemPresetForClass
|
||||
//
|
||||
message CMsgSelectItemPresetForClass
|
||||
{
|
||||
optional uint32 class_index = 2;
|
||||
optional uint32 preset_index = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// CSOSelectedItemPreset
|
||||
//
|
||||
message CSOSelectedItemPreset
|
||||
{
|
||||
optional uint32 account_id = 1 [ (key_field) = true ];
|
||||
optional uint32 class_index = 2 [ (key_field) = true ];
|
||||
optional uint32 preset_index = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// CSOCommunityMapItem
|
||||
//
|
||||
message CSOItemCommunityMap
|
||||
{
|
||||
optional uint32 mapID = 1;
|
||||
optional uint32 mapAuthorID = 2;
|
||||
optional string mapName = 3;
|
||||
optional string mapFilename = 4;
|
||||
optional fixed64 mapUGCHandle = 5;
|
||||
optional fixed64 mapUGCThumbHandle = 6;
|
||||
optional uint32 mapVersion = 7;
|
||||
optional fixed32 mapCreateDate = 8;
|
||||
optional uint32 mapVoteUp = 9;
|
||||
optional uint32 mapVoteDown = 10;
|
||||
optional uint32 mapDownloads = 11;
|
||||
optional uint32 userVoteStatus = 12;
|
||||
optional bool userCompleted = 13;
|
||||
optional fixed32 userDownloadTimestamp=14;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgPlaytestReportDemo
|
||||
//
|
||||
message CMsgPlaytestReportDemo
|
||||
{
|
||||
optional fixed64 author_id = 1;
|
||||
optional fixed64 ugc_handle = 2;
|
||||
optional fixed64 map_id = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgPlaytestRetrieveDemoHandles
|
||||
//
|
||||
message CMsgPlaytestRetrieveDemoHandles
|
||||
{
|
||||
optional fixed64 author_id = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgPlaytestRetrieveDemoHandlesResponse
|
||||
//
|
||||
message CMsgPlaytestRetrieveDemoHandlesResponse
|
||||
{
|
||||
optional fixed64 author_id = 1;
|
||||
repeated fixed64 ugc_handle = 2;
|
||||
repeated fixed64 map_id = 3;
|
||||
};
|
||||
|
||||
//
|
||||
// CMsgPlaytestRemoveDemo
|
||||
//
|
||||
message CMsgPlaytestRemoveDemo
|
||||
{
|
||||
optional fixed64 author_id = 1;
|
||||
optional fixed64 ugc_handle = 2;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,310 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASE_PLAYERANIMSTATE_H
|
||||
#define BASE_PLAYERANIMSTATE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "iplayeranimstate.h"
|
||||
#include "studio.h"
|
||||
#include "sequence_Transitioner.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
class C_BaseAnimatingOverlay;
|
||||
#define CBaseAnimatingOverlay C_BaseAnimatingOverlay
|
||||
#else
|
||||
class CBaseAnimatingOverlay;
|
||||
#endif
|
||||
|
||||
// If a guy is moving slower than this, then he's considered to not be moving
|
||||
// (so he goes to his idle animation at full playback rate rather than his walk
|
||||
// animation at low playback rate).
|
||||
#define MOVING_MINIMUM_SPEED 0.5f
|
||||
|
||||
#define FOOTPLANT_MINIMUM_SPEED 0.1f
|
||||
|
||||
#define MAIN_IDLE_SEQUENCE_LAYER 0 // For 8-way blended models, this layer blends an idle on top of the run/walk animation to simulate a 9-way blend.
|
||||
// For 9-way blended models, we don't use this layer.
|
||||
|
||||
#define AIMSEQUENCE_LAYER 1 // Aim sequence uses layers 0 and 1 for the weapon idle animation (needs 2 layers so it can blend).
|
||||
|
||||
|
||||
#define NUM_AIMSEQUENCE_LAYERS 2 // Then it uses layers 2 and 3 to blend in the weapon run/walk/crouchwalk animation.
|
||||
|
||||
|
||||
// Everyone who derives from CBasePlayerAnimState gets to fill in this info
|
||||
// to drive how the animation state is generated.
|
||||
class CModAnimConfig
|
||||
{
|
||||
public:
|
||||
// This tells how far the upper body can rotate left and right. If he begins to rotate
|
||||
// past this, it'll turn his feet to face his upper body.
|
||||
float m_flMaxBodyYawDegrees;
|
||||
|
||||
float m_flMaxBodyYawDegreesCorrectionAmount;
|
||||
float m_flIdleFootPlantMaxYaw;
|
||||
float m_flIdleFootPlantFootLiftDelta;
|
||||
|
||||
// How do the legs animate?
|
||||
LegAnimType_t m_LegAnimType;
|
||||
|
||||
// Use aim sequences? (CS hostages don't).
|
||||
bool m_bUseAimSequences;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ //
|
||||
// CBasePlayerAnimState declaration.
|
||||
// ------------------------------------------------------------------------------------------------ //
|
||||
|
||||
abstract_class CBasePlayerAnimState : public IPlayerAnimState
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS_NOBASE( CBasePlayerAnimState );
|
||||
|
||||
enum
|
||||
{
|
||||
TURN_NONE = 0,
|
||||
TURN_LEFT,
|
||||
TURN_RIGHT
|
||||
};
|
||||
|
||||
CBasePlayerAnimState();
|
||||
virtual ~CBasePlayerAnimState();
|
||||
|
||||
void Init( CBaseAnimatingOverlay *pPlayer, const CModAnimConfig &config );
|
||||
virtual void Release();
|
||||
|
||||
// Update() and DoAnimationEvent() together maintain the entire player's animation state.
|
||||
//
|
||||
// Update() maintains the the lower body animation (the player's m_nSequence)
|
||||
// and the upper body overlay based on the player's velocity and look direction.
|
||||
//
|
||||
// It also modulates these based on events triggered by DoAnimationEvent.
|
||||
virtual void Update( float eyeYaw, float eyePitch );
|
||||
|
||||
// This is called by the client when a new player enters the PVS to clear any events
|
||||
// the dormant version of the entity may have been playing.
|
||||
virtual void ClearAnimationState();
|
||||
|
||||
// This is called every frame to prepare the animation layers to be filled with data
|
||||
// since we reconstruct them every frame (in case they get stomped by the networking
|
||||
// or anything else).
|
||||
virtual void ClearAnimationLayers();
|
||||
|
||||
// The client uses this to figure out what angles to render the entity with (since as the guy turns,
|
||||
// it will change his body_yaw pose parameter before changing his rendered angle).
|
||||
virtual const QAngle& GetRenderAngles();
|
||||
|
||||
virtual void SetForceAimYaw( bool bForce );
|
||||
|
||||
// Overrideables.
|
||||
public:
|
||||
|
||||
virtual bool ShouldUpdateAnimState();
|
||||
|
||||
// This is called near the start of each frame.
|
||||
// The base class figures out the main sequence and the aim sequence, and derived
|
||||
// classes can overlay whatever other animations they want.
|
||||
virtual void ComputeSequences( CStudioHdr *pStudioHdr );
|
||||
|
||||
// This is called to figure out what the main activity is. The mod-specific class
|
||||
// overrides this to handle events like jumping, firing, etc.
|
||||
virtual Activity CalcMainActivity() = 0;
|
||||
|
||||
// This is called to calculate the aim layer sequence. It usually figures out the
|
||||
// animation prefixes and suffixes and calls CalcSequenceIndex().
|
||||
virtual int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ) = 0;
|
||||
|
||||
// This lets server-controlled idle sequences to play unchanged on the client
|
||||
virtual bool ShouldChangeSequences( void ) const;
|
||||
|
||||
// If this returns true, then it will blend the current aim layer sequence with an idle aim layer
|
||||
// sequence based on how fast the character is moving, so it doesn't play the upper-body run at
|
||||
// full speed if he's moving really slowly.
|
||||
//
|
||||
// We return false on this for animations that don't have blends, like reloads.
|
||||
virtual bool ShouldBlendAimSequenceToIdle();
|
||||
|
||||
// For the body left/right rotation, some models use a pose parameter and some use a bone controller.
|
||||
virtual float SetOuterBodyYaw( float flValue );
|
||||
|
||||
// Return true if the player is allowed to move.
|
||||
virtual bool CanThePlayerMove();
|
||||
|
||||
// This is called every frame to see what the maximum speed the player can move is.
|
||||
// It is used to determine where to put the move_x/move_y pose parameters or to
|
||||
// determine the animation playback rate, based on the player's movement speed.
|
||||
// The return value from here is interpolated so the playback rate or pose params don't move sharply.
|
||||
virtual float GetCurrentMaxGroundSpeed() = 0;
|
||||
|
||||
// Display Con_NPrint output about the animation state. This is called if
|
||||
// we're on the client and if cl_showanimstate holds the current entity's index.
|
||||
void DebugShowAnimStateFull( int iStartLine );
|
||||
|
||||
virtual void DebugShowAnimState( int iStartLine );
|
||||
void AnimStatePrintf( int iLine, PRINTF_FORMAT_STRING const char *pMsg, ... );
|
||||
void AnimStateLog( PRINTF_FORMAT_STRING const char *pMsg, ... );
|
||||
|
||||
// Calculate the playback rate for movement layer
|
||||
virtual float CalcMovementPlaybackRate( bool *bIsMoving );
|
||||
|
||||
// Allow inheriting classes to translate their desired activity, while keeping all
|
||||
// internal ACT comparisons using the base activity
|
||||
virtual Activity TranslateActivity( Activity actDesired ) { return actDesired; }
|
||||
|
||||
// Allow inheriting classes to override SelectWeightedSequence
|
||||
virtual int SelectWeightedSequence( Activity activity );
|
||||
|
||||
public:
|
||||
|
||||
void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );
|
||||
|
||||
CBaseAnimatingOverlay *GetOuter() const;
|
||||
|
||||
void RestartMainSequence();
|
||||
|
||||
virtual float GetFeetYawRate( void );
|
||||
|
||||
|
||||
// Helpers for the derived classes to use.
|
||||
protected:
|
||||
|
||||
// Sets up the string you specify, looks for that sequence and returns the index.
|
||||
// Complains in the console and returns 0 if it can't find it.
|
||||
virtual int CalcSequenceIndex( PRINTF_FORMAT_STRING const char *pBaseName, ... );
|
||||
|
||||
Activity GetCurrentMainSequenceActivity() const;
|
||||
|
||||
void GetOuterAbsVelocity( Vector& vel ) const;
|
||||
float GetOuterXYSpeed() const;
|
||||
|
||||
// How long has it been since we cleared the animation state?
|
||||
float TimeSinceLastAnimationStateClear() const;
|
||||
|
||||
float GetEyeYaw() const { return m_flEyeYaw; }
|
||||
|
||||
void SetOuterPoseParameter( int iParam, float flValue );
|
||||
|
||||
protected:
|
||||
|
||||
CModAnimConfig m_AnimConfig;
|
||||
CBaseAnimatingOverlay *m_pOuter;
|
||||
|
||||
protected:
|
||||
virtual int ConvergeAngles( float goal,float maxrate, float maxgap, float dt, float& current );
|
||||
virtual void ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr );
|
||||
virtual void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
|
||||
virtual void ComputePoseParam_BodyYaw();
|
||||
|
||||
virtual void ResetGroundSpeed( void );
|
||||
virtual bool ShouldResetGroundSpeed( Activity oldActivity, Activity idealActivity );
|
||||
|
||||
protected:
|
||||
// The player's eye yaw and pitch angles.
|
||||
float m_flEyeYaw;
|
||||
float m_flEyePitch;
|
||||
|
||||
// The following variables are used for tweaking the yaw of the upper body when standing still and
|
||||
// making sure that it smoothly blends in and out once the player starts moving
|
||||
// Direction feet were facing when we stopped moving
|
||||
float m_flGoalFeetYaw;
|
||||
|
||||
float m_flCurrentFeetYaw;
|
||||
bool m_bCurrentFeetYawInitialized;
|
||||
|
||||
bool m_bForceAimYaw;
|
||||
|
||||
float m_flCurrentTorsoYaw;
|
||||
|
||||
// To check if they are rotating in place
|
||||
float m_flLastYaw;
|
||||
|
||||
// Time when we stopped moving
|
||||
float m_flLastTurnTime;
|
||||
|
||||
// One of the above enums
|
||||
int m_nTurningInPlace;
|
||||
|
||||
QAngle m_angRender;
|
||||
|
||||
Vector2D m_vLastMovePose;
|
||||
|
||||
bool m_bInFootPlantIdleTurn;
|
||||
float m_flFootPlantIdleTurnCycle;
|
||||
bool m_bFootPlantIdleNeedToLiftFeet;
|
||||
|
||||
float m_flPoseParamTargetDampenedScaleIdeal;
|
||||
|
||||
private:
|
||||
|
||||
// Update the prone state machine.
|
||||
void UpdateProneState();
|
||||
|
||||
// Get the string that's appended to animation names for the player's current weapon.
|
||||
const char* GetWeaponSuffix();
|
||||
|
||||
Activity BodyYawTranslateActivity( Activity activity );
|
||||
|
||||
void EstimateYaw();
|
||||
|
||||
virtual bool ShouldResetMainSequence( int iCurrentSequence, int iNewSequence );
|
||||
void ComputeMainSequence();
|
||||
void ComputeAimSequence();
|
||||
|
||||
void ComputePlaybackRate();
|
||||
|
||||
void ResetCycleAcrossCustomActivityChange( Activity iCurrent, Activity iNew );
|
||||
|
||||
void UpdateInterpolators();
|
||||
float GetInterpolatedGroundSpeed();
|
||||
|
||||
private:
|
||||
|
||||
float m_flMaxGroundSpeed;
|
||||
|
||||
float m_flLastAnimationStateClearTime;
|
||||
|
||||
// If he's using 8-way blending, then we blend to this idle
|
||||
int m_iCurrent8WayIdleSequence;
|
||||
int m_iCurrent8WayCrouchIdleSequence;
|
||||
|
||||
// Last activity we've used on the lower body. Used to determine if animations should restart.
|
||||
Activity m_eCurrentMainSequenceActivity;
|
||||
|
||||
float m_flGaitYaw;
|
||||
float m_flStoredCycle;
|
||||
|
||||
void UpdateAimSequenceLayers(
|
||||
float flCycle,
|
||||
int iFirstLayer,
|
||||
bool bForceIdle,
|
||||
CSequenceTransitioner *pTransitioner,
|
||||
float flWeightScale
|
||||
);
|
||||
|
||||
void OptimizeLayerWeights( int iFirstLayer, int nLayers );
|
||||
|
||||
protected:
|
||||
|
||||
// This gives us smooth transitions between aim anim sequences on the client.
|
||||
CSequenceTransitioner m_HighAimSequenceTransitioner;
|
||||
CSequenceTransitioner m_LowAimSequenceTransitioner;
|
||||
};
|
||||
|
||||
extern float g_flLastBodyPitch, g_flLastBodyYaw, m_flLastMoveYaw;
|
||||
|
||||
|
||||
inline Activity CBasePlayerAnimState::GetCurrentMainSequenceActivity() const
|
||||
{
|
||||
return m_eCurrentMainSequenceActivity;
|
||||
}
|
||||
|
||||
|
||||
#endif // BASE_PLAYERANIMSTATE_H
|
||||
@@ -0,0 +1,891 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "achievementmgr.h"
|
||||
#include "icommandline.h"
|
||||
#ifdef CLIENT_DLL
|
||||
#include "tier3/tier3.h"
|
||||
#include "vgui/ILocalize.h"
|
||||
#include "achievement_notification_panel.h"
|
||||
#include "fmtstr.h"
|
||||
#include "cdll_client_int.h"
|
||||
#include "matchmaking/imatchframework.h"
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#include <vgui/ISystem.h>
|
||||
#include "../../src/public/vgui_controls/Controls.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
|
||||
CBaseAchievementHelper *CBaseAchievementHelper::s_pFirst = NULL;
|
||||
static int g_nAchivementBitchCount = 0;
|
||||
|
||||
BEGIN_DATADESC_NO_BASE( CBaseAchievement )
|
||||
DEFINE_FIELD( m_iCount, FIELD_INTEGER ),
|
||||
END_DATADESC()
|
||||
|
||||
BEGIN_DATADESC( CFailableAchievement )
|
||||
DEFINE_FIELD( m_bActivated, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( m_bFailed, FIELD_BOOLEAN ),
|
||||
END_DATADESC()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseAchievement::CBaseAchievement()
|
||||
{
|
||||
m_iFlags = 0;
|
||||
m_iGoal = 0;
|
||||
m_iProgressMsgIncrement = 0;
|
||||
m_iProgressMsgMinimum = 0;
|
||||
m_iAchievementID = 0;
|
||||
m_iPointValue = 0;
|
||||
m_bHideUntilAchieved = false;
|
||||
m_bStoreProgressInSteam = false;
|
||||
m_pVictimClassNameFilter = NULL;
|
||||
m_pAttackerClassNameFilter = NULL;
|
||||
m_pInflictorClassNameFilter = NULL;
|
||||
m_pInflictorEntityNameFilter = NULL;
|
||||
m_pMapNameFilter = NULL;
|
||||
m_pGameDirFilter = NULL;
|
||||
m_pszComponentNames = NULL;
|
||||
m_pszComponentDisplayNames = NULL;
|
||||
m_pszComponentPrefix = NULL;
|
||||
m_iNumComponents = 0;
|
||||
m_iComponentPrefixLen = 0;
|
||||
m_iComponentBits = 0;
|
||||
m_iCount = 0;
|
||||
m_iProgressShown = 0;
|
||||
m_bAchieved = false;
|
||||
m_uUnlockTime = 0;
|
||||
m_pAchievementMgr = NULL;
|
||||
m_nUserSlot = 0;
|
||||
m_iAssetAwardID = 0;
|
||||
m_bShowOnHUD = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets flags
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetFlags( int iFlags )
|
||||
{
|
||||
// must always specify a save method
|
||||
Assert( iFlags & ( ACH_SAVE_WITH_GAME | ACH_SAVE_GLOBAL ) );
|
||||
|
||||
m_iFlags = iFlags;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when a game event being listened for is dispatched
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::FireGameEvent( IGameEvent *event )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nUserSlot );
|
||||
#endif
|
||||
//
|
||||
// Perform common filtering to make it simpler to write achievements
|
||||
//
|
||||
if ( !IsActive() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if the achievement only applies to a specific map, and it's not the current map, skip it
|
||||
if ( m_pMapNameFilter && ( 0 != Q_strcmp( m_pAchievementMgr->GetMapName(), m_pMapNameFilter ) ) )
|
||||
return;
|
||||
|
||||
const char *name = event->GetName();
|
||||
if ( 0 == Q_strcmp( name, "teamplay_round_win" ) )
|
||||
{
|
||||
// if this is a round win and the achievement wants full round events only, filter this out
|
||||
// if this is not the end of a full round
|
||||
if ( ( m_iFlags & ACH_FILTER_FULL_ROUND_ONLY ) && ( false == event->GetBool( "full_round" ) ) )
|
||||
return;
|
||||
}
|
||||
|
||||
// let the achievement handle the event
|
||||
FireGameEvent_Internal( event );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets victim class to filter with
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetVictimFilter( const char *pClassName )
|
||||
{
|
||||
m_pVictimClassNameFilter = pClassName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets attacker class to filter with
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetAttackerFilter( const char *pClassName )
|
||||
{
|
||||
m_pAttackerClassNameFilter = pClassName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets inflictor class to filter with
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetInflictorFilter( const char *pClassName )
|
||||
{
|
||||
m_pInflictorClassNameFilter = pClassName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets inflictor entity name to filter with
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetInflictorEntityNameFilter( const char *pEntityName )
|
||||
{
|
||||
m_pInflictorEntityNameFilter = pEntityName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets map name to filter with
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetMapNameFilter( const char *pMapName )
|
||||
{
|
||||
m_pMapNameFilter = pMapName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets game dir to filter with. Note: in general, achievements should
|
||||
// only be compiled into products they pertain to. But if there are
|
||||
// any game-specific achievements which need to be in a binary shared
|
||||
// across products (e.g. Ep1 & Ep2), use the game dir as a runtime
|
||||
// filter.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetGameDirFilter( const char *pGameDir )
|
||||
{
|
||||
m_pGameDirFilter = pGameDir;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets prefix to look for in map event string to identify a component
|
||||
// for this achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetComponentPrefix( const char *pPrefix )
|
||||
{
|
||||
m_pszComponentPrefix = pPrefix;
|
||||
m_iComponentPrefixLen = Q_strlen( pPrefix );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when a kill that passes filter critera occurs. This
|
||||
// is the default implementation, achievements can override to
|
||||
// do special handling
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
|
||||
{
|
||||
// extra paranoid check: should only get here if registered as a kill event listener
|
||||
Assert( GetFlags() & ACH_LISTEN_KILL_EVENTS );
|
||||
if ( !( GetFlags() & ACH_LISTEN_KILL_EVENTS ) )
|
||||
return;
|
||||
|
||||
// default implementation is just to increase count when filter criteria pass
|
||||
IncrementCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when an event that counts toward an achievement occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::IncrementCount( int iOptIncrement )
|
||||
{
|
||||
if ( !IsAchieved() )
|
||||
{
|
||||
if ( !CheckAchievementsEnabled() )
|
||||
{
|
||||
#ifndef _DEBUG
|
||||
if ( g_nAchivementBitchCount++ < 10 )
|
||||
{
|
||||
DevMsg( "Achievements disabled, ignoring achievement progress for %s\n", GetName() );
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// on client, where the count is kept, increment count
|
||||
if ( iOptIncrement > 0 )
|
||||
{
|
||||
// user specified that we want to increase by more than one.
|
||||
m_iCount += iOptIncrement;
|
||||
if ( m_iCount > m_iGoal )
|
||||
{
|
||||
m_iCount = m_iGoal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iCount++;
|
||||
}
|
||||
|
||||
// if this achievement gets saved w/global state, flag our global state as dirty
|
||||
if ( GetFlags() & ACH_SAVE_GLOBAL )
|
||||
{
|
||||
m_pAchievementMgr->SetDirty( true, m_nUserSlot );
|
||||
}
|
||||
|
||||
if ( cc_achievement_debug.GetInt() )
|
||||
{
|
||||
Msg( "Achievement count increased for %s: %d/%d\n", GetName(), m_iCount, m_iGoal );
|
||||
}
|
||||
|
||||
#if 0 // !defined( NO_STEAM ) - <vitaliy> achievements should always go via TitleData
|
||||
// if this achievement's progress should be stored in Steam, set the steam stat for it
|
||||
if ( StoreProgressInSteam() && steamapicontext->SteamUserStats() )
|
||||
{
|
||||
// Set the Steam stat with the same name as the achievement. Only cached locally until we upload it.
|
||||
char pszProgressName[1024];
|
||||
Q_snprintf( pszProgressName, 1024, "%s_STAT", GetName() );
|
||||
bool bRet = steamapicontext->SteamUserStats()->SetStat( pszProgressName, m_iCount );
|
||||
if ( !bRet )
|
||||
{
|
||||
DevMsg( "ISteamUserStats::GetStat failed to set progress value in Steam for achievement %s\n", pszProgressName );
|
||||
}
|
||||
|
||||
#ifdef INFESTED_DLL
|
||||
// Upload user data to commit the change to Steam so if the client crashes, progress isn't lost.
|
||||
// Only upload if we haven't uploaded recently, to keep us from spamming Steam with uploads. If we don't
|
||||
// upload now, it will get uploaded no later than level shutdown.
|
||||
if ( ( m_pAchievementMgr->GetTimeLastUpload() == 0 ) || ( Plat_FloatTime() - m_pAchievementMgr->GetTimeLastUpload() > 60 * 15 ) )
|
||||
{
|
||||
m_pAchievementMgr->UploadUserData( STEAM_PLAYER_SLOT );
|
||||
}
|
||||
#else
|
||||
m_pAchievementMgr->SetDirty( true, m_nUserSlot );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// if we've hit goal, award the achievement
|
||||
if ( m_iGoal > 0 )
|
||||
{
|
||||
if ( m_iCount >= m_iGoal )
|
||||
{
|
||||
AwardAchievement();
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleProgressUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBaseAchievement::SetShowOnHUD( bool bShow )
|
||||
{
|
||||
if ( m_bShowOnHUD != bShow )
|
||||
{
|
||||
m_pAchievementMgr->SetDirty( true, m_nUserSlot );
|
||||
}
|
||||
|
||||
m_bShowOnHUD = bShow;
|
||||
}
|
||||
|
||||
void CBaseAchievement::HandleProgressUpdate()
|
||||
{
|
||||
// if we've hit the right # of progress steps to show a progress notification, show it
|
||||
if ( ( m_iProgressMsgIncrement > 0 ) && m_iCount >= m_iProgressMsgMinimum && ( 0 == ( m_iCount % m_iProgressMsgIncrement ) ) )
|
||||
{
|
||||
// which notification is this
|
||||
int iProgress = m_iCount / m_iProgressMsgIncrement;
|
||||
// if we haven't already shown this progress step, show it
|
||||
if ( iProgress > m_iProgressShown )
|
||||
{
|
||||
ShowProgressNotification();
|
||||
// remember progress step shown so we don't show it again if the player loads an earlier save game
|
||||
// and gets past this point again
|
||||
m_iProgressShown = iProgress;
|
||||
m_pAchievementMgr->SetDirty( true, m_nUserSlot );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: calculates at how many steps we should show a progress notification
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::CalcProgressMsgIncrement()
|
||||
{
|
||||
// by default, show progress at every 25%
|
||||
m_iProgressMsgIncrement = m_iGoal / 4;
|
||||
// if goal is not evenly divisible by 4, try some other values
|
||||
if ( 0 != ( m_iGoal % 4 ) )
|
||||
{
|
||||
if ( 0 == ( m_iGoal % 3 ) )
|
||||
{
|
||||
// if evenly divisible by 3, use that
|
||||
m_iProgressMsgIncrement = m_iGoal / 3;
|
||||
}
|
||||
else if ( 0 == ( m_iGoal % 5 ) )
|
||||
{
|
||||
// if evenly divisible by 5, use that
|
||||
m_iProgressMsgIncrement = m_iGoal / 5;
|
||||
}
|
||||
// otherwise stick with divided by 4, rounded off
|
||||
}
|
||||
|
||||
// don't show progress notifications for less than 5 things
|
||||
if ( m_iProgressMsgIncrement < 5 )
|
||||
{
|
||||
m_iProgressMsgIncrement = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetNextThink( float flThinkTime )
|
||||
{
|
||||
m_pAchievementMgr->SetAchievementThink( this, flThinkTime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::ClearThink( void )
|
||||
{
|
||||
m_pAchievementMgr->SetAchievementThink( this, THINK_CLEAR );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: see if we should award an achievement based on what just happened
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::EvaluateNewAchievement()
|
||||
{
|
||||
if ( !IsAchieved() && m_iGoal > 0 && m_iCount >= m_iGoal )
|
||||
{
|
||||
m_pAchievementMgr->CheckSignInState( false ); // Local user isn't resolvable, but we know we are signed in (our caller checks).
|
||||
AwardAchievement();
|
||||
m_pAchievementMgr->CheckSignInState( true );
|
||||
|
||||
CheckAssetAwards( m_nUserSlot ); // Since we awarded the achievement we might need to award associated assets as well
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: determine if we should set this achievement to be achieved based
|
||||
// on other state. Used at init time.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::EvaluateIsAlreadyAchieved()
|
||||
{
|
||||
// Check platform specific data to determine status of completed achievements.
|
||||
#if !defined(NO_STEAM)
|
||||
ISteamUserStats *pSteamUserStats = steamapicontext->SteamUserStats();
|
||||
if ( pSteamUserStats )
|
||||
{
|
||||
bool bAchieved;
|
||||
pSteamUserStats->GetAchievement( GetName(), &bAchieved );
|
||||
SetAchieved( bAchieved );
|
||||
}
|
||||
// Handled in CAchievementMgr::UserConnected on X360
|
||||
#endif
|
||||
|
||||
EvaluateNewAchievement();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called a map event for this achievement occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::OnMapEvent( const char *pEventName )
|
||||
{
|
||||
Assert( m_iFlags & ACH_LISTEN_MAP_EVENTS );
|
||||
|
||||
if ( 0 == Q_stricmp( pEventName, GetName() ) )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when an achievement is awarded
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::AwardAchievement()
|
||||
{
|
||||
Assert( !IsAchieved() );
|
||||
if ( IsAchieved() )
|
||||
return;
|
||||
|
||||
m_pAchievementMgr->AwardAchievement( m_iAchievementID, m_nUserSlot );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when a component of a multi-component event is found
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::OnComponentEvent( const char *pchComponentName )
|
||||
{
|
||||
// find the component name in our list
|
||||
for ( int i = 0; i < m_iNumComponents; i++ )
|
||||
{
|
||||
if ( 0 == Q_strcmp( pchComponentName, m_pszComponentNames[i] ) )
|
||||
{
|
||||
EnsureComponentBitSetAndEvaluate( i );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets the specified component bit # if it is not already.
|
||||
// If it does get set, evaluate if this satisfies an achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::EnsureComponentBitSetAndEvaluate( int iBitNumber )
|
||||
{
|
||||
Assert( iBitNumber < 64 ); // this is bit #, not a bit mask
|
||||
|
||||
if ( IsAchieved() )
|
||||
return;
|
||||
|
||||
// calculate which bit this component corresponds to
|
||||
uint64 iBitMask = ( (uint64) 1 ) << iBitNumber;
|
||||
|
||||
// see if we already have gotten this component
|
||||
if ( 0 == ( iBitMask & m_iComponentBits ) )
|
||||
{
|
||||
if ( !CheckAchievementsEnabled() )
|
||||
{
|
||||
Msg( "Achievements disabled, ignoring achievement component for %s\n", GetName() );
|
||||
return;
|
||||
}
|
||||
|
||||
// new component, set the bit and increment the count
|
||||
SetComponentBits( m_iComponentBits | iBitMask );
|
||||
|
||||
#if 0 // !defined( NO_STEAM ) - <vitaliy> achievements should go via TitleData
|
||||
// if this achievement's progress should be stored in Steam, set the steam stat for it
|
||||
if ( StoreProgressInSteam() && steamapicontext->SteamUserStats() )
|
||||
{
|
||||
// Set the Steam stat with the same name as the achievement. Only cached locally until we upload it.
|
||||
char pszProgressName[1024];
|
||||
Q_snprintf( pszProgressName, 1024, "%s_STAT", GetName() );
|
||||
bool bRet = steamapicontext->SteamUserStats()->SetStat( pszProgressName, m_iCount );
|
||||
if ( !bRet )
|
||||
{
|
||||
DevMsg( "ISteamUserStats::GetStat failed to set progress value in Steam for achievement %s\n", pszProgressName );
|
||||
}
|
||||
|
||||
if ( HasComponents() )
|
||||
{
|
||||
Q_snprintf( pszProgressName, 1024, "%s_COMP", GetName() );
|
||||
int32 bits = (int32) GetComponentBits();
|
||||
bool bRet = steamapicontext->SteamUserStats()->SetStat( pszProgressName, bits );
|
||||
if ( !bRet )
|
||||
{
|
||||
DevMsg( "ISteamUserStats::GetStat failed to set component value in Steam for achievement %s\n", pszProgressName );
|
||||
}
|
||||
}
|
||||
|
||||
// Upload user data to commit the change to Steam so if the client crashes, progress isn't lost.
|
||||
// Only upload if we haven't uploaded recently, to keep us from spamming Steam with uploads. If we don't
|
||||
// upload now, it will get uploaded no later than level shutdown.
|
||||
if ( ( m_pAchievementMgr->GetTimeLastUpload() == 0 ) || ( Plat_FloatTime() - m_pAchievementMgr->GetTimeLastUpload() > 60 * 15 ) )
|
||||
{
|
||||
m_pAchievementMgr->UploadUserData( m_nUserSlot );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Assert( m_iCount <= m_iGoal );
|
||||
if ( m_iCount == m_iGoal )
|
||||
{
|
||||
// all components found, award the achievement (and save state)
|
||||
AwardAchievement();
|
||||
}
|
||||
else
|
||||
{
|
||||
// save our state at the next good opportunity
|
||||
m_pAchievementMgr->SetDirty( true, m_nUserSlot );
|
||||
|
||||
if ( cc_achievement_debug.GetInt() )
|
||||
{
|
||||
Msg( "Component %d for achievement %s found\n", iBitNumber, GetName() );
|
||||
}
|
||||
|
||||
ShowProgressNotification();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( cc_achievement_debug.GetInt() )
|
||||
{
|
||||
Msg( "Component %d for achievement %s found, but already had that component\n", iBitNumber, GetName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: displays achievement progress notification in the HUD
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::ShowProgressNotification()
|
||||
{
|
||||
if ( !ShouldShowProgressNotification() )
|
||||
return;
|
||||
|
||||
IGameEvent *event = gameeventmanager->CreateEvent( "achievement_event" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetString( "achievement_name", GetName() );
|
||||
event->SetInt( "cur_val", m_iCount );
|
||||
event->SetInt( "max_val", m_iGoal );
|
||||
#ifdef GAME_DLL
|
||||
gameeventmanager->FireEvent( event );
|
||||
#else
|
||||
gameeventmanager->FireEventClientSide( event );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: clears dynamic state for this achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::PreRestoreSavedGame()
|
||||
{
|
||||
// if this achievement gets saved with the game, clear its state
|
||||
if ( m_iFlags & ACH_SAVE_WITH_GAME )
|
||||
{
|
||||
m_iCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called after the data in this achievement has been restored from saved game
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::PostRestoreSavedGame()
|
||||
{
|
||||
EvaluateIsAlreadyAchieved();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets component bits for this achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetComponentBits( uint64 iComponentBits )
|
||||
{
|
||||
Assert( m_iFlags & ACH_HAS_COMPONENTS );
|
||||
// set the bit field
|
||||
m_iComponentBits = iComponentBits;
|
||||
// count how many bits are set and save that as the count
|
||||
int iNumBitsSet = 0;
|
||||
while ( iComponentBits > 0 )
|
||||
{
|
||||
if ( iComponentBits & 1 )
|
||||
{
|
||||
iNumBitsSet++;
|
||||
}
|
||||
iComponentBits >>= 1;
|
||||
}
|
||||
m_iCount = iNumBitsSet;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the number of bits that are set in our components
|
||||
//-----------------------------------------------------------------------------
|
||||
int CBaseAchievement::GetNumComponentBitsSet( void )
|
||||
{
|
||||
int iNumBitsSet = 0;
|
||||
|
||||
uint64 iComponentBits = m_iComponentBits;
|
||||
|
||||
while ( iComponentBits > 0 )
|
||||
{
|
||||
if ( iComponentBits & 1 )
|
||||
{
|
||||
iNumBitsSet++;
|
||||
}
|
||||
iComponentBits >>= 1;
|
||||
}
|
||||
|
||||
return iNumBitsSet;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns whether we should save this achievement with a save game
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseAchievement::ShouldSaveWithGame()
|
||||
{
|
||||
// save if we should get saved with the game, have a non-zero count, and have not
|
||||
// been achieved (at which point the achievement state gets saved globally)
|
||||
return ( ( m_iFlags & ACH_SAVE_WITH_GAME ) > 0 && ( GetCount() > 0 ) && !IsAchieved() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns whether we should save this achievement to the global file
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseAchievement::ShouldSaveGlobal()
|
||||
{
|
||||
// save if we should get saved globally and have a non-zero count, or if we have been achieved, or if the player has pinned this achievement to the HUD
|
||||
return ( ( ( m_iFlags & ACH_SAVE_GLOBAL ) > 0 && ( GetCount() > 0 ) ) || IsAchieved() || ( m_iProgressShown > 0 ) || ShouldShowOnHUD() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns whether this achievement is active
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseAchievement::IsActive()
|
||||
{
|
||||
// we're not active if already achieved
|
||||
if ( IsAchieved() )
|
||||
return false;
|
||||
|
||||
// if there's a map filter and we're not on the specified map, we're not active
|
||||
if ( ( m_pMapNameFilter ) && ( 0 != Q_strcmp( m_pAchievementMgr->GetMapName(), m_pMapNameFilter ) ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns whether this achievement is available. It can be made
|
||||
// not available if it requires DLC, etc
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseAchievement::IsAvailable()
|
||||
{
|
||||
return true; // by default all achievements are available
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Serialize our data to the KeyValues node
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::GetSettings( KeyValues *pNodeOut )
|
||||
{
|
||||
pNodeOut->SetInt( "value", IsAchieved() ? 1 : 0 );
|
||||
|
||||
if ( HasComponents() )
|
||||
{
|
||||
pNodeOut->SetUint64( "data", m_iComponentBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !IsAchieved() )
|
||||
{
|
||||
pNodeOut->SetInt( "data", m_iCount );
|
||||
}
|
||||
}
|
||||
pNodeOut->SetInt( "hud", ShouldShowOnHUD() ? 1 : 0 );
|
||||
pNodeOut->SetInt( "msg", m_iProgressShown );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Unserialize our data from the KeyValues node
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::ApplySettings( KeyValues *pNodeIn )
|
||||
{
|
||||
// set the count
|
||||
if ( pNodeIn->GetInt( "value" ) > 0 )
|
||||
{
|
||||
m_iCount = m_iGoal;
|
||||
m_bAchieved = true;
|
||||
}
|
||||
else if ( !HasComponents() )
|
||||
{
|
||||
m_iCount = pNodeIn->GetInt( "data" );
|
||||
}
|
||||
|
||||
// if this achievement has components, set the component bits
|
||||
if ( HasComponents() )
|
||||
{
|
||||
int64 iComponentBits = pNodeIn->GetUint64( "data" );
|
||||
SetComponentBits( iComponentBits );
|
||||
}
|
||||
SetShowOnHUD( !!pNodeIn->GetInt( "hud" ) );
|
||||
m_iProgressShown = pNodeIn->GetInt( "msg" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Clears achievement data
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::ClearAchievementData()
|
||||
{
|
||||
SetCount( 0 );
|
||||
if ( this->HasComponents() )
|
||||
{
|
||||
this->SetComponentBits( 0 );
|
||||
}
|
||||
SetAchieved( false );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: get the localizable display string for a specific component
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CBaseAchievement::GetComponentDisplayString( int iComponent )
|
||||
{
|
||||
if ( !( m_iFlags & ACH_HAS_COMPONENTS ) || iComponent < 0 || iComponent > m_iNumComponents )
|
||||
return "";
|
||||
|
||||
return m_pszComponentDisplayNames[iComponent];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Translate the asset string into an xbox asset id.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAchievement::SetAssetAward( const char* assetAwardName )
|
||||
{
|
||||
TitleAvatarAwardsDescription_t const *pTitleAssetMap = g_pMatchFramework->GetMatchTitle()->DescribeTitleAvatarAwards();
|
||||
while ( pTitleAssetMap && pTitleAssetMap->m_szAvatarAwardName )
|
||||
{
|
||||
if ( !Q_stricmp( pTitleAssetMap->m_szAvatarAwardName, assetAwardName ) )
|
||||
{
|
||||
SetAssetAwardID( pTitleAssetMap->m_idAvatarAward );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
++pTitleAssetMap;
|
||||
}
|
||||
}
|
||||
|
||||
SetAssetAwardID( 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Wrapper for achievement manager so we can check enabled per achievement with the gamerules
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseAchievement::CheckAchievementsEnabled( void )
|
||||
{
|
||||
if ( g_pGameRules && !g_pGameRules->CheckAchievementsEnabled( GetAchievementID() ) )
|
||||
return false;
|
||||
|
||||
return m_pAchievementMgr->CheckAchievementsEnabled();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFailableAchievement::CFailableAchievement() : CBaseAchievement()
|
||||
{
|
||||
m_bFailed = false;
|
||||
m_bActivated = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns whether we should save this achievement with a save game
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFailableAchievement::ShouldSaveWithGame()
|
||||
{
|
||||
// save if we should get saved with the game, and are active or have failed
|
||||
return ( ( ( m_iFlags & ACH_SAVE_WITH_GAME ) > 0 ) && ( m_bActivated || m_bFailed ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: clears dynamic state for this achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFailableAchievement::PreRestoreSavedGame()
|
||||
{
|
||||
m_bFailed = false;
|
||||
m_bActivated = false;
|
||||
|
||||
BaseClass::PreRestoreSavedGame();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called after the data in this achievement has been restored from saved game
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFailableAchievement::PostRestoreSavedGame()
|
||||
{
|
||||
// if there is no activation event set for this achievement, it is always active, activate it now
|
||||
if ( !m_bFailed && !GetActivationEventName()[0] )
|
||||
{
|
||||
m_bActivated = true;
|
||||
}
|
||||
|
||||
if ( m_bActivated )
|
||||
{
|
||||
Activate();
|
||||
}
|
||||
|
||||
BaseClass::PostRestoreSavedGame();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when a map event occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFailableAchievement::OnMapEvent( const char *pEventName )
|
||||
{
|
||||
// if we're not activated and we got the activation event, activate
|
||||
if ( !m_bActivated && ( 0 == Q_stricmp( pEventName, GetActivationEventName() ) ) )
|
||||
{
|
||||
OnActivationEvent();
|
||||
}
|
||||
// if this is the evaluation event, see if we've failed or not
|
||||
else if ( m_bActivated && 0 == Q_stricmp( pEventName, GetEvaluationEventName() ) )
|
||||
{
|
||||
OnEvaluationEvent();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when this failable achievement is activated
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFailableAchievement::Activate()
|
||||
{
|
||||
m_bActivated = true;
|
||||
ListenForEvents();
|
||||
if ( cc_achievement_debug.GetInt() )
|
||||
{
|
||||
Msg( "Failable achievement %s now active\n", GetName() );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when this failable achievement should be evaluated
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFailableAchievement::OnEvaluationEvent()
|
||||
{
|
||||
if ( !m_bFailed )
|
||||
{
|
||||
// we haven't failed and we reached the evaluation point, we've succeeded
|
||||
IncrementCount();
|
||||
}
|
||||
|
||||
if ( cc_achievement_debug.GetInt() )
|
||||
{
|
||||
Msg( "Failable achievement %s has been evaluated (%s), now inactive\n", GetName(), m_bFailed ? "FAILED" : "AWARDED" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets this achievement to failed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFailableAchievement::SetFailed()
|
||||
{
|
||||
if ( !m_bFailed )
|
||||
{
|
||||
m_bFailed = true;
|
||||
|
||||
if ( cc_achievement_debug.GetInt() )
|
||||
{
|
||||
Msg( "Achievement failed: %s (%s)\n", GetName(), GetName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================
|
||||
|
||||
void CAchievement_AchievedCount::Init()
|
||||
{
|
||||
SetFlags( ACH_SAVE_GLOBAL );
|
||||
SetGoal( 1 );
|
||||
SetAchievementsRequired( 0, 0, 0 );
|
||||
}
|
||||
|
||||
// Count how many achievements have been earned in our range
|
||||
void CAchievement_AchievedCount::OnSteamUserStatsStored( void )
|
||||
{
|
||||
// DO NO CALL. REPLACED BY CHECKMETAACHIEVEMENTS!
|
||||
Assert( 0 );
|
||||
}
|
||||
|
||||
void CAchievement_AchievedCount::SetAchievementsRequired( int iNumRequired, int iLowRange, int iHighRange )
|
||||
{
|
||||
m_iNumRequired = iNumRequired;
|
||||
m_iLowRange = iLowRange;
|
||||
m_iHighRange = iHighRange;
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef BASEACHIEVEMENT_H
|
||||
#define BASEACHIEVEMENT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "GameEventListener.h"
|
||||
#include "../common/xlast_csgo/csgo.spa.h"
|
||||
#include "iachievementmgr.h"
|
||||
|
||||
#define AWARD_ID_NONE ""
|
||||
|
||||
class CAchievementMgr;
|
||||
class IPlayerLocal;
|
||||
|
||||
//
|
||||
// Base class for achievements
|
||||
//
|
||||
|
||||
class CBaseAchievement : public CGameEventListener, public IAchievement
|
||||
{
|
||||
DECLARE_CLASS_NOBASE( CBaseAchievement );
|
||||
public:
|
||||
CBaseAchievement();
|
||||
virtual void Init() {}
|
||||
virtual void ListenForEvents() {};
|
||||
virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event );
|
||||
|
||||
int GetAchievementID() { return m_iAchievementID; }
|
||||
void SetAchievementID( int iAchievementID ) { m_iAchievementID = iAchievementID; }
|
||||
void SetName( const char *pszName ) { m_pszName = pszName; }
|
||||
const char *GetName() { return m_pszName; }
|
||||
void SetFlags( int iFlags );
|
||||
int GetFlags() { return m_iFlags; }
|
||||
void SetGoal( int iGoal ) { m_iGoal = iGoal; }
|
||||
int GetGoal() { return m_iGoal; }
|
||||
void SetGameDirFilter( const char *pGameDir );
|
||||
bool HasComponents() { return ( m_iFlags & ACH_HAS_COMPONENTS ) > 0; }
|
||||
void SetPointValue( int iPointValue ) { m_iPointValue = iPointValue; }
|
||||
int GetPointValue() { return m_iPointValue; }
|
||||
bool ShouldHideUntilAchieved() { return m_bHideUntilAchieved; }
|
||||
|
||||
|
||||
void SetHideUntilAchieved( bool bHide ) { m_bHideUntilAchieved = bHide; }
|
||||
void SetStoreProgressInSteam( bool bStoreProgressInSteam ) { m_bStoreProgressInSteam = bStoreProgressInSteam; }
|
||||
bool StoreProgressInSteam() { return m_bStoreProgressInSteam; }
|
||||
virtual bool ShouldShowProgressNotification() { return true; }
|
||||
virtual void OnPlayerStatsUpdate( int nUserSlot ) {}
|
||||
|
||||
virtual bool ShouldSaveWithGame();
|
||||
bool ShouldSaveGlobal();
|
||||
virtual void PreRestoreSavedGame();
|
||||
virtual void PostRestoreSavedGame();
|
||||
void SetCount( int iCount ) { m_iCount = iCount; }
|
||||
int GetCount() { return m_iCount; }
|
||||
void SetProgressShown( int iProgressShown ) { m_iProgressShown = iProgressShown; }
|
||||
int GetProgressShown() { return m_iProgressShown; }
|
||||
virtual bool IsAchieved() { return m_bAchieved; }
|
||||
virtual bool IsActive();
|
||||
virtual bool IsAvailable(); // Is this achievement available? Might need DLC, etc
|
||||
virtual bool LocalPlayerCanEarn( void ) { return true; }
|
||||
void SetAchieved( bool bAchieved ) { m_bAchieved = bAchieved; }
|
||||
virtual void CheckAssetAwards( int nSlotId ) {}
|
||||
virtual bool IsMetaAchievement() { return false; }
|
||||
|
||||
virtual void OnAchieved( void ) {}
|
||||
uint32 GetUnlockTime( void ) const { return m_uUnlockTime; }
|
||||
void SetUnlockTime( uint32 unlockTime ) { m_uUnlockTime = unlockTime; }
|
||||
|
||||
uint64 GetComponentBits() { return m_iComponentBits; }
|
||||
virtual int GetNumComponents() { return m_iNumComponents; }
|
||||
virtual const char *GetComponentDisplayString( int iComponent );
|
||||
void SetComponentBits( uint64 iComponentBits );
|
||||
int GetNumComponentBitsSet( void );
|
||||
void OnComponentEvent( const char *pchComponentName );
|
||||
void EnsureComponentBitSetAndEvaluate( int iBitNumber );
|
||||
void EvaluateIsAlreadyAchieved();
|
||||
virtual void OnMapEvent( const char *pEventName );
|
||||
virtual void PrintAdditionalStatus() {} // for debugging, achievements may report additional status in achievement_status concmd
|
||||
virtual void OnSteamUserStatsStored() {}
|
||||
virtual void UpdateAchievement( int nData ) {}
|
||||
virtual bool ShouldShowOnHUD() { return m_bShowOnHUD; }
|
||||
virtual void SetShowOnHUD( bool bShow );
|
||||
virtual void SetUserSlot( int nUserSlot ) { m_nUserSlot = nUserSlot; }
|
||||
virtual void ClearAchievementData();
|
||||
virtual const char *GetIconPath() { return NULL; }
|
||||
void SetDisplayOrder( int iDisplayOrder ) { m_iDisplayOrder = iDisplayOrder; }
|
||||
int GetDisplayOrder( ) { return m_iDisplayOrder; }
|
||||
|
||||
virtual void ReadProgress( IPlayerLocal *pPlayer ) {}
|
||||
virtual bool WriteProgress( IPlayerLocal *pPlayer ) { return false; }
|
||||
|
||||
virtual void GetSettings( KeyValues* pNodeOut ); // serialize
|
||||
virtual void ApplySettings( /* const */ KeyValues* pNodeIn ); // unserialize
|
||||
|
||||
virtual void Think( void ) { return; }
|
||||
|
||||
// XBox Asset Awards
|
||||
void SetAssetAward( const char* assetAwardName );
|
||||
void SetAssetAwardID( int iAssetAwardID ) { m_iAssetAwardID = iAssetAwardID; }
|
||||
int GetAssetAwardID( void ) { return m_iAssetAwardID; }
|
||||
bool IsAssetAward( void ) { return m_iAssetAwardID > 0; }
|
||||
|
||||
virtual bool CheckAchievementsEnabled( void );
|
||||
|
||||
protected:
|
||||
virtual void FireGameEvent( IGameEvent *event );
|
||||
virtual void FireGameEvent_Internal( IGameEvent *event ) {};
|
||||
void SetVictimFilter( const char *pClassName );
|
||||
void SetAttackerFilter( const char *pClassName );
|
||||
void SetInflictorFilter( const char *pClassName );
|
||||
void SetInflictorEntityNameFilter( const char *pEntityName );
|
||||
void SetMapNameFilter( const char *pMapName );
|
||||
void SetComponentPrefix( const char *pPrefix );
|
||||
void IncrementCount( int iOptIncrement = 0 );
|
||||
void EvaluateNewAchievement();
|
||||
void AwardAchievement();
|
||||
void ShowProgressNotification();
|
||||
void HandleProgressUpdate();
|
||||
virtual void CalcProgressMsgIncrement();
|
||||
void SetNextThink( float flThinkTime );
|
||||
void ClearThink( void );
|
||||
|
||||
const char *m_pszName; // name of this achievement
|
||||
int m_iAchievementID; // ID of this achievement
|
||||
int m_iFlags; // ACH_* flags for this achievement
|
||||
int m_iGoal; // goal # of steps to award this achievement
|
||||
int m_iProgressMsgIncrement; // after how many steps show we show a progress notification
|
||||
int m_iProgressMsgMinimum; // the minimum progress needed before showing progress notification
|
||||
int m_iPointValue; // # of points this achievement is worth (currently only used for XBox Live)
|
||||
bool m_bHideUntilAchieved; // should this achievement be hidden until achieved?
|
||||
bool m_bStoreProgressInSteam; // should incremental progress be stored in Steam. A counter with same name as achievement must be set up in Steam.
|
||||
const char *m_pInflictorClassNameFilter; // if non-NULL, inflictor class name to filter with
|
||||
const char *m_pInflictorEntityNameFilter; // if non-NULL, inflictor entity name to filter with
|
||||
const char *m_pVictimClassNameFilter; // if non-NULL, victim class name to filter with
|
||||
const char *m_pAttackerClassNameFilter; // if non-NULL, attacker class name to filter with
|
||||
const char *m_pMapNameFilter; // if non-NULL, map name to filter with
|
||||
const char *m_pGameDirFilter; // if non-NULL, game dir name to filter with
|
||||
|
||||
const char **m_pszComponentNames;
|
||||
const char **m_pszComponentDisplayNames; // localizable strings for each component
|
||||
int m_iNumComponents;
|
||||
const char *m_pszComponentPrefix;
|
||||
int m_iComponentPrefixLen;
|
||||
bool m_bAchieved; // is this achievement achieved
|
||||
uint32 m_uUnlockTime; // time_t that this achievement was unlocked (0 if before Steamworks unlock time support)
|
||||
int m_iCount; // # of steps satisfied toward this achievement (only valid if not achieved)
|
||||
int m_iProgressShown; // # of progress msgs we've shown
|
||||
uint64 m_iComponentBits; // bitfield of components achieved
|
||||
CAchievementMgr *m_pAchievementMgr; // our achievement manager
|
||||
int m_nUserSlot;
|
||||
int m_iDisplayOrder; // Order in which the achievement is displayed in the UI
|
||||
bool m_bShowOnHUD; // if set, the player wants this achievement pinned to the HUD
|
||||
|
||||
int m_iAssetAwardID; // ID of the avatar award asset associated with this achievement. Alliteration!
|
||||
|
||||
friend class CAchievementMgr;
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
};
|
||||
|
||||
class CFailableAchievement : public CBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CFailableAchievement, CBaseAchievement );
|
||||
public:
|
||||
CFailableAchievement();
|
||||
void SetFailed();
|
||||
|
||||
virtual bool ShouldSaveWithGame();
|
||||
virtual void PreRestoreSavedGame();
|
||||
virtual void PostRestoreSavedGame();
|
||||
virtual bool IsAchieved() { return !m_bFailed && BaseClass::IsAchieved(); }
|
||||
virtual bool IsActive() { return m_bActivated && !m_bFailed && BaseClass::IsActive(); }
|
||||
bool IsFailed() { return m_bFailed; }
|
||||
|
||||
virtual void OnMapEvent( const char *pEventName );
|
||||
virtual void OnActivationEvent() { Activate(); }
|
||||
virtual void OnEvaluationEvent();
|
||||
virtual const char *GetActivationEventName() =0;
|
||||
virtual const char *GetEvaluationEventName() =0;
|
||||
|
||||
protected:
|
||||
void Activate();
|
||||
|
||||
bool m_bActivated; // are we activated? (If there is a map event that turns us on, has that happened)
|
||||
bool m_bFailed; // has this achievement failed
|
||||
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
};
|
||||
|
||||
class CMapAchievement : public CBaseAchievement
|
||||
{
|
||||
virtual void Init()
|
||||
{
|
||||
SetFlags( ACH_LISTEN_MAP_EVENTS | ACH_SAVE_GLOBAL );
|
||||
SetGoal( 1 );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
class CAchievement_AchievedCount : public CBaseAchievement
|
||||
{
|
||||
public:
|
||||
void Init();
|
||||
virtual void OnSteamUserStatsStored( void );
|
||||
virtual bool IsMetaAchievement() { return true; }
|
||||
|
||||
int GetLowRange() { return m_iLowRange; }
|
||||
int GetHighRange() { return m_iHighRange; }
|
||||
int GetNumRequired() { return m_iNumRequired; }
|
||||
|
||||
protected:
|
||||
void SetAchievementsRequired( int iNumRequired, int iLowRange, int iHighRange );
|
||||
|
||||
private:
|
||||
int m_iNumRequired;
|
||||
int m_iLowRange;
|
||||
int m_iHighRange;
|
||||
};
|
||||
|
||||
//
|
||||
// Helper class for achievement creation
|
||||
//
|
||||
|
||||
typedef CBaseAchievement* (*achievementCreateFunc) (void);
|
||||
class CBaseAchievementHelper
|
||||
{
|
||||
public:
|
||||
CBaseAchievementHelper( achievementCreateFunc createFunc )
|
||||
{
|
||||
m_pfnCreate = createFunc;
|
||||
m_pNext = s_pFirst;
|
||||
s_pFirst = this;
|
||||
}
|
||||
achievementCreateFunc m_pfnCreate;
|
||||
CBaseAchievementHelper *m_pNext;
|
||||
static CBaseAchievementHelper *s_pFirst;
|
||||
};
|
||||
|
||||
#define DECLARE_ACHIEVEMENT_( className, achievementID, achievementName, gameDirFilter, iPointValue, bHidden ) \
|
||||
static CBaseAchievement *Create_##className( void ) \
|
||||
{ \
|
||||
CBaseAchievement *pAchievement = new className( ); \
|
||||
pAchievement->SetAchievementID( achievementID ); \
|
||||
pAchievement->SetName( achievementName ); \
|
||||
pAchievement->SetPointValue( iPointValue ); \
|
||||
pAchievement->SetHideUntilAchieved( bHidden ); \
|
||||
if ( gameDirFilter ) pAchievement->SetGameDirFilter( gameDirFilter ); \
|
||||
return pAchievement; \
|
||||
}; \
|
||||
static CBaseAchievementHelper g_##className##_Helper( Create_##className );
|
||||
|
||||
#define DECLARE_ACHIEVEMENT( className, achievementID, achievementName, iPointValue ) \
|
||||
DECLARE_ACHIEVEMENT_( className, achievementID, achievementName, NULL, iPointValue, false )
|
||||
|
||||
#define DECLARE_MAP_EVENT_ACHIEVEMENT_( achievementID, achievementName, gameDirFilter, iPointValue, bHidden ) \
|
||||
class CAchievement##achievementID : public CMapAchievement {}; \
|
||||
DECLARE_ACHIEVEMENT_( CAchievement##achievementID, achievementID, achievementName, gameDirFilter, iPointValue, bHidden ) \
|
||||
|
||||
#define DECLARE_MAP_EVENT_ACHIEVEMENT( achievementID, achievementName, iPointValue ) \
|
||||
DECLARE_MAP_EVENT_ACHIEVEMENT_( achievementID, achievementName, NULL, iPointValue, false )
|
||||
|
||||
#define DECLARE_MAP_EVENT_ACHIEVEMENT_HIDDEN( achievementID, achievementName, iPointValue ) \
|
||||
DECLARE_MAP_EVENT_ACHIEVEMENT_( achievementID, achievementName, NULL, iPointValue, true )
|
||||
|
||||
#endif // BASEACHIEVEMENT_H
|
||||
@@ -0,0 +1,792 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "ammodef.h"
|
||||
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Switches to the best weapon that is also better than the given weapon.
|
||||
// Input : pCurrent - The current weapon used by the player.
|
||||
// Output : Returns true if the weapon was switched, false if there was no better
|
||||
// weapon to switch to.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::SwitchToNextBestWeapon(CBaseCombatWeapon *pCurrent)
|
||||
{
|
||||
CBaseCombatWeapon *pNewWeapon = g_pGameRules->GetNextBestWeapon(this, pCurrent);
|
||||
|
||||
if ( ( pNewWeapon != NULL ) && ( pNewWeapon != pCurrent ) )
|
||||
{
|
||||
return Weapon_Switch( pNewWeapon );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Switches to the given weapon (providing it has ammo)
|
||||
// Input :
|
||||
// Output : true is switch succeeded
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex /*=0*/ )
|
||||
{
|
||||
if ( pWeapon == NULL )
|
||||
return false;
|
||||
|
||||
// Already have it out?
|
||||
if ( m_hActiveWeapon.Get() == pWeapon )
|
||||
{
|
||||
if ( !m_hActiveWeapon->IsWeaponVisible() || m_hActiveWeapon->IsHolstered() )
|
||||
return m_hActiveWeapon->Deploy( );
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Weapon_CanSwitchTo(pWeapon))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_hActiveWeapon )
|
||||
{
|
||||
if ( !m_hActiveWeapon->IsAlwaysActive() )
|
||||
{
|
||||
if ( !m_hActiveWeapon->Holster( pWeapon ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_hActiveWeapon = pWeapon;
|
||||
return pWeapon->Deploy( );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns whether or not we can switch to the given weapon.
|
||||
// Input : pWeapon -
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
if (IsPlayer())
|
||||
{
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)this;
|
||||
#if !defined( CLIENT_DLL )
|
||||
IServerVehicle *pVehicle = pPlayer->GetVehicle();
|
||||
#else
|
||||
IClientVehicle *pVehicle = pPlayer->GetVehicle();
|
||||
#endif
|
||||
if (pVehicle && !pPlayer->UsingStandardWeaponsInVehicle())
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !pWeapon->HasAnyAmmo() && !GetAmmoCount( pWeapon->m_iPrimaryAmmoType ) )
|
||||
return false;
|
||||
|
||||
if ( !pWeapon->CanDeploy() )
|
||||
return false;
|
||||
|
||||
if ( m_hActiveWeapon )
|
||||
{
|
||||
if ( !m_hActiveWeapon->CanHolster() )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CBaseCombatWeapon
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatWeapon *CBaseCombatCharacter::GetActiveWeapon() const
|
||||
{
|
||||
return m_hActiveWeapon;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : i -
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatWeapon *CBaseCombatCharacter::GetWeapon( int i ) const
|
||||
{
|
||||
Assert( (i >= 0) && (i < MAX_WEAPONS) );
|
||||
return m_hMyWeapons[i].Get();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : iCount -
|
||||
// iAmmoIndex -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::RemoveAmmo( int iCount, int iAmmoIndex )
|
||||
{
|
||||
if (iCount <= 0)
|
||||
return;
|
||||
|
||||
if ( iAmmoIndex < 0 )
|
||||
return;
|
||||
|
||||
// Infinite ammo?
|
||||
if ( GetAmmoDef()->CanCarryInfiniteAmmo( iAmmoIndex ) )
|
||||
return;
|
||||
|
||||
extern ConVar sv_infinite_ammo;
|
||||
if ( sv_infinite_ammo.GetInt() == 2 ) // infinite total ammo but magazine reloads are still required.
|
||||
return;
|
||||
|
||||
// Ammo pickup sound
|
||||
m_iAmmo.Set( iAmmoIndex, MAX( m_iAmmo[iAmmoIndex] - iCount, 0 ) );
|
||||
}
|
||||
|
||||
void CBaseCombatCharacter::RemoveAmmo( int iCount, const char *szName )
|
||||
{
|
||||
RemoveAmmo( iCount, GetAmmoDef()->Index(szName) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::RemoveAllAmmo( )
|
||||
{
|
||||
for ( int i = 0; i < MAX_AMMO_SLOTS; i++ )
|
||||
{
|
||||
m_iAmmo.Set( i, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FIXME: This is a sort of hack back-door only used by physgun!
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::SetAmmoCount( int iCount, int iAmmoIndex )
|
||||
{
|
||||
// NOTE: No sound, no max check! Seems pretty bogus to me!
|
||||
m_iAmmo.Set( iAmmoIndex, iCount );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the amount of ammunition of a particular type owned
|
||||
// owned by the character
|
||||
// Input : Ammo Index
|
||||
// Output : The amount of ammo
|
||||
//-----------------------------------------------------------------------------
|
||||
int CBaseCombatCharacter::GetAmmoCount( int iAmmoIndex ) const
|
||||
{
|
||||
|
||||
// DEPRECATED - Ido says please use GetReserveAmmoCount
|
||||
|
||||
if ( iAmmoIndex == -1 )
|
||||
return 0;
|
||||
|
||||
// Infinite ammo?
|
||||
if ( GetAmmoDef()->CanCarryInfiniteAmmo( iAmmoIndex ) )
|
||||
return 999;
|
||||
|
||||
return m_iAmmo[ iAmmoIndex ];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the amount of ammunition of the specified type the character's carrying
|
||||
//-----------------------------------------------------------------------------
|
||||
int CBaseCombatCharacter::GetAmmoCount( char *szName ) const
|
||||
{
|
||||
return GetAmmoCount( GetAmmoDef()->Index(szName) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns weapon if already owns a weapon of this class
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatWeapon* CBaseCombatCharacter::Weapon_OwnsThisType( const char *pszWeapon, int iSubType ) const
|
||||
{
|
||||
for ( int i = 0; i < MAX_WEAPONS; i++ )
|
||||
{
|
||||
if ( m_hMyWeapons[i].Get() && FClassnameIs( m_hMyWeapons[i], pszWeapon ) )
|
||||
{
|
||||
// Make sure it matches the subtype
|
||||
if ( m_hMyWeapons[i]->GetSubType() == iSubType )
|
||||
{
|
||||
return m_hMyWeapons[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the weapon (if any) in the requested slot
|
||||
// Input : slot - which slot to poll
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatWeapon *CBaseCombatCharacter::Weapon_GetSlot( int slot ) const
|
||||
{
|
||||
int targetSlot = slot;
|
||||
|
||||
// Check for that slot being occupied already
|
||||
for ( int i=0; i < MAX_WEAPONS; i++ )
|
||||
{
|
||||
if ( m_hMyWeapons[i].Get() != NULL )
|
||||
{
|
||||
// If the slots match, it's already occupied
|
||||
if ( m_hMyWeapons[i]->GetSlot() == targetSlot )
|
||||
return m_hMyWeapons[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the weapon (if any) in the requested loadout position
|
||||
// Input : position - which slot to poll
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatWeapon *CBaseCombatCharacter::Weapon_GetPosition( int position ) const
|
||||
{
|
||||
// Check for that slot being occupied already
|
||||
for ( int i = 0; i < MAX_WEAPONS; i++ )
|
||||
{
|
||||
if ( m_hMyWeapons[ i ].Get() != NULL )
|
||||
{
|
||||
CEconItemView * pItem = m_hMyWeapons[ i ]->GetEconItemView() ;
|
||||
if ( !pItem )
|
||||
continue;
|
||||
|
||||
loadout_positions_t unItemPos = ( loadout_positions_t )pItem->GetItemDefinition()->GetLoadoutSlot( GetTeamNumber() );
|
||||
|
||||
// If the slots match, it's already occupied
|
||||
if ( unItemPos == position )
|
||||
return m_hMyWeapons[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int CBaseCombatCharacter::BloodColor()
|
||||
{
|
||||
return m_bloodColor;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Blood color (see BLOOD_COLOR_* macros in baseentity.h)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::SetBloodColor( int nBloodColor )
|
||||
{
|
||||
m_bloodColor = nBloodColor;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
The main visibility check. Checks all the entity specific reasons that could
|
||||
make IsVisible fail. Then checks points in space to get environmental reasons.
|
||||
This is LOS, plus invisibility and fog and smoke and such.
|
||||
*/
|
||||
|
||||
enum VisCacheResult_t
|
||||
{
|
||||
VISCACHE_UNKNOWN = 0,
|
||||
VISCACHE_IS_VISIBLE,
|
||||
VISCACHE_IS_NOT_VISIBLE,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VIS_CACHE_INVALID = 0x80000000
|
||||
};
|
||||
|
||||
#define VIS_CACHE_ENTRY_LIFE .090f
|
||||
|
||||
class CCombatCharVisCache : public CAutoGameSystemPerFrame
|
||||
{
|
||||
public:
|
||||
virtual void FrameUpdatePreEntityThink();
|
||||
virtual void LevelShutdownPreEntity();
|
||||
|
||||
int LookupVisibility( const CBaseCombatCharacter *pChar1, CBaseCombatCharacter *pChar2 );
|
||||
VisCacheResult_t HasVisibility( int iCache ) const;
|
||||
void RegisterVisibility( int iCache, bool bChar1SeesChar2, bool bChar2SeesChar1 );
|
||||
|
||||
private:
|
||||
struct VisCacheEntry_t
|
||||
{
|
||||
CHandle< CBaseCombatCharacter > m_hEntity1;
|
||||
CHandle< CBaseCombatCharacter > m_hEntity2;
|
||||
float m_flTime;
|
||||
bool m_bEntity1CanSeeEntity2;
|
||||
bool m_bEntity2CanSeeEntity1;
|
||||
};
|
||||
|
||||
class CVisCacheEntryLess
|
||||
{
|
||||
public:
|
||||
CVisCacheEntryLess( int ) {}
|
||||
bool operator!() const { return false; }
|
||||
bool operator()( const VisCacheEntry_t &lhs, const VisCacheEntry_t &rhs ) const
|
||||
{
|
||||
return ( memcmp( &lhs, &rhs, offsetof( VisCacheEntry_t, m_flTime ) ) < 0 );
|
||||
}
|
||||
};
|
||||
|
||||
CUtlRBTree< VisCacheEntry_t, unsigned short, CVisCacheEntryLess > m_VisCache;
|
||||
|
||||
mutable int m_nTestCount;
|
||||
mutable int m_nHitCount;
|
||||
};
|
||||
|
||||
void CCombatCharVisCache::FrameUpdatePreEntityThink()
|
||||
{
|
||||
// Msg( "test: %d/%d\n", m_nHitCount, m_nTestCount );
|
||||
|
||||
// Lazy retirement of vis cache
|
||||
// NOTE: 256 was chosen heuristically based on a playthrough where 200
|
||||
// was the max # in the viscache where nothing could be retired.
|
||||
if ( m_VisCache.Count() < 256 )
|
||||
return;
|
||||
|
||||
int nMaxIndex = m_VisCache.MaxElement() - 1;
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
int n = RandomInt( 0, nMaxIndex );
|
||||
if ( !m_VisCache.IsValidIndex( n ) )
|
||||
continue;
|
||||
|
||||
const VisCacheEntry_t &entry = m_VisCache[n];
|
||||
if ( !entry.m_hEntity1.IsValid() || !entry.m_hEntity2.IsValid() || ( gpGlobals->curtime - entry.m_flTime > 10.0f ) )
|
||||
{
|
||||
m_VisCache.RemoveAt( n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCombatCharVisCache::LevelShutdownPreEntity()
|
||||
{
|
||||
m_VisCache.Purge();
|
||||
}
|
||||
|
||||
int CCombatCharVisCache::LookupVisibility( const CBaseCombatCharacter *pChar1, CBaseCombatCharacter *pChar2 )
|
||||
{
|
||||
VisCacheEntry_t cacheEntry;
|
||||
if ( pChar1 < pChar2 )
|
||||
{
|
||||
cacheEntry.m_hEntity1 = pChar1;
|
||||
cacheEntry.m_hEntity2 = pChar2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheEntry.m_hEntity1 = pChar2;
|
||||
cacheEntry.m_hEntity2 = pChar1;
|
||||
}
|
||||
|
||||
int iCache = m_VisCache.Find( cacheEntry );
|
||||
if ( iCache == m_VisCache.InvalidIndex() )
|
||||
{
|
||||
if ( m_VisCache.Count() == m_VisCache.InvalidIndex() )
|
||||
return VIS_CACHE_INVALID;
|
||||
|
||||
iCache = m_VisCache.Insert( cacheEntry );
|
||||
m_VisCache[iCache].m_flTime = gpGlobals->curtime - 2.0f * VIS_CACHE_ENTRY_LIFE;
|
||||
}
|
||||
|
||||
return ( pChar1 < pChar2 ) ? iCache : - iCache - 1;
|
||||
}
|
||||
|
||||
VisCacheResult_t CCombatCharVisCache::HasVisibility( int iCache ) const
|
||||
{
|
||||
if ( iCache == VIS_CACHE_INVALID )
|
||||
return VISCACHE_UNKNOWN;
|
||||
|
||||
m_nTestCount++;
|
||||
|
||||
bool bReverse = ( iCache < 0 );
|
||||
if ( bReverse )
|
||||
{
|
||||
iCache = - iCache - 1;
|
||||
}
|
||||
|
||||
const VisCacheEntry_t &entry = m_VisCache[iCache];
|
||||
if ( gpGlobals->curtime - entry.m_flTime > VIS_CACHE_ENTRY_LIFE )
|
||||
return VISCACHE_UNKNOWN;
|
||||
|
||||
m_nHitCount++;
|
||||
|
||||
bool bIsVisible = !bReverse ? entry.m_bEntity1CanSeeEntity2 : entry.m_bEntity2CanSeeEntity1;
|
||||
return bIsVisible ? VISCACHE_IS_VISIBLE : VISCACHE_IS_NOT_VISIBLE;
|
||||
}
|
||||
|
||||
void CCombatCharVisCache::RegisterVisibility( int iCache, bool bEntity1CanSeeEntity2, bool bEntity2CanSeeEntity1 )
|
||||
{
|
||||
if ( iCache == VIS_CACHE_INVALID )
|
||||
return;
|
||||
|
||||
bool bReverse = ( iCache < 0 );
|
||||
if ( bReverse )
|
||||
{
|
||||
iCache = - iCache - 1;
|
||||
}
|
||||
|
||||
VisCacheEntry_t &entry = m_VisCache[iCache];
|
||||
entry.m_flTime = gpGlobals->curtime;
|
||||
if ( !bReverse )
|
||||
{
|
||||
entry.m_bEntity1CanSeeEntity2 = bEntity1CanSeeEntity2;
|
||||
entry.m_bEntity2CanSeeEntity1 = bEntity2CanSeeEntity1;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.m_bEntity1CanSeeEntity2 = bEntity2CanSeeEntity1;
|
||||
entry.m_bEntity2CanSeeEntity1 = bEntity1CanSeeEntity2;
|
||||
}
|
||||
}
|
||||
|
||||
static CCombatCharVisCache s_CombatCharVisCache;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::IsAbleToSee( const CBaseEntity *pEntity, FieldOfViewCheckType checkFOV )
|
||||
{
|
||||
CBaseCombatCharacter *pBCC = const_cast<CBaseEntity *>( pEntity )->MyCombatCharacterPointer();
|
||||
if ( pBCC )
|
||||
return IsAbleToSee( pBCC, checkFOV );
|
||||
|
||||
// Test this every time; it's cheap.
|
||||
Vector vecEyePosition = EyePosition();
|
||||
Vector vecTargetPosition = pEntity->WorldSpaceCenter();
|
||||
|
||||
#ifdef GAME_DLL
|
||||
Vector vecEyeToTarget;
|
||||
VectorSubtract( vecTargetPosition, vecEyePosition, vecEyeToTarget );
|
||||
float flDistToOther = VectorNormalize( vecEyeToTarget );
|
||||
|
||||
// We can't see because they are too far in the fog
|
||||
if ( IsHiddenByFog( flDistToOther ) )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if ( !ComputeLOS( vecEyePosition, vecTargetPosition ) )
|
||||
return false;
|
||||
|
||||
#if defined(GAME_DLL) && defined(TERROR)
|
||||
if ( flDistToOther > NavObscureRange.GetFloat() )
|
||||
{
|
||||
const float flMaxDistance = 100.0f;
|
||||
TerrorNavArea *pTargetArea = static_cast< TerrorNavArea* >( TheNavMesh->GetNearestNavArea( vecTargetPosition, false, flMaxDistance ) );
|
||||
if ( !pTargetArea || pTargetArea->HasSpawnAttributes( TerrorNavArea::SPAWN_OBSCURED ) )
|
||||
return false;
|
||||
|
||||
if ( ComputeTargetIsInDarkness( vecEyePosition, pTargetArea, vecTargetPosition ) )
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ( checkFOV != USE_FOV || IsInFieldOfView( vecTargetPosition ) );
|
||||
}
|
||||
|
||||
static void ComputeSeeTestPosition( Vector *pEyePosition, CBaseCombatCharacter *pBCC )
|
||||
{
|
||||
#if defined(GAME_DLL) && defined(TERROR)
|
||||
if ( pBCC->IsPlayer() )
|
||||
{
|
||||
CTerrorPlayer *pPlayer = ToTerrorPlayer( pBCC );
|
||||
*pEyePosition = !pPlayer->IsDead() ? pPlayer->EyePosition() : pPlayer->GetDeathPosition();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
*pEyePosition = pBCC->EyePosition();
|
||||
}
|
||||
}
|
||||
|
||||
bool CBaseCombatCharacter::IsAbleToSee( CBaseCombatCharacter *pBCC, FieldOfViewCheckType checkFOV )
|
||||
{
|
||||
Vector vecEyePosition, vecOtherEyePosition;
|
||||
ComputeSeeTestPosition( &vecEyePosition, this );
|
||||
ComputeSeeTestPosition( &vecOtherEyePosition, pBCC );
|
||||
|
||||
#ifdef GAME_DLL
|
||||
Vector vecEyeToTarget;
|
||||
VectorSubtract( vecOtherEyePosition, vecEyePosition, vecEyeToTarget );
|
||||
float flDistToOther = VectorNormalize( vecEyeToTarget );
|
||||
|
||||
// Test this every time; it's cheap.
|
||||
// We can't see because they are too far in the fog
|
||||
if ( IsHiddenByFog( flDistToOther ) )
|
||||
return false;
|
||||
|
||||
#ifdef TERROR
|
||||
// Check this every time also, it's cheap; check to see if the enemy is in an obscured area.
|
||||
bool bIsInNavObscureRange = ( flDistToOther > NavObscureRange.GetFloat() );
|
||||
if ( bIsInNavObscureRange )
|
||||
{
|
||||
TerrorNavArea *pOtherNavArea = static_cast< TerrorNavArea* >( pBCC->GetLastKnownArea() );
|
||||
if ( !pOtherNavArea || pOtherNavArea->HasSpawnAttributes( TerrorNavArea::SPAWN_OBSCURED ) )
|
||||
return false;
|
||||
}
|
||||
#endif // TERROR
|
||||
#endif
|
||||
|
||||
// Check if we have a cached-off visibility
|
||||
int iCache = s_CombatCharVisCache.LookupVisibility( this, pBCC );
|
||||
VisCacheResult_t nResult = s_CombatCharVisCache.HasVisibility( iCache );
|
||||
|
||||
// Compute symmetric visibility
|
||||
if ( nResult == VISCACHE_UNKNOWN )
|
||||
{
|
||||
bool bThisCanSeeOther = false, bOtherCanSeeThis = false;
|
||||
if ( ComputeLOS( vecEyePosition, vecOtherEyePosition ) )
|
||||
{
|
||||
#if defined(GAME_DLL) && defined(TERROR)
|
||||
if ( !bIsInNavObscureRange )
|
||||
{
|
||||
bThisCanSeeOther = true, bOtherCanSeeThis = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bThisCanSeeOther = !ComputeTargetIsInDarkness( vecEyePosition, pBCC->GetLastKnownArea(), vecOtherEyePosition );
|
||||
bOtherCanSeeThis = !ComputeTargetIsInDarkness( vecOtherEyePosition, GetLastKnownArea(), vecEyePosition );
|
||||
}
|
||||
#else
|
||||
bThisCanSeeOther = true, bOtherCanSeeThis = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
s_CombatCharVisCache.RegisterVisibility( iCache, bThisCanSeeOther, bOtherCanSeeThis );
|
||||
nResult = bThisCanSeeOther ? VISCACHE_IS_VISIBLE : VISCACHE_IS_NOT_VISIBLE;
|
||||
}
|
||||
|
||||
if ( nResult == VISCACHE_IS_VISIBLE )
|
||||
return ( checkFOV != USE_FOV || IsInFieldOfView( pBCC ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class CTraceFilterNoCombatCharacters : public CTraceFilterSimple
|
||||
{
|
||||
public:
|
||||
CTraceFilterNoCombatCharacters( const IHandleEntity *passentity = NULL, int collisionGroup = COLLISION_GROUP_NONE )
|
||||
: CTraceFilterSimple( passentity, collisionGroup )
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
|
||||
{
|
||||
if ( CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask ) )
|
||||
{
|
||||
CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
|
||||
if ( !pEntity )
|
||||
return NULL;
|
||||
|
||||
if ( pEntity->MyCombatCharacterPointer() || pEntity->MyCombatWeaponPointer() )
|
||||
return false;
|
||||
|
||||
// Honor BlockLOS - this lets us see through partially-broken doors, etc
|
||||
if ( !pEntity->BlocksLOS() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool CBaseCombatCharacter::ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const
|
||||
{
|
||||
// We simply can't see because the world is in the way.
|
||||
trace_t result;
|
||||
CTraceFilterNoCombatCharacters traceFilter( NULL, COLLISION_GROUP_NONE );
|
||||
UTIL_TraceLine( vecEyePosition, vecTarget, MASK_OPAQUE | CONTENTS_IGNORE_NODRAW_OPAQUE | CONTENTS_MONSTER, &traceFilter, &result );
|
||||
return ( result.fraction == 1.0f );
|
||||
}
|
||||
|
||||
#if defined(GAME_DLL) && defined(TERROR)
|
||||
bool CBaseCombatCharacter::ComputeTargetIsInDarkness( const Vector &vecEyePosition, CNavArea *pTargetNavArea, const Vector &vecTargetPos ) const
|
||||
{
|
||||
if ( GetTeamNumber() != TEAM_SURVIVOR )
|
||||
return false;
|
||||
|
||||
// Check light info
|
||||
const float flMinLightIntensity = 0.1f;
|
||||
|
||||
if ( !pTargetNavArea || ( pTargetNavArea->GetLightIntensity() >= flMinLightIntensity ) )
|
||||
return false;
|
||||
|
||||
CTraceFilterNoNPCsOrPlayer lightingFilter( this, COLLISION_GROUP_NONE );
|
||||
|
||||
Vector vecSightDirection;
|
||||
VectorSubtract( vecTargetPos, vecEyePosition, vecSightDirection );
|
||||
VectorNormalize( vecSightDirection );
|
||||
|
||||
trace_t result;
|
||||
UTIL_TraceLine( vecTargetPos, vecTargetPos + vecSightDirection * 32768.0f, MASK_L4D_VISION, &lightingFilter, &result );
|
||||
if ( ( result.fraction < 1.0f ) && ( ( result.surface.flags & SURF_SKY ) == 0 ) )
|
||||
{
|
||||
const float flMaxDistance = 100.0f;
|
||||
TerrorNavArea *pFarArea = (TerrorNavArea *)TheNavMesh->GetNearestNavArea( result.endpos, false, flMaxDistance );
|
||||
|
||||
// Target is in darkness, the wall behind him is too, and we are too far away
|
||||
if ( pFarArea && pFarArea->GetLightIntensity() < flMinLightIntensity )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Return true if our view direction is pointing at the given target,
|
||||
within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
|
||||
*/
|
||||
bool CBaseCombatCharacter::IsLookingTowards( const CBaseEntity *target, float cosTolerance ) const
|
||||
{
|
||||
return IsLookingTowards( target->WorldSpaceCenter(), cosTolerance ) || IsLookingTowards( target->EyePosition(), cosTolerance ) || IsLookingTowards( target->GetAbsOrigin(), cosTolerance );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Return true if our view direction is pointing at the given target,
|
||||
within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
|
||||
*/
|
||||
bool CBaseCombatCharacter::IsLookingTowards( const Vector &target, float cosTolerance ) const
|
||||
{
|
||||
Vector toTarget = target - EyePosition();
|
||||
toTarget.NormalizeInPlace();
|
||||
|
||||
Vector forward;
|
||||
AngleVectors( EyeAngles(), &forward );
|
||||
|
||||
return ( DotProduct( forward, toTarget ) >= cosTolerance );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Returns true if we are looking towards something within a tolerence determined
|
||||
by our field of view
|
||||
*/
|
||||
bool CBaseCombatCharacter::IsInFieldOfView( CBaseEntity *entity ) const
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( const_cast< CBaseCombatCharacter* >( this ) );
|
||||
float flTolerance = pPlayer ? cos( DEG2RAD( pPlayer->GetFOV() * 0.5f ) ) : BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE;
|
||||
|
||||
Vector vecForward;
|
||||
Vector vecEyePosition = EyePosition();
|
||||
AngleVectors( EyeAngles(), &vecForward );
|
||||
|
||||
// FIXME: Use a faster check than this!
|
||||
|
||||
// Check 3 spots, or else when standing right next to someone looking at their eyes,
|
||||
// the angle will be too great to see their center.
|
||||
Vector vecToTarget = entity->GetAbsOrigin() - vecEyePosition;
|
||||
vecToTarget.NormalizeInPlace();
|
||||
if ( DotProduct( vecForward, vecToTarget ) >= flTolerance )
|
||||
return true;
|
||||
|
||||
vecToTarget = entity->WorldSpaceCenter() - vecEyePosition;
|
||||
vecToTarget.NormalizeInPlace();
|
||||
if ( DotProduct( vecForward, vecToTarget ) >= flTolerance )
|
||||
return true;
|
||||
|
||||
vecToTarget = entity->EyePosition() - vecEyePosition;
|
||||
vecToTarget.NormalizeInPlace();
|
||||
return ( DotProduct( vecForward, vecToTarget ) >= flTolerance );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Returns true if we are looking towards something within a tolerence determined
|
||||
by our field of view
|
||||
*/
|
||||
bool CBaseCombatCharacter::IsInFieldOfView( const Vector &pos ) const
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( const_cast< CBaseCombatCharacter* >( this ) );
|
||||
|
||||
if ( pPlayer )
|
||||
return IsLookingTowards( pos, cos( DEG2RAD( pPlayer->GetFOV() * 0.5f ) ) );
|
||||
|
||||
return IsLookingTowards( pos );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Strictly checks Line of Sight only.
|
||||
*/
|
||||
|
||||
bool CBaseCombatCharacter::IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType ) const
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if ( entity->MyCombatCharacterPointer() )
|
||||
return IsLineOfSightClear( entity->EyePosition(), checkType, entity );
|
||||
return IsLineOfSightClear( entity->WorldSpaceCenter(), checkType, entity );
|
||||
#else
|
||||
// FIXME: Should we do the same check here as the client does?
|
||||
return IsLineOfSightClear( entity->WorldSpaceCenter(), checkType, entity ) || IsLineOfSightClear( entity->EyePosition(), checkType, entity ) || IsLineOfSightClear( entity->GetAbsOrigin(), checkType, entity );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
Strictly checks Line of Sight only.
|
||||
*/
|
||||
static bool TraceFilterNoCombatCharacters( IHandleEntity *pServerEntity, int contentsMask )
|
||||
{
|
||||
// Honor BlockLOS also to allow seeing through partially-broken doors
|
||||
CBaseEntity *entity = EntityFromEntityHandle( pServerEntity );
|
||||
return ( entity->MyCombatCharacterPointer() == NULL && !entity->MyCombatWeaponPointer() && entity->BlocksLOS() );
|
||||
}
|
||||
|
||||
bool CBaseCombatCharacter::IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType, CBaseEntity *entityToIgnore ) const
|
||||
{
|
||||
#if defined(GAME_DLL) && defined(COUNT_BCC_LOS)
|
||||
static int count, frame;
|
||||
if ( frame != gpGlobals->framecount )
|
||||
{
|
||||
Msg( ">> %d\n", count );
|
||||
frame = gpGlobals->framecount;
|
||||
count = 0;
|
||||
}
|
||||
count++;
|
||||
#endif
|
||||
if( checkType == IGNORE_ACTORS )
|
||||
{
|
||||
|
||||
// use the query cache unless it causes problems
|
||||
#if defined(GAME_DLL) && defined(TERROR)
|
||||
return IsLineOfSightBetweenTwoEntitiesClear( const_cast<CBaseCombatCharacter *>(this), EOFFSET_MODE_EYEPOSITION,
|
||||
entityToIgnore, EOFFSET_MODE_WORLDSPACE_CENTER,
|
||||
entityToIgnore, COLLISION_GROUP_NONE,
|
||||
MASK_L4D_VISION, TraceFilterNoCombatCharacters, 1.0 );
|
||||
#else
|
||||
trace_t trace;
|
||||
CTraceFilterNoCombatCharacters traceFilter( entityToIgnore, COLLISION_GROUP_NONE );
|
||||
UTIL_TraceLine( EyePosition(), pos, MASK_OPAQUE | CONTENTS_IGNORE_NODRAW_OPAQUE | CONTENTS_MONSTER, &traceFilter, &trace );
|
||||
|
||||
return trace.fraction == 1.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_t trace;
|
||||
CTraceFilterSkipTwoEntities traceFilter( this, entityToIgnore, COLLISION_GROUP_NONE );
|
||||
UTIL_TraceLine( EyePosition(), pos, MASK_OPAQUE | CONTENTS_IGNORE_NODRAW_OPAQUE, &traceFilter, &trace );
|
||||
|
||||
return trace.fraction == 1.0f;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,767 @@
|
||||
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef COMBATWEAPON_SHARED_H
|
||||
#define COMBATWEAPON_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "sharedInterface.h"
|
||||
#include "vphysics_interface.h"
|
||||
#include "predictable_entity.h"
|
||||
#include "soundflags.h"
|
||||
#include "weapon_parse.h"
|
||||
#include "baseviewmodel_shared.h"
|
||||
#include "weapon_proficiency.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#undef CBaseCombatWeapon
|
||||
#define CBaseCombatWeapon C_BaseCombatWeapon
|
||||
#undef CBaseWeaponWorldModel
|
||||
#define CBaseWeaponWorldModel C_BaseWeaponWorldModel
|
||||
#endif
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
extern void OnBaseCombatWeaponCreated( CBaseCombatWeapon * );
|
||||
extern void OnBaseCombatWeaponDestroyed( CBaseCombatWeapon * );
|
||||
|
||||
void *SendProxy_SendLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID );
|
||||
#endif
|
||||
|
||||
class CBasePlayer;
|
||||
class CBaseCombatCharacter;
|
||||
class IPhysicsConstraint;
|
||||
class CUserCmd;
|
||||
|
||||
// How many times to display altfire hud hints (per weapon)
|
||||
#define WEAPON_ALTFIRE_HUD_HINT_COUNT 1
|
||||
#define WEAPON_RELOAD_HUD_HINT_COUNT 1
|
||||
|
||||
//Start with a constraint in place (don't drop to floor)
|
||||
#define SF_WEAPON_START_CONSTRAINED (1<<0)
|
||||
#define SF_WEAPON_NO_PLAYER_PICKUP (1<<1)
|
||||
#define SF_WEAPON_NO_PHYSCANNON_PUNT (1<<2)
|
||||
|
||||
//Percent
|
||||
#define CLIP_PERC_THRESHOLD 0.75f
|
||||
|
||||
// Put this in your derived class definition to declare it's activity table
|
||||
// UNDONE: Cascade these?
|
||||
#define DECLARE_ACTTABLE() static acttable_t m_acttable[];\
|
||||
acttable_t *ActivityList( void );\
|
||||
int ActivityListCount( void );
|
||||
|
||||
// You also need to include the activity table itself in your class' implementation:
|
||||
// e.g.
|
||||
// acttable_t CWeaponStunstick::m_acttable[] =
|
||||
// {
|
||||
// { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, TRUE },
|
||||
// };
|
||||
//
|
||||
// The stunstick overrides the ACT_MELEE_ATTACK1 activity, replacing it with ACT_MELEE_ATTACK_SWING.
|
||||
// This animation is required for this weapon's operation.
|
||||
//
|
||||
|
||||
// Put this after your derived class' definition to implement the accessors for the
|
||||
// activity table.
|
||||
// UNDONE: Cascade these?
|
||||
#define IMPLEMENT_ACTTABLE(className) \
|
||||
acttable_t *className::ActivityList( void ) { return m_acttable; } \
|
||||
int className::ActivityListCount( void ) { return ARRAYSIZE(m_acttable); } \
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int baseAct;
|
||||
int weaponAct;
|
||||
bool required;
|
||||
} acttable_t;
|
||||
|
||||
class CHudTexture;
|
||||
class Color;
|
||||
|
||||
namespace vgui2
|
||||
{
|
||||
typedef unsigned long HFont;
|
||||
}
|
||||
|
||||
#define MWHEEL_UP 1
|
||||
#define MWHEEL_DOWN -1
|
||||
|
||||
|
||||
// -----------------------------------------
|
||||
// Vector cones
|
||||
// -----------------------------------------
|
||||
// VECTOR_CONE_PRECALCULATED - this resolves to vec3_origin, but adds some
|
||||
// context indicating that the person writing the code is not allowing
|
||||
// FireBullets() to modify the direction of the shot because the shot direction
|
||||
// being passed into the function has already been modified by another piece of
|
||||
// code and should be fired as specified. See GetActualShotTrajectory().
|
||||
|
||||
// NOTE: The way these are calculated is that each component == sin (degrees/2)
|
||||
#define VECTOR_CONE_PRECALCULATED vec3_origin
|
||||
#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 )
|
||||
#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 )
|
||||
#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 )
|
||||
#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 )
|
||||
#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 )
|
||||
#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 )
|
||||
#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 )
|
||||
#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 )
|
||||
#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 )
|
||||
#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 )
|
||||
#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 )
|
||||
#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base weapon class, shared on client and server
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BASECOMBATWEAPON_DERIVED_FROM CBaseAnimating
|
||||
|
||||
// temp states for modular weapon body groups
|
||||
#define MODULAR_BODYGROUPS_DEFAULT_NONE_SET 0
|
||||
#define MODULAR_BODYGROUPS_NONE_AVAILABLE 1
|
||||
#define MODULAR_BODYGROUPS_RANDOMIZED 2
|
||||
|
||||
enum WeaponHoldsPlayerAnimCapability_t
|
||||
{
|
||||
WEAPON_PLAYER_ANIMS_UNKNOWN = 0,
|
||||
WEAPON_PLAYER_ANIMS_AVAILABLE,
|
||||
WEAPON_PLAYER_ANIMS_NOT_AVAILABLE
|
||||
};
|
||||
|
||||
enum WeaponModelClassification_t
|
||||
{
|
||||
WEAPON_MODEL_IS_UNCLASSIFIED = 0,
|
||||
WEAPON_MODEL_IS_VIEWMODEL,
|
||||
WEAPON_MODEL_IS_WORLDMODEL,
|
||||
WEAPON_MODEL_IS_DROPPEDMODEL,
|
||||
WEAPON_MODEL_IS_UNRECOGNIZED
|
||||
};
|
||||
|
||||
class CBaseWeaponWorldModel : public CBaseAnimatingOverlay
|
||||
{
|
||||
DECLARE_CLASS( CBaseWeaponWorldModel, CBaseAnimatingOverlay );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
public:
|
||||
CBaseWeaponWorldModel();
|
||||
~CBaseWeaponWorldModel();
|
||||
void SetOwningWeapon( CBaseCombatWeapon *pWeaponParent );
|
||||
void ShowWorldModel( bool bVisible );
|
||||
bool HoldsPlayerAnimations( void );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
void ApplyCustomMaterialsAndStickers( void );
|
||||
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
virtual bool ShouldDraw( void ) OVERRIDE;
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
float * GetRenderClipPlane( void );
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
|
||||
virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
|
||||
|
||||
virtual bool IsFollowingEntity() { return true; } // weapon world models are ALWAYS carried by players
|
||||
|
||||
#else
|
||||
virtual void HandleAnimEvent( animevent_t *pEvent );
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ) OVERRIDE;
|
||||
virtual int UpdateTransmitState() OVERRIDE;
|
||||
#endif
|
||||
|
||||
virtual bool IsWeaponWorldModel( void ) const { return true; };
|
||||
|
||||
void ValidateParent( void );
|
||||
|
||||
int GetLeftHandAttachBoneIndex();
|
||||
int GetRightHandAttachBoneIndex();
|
||||
int GetMuzzleAttachIndex();
|
||||
int GetMuzzleBoneIndex();
|
||||
void ResetCachedBoneIndices();
|
||||
|
||||
bool HasDormantOwner( void );
|
||||
|
||||
typedef CHandle<CBaseCombatWeapon> CBaseCombatWeaponHandle;
|
||||
CNetworkVar( CBaseCombatWeaponHandle, m_hCombatWeaponParent );
|
||||
|
||||
private:
|
||||
WeaponHoldsPlayerAnimCapability_t m_nHoldsPlayerAnims;
|
||||
|
||||
int m_nLeftHandAttachBoneIndex;
|
||||
int m_nRightHandAttachBoneIndex;
|
||||
int m_nMuzzleAttachIndex;
|
||||
int m_nMuzzleBoneIndex;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool m_bStickersApplied;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Client side rep of CBaseTFCombatWeapon
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hacky
|
||||
class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBaseCombatWeapon, BASECOMBATWEAPON_DERIVED_FROM );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CBaseCombatWeapon();
|
||||
virtual ~CBaseCombatWeapon();
|
||||
|
||||
// Get unique weapon ID
|
||||
// FIXMEL4DTOMAINMERGE
|
||||
// We might have to disable this code in main until we refactor all weapons to use this system, as it's a pretty good perf boost
|
||||
virtual int GetWeaponID( void ) const { return 0; }
|
||||
|
||||
const CEconItemView* GetEconItemView( void ) const;
|
||||
CEconItemView* GetEconItemView( void );
|
||||
|
||||
virtual bool IsBaseCombatWeapon( void ) const { return true; }
|
||||
virtual CBaseCombatWeapon *MyCombatWeaponPointer( void ) { return this; }
|
||||
|
||||
// A derived weapon class should return true here so that weapon sounds, etc, can
|
||||
// apply the proper filter
|
||||
virtual bool IsPredicted( void ) const { return false; }
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
|
||||
void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType );
|
||||
|
||||
// Subtypes are used to manage multiple weapons of the same type on the player.
|
||||
virtual int GetSubType( void ) { return m_iSubType; }
|
||||
virtual void SetSubType( int iType ) { m_iSubType = iType; }
|
||||
|
||||
virtual void Equip( CBaseCombatCharacter *pOwner );
|
||||
virtual void Drop( const Vector &vecVelocity );
|
||||
|
||||
virtual int UpdateClientData( CBasePlayer *pPlayer );
|
||||
|
||||
virtual bool IsAllowedToSwitch( void );
|
||||
virtual bool CanBeSelected( void );
|
||||
virtual bool VisibleInWeaponSelection( void );
|
||||
virtual bool HasAmmo( void );
|
||||
|
||||
// Weapon Pickup For Player
|
||||
virtual void SetPickupTouch( void );
|
||||
virtual void DefaultTouch( CBaseEntity *pOther ); // default weapon touch
|
||||
virtual void GiveTo( CBaseEntity *pOther );
|
||||
|
||||
// HUD Hints
|
||||
virtual bool ShouldDisplayAltFireHUDHint();
|
||||
virtual void DisplayAltFireHudHint();
|
||||
virtual void RescindAltFireHudHint(); ///< undisplay the hud hint and pretend it never showed.
|
||||
|
||||
virtual bool ShouldDisplayReloadHUDHint();
|
||||
virtual void DisplayReloadHudHint();
|
||||
virtual void RescindReloadHudHint();
|
||||
|
||||
// Weapon client handling
|
||||
virtual void SetViewModelIndex( int index = 0 );
|
||||
virtual bool SendWeaponAnim( int iActivity );
|
||||
virtual void SendViewModelAnim( int nSequence );
|
||||
float GetViewModelSequenceDuration(); // Return how long the current view model sequence is.
|
||||
bool IsViewModelSequenceFinished( void ); // Returns if the viewmodel's current animation is finished
|
||||
|
||||
virtual void SetViewModel();
|
||||
|
||||
virtual bool HasWeaponIdleTimeElapsed( void );
|
||||
virtual void SetWeaponIdleTime( float time );
|
||||
virtual float GetWeaponIdleTime( void );
|
||||
|
||||
// Weapon selection
|
||||
virtual bool HasAnyAmmo( void ); // Returns true is weapon has ammo
|
||||
virtual bool HasPrimaryAmmo( void ); // Returns true is weapon has ammo
|
||||
virtual bool HasSecondaryAmmo( void ); // Returns true is weapon has ammo
|
||||
bool UsesPrimaryAmmo( void ); // returns true if the weapon actually uses primary ammo
|
||||
bool UsesSecondaryAmmo( void ); // returns true if the weapon actually uses secondary ammo
|
||||
void GiveDefaultAmmo( void );
|
||||
|
||||
virtual bool CanHolster( void ) { return TRUE; }; // returns true if the weapon can be holstered
|
||||
virtual bool DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt );
|
||||
virtual bool CanDeploy( void ) { return true; } // return true if the weapon's allowed to deploy
|
||||
virtual bool Deploy( void ); // returns true is deploy was successful
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
|
||||
virtual CBaseCombatWeapon *GetLastWeapon( void ) { return this; }
|
||||
virtual void SetWeaponVisible( bool visible );
|
||||
virtual bool IsWeaponVisible( void );
|
||||
virtual bool ReloadOrSwitchWeapons( void );
|
||||
virtual bool HolsterOnDetach() { return false; }
|
||||
virtual bool IsHolstered(){ return false; }
|
||||
|
||||
// Weapon behaviour
|
||||
virtual void ItemPreFrame( void ); // called each frame by the player PreThink
|
||||
virtual void ItemPostFrame( void ); // called each frame by the player PostThink
|
||||
virtual void ItemBusyFrame( void ); // called each frame by the player PostThink, if the player's not ready to attack yet
|
||||
virtual void ItemHolsterFrame( void ) {}; // called each frame by the player PreThink, if the weapon is holstered
|
||||
virtual void WeaponIdle( void ); // called when no buttons pressed
|
||||
virtual void HandleFireOnEmpty(); // Called when they have the attack button down
|
||||
// but they are out of ammo. The default implementation
|
||||
// either reloads, switches weapons, or plays an empty sound.
|
||||
|
||||
virtual bool ShouldBlockPrimaryFire() { return true; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd, const QAngle &vecOldViewAngles ) {}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
virtual bool IsZoomed() const { return false; } // Is this weapon in its 'zoomed in' mode?
|
||||
|
||||
// Reloading
|
||||
virtual void CheckReload( void );
|
||||
virtual void FinishReload( void );
|
||||
virtual void AbortReload( void );
|
||||
virtual bool Reload( void );
|
||||
bool DefaultReload( int iClipSize1, int iClipSize2, int iActivity );
|
||||
|
||||
// Weapon firing
|
||||
virtual void PrimaryAttack( void ); // do "+ATTACK"
|
||||
virtual void SecondaryAttack( void ) { return; } // do "+ATTACK2"
|
||||
virtual void BaseForceFire( CBaseCombatCharacter *pOperator, CBaseEntity *pTarget = NULL );
|
||||
|
||||
// Firing animations
|
||||
virtual Activity GetPrimaryAttackActivity( void );
|
||||
virtual Activity GetSecondaryAttackActivity( void );
|
||||
virtual Activity GetDrawActivity( void );
|
||||
virtual float GetDefaultAnimSpeed( void ) { return 1.0; }
|
||||
|
||||
// Bullet launch information
|
||||
virtual int GetBulletType( void );
|
||||
virtual const Vector& GetBulletSpread( void );
|
||||
virtual Vector GetBulletSpread( WeaponProficiency_t proficiency ) { return GetBulletSpread(); }
|
||||
virtual float GetSpreadBias( WeaponProficiency_t proficiency ) { return 1.0; }
|
||||
virtual float GetAccuracyFishtail() const { return 0.0f; }
|
||||
virtual float GetFireRate( void );
|
||||
virtual int GetMinBurst() { return 1; }
|
||||
virtual int GetMaxBurst() { return 1; }
|
||||
virtual float GetMinRestTime() { return 0.3; }
|
||||
virtual float GetMaxRestTime() { return 0.6; }
|
||||
virtual int GetRandomBurst() { return random->RandomInt( GetMinBurst(), GetMaxBurst() ); }
|
||||
virtual void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f );
|
||||
virtual void StopWeaponSound( WeaponSound_t sound_type );
|
||||
virtual const WeaponProficiencyInfo_t *GetProficiencyValues();
|
||||
|
||||
// Autoaim
|
||||
virtual float GetMaxAutoAimDeflection() { return 0.99f; }
|
||||
virtual float WeaponAutoAimScale() { return 1.0f; } // allows a weapon to influence the perceived size of the target's autoaim radius.
|
||||
|
||||
// TF Sprinting functions
|
||||
virtual bool StartSprinting( void ) { return false; };
|
||||
virtual bool StopSprinting( void ) { return false; };
|
||||
|
||||
// TF Injury functions
|
||||
virtual float GetDamage( float flDistance, int iLocation ) { return 0.0; };
|
||||
|
||||
virtual void SetActivity( Activity act, float duration );
|
||||
inline void SetActivity( Activity eActivity ) { m_Activity = eActivity; }
|
||||
inline Activity GetActivity( void ) { return m_Activity; }
|
||||
|
||||
virtual void AddViewKick( void ); // Add in the view kick for the weapon
|
||||
|
||||
virtual char *GetDeathNoticeName( void ); // Get the string to print death notices with
|
||||
|
||||
CBaseCombatCharacter *GetOwner() const;
|
||||
void SetOwner( CBaseCombatCharacter *owner );
|
||||
virtual void OnPickedUp( CBaseCombatCharacter *pNewOwner );
|
||||
|
||||
virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ) {};
|
||||
virtual float CalcViewmodelBob( void ) { return 0.0f; };
|
||||
|
||||
// Returns information about the various control panels
|
||||
virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
|
||||
virtual void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName );
|
||||
|
||||
virtual bool ShouldShowControlPanels( void ) { return true; }
|
||||
|
||||
void Lock( float lockTime, CBaseEntity *pLocker );
|
||||
bool IsLocked( CBaseEntity *pAsker );
|
||||
|
||||
//All weapons can be picked up by NPCs by default
|
||||
virtual bool CanBePickedUpByNPCs( void ) { return true; }
|
||||
|
||||
public:
|
||||
|
||||
// Weapon info accessors for data in the weapon's data file
|
||||
const FileWeaponInfo_t &GetWpnData( void ) const;
|
||||
virtual const char *GetViewModel( int viewmodelindex = 0 ) const;
|
||||
virtual const char *GetWorldModel( void ) const;
|
||||
virtual const char *GetWorldDroppedModel( void ) const;
|
||||
virtual const char *GetAnimPrefix( void ) const;
|
||||
virtual int GetMaxClip1( void ) const { return GetWpnData().GetPrimaryClipSize( GetEconItemView() ); }
|
||||
virtual int GetMaxClip2( void ) const { return GetWpnData().GetSecondaryClipSize( GetEconItemView() ); }
|
||||
virtual int GetDefaultClip1( void ) const { return GetWpnData().GetDefaultPrimaryClipSize( GetEconItemView() ); }
|
||||
virtual int GetDefaultClip2( void ) const { return GetWpnData().GetDefaultSecondaryClipSize( GetEconItemView() ); }
|
||||
virtual int GetReserveAmmoMax( AmmoPosition_t nAmmoPos ) const;
|
||||
virtual int GetWeight( void ) const;
|
||||
virtual bool AllowsAutoSwitchTo( void ) const;
|
||||
virtual bool AllowsAutoSwitchFrom( void ) const;
|
||||
virtual int GetWeaponFlags( void ) const;
|
||||
virtual int GetSlot( void ) const;
|
||||
virtual int GetPosition( void ) const;
|
||||
virtual char const *GetName( void ) const;
|
||||
virtual char const *GetPrintName( void ) const;
|
||||
virtual char const *GetShootSound( int iIndex ) const;
|
||||
virtual int GetRumbleEffect() const;
|
||||
virtual bool UsesClipsForAmmo1( void ) const;
|
||||
virtual bool UsesClipsForAmmo2( void ) const;
|
||||
bool IsMeleeWeapon() const;
|
||||
|
||||
virtual void OnMouseWheel( int nDirection ) {}
|
||||
|
||||
// derive this function if you mod uses encrypted weapon info files
|
||||
virtual const unsigned char *GetEncryptionKey( void );
|
||||
|
||||
virtual int GetPrimaryAmmoType( void ) const { return m_iPrimaryAmmoType; }
|
||||
virtual int GetSecondaryAmmoType( void ) const { return m_iSecondaryAmmoType; }
|
||||
int Clip1() const { return m_iClip1; }
|
||||
int Clip2() const { return m_iClip2; }
|
||||
|
||||
// Ammo quantity queries for weapons that do not use clips. These are only
|
||||
// used to determine how much ammo is in a weapon that does not have an owner.
|
||||
// That is, a weapon that's on the ground for the player to get ammo out of.
|
||||
int GetPrimaryAmmoCount() { return m_iPrimaryAmmoCount; }
|
||||
void SetPrimaryAmmoCount( int count ) { m_iPrimaryAmmoCount = count; }
|
||||
|
||||
int GetSecondaryAmmoCount() { return m_iSecondaryAmmoCount; }
|
||||
void SetSecondaryAmmoCount( int count ) { m_iSecondaryAmmoCount = count; }
|
||||
|
||||
int GetReserveAmmoCount( AmmoPosition_t nAmmoPosition, CBaseCombatCharacter * pForcedOwner = NULL );
|
||||
int SetReserveAmmoCount( AmmoPosition_t nAmmoPosition, int nCount, bool bSuppressSound = false, CBaseCombatCharacter * pOwner = NULL );
|
||||
int GiveReserveAmmo( AmmoPosition_t nAmmoPosition, int nCount, bool bSuppressSound = false, CBaseCombatCharacter * pOwner = NULL );
|
||||
|
||||
virtual CHudTexture const *GetSpriteActive( void ) const;
|
||||
virtual CHudTexture const *GetSpriteInactive( void ) const;
|
||||
virtual CHudTexture const *GetSpriteAmmo( void ) const;
|
||||
virtual CHudTexture const *GetSpriteAmmo2( void ) const;
|
||||
virtual CHudTexture const *GetSpriteCrosshair( void ) const;
|
||||
virtual CHudTexture const *GetSpriteAutoaim( void ) const;
|
||||
virtual CHudTexture const *GetSpriteZoomedCrosshair( void ) const;
|
||||
virtual CHudTexture const *GetSpriteZoomedAutoaim( void ) const;
|
||||
|
||||
virtual Activity ActivityOverride( Activity baseAct, bool *pRequired );
|
||||
virtual acttable_t* ActivityList( void ) { return NULL; }
|
||||
virtual int ActivityListCount( void ) { return 0; }
|
||||
|
||||
virtual void Activate( void );
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// Server Only Methods
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
CBaseWeaponWorldModel* CreateWeaponWorldModel( void );
|
||||
|
||||
DECLARE_DATADESC();
|
||||
virtual void FallInit( void ); // prepare to fall to the ground
|
||||
virtual void FallThink( void ); // make the weapon fall to the ground after spawning
|
||||
|
||||
// Weapon spawning
|
||||
bool IsConstrained() { return m_pConstraint != NULL; }
|
||||
bool IsInBadPosition ( void ); // Is weapon in bad position to pickup?
|
||||
bool RepositionWeapon ( void ); // Attempts to reposition the weapon in a location where it can be
|
||||
virtual void Materialize( void ); // make a weapon visible and tangible
|
||||
void AttemptToMaterialize( void ); // see if the game rules will let the weapon become visible and tangible
|
||||
virtual void CheckRespawn( void ); // see if this weapon should respawn after being picked up
|
||||
CBaseEntity *Respawn ( void ); // copy a weapon
|
||||
|
||||
static int GetAvailableWeaponsInBox( CBaseCombatWeapon **pList, int listMax, const Vector &mins, const Vector &maxs );
|
||||
|
||||
// Weapon dropping / destruction
|
||||
virtual void Delete( void );
|
||||
void DestroyItem( void );
|
||||
virtual void Kill( void );
|
||||
|
||||
virtual int CapabilitiesGet( void ) { return 0; }
|
||||
virtual int ObjectCaps( void );
|
||||
|
||||
bool IsRemoveable() { return m_bRemoveable; }
|
||||
void SetRemoveable( bool bRemoveable ) { m_bRemoveable = bRemoveable; }
|
||||
|
||||
// Returns bits for weapon conditions
|
||||
virtual bool WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions );
|
||||
virtual int WeaponRangeAttack1Condition( float flDot, float flDist );
|
||||
virtual int WeaponRangeAttack2Condition( float flDot, float flDist );
|
||||
virtual int WeaponMeleeAttack1Condition( float flDot, float flDist );
|
||||
virtual int WeaponMeleeAttack2Condition( float flDot, float flDist );
|
||||
|
||||
virtual void Operator_FrameUpdate( CBaseCombatCharacter *pOperator );
|
||||
virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
|
||||
virtual void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary, CBaseEntity *pTarget = NULL ) { return; }
|
||||
// NOTE: This should never be called when a character is operating the weapon. Animation events should be
|
||||
// routed through the character, and then back into CharacterAnimEvent()
|
||||
void HandleAnimEvent( animevent_t *pEvent );
|
||||
|
||||
virtual int UpdateTransmitState( void );
|
||||
|
||||
void InputHideWeapon( inputdata_t &inputdata );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual void MakeWeaponNameFromEntity( CBaseEntity *pOther );
|
||||
|
||||
//weapon module body groups
|
||||
virtual void SetWeaponModules( void );
|
||||
|
||||
// Client only methods
|
||||
#else
|
||||
|
||||
virtual void UpdateVisibility( void );
|
||||
|
||||
virtual void BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const;
|
||||
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options ) { return false; }
|
||||
|
||||
// Should this object cast shadows?
|
||||
virtual ShadowType_t ShadowCastType();
|
||||
virtual void SetDormant( bool bDormant );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnRestore();
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
virtual void Redraw(void);
|
||||
virtual void ViewModelDrawn( int nFlags, CBaseViewModel *pViewModel );
|
||||
// Get the position that bullets are seen coming out. Note: the returned values are different
|
||||
// for first person and third person.
|
||||
bool GetShootPosition( Vector &vOrigin, QAngle &vAngles );
|
||||
virtual void DrawCrosshair( void );
|
||||
virtual bool ShouldDrawCrosshair( void ) { return true; }
|
||||
|
||||
// Weapon state checking
|
||||
virtual bool IsCarriedByLocalPlayer( void );
|
||||
virtual bool IsActiveByLocalPlayer( void );
|
||||
|
||||
bool IsBeingCarried() const;
|
||||
|
||||
// Returns the aiment render origin + angles
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual bool ShouldDraw( void );
|
||||
virtual bool ShouldSuppressForSplitScreenPlayer( int nSlot );
|
||||
virtual bool ShouldDrawPickup( void );
|
||||
virtual void HandleInput( void ) { return; };
|
||||
virtual void OverrideMouseInput( float *x, float *y ) { return; };
|
||||
virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { return 1; }
|
||||
virtual bool AddLookShift( void ) { return true; };
|
||||
|
||||
virtual void GetViewmodelBoneControllers(C_BaseViewModel *pViewModel, float controllers[MAXSTUDIOBONECTRLS]) { return; }
|
||||
|
||||
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
|
||||
|
||||
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
bool IsFirstPersonSpectated( void ); //true if the weapon is held by someone we're spectating in first person
|
||||
|
||||
virtual void GetWeaponCrosshairScale( float &flScale ) { flScale = 1.f; }
|
||||
|
||||
virtual void GetToolViewModelState( KeyValues *msg ) {} // this is just a stub for viewmodels to request recording of weapon-specific effects, etc
|
||||
|
||||
// Viewmodel overriding
|
||||
virtual bool IsOverridingViewmodel( void ) { return false; };
|
||||
virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags, const RenderableInstance_t &instance ) { return 0; };
|
||||
bool WantsToOverrideViewmodelAttachments( void ) { return false; }
|
||||
|
||||
virtual IClientModelRenderable* GetClientModelRenderable();
|
||||
|
||||
static CUtlLinkedList< CBaseCombatWeapon * >& GetWeaponList( void );
|
||||
|
||||
|
||||
void ApplyThirdPersonStickers( C_BaseAnimating *pWeaponModelTargetOverride = NULL );
|
||||
|
||||
#endif // End client-only methods
|
||||
|
||||
// virtual float GetAttributeFloat( const char* szAttribClassName ) const;
|
||||
// virtual bool GetAttributeBool( const char* szAttribClassName ) const;
|
||||
// virtual int GetAttributeInt( const char* szAttribClassName ) const;
|
||||
|
||||
WEAPON_FILE_INFO_HANDLE GetWeaponFileInfoHandle() const { return m_hWeaponFileInfo; }
|
||||
|
||||
// Is the carrier alive?
|
||||
bool IsCarrierAlive() const;
|
||||
virtual bool IsAlwaysActive( void ) { return false; }
|
||||
|
||||
virtual bool CanLower( void ) { return false; }
|
||||
virtual bool Ready( void ) { return false; }
|
||||
virtual bool Lower( void ) { return false; }
|
||||
|
||||
virtual void HideThink( void );
|
||||
virtual bool CanReload( void ){ return true; }
|
||||
|
||||
virtual bool IsSilentPickupThirdperson( CBaseCombatCharacter *pNewOwner ) { return false; }
|
||||
|
||||
// FTYPEDESC_INSENDTABLE STUFF
|
||||
private:
|
||||
typedef CHandle< CBaseCombatCharacter > CBaseCombatCharacterHandle;
|
||||
CNetworkVar( CBaseCombatCharacterHandle, m_hOwner ); // Player carrying this weapon
|
||||
public:
|
||||
// Networked fields
|
||||
CNetworkVar( int, m_nViewModelIndex );
|
||||
// Weapon firing
|
||||
CNetworkVar( float, m_flNextPrimaryAttack ); // soonest time ItemPostFrame will call PrimaryAttack
|
||||
CNetworkVar( float, m_flNextSecondaryAttack ); // soonest time ItemPostFrame will call SecondaryAttack
|
||||
|
||||
// Weapon art
|
||||
CNetworkVar( int, m_iViewModelIndex );
|
||||
CNetworkVar( int, m_iWorldModelIndex );
|
||||
|
||||
CNetworkVar( int, m_iWorldDroppedModelIndex );
|
||||
|
||||
CNetworkVar( int, m_iWeaponModule );
|
||||
|
||||
CNetworkVar( int, m_iNumEmptyAttacks );
|
||||
|
||||
typedef CHandle<CBaseWeaponWorldModel> CBaseWeaponWorldModelHandle;
|
||||
CNetworkVar( CBaseWeaponWorldModelHandle, m_hWeaponWorldModel );
|
||||
|
||||
CBaseWeaponWorldModel* GetWeaponWorldModel( void ) { return m_hWeaponWorldModel->Get(); }
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
void ShowWeaponWorldModel( bool bVisible );
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Weapon data
|
||||
CNetworkVar( int, m_iState ); // See WEAPON_* definition
|
||||
CNetworkVar( int, m_iPrimaryAmmoType ); // "primary" ammo index into the ammo info array
|
||||
CNetworkVar( int, m_iSecondaryAmmoType ); // "secondary" ammo index into the ammo info array
|
||||
CNetworkVar( int, m_iClip1 ); // number of shots left in the primary weapon clip, -1 it not used
|
||||
CNetworkVar( int, m_iClip2 ); // number of shots left in the secondary weapon clip, -1 it not used
|
||||
|
||||
CNetworkVar( int, m_iPrimaryReserveAmmoCount); // amount of reserve ammo. This used to be on the player ( m_iAmmo ) but we're moving it to the weapon.
|
||||
CNetworkVar( int, m_iSecondaryReserveAmmoCount); // amount of reserve ammo. This used to be on the player ( m_iAmmo ) but we're moving it to the weapon.
|
||||
|
||||
public:
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
float m_flLastTimeInAir;
|
||||
virtual void PhysicsSimulate( void );
|
||||
#endif
|
||||
|
||||
// Non-networked prediction fields
|
||||
CNetworkVar( float, m_flTimeWeaponIdle ); // soonest time ItemPostFrame will call WeaponIdle
|
||||
// Sounds
|
||||
float m_flNextEmptySoundTime; // delay on empty sound playing
|
||||
float m_fMinRange1; // What's the closest this weapon can be used?
|
||||
float m_fMinRange2; // What's the closest this weapon can be used?
|
||||
float m_fMaxRange1; // What's the furthest this weapon can be used?
|
||||
float m_fMaxRange2; // What's the furthest this weapon can be used?
|
||||
float m_fFireDuration; // The amount of time that the weapon has sustained firing
|
||||
int m_iReloadActivityIndex;
|
||||
|
||||
private:
|
||||
Activity m_Activity;
|
||||
int m_iPrimaryAmmoCount;
|
||||
int m_iSecondaryAmmoCount;
|
||||
|
||||
public:
|
||||
string_t m_iszName; // Classname of this weapon.
|
||||
|
||||
private:
|
||||
bool m_bRemoveable;
|
||||
public:
|
||||
// Weapon state
|
||||
CNetworkVar( bool, m_bInReload ); // Are we in the middle of a reload;
|
||||
bool m_bFireOnEmpty; // True when the gun is empty and the player is still holding down the attack key(s)
|
||||
bool m_bFiresUnderwater; // true if this weapon can fire underwater
|
||||
bool m_bAltFiresUnderwater; // true if this weapon can fire underwater
|
||||
bool m_bReloadsSingly; // Tryue if this weapon reloads 1 round at a time
|
||||
|
||||
float m_flWeaponTauntHideTimeout;
|
||||
|
||||
// FTYPEDESC_INSENDTABLE STUFF (end)
|
||||
public:
|
||||
Activity GetIdealActivity( void ) { return m_IdealActivity; }
|
||||
int GetIdealSequence( void ) { return m_nIdealSequence; }
|
||||
|
||||
bool SetIdealActivity( Activity ideal );
|
||||
void MaintainIdealActivity( void );
|
||||
|
||||
private:
|
||||
int m_nIdealSequence;
|
||||
Activity m_IdealActivity;
|
||||
|
||||
public:
|
||||
|
||||
IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_nNextThinkTick );
|
||||
|
||||
int WeaponState() const { return m_iState; }
|
||||
|
||||
int m_iSubType;
|
||||
|
||||
float m_flUnlockTime;
|
||||
EHANDLE m_hLocker; // Who locked this weapon.
|
||||
|
||||
CNetworkVar( bool, m_bFlipViewModel );
|
||||
|
||||
CNetworkVar( int, m_iWeaponOrigin ); // How the player acquired the weapon
|
||||
|
||||
IPhysicsConstraint *GetConstraint() { return m_pConstraint; }
|
||||
|
||||
virtual CStudioHdr *OnNewModel() OVERRIDE;
|
||||
void ClassifyWeaponModel( void );
|
||||
WeaponModelClassification_t GetWeaponModelClassification( void );
|
||||
void VerifyAndSetContextSensitiveWeaponModel( void );
|
||||
|
||||
private:
|
||||
WeaponModelClassification_t m_WeaponModelClassification;
|
||||
|
||||
WEAPON_FILE_INFO_HANDLE m_hWeaponFileInfo;
|
||||
IPhysicsConstraint *m_pConstraint;
|
||||
|
||||
int m_iAltFireHudHintCount; // How many times has this weapon displayed its alt-fire HUD hint?
|
||||
int m_iReloadHudHintCount; // How many times has this weapon displayed its reload HUD hint?
|
||||
bool m_bAltFireHudHintDisplayed; // Have we displayed an alt-fire HUD hint since this weapon was deployed?
|
||||
bool m_bReloadHudHintDisplayed; // Have we displayed a reload HUD hint since this weapon was deployed?
|
||||
float m_flHudHintPollTime; // When to poll the weapon again for whether it should display a hud hint.
|
||||
float m_flHudHintMinDisplayTime; // if the hint is squelched before this, reset my counter so we'll display it again.
|
||||
|
||||
// Server only
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
// Outputs
|
||||
protected:
|
||||
COutputEvent m_OnPlayerUse; // Fired when the player uses the weapon.
|
||||
COutputEvent m_OnPlayerPickup; // Fired when the player picks up the weapon.
|
||||
COutputEvent m_OnNPCPickup; // Fired when an NPC picks up the weapon.
|
||||
COutputEvent m_OnCacheInteraction; // For awarding lambda cache achievements in HL2 on 360. See .FGD file for details
|
||||
|
||||
#else // Client .dll only
|
||||
bool m_bJustRestored;
|
||||
|
||||
// Allow weapons resource to access m_hWeaponFileInfo directly
|
||||
friend class WeaponsResource;
|
||||
|
||||
|
||||
protected:
|
||||
int m_iOldState;
|
||||
|
||||
#endif // End Client .dll only
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inline methods
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CBaseCombatWeapon *ToBaseCombatWeapon( CBaseEntity *pEntity )
|
||||
{
|
||||
if ( !pEntity )
|
||||
return NULL;
|
||||
return pEntity->MyCombatWeaponPointer();
|
||||
}
|
||||
|
||||
|
||||
#endif // COMBATWEAPON_SHARED_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,382 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASEENTITY_SHARED_H
|
||||
#define BASEENTITY_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#define SERVER_PLATTIME_RNG true
|
||||
#else
|
||||
#define SERVER_PLATTIME_RNG
|
||||
#endif
|
||||
|
||||
extern ConVar hl2_episodic;
|
||||
|
||||
// Simple shared header file for common base entities
|
||||
|
||||
// entity capabilities
|
||||
// These are caps bits to indicate what an object's capabilities (currently used for +USE, save/restore and level transitions)
|
||||
// NOTE: (For portal 2 and paint) These +use related caps MUST be the first 6 bits!
|
||||
#define FCAP_IMPULSE_USE 0x00000001 // can be used by the player
|
||||
#define FCAP_CONTINUOUS_USE 0x00000002 // can be used by the player
|
||||
#define FCAP_ONOFF_USE 0x00000004 // can be used by the player
|
||||
#define FCAP_DIRECTIONAL_USE 0x00000008 // Player sends +/- 1 when using (currently only tracktrains)
|
||||
// NOTE: Normally +USE only works in direct line of sight. Add these caps for additional searches
|
||||
#define FCAP_USE_ONGROUND 0x00000010
|
||||
#define FCAP_USE_IN_RADIUS 0x00000020
|
||||
|
||||
#define FCAP_MUST_SPAWN 0x00000040 // Spawn after restore
|
||||
#define FCAP_ACROSS_TRANSITION 0x00000080 // should transfer between transitions
|
||||
// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!!
|
||||
#define FCAP_FORCE_TRANSITION 0x00000100 // ALWAYS goes across transitions
|
||||
#define FCAP_NOTIFY_ON_TRANSITION 0x00000200 // Entity will receive Inside/Outside transition inputs when a transition occurs
|
||||
|
||||
#define FCAP_SAVE_NON_NETWORKABLE 0x00000400
|
||||
|
||||
#define FCAP_MASTER 0x10000000 // Can be used to "master" other entities (like multisource)
|
||||
#define FCAP_WCEDIT_POSITION 0x40000000 // Can change position and update Hammer in edit mode
|
||||
#define FCAP_DONT_SAVE 0x80000000 // Don't save this
|
||||
|
||||
|
||||
// How many bits are used to transmit parent attachment indices?
|
||||
#define NUM_PARENTATTACHMENT_BITS 6
|
||||
|
||||
// Maximum number of vphysics objects per entity
|
||||
#define VPHYSICS_MAX_OBJECT_LIST_COUNT 1024
|
||||
|
||||
#define DEFAULT_LOOK_AT_USE_ANGLE 0.8f
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_baseentity.h"
|
||||
#include "c_baseanimating.h"
|
||||
#else
|
||||
#include "baseentity.h"
|
||||
|
||||
#ifdef HL2_EPISODIC
|
||||
#include "info_darknessmode_lightsource.h"
|
||||
#endif // HL2_EPISODIC
|
||||
|
||||
#endif
|
||||
|
||||
#include "vscript/ivscript.h"
|
||||
#include "vscript_shared.h"
|
||||
|
||||
#if !defined( NO_ENTITY_PREDICTION )
|
||||
// CBaseEntity inlines
|
||||
inline bool CBaseEntity::IsPlayerSimulated( void ) const
|
||||
{
|
||||
return m_bIsPlayerSimulated;
|
||||
}
|
||||
|
||||
inline CBasePlayer *CBaseEntity::GetSimulatingPlayer( void )
|
||||
{
|
||||
return m_hPlayerSimulationOwner.Get();
|
||||
}
|
||||
#endif
|
||||
|
||||
inline MoveType_t CBaseEntity::GetMoveType() const
|
||||
{
|
||||
return (MoveType_t)(unsigned char)m_MoveType;
|
||||
}
|
||||
|
||||
inline MoveCollide_t CBaseEntity::GetMoveCollide() const
|
||||
{
|
||||
return (MoveCollide_t)(unsigned char)m_MoveCollide;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Collision group accessors
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int CBaseEntity::GetCollisionGroup() const
|
||||
{
|
||||
return m_CollisionGroup;
|
||||
}
|
||||
|
||||
inline int CBaseEntity::GetFlags( void ) const
|
||||
{
|
||||
return m_fFlags;
|
||||
}
|
||||
|
||||
inline bool CBaseEntity::IsAlive( void )const
|
||||
{
|
||||
return m_lifeState == LIFE_ALIVE;
|
||||
}
|
||||
|
||||
inline CBaseEntity *CBaseEntity::GetOwnerEntity() const
|
||||
{
|
||||
return m_hOwnerEntity.Get();
|
||||
}
|
||||
|
||||
inline CBaseEntity *CBaseEntity::GetEffectEntity() const
|
||||
{
|
||||
return m_hEffectEntity.Get();
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
inline int CBaseEntity::GetPredictionRandomSeed( void )
|
||||
{
|
||||
return m_nPredictionRandomSeed;
|
||||
}
|
||||
#else
|
||||
inline int CBaseEntity::GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime )
|
||||
{
|
||||
return bUseUnSyncedServerPlatTime ? m_nPredictionRandomSeedServer : m_nPredictionRandomSeed;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline CBasePlayer *CBaseEntity::GetPredictionPlayer( void )
|
||||
{
|
||||
return m_pPredictionPlayer;
|
||||
}
|
||||
|
||||
inline void CBaseEntity::SetPredictionPlayer( CBasePlayer *player )
|
||||
{
|
||||
m_pPredictionPlayer = player;
|
||||
}
|
||||
|
||||
|
||||
inline bool CBaseEntity::IsSimulatedEveryTick() const
|
||||
{
|
||||
return m_bSimulatedEveryTick;
|
||||
}
|
||||
|
||||
inline bool CBaseEntity::IsAnimatedEveryTick() const
|
||||
{
|
||||
return m_bAnimatedEveryTick;
|
||||
}
|
||||
|
||||
inline void CBaseEntity::SetSimulatedEveryTick( bool sim )
|
||||
{
|
||||
if ( m_bSimulatedEveryTick != sim )
|
||||
{
|
||||
m_bSimulatedEveryTick = sim;
|
||||
#ifdef CLIENT_DLL
|
||||
Interp_UpdateInterpolationAmounts( GetVarMapping() );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void CBaseEntity::SetAnimatedEveryTick( bool anim )
|
||||
{
|
||||
if ( m_bAnimatedEveryTick != anim )
|
||||
{
|
||||
m_bAnimatedEveryTick = anim;
|
||||
#ifdef CLIENT_DLL
|
||||
Interp_UpdateInterpolationAmounts( GetVarMapping() );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline float CBaseEntity::GetAnimTime() const
|
||||
{
|
||||
return m_flAnimTime;
|
||||
}
|
||||
|
||||
inline float CBaseEntity::GetSimulationTime() const
|
||||
{
|
||||
return m_flSimulationTime;
|
||||
}
|
||||
|
||||
inline void CBaseEntity::SetAnimTime( float at )
|
||||
{
|
||||
m_flAnimTime = at;
|
||||
}
|
||||
|
||||
inline void CBaseEntity::SetSimulationTime( float st )
|
||||
{
|
||||
m_flSimulationTime = st;
|
||||
}
|
||||
|
||||
inline int CBaseEntity::GetEffects( void ) const
|
||||
{
|
||||
return m_fEffects;
|
||||
}
|
||||
|
||||
inline void CBaseEntity::RemoveEffects( int nEffects )
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
#ifdef HL2_EPISODIC
|
||||
if ( nEffects & (EF_BRIGHTLIGHT|EF_DIMLIGHT) )
|
||||
{
|
||||
// Hack for now, to avoid player emitting radius with his flashlight
|
||||
if ( !IsPlayer() )
|
||||
{
|
||||
RemoveEntityFromDarknessCheck( this );
|
||||
}
|
||||
}
|
||||
#endif // HL2_EPISODIC
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
m_fEffects &= ~nEffects;
|
||||
if ( nEffects & EF_NODRAW )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
NetworkProp()->MarkPVSInformationDirty();
|
||||
DispatchUpdateTransmitState();
|
||||
#else
|
||||
UpdateVisibility();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
if ( nEffects & EF_MARKED_FOR_FAST_REFLECTION )
|
||||
{
|
||||
OnFastReflectionRenderingChanged();
|
||||
}
|
||||
OnDisableShadowDepthRenderingChanged();
|
||||
OnDisableCSMRenderingChanged();
|
||||
OnShadowDepthRenderingCacheableStateChanged();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void CBaseEntity::ClearEffects( void )
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
#ifdef HL2_EPISODIC
|
||||
if ( m_fEffects & (EF_BRIGHTLIGHT|EF_DIMLIGHT) )
|
||||
{
|
||||
// Hack for now, to avoid player emitting radius with his flashlight
|
||||
if ( !IsPlayer() )
|
||||
{
|
||||
RemoveEntityFromDarknessCheck( this );
|
||||
}
|
||||
}
|
||||
#endif // HL2_EPISODIC
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
bool bRendersInFastReflection = ( m_fEffects & EF_MARKED_FOR_FAST_REFLECTION ) != 0;
|
||||
#endif
|
||||
|
||||
m_fEffects = 0;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DispatchUpdateTransmitState();
|
||||
#else
|
||||
UpdateVisibility();
|
||||
if ( bRendersInFastReflection )
|
||||
{
|
||||
OnFastReflectionRenderingChanged();
|
||||
}
|
||||
OnDisableShadowDepthRenderingChanged();
|
||||
OnDisableCSMRenderingChanged();
|
||||
OnShadowDepthRenderingCacheableStateChanged();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CBaseEntity::IsEffectActive( int nEffects ) const
|
||||
{
|
||||
return (m_fEffects & nEffects) != 0;
|
||||
}
|
||||
|
||||
|
||||
inline HSCRIPT ToHScript( CBaseEntity *pEnt )
|
||||
{
|
||||
return ( pEnt ) ? pEnt->GetScriptInstance() : NULL;
|
||||
}
|
||||
|
||||
template <> ScriptClassDesc_t *GetScriptDesc<CBaseEntity>( CBaseEntity * );
|
||||
inline CBaseEntity *ToEnt( HSCRIPT hScript )
|
||||
{
|
||||
|
||||
return ( hScript ) ? (CBaseEntity *)g_pScriptVM->GetInstanceValue( hScript, GetScriptDescForClass(CBaseEntity) ) : NULL;
|
||||
}
|
||||
|
||||
// convenience functions for fishing out the vectors of this object
|
||||
// equivalent to GetVectors(), but doesn't need an intermediate stack
|
||||
// variable (which might cause an LHS anyway)
|
||||
inline Vector CBaseEntity::Forward() const RESTRICT ///< get my forward (+x) vector
|
||||
{
|
||||
const matrix3x4_t &mat = EntityToWorldTransform();
|
||||
return Vector( mat[0][0], mat[1][0], mat[2][0] );
|
||||
}
|
||||
|
||||
inline Vector CBaseEntity::Left() const RESTRICT ///< get my left (+y) vector
|
||||
{
|
||||
const matrix3x4_t &mat = EntityToWorldTransform();
|
||||
return Vector( mat[0][1], mat[1][1], mat[2][1] );
|
||||
}
|
||||
|
||||
inline Vector CBaseEntity::Up() const RESTRICT ///< get my up (+z) vector
|
||||
{
|
||||
const matrix3x4_t &mat = EntityToWorldTransform();
|
||||
return Vector( mat[0][2], mat[1][2], mat[2][2] );
|
||||
}
|
||||
|
||||
// Shared EntityMessage between game and client .dlls
|
||||
#define BASEENTITY_MSG_REMOVE_DECALS 1
|
||||
|
||||
inline bool IsPushableMoveType( int nMoveType )
|
||||
{
|
||||
if ( nMoveType == MOVETYPE_PUSH || nMoveType == MOVETYPE_NONE ||
|
||||
nMoveType == MOVETYPE_VPHYSICS || nMoveType == MOVETYPE_NOCLIP )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern float k_flMaxEntityPosCoord;
|
||||
extern float k_flMaxEntityEulerAngle;
|
||||
extern float k_flMaxEntitySpeed;
|
||||
extern float k_flMaxEntitySpinRate;
|
||||
|
||||
inline bool IsEntityCoordinateReasonable( const vec_t c )
|
||||
{
|
||||
float r = k_flMaxEntityPosCoord;
|
||||
return c > -r && c < r;
|
||||
}
|
||||
|
||||
inline bool IsEntityPositionReasonable( const Vector &v )
|
||||
{
|
||||
float r = k_flMaxEntityPosCoord;
|
||||
return
|
||||
v.x > -r && v.x < r &&
|
||||
v.y > -r && v.y < r &&
|
||||
v.z > -r && v.z < r;
|
||||
}
|
||||
|
||||
// Returns:
|
||||
// -1 - velocity is really, REALLY bad and probably should be rejected.
|
||||
// 0 - velocity was suspicious and clamped.
|
||||
// 1 - velocity was OK and not modified
|
||||
extern int CheckEntityVelocity( Vector &v );
|
||||
|
||||
inline bool IsEntityQAngleReasonable( const QAngle &q )
|
||||
{
|
||||
float r = k_flMaxEntityEulerAngle;
|
||||
return
|
||||
q.x > -r && q.x < r &&
|
||||
q.y > -r && q.y < r &&
|
||||
q.z > -r && q.z < r;
|
||||
}
|
||||
|
||||
// Angular velocity in exponential map form
|
||||
inline bool IsEntityAngularVelocityReasonable( const Vector &q )
|
||||
{
|
||||
float r = k_flMaxEntitySpinRate;
|
||||
return
|
||||
q.x > -r && q.x < r &&
|
||||
q.y > -r && q.y < r &&
|
||||
q.z > -r && q.z < r;
|
||||
}
|
||||
|
||||
// Angular velocity of each Euler angle.
|
||||
inline bool IsEntityQAngleVelReasonable( const QAngle &q )
|
||||
{
|
||||
float r = k_flMaxEntitySpinRate;
|
||||
return
|
||||
q.x > -r && q.x < r &&
|
||||
q.y > -r && q.y < r &&
|
||||
q.z > -r && q.z < r;
|
||||
}
|
||||
|
||||
// Should we emit physics spew into the log or not?
|
||||
extern bool CheckEmitReasonablePhysicsSpew();
|
||||
|
||||
#endif // BASEENTITY_SHARED_H
|
||||
@@ -0,0 +1,605 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
#include "cbase.h"
|
||||
#include "decals.h"
|
||||
#include "basegrenade_shared.h"
|
||||
#include "shake.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "particle_parse.h"
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
#include "soundent.h"
|
||||
#include "entitylist.h"
|
||||
#include "GameStats.h"
|
||||
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
extern int g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the fireball
|
||||
extern int g_sModelIndexWExplosion; // (in combatweapon.cpp) holds the index for the underwater explosion
|
||||
extern int g_sModelIndexSmoke; // (in combatweapon.cpp) holds the index for the smoke cloud
|
||||
extern ConVar sk_plr_dmg_grenade;
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
// Global Savedata for friction modifier
|
||||
BEGIN_DATADESC( CBaseGrenade )
|
||||
// nextGrenade
|
||||
DEFINE_FIELD( m_hThrower, FIELD_EHANDLE ),
|
||||
// m_fRegisteredSound ???
|
||||
DEFINE_FIELD( m_bIsLive, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( m_DmgRadius, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flDetonateTime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_flWarnAITime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_flDamage, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_iszBounceSound, FIELD_STRING ),
|
||||
DEFINE_FIELD( m_bHasWarnedAI, FIELD_BOOLEAN ),
|
||||
|
||||
// Function Pointers
|
||||
DEFINE_THINKFUNC( Smoke ),
|
||||
DEFINE_ENTITYFUNC( BounceTouch ),
|
||||
DEFINE_ENTITYFUNC( SlideTouch ),
|
||||
DEFINE_ENTITYFUNC( ExplodeTouch ),
|
||||
DEFINE_USEFUNC( DetonateUse ),
|
||||
DEFINE_THINKFUNC( DangerSoundThink ),
|
||||
DEFINE_THINKFUNC( PreDetonate ),
|
||||
DEFINE_THINKFUNC( Detonate ),
|
||||
DEFINE_THINKFUNC( TumbleThink ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID);
|
||||
|
||||
#endif
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseGrenade, DT_BaseGrenade )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CBaseGrenade, DT_BaseGrenade )
|
||||
#if !defined( CLIENT_DLL )
|
||||
SendPropFloat( SENDINFO( m_flDamage ), 10, SPROP_ROUNDDOWN, 0.0, 256.0f ),
|
||||
SendPropFloat( SENDINFO( m_DmgRadius ), 10, SPROP_ROUNDDOWN, 0.0, 1024.0f ),
|
||||
SendPropInt( SENDINFO( m_bIsLive ), 1, SPROP_UNSIGNED ),
|
||||
// SendPropTime( SENDINFO( m_flDetonateTime ) ),
|
||||
SendPropEHandle( SENDINFO( m_hThrower ) ),
|
||||
|
||||
SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
|
||||
|
||||
SendPropVector( SENDINFO( m_vecVelocity ), 0, SPROP_NOSCALE ),
|
||||
// HACK: Use same flag bits as player for now
|
||||
SendPropInt ( SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED, SendProxy_CropFlagsToPlayerFlagBitsLength ),
|
||||
#else
|
||||
RecvPropFloat( RECVINFO( m_flDamage ) ),
|
||||
RecvPropFloat( RECVINFO( m_DmgRadius ) ),
|
||||
RecvPropInt( RECVINFO( m_bIsLive ) ),
|
||||
// RecvPropTime( RECVINFO( m_flDetonateTime ) ),
|
||||
RecvPropEHandle( RECVINFO( m_hThrower ) ),
|
||||
|
||||
// Need velocity from grenades to make animation system work correctly when running
|
||||
RecvPropVector( RECVINFO(m_vecVelocity), 0, RecvProxy_LocalVelocity ),
|
||||
|
||||
RecvPropInt( RECVINFO( m_fFlags ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS_ALIASED( grenade, BaseGrenade );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
BEGIN_PREDICTION_DATA( CBaseGrenade )
|
||||
|
||||
DEFINE_PRED_FIELD( m_hThrower, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bIsLive, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_DmgRadius, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
// DEFINE_PRED_FIELD_TOL( m_flDetonateTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
|
||||
DEFINE_PRED_FIELD( m_flDamage, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
|
||||
DEFINE_PRED_FIELD_TOL( m_vecVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.5f ),
|
||||
DEFINE_PRED_FIELD_TOL( m_flNextAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
|
||||
|
||||
// DEFINE_FIELD( m_fRegisteredSound, FIELD_BOOLEAN ),
|
||||
// DEFINE_FIELD( m_iszBounceSound, FIELD_STRING ),
|
||||
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
#endif
|
||||
|
||||
// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges
|
||||
#define SF_DETONATE 0x0001
|
||||
|
||||
#define MAX_WATER_SURFACE_DISTANCE 512
|
||||
|
||||
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
|
||||
void CBaseGrenade::Explode( trace_t *pTrace, int bitsDamageType )
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
SetModelName( NULL_STRING );//invisible
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
|
||||
m_takedamage = DAMAGE_NO;
|
||||
|
||||
// Pull out of the wall a bit
|
||||
if ( pTrace->fraction != 1.0 )
|
||||
{
|
||||
SetAbsOrigin( pTrace->endpos + (pTrace->plane.normal * 0.6) );
|
||||
}
|
||||
|
||||
Vector vecAbsOrigin = GetAbsOrigin();
|
||||
int contents = UTIL_PointContents ( vecAbsOrigin, MASK_ALL );
|
||||
|
||||
#if defined( TF_DLL )
|
||||
// Since this code only runs on the server, make sure it shows the tempents it creates.
|
||||
// This solves a problem with remote detonating the pipebombs (client wasn't seeing the explosion effect)
|
||||
CDisablePredictionFiltering disabler;
|
||||
#endif
|
||||
|
||||
// Try using the new particle system instead of temp ents
|
||||
surfacedata_t *pSurfaceData = physprops->GetSurfaceData( pTrace->surface.surfaceProps );
|
||||
const char *pEffectName = GetParticleSystemName( contents, pSurfaceData );
|
||||
if ( pEffectName != NULL )
|
||||
{
|
||||
Vector vecParticleOrigin = vecAbsOrigin;
|
||||
|
||||
if ( contents & MASK_WATER )
|
||||
{
|
||||
// Find our water surface by tracing up till we're out of the water
|
||||
trace_t tr;
|
||||
Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
|
||||
UTIL_TraceLine( vecParticleOrigin, vecParticleOrigin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// If we didn't start in water, we're above it
|
||||
if ( tr.startsolid == false )
|
||||
{
|
||||
// Look downward to find the surface
|
||||
vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
|
||||
UTIL_TraceLine( vecParticleOrigin, vecParticleOrigin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// If we hit it, setup the explosion
|
||||
if ( tr.fraction < 1.0f )
|
||||
{
|
||||
vecParticleOrigin = tr.endpos;
|
||||
}
|
||||
}
|
||||
else if ( tr.fractionleftsolid )
|
||||
{
|
||||
// Otherwise we came out of the water at this point
|
||||
vecParticleOrigin = vecParticleOrigin + (vecTrace * tr.fractionleftsolid);
|
||||
}
|
||||
}
|
||||
|
||||
QAngle vecAngles;
|
||||
DispatchParticleEffect( pEffectName, vecParticleOrigin, vecAngles );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pTrace->fraction != 1.0 )
|
||||
{
|
||||
Vector vecNormal = pTrace->plane.normal;
|
||||
surfacedata_t *pdata = physprops->GetSurfaceData( pTrace->surface.surfaceProps );
|
||||
CPASFilter filter( vecAbsOrigin );
|
||||
|
||||
te->Explosion( filter, -1.0, // don't apply cl_interp delay
|
||||
vecAbsOrigin,
|
||||
!( contents & MASK_WATER ) ? g_sModelIndexFireball : g_sModelIndexWExplosion,
|
||||
m_DmgRadius * .03,
|
||||
25,
|
||||
TE_EXPLFLAG_NONE,
|
||||
m_DmgRadius,
|
||||
m_flDamage,
|
||||
&vecNormal,
|
||||
(char) pdata->game.material );
|
||||
}
|
||||
else
|
||||
{
|
||||
CPASFilter filter( vecAbsOrigin );
|
||||
te->Explosion( filter, -1.0, // don't apply cl_interp delay
|
||||
vecAbsOrigin,
|
||||
!( contents & MASK_WATER ) ? g_sModelIndexFireball : g_sModelIndexWExplosion,
|
||||
m_DmgRadius * .03,
|
||||
25,
|
||||
TE_EXPLFLAG_NONE,
|
||||
m_DmgRadius,
|
||||
m_flDamage );
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 );
|
||||
#endif
|
||||
|
||||
// Use the thrower's position as the reported position
|
||||
Vector vecReported = m_hThrower ? m_hThrower->GetAbsOrigin() : vec3_origin;
|
||||
|
||||
EmitSound( "BaseGrenade.Explode" );
|
||||
CTakeDamageInfo info( this, m_hThrower, GetBlastForce(), GetAbsOrigin(), m_flDamage, bitsDamageType, 0, &vecReported );
|
||||
|
||||
RadiusDamage( info, GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
|
||||
|
||||
UTIL_DecalTrace( pTrace, "Scorch" );
|
||||
|
||||
SetThink( &CBaseGrenade::SUB_Remove );
|
||||
SetTouch( NULL );
|
||||
SetSolid( SOLID_NONE );
|
||||
|
||||
AddEffects( EF_NODRAW );
|
||||
SetAbsVelocity( vec3_origin );
|
||||
|
||||
#if HL2_EPISODIC
|
||||
// Because the grenade is zipped out of the world instantly, the EXPLOSION sound that it makes for
|
||||
// the AI is also immediately destroyed. For this reason, we now make the grenade entity inert and
|
||||
// throw it away in 1/10th of a second instead of right away. Removing the grenade instantly causes
|
||||
// intermittent bugs with env_microphones who are listening for explosions. They will 'randomly' not
|
||||
// hear explosion sounds when the grenade is removed and the SoundEnt thinks (and removes the sound)
|
||||
// before the env_microphone thinks and hears the sound.
|
||||
SetNextThink( gpGlobals->curtime + 0.1 );
|
||||
#else
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
#endif//HL2_EPISODIC
|
||||
|
||||
#if defined( HL2_DLL )
|
||||
CBasePlayer *pPlayer = ToBasePlayer( m_hThrower.Get() );
|
||||
if ( pPlayer )
|
||||
{
|
||||
gamestats->Event_WeaponHit( pPlayer, true, "weapon_frag", info );
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CBaseGrenade::Smoke( void )
|
||||
{
|
||||
Vector vecAbsOrigin = GetAbsOrigin();
|
||||
if ( UTIL_PointContents ( vecAbsOrigin, MASK_WATER ) & MASK_WATER )
|
||||
{
|
||||
UTIL_Bubbles( vecAbsOrigin - Vector( 64, 64, 64 ), vecAbsOrigin + Vector( 64, 64, 64 ), 100 );
|
||||
}
|
||||
else
|
||||
{
|
||||
CPVSFilter filter( vecAbsOrigin );
|
||||
|
||||
te->Smoke( filter, 0.0,
|
||||
&vecAbsOrigin, g_sModelIndexSmoke,
|
||||
m_DmgRadius * 0.03,
|
||||
24 );
|
||||
}
|
||||
#if !defined( CLIENT_DLL )
|
||||
SetThink ( &CBaseGrenade::SUB_Remove );
|
||||
#endif
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
void CBaseGrenade::Event_Killed( const CTakeDamageInfo &info )
|
||||
{
|
||||
Detonate( );
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseGrenade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
// Support player pickup
|
||||
if ( useType == USE_TOGGLE )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( pActivator );
|
||||
if ( pPlayer )
|
||||
{
|
||||
pPlayer->PickupObject( this );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass up so we still call any custom Use function
|
||||
BaseClass::Use( pActivator, pCaller, useType, value );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Timed grenade, this think is called when time runs out.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
SetThink( &CBaseGrenade::Detonate );
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
void CBaseGrenade::PreDetonate( void )
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 400, 1.5, this );
|
||||
#endif
|
||||
|
||||
SetThink( &CBaseGrenade::Detonate );
|
||||
SetNextThink( gpGlobals->curtime + 1.5 );
|
||||
}
|
||||
|
||||
|
||||
void CBaseGrenade::Detonate( void )
|
||||
{
|
||||
trace_t tr;
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
SetThink( NULL );
|
||||
|
||||
vecSpot = GetAbsOrigin() + Vector ( 0 , 0 , 8 );
|
||||
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -32 ), MASK_SHOT_HULL, this, COLLISION_GROUP_NONE, & tr);
|
||||
|
||||
if( tr.startsolid )
|
||||
{
|
||||
// Since we blindly moved the explosion origin vertically, we may have inadvertently moved the explosion into a solid,
|
||||
// in which case nothing is going to be harmed by the grenade's explosion because all subsequent traces will startsolid.
|
||||
// If this is the case, we do the downward trace again from the actual origin of the grenade. (sjb) 3/8/2007 (for ep2_outland_09)
|
||||
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, -32), MASK_SHOT_HULL, this, COLLISION_GROUP_NONE, &tr );
|
||||
}
|
||||
|
||||
Explode( &tr, DMG_BLAST );
|
||||
|
||||
if ( GetShakeAmplitude() )
|
||||
{
|
||||
UTIL_ScreenShake( GetAbsOrigin(), GetShakeAmplitude(), 150.0, 1.0, GetShakeRadius(), SHAKE_START );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Contact grenade, explode when it touches something
|
||||
//
|
||||
void CBaseGrenade::ExplodeTouch( CBaseEntity *pOther )
|
||||
{
|
||||
trace_t tr;
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
Assert( pOther );
|
||||
if ( !pOther->IsSolid() )
|
||||
return;
|
||||
|
||||
Vector velDir = GetAbsVelocity();
|
||||
VectorNormalize( velDir );
|
||||
vecSpot = GetAbsOrigin() - velDir * 32;
|
||||
UTIL_TraceLine( vecSpot, vecSpot + velDir * 64, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
Explode( &tr, DMG_BLAST );
|
||||
}
|
||||
|
||||
|
||||
void CBaseGrenade::DangerSoundThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
Remove( );
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2, this );
|
||||
#endif
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.2 );
|
||||
|
||||
if (GetWaterLevel() != WL_NotInWater)
|
||||
{
|
||||
SetAbsVelocity( GetAbsVelocity() * 0.5 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBaseGrenade::BounceTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS) )
|
||||
return;
|
||||
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pOther == GetThrower() )
|
||||
return;
|
||||
|
||||
// only do damage if we're moving fairly fast
|
||||
if ( (pOther->m_takedamage != DAMAGE_NO) && (m_flNextAttack < gpGlobals->curtime && GetAbsVelocity().Length() > 100))
|
||||
{
|
||||
if (m_hThrower)
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
trace_t tr;
|
||||
tr = CBaseEntity::GetTouchTrace( );
|
||||
ClearMultiDamage( );
|
||||
Vector forward;
|
||||
AngleVectors( GetLocalAngles(), &forward, NULL, NULL );
|
||||
CTakeDamageInfo info( this, m_hThrower, 1, DMG_CLUB );
|
||||
CalculateMeleeDamageForce( &info, GetAbsVelocity(), GetAbsOrigin() );
|
||||
pOther->DispatchTraceAttack( info, forward, &tr );
|
||||
ApplyMultiDamage();
|
||||
#endif
|
||||
}
|
||||
m_flNextAttack = gpGlobals->curtime + 1.0; // debounce
|
||||
}
|
||||
|
||||
Vector vecTestVelocity;
|
||||
// m_vecAngVelocity = Vector (300, 300, 300);
|
||||
|
||||
// this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical
|
||||
// or thrown very far tend to slow down too quickly for me to always catch just by testing velocity.
|
||||
// trimming the Z velocity a bit seems to help quite a bit.
|
||||
vecTestVelocity = GetAbsVelocity();
|
||||
vecTestVelocity.z *= 0.45;
|
||||
|
||||
if ( !m_bHasWarnedAI && vecTestVelocity.Length() <= 60 )
|
||||
{
|
||||
// grenade is moving really slow. It's probably very close to where it will ultimately stop moving.
|
||||
// emit the danger sound.
|
||||
|
||||
// register a radius louder than the explosion, so we make sure everyone gets out of the way
|
||||
#if !defined( CLIENT_DLL )
|
||||
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), m_flDamage / 0.4, 0.3, this );
|
||||
#endif
|
||||
m_bHasWarnedAI = true;
|
||||
}
|
||||
|
||||
if (GetFlags() & FL_ONGROUND)
|
||||
{
|
||||
// add a bit of static friction
|
||||
// SetAbsVelocity( GetAbsVelocity() * 0.8 );
|
||||
|
||||
// SetSequence( random->RandomInt( 1, 1 ) ); // FIXME: missing tumble animations
|
||||
}
|
||||
else
|
||||
{
|
||||
// play bounce sound
|
||||
BounceSound();
|
||||
}
|
||||
m_flPlaybackRate = GetAbsVelocity().Length() / 200.0;
|
||||
if (GetPlaybackRate() > 1.0)
|
||||
m_flPlaybackRate = 1;
|
||||
else if (GetPlaybackRate() < 0.5)
|
||||
m_flPlaybackRate = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CBaseGrenade::SlideTouch( CBaseEntity *pOther )
|
||||
{
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pOther == GetThrower() )
|
||||
return;
|
||||
|
||||
// m_vecAngVelocity = Vector (300, 300, 300);
|
||||
|
||||
if (GetFlags() & FL_ONGROUND)
|
||||
{
|
||||
// add a bit of static friction
|
||||
// SetAbsVelocity( GetAbsVelocity() * 0.95 );
|
||||
|
||||
if (GetAbsVelocity().x != 0 || GetAbsVelocity().y != 0)
|
||||
{
|
||||
// maintain sliding sound
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BounceSound();
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseGrenade ::BounceSound( void )
|
||||
{
|
||||
// Doesn't need to do anything anymore! Physics makes the sound.
|
||||
}
|
||||
|
||||
void CBaseGrenade ::TumbleThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
Remove( );
|
||||
return;
|
||||
}
|
||||
|
||||
StudioFrameAdvance( );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
//
|
||||
// Emit a danger sound one second before exploding.
|
||||
//
|
||||
if (m_flDetonateTime - 1 < gpGlobals->curtime)
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * (m_flDetonateTime - gpGlobals->curtime), 400, 0.1, this );
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_flDetonateTime <= gpGlobals->curtime)
|
||||
{
|
||||
SetThink( &CBaseGrenade::Detonate );
|
||||
}
|
||||
|
||||
if (GetWaterLevel() != WL_NotInWater)
|
||||
{
|
||||
SetAbsVelocity( GetAbsVelocity() * 0.5 );
|
||||
m_flPlaybackRate = 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseGrenade::Precache( void )
|
||||
{
|
||||
BaseClass::Precache( );
|
||||
|
||||
PrecacheScriptSound( "BaseGrenade.Explode" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CBaseCombatCharacter
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatCharacter *CBaseGrenade::GetThrower( void )
|
||||
{
|
||||
CBaseCombatCharacter *pResult = ToBaseCombatCharacter( m_hThrower );
|
||||
if ( !pResult && GetOwnerEntity() != NULL )
|
||||
{
|
||||
pResult = ToBaseCombatCharacter( GetOwnerEntity() );
|
||||
}
|
||||
return pResult;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CBaseGrenade::SetThrower( CBaseCombatCharacter *pThrower )
|
||||
{
|
||||
m_hThrower = pThrower;
|
||||
|
||||
// if this is the first thrower, set it as the original thrower
|
||||
if ( NULL == m_hOriginalThrower )
|
||||
{
|
||||
m_hOriginalThrower = pThrower;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseGrenade::~CBaseGrenade(void)
|
||||
{
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseGrenade::CBaseGrenade(void)
|
||||
#ifdef CLIENT_DLL
|
||||
:m_GlowObject( this, Vector( 1.0f, 1.0f, 1.0f ), 0.0f, false, false )
|
||||
#endif
|
||||
{
|
||||
m_hThrower = NULL;
|
||||
m_hOriginalThrower = NULL;
|
||||
m_bIsLive = false;
|
||||
m_DmgRadius = 100;
|
||||
m_flDetonateTime = 0;
|
||||
m_bHasWarnedAI = false;
|
||||
|
||||
SetSimulatedEveryTick( true );
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASEGRENADE_SHARED_H
|
||||
#define BASEGRENADE_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CBaseGrenade C_BaseGrenade
|
||||
|
||||
#include "c_basecombatcharacter.h"
|
||||
#include "glow_outline_effect.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "basecombatcharacter.h"
|
||||
#include "player_pickup.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "cs_shareddefs.h"
|
||||
|
||||
#define BASEGRENADE_EXPLOSION_VOLUME 1024
|
||||
|
||||
class CTakeDamageInfo;
|
||||
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
class CBaseGrenade : public CBaseAnimating, public CDefaultPlayerPickupVPhysics
|
||||
#else
|
||||
class CBaseGrenade : public CBaseAnimating
|
||||
#endif
|
||||
{
|
||||
DECLARE_CLASS( CBaseGrenade, CBaseAnimating );
|
||||
public:
|
||||
|
||||
CBaseGrenade(void);
|
||||
~CBaseGrenade(void);
|
||||
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_NETWORKCLASS();
|
||||
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
virtual void Precache( void );
|
||||
|
||||
virtual void Explode( trace_t *pTrace, int bitsDamageType );
|
||||
void Smoke( void );
|
||||
|
||||
void BounceTouch( CBaseEntity *pOther );
|
||||
void SlideTouch( CBaseEntity *pOther );
|
||||
void ExplodeTouch( CBaseEntity *pOther );
|
||||
void DangerSoundThink( void );
|
||||
void PreDetonate( void );
|
||||
virtual void Detonate( void );
|
||||
void DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void TumbleThink( void );
|
||||
|
||||
virtual Vector GetBlastForce() { return vec3_origin; }
|
||||
|
||||
virtual void BounceSound( void );
|
||||
virtual int BloodColor( void ) { return DONT_BLEED; }
|
||||
virtual void Event_Killed( const CTakeDamageInfo &info );
|
||||
|
||||
virtual float GetShakeAmplitude( void ) { return 25.0; }
|
||||
virtual float GetShakeRadius( void ) { return 750.0; }
|
||||
|
||||
virtual const char *GetParticleSystemName( int pointContents, surfacedata_t *pdata = NULL ) { return NULL; }
|
||||
|
||||
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_EXPLOSIVE; }
|
||||
|
||||
// Damage accessors.
|
||||
virtual float GetDamage()
|
||||
{
|
||||
return m_flDamage;
|
||||
}
|
||||
virtual float GetDamageRadius()
|
||||
{
|
||||
return m_DmgRadius;
|
||||
}
|
||||
|
||||
virtual void SetDamage(float flDamage)
|
||||
{
|
||||
m_flDamage = flDamage;
|
||||
}
|
||||
|
||||
virtual void SetDamageRadius(float flDamageRadius)
|
||||
{
|
||||
m_DmgRadius = flDamageRadius;
|
||||
}
|
||||
|
||||
// Bounce sound accessors.
|
||||
void SetBounceSound( const char *pszBounceSound )
|
||||
{
|
||||
m_iszBounceSound = MAKE_STRING( pszBounceSound );
|
||||
}
|
||||
|
||||
CBaseCombatCharacter *GetThrower( void );
|
||||
void SetThrower( CBaseCombatCharacter *pThrower );
|
||||
CBaseEntity *GetOriginalThrower() { return m_hOriginalThrower; }
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
// Allow +USE pickup
|
||||
int ObjectCaps()
|
||||
{
|
||||
return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS);
|
||||
}
|
||||
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
#endif
|
||||
|
||||
public:
|
||||
IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_vecVelocity );
|
||||
IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_fFlags );
|
||||
|
||||
bool m_bHasWarnedAI; // whether or not this grenade has issued its DANGER sound to the world sound list yet.
|
||||
CNetworkVar( bool, m_bIsLive ); // Is this grenade live, or can it be picked up?
|
||||
CNetworkVar( float, m_DmgRadius ); // How far do I do damage?
|
||||
CNetworkVar( float, m_flNextAttack );
|
||||
float m_flDetonateTime; // Time at which to detonate.
|
||||
float m_flWarnAITime; // Time at which to warn the AI
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
CGlowObject m_GlowObject;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
CNetworkVar( float, m_flDamage ); // Damage to inflict.
|
||||
string_t m_iszBounceSound; // The sound to make on bouncing. If not NULL, overrides the BounceSound() function.
|
||||
|
||||
private:
|
||||
CNetworkHandle( CBaseEntity, m_hThrower ); // Who threw this grenade
|
||||
EHANDLE m_hOriginalThrower; // Who was the original thrower of this grenade
|
||||
|
||||
CBaseGrenade( const CBaseGrenade & ); // not defined, not accessible
|
||||
|
||||
};
|
||||
|
||||
#endif // BASEGRENADE_SHARED_H
|
||||
@@ -0,0 +1,115 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "baseparticleentity.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "toolframework_client.h"
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseParticleEntity, DT_BaseParticleEntity )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CBaseParticleEntity, DT_BaseParticleEntity )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CBaseParticleEntity )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
REGISTER_EFFECT( CBaseParticleEntity );
|
||||
#endif
|
||||
|
||||
CBaseParticleEntity::CBaseParticleEntity( void )
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
m_bSimulate = true;
|
||||
m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID;
|
||||
#endif
|
||||
}
|
||||
|
||||
CBaseParticleEntity::~CBaseParticleEntity( void )
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
if ( ToolsEnabled() && ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID ) && clienttools->IsInRecordingMode() )
|
||||
{
|
||||
KeyValues *msg = new KeyValues( "OldParticleSystem_Destroy" );
|
||||
msg->SetInt( "id", m_nToolParticleEffectId );
|
||||
m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
int CBaseParticleEntity::UpdateTransmitState( void )
|
||||
{
|
||||
if ( IsEffectActive( EF_NODRAW ) )
|
||||
return SetTransmitState( FL_EDICT_DONTSEND );
|
||||
|
||||
if ( IsEFlagSet( EFL_IN_SKYBOX ) )
|
||||
return SetTransmitState( FL_EDICT_ALWAYS );
|
||||
|
||||
// cull against PVS
|
||||
return SetTransmitState( FL_EDICT_PVSCHECK );
|
||||
}
|
||||
#endif
|
||||
|
||||
void CBaseParticleEntity::Activate()
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
BaseClass::Activate();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CBaseParticleEntity::Think()
|
||||
{
|
||||
Remove( );
|
||||
}
|
||||
|
||||
|
||||
void CBaseParticleEntity::FollowEntity(CBaseEntity *pEntity)
|
||||
{
|
||||
BaseClass::FollowEntity( pEntity );
|
||||
SetLocalOrigin( vec3_origin );
|
||||
}
|
||||
|
||||
|
||||
void CBaseParticleEntity::SetLifetime(float lifetime)
|
||||
{
|
||||
if(lifetime == -1)
|
||||
SetNextThink( TICK_NEVER_THINK );
|
||||
else
|
||||
SetNextThink( gpGlobals->curtime + lifetime );
|
||||
}
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
const Vector &CBaseParticleEntity::GetSortOrigin()
|
||||
{
|
||||
// By default, we do the cheaper behavior of getting the root parent's abs origin, so we don't have to
|
||||
// setup any bones along the way. If this screws anything up, we can always make it an option.
|
||||
return GetRootMoveParent()->GetAbsOrigin();
|
||||
}
|
||||
|
||||
void CBaseParticleEntity::SimulateParticles( CParticleSimulateIterator *pIterator )
|
||||
{
|
||||
// If you derive from CBaseParticleEntity, you must implement simulation and rendering.
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
void CBaseParticleEntity::RenderParticles( CParticleRenderIterator *pIterator )
|
||||
{
|
||||
// If you derive from CBaseParticleEntity, you must implement simulation and rendering.
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
// Particle system entities can derive from this to handle some of the mundane
|
||||
// functionality of hooking into the engine's entity system.
|
||||
|
||||
#ifndef PARTICLE_BASEEFFECT_H
|
||||
#define PARTICLE_BASEEFFECT_H
|
||||
|
||||
#include "predictable_entity.h"
|
||||
#include "baseentity_shared.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CBaseParticleEntity C_BaseParticleEntity
|
||||
|
||||
#include "particlemgr.h"
|
||||
|
||||
#endif
|
||||
|
||||
class CBaseParticleEntity : public CBaseEntity
|
||||
#if defined( CLIENT_DLL )
|
||||
, public IParticleEffect
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBaseParticleEntity, CBaseEntity );
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_NETWORKCLASS();
|
||||
|
||||
CBaseParticleEntity();
|
||||
virtual ~CBaseParticleEntity();
|
||||
|
||||
// CBaseEntity overrides.
|
||||
public:
|
||||
#if !defined( CLIENT_DLL )
|
||||
virtual int UpdateTransmitState( void );
|
||||
#else
|
||||
// Default IParticleEffect overrides.
|
||||
public:
|
||||
|
||||
virtual bool ShouldSimulate() const { return m_bSimulate; }
|
||||
virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; }
|
||||
|
||||
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
|
||||
virtual void RenderParticles( CParticleRenderIterator *pIterator );
|
||||
virtual const Vector & GetSortOrigin();
|
||||
public:
|
||||
CParticleEffectBinding m_ParticleEffect;
|
||||
#endif
|
||||
|
||||
virtual void Activate();
|
||||
virtual void Think();
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
// NOTE: Ths enclosed particle effect binding will do all the drawing
|
||||
virtual bool ShouldDraw() { return false; }
|
||||
|
||||
int AllocateToolParticleEffectId();
|
||||
int GetToolParticleEffectId() const;
|
||||
|
||||
private:
|
||||
int m_nToolParticleEffectId;
|
||||
bool m_bSimulate;
|
||||
#endif
|
||||
|
||||
public:
|
||||
void FollowEntity(CBaseEntity *pEntity);
|
||||
|
||||
// UTIL_Remove will be called after the specified amount of time.
|
||||
// If you pass in -1, the entity will never go away automatically.
|
||||
void SetLifetime(float lifetime);
|
||||
|
||||
private:
|
||||
CBaseParticleEntity( const CBaseParticleEntity & ); // not defined, not accessible
|
||||
};
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
inline int CBaseParticleEntity::GetToolParticleEffectId() const
|
||||
{
|
||||
return m_nToolParticleEffectId;
|
||||
}
|
||||
|
||||
inline int CBaseParticleEntity::AllocateToolParticleEffectId()
|
||||
{
|
||||
m_nToolParticleEffectId = ParticleMgr()->AllocateToolParticleEffectId();
|
||||
return m_nToolParticleEffectId;
|
||||
}
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,137 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASEPLAYER_SHARED_H
|
||||
#define BASEPLAYER_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// PlayerUse defines
|
||||
#ifdef PORTAL2
|
||||
#define PLAYER_USE_RADIUS 100.f
|
||||
#else
|
||||
#define PLAYER_USE_RADIUS 80.f
|
||||
#define PLAYER_USE_BOT_RADIUS 140.f
|
||||
#endif // PORTAL2
|
||||
|
||||
#define CONE_45_DEGREES 0.707f
|
||||
#define CONE_15_DEGREES 0.9659258f
|
||||
#define CONE_90_DEGREES 0
|
||||
|
||||
#define TRAIN_ACTIVE 0x80
|
||||
#define TRAIN_NEW 0xc0
|
||||
#define TRAIN_OFF 0x00
|
||||
#define TRAIN_NEUTRAL 0x01
|
||||
#define TRAIN_SLOW 0x02
|
||||
#define TRAIN_MEDIUM 0x03
|
||||
#define TRAIN_FAST 0x04
|
||||
#define TRAIN_BACK 0x05
|
||||
|
||||
// entity messages
|
||||
#define UPDATE_PLAYER_RADAR 2
|
||||
|
||||
#define DEATH_ANIMATION_TIME 3.0f
|
||||
|
||||
// multiplayer only
|
||||
#define NOINTERP_PARITY_MAX 4
|
||||
#define NOINTERP_PARITY_MAX_BITS 2
|
||||
|
||||
struct autoaim_params_t
|
||||
{
|
||||
autoaim_params_t()
|
||||
{
|
||||
m_fScale = 0;
|
||||
m_fMaxDist = 0;
|
||||
m_fMaxDeflection = -1.0f;
|
||||
m_bOnTargetQueryOnly = false;
|
||||
}
|
||||
|
||||
Vector m_vecAutoAimDir; // Output: The direction autoaim wishes to point.
|
||||
Vector m_vecAutoAimPoint; // Output: The point (world space) that autoaim is aiming at.
|
||||
EHANDLE m_hAutoAimEntity; // Output: The entity that autoaim is aiming at.
|
||||
float m_fScale; // Input:
|
||||
float m_fMaxDist; // Input:
|
||||
float m_fMaxDeflection; // Input:
|
||||
bool m_bOnTargetQueryOnly; // Input: Don't do expensive assistance, just resolve m_bOnTargetNatural
|
||||
bool m_bAutoAimAssisting; // Output: If this is true, autoaim is aiming at the target.
|
||||
bool m_bOnTargetNatural; // Output: If true, the player is on target without assistance.
|
||||
};
|
||||
|
||||
enum stepsoundtimes_t
|
||||
{
|
||||
STEPSOUNDTIME_NORMAL = 0,
|
||||
STEPSOUNDTIME_ON_LADDER,
|
||||
STEPSOUNDTIME_WATER_KNEE,
|
||||
STEPSOUNDTIME_WATER_FOOT,
|
||||
};
|
||||
|
||||
//
|
||||
// Player PHYSICS FLAGS bits
|
||||
//
|
||||
enum PlayerPhysFlag_e
|
||||
{
|
||||
PFLAG_DIROVERRIDE = ( 1<<0 ), // override the player's directional control (trains, physics gun, etc.)
|
||||
PFLAG_DUCKING = ( 1<<1 ), // In the process of ducking, but totally squatted yet
|
||||
PFLAG_USING = ( 1<<2 ), // Using a continuous entity
|
||||
PFLAG_OBSERVER = ( 1<<3 ), // player is locked in stationary cam mode. Spectators can move, observers can't.
|
||||
PFLAG_VPHYSICS_MOTIONCONTROLLER = ( 1<<4 ), // player is physically attached to a motion controller
|
||||
PFLAG_GAMEPHYSICS_ROTPUSH = (1<<5), // game physics did a rotating push that we may want to override with vphysics
|
||||
|
||||
// If you add another flag here check that you aren't
|
||||
// overwriting phys flags in the HL2 of TF2 player classes
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VPHYS_WALK = 0,
|
||||
VPHYS_CROUCH,
|
||||
VPHYS_NOCLIP,
|
||||
};
|
||||
|
||||
// useful cosines
|
||||
#define DOT_1DEGREE 0.9998476951564
|
||||
#define DOT_2DEGREE 0.9993908270191
|
||||
#define DOT_3DEGREE 0.9986295347546
|
||||
#define DOT_4DEGREE 0.9975640502598
|
||||
#define DOT_5DEGREE 0.9961946980917
|
||||
#define DOT_6DEGREE 0.9945218953683
|
||||
#define DOT_7DEGREE 0.9925461516413
|
||||
#define DOT_8DEGREE 0.9902680687416
|
||||
#define DOT_9DEGREE 0.9876883405951
|
||||
#define DOT_10DEGREE 0.9848077530122
|
||||
#define DOT_15DEGREE 0.9659258262891
|
||||
#define DOT_20DEGREE 0.9396926207859
|
||||
#define DOT_25DEGREE 0.9063077870367
|
||||
#define DOT_30DEGREE 0.866025403784
|
||||
#define DOT_45DEGREE 0.707106781187
|
||||
|
||||
//#define DEBUG_MOTION_CONTROLLERS //uncomment to spew debug data while in a motion controller
|
||||
|
||||
|
||||
enum HltvUiType_t
|
||||
{
|
||||
HLTV_UI_XRAY_ON = 0,
|
||||
HLTV_UI_XRAY_OFF,
|
||||
HLTV_UI_SCOREBOARD_ON,
|
||||
HLTV_UI_SCOREBOARD_OFF,
|
||||
HLTV_UI_OVERVIEW_ON,
|
||||
HLTV_UI_OVERVIEW_OFF,
|
||||
HLTV_UI_GRAPHS_ON,
|
||||
HLTV_UI_GRAPHS_OFF
|
||||
};
|
||||
|
||||
|
||||
// Shared header file for players
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CBasePlayer C_BasePlayer
|
||||
#include "c_baseplayer.h"
|
||||
#else
|
||||
#include "player.h"
|
||||
#endif
|
||||
|
||||
#endif // BASEPLAYER_SHARED_H
|
||||
@@ -0,0 +1,780 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "baseviewmodel_shared.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
|
||||
#include "cs_shareddefs.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "iprediction.h"
|
||||
#include "prediction.h"
|
||||
#include "inputsystem/iinputsystem.h"
|
||||
#include "iclientmode.h"
|
||||
|
||||
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
|
||||
#include "weapon_basecsgrenade.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include "vguiscreen.h"
|
||||
#endif
|
||||
|
||||
#if defined( CLIENT_DLL ) && defined( SIXENSE )
|
||||
#include "sixense/in_sixense.h"
|
||||
#include "sixense/sixense_convars_extern.h"
|
||||
#endif
|
||||
|
||||
extern ConVar in_forceuser;
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define VIEWMODEL_ANIMATION_PARITY_BITS 3
|
||||
#define SCREEN_OVERLAY_MATERIAL "vgui/screens/vgui_overlay"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
ConVar viewmodel_offset_x( "viewmodel_offset_x", "0.0", FCVAR_ARCHIVE ); // the viewmodel offset from default in X
|
||||
ConVar viewmodel_offset_y( "viewmodel_offset_y", "0.0", FCVAR_ARCHIVE ); // the viewmodel offset from default in Y
|
||||
ConVar viewmodel_offset_z( "viewmodel_offset_z", "0.0", FCVAR_ARCHIVE ); // the viewmodel offset from default in Z
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseViewModel::CBaseViewModel()
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
// NOTE: We do this here because the color is never transmitted for the view model.
|
||||
m_nOldAnimationParity = 0;
|
||||
m_EntClientFlags |= ENTCLIENTFLAG_ALWAYS_INTERPOLATE;
|
||||
RenderWithViewModels( true );
|
||||
m_flStatTrakGlowMultiplier = 0.0f;
|
||||
m_flStatTrakGlowMultiplierIdeal = 0.0f;
|
||||
m_szLastSound[0] = '\0';
|
||||
m_flLastSoundTime = 0.0f;
|
||||
|
||||
m_flCamDriverAppliedTime = 0;
|
||||
m_flCamDriverWeight = 0;
|
||||
m_vecCamDriverLastPos.Init();
|
||||
m_angCamDriverLastAng.Init();
|
||||
|
||||
#ifdef IRONSIGHT
|
||||
m_bScopeStencilMaskModeEnabled = false;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
SetRenderColor( 255, 255, 255 );
|
||||
SetRenderAlpha( 255 );
|
||||
|
||||
// View model of this weapon
|
||||
m_sVMName = NULL_STRING;
|
||||
// Prefix of the animations that should be used by the player carrying this weapon
|
||||
m_sAnimationPrefix = NULL_STRING;
|
||||
|
||||
m_nViewModelIndex = 0;
|
||||
|
||||
m_nAnimationParity = 0;
|
||||
|
||||
m_bShouldIgnoreOffsetAndAccuracy = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseViewModel::~CBaseViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
void CBaseViewModel::UpdateOnRemove( void )
|
||||
{
|
||||
BaseClass::UpdateOnRemove();
|
||||
|
||||
DestroyControlPanels();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::Precache( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::Spawn( void )
|
||||
{
|
||||
Precache( );
|
||||
SetSize( Vector( -8, -4, -2), Vector(8, 4, 2) );
|
||||
SetSolid( SOLID_NONE );
|
||||
}
|
||||
|
||||
|
||||
#if defined ( CSTRIKE_DLL ) && !defined ( CLIENT_DLL )
|
||||
#define VGUI_CONTROL_PANELS
|
||||
#endif
|
||||
|
||||
#if defined ( TF_DLL )
|
||||
#define VGUI_CONTROL_PANELS
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::SetControlPanelsActive( bool bState )
|
||||
{
|
||||
#if defined( VGUI_CONTROL_PANELS )
|
||||
// Activate control panel screens
|
||||
for ( int i = m_hScreens.Count(); --i >= 0; )
|
||||
{
|
||||
if (m_hScreens[i].Get())
|
||||
{
|
||||
m_hScreens[i]->SetActive( bState );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This is called by the base object when it's time to spawn the control panels
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::SpawnControlPanels()
|
||||
{
|
||||
#if defined( VGUI_CONTROL_PANELS )
|
||||
char buf[64];
|
||||
|
||||
// Destroy existing panels
|
||||
DestroyControlPanels();
|
||||
|
||||
CBaseCombatWeapon *weapon = m_hWeapon.Get();
|
||||
|
||||
if ( weapon == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
|
||||
// FIXME: Deal with dynamically resizing control panels?
|
||||
|
||||
// If we're attached to an entity, spawn control panels on it instead of use
|
||||
CBaseAnimating *pEntityToSpawnOn = this;
|
||||
char *pOrgLL = "controlpanel%d_ll";
|
||||
char *pOrgUR = "controlpanel%d_ur";
|
||||
char *pAttachmentNameLL = pOrgLL;
|
||||
char *pAttachmentNameUR = pOrgUR;
|
||||
/*
|
||||
if ( IsBuiltOnAttachment() )
|
||||
{
|
||||
pEntityToSpawnOn = dynamic_cast<CBaseAnimating*>((CBaseEntity*)m_hBuiltOnEntity.Get());
|
||||
if ( pEntityToSpawnOn )
|
||||
{
|
||||
char sBuildPointLL[64];
|
||||
char sBuildPointUR[64];
|
||||
Q_snprintf( sBuildPointLL, sizeof( sBuildPointLL ), "bp%d_controlpanel%%d_ll", m_iBuiltOnPoint );
|
||||
Q_snprintf( sBuildPointUR, sizeof( sBuildPointUR ), "bp%d_controlpanel%%d_ur", m_iBuiltOnPoint );
|
||||
pAttachmentNameLL = sBuildPointLL;
|
||||
pAttachmentNameUR = sBuildPointUR;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEntityToSpawnOn = this;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Assert( pEntityToSpawnOn );
|
||||
|
||||
// Lookup the attachment point...
|
||||
int nPanel;
|
||||
for ( nPanel = 0; true; ++nPanel )
|
||||
{
|
||||
Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel );
|
||||
int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
|
||||
if (nLLAttachmentIndex <= 0)
|
||||
{
|
||||
// Try and use my panels then
|
||||
pEntityToSpawnOn = this;
|
||||
Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel );
|
||||
nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
|
||||
if (nLLAttachmentIndex <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel );
|
||||
int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
|
||||
if (nURAttachmentIndex <= 0)
|
||||
{
|
||||
// Try and use my panels then
|
||||
Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel );
|
||||
nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
|
||||
if (nURAttachmentIndex <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
const char *pScreenName;
|
||||
weapon->GetControlPanelInfo( nPanel, pScreenName );
|
||||
if (!pScreenName)
|
||||
continue;
|
||||
|
||||
const char *pScreenClassname;
|
||||
weapon->GetControlPanelClassName( nPanel, pScreenClassname );
|
||||
if ( !pScreenClassname )
|
||||
continue;
|
||||
|
||||
// Compute the screen size from the attachment points...
|
||||
matrix3x4_t panelToWorld;
|
||||
pEntityToSpawnOn->GetAttachment( nLLAttachmentIndex, panelToWorld );
|
||||
|
||||
matrix3x4_t worldToPanel;
|
||||
MatrixInvert( panelToWorld, worldToPanel );
|
||||
|
||||
// Now get the lower right position + transform into panel space
|
||||
Vector lr, lrlocal;
|
||||
pEntityToSpawnOn->GetAttachment( nURAttachmentIndex, panelToWorld );
|
||||
MatrixGetColumn( panelToWorld, 3, lr );
|
||||
VectorTransform( lr, worldToPanel, lrlocal );
|
||||
|
||||
// Not sure why, but the transform for the vgui panel to the world is improperly scaling.
|
||||
// We add a fudge value here to compensate.
|
||||
const float SCALE_FUDGE = 1.6f;
|
||||
float flWidth = fabs( lrlocal.x ) * SCALE_FUDGE;
|
||||
float flHeight = fabs( lrlocal.y ) * SCALE_FUDGE;
|
||||
|
||||
CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, pEntityToSpawnOn, this, nLLAttachmentIndex );
|
||||
pScreen->ChangeTeam( GetTeamNumber() );
|
||||
pScreen->SetActualSize( flWidth, flHeight );
|
||||
pScreen->SetActive( false );
|
||||
pScreen->MakeVisibleOnlyToTeammates( false );
|
||||
|
||||
pScreen->SetAttachedToViewModel( true );
|
||||
int nScreen = m_hScreens.AddToTail( );
|
||||
m_hScreens[nScreen].Set( pScreen );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBaseViewModel::DestroyControlPanels()
|
||||
{
|
||||
#if defined( VGUI_CONTROL_PANELS )
|
||||
// Kill the control panels
|
||||
int i;
|
||||
for ( i = m_hScreens.Count(); --i >= 0; )
|
||||
{
|
||||
DestroyVGuiScreen( m_hScreens[i].Get() );
|
||||
}
|
||||
m_hScreens.RemoveAll();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pEntity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::SetOwner( CBaseEntity *pEntity )
|
||||
{
|
||||
m_hOwner = pEntity;
|
||||
#if !defined( CLIENT_DLL )
|
||||
// Make sure we're linked into hierarchy
|
||||
//SetParent( pEntity );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nIndex -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::SetIndex( int nIndex )
|
||||
{
|
||||
m_nViewModelIndex = nIndex;
|
||||
Assert( m_nViewModelIndex < (1 << VIEWMODEL_INDEX_BITS) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CBaseViewModel::ViewModelIndex( ) const
|
||||
{
|
||||
return m_nViewModelIndex;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pass our visibility on to our child screens
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::AddEffects( int nEffects )
|
||||
{
|
||||
if ( nEffects & EF_NODRAW )
|
||||
{
|
||||
SetControlPanelsActive( false );
|
||||
}
|
||||
|
||||
BaseClass::AddEffects( nEffects );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pass our visibility on to our child screens
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::RemoveEffects( int nEffects )
|
||||
{
|
||||
if ( nEffects & EF_NODRAW )
|
||||
{
|
||||
SetControlPanelsActive( true );
|
||||
}
|
||||
|
||||
BaseClass::RemoveEffects( nEffects );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *modelname -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::SetWeaponModel( const char *modelname, CBaseCombatWeapon *weapon )
|
||||
{
|
||||
m_hWeapon = weapon;
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
SetModel( modelname );
|
||||
#else
|
||||
string_t str;
|
||||
if ( modelname != NULL )
|
||||
{
|
||||
str = MAKE_STRING( modelname );
|
||||
}
|
||||
else
|
||||
{
|
||||
str = NULL_STRING;
|
||||
}
|
||||
|
||||
if ( str != m_sVMName )
|
||||
{
|
||||
// Msg( "SetWeaponModel %s at %f\n", modelname, gpGlobals->curtime );
|
||||
m_sVMName = str;
|
||||
SetModel( STRING( m_sVMName ) );
|
||||
|
||||
// Create any vgui control panels associated with the weapon
|
||||
SpawnControlPanels();
|
||||
|
||||
bool showControlPanels = weapon && weapon->ShouldShowControlPanels();
|
||||
SetControlPanelsActive( showControlPanels );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CBaseCombatWeapon
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCombatWeapon *CBaseViewModel::GetOwningWeapon( void )
|
||||
{
|
||||
return m_hWeapon.Get();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : sequence -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::SendViewModelMatchingSequence( int sequence )
|
||||
{
|
||||
// since all we do is send a sequence number down to the client,
|
||||
// set this here so other weapons code knows which sequence is playing.
|
||||
SetSequence( sequence );
|
||||
|
||||
m_nAnimationParity = ( m_nAnimationParity + 1 ) & ( (1<<VIEWMODEL_ANIMATION_PARITY_BITS) - 1 );
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
m_nOldAnimationParity = m_nAnimationParity;
|
||||
|
||||
// Force frame interpolation to start at exactly frame zero
|
||||
m_flAnimTime = gpGlobals->curtime;
|
||||
#else
|
||||
CBaseCombatWeapon *weapon = m_hWeapon.Get();
|
||||
bool showControlPanels = weapon && weapon->ShouldShowControlPanels();
|
||||
SetControlPanelsActive( showControlPanels );
|
||||
#endif
|
||||
|
||||
// Restart animation at frame 0
|
||||
SetCycle( 0 );
|
||||
ResetSequenceInfo();
|
||||
}
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "ivieweffects.h"
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
void CBaseViewModel::PostBuildTransformations( CStudioHdr *pStudioHdr, BoneVector *pos, BoneQuaternion q[] )
|
||||
{
|
||||
int nCamDriverBone = LookupBone( "cam_driver" );
|
||||
if ( nCamDriverBone != -1 )
|
||||
{
|
||||
m_flCamDriverAppliedTime = gpGlobals->curtime;
|
||||
VectorCopy( pos[nCamDriverBone], m_vecCamDriverLastPos );
|
||||
QuaternionAngles( q[nCamDriverBone], m_angCamDriverLastAng );
|
||||
|
||||
if ( ShouldFlipModel() )
|
||||
{
|
||||
m_angCamDriverLastAng[YAW] = -m_angCamDriverLastAng[YAW];
|
||||
m_vecCamDriverLastPos.y = -m_vecCamDriverLastPos.y;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CBaseViewModel::CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, const QAngle& eyeAngles )
|
||||
{
|
||||
|
||||
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
|
||||
#ifdef CLIENT_DLL
|
||||
// apply viewmodel pose param
|
||||
if ( owner )
|
||||
{
|
||||
CBaseCSGrenade* pGrenade = dynamic_cast<CBaseCSGrenade*>( owner->GetActiveWeapon() );
|
||||
if ( pGrenade )
|
||||
{
|
||||
int iPoseParam = LookupPoseParameter( "throwcharge" );
|
||||
if ( iPoseParam != -1 )
|
||||
SetPoseParameter( iPoseParam, clamp(pGrenade->ApproachThrownStrength(), 0.0f, 1.0f) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// UNDONE: Calc this on the server? Disabled for now as it seems unnecessary to have this info on the server
|
||||
#if defined( CLIENT_DLL )
|
||||
QAngle vmangoriginal = eyeAngles;
|
||||
QAngle vmangles = eyeAngles;
|
||||
Vector vmorigin = eyePosition;
|
||||
|
||||
Vector vecRight;
|
||||
Vector vecUp;
|
||||
Vector vecForward;
|
||||
AngleVectors( vmangoriginal, &vecForward, &vecRight, &vecUp );
|
||||
//Vector vecOffset = Vector( viewmodel_offset_x.GetFloat(), viewmodel_offset_y.GetFloat(), viewmodel_offset_z.GetFloat() );
|
||||
if ( !m_bShouldIgnoreOffsetAndAccuracy )
|
||||
{
|
||||
#ifdef IRONSIGHT
|
||||
CWeaponCSBase *pIronSightWeapon = (CWeaponCSBase*)owner->GetActiveWeapon();
|
||||
if ( pIronSightWeapon )
|
||||
{
|
||||
CIronSightController* pIronSightController = pIronSightWeapon->GetIronSightController();
|
||||
if ( pIronSightController && pIronSightController->IsInIronSight() )
|
||||
{
|
||||
float flInvIronSightAmount = ( 1.0f - pIronSightController->GetIronSightAmount() );
|
||||
|
||||
vecForward *= flInvIronSightAmount;
|
||||
vecUp *= flInvIronSightAmount;
|
||||
vecRight *= flInvIronSightAmount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
vmorigin += (vecForward * viewmodel_offset_y.GetFloat()) + (vecUp * viewmodel_offset_z.GetFloat()) + (vecRight * viewmodel_offset_x.GetFloat());
|
||||
}
|
||||
|
||||
// TrackIR
|
||||
if ( IsHeadTrackingEnabled() )
|
||||
{
|
||||
vmorigin = owner->EyePosition();
|
||||
VectorAngles( owner->GetAutoaimVector( AUTOAIM_5DEGREES ), vmangoriginal );
|
||||
vmangles = vmangoriginal;
|
||||
}
|
||||
// TrackIR
|
||||
|
||||
CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
|
||||
//Allow weapon lagging
|
||||
if ( pWeapon != NULL )
|
||||
{
|
||||
if ( !prediction->InPrediction() )
|
||||
{
|
||||
// add weapon-specific bob
|
||||
pWeapon->AddViewmodelBob( this, vmorigin, vmangles );
|
||||
#if defined ( CSTRIKE_DLL )
|
||||
CalcViewModelLag( vmorigin, vmangles, vmangoriginal );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Add model-specific bob even if no weapon associated (for head bob for off hand models)
|
||||
AddViewModelBob( owner, vmorigin, vmangles );
|
||||
#if !defined ( CSTRIKE_DLL )
|
||||
// This was causing weapon jitter when rotating in updated CS:S; original Source had this in above InPrediction block 07/14/10
|
||||
// Add lag
|
||||
CalcViewModelLag( vmorigin, vmangles, vmangoriginal );
|
||||
#endif
|
||||
|
||||
if ( !prediction->InPrediction() )
|
||||
{
|
||||
// Let the viewmodel shake at about 10% of the amplitude of the player's view
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( GetOwner() );
|
||||
GetViewEffects()->ApplyShake( vmorigin, vmangles, 0.1 );
|
||||
}
|
||||
|
||||
SetLocalOrigin( vmorigin );
|
||||
SetLocalAngles( vmangles );
|
||||
|
||||
#endif //#if defined( CLIENT_DLL )
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseViewModel::CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles )
|
||||
{
|
||||
Vector vOriginalOrigin = origin;
|
||||
QAngle vOriginalAngles = angles;
|
||||
|
||||
// Calculate our drift
|
||||
Vector forward;
|
||||
AngleVectors( angles, &forward, NULL, NULL );
|
||||
|
||||
if ( gpGlobals->frametime != 0.0f )
|
||||
{
|
||||
Vector vDifference;
|
||||
VectorSubtract( forward, m_vecLastFacing, vDifference );
|
||||
|
||||
float flSpeed = 5.0f;
|
||||
|
||||
// If we start to lag too far behind, we'll increase the "catch up" speed. Solves the problem with fast cl_yawspeed, m_yaw or joysticks
|
||||
// rotating quickly. The old code would slam lastfacing with origin causing the viewmodel to pop to a new position
|
||||
float flDiff = vDifference.Length();
|
||||
if ( flDiff > 1.5f )
|
||||
{
|
||||
float flScale = flDiff / 1.5f;
|
||||
flSpeed *= flScale;
|
||||
}
|
||||
|
||||
// FIXME: Needs to be predictable?
|
||||
VectorMA( m_vecLastFacing, flSpeed * gpGlobals->frametime, vDifference, m_vecLastFacing );
|
||||
// Make sure it doesn't grow out of control!!!
|
||||
VectorNormalize( m_vecLastFacing );
|
||||
VectorMA( origin, 5.0f, vDifference * -1.0f, origin );
|
||||
|
||||
Assert( m_vecLastFacing.IsValid() );
|
||||
}
|
||||
|
||||
#if !defined( PORTAL ) //floor/wall floor/floor portals cause a sudden and large pitch change, causing a pop unless we write a bunch of interpolation code. Easier to just disable this
|
||||
Vector right, up;
|
||||
AngleVectors( original_angles, &forward, &right, &up );
|
||||
|
||||
float pitch = original_angles[ PITCH ];
|
||||
if ( pitch > 180.0f )
|
||||
pitch -= 360.0f;
|
||||
else if ( pitch < -180.0f )
|
||||
pitch += 360.0f;
|
||||
|
||||
//FIXME: These are the old settings that caused too many exposed polys on some models
|
||||
VectorMA( origin, -pitch * 0.035f, forward, origin );
|
||||
VectorMA( origin, -pitch * 0.03f, right, origin );
|
||||
VectorMA( origin, -pitch * 0.02f, up, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stub to keep networking consistent for DEM files
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( CLIENT_DLL )
|
||||
extern void RecvProxy_EffectFlags( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
void RecvProxy_ViewmodelSequenceNum( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
void RecvProxy_Viewmodel( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Resets anim cycle when the server changes the weapon on us
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( CLIENT_DLL )
|
||||
static void RecvProxy_Weapon( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
CBaseViewModel *pViewModel = ((CBaseViewModel*)pStruct);
|
||||
CBaseCombatWeapon *pOldWeapon = pViewModel->GetOwningWeapon();
|
||||
bool bViewModelWasVisible = pViewModel->IsVisible();
|
||||
|
||||
// Chain through to the default recieve proxy ...
|
||||
RecvProxy_IntToEHandle( pData, pStruct, pOut );
|
||||
|
||||
// ... and reset our cycle index if the server is switching weapons on us
|
||||
CBaseCombatWeapon *pNewWeapon = pViewModel->GetOwningWeapon();
|
||||
if ( pNewWeapon != pOldWeapon || !bViewModelWasVisible )
|
||||
{
|
||||
// Restart animation at frame 0
|
||||
pViewModel->SetCycle( 0 );
|
||||
pViewModel->m_flAnimTime = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
|
||||
static void RecvProxy_Owner( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
CBaseViewModel *pViewModel = ( ( CBaseViewModel* )pStruct );
|
||||
//Msg( "BaseViewModel changed from (%d)%x", ( pViewModel->m_hOwner.GetForModify().GetSerialNumber(), pViewModel->m_hOwner.GetForModify().GetEntryIndex() ) );
|
||||
|
||||
// Chain through to the default recieve proxy ...
|
||||
RecvProxy_IntToEHandle( pData, pStruct, pOut );
|
||||
|
||||
//Msg( " to (%d)%x\n", ( pViewModel->m_hOwner.GetForModify().GetSerialNumber(), pViewModel->m_hOwner.GetForModify().GetEntryIndex() ) );
|
||||
pViewModel->UpdateVisibility(); // visibility of a viewmodel is owner-dependant, and other events like SetDormant() may happen out of order with setting owner, especially when doing full frame update after spectator mode, which happens most often (pretty much exclusively) after HLTV replay ends.
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseViewModel, DT_BaseViewModel )
|
||||
LINK_ENTITY_TO_CLASS_ALIASED( viewmodel, BaseViewModel );
|
||||
|
||||
BEGIN_NETWORK_TABLE_NOBASE(CBaseViewModel, DT_BaseViewModel)
|
||||
#if !defined( CLIENT_DLL )
|
||||
SendPropModelIndex(SENDINFO(m_nModelIndex)),
|
||||
SendPropEHandle (SENDINFO(m_hWeapon)),
|
||||
SendPropInt (SENDINFO(m_nBody), ANIMATION_BODY_BITS ), // increased to 32 bits to support number of bits equal to number of bodygroups
|
||||
SendPropInt (SENDINFO(m_nSkin), 10),
|
||||
SendPropInt (SENDINFO(m_nSequence), 8, SPROP_UNSIGNED),
|
||||
SendPropInt (SENDINFO(m_nViewModelIndex), VIEWMODEL_INDEX_BITS, SPROP_UNSIGNED),
|
||||
SendPropFloat (SENDINFO(m_flPlaybackRate), 8, SPROP_ROUNDUP, -4.0, 12.0f),
|
||||
SendPropInt (SENDINFO(m_fEffects), EF_MAX_BITS, SPROP_UNSIGNED),
|
||||
SendPropInt (SENDINFO(m_nAnimationParity), 3, SPROP_UNSIGNED ),
|
||||
SendPropEHandle (SENDINFO(m_hOwner)),
|
||||
|
||||
SendPropInt( SENDINFO( m_nNewSequenceParity ), EF_PARITY_BITS, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO( m_nResetEventsParity ), EF_PARITY_BITS, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO( m_nMuzzleFlashParity ), EF_MUZZLEFLASH_BITS, SPROP_UNSIGNED ),
|
||||
|
||||
SendPropBool( SENDINFO( m_bShouldIgnoreOffsetAndAccuracy ) ),
|
||||
#else
|
||||
RecvPropInt (RECVINFO(m_nModelIndex), 0, RecvProxy_Viewmodel ),
|
||||
RecvPropEHandle (RECVINFO(m_hWeapon), RecvProxy_Weapon ),
|
||||
RecvPropInt (RECVINFO(m_nSkin)),
|
||||
RecvPropInt (RECVINFO(m_nBody)),
|
||||
RecvPropInt (RECVINFO(m_nSequence), 0, RecvProxy_ViewmodelSequenceNum ),
|
||||
RecvPropInt (RECVINFO(m_nViewModelIndex)),
|
||||
RecvPropFloat (RECVINFO(m_flPlaybackRate)),
|
||||
RecvPropInt (RECVINFO(m_fEffects), 0, RecvProxy_EffectFlags ),
|
||||
RecvPropInt (RECVINFO(m_nAnimationParity)),
|
||||
RecvPropEHandle (RECVINFO(m_hOwner), RecvProxy_Owner ),
|
||||
|
||||
RecvPropInt( RECVINFO( m_nNewSequenceParity )),
|
||||
RecvPropInt( RECVINFO( m_nResetEventsParity )),
|
||||
RecvPropInt( RECVINFO( m_nMuzzleFlashParity )),
|
||||
|
||||
RecvPropBool( RECVINFO( m_bShouldIgnoreOffsetAndAccuracy ) ),
|
||||
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
BEGIN_PREDICTION_DATA( CBaseViewModel )
|
||||
|
||||
// Networked
|
||||
DEFINE_PRED_FIELD( m_nModelIndex, FIELD_SHORT, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
|
||||
DEFINE_PRED_FIELD( m_nSkin, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_nBody, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_nSequence, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_nViewModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD_TOL( m_flPlaybackRate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.125f ),
|
||||
DEFINE_PRED_FIELD( m_fEffects, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE ),
|
||||
DEFINE_PRED_FIELD( m_nAnimationParity, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_hWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flAnimTime, FIELD_FLOAT, 0 ),
|
||||
|
||||
DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
|
||||
DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
|
||||
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
// This needed to be done as a proxy for the surrounding box auto update when animations change.
|
||||
// This doesn't have to be done for view models as they don't affect the bounding box and it was
|
||||
// causing some timing problems with our world to view model under the covers swap.
|
||||
|
||||
// [msmith] Added back in for CS:GO because without this the m_nSequence number gets reset during prediction causing
|
||||
// view model animations to freeze up. This issue is probably caused by the fact that prediction doesn't fix up
|
||||
// m_nSequence, but this fixes it and makes it consistent with CS:S ... which also has the same prediction issues.
|
||||
void RecvProxy_ViewmodelSequenceNum( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
CBaseViewModel *model = (CBaseViewModel *)pStruct;
|
||||
if (pData->m_Value.m_Int != model->GetSequence())
|
||||
{
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
model->SetSequence(pData->m_Value.m_Int);
|
||||
model->m_flAnimTime = gpGlobals->curtime;
|
||||
model->SetCycle(0);
|
||||
}
|
||||
}
|
||||
|
||||
void RecvProxy_Viewmodel( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
// We assign the model index via the SetModelByIndex function so that the model pointer gets updated as soon as we change the model index.
|
||||
// This is necessary since this new model may be accessed with frame.
|
||||
// An example is the SetSequence code in RecvProxy_ViewmodelSequenceNum that checks to make sure the sequence number is in range of those available in
|
||||
// model.
|
||||
CBaseViewModel *model = (CBaseViewModel *)pStruct;
|
||||
if ( model )
|
||||
{
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
model->SetModelByIndex( pData->m_Value.m_Int );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CBaseViewModel::LookupAttachment( const char *pAttachmentName )
|
||||
{
|
||||
if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
|
||||
return m_hWeapon.Get()->LookupAttachment( pAttachmentName );
|
||||
|
||||
return BaseClass::LookupAttachment( pAttachmentName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseViewModel::GetAttachment( int number, matrix3x4_t &matrix )
|
||||
{
|
||||
if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
|
||||
return m_hWeapon.Get()->GetAttachment( number, matrix );
|
||||
|
||||
return BaseClass::GetAttachment( number, matrix );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseViewModel::GetAttachment( int number, Vector &origin )
|
||||
{
|
||||
if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
|
||||
return m_hWeapon.Get()->GetAttachment( number, origin );
|
||||
|
||||
return BaseClass::GetAttachment( number, origin );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseViewModel::GetAttachment( int number, Vector &origin, QAngle &angles )
|
||||
{
|
||||
if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
|
||||
return m_hWeapon.Get()->GetAttachment( number, origin, angles );
|
||||
|
||||
return BaseClass::GetAttachment( number, origin, angles );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseViewModel::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
|
||||
{
|
||||
if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
|
||||
return m_hWeapon.Get()->GetAttachmentVelocity( number, originVel, angleVel );
|
||||
|
||||
return BaseClass::GetAttachmentVelocity( number, originVel, angleVel );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,304 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef BASEVIEWMODEL_SHARED_H
|
||||
#define BASEVIEWMODEL_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "predictable_entity.h"
|
||||
#include "utlvector.h"
|
||||
#include "baseplayer_shared.h"
|
||||
#include "shared_classnames.h"
|
||||
#include "ihasowner.h"
|
||||
|
||||
#ifdef CSTRIKE15
|
||||
#include "cs_shareddefs.h"
|
||||
#endif
|
||||
|
||||
class CBaseCombatWeapon;
|
||||
class CBaseCombatCharacter;
|
||||
class CVGuiScreen;
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
class C_ViewmodelAttachmentModel;
|
||||
class C_CSPlayer;
|
||||
#define CBaseViewModel C_BaseViewModel
|
||||
#undef CBaseCombatWeapon
|
||||
#define CBaseCombatWeapon C_BaseCombatWeapon
|
||||
#define NUM_UID_CHARS 20
|
||||
|
||||
class C_BaseViewModel;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
class C_ViewmodelAttachmentModel : public C_BaseAnimating
|
||||
{
|
||||
DECLARE_CLASS( C_ViewmodelAttachmentModel, C_BaseAnimating );
|
||||
public:
|
||||
|
||||
bool InitializeAsClientEntity( const char *pszModelName, bool bRenderWithViewModels );
|
||||
|
||||
void SetViewmodel( C_BaseViewModel *pVM );
|
||||
virtual int InternalDrawModel( int flags, const RenderableInstance_t &instance );
|
||||
|
||||
private:
|
||||
CHandle< C_BaseViewModel > m_hViewmodel;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#define VIEWMODEL_INDEX_BITS 1
|
||||
|
||||
class CBaseViewModel : public CBaseAnimating, public IHasOwner
|
||||
{
|
||||
DECLARE_CLASS( CBaseViewModel, CBaseAnimating );
|
||||
public:
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
CBaseViewModel( void );
|
||||
~CBaseViewModel( void );
|
||||
|
||||
|
||||
bool IsViewable(void) { return false; }
|
||||
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
// Weapon client handling
|
||||
virtual void SendViewModelMatchingSequence( int sequence );
|
||||
virtual void SetWeaponModel( const char *pszModelname, CBaseCombatWeapon *weapon );
|
||||
|
||||
virtual void CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles );
|
||||
virtual void CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition,
|
||||
const QAngle& eyeAngles );
|
||||
virtual void AddViewModelBob( CBasePlayer *owner, Vector& eyePosition, QAngle& eyeAngles ) {};
|
||||
|
||||
void CalcViewModelUnzoom( CBasePlayer *owner, Vector& origin, QAngle& angles );
|
||||
|
||||
// Initializes the viewmodel for use
|
||||
void SetOwner( CBaseEntity *pEntity );
|
||||
void SetIndex( int nIndex );
|
||||
// Returns which viewmodel it is
|
||||
int ViewModelIndex( ) const;
|
||||
|
||||
virtual void Precache( void );
|
||||
|
||||
virtual void Spawn( void );
|
||||
|
||||
virtual CBaseEntity *GetOwner( void ) { return m_hOwner; };
|
||||
|
||||
virtual void AddEffects( int nEffects );
|
||||
virtual void RemoveEffects( int nEffects );
|
||||
|
||||
void SpawnControlPanels();
|
||||
void DestroyControlPanels();
|
||||
void SetControlPanelsActive( bool bState );
|
||||
void ShowControlPanells( bool show );
|
||||
|
||||
virtual CBaseCombatWeapon *GetOwningWeapon( void );
|
||||
|
||||
virtual CBaseEntity *GetOwnerViaInterface( void ) { return GetOwner(); }
|
||||
|
||||
virtual bool IsSelfAnimating()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector m_vecLastFacing;
|
||||
|
||||
virtual bool IsViewModel() const { return true; }
|
||||
virtual bool IsViewModelOrAttachment() const { return true; }
|
||||
|
||||
void UpdateAllViewmodelAddons( void );
|
||||
|
||||
#if defined ( CLIENT_DLL )
|
||||
C_ViewmodelAttachmentModel *AddViewmodelArmModel( const char *pszModel, int nSkintoneIndex = -1 );
|
||||
C_ViewmodelAttachmentModel* FindArmModelForLoadoutPosition( loadout_positions_t nPosition ) const;
|
||||
#endif
|
||||
void AddViewmodelLabel( CEconItemView *pItem );
|
||||
void AddViewmodelStatTrak( CEconItemView *pItem, int nStatTrakType, int nWeaponID, AccountID_t holderAcctId );
|
||||
void AddViewmodelStickers( CEconItemView *pItem, int nWeaponID );
|
||||
bool ViewmodelStickersAreValid( int nWeaponID );
|
||||
|
||||
void RemoveViewmodelArmModels( void );
|
||||
void RemoveViewmodelLabel( void );
|
||||
void RemoveViewmodelStatTrak( void );
|
||||
void RemoveViewmodelStickers( void );
|
||||
|
||||
CNetworkVar(bool, m_bShouldIgnoreOffsetAndAccuracy );
|
||||
virtual void SetShouldIgnoreOffsetAndAccuracy( bool bIgnore ) { m_bShouldIgnoreOffsetAndAccuracy = bIgnore; }
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
virtual int UpdateTransmitState( void );
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
|
||||
#else
|
||||
|
||||
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
|
||||
virtual C_BasePlayer *GetPredictionOwner( void );
|
||||
|
||||
virtual bool Interpolate( float currentTime );
|
||||
|
||||
virtual bool ShouldFlipModel( void );
|
||||
void UpdateAnimationParity( void );
|
||||
|
||||
virtual void PostBuildTransformations( CStudioHdr *pStudioHdr, BoneVector *pos, BoneQuaternion q[] );
|
||||
Vector m_vecCamDriverLastPos;
|
||||
QAngle m_angCamDriverLastAng;
|
||||
float m_flCamDriverAppliedTime;
|
||||
float m_flCamDriverWeight;
|
||||
|
||||
virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform );
|
||||
|
||||
virtual bool ShouldDraw();
|
||||
virtual bool ShouldSuppressForSplitScreenPlayer( int nSlot );
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags, const RenderableInstance_t &instance );
|
||||
virtual uint8 OverrideAlphaModulation( uint8 nAlpha );
|
||||
RenderableTranslucencyType_t ComputeTranslucencyType( void );
|
||||
|
||||
// Should this object cast shadows?
|
||||
virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; }
|
||||
|
||||
// Should this object receive shadows?
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);
|
||||
|
||||
// See C_StudioModel's definition of this.
|
||||
virtual void UncorrectViewModelAttachment( Vector &vOrigin );
|
||||
|
||||
// (inherited from C_BaseAnimating)
|
||||
virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld );
|
||||
|
||||
CBaseCombatWeapon *GetWeapon() const { return m_hWeapon.Get(); }
|
||||
|
||||
|
||||
virtual bool ShouldResetSequenceOnNewModel( void ) { return false; }
|
||||
|
||||
// Attachments
|
||||
virtual int LookupAttachment( const char *pAttachmentName );
|
||||
virtual bool GetAttachment( int number, matrix3x4_t &matrix );
|
||||
virtual bool GetAttachment( int number, Vector &origin );
|
||||
virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
|
||||
virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel );
|
||||
|
||||
virtual bool Simulate( void );
|
||||
|
||||
private:
|
||||
CBaseViewModel( const CBaseViewModel & ); // not defined, not accessible
|
||||
|
||||
void UpdateParticles( int nSlot );
|
||||
|
||||
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
|
||||
virtual void OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect );
|
||||
|
||||
CUtlReference<CNewParticleEffect> m_viewmodelParticleEffect;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef PORTAL2
|
||||
// We need to always transition because we handle our transition volumes in a different manner
|
||||
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_FORCE_TRANSITION; }
|
||||
#endif // PORTAL2
|
||||
|
||||
private:
|
||||
typedef CHandle< CBaseCombatWeapon > CBaseCombatWeaponHandle;
|
||||
// FTYPEDESC_INSENDTABLE STUFF
|
||||
CNetworkVar( int, m_nViewModelIndex ); // Which viewmodel is it?
|
||||
// Used to force restart on client, only needs a few bits
|
||||
CNetworkVar( int, m_nAnimationParity );
|
||||
CNetworkVar( CBaseCombatWeaponHandle, m_hWeapon );
|
||||
// FTYPEDESC_INSENDTABLE STUFF (end)
|
||||
|
||||
CNetworkHandle( CBaseEntity, m_hOwner ); // Player or AI carrying this weapon
|
||||
|
||||
// soonest time Update will call WeaponIdle
|
||||
float m_flTimeWeaponIdle;
|
||||
|
||||
Activity m_Activity;
|
||||
|
||||
// Weapon art
|
||||
string_t m_sVMName; // View model of this weapon
|
||||
string_t m_sAnimationPrefix; // Prefix of the animations that should be used by the player carrying this weapon
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
int m_nOldAnimationParity;
|
||||
|
||||
public:
|
||||
float m_fCycleOffset;
|
||||
|
||||
void UpdateStatTrakGlow( void );
|
||||
void SetStatTrakGlowMultiplier( float flNewIdealGlow ) { m_flStatTrakGlowMultiplierIdeal = flNewIdealGlow; }
|
||||
const float GetStatTrakGlowMultiplier( void ){ return m_flStatTrakGlowMultiplier; }
|
||||
|
||||
#ifdef IRONSIGHT
|
||||
void SetScopeStencilMaskMode( bool bEnabled ) { m_bScopeStencilMaskModeEnabled = bEnabled; }
|
||||
bool GetScopeStencilMaskMode( void ) { return m_bScopeStencilMaskModeEnabled; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#ifdef IRONSIGHT
|
||||
bool m_bScopeStencilMaskModeEnabled;
|
||||
CHandle< C_ViewmodelAttachmentModel > m_viewmodelScopeStencilMask;
|
||||
#endif
|
||||
|
||||
CUtlVector< CHandle< C_ViewmodelAttachmentModel > > m_vecViewmodelArmModels; // gloves, sleeves, etc
|
||||
CHandle< C_ViewmodelAttachmentModel > m_viewmodelStatTrakAddon;
|
||||
CHandle< C_ViewmodelAttachmentModel > m_viewmodelUidAddon;
|
||||
int m_iAddOnPlayerClass;
|
||||
int m_iAddOnWeaponID;
|
||||
float m_flStatTrakGlowMultiplierIdeal;
|
||||
float m_flStatTrakGlowMultiplier;
|
||||
|
||||
//stickers
|
||||
typedef CHandle<C_ViewmodelAttachmentModel> StickerHandle_t;
|
||||
CUtlVector<StickerHandle_t> m_hStickerModelAddons;
|
||||
CBaseAnimating* m_pMaterialPreviewShape;
|
||||
|
||||
char m_szLastSound[64];
|
||||
float m_flLastSoundTime;
|
||||
bool IsSoundSameAsPreviousSound( const char* soundName, float flPastTimeThreshold ) { return ( gpGlobals->curtime - m_flLastSoundTime < flPastTimeThreshold ) && !V_strcmp( soundName, m_szLastSound ); }
|
||||
void ResetTimeSincePreviousSound( void ) { m_flLastSoundTime = gpGlobals->curtime; }
|
||||
void SetPreviousSoundStr( const char* soundName ) { V_strcpy( m_szLastSound, soundName ); }
|
||||
|
||||
#endif
|
||||
|
||||
// Control panel
|
||||
typedef CHandle<CVGuiScreen> ScreenHandle_t;
|
||||
CUtlVector<ScreenHandle_t> m_hScreens;
|
||||
};
|
||||
|
||||
inline CBaseViewModel *ToBaseViewModel( CBaseAnimating *pAnim )
|
||||
{
|
||||
if ( pAnim && pAnim->IsViewModel() )
|
||||
return assert_cast<CBaseViewModel *>(pAnim);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline CBaseViewModel *ToBaseViewModel( CBaseEntity *pEntity )
|
||||
{
|
||||
if ( !pEntity )
|
||||
return NULL;
|
||||
return ToBaseViewModel(pEntity->GetBaseAnimating());
|
||||
}
|
||||
|
||||
#endif // BASEVIEWMODEL_SHARED_H
|
||||
@@ -0,0 +1,38 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#if !defined( BEAM_FLAGS_H )
|
||||
#define BEAM_FLAGS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
FBEAM_STARTENTITY = 0x00000001,
|
||||
FBEAM_ENDENTITY = 0x00000002,
|
||||
FBEAM_FADEIN = 0x00000004,
|
||||
FBEAM_FADEOUT = 0x00000008,
|
||||
FBEAM_SINENOISE = 0x00000010,
|
||||
FBEAM_SOLID = 0x00000020,
|
||||
FBEAM_SHADEIN = 0x00000040,
|
||||
FBEAM_SHADEOUT = 0x00000080,
|
||||
FBEAM_ONLYNOISEONCE = 0x00000100, // Only calculate our noise once
|
||||
FBEAM_NOTILE = 0x00000200,
|
||||
FBEAM_USE_HITBOXES = 0x00000400, // Attachment indices represent hitbox indices instead when this is set.
|
||||
FBEAM_STARTVISIBLE = 0x00000800, // Has this client actually seen this beam's start entity yet?
|
||||
FBEAM_ENDVISIBLE = 0x00001000, // Has this client actually seen this beam's end entity yet?
|
||||
FBEAM_ISACTIVE = 0x00002000,
|
||||
FBEAM_FOREVER = 0x00004000,
|
||||
FBEAM_HALOBEAM = 0x00008000, // When drawing a beam with a halo, don't ignore the segments and endwidth
|
||||
FBEAM_REVERSED = 0x00010000,
|
||||
NUM_BEAM_FLAGS = 17 // KEEP THIS UPDATED!
|
||||
};
|
||||
|
||||
#endif // BEAM_FLAGS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,489 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BEAM_H
|
||||
#define BEAM_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "baseentity_shared.h"
|
||||
#include "baseplayer_shared.h"
|
||||
#if !defined( CLIENT_DLL )
|
||||
#include "entityoutput.h"
|
||||
#endif
|
||||
|
||||
#include "beam_flags.h"
|
||||
|
||||
#define MAX_BEAM_WIDTH 102.3f
|
||||
#define MAX_BEAM_SCROLLSPEED 100.0f
|
||||
#define MAX_BEAM_NOISEAMPLITUDE 64
|
||||
|
||||
#define SF_BEAM_STARTON 0x0001
|
||||
#define SF_BEAM_TOGGLE 0x0002
|
||||
#define SF_BEAM_RANDOM 0x0004
|
||||
#define SF_BEAM_RING 0x0008
|
||||
#define SF_BEAM_SPARKSTART 0x0010
|
||||
#define SF_BEAM_SPARKEND 0x0020
|
||||
#define SF_BEAM_DECALS 0x0040
|
||||
#define SF_BEAM_SHADEIN 0x0080
|
||||
#define SF_BEAM_SHADEOUT 0x0100
|
||||
#define SF_BEAM_TAPEROUT 0x0200 // Tapers to zero
|
||||
#define SF_BEAM_TEMPORARY 0x8000
|
||||
|
||||
#define ATTACHMENT_INDEX_BITS 5
|
||||
#define ATTACHMENT_INDEX_MASK ((1 << ATTACHMENT_INDEX_BITS) - 1)
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CBeam C_Beam
|
||||
#include "c_pixel_visibility.h"
|
||||
#endif
|
||||
|
||||
// I've seen CBeams glitter in the dark near Tannhauser gate...
|
||||
class CBeam : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CBeam, CBaseEntity );
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
#if !defined( CLIENT_DLL )
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
CBeam();
|
||||
|
||||
virtual void SetModel( const char *szModelName );
|
||||
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
#if !defined( CLIENT_DLL )
|
||||
int ObjectCaps( void );
|
||||
void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
|
||||
int UpdateTransmitState( void );
|
||||
int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
#endif
|
||||
|
||||
virtual int DrawDebugTextOverlays(void);
|
||||
|
||||
// These functions are here to show the way beams are encoded as entities.
|
||||
// Encoding beams as entities simplifies their management in the client/server architecture
|
||||
void SetType( int type );
|
||||
void SetBeamFlags( int flags );
|
||||
void SetBeamFlag( int flag );
|
||||
|
||||
// NOTE: Start + End Pos are specified in *relative* coordinates
|
||||
void SetStartPos( const Vector &pos );
|
||||
void SetEndPos( const Vector &pos );
|
||||
|
||||
// This will change things so the abs position matches the requested spot
|
||||
void SetAbsStartPos( const Vector &pos );
|
||||
void SetAbsEndPos( const Vector &pos );
|
||||
|
||||
const Vector &GetAbsStartPos( void ) const;
|
||||
const Vector &GetAbsEndPos( void ) const;
|
||||
|
||||
void SetStartEntity( CBaseEntity *pEntity );
|
||||
void SetEndEntity( CBaseEntity *pEntity );
|
||||
|
||||
void SetStartAttachment( int attachment );
|
||||
void SetEndAttachment( int attachment );
|
||||
|
||||
void SetTexture( int spriteIndex );
|
||||
void SetHaloTexture( int spriteIndex );
|
||||
void SetHaloScale( float haloScale );
|
||||
void SetWidth( float width );
|
||||
void SetEndWidth( float endWidth );
|
||||
void SetFadeLength( float fadeLength );
|
||||
void SetNoise( float amplitude );
|
||||
void SetColor( int r, int g, int b );
|
||||
void SetBrightness( int brightness );
|
||||
void SetFrame( float frame );
|
||||
void SetScrollRate( int speed );
|
||||
void SetFireTime( float flFireTime );
|
||||
void SetFrameRate( float flFrameRate ) { m_flFrameRate = flFrameRate; }
|
||||
|
||||
void TurnOn( void );
|
||||
void TurnOff( void );
|
||||
|
||||
int GetType( void ) const;
|
||||
int GetBeamFlags( void ) const;
|
||||
CBaseEntity* GetStartEntityPtr( void ) const;
|
||||
int GetStartEntity( void ) const;
|
||||
CBaseEntity* GetEndEntityPtr( void ) const;
|
||||
int GetEndEntity( void ) const;
|
||||
int GetStartAttachment() const;
|
||||
int GetEndAttachment() const;
|
||||
|
||||
virtual const Vector &WorldSpaceCenter( void ) const;
|
||||
|
||||
int GetTexture( void );
|
||||
int GetHaloTexture( void ) const;
|
||||
float GetWidth( void ) const;
|
||||
float GetEndWidth( void ) const;
|
||||
float GetFadeLength( void ) const;
|
||||
float GetNoise( void ) const;
|
||||
float GetHaloScale( void ) const;
|
||||
int GetBrightness( void ) const;
|
||||
float GetFrame( void ) const;
|
||||
float GetScrollRate( void ) const;
|
||||
float GetHDRColorScale( void ) const;
|
||||
void SetHDRColorScale( float flScale ) { m_flHDRColorScale = flScale; }
|
||||
|
||||
|
||||
// Call after you change start/end positions
|
||||
void RelinkBeam( void );
|
||||
|
||||
void DoSparks( const Vector &start, const Vector &end );
|
||||
CBaseEntity *RandomTargetname( const char *szName );
|
||||
void BeamDamage( trace_t *ptr );
|
||||
// Init after BeamCreate()
|
||||
void BeamInit( const char *pSpriteName, float width );
|
||||
void PointsInit( const Vector &start, const Vector &end );
|
||||
void PointEntInit( const Vector &start, CBaseEntity *pEndEntity );
|
||||
void EntsInit( CBaseEntity *pStartEntity, CBaseEntity *pEndEntity );
|
||||
void LaserInit( CBaseEntity *pStartEntity, CBaseEntity *pEndEntity );
|
||||
void HoseInit( const Vector &start, const Vector &direction );
|
||||
void SplineInit( int nNumEnts, CBaseEntity** pEntList, int *attachment );
|
||||
|
||||
// Input handlers
|
||||
|
||||
static CBeam *BeamCreate( const char *pSpriteName, float width );
|
||||
static CBeam *BeamCreatePredictable( const char *module, int line, bool persist, const char *pSpriteName, float width, CBasePlayer *pOwner );
|
||||
|
||||
void LiveForTime( float time );
|
||||
void BeamDamageInstant( trace_t *ptr, float damage );
|
||||
|
||||
virtual const char *GetDecalName( void ) { return "BigShot"; }
|
||||
|
||||
// specify whether the beam should always go all the way to
|
||||
// the end point, or clip against geometry, or clip against
|
||||
// geometry and NPCs. This is only used by env_beams at present, but
|
||||
// need to be in this CBeam because of the way it affects drawing.
|
||||
enum BeamClipStyle_t
|
||||
{
|
||||
kNOCLIP = 0, // don't clip (default)
|
||||
kGEOCLIP = 1,
|
||||
kMODELCLIP = 2,
|
||||
|
||||
kBEAMCLIPSTYLE_NUMBITS = 2, //< number of bits needed to represent this object
|
||||
};
|
||||
|
||||
inline BeamClipStyle_t GetClipStyle() const { return m_nClipStyle; }
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
// IClientEntity overrides.
|
||||
public:
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual RenderableTranslucencyType_t ComputeTranslucencyType();
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
virtual bool OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted );
|
||||
|
||||
// Add beam to visible entities list?
|
||||
virtual bool Simulate( void );
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
void RestoreToToolRecordedState( KeyValues *pKV );
|
||||
|
||||
// Beam Data Elements
|
||||
private:
|
||||
// Computes the bounding box of a beam local to the origin of the beam
|
||||
void ComputeBounds( Vector& mins, Vector& maxs );
|
||||
|
||||
friend void RecvProxy_Beam_ScrollSpeed( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
friend class CViewRenderBeams;
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
CNetworkVar( float, m_flFrameRate );
|
||||
CNetworkVar( float, m_flHDRColorScale );
|
||||
float m_flFireTime;
|
||||
float m_flDamage; // Damage per second to touchers.
|
||||
CNetworkVar( int, m_nNumBeamEnts );
|
||||
#if defined( CLIENT_DLL )
|
||||
pixelvis_handle_t m_queryHandleHalo;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if !defined( CLIENT_DLL )
|
||||
void InputNoise( inputdata_t &inputdata );
|
||||
void InputWidth( inputdata_t &inputdata );
|
||||
void InputColorRedValue( inputdata_t &inputdata );
|
||||
void InputColorBlueValue( inputdata_t &inputdata );
|
||||
void InputColorGreenValue( inputdata_t &inputdata );
|
||||
#endif
|
||||
|
||||
// Beam Data Elements
|
||||
CNetworkVar( int, m_nHaloIndex );
|
||||
CNetworkVar( int, m_nBeamType );
|
||||
CNetworkVar( int, m_nBeamFlags );
|
||||
CNetworkArray( EHANDLE, m_hAttachEntity, MAX_BEAM_ENTS );
|
||||
CNetworkArray( int, m_nAttachIndex, MAX_BEAM_ENTS );
|
||||
CNetworkVar( float, m_fWidth );
|
||||
CNetworkVar( float, m_fEndWidth );
|
||||
CNetworkVar( float, m_fFadeLength );
|
||||
CNetworkVar( float, m_fHaloScale );
|
||||
CNetworkVar( float, m_fAmplitude );
|
||||
CNetworkVar( float, m_fStartFrame );
|
||||
CNetworkVar( float, m_fSpeed );
|
||||
CNetworkVar( float, m_flFrame );
|
||||
CNetworkVar( BeamClipStyle_t, m_nClipStyle );
|
||||
|
||||
CNetworkVector( m_vecEndPos );
|
||||
|
||||
EHANDLE m_hEndEntity;
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
int m_nDissolveType;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inline methods
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int CBeam::ObjectCaps( void )
|
||||
{
|
||||
int flags = 0;
|
||||
if ( HasSpawnFlags( SF_BEAM_TEMPORARY ) )
|
||||
flags = FCAP_DONT_SAVE;
|
||||
return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void CBeam::SetFireTime( float flFireTime )
|
||||
{
|
||||
m_flFireTime = flFireTime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// NOTE: Start + End Pos are specified in *relative* coordinates
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CBeam::SetStartPos( const Vector &pos )
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
SetNetworkOrigin( pos );
|
||||
#endif
|
||||
SetLocalOrigin( pos );
|
||||
}
|
||||
|
||||
inline void CBeam::SetEndPos( const Vector &pos )
|
||||
{
|
||||
m_vecEndPos = pos;
|
||||
}
|
||||
|
||||
// center point of beam
|
||||
inline const Vector &CBeam::WorldSpaceCenter( void ) const
|
||||
{
|
||||
Vector &vecResult = AllocTempVector();
|
||||
VectorAdd( GetAbsStartPos(), GetAbsEndPos(), vecResult );
|
||||
vecResult *= 0.5f;
|
||||
return vecResult;
|
||||
}
|
||||
|
||||
inline void CBeam::SetStartAttachment( int attachment )
|
||||
{
|
||||
Assert( (attachment & ~ATTACHMENT_INDEX_MASK) == 0 );
|
||||
m_nAttachIndex.Set( 0, attachment );
|
||||
}
|
||||
|
||||
inline void CBeam::SetEndAttachment( int attachment )
|
||||
{
|
||||
Assert( (attachment & ~ATTACHMENT_INDEX_MASK) == 0 );
|
||||
m_nAttachIndex.Set( m_nNumBeamEnts-1, attachment );
|
||||
}
|
||||
|
||||
inline void CBeam::SetTexture( int spriteIndex )
|
||||
{
|
||||
SetModelIndex( spriteIndex );
|
||||
}
|
||||
|
||||
inline void CBeam::SetHaloTexture( int spriteIndex )
|
||||
{
|
||||
m_nHaloIndex = spriteIndex;
|
||||
}
|
||||
|
||||
inline void CBeam::SetHaloScale( float haloScale )
|
||||
{
|
||||
m_fHaloScale = haloScale;
|
||||
}
|
||||
|
||||
inline void CBeam::SetWidth( float width )
|
||||
{
|
||||
Assert( width <= MAX_BEAM_WIDTH );
|
||||
m_fWidth = MIN( MAX_BEAM_WIDTH, width );
|
||||
}
|
||||
|
||||
inline void CBeam::SetEndWidth( float endWidth )
|
||||
{
|
||||
Assert( endWidth <= MAX_BEAM_WIDTH );
|
||||
m_fEndWidth = MIN( MAX_BEAM_WIDTH, endWidth );
|
||||
}
|
||||
|
||||
inline void CBeam::SetFadeLength( float fadeLength )
|
||||
{
|
||||
m_fFadeLength = fadeLength;
|
||||
}
|
||||
|
||||
inline void CBeam::SetNoise( float amplitude )
|
||||
{
|
||||
m_fAmplitude = amplitude;
|
||||
}
|
||||
|
||||
inline void CBeam::SetColor( int r, int g, int b )
|
||||
{
|
||||
SetRenderColor( r, g, b );
|
||||
}
|
||||
|
||||
inline void CBeam::SetBrightness( int brightness )
|
||||
{
|
||||
SetRenderAlpha( brightness );
|
||||
}
|
||||
|
||||
inline void CBeam::SetFrame( float frame )
|
||||
{
|
||||
m_fStartFrame = frame;
|
||||
}
|
||||
|
||||
inline void CBeam::SetScrollRate( int speed )
|
||||
{
|
||||
m_fSpeed = speed;
|
||||
}
|
||||
|
||||
inline CBaseEntity* CBeam::GetStartEntityPtr( void ) const
|
||||
{
|
||||
return m_hAttachEntity[0].Get();
|
||||
}
|
||||
|
||||
inline int CBeam::GetStartEntity( void ) const
|
||||
{
|
||||
CBaseEntity *pEntity = m_hAttachEntity[0].Get();
|
||||
return pEntity ? pEntity->entindex() : 0;
|
||||
}
|
||||
|
||||
inline CBaseEntity* CBeam::GetEndEntityPtr( void ) const
|
||||
{
|
||||
return m_hAttachEntity[1].Get();
|
||||
}
|
||||
|
||||
inline int CBeam::GetEndEntity( void ) const
|
||||
{
|
||||
CBaseEntity *pEntity = m_hAttachEntity[m_nNumBeamEnts-1].Get();
|
||||
return pEntity ? pEntity->entindex() : 0;
|
||||
}
|
||||
|
||||
inline int CBeam::GetStartAttachment() const
|
||||
{
|
||||
return m_nAttachIndex[0] & ATTACHMENT_INDEX_MASK;
|
||||
}
|
||||
|
||||
inline int CBeam::GetEndAttachment() const
|
||||
{
|
||||
return m_nAttachIndex[m_nNumBeamEnts-1] & ATTACHMENT_INDEX_MASK;
|
||||
}
|
||||
|
||||
inline int CBeam::GetTexture( void )
|
||||
{
|
||||
return GetModelIndex();
|
||||
}
|
||||
|
||||
inline int CBeam::GetHaloTexture( void ) const
|
||||
{
|
||||
return m_nHaloIndex;
|
||||
}
|
||||
|
||||
inline float CBeam::GetWidth( void ) const
|
||||
{
|
||||
return m_fWidth;
|
||||
}
|
||||
|
||||
inline float CBeam::GetEndWidth( void ) const
|
||||
{
|
||||
return m_fEndWidth;
|
||||
}
|
||||
|
||||
inline float CBeam::GetFadeLength( void ) const
|
||||
{
|
||||
return m_fFadeLength;
|
||||
}
|
||||
|
||||
inline float CBeam::GetNoise( void ) const
|
||||
{
|
||||
return m_fAmplitude;
|
||||
}
|
||||
|
||||
inline float CBeam::GetHaloScale( void ) const
|
||||
{
|
||||
return m_fHaloScale;
|
||||
}
|
||||
|
||||
inline int CBeam::GetBrightness( void ) const
|
||||
{
|
||||
return GetRenderAlpha();
|
||||
}
|
||||
|
||||
inline float CBeam::GetFrame( void ) const
|
||||
{
|
||||
return m_fStartFrame;
|
||||
}
|
||||
|
||||
inline float CBeam::GetScrollRate( void ) const
|
||||
{
|
||||
return m_fSpeed;
|
||||
}
|
||||
|
||||
inline float CBeam::GetHDRColorScale( void ) const
|
||||
{
|
||||
return m_flHDRColorScale;
|
||||
}
|
||||
|
||||
inline void CBeam::LiveForTime( float time )
|
||||
{
|
||||
SetThink(&CBeam::SUB_Remove);
|
||||
SetNextThink( gpGlobals->curtime + time );
|
||||
}
|
||||
|
||||
inline void CBeam::BeamDamageInstant( trace_t *ptr, float damage )
|
||||
{
|
||||
m_flDamage = damage;
|
||||
m_flFireTime = gpGlobals->curtime - 1;
|
||||
BeamDamage(ptr);
|
||||
}
|
||||
|
||||
bool IsStaticPointEntity( CBaseEntity *pEnt );
|
||||
|
||||
// Macro to wrap creation
|
||||
#define BEAM_CREATE_PREDICTABLE( name, width, player ) \
|
||||
CBeam::BeamCreatePredictable( __FILE__, __LINE__, false, name, width, player )
|
||||
|
||||
#define BEAM_CREATE_PREDICTABLE_PERSIST( name, width, player ) \
|
||||
CBeam::BeamCreatePredictable( __FILE__, __LINE__, true, name, width, player )
|
||||
|
||||
// Start/End Entity is encoded as 12 bits of entity index, and 4 bits of attachment (4:12)
|
||||
#define BEAMENT_ENTITY(x) ((x)&0xFFF)
|
||||
#define BEAMENT_ATTACHMENT(x) (((x)>>12)&0xF)
|
||||
|
||||
|
||||
// Beam types, encoded as a byte
|
||||
enum
|
||||
{
|
||||
BEAM_POINTS = 0,
|
||||
BEAM_ENTPOINT,
|
||||
BEAM_ENTS,
|
||||
BEAM_HOSE,
|
||||
BEAM_SPLINE,
|
||||
BEAM_LASER,
|
||||
NUM_BEAM_TYPES
|
||||
};
|
||||
|
||||
|
||||
#endif // BEAM_H
|
||||
@@ -0,0 +1,353 @@
|
||||
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "blob_networkbypass.h"
|
||||
#include "ispsharedmemory.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "npc_surface.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
BlobNetworkBypass_t *g_pBlobNetworkBypass;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
CInterpolatedVar< Vector > s_PositionInterpolators[BLOB_MAX_LEVEL_PARTICLES];
|
||||
CInterpolatedVar< float > s_RadiusInterpolators[BLOB_MAX_LEVEL_PARTICLES];
|
||||
CInterpolatedVar< Vector > s_ClosestSurfDirInterpolators[BLOB_MAX_LEVEL_PARTICLES];
|
||||
BlobParticleInterpolation_t g_BlobParticleInterpolation;
|
||||
void BlobNetworkBypass_CustomDemoDataCallback( uint8 *pData, size_t iSize );
|
||||
#endif
|
||||
|
||||
class CBlobParticleNetworkBypassAutoGame : public CAutoGameSystemPerFrame
|
||||
{
|
||||
public:
|
||||
virtual bool Init()
|
||||
{
|
||||
m_pSharedMemory = engine->GetSinglePlayerSharedMemorySpace( "BlobParticleNetworkBypass" );
|
||||
m_pSharedMemory->Init( sizeof( BlobNetworkBypass_t ) );
|
||||
g_pBlobNetworkBypass = (BlobNetworkBypass_t *)m_pSharedMemory->Base();
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
float fInterpAmount = TICK_INTERVAL * (C_BaseEntity::IsSimulatingOnAlternateTicks()?2:1);
|
||||
|
||||
for( int i = 0; i != BLOB_MAX_LEVEL_PARTICLES; ++i )
|
||||
{
|
||||
s_PositionInterpolators[i].Setup( &g_BlobParticleInterpolation.vInterpolatedPositions[i], LATCH_ANIMATION_VAR ); //LATCH_SIMULATION_VAR, LATCH_ANIMATION_VAR
|
||||
s_PositionInterpolators[i].SetInterpolationAmount( fInterpAmount ); //fInterpAmount
|
||||
s_RadiusInterpolators[i].Setup( &g_BlobParticleInterpolation.vInterpolatedRadii[i], LATCH_ANIMATION_VAR ); //LATCH_SIMULATION_VAR, LATCH_ANIMATION_VAR
|
||||
s_RadiusInterpolators[i].SetInterpolationAmount( fInterpAmount ); //fInterpAmount
|
||||
s_ClosestSurfDirInterpolators[i].Setup( &g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[i], LATCH_ANIMATION_VAR ); //LATCH_SIMULATION_VAR, LATCH_ANIMATION_VAR
|
||||
s_ClosestSurfDirInterpolators[i].SetInterpolationAmount( fInterpAmount ); //fInterpAmount
|
||||
}
|
||||
|
||||
m_iOldHighestIndexUsed = 0;
|
||||
memset( &m_bOldInUse, 0, sizeof( m_bOldInUse ) );
|
||||
|
||||
engine->RegisterDemoCustomDataCallback( MAKE_STRING( "BlobNetworkBypass_CustomDemoDataCallback" ), BlobNetworkBypass_CustomDemoDataCallback );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Shutdown()
|
||||
{
|
||||
m_pSharedMemory->Release();
|
||||
m_pSharedMemory = NULL;
|
||||
g_pBlobNetworkBypass = NULL;
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual void PreRender( void );
|
||||
unsigned int m_iOldHighestIndexUsed;
|
||||
CBitVec<BLOB_MAX_LEVEL_PARTICLES> m_bOldInUse;
|
||||
#else
|
||||
virtual void PreClientUpdate()
|
||||
{
|
||||
CNPC_Surface::UpdateBypassParticleData();
|
||||
}
|
||||
#endif
|
||||
|
||||
ISPSharedMemory *m_pSharedMemory;
|
||||
};
|
||||
|
||||
static CBlobParticleNetworkBypassAutoGame s_CBPNBAG;
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
int AllocateBlobNetworkBypassIndex( void )
|
||||
{
|
||||
int retval;
|
||||
if( g_pBlobNetworkBypass->iNumParticlesAllocated == g_pBlobNetworkBypass->iHighestIndexUsed )
|
||||
{
|
||||
//no holes in the allocations, allocate from the end
|
||||
retval = g_pBlobNetworkBypass->iHighestIndexUsed;
|
||||
++g_pBlobNetworkBypass->iHighestIndexUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
CBitVec<BLOB_MAX_LEVEL_PARTICLES> notUsed;
|
||||
g_pBlobNetworkBypass->bCurrentlyInUse.Not( ¬Used );
|
||||
retval = notUsed.FindNextSetBit( 0 );
|
||||
Assert( retval < (int)g_pBlobNetworkBypass->iHighestIndexUsed );
|
||||
}
|
||||
|
||||
++g_pBlobNetworkBypass->iNumParticlesAllocated;
|
||||
|
||||
g_pBlobNetworkBypass->bCurrentlyInUse.Set( retval );
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ReleaseBlobNetworkBypassIndex( int iIndex )
|
||||
{
|
||||
Assert( g_pBlobNetworkBypass->bCurrentlyInUse.IsBitSet( iIndex ) );
|
||||
g_pBlobNetworkBypass->bCurrentlyInUse.Clear( iIndex );
|
||||
g_pBlobNetworkBypass->vParticlePositions[iIndex] = vec3_origin;
|
||||
g_pBlobNetworkBypass->vParticleRadii[iIndex] = 1.0f;
|
||||
g_pBlobNetworkBypass->vParticleClosestSurfDir[iIndex] = vec3_origin;
|
||||
--g_pBlobNetworkBypass->iNumParticlesAllocated;
|
||||
Assert( iIndex < (int)g_pBlobNetworkBypass->iHighestIndexUsed );
|
||||
if( iIndex == ((int)g_pBlobNetworkBypass->iHighestIndexUsed - 1) )
|
||||
{
|
||||
//search for newest high index
|
||||
int iOldHighestIntUsed = g_pBlobNetworkBypass->iHighestIndexUsed / BITS_PER_INT;
|
||||
for( int i = iOldHighestIntUsed; i >= 0; --i )
|
||||
{
|
||||
if( (g_pBlobNetworkBypass->bCurrentlyInUse.GetDWord( i ) & (-1)) != 0 )
|
||||
{
|
||||
int iLowBit = i * BITS_PER_INT;
|
||||
int iHighBit = iLowBit + BITS_PER_INT;
|
||||
for( int j = iHighBit; --j >= iLowBit; )
|
||||
{
|
||||
if( g_pBlobNetworkBypass->bCurrentlyInUse.IsBitSet( j ) )
|
||||
{
|
||||
g_pBlobNetworkBypass->iHighestIndexUsed = (uint32)j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert( g_pBlobNetworkBypass->iHighestIndexUsed >= g_pBlobNetworkBypass->iNumParticlesAllocated );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void CBlobParticleNetworkBypassAutoGame::PreRender( void )
|
||||
{
|
||||
if( engine->IsRecordingDemo() && g_pBlobNetworkBypass->bDataUpdated )
|
||||
{
|
||||
//record the update, TODO: compress the data by omitting the holes
|
||||
|
||||
int iMaxIndex = MAX(g_pBlobNetworkBypass->iHighestIndexUsed, m_iOldHighestIndexUsed);
|
||||
int iBitMax = (iMaxIndex / BITS_PER_INT) + 1;
|
||||
|
||||
size_t iDataSize = sizeof( int ) + sizeof( float ) + sizeof( int ) + sizeof( int ) + (sizeof( int ) * iBitMax) +
|
||||
iMaxIndex*( sizeof( Vector ) + sizeof( float ) + sizeof( Vector ) );
|
||||
uint8 *pData = new uint8 [iDataSize];
|
||||
uint8 *pWrite = pData;
|
||||
|
||||
//let the receiver know how much of each array to expect
|
||||
*(int *)pWrite = LittleDWord( iMaxIndex );
|
||||
pWrite += sizeof( int );
|
||||
|
||||
//write the update timestamp
|
||||
*(float *)pWrite = g_pBlobNetworkBypass->fTimeDataUpdated;
|
||||
pWrite += sizeof( float );
|
||||
|
||||
//record usage information, also helps us effectively compress the subsequent data by omitting the holes.
|
||||
*(int *)pWrite = LittleDWord( g_pBlobNetworkBypass->iHighestIndexUsed );
|
||||
pWrite += sizeof( int );
|
||||
|
||||
*(int *)pWrite = LittleDWord( g_pBlobNetworkBypass->iNumParticlesAllocated );
|
||||
pWrite += sizeof( int );
|
||||
|
||||
int *pIntParser = (int *)&g_pBlobNetworkBypass->bCurrentlyInUse;
|
||||
for( int i = 0; i != iBitMax; ++i )
|
||||
{
|
||||
//convert and write the bitfield integers
|
||||
*(int *)pWrite = LittleDWord( *pIntParser );
|
||||
pWrite += sizeof( int );
|
||||
++pIntParser;
|
||||
}
|
||||
|
||||
//write positions
|
||||
memcpy( pWrite, g_pBlobNetworkBypass->vParticlePositions, sizeof( Vector ) * iMaxIndex );
|
||||
pWrite += sizeof( Vector ) * iMaxIndex;
|
||||
|
||||
//write radii
|
||||
memcpy( pWrite, g_pBlobNetworkBypass->vParticleRadii, sizeof( float ) * iMaxIndex );
|
||||
pWrite += sizeof( float ) * iMaxIndex;
|
||||
|
||||
//write closest surface direction
|
||||
memcpy( pWrite, g_pBlobNetworkBypass->vParticleClosestSurfDir, sizeof( Vector ) * iMaxIndex );
|
||||
pWrite += sizeof( Vector ) * iMaxIndex;
|
||||
|
||||
engine->RecordDemoCustomData( BlobNetworkBypass_CustomDemoDataCallback, pData, iDataSize );
|
||||
|
||||
Assert( pWrite == (pData + iDataSize) );
|
||||
|
||||
delete []pData;
|
||||
}
|
||||
|
||||
//invalidate interpolation on freed indices, do a quick update for brand new indices
|
||||
{
|
||||
//operate on smaller chunks based on the assumption that LARGE portions of the end of the bitvecs are empty
|
||||
CBitVec<BITS_PER_INT> *pCurrentlyInUse = (CBitVec<BITS_PER_INT> *)&g_pBlobNetworkBypass->bCurrentlyInUse;
|
||||
CBitVec<BITS_PER_INT> *pOldInUse = (CBitVec<BITS_PER_INT> *)&m_bOldInUse;
|
||||
int iStop = (MAX(g_pBlobNetworkBypass->iHighestIndexUsed, m_iOldHighestIndexUsed) / BITS_PER_INT) + 1;
|
||||
int iBaseIndex = 0;
|
||||
|
||||
//float fNewIndicesUpdateTime = g_pBlobNetworkBypass->bPositionsUpdated ? g_pBlobNetworkBypass->fTimeDataUpdated : gpGlobals->curtime;
|
||||
|
||||
for( int i = 0; i != iStop; ++i )
|
||||
{
|
||||
CBitVec<BITS_PER_INT> bInUseXOR;
|
||||
pCurrentlyInUse->Xor( *pOldInUse, &bInUseXOR ); //find bits that changed
|
||||
|
||||
int j = 0;
|
||||
while( (j = bInUseXOR.FindNextSetBit( j )) != -1 )
|
||||
{
|
||||
int iChangedUsageIndex = iBaseIndex + j;
|
||||
|
||||
if( pOldInUse->IsBitSet( iChangedUsageIndex ) )
|
||||
{
|
||||
//index no longer used
|
||||
g_BlobParticleInterpolation.vInterpolatedPositions[iChangedUsageIndex] = vec3_origin;
|
||||
s_PositionInterpolators[iChangedUsageIndex].ClearHistory();
|
||||
g_BlobParticleInterpolation.vInterpolatedRadii[iChangedUsageIndex] = 1.0f;
|
||||
s_RadiusInterpolators[iChangedUsageIndex].ClearHistory();
|
||||
g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iChangedUsageIndex] = vec3_origin;
|
||||
s_ClosestSurfDirInterpolators[iChangedUsageIndex].ClearHistory();
|
||||
}
|
||||
else
|
||||
{
|
||||
//index just started being used. Assume we got an out of band update to the position
|
||||
g_BlobParticleInterpolation.vInterpolatedPositions[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticlePositions[iChangedUsageIndex];
|
||||
s_PositionInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
|
||||
g_BlobParticleInterpolation.vInterpolatedRadii[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticleRadii[iChangedUsageIndex];
|
||||
s_RadiusInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
|
||||
g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticleClosestSurfDir[iChangedUsageIndex];
|
||||
s_ClosestSurfDirInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
|
||||
//s_PositionInterpolators[iChangedUsageIndex].NoteChanged( gpGlobals->curtime, fNewIndicesUpdateTime, true );
|
||||
}
|
||||
|
||||
++j;
|
||||
if( j == BITS_PER_INT )
|
||||
break;
|
||||
}
|
||||
iBaseIndex += BITS_PER_INT;
|
||||
++pCurrentlyInUse;
|
||||
++pOldInUse;
|
||||
}
|
||||
|
||||
memcpy( &m_bOldInUse, &g_pBlobNetworkBypass->bCurrentlyInUse, sizeof( m_bOldInUse ) );
|
||||
m_iOldHighestIndexUsed = g_pBlobNetworkBypass->iHighestIndexUsed;
|
||||
}
|
||||
|
||||
if( g_pBlobNetworkBypass->iHighestIndexUsed == 0 )
|
||||
return;
|
||||
|
||||
static ConVarRef cl_interpREF( "cl_interp" );
|
||||
//now do the interpolation of positions still in use
|
||||
{
|
||||
float fInterpTime = gpGlobals->curtime - cl_interpREF.GetFloat();
|
||||
|
||||
CBitVec<BITS_PER_INT> *pIntParser = (CBitVec<BITS_PER_INT> *)&g_pBlobNetworkBypass->bCurrentlyInUse;
|
||||
int iStop = (g_pBlobNetworkBypass->iHighestIndexUsed / BITS_PER_INT) + 1;
|
||||
int iBaseIndex = 0;
|
||||
for( int i = 0; i != iStop; ++i )
|
||||
{
|
||||
int j = 0;
|
||||
while( (j = pIntParser->FindNextSetBit( j )) != -1 )
|
||||
{
|
||||
int iUpdateIndex = iBaseIndex + j;
|
||||
|
||||
if( g_pBlobNetworkBypass->bDataUpdated )
|
||||
{
|
||||
g_BlobParticleInterpolation.vInterpolatedPositions[iUpdateIndex] = g_pBlobNetworkBypass->vParticlePositions[iUpdateIndex];
|
||||
s_PositionInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
|
||||
g_BlobParticleInterpolation.vInterpolatedRadii[iUpdateIndex] = g_pBlobNetworkBypass->vParticleRadii[iUpdateIndex];
|
||||
s_RadiusInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
|
||||
g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iUpdateIndex] = g_pBlobNetworkBypass->vParticleClosestSurfDir[iUpdateIndex];
|
||||
s_ClosestSurfDirInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
|
||||
//s_PositionInterpolators[iUpdateIndex].AddToHead( gpGlobals->curtime, &g_pBlobNetworkBypass->vParticlePositions[iUpdateIndex], false );
|
||||
}
|
||||
|
||||
s_PositionInterpolators[iUpdateIndex].Interpolate( fInterpTime );
|
||||
s_RadiusInterpolators[iUpdateIndex].Interpolate( fInterpTime );
|
||||
s_ClosestSurfDirInterpolators[iUpdateIndex].Interpolate( fInterpTime );
|
||||
|
||||
++j;
|
||||
if( j == BITS_PER_INT )
|
||||
break;
|
||||
}
|
||||
iBaseIndex += BITS_PER_INT;
|
||||
++pIntParser;
|
||||
}
|
||||
|
||||
g_pBlobNetworkBypass->bDataUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BlobNetworkBypass_CustomDemoDataCallback( uint8 *pData, size_t iSize )
|
||||
{
|
||||
// FIXME: need a version number!
|
||||
|
||||
uint8 *pParse = pData;
|
||||
int iMaxIndex = LittleDWord( *(int *)pParse );
|
||||
pParse += sizeof( int );
|
||||
|
||||
int iBitMax = (iMaxIndex / BITS_PER_INT) + 1;
|
||||
|
||||
Assert( iSize == (sizeof( int ) + sizeof( float ) + sizeof( int ) + sizeof( int ) + (sizeof( int ) * iBitMax) +
|
||||
iMaxIndex*( sizeof( Vector ) + sizeof( float ) + sizeof( Vector ) )) );
|
||||
|
||||
g_pBlobNetworkBypass->fTimeDataUpdated = *(float *)pParse;
|
||||
pParse += sizeof( float );
|
||||
|
||||
g_pBlobNetworkBypass->iHighestIndexUsed = LittleDWord( *(int *)pParse );
|
||||
pParse += sizeof( int );
|
||||
|
||||
g_pBlobNetworkBypass->iNumParticlesAllocated = LittleDWord( *(int *)pParse );
|
||||
pParse += sizeof( int );
|
||||
|
||||
int *pIntParser = (int *)&g_pBlobNetworkBypass->bCurrentlyInUse;
|
||||
for( int i = 0; i != iBitMax; ++i )
|
||||
{
|
||||
//read and convert the bitfield integers
|
||||
*pIntParser = LittleDWord( *(int *)pParse );
|
||||
pParse += sizeof( int );
|
||||
++pIntParser;
|
||||
}
|
||||
|
||||
//read positions
|
||||
memcpy( g_pBlobNetworkBypass->vParticlePositions, pParse, sizeof( Vector ) * iMaxIndex );
|
||||
pParse += sizeof( Vector ) * iMaxIndex;
|
||||
|
||||
//read radii
|
||||
memcpy( g_pBlobNetworkBypass->vParticleRadii, pParse, sizeof( float ) * iMaxIndex );
|
||||
pParse += sizeof( float ) * iMaxIndex;
|
||||
|
||||
//read closest surface direction
|
||||
memcpy( g_pBlobNetworkBypass->vParticleClosestSurfDir, pParse, sizeof( Vector ) * iMaxIndex );
|
||||
pParse += sizeof( Vector ) * iMaxIndex;
|
||||
|
||||
g_pBlobNetworkBypass->bDataUpdated = true;
|
||||
|
||||
Assert( pParse == (pData + iSize) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Game rules for Blob.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BLOB_NETWORKBYPASS_H
|
||||
#define BLOB_NETWORKBYPASS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "bitvec.h"
|
||||
|
||||
#define BLOB_MAX_LEVEL_PARTICLES 4000 // maximum number of blob particles in a given level at any one time
|
||||
#define BLOB_MAX_LEVEL_PARTICLES_BITS 12 // the number of bits needed to represent the number of particles above (should be ceil(lg(BLOB_MAX_LEVEL_PARTICLES)))
|
||||
#define PARTICLEUSAGENUMINTS ((BLOB_MAX_LEVEL_PARTICLES + (BITS_PER_INT-1)) / BITS_PER_INT)
|
||||
#define BLOBPARTICLEPOSITION(x) (g_pBlobNetworkBypass->vParticlePositions[x])
|
||||
#define BLOBPARTICLERADIUS(x) (g_pBlobNetworkBypass->vParticleRadii[x])
|
||||
#define BLOBPARTICLECLOSESTSURFDIR(x) (g_pBlobNetworkBypass->vParticleClosestSurfDir[x])
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define BLOBPARTICLEPOS_INTERP(x) (g_BlobParticleInterpolation.vInterpolatedPositions[x])
|
||||
#define BLOBPARTICLERADIUS_INTERP(x) (g_BlobParticleInterpolation.vInterpolatedRadii[x])
|
||||
#define BLOBPARTICLECLOSESTSURFDIR_INTERP(x) (g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[x])
|
||||
#endif
|
||||
|
||||
struct BlobNetworkBypass_t
|
||||
{
|
||||
//these 2 ints and bitvec help us communicate which particles contain valid data
|
||||
uint32 iNumParticlesAllocated;
|
||||
uint32 iHighestIndexUsed;
|
||||
CBitVec<BLOB_MAX_LEVEL_PARTICLES> bCurrentlyInUse;
|
||||
|
||||
//actual data we want to communicate using the bypass
|
||||
Vector vParticlePositions[BLOB_MAX_LEVEL_PARTICLES];
|
||||
float vParticleRadii[BLOB_MAX_LEVEL_PARTICLES];
|
||||
Vector vParticleClosestSurfDir[BLOB_MAX_LEVEL_PARTICLES];
|
||||
float fTimeDataUpdated;
|
||||
bool bDataUpdated;
|
||||
};
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
struct BlobParticleInterpolation_t
|
||||
{
|
||||
Vector vInterpolatedPositions[BLOB_MAX_LEVEL_PARTICLES];
|
||||
float vInterpolatedRadii[BLOB_MAX_LEVEL_PARTICLES];
|
||||
Vector vInterpolatedClosestSurfDir[BLOB_MAX_LEVEL_PARTICLES];
|
||||
};
|
||||
extern BlobParticleInterpolation_t g_BlobParticleInterpolation;
|
||||
#endif
|
||||
|
||||
extern BlobNetworkBypass_t *g_pBlobNetworkBypass;
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
int AllocateBlobNetworkBypassIndex( void );
|
||||
void ReleaseBlobNetworkBypassIndex( int iIndex );
|
||||
#endif
|
||||
|
||||
#endif // BLOB_NETWORKBYPASS_H
|
||||
@@ -0,0 +1,439 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "bone_merge_cache.h"
|
||||
#include "bone_setup.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CBoneMergeCache
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CBoneMergeCache::CBoneMergeCache()
|
||||
{
|
||||
Init( NULL );
|
||||
}
|
||||
|
||||
void CBoneMergeCache::Init( CBaseAnimating *pOwner )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
m_pFollow = NULL;
|
||||
m_pFollowHdr = NULL;
|
||||
m_pFollowRenderHdr = NULL;
|
||||
m_pOwnerHdr = NULL;
|
||||
m_pFollowRenderHdr = NULL;
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
m_bForceCacheClear = false;
|
||||
m_MergedBones.Purge();
|
||||
V_memset( m_iRawIndexMapping, 0xFF, sizeof( m_iRawIndexMapping ) ); // initialize to -1s
|
||||
}
|
||||
|
||||
void CBoneMergeCache::UpdateCache()
|
||||
{
|
||||
if ( !m_pOwner )
|
||||
return;
|
||||
|
||||
CStudioHdr *pOwnerHdr = m_pOwner->GetModelPtr();
|
||||
if ( !pOwnerHdr )
|
||||
return;
|
||||
const studiohdr_t *pOwnerRenderHdr = pOwnerHdr->GetRenderHdr();
|
||||
|
||||
CBaseAnimating *pFollow = m_pOwner->FindFollowedEntity();
|
||||
CStudioHdr *pFollowHdr = (pFollow ? pFollow->GetModelPtr() : NULL);
|
||||
const studiohdr_t *pFollowRenderHdr = (pFollowHdr ? pFollowHdr->GetRenderHdr() : NULL );
|
||||
|
||||
// if the follow parent has changed, or any of the underlying models has changed, reset the MergedBones list
|
||||
if ( pFollow != m_pFollow || pFollowRenderHdr != m_pFollowRenderHdr || pOwnerRenderHdr != m_pOwnerRenderHdr || m_bForceCacheClear )
|
||||
{
|
||||
m_MergedBones.Purge();
|
||||
|
||||
m_bForceCacheClear = false;
|
||||
|
||||
// Update the cache.
|
||||
if ( pFollow && pFollowHdr && pOwnerHdr )
|
||||
{
|
||||
m_pFollow = pFollow;
|
||||
m_pFollowHdr = pFollowHdr;
|
||||
m_pFollowRenderHdr = pFollowRenderHdr;
|
||||
m_pOwnerHdr = pOwnerHdr;
|
||||
m_pOwnerRenderHdr = pOwnerRenderHdr;
|
||||
|
||||
m_BoneMergeBits.Resize( pOwnerHdr->numbones() );
|
||||
m_BoneMergeBits.ClearAll();
|
||||
|
||||
const mstudiobone_t *pOwnerBones = m_pOwnerHdr->pBone( 0 );
|
||||
|
||||
m_nFollowBoneSetupMask = BONE_USED_BY_BONE_MERGE;
|
||||
for ( int i = 0; i < m_pOwnerHdr->numbones(); i++ )
|
||||
{
|
||||
int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() );
|
||||
if ( parentBoneIndex < 0 )
|
||||
continue;
|
||||
|
||||
m_iRawIndexMapping[i] = parentBoneIndex;
|
||||
|
||||
// Add a merged bone here.
|
||||
CMergedBone mergedBone;
|
||||
mergedBone.m_iMyBone = i;
|
||||
mergedBone.m_iParentBone = parentBoneIndex;
|
||||
m_MergedBones.AddToTail( mergedBone );
|
||||
m_BoneMergeBits.Set( i );
|
||||
|
||||
// flag bones used in merge so that they'll always be setup
|
||||
if ( ( m_pFollowHdr->boneFlags( parentBoneIndex ) & BONE_USED_BY_BONE_MERGE ) == 0 )
|
||||
{
|
||||
// go ahead and mark the bone and its parents
|
||||
int n = parentBoneIndex;
|
||||
while (n != -1)
|
||||
{
|
||||
m_pFollowHdr->setBoneFlags( n, BONE_USED_BY_BONE_MERGE );
|
||||
n = m_pFollowHdr->boneParent( n );
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: only do this if it's for a "reverse" merge
|
||||
if ( ( m_pOwnerHdr->boneFlags( i ) & BONE_USED_BY_BONE_MERGE ) == 0 )
|
||||
{
|
||||
// go ahead and mark the bone and its parents
|
||||
int n = i;
|
||||
while (n != -1)
|
||||
{
|
||||
m_pOwnerHdr->setBoneFlags( n, BONE_USED_BY_BONE_MERGE );
|
||||
n = m_pOwnerHdr->boneParent( n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No merged bones found? Slam the mask to 0
|
||||
if ( !m_MergedBones.Count() )
|
||||
{
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
}
|
||||
|
||||
// find and record pose params that match by name
|
||||
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
|
||||
{
|
||||
// init mapping as invalid
|
||||
m_nOwnerToFollowPoseParamMapping[i] = -1;
|
||||
|
||||
if ( i < m_pFollowHdr->GetNumPoseParameters() )
|
||||
{
|
||||
// get the follower's pose param name for this index
|
||||
const char * szFollowerPoseParamName = m_pFollowHdr->pPoseParameter( i ).pszName();
|
||||
|
||||
// find it on the owner
|
||||
for ( int n = 0; n < MAXSTUDIOPOSEPARAM && n < m_pOwnerHdr->GetNumPoseParameters(); n++ )
|
||||
{
|
||||
const char * szOwnerPoseParamName = m_pOwnerHdr->pPoseParameter( n ).pszName();
|
||||
if ( !Q_strcmp( szFollowerPoseParamName, szOwnerPoseParamName ) )
|
||||
{
|
||||
//match
|
||||
m_nOwnerToFollowPoseParamMapping[i] = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Init( m_pOwner );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBoneMergeCache::MergeMatchingPoseParams( void )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// set follower pose params using mapped indices from owner
|
||||
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
|
||||
{
|
||||
if ( m_nOwnerToFollowPoseParamMapping[i] != -1 )
|
||||
{
|
||||
m_pOwner->SetPoseParameter( m_nOwnerToFollowPoseParamMapping[i], m_pFollow->GetPoseParameter( i ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
void CBoneMergeCache::MergeMatchingBones( int boneMask )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// Have the entity we're following setup its bones.
|
||||
|
||||
int nTempMask = m_nFollowBoneSetupMask;
|
||||
if ( m_pFollow->IsPlayer() )
|
||||
{
|
||||
// if the parent is a player, respect the incoming bone mask plus attachments,
|
||||
nTempMask = ( boneMask | BONE_USED_BY_ATTACHMENT );
|
||||
|
||||
// but only use the custom blending rule portion
|
||||
if ( m_pFollow->m_nCustomBlendingRuleMask != -1 )
|
||||
nTempMask &= m_pFollow->m_nCustomBlendingRuleMask;
|
||||
}
|
||||
|
||||
m_pFollow->SetupBones( NULL, -1, nTempMask, gpGlobals->curtime );
|
||||
|
||||
// Now copy the bone matrices.
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
void CBoneMergeCache::BuildMatricesWithBoneMerge(
|
||||
const CStudioHdr *pStudioHdr,
|
||||
const QAngle& angles,
|
||||
const Vector& origin,
|
||||
const Vector pos[MAXSTUDIOBONES],
|
||||
const Quaternion q[MAXSTUDIOBONES],
|
||||
matrix3x4_t bonetoworld[MAXSTUDIOBONES],
|
||||
CBaseAnimating *pParent,
|
||||
CBoneCache *pParentCache,
|
||||
int boneMask
|
||||
)
|
||||
{
|
||||
|
||||
UpdateCache();
|
||||
|
||||
|
||||
bool bMergedBone[ MAXSTUDIOBONES ];
|
||||
memset( &bMergedBone, 0, sizeof(bool) * MAXSTUDIOBONES );
|
||||
|
||||
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
if ( iParentBone >= 0 )
|
||||
{
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( pStudioHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
matrix3x4_t *pMat = pParentCache->GetCachedBone( iParentBone );
|
||||
if ( pMat )
|
||||
{
|
||||
MatrixCopy( *pMat, bonetoworld[ iOwnerBone ] );
|
||||
bMergedBone[iOwnerBone] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
|
||||
|
||||
matrix3x4_t rotationmatrix; // model to world transformation
|
||||
AngleMatrix( angles, origin, rotationmatrix);
|
||||
|
||||
for ( int i=0; i < pStudioHdr->numbones(); i++ )
|
||||
{
|
||||
if ( !bMergedBone[i] )
|
||||
{
|
||||
// If we get down here, then the bone wasn't merged.
|
||||
matrix3x4_t bonematrix;
|
||||
QuaternionMatrix( q[i], pos[i], bonematrix );
|
||||
|
||||
if (pbones[i].parent == -1)
|
||||
{
|
||||
ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//CStudioHdr *fhdr = pParent->GetModelPtr();
|
||||
//const mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
|
||||
//
|
||||
//matrix3x4_t rotationmatrix; // model to world transformation
|
||||
//AngleMatrix( angles, origin, rotationmatrix);
|
||||
//
|
||||
//for ( int i=0; i < pStudioHdr->numbones(); i++ )
|
||||
//{
|
||||
// // Now find the bone in the parent entity.
|
||||
// bool merged = false;
|
||||
// int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() );
|
||||
// if ( parentBoneIndex >= 0 )
|
||||
// {
|
||||
// matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex );
|
||||
// if ( pMat )
|
||||
// {
|
||||
// MatrixCopy( *pMat, bonetoworld[ i ] );
|
||||
// merged = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ( !merged )
|
||||
// {
|
||||
// // If we get down here, then the bone wasn't merged.
|
||||
// matrix3x4_t bonematrix;
|
||||
// QuaternionMatrix( q[i], pos[i], bonematrix );
|
||||
//
|
||||
// if (pbones[i].parent == -1)
|
||||
// {
|
||||
// ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void CBoneMergeCache::CopyFromFollow( const BoneVector followPos[], const BoneQuaternion followQ[], int boneMask, BoneVector myPos[], BoneQuaternion myQ[] )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// Now copy the bone matrices.
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
myPos[ iOwnerBone ] = followPos[ iParentBone ];
|
||||
myQ[ iOwnerBone ] = followQ[ iParentBone ];
|
||||
}
|
||||
}
|
||||
|
||||
void CBoneMergeCache::CopyToFollow( const BoneVector myPos[], const BoneQuaternion myQ[], int boneMask, BoneVector followPos[], BoneQuaternion followQ[] )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// Now copy the bone matrices.
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
followPos[ iParentBone ] = myPos[ iOwnerBone ];
|
||||
followQ[ iParentBone ] = myQ[ iOwnerBone ];
|
||||
}
|
||||
m_nCopiedFramecount = gpGlobals->framecount;
|
||||
}
|
||||
|
||||
bool CBoneMergeCache::IsCopied( )
|
||||
{
|
||||
return (m_nCopiedFramecount == gpGlobals->framecount);
|
||||
}
|
||||
|
||||
|
||||
bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return false;
|
||||
|
||||
// We want the abs origin such that if we put the entity there, the first merged bone
|
||||
// will be aligned. This way the entity will be culled in the correct position.
|
||||
//
|
||||
// ie: mEntity * mBoneLocal = mFollowBone
|
||||
// so: mEntity = mFollowBone * Inverse( mBoneLocal )
|
||||
//
|
||||
// Note: the code below doesn't take animation into account. If the attached entity animates
|
||||
// all over the place, then this won't get the right results.
|
||||
|
||||
// FIXME: we're merged onto a dead player that's likely ragdolled all over the place.
|
||||
// The parent's cached position and angles are dirty, but the absorigin and absangles are good enough.
|
||||
// Returning false here means the uncached parent origin/angles will be used.
|
||||
if ( m_pFollow->IsPlayer() && !m_pFollow->IsAlive() )
|
||||
return false;
|
||||
|
||||
// Get mFollowBone.
|
||||
#ifdef CLIENT_DLL
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
|
||||
m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
|
||||
const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
|
||||
#else
|
||||
m_pFollow->SetupBones( NULL, m_nFollowBoneSetupMask );
|
||||
|
||||
matrix3x4_t mFollowBone;
|
||||
m_pFollow->GetBoneTransform( m_MergedBones[0].m_iParentBone, mFollowBone );
|
||||
#endif
|
||||
|
||||
// Get Inverse( mBoneLocal )
|
||||
matrix3x4_t mBoneLocal, mBoneLocalInv;
|
||||
SetupSingleBoneMatrix( m_pOwnerHdr, m_pOwner->GetSequence(), 0, m_MergedBones[0].m_iMyBone, mBoneLocal );
|
||||
MatrixInvert( mBoneLocal, mBoneLocalInv );
|
||||
|
||||
// Now calculate mEntity = mFollowBone * Inverse( mBoneLocal )
|
||||
matrix3x4_t mEntity;
|
||||
ConcatTransforms( mFollowBone, mBoneLocalInv, mEntity );
|
||||
MatrixAngles( mEntity, *pAbsAngles, *pAbsOrigin );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return false;
|
||||
|
||||
// Get mFollowBone.
|
||||
#ifdef CLIENT_DLL
|
||||
m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
|
||||
rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
|
||||
#else
|
||||
m_pFollow->SetupBones( NULL, m_nFollowBoneSetupMask );
|
||||
m_pFollow->GetBoneTransform( m_MergedBones[0].m_iParentBone, rootBone );
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BONE_MERGE_CACHE_H
|
||||
#define BONE_MERGE_CACHE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#undef CBaseAnimating
|
||||
#define CBaseAnimating C_BaseAnimating
|
||||
#endif
|
||||
|
||||
class CBaseAnimating;
|
||||
class CStudioHdr;
|
||||
struct studiohdr_t;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "bone_setup.h"
|
||||
#endif
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
|
||||
class CBoneMergeCache
|
||||
{
|
||||
public:
|
||||
|
||||
CBoneMergeCache();
|
||||
|
||||
void Init( CBaseAnimating *pOwner );
|
||||
|
||||
// Updates the lookups that let it merge bones quickly.
|
||||
void UpdateCache();
|
||||
|
||||
// This copies the transform from all bones in the followed entity that have
|
||||
// names that match our bones.
|
||||
#ifdef CLIENT_DLL
|
||||
void MergeMatchingBones( int boneMask );
|
||||
#else
|
||||
void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles,
|
||||
const Vector& origin, const Vector pos[MAXSTUDIOBONES],
|
||||
const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES],
|
||||
CBaseAnimating *pParent, CBoneCache *pParentCache, int boneMask );
|
||||
#endif
|
||||
|
||||
|
||||
void MergeMatchingPoseParams( void );
|
||||
|
||||
void CopyFromFollow( const BoneVector followPos[], const BoneQuaternion followQ[], int boneMask, BoneVector myPos[], BoneQuaternion myQ[] );
|
||||
void CopyToFollow( const BoneVector myPos[], const BoneQuaternion myQ[], int boneMask, BoneVector followPos[], BoneQuaternion followQ[] );
|
||||
bool IsCopied( );
|
||||
|
||||
// Returns true if the specified bone is one that gets merged in MergeMatchingBones.
|
||||
int IsBoneMerged( int iBone ) const;
|
||||
|
||||
// Gets the origin for the first merge bone on the parent.
|
||||
bool GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles );
|
||||
bool GetRootBone( matrix3x4_t &rootBone );
|
||||
|
||||
void ForceCacheClear( void ) { m_bForceCacheClear = true; UpdateCache(); }
|
||||
|
||||
const unsigned short *GetRawIndexMapping( void ) { return &m_iRawIndexMapping[0]; }
|
||||
|
||||
protected:
|
||||
|
||||
// This is the entity that we're keeping the cache updated for.
|
||||
CBaseAnimating *m_pOwner;
|
||||
|
||||
// All the cache data is based off these. When they change, the cache data is regenerated.
|
||||
// These are either all valid pointers or all NULL.
|
||||
CBaseAnimating *m_pFollow;
|
||||
CStudioHdr *m_pFollowHdr;
|
||||
const studiohdr_t *m_pFollowRenderHdr;
|
||||
CStudioHdr *m_pOwnerHdr;
|
||||
const studiohdr_t *m_pOwnerRenderHdr;
|
||||
|
||||
// keeps track if this entity is part of a reverse bonemerge
|
||||
int m_nCopiedFramecount;
|
||||
|
||||
// This is the mask we need to use to set up bones on the followed entity to do the bone merge
|
||||
int m_nFollowBoneSetupMask;
|
||||
|
||||
// Cache data.
|
||||
class CMergedBone
|
||||
{
|
||||
public:
|
||||
unsigned short m_iMyBone; // index of MergeCache's owner's bone
|
||||
unsigned short m_iParentBone; // index of m_pFollow's matching bone
|
||||
};
|
||||
|
||||
// This is an array of pose param indices on the follower to pose param indices on the owner
|
||||
int m_nOwnerToFollowPoseParamMapping[MAXSTUDIOPOSEPARAM];
|
||||
|
||||
CUtlVector<CMergedBone> m_MergedBones;
|
||||
CVarBitVec m_BoneMergeBits; // One bit for each bone. The bit is set if the bone gets merged.
|
||||
|
||||
unsigned short m_iRawIndexMapping[ MAXSTUDIOBONES ];
|
||||
|
||||
bool m_bForceCacheClear;
|
||||
};
|
||||
|
||||
|
||||
inline int CBoneMergeCache::IsBoneMerged( int iBone ) const
|
||||
{
|
||||
if ( m_pOwnerHdr )
|
||||
return m_BoneMergeBits.Get( iBone );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif // BONE_MERGE_CACHE_H
|
||||
@@ -0,0 +1,233 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cam_thirdperson.h"
|
||||
#include "gamerules.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static Vector CAM_HULL_MIN(-CAM_HULL_OFFSET,-CAM_HULL_OFFSET,-CAM_HULL_OFFSET);
|
||||
static Vector CAM_HULL_MAX( CAM_HULL_OFFSET, CAM_HULL_OFFSET, CAM_HULL_OFFSET);
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "input.h"
|
||||
|
||||
|
||||
extern const ConVar *sv_cheats;
|
||||
|
||||
extern ConVar cam_idealdist;
|
||||
extern ConVar cam_idealdistright;
|
||||
extern ConVar cam_idealdistup;
|
||||
|
||||
void CAM_ToThirdPerson(void);
|
||||
void CAM_ToFirstPerson(void);
|
||||
|
||||
void ToggleThirdPerson( bool bValue )
|
||||
{
|
||||
if ( bValue == true )
|
||||
{
|
||||
CAM_ToThirdPerson();
|
||||
}
|
||||
else
|
||||
{
|
||||
CAM_ToFirstPerson();
|
||||
}
|
||||
}
|
||||
|
||||
void ThirdPersonChange( IConVar *pConVar, const char *pOldValue, float flOldValue )
|
||||
{
|
||||
ConVarRef var( pConVar );
|
||||
|
||||
ToggleThirdPerson( var.GetBool() );
|
||||
}
|
||||
|
||||
ConVar cl_thirdperson( "cl_thirdperson", "0", FCVAR_NOT_CONNECTED | FCVAR_ARCHIVE | FCVAR_DEVELOPMENTONLY, "Enables/Disables third person", ThirdPersonChange );
|
||||
|
||||
#endif
|
||||
|
||||
CThirdPersonManager::CThirdPersonManager( void )
|
||||
{
|
||||
}
|
||||
|
||||
void CThirdPersonManager::Init( void )
|
||||
{
|
||||
m_bOverrideThirdPerson = false;
|
||||
m_bForced = false;
|
||||
m_flUpFraction = 0.0f;
|
||||
m_flFraction = 1.0f;
|
||||
|
||||
m_flUpLerpTime = 0.0f;
|
||||
m_flLerpTime = 0.0f;
|
||||
|
||||
m_flUpOffset = CAMERA_UP_OFFSET;
|
||||
|
||||
if ( input )
|
||||
{
|
||||
input->CAM_SetCameraThirdData( NULL, vec3_angle );
|
||||
}
|
||||
}
|
||||
|
||||
void CThirdPersonManager::Update( void )
|
||||
{
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
if ( !sv_cheats )
|
||||
{
|
||||
sv_cheats = cvar->FindVar( "sv_cheats" );
|
||||
}
|
||||
|
||||
bool bIsThirdPerson = input->CAM_IsThirdPerson() != 0;
|
||||
|
||||
// If cheats have been disabled, pull us back out of third-person view.
|
||||
if ( sv_cheats && !sv_cheats->GetBool() && GameRules() && GameRules()->AllowThirdPersonCamera() == false )
|
||||
{
|
||||
if ( bIsThirdPerson )
|
||||
{
|
||||
input->CAM_ToFirstPerson();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( IsOverridingThirdPerson() == false )
|
||||
{
|
||||
|
||||
if ( bIsThirdPerson != ( cl_thirdperson.GetBool() || m_bForced ) && GameRules() && GameRules()->AllowThirdPersonCamera() == true )
|
||||
{
|
||||
ToggleThirdPerson( m_bForced || cl_thirdperson.GetBool() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Vector CThirdPersonManager::GetDesiredCameraOffset( void )
|
||||
{
|
||||
if ( IsOverridingThirdPerson() == true )
|
||||
{
|
||||
return Vector( cam_idealdist.GetFloat(), cam_idealdistright.GetFloat(), cam_idealdistup.GetFloat() );
|
||||
}
|
||||
|
||||
return m_vecDesiredCameraOffset;
|
||||
}
|
||||
|
||||
Vector CThirdPersonManager::GetFinalCameraOffset( void )
|
||||
{
|
||||
Vector vDesired = GetDesiredCameraOffset();
|
||||
|
||||
if ( m_flUpFraction != 1.0f )
|
||||
{
|
||||
vDesired.z += m_flUpOffset;
|
||||
}
|
||||
|
||||
return vDesired;
|
||||
|
||||
}
|
||||
|
||||
Vector CThirdPersonManager::GetDistanceFraction( void )
|
||||
{
|
||||
if ( IsOverridingThirdPerson() == true )
|
||||
{
|
||||
return Vector( m_flTargetFraction, m_flTargetFraction, m_flTargetFraction );
|
||||
}
|
||||
|
||||
float flFraction = m_flFraction;
|
||||
float flUpFraction = m_flUpFraction;
|
||||
|
||||
float flFrac = RemapValClamped( gpGlobals->curtime - m_flLerpTime, 0, CAMERA_OFFSET_LERP_TIME, 0, 1 );
|
||||
|
||||
flFraction = Lerp( flFrac, m_flFraction, m_flTargetFraction );
|
||||
|
||||
if ( flFrac == 1.0f )
|
||||
{
|
||||
m_flFraction = m_flTargetFraction;
|
||||
}
|
||||
|
||||
flFrac = RemapValClamped( gpGlobals->curtime - m_flUpLerpTime, 0, CAMERA_UP_OFFSET_LERP_TIME, 0, 1 );
|
||||
|
||||
flUpFraction = 1.0f - Lerp( flFrac, m_flUpFraction, m_flTargetUpFraction );
|
||||
|
||||
if ( flFrac == 1.0f )
|
||||
{
|
||||
m_flUpFraction = m_flTargetUpFraction;
|
||||
}
|
||||
|
||||
return Vector( flFraction, flFraction, flUpFraction );
|
||||
}
|
||||
|
||||
void CThirdPersonManager::PositionCamera( CBasePlayer *pPlayer, QAngle angles )
|
||||
{
|
||||
if ( pPlayer )
|
||||
{
|
||||
trace_t trace;
|
||||
|
||||
Vector camForward, camRight, camUp;
|
||||
|
||||
// find our player's origin, and from there, the eye position
|
||||
Vector origin = pPlayer->GetLocalOrigin();
|
||||
origin += pPlayer->GetViewOffset();
|
||||
|
||||
AngleVectors( angles, &camForward, &camRight, &camUp );
|
||||
|
||||
Vector endPos = origin;
|
||||
|
||||
Vector vecCamOffset = endPos + (camForward * - GetDesiredCameraOffset()[DIST_FORWARD]) + (camRight * GetDesiredCameraOffset()[ DIST_RIGHT ]) + (camUp * GetDesiredCameraOffset()[ DIST_UP ] );
|
||||
|
||||
// use our previously #defined hull to collision trace
|
||||
CTraceFilterSimple traceFilter( pPlayer, COLLISION_GROUP_NONE );
|
||||
UTIL_TraceHull( endPos, vecCamOffset, CAM_HULL_MIN, CAM_HULL_MAX, MASK_SOLID & ~CONTENTS_MONSTER, &traceFilter, &trace );
|
||||
|
||||
if ( trace.fraction != m_flTargetFraction )
|
||||
{
|
||||
m_flLerpTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
m_flTargetFraction = trace.fraction;
|
||||
m_flTargetUpFraction = 1.0f;
|
||||
|
||||
//If we're getting closer to a wall snap the fraction right away.
|
||||
if ( m_flTargetFraction < m_flFraction )
|
||||
{
|
||||
m_flFraction = m_flTargetFraction;
|
||||
m_flLerpTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
|
||||
// move the camera closer if it hit something
|
||||
if( trace.fraction < 1.0 )
|
||||
{
|
||||
m_vecCameraOffset[ DIST ] *= trace.fraction;
|
||||
|
||||
UTIL_TraceHull( endPos, endPos + (camForward * - GetDesiredCameraOffset()[DIST_FORWARD]), CAM_HULL_MIN, CAM_HULL_MAX, MASK_SOLID & ~CONTENTS_MONSTER, &traceFilter, &trace );
|
||||
|
||||
if ( trace.fraction != 1.0f )
|
||||
{
|
||||
if ( trace.fraction != m_flTargetUpFraction )
|
||||
{
|
||||
m_flUpLerpTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
m_flTargetUpFraction = trace.fraction;
|
||||
|
||||
if ( m_flTargetUpFraction < m_flUpFraction )
|
||||
{
|
||||
m_flUpFraction = trace.fraction;
|
||||
m_flUpLerpTime = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CThirdPersonManager::WantToUseGameThirdPerson( void )
|
||||
{
|
||||
return cl_thirdperson.GetBool() && GameRules() && GameRules()->AllowThirdPersonCamera() && IsOverridingThirdPerson() == false;
|
||||
}
|
||||
|
||||
|
||||
CThirdPersonManager g_ThirdPersonManager;
|
||||
@@ -0,0 +1,108 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CAM_THIRDPERSON_H
|
||||
#define CAM_THIRDPERSON_H
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_baseplayer.h"
|
||||
#else
|
||||
#include "baseplayer.h"
|
||||
#endif
|
||||
|
||||
#define DIST_FORWARD 0
|
||||
#define DIST_RIGHT 1
|
||||
#define DIST_UP 2
|
||||
|
||||
//-------------------------------------------------- Constants
|
||||
|
||||
#define CAM_MIN_DIST 30.0
|
||||
#define CAM_ANGLE_MOVE .5
|
||||
#define MAX_ANGLE_DIFF 10.0
|
||||
#define PITCH_MAX 90.0
|
||||
#define PITCH_MIN 0
|
||||
#define YAW_MAX 135.0
|
||||
#define YAW_MIN -135.0
|
||||
#define DIST 2
|
||||
#define CAM_HULL_OFFSET 14.0 // the size of the bounding hull used for collision checking
|
||||
|
||||
#define CAMERA_UP_OFFSET 25.0f
|
||||
#define CAMERA_OFFSET_LERP_TIME 0.5f
|
||||
#define CAMERA_UP_OFFSET_LERP_TIME 0.25f
|
||||
|
||||
class CThirdPersonManager
|
||||
{
|
||||
public:
|
||||
|
||||
CThirdPersonManager();
|
||||
void SetCameraOffsetAngles( Vector vecOffset ) { m_vecCameraOffset = vecOffset; }
|
||||
Vector GetCameraOffsetAngles( void ) { return m_vecCameraOffset; }
|
||||
|
||||
void SetDesiredCameraOffset( Vector vecOffset ) { m_vecDesiredCameraOffset = vecOffset; }
|
||||
Vector GetDesiredCameraOffset( void );
|
||||
|
||||
Vector GetFinalCameraOffset( void );
|
||||
|
||||
void SetCameraOrigin( Vector vecOffset ) { m_vecCameraOrigin = vecOffset; }
|
||||
Vector GetCameraOrigin( void ) { return m_vecCameraOrigin; }
|
||||
|
||||
void Update( void );
|
||||
|
||||
void PositionCamera( CBasePlayer *pPlayer, QAngle angles );
|
||||
|
||||
void UseCameraOffsets( bool bUse ) { m_bUseCameraOffsets = bUse; }
|
||||
bool UsingCameraOffsets( void ) { return m_bUseCameraOffsets; }
|
||||
|
||||
QAngle GetCameraViewAngles( void ) { return m_ViewAngles; }
|
||||
|
||||
Vector GetDistanceFraction( void );
|
||||
|
||||
bool WantToUseGameThirdPerson( void );
|
||||
|
||||
void SetOverridingThirdPerson( bool bOverride ) { m_bOverrideThirdPerson = bOverride; }
|
||||
bool IsOverridingThirdPerson( void ) { return m_bOverrideThirdPerson; }
|
||||
|
||||
void Init( void );
|
||||
|
||||
void SetForcedThirdPerson( bool bForced ) { m_bForced = bForced; }
|
||||
bool GetForcedThirdPerson() const { return m_bForced; }
|
||||
|
||||
private:
|
||||
|
||||
// What is the current camera offset from the view origin?
|
||||
Vector m_vecCameraOffset;
|
||||
// Distances from the center
|
||||
Vector m_vecDesiredCameraOffset;
|
||||
|
||||
Vector m_vecCameraOrigin;
|
||||
|
||||
bool m_bUseCameraOffsets;
|
||||
|
||||
QAngle m_ViewAngles;
|
||||
|
||||
float m_flFraction;
|
||||
float m_flUpFraction;
|
||||
|
||||
float m_flTargetFraction;
|
||||
float m_flTargetUpFraction;
|
||||
|
||||
bool m_bOverrideThirdPerson;
|
||||
|
||||
bool m_bForced;
|
||||
|
||||
float m_flUpOffset;
|
||||
|
||||
float m_flLerpTime;
|
||||
float m_flUpLerpTime;
|
||||
};
|
||||
|
||||
extern CThirdPersonManager g_ThirdPersonManager;
|
||||
|
||||
#endif // CAM_THIRDPERSON_H
|
||||
@@ -0,0 +1,63 @@
|
||||
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Utility functions for cell coordinate calculations
|
||||
// to reduce bandwidth usage
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CELLCOORD_H
|
||||
#define CELLCOORD_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "worldsize.h"
|
||||
|
||||
// Given a world coord, return the cell it should be in
|
||||
inline int CellFromCoord( int cellwidth, float f )
|
||||
{
|
||||
// We handle each side of zero difference to reduce precision errors
|
||||
if ( f < 0.0f )
|
||||
{
|
||||
return Float2Int( f + MAX_COORD_INTEGER ) / cellwidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Float2Int(f) / cellwidth + ( MAX_COORD_INTEGER / cellwidth );
|
||||
}
|
||||
}
|
||||
|
||||
// Given a cell and a world coord, return the offset into the cell
|
||||
// cell should have been returned from CellFromCoord with the same f, we don't
|
||||
// recompute here
|
||||
inline float CellInCoord( int cellwidth, int cell, float f )
|
||||
{
|
||||
float r;
|
||||
|
||||
int c = abs( cell * cellwidth - MAX_COORD_INTEGER ) ;
|
||||
|
||||
if ( f < 0.0f )
|
||||
{
|
||||
r = c + f;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = f - c;
|
||||
}
|
||||
|
||||
// Pecision errors can futz the edges
|
||||
return clamp( r, 0.0f, (float)cellwidth );
|
||||
}
|
||||
|
||||
// Given a cell and an offset in that cell, reconstructor the world coord
|
||||
inline float CoordFromCell( int cellwidth, int cell, float f )
|
||||
{
|
||||
int cellPos = ( cell * cellwidth );
|
||||
|
||||
float r = ( cellPos - MAX_COORD_INTEGER ) + f;
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif //CELLCOORDCONVERTER_H
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "choreoactor.h"
|
||||
#include "choreochannel.h"
|
||||
#include "choreoscene.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoActor::CChoreoActor( void )
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoActor::CChoreoActor( const char *name )
|
||||
{
|
||||
Init();
|
||||
SetName( name );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: // Assignment
|
||||
// Input : src -
|
||||
// Output : CChoreoActor&
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoActor& CChoreoActor::operator=( const CChoreoActor& src )
|
||||
{
|
||||
m_bActive = src.m_bActive;
|
||||
|
||||
Q_strncpy( m_szName, src.m_szName, sizeof( m_szName ) );
|
||||
Q_strncpy( m_szFacePoserModelName, src.m_szFacePoserModelName, sizeof( m_szFacePoserModelName ) );
|
||||
|
||||
for ( int i = 0; i < src.m_Channels.Count(); i++ )
|
||||
{
|
||||
CChoreoChannel *c = src.m_Channels[ i ];
|
||||
CChoreoChannel *newChannel = new CChoreoChannel();
|
||||
newChannel->SetActor( this );
|
||||
*newChannel = *c;
|
||||
AddChannel( newChannel );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::Init( void )
|
||||
{
|
||||
m_szName[ 0 ] = 0;
|
||||
m_szFacePoserModelName[ 0 ] = 0;
|
||||
m_bActive = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::SetName( const char *name )
|
||||
{
|
||||
assert( strlen( name ) < MAX_ACTOR_NAME );
|
||||
Q_strncpy( m_szName, name, sizeof( m_szName ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CChoreoActor::GetName( void )
|
||||
{
|
||||
return m_szName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CChoreoActor::GetNumChannels( void )
|
||||
{
|
||||
return m_Channels.Count();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : channel -
|
||||
// Output : CChoreoChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoChannel *CChoreoActor::GetChannel( int channel )
|
||||
{
|
||||
if ( channel < 0 || channel >= m_Channels.Count() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_Channels[ channel ];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *channel -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::AddChannel( CChoreoChannel *channel )
|
||||
{
|
||||
m_Channels.AddToTail( channel );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *channel -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::RemoveChannel( CChoreoChannel *channel )
|
||||
{
|
||||
int idx = FindChannelIndex( channel );
|
||||
if ( idx == -1 )
|
||||
return;
|
||||
|
||||
m_Channels.Remove( idx );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::RemoveAllChannels()
|
||||
{
|
||||
m_Channels.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : c1 -
|
||||
// c2 -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::SwapChannels( int c1, int c2 )
|
||||
{
|
||||
CChoreoChannel *temp;
|
||||
|
||||
temp = m_Channels[ c1 ];
|
||||
m_Channels[ c1 ] = m_Channels[ c2 ];
|
||||
m_Channels[ c2 ] = temp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *channel -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CChoreoActor::FindChannelIndex( CChoreoChannel *channel )
|
||||
{
|
||||
for ( int i = 0; i < m_Channels.Count(); i++ )
|
||||
{
|
||||
if ( channel == m_Channels[ i ] )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::SetFacePoserModelName( const char *name )
|
||||
{
|
||||
Q_strncpy( m_szFacePoserModelName, name, sizeof( m_szFacePoserModelName ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : char const
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CChoreoActor::GetFacePoserModelName( void ) const
|
||||
{
|
||||
return m_szFacePoserModelName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : active -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::SetActive( bool active )
|
||||
{
|
||||
m_bActive = active;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CChoreoActor::GetActive( void ) const
|
||||
{
|
||||
return m_bActive;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoActor::MarkForSaveAll( bool mark )
|
||||
{
|
||||
SetMarkedForSave( mark );
|
||||
|
||||
int c = GetNumChannels();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoChannel *channel = GetChannel( i );
|
||||
channel->MarkForSaveAll( mark );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
// Output : CChoreoChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoChannel *CChoreoActor::FindChannel( const char *name )
|
||||
{
|
||||
int c = GetNumChannels();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoChannel *channel = GetChannel( i );
|
||||
if ( !Q_stricmp( channel->GetName(), name ) )
|
||||
return channel;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CChoreoActor::SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool )
|
||||
{
|
||||
buf.PutShort( pStringPool->FindOrAddString( GetName() ) );
|
||||
|
||||
int c = GetNumChannels();
|
||||
Assert( c <= 255 );
|
||||
buf.PutUnsignedChar( c );
|
||||
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoChannel *channel = GetChannel( i );
|
||||
Assert( channel );
|
||||
channel->SaveToBuffer( buf, pScene, pStringPool );
|
||||
}
|
||||
|
||||
/*
|
||||
if ( Q_strlen( a->GetFacePoserModelName() ) > 0 )
|
||||
{
|
||||
FilePrintf( buf, level + 1, "faceposermodel \"%s\"\n", a->GetFacePoserModelName() );
|
||||
}
|
||||
*/
|
||||
buf.PutChar( GetActive() ? 1 : 0 );
|
||||
}
|
||||
|
||||
bool CChoreoActor::RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool )
|
||||
{
|
||||
char sz[ 256 ];
|
||||
pStringPool->GetString( buf.GetShort(), sz, sizeof( sz ) );
|
||||
|
||||
SetName( sz );
|
||||
|
||||
int i;
|
||||
int c = buf.GetUnsignedChar();
|
||||
for ( i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoChannel *channel = pScene->AllocChannel();
|
||||
Assert( channel );
|
||||
if ( channel->RestoreFromBuffer( buf, pScene, this, pStringPool ) )
|
||||
{
|
||||
AddChannel( channel );
|
||||
channel->SetActor( this );
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SetActive( buf.GetChar() == 1 ? true : false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef CHOREOACTOR_H
|
||||
#define CHOREOACTOR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utlvector.h"
|
||||
|
||||
class CChoreoChannel;
|
||||
class CChoreoScene;
|
||||
class CUtlBuffer;
|
||||
class IChoreoStringPool;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The actor is the atomic element of a scene
|
||||
// A scene can have one or more actors, who have multiple events on one or
|
||||
// more channels
|
||||
//-----------------------------------------------------------------------------
|
||||
class CChoreoActor
|
||||
{
|
||||
public:
|
||||
|
||||
// Construction
|
||||
CChoreoActor( void );
|
||||
CChoreoActor( const char *name );
|
||||
// Assignment
|
||||
CChoreoActor& operator = ( const CChoreoActor& src );
|
||||
|
||||
// Serialization
|
||||
void SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
|
||||
bool RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
|
||||
|
||||
// Accessors
|
||||
void SetName( const char *name );
|
||||
const char *GetName( void );
|
||||
|
||||
// Iteration
|
||||
int GetNumChannels( void );
|
||||
CChoreoChannel *GetChannel( int channel );
|
||||
|
||||
CChoreoChannel *FindChannel( const char *name );
|
||||
|
||||
// Manipulate children
|
||||
void AddChannel( CChoreoChannel *channel );
|
||||
void RemoveChannel( CChoreoChannel *channel );
|
||||
int FindChannelIndex( CChoreoChannel *channel );
|
||||
void SwapChannels( int c1, int c2 );
|
||||
void RemoveAllChannels();
|
||||
|
||||
void SetFacePoserModelName( const char *name );
|
||||
char const *GetFacePoserModelName( void ) const;
|
||||
|
||||
void SetActive( bool active );
|
||||
bool GetActive( void ) const;
|
||||
|
||||
bool IsMarkedForSave() const { return m_bMarkedForSave; }
|
||||
void SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; }
|
||||
|
||||
void MarkForSaveAll( bool mark );
|
||||
|
||||
private:
|
||||
// Clear structure out
|
||||
void Init( void );
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_ACTOR_NAME = 128,
|
||||
MAX_FACEPOSER_MODEL_NAME = 128
|
||||
};
|
||||
|
||||
char m_szName[ MAX_ACTOR_NAME ];
|
||||
char m_szFacePoserModelName[ MAX_FACEPOSER_MODEL_NAME ];
|
||||
|
||||
// Children
|
||||
CUtlVector < CChoreoChannel * > m_Channels;
|
||||
|
||||
bool m_bActive;
|
||||
|
||||
// Purely for save/load
|
||||
bool m_bMarkedForSave;
|
||||
};
|
||||
|
||||
#endif // CHOREOACTOR_H
|
||||
@@ -0,0 +1,563 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "choreochannel.h"
|
||||
#include "choreoevent.h"
|
||||
#include "choreoscene.h"
|
||||
#include "utlrbtree.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoChannel::CChoreoChannel( void )
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoChannel::CChoreoChannel(const char *name )
|
||||
{
|
||||
Init();
|
||||
SetName( name );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Assignment
|
||||
// Input : src -
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoChannel& CChoreoChannel::operator=( const CChoreoChannel& src )
|
||||
{
|
||||
m_bActive = src.m_bActive;
|
||||
Q_strncpy( m_szName, src.m_szName, sizeof( m_szName ) );
|
||||
for ( int i = 0; i < src.m_Events.Count(); i++ )
|
||||
{
|
||||
CChoreoEvent *e = src.m_Events[ i ];
|
||||
CChoreoEvent *newEvent = new CChoreoEvent( e->GetScene() );
|
||||
*newEvent = *e;
|
||||
AddEvent( newEvent );
|
||||
newEvent->SetChannel( this );
|
||||
newEvent->SetActor( m_pActor );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::SetName( const char *name )
|
||||
{
|
||||
assert( Q_strlen( name ) < MAX_CHANNEL_NAME );
|
||||
Q_strncpy( m_szName, name, sizeof( m_szName ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CChoreoChannel::GetName( void )
|
||||
{
|
||||
return m_szName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CChoreoChannel::GetNumEvents( void )
|
||||
{
|
||||
return m_Events.Count();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : event -
|
||||
// Output : CChoreoEvent
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoEvent *CChoreoChannel::GetEvent( int event )
|
||||
{
|
||||
if ( event < 0 || event >= m_Events.Count() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_Events[ event ];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *event -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::AddEvent( CChoreoEvent *event )
|
||||
{
|
||||
m_Events.AddToTail( event );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *event -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::RemoveEvent( CChoreoEvent *event )
|
||||
{
|
||||
int idx = FindEventIndex( event );
|
||||
if ( idx == -1 )
|
||||
return;
|
||||
|
||||
m_Events.Remove( idx );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::RemoveAllEvents()
|
||||
{
|
||||
m_Events.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *event -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CChoreoChannel::FindEventIndex( CChoreoEvent *event )
|
||||
{
|
||||
for ( int i = 0; i < m_Events.Count(); i++ )
|
||||
{
|
||||
if ( event == m_Events[ i ] )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::Init( void )
|
||||
{
|
||||
m_szName[ 0 ] = 0;
|
||||
SetActor( NULL );
|
||||
m_bActive = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CChoreoActor
|
||||
//-----------------------------------------------------------------------------
|
||||
CChoreoActor *CChoreoChannel::GetActor( void )
|
||||
{
|
||||
return m_pActor;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *actor -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::SetActor( CChoreoActor *actor )
|
||||
{
|
||||
m_pActor = actor;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : active -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::SetActive( bool active )
|
||||
{
|
||||
m_bActive = active;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CChoreoChannel::GetActive( void ) const
|
||||
{
|
||||
return m_bActive;
|
||||
}
|
||||
|
||||
static bool ChoreEventStartTimeLessFunc( CChoreoEvent * const &p1, CChoreoEvent * const &p2 )
|
||||
{
|
||||
CChoreoEvent *e1;
|
||||
CChoreoEvent *e2;
|
||||
|
||||
e1 = const_cast< CChoreoEvent * >( p1 );
|
||||
e2 = const_cast< CChoreoEvent * >( p2 );
|
||||
|
||||
return e1->GetStartTime() < e2->GetStartTime();
|
||||
}
|
||||
|
||||
void CChoreoChannel::ReconcileGestureTimes()
|
||||
{
|
||||
// Sort gesture events within channel by starting time
|
||||
CUtlRBTree< CChoreoEvent * > sortedGestures( 0, 0, ChoreEventStartTimeLessFunc );
|
||||
int i;
|
||||
// Sort items
|
||||
int c = GetNumEvents();
|
||||
for ( i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoEvent *e = GetEvent( i );
|
||||
Assert( e );
|
||||
if ( e->GetType() != CChoreoEvent::GESTURE )
|
||||
continue;
|
||||
|
||||
sortedGestures.Insert( e );
|
||||
}
|
||||
|
||||
// Now walk list of gestures
|
||||
if ( !sortedGestures.Count() )
|
||||
return;
|
||||
|
||||
CChoreoEvent *previous = NULL;
|
||||
|
||||
for ( i = sortedGestures.FirstInorder(); i != sortedGestures.InvalidIndex(); i = sortedGestures.NextInorder( i ) )
|
||||
{
|
||||
CChoreoEvent *event = sortedGestures[ i ];
|
||||
|
||||
if ( !previous )
|
||||
{
|
||||
// event->SetStartTime( 0.0f );
|
||||
}
|
||||
else if ( previous->GetSyncToFollowingGesture() )
|
||||
{
|
||||
// TODO: ask the sequence for what tags to match
|
||||
|
||||
CEventAbsoluteTag *pEntryTag = event->FindEntryTag( CChoreoEvent::PLAYBACK );
|
||||
CEventAbsoluteTag *pExitTag = previous->FindExitTag( CChoreoEvent::PLAYBACK );
|
||||
|
||||
if (pEntryTag && pExitTag)
|
||||
{
|
||||
float entryTime = pEntryTag->GetAbsoluteTime( );
|
||||
|
||||
// get current decay rate of previous gesture
|
||||
float duration = previous->GetDuration();
|
||||
float decayTime = (1.0 - pExitTag->GetPercentage()) * duration;
|
||||
|
||||
// adjust the previous gestures end time to current apex + existing decay rate
|
||||
previous->RescaleGestureTimes( previous->GetStartTime(), entryTime + decayTime, true );
|
||||
previous->SetEndTime( entryTime + decayTime );
|
||||
|
||||
// set the previous gestures end tag to the current apex
|
||||
pExitTag->SetAbsoluteTime( entryTime );
|
||||
|
||||
event->PreventTagOverlap( );
|
||||
previous->PreventTagOverlap( );
|
||||
}
|
||||
// BUG: Tracker 3298: ywb 1/31/04
|
||||
// I think this fixes the issue with abutting past NULL gestures on paste:
|
||||
// Here's the bug report:
|
||||
// -------------------------
|
||||
// When copying and pasteing posture and gesture clips in face poser the beginings of the clips stretch
|
||||
// to the begining of the scene even if there is a null gesture in place at the begining.
|
||||
// -------------------------
|
||||
/*
|
||||
else if ( pEntryTag && !Q_stricmp( previous->GetName(), "NULL" ) )
|
||||
{
|
||||
// If the previous was a null event, then do a bit of fixup
|
||||
event->SetStartTime( previous->GetEndTime() );
|
||||
|
||||
event->PreventTagOverlap( );
|
||||
}
|
||||
*/
|
||||
|
||||
// The previous event decays from it's end dispaly end time to the current event's display start time
|
||||
// The next event starts just after the display end time of the previous event
|
||||
}
|
||||
|
||||
previous = event;
|
||||
}
|
||||
|
||||
if ( previous )
|
||||
{
|
||||
CChoreoScene *scene = previous->GetScene();
|
||||
if ( scene )
|
||||
{
|
||||
// HACK: Could probably do better by allowing user to drag the blue "end time" bar
|
||||
//float finish = scene->FindStopTime();
|
||||
//previous->RescaleGestureTimes( previous->GetStartTime(), finish );
|
||||
//previous->SetEndTime( finish );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
c = 0;
|
||||
for ( i = sortedGestures.FirstInorder(); i != sortedGestures.InvalidIndex(); i = sortedGestures.NextInorder( i ) )
|
||||
{
|
||||
CChoreoEvent *event = sortedGestures[ i ];
|
||||
|
||||
Msg( "event %i start %f disp %f dispend %f end %f\n",
|
||||
c + 1,
|
||||
event->GetStartTime( CChoreoEvent::SIMULATION ),
|
||||
event->GetStartTime( CChoreoEvent::DISPLAY ),
|
||||
event->GetEndTime( CChoreoEvent::DISPLAY ),
|
||||
event->GetEndTime( CChoreoEvent::SIMULATION )
|
||||
);
|
||||
c++;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::MarkForSaveAll( bool mark )
|
||||
{
|
||||
SetMarkedForSave( mark );
|
||||
|
||||
int c = GetNumEvents();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoEvent *e = GetEvent( i );
|
||||
e->SetMarkedForSave( mark );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct EventGroup
|
||||
{
|
||||
EventGroup() :
|
||||
timeSortedEvents( 0, 0, ChoreEventStartTimeLessFunc )
|
||||
{
|
||||
}
|
||||
|
||||
EventGroup( const EventGroup& src )
|
||||
:
|
||||
timeSortedEvents( 0, 0, ChoreEventStartTimeLessFunc )
|
||||
{
|
||||
timeSortedEvents.RemoveAll();
|
||||
int i = src.timeSortedEvents.FirstInorder();
|
||||
while ( i != src.timeSortedEvents.InvalidIndex() )
|
||||
{
|
||||
timeSortedEvents.Insert( src.timeSortedEvents[ i ] );
|
||||
|
||||
i = src.timeSortedEvents.NextInorder( i );
|
||||
}
|
||||
}
|
||||
|
||||
EventGroup & operator=( const EventGroup& src )
|
||||
{
|
||||
if ( this == &src )
|
||||
return *this;
|
||||
|
||||
timeSortedEvents.RemoveAll();
|
||||
int i = src.timeSortedEvents.FirstInorder();
|
||||
while ( i != src.timeSortedEvents.InvalidIndex() )
|
||||
{
|
||||
timeSortedEvents.Insert( src.timeSortedEvents[ i ] );
|
||||
|
||||
i = src.timeSortedEvents.NextInorder( i );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CUtlRBTree< CChoreoEvent * > timeSortedEvents;
|
||||
};
|
||||
|
||||
// Compute master/slave, count, endtime info for close captioning data
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CChoreoChannel::ReconcileCloseCaption()
|
||||
{
|
||||
// Create a dictionary based on the combined token name
|
||||
CUtlDict< EventGroup, int > validSpeakEventsGroupedByName;
|
||||
|
||||
int i;
|
||||
// Sort items
|
||||
int c = GetNumEvents();
|
||||
for ( i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoEvent *e = GetEvent( i );
|
||||
Assert( e );
|
||||
if ( e->GetType() != CChoreoEvent::SPEAK )
|
||||
continue;
|
||||
|
||||
CChoreoEvent::CLOSECAPTION type;
|
||||
|
||||
type = e->GetCloseCaptionType();
|
||||
if ( type == CChoreoEvent::CC_DISABLED )
|
||||
{
|
||||
e->SetUsingCombinedFile( false );
|
||||
e->SetRequiredCombinedChecksum( 0 );
|
||||
e->SetNumSlaves( 0 );
|
||||
e->SetLastSlaveEndTime( 0.0f );
|
||||
continue;
|
||||
}
|
||||
|
||||
char const *name = e->GetCloseCaptionToken();
|
||||
if ( !name || !name[0] )
|
||||
{
|
||||
// Fixup invalid slave tag
|
||||
if ( type == CChoreoEvent::CC_SLAVE )
|
||||
{
|
||||
e->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
|
||||
e->SetUsingCombinedFile( false );
|
||||
e->SetRequiredCombinedChecksum( 0 );
|
||||
e->SetNumSlaves( 0 );
|
||||
e->SetLastSlaveEndTime( 0.0f );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = validSpeakEventsGroupedByName.Find( name );
|
||||
if ( idx == validSpeakEventsGroupedByName.InvalidIndex() )
|
||||
{
|
||||
EventGroup eg;
|
||||
eg.timeSortedEvents.Insert( e );
|
||||
validSpeakEventsGroupedByName.Insert( name, eg );
|
||||
}
|
||||
else
|
||||
{
|
||||
EventGroup & eg = validSpeakEventsGroupedByName[ idx ];
|
||||
eg.timeSortedEvents.Insert( e );
|
||||
}
|
||||
}
|
||||
|
||||
c = validSpeakEventsGroupedByName.Count();
|
||||
// Now walk list of events by group
|
||||
if ( !c )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0; i < c; ++i )
|
||||
{
|
||||
EventGroup & eg = validSpeakEventsGroupedByName[ i ];
|
||||
int sortedEventInGroup = eg.timeSortedEvents.Count();
|
||||
// If there's only one, just mark it valid
|
||||
if ( sortedEventInGroup <= 1 )
|
||||
{
|
||||
CChoreoEvent *e = eg.timeSortedEvents[ 0 ];
|
||||
Assert( e );
|
||||
// Make sure it's the master
|
||||
e->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
|
||||
// Since it's by itself, can't be using "combined" file
|
||||
e->SetUsingCombinedFile( false );
|
||||
e->SetRequiredCombinedChecksum( 0 );
|
||||
e->SetNumSlaves( 0 );
|
||||
e->SetLastSlaveEndTime( 0.0f );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Okay, read them back in of start time
|
||||
int j = eg.timeSortedEvents.FirstInorder();
|
||||
CChoreoEvent *master = NULL;
|
||||
while ( j != eg.timeSortedEvents.InvalidIndex() )
|
||||
{
|
||||
CChoreoEvent *e = eg.timeSortedEvents[ j ];
|
||||
if ( !master )
|
||||
{
|
||||
master = e;
|
||||
e->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
|
||||
//e->SetUsingCombinedFile( true );
|
||||
e->SetRequiredCombinedChecksum( 0 );
|
||||
e->SetNumSlaves( sortedEventInGroup - 1 );
|
||||
e->SetLastSlaveEndTime( e->GetEndTime() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep bumping out the end time
|
||||
master->SetLastSlaveEndTime( e->GetEndTime() );
|
||||
e->SetCloseCaptionType( CChoreoEvent::CC_SLAVE );
|
||||
e->SetUsingCombinedFile( master->IsUsingCombinedFile() );
|
||||
e->SetRequiredCombinedChecksum( 0 );
|
||||
e->SetLastSlaveEndTime( 0.0f );
|
||||
}
|
||||
|
||||
j = eg.timeSortedEvents.NextInorder( j );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CChoreoChannel::GetSortedCombinedEventList( char const *cctoken, CUtlRBTree< CChoreoEvent * >& events )
|
||||
{
|
||||
events.RemoveAll();
|
||||
|
||||
int i;
|
||||
// Sort items
|
||||
int c = GetNumEvents();
|
||||
for ( i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoEvent *e = GetEvent( i );
|
||||
Assert( e );
|
||||
if ( e->GetType() != CChoreoEvent::SPEAK )
|
||||
continue;
|
||||
|
||||
if ( e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
|
||||
continue;
|
||||
|
||||
// A master with no slaves is not a combined event
|
||||
if ( e->GetCloseCaptionType() == CChoreoEvent::CC_MASTER &&
|
||||
e->GetNumSlaves() == 0 )
|
||||
continue;
|
||||
|
||||
char const *token = e->GetCloseCaptionToken();
|
||||
if ( Q_stricmp( token, cctoken ) )
|
||||
continue;
|
||||
|
||||
events.Insert( e );
|
||||
}
|
||||
|
||||
return ( events.Count() > 0 ) ? true : false;
|
||||
}
|
||||
|
||||
void CChoreoChannel::SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool )
|
||||
{
|
||||
buf.PutShort( pStringPool->FindOrAddString( GetName() ) );
|
||||
|
||||
int c = GetNumEvents();
|
||||
Assert( c <= 255 );
|
||||
buf.PutUnsignedChar( c );
|
||||
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoEvent *e = GetEvent( i );
|
||||
Assert( e );
|
||||
e->SaveToBuffer( buf, pScene, pStringPool );
|
||||
}
|
||||
|
||||
buf.PutChar( GetActive() ? 1 : 0 );
|
||||
}
|
||||
|
||||
bool CChoreoChannel::RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, CChoreoActor *pActor, IChoreoStringPool *pStringPool )
|
||||
{
|
||||
char sz[ 256 ];
|
||||
pStringPool->GetString( buf.GetShort(), sz, sizeof( sz ) );
|
||||
SetName( sz );
|
||||
|
||||
int numEvents = (int)buf.GetUnsignedChar();
|
||||
for ( int i = 0 ; i < numEvents; ++i )
|
||||
{
|
||||
CChoreoEvent *e = pScene->AllocEvent();
|
||||
if ( e->RestoreFromBuffer( buf, pScene, pStringPool ) )
|
||||
{
|
||||
AddEvent( e );
|
||||
e->SetChannel( this );
|
||||
e->SetActor( pActor );
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SetActive( buf.GetChar() == 1 ? true : false );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CHOREOCHANNEL_H
|
||||
#define CHOREOCHANNEL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utlrbtree.h"
|
||||
|
||||
class CChoreoEvent;
|
||||
class CChoreoActor;
|
||||
class CChoreoScene;
|
||||
class CUtlBuffer;
|
||||
class IChoreoStringPool;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A channel is owned by an actor and contains zero or more events
|
||||
//-----------------------------------------------------------------------------
|
||||
class CChoreoChannel
|
||||
{
|
||||
public:
|
||||
// Construction
|
||||
CChoreoChannel( void );
|
||||
CChoreoChannel( const char *name );
|
||||
|
||||
// Assignment
|
||||
CChoreoChannel& operator=(const CChoreoChannel& src );
|
||||
|
||||
// Serialization
|
||||
void SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
|
||||
bool RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, CChoreoActor *pActor, IChoreoStringPool *pStringPool );
|
||||
|
||||
// Accessors
|
||||
void SetName( const char *name );
|
||||
const char *GetName( void );
|
||||
|
||||
// Iterate children
|
||||
int GetNumEvents( void );
|
||||
CChoreoEvent *GetEvent( int event );
|
||||
|
||||
// Manipulate children
|
||||
void AddEvent( CChoreoEvent *event );
|
||||
void RemoveEvent( CChoreoEvent *event );
|
||||
int FindEventIndex( CChoreoEvent *event );
|
||||
void RemoveAllEvents();
|
||||
|
||||
CChoreoActor *GetActor( void );
|
||||
void SetActor( CChoreoActor *actor );
|
||||
|
||||
void SetActive( bool active );
|
||||
bool GetActive( void ) const;
|
||||
|
||||
// Compute true start/end times for gesture events in this channel, factoring in "null" gestures as needed
|
||||
void ReconcileGestureTimes();
|
||||
// Compute master/slave, count, endtime info for close captioning data
|
||||
void ReconcileCloseCaption();
|
||||
|
||||
bool IsMarkedForSave() const { return m_bMarkedForSave; }
|
||||
void SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; }
|
||||
|
||||
void MarkForSaveAll( bool mark );
|
||||
|
||||
bool GetSortedCombinedEventList( char const *cctoken, CUtlRBTree< CChoreoEvent * >& sorted );
|
||||
|
||||
private:
|
||||
// Initialize fields
|
||||
void Init( void );
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_CHANNEL_NAME = 128,
|
||||
};
|
||||
|
||||
CChoreoActor *m_pActor;
|
||||
|
||||
// Channels are just named
|
||||
char m_szName[ MAX_CHANNEL_NAME ];
|
||||
|
||||
// All of the events for this channel
|
||||
CUtlVector < CChoreoEvent * > m_Events;
|
||||
|
||||
bool m_bActive;
|
||||
|
||||
// Purely for save/load
|
||||
bool m_bMarkedForSave;
|
||||
};
|
||||
|
||||
#endif // CHOREOCHANNEL_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,718 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CHOREOEVENT_H
|
||||
#define CHOREOEVENT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class CChoreoActor;
|
||||
class CChoreoChannel;
|
||||
class CChoreoEvent;
|
||||
class CChoreoScene;
|
||||
class IChoreoEventCallback;
|
||||
class CAudioMixer;
|
||||
class CUtlBuffer;
|
||||
class IChoreoStringPool;
|
||||
|
||||
|
||||
#include "tier1/utlstring.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "expressionsample.h"
|
||||
#include "networkvar.h"
|
||||
#include "localflexcontroller.h"
|
||||
|
||||
typedef CUtlString ChoreoStr_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: SPEAK events can have "relative tags" that other objects can reference
|
||||
// to specify their start times off of
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEventRelativeTag
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS_NOBASE( CEventRelativeTag );
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_EVENTTAG_LENGTH = 128,
|
||||
};
|
||||
|
||||
CEventRelativeTag( CChoreoEvent *owner, const char *name, float percentage );
|
||||
CEventRelativeTag( const CEventRelativeTag& src );
|
||||
|
||||
const char *GetName( void );
|
||||
float GetPercentage( void );
|
||||
void SetPercentage( float percentage );
|
||||
|
||||
// Returns the corrected time based on the owner's length and start time
|
||||
float GetStartTime( void );
|
||||
CChoreoEvent *GetOwner( void );
|
||||
void SetOwner( CChoreoEvent *event );
|
||||
|
||||
protected:
|
||||
|
||||
ChoreoStr_t m_Name;
|
||||
float m_flPercentage;
|
||||
CChoreoEvent *m_pOwner;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: GESTURE events can have "absolute tags" (where the value is not a
|
||||
// percentage, but an actual timestamp from the start of the event)
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEventAbsoluteTag
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_EVENTTAG_LENGTH = 128,
|
||||
};
|
||||
|
||||
CEventAbsoluteTag( CChoreoEvent *owner, const char *name, float percentage );
|
||||
CEventAbsoluteTag( const CEventAbsoluteTag& src );
|
||||
|
||||
const char *GetName( void );
|
||||
|
||||
float GetPercentage( void );
|
||||
void SetPercentage( float percentage );
|
||||
|
||||
float GetEventTime( void );
|
||||
void SetEventTime( float t );
|
||||
|
||||
float GetAbsoluteTime( void );
|
||||
void SetAbsoluteTime( float t );
|
||||
|
||||
CChoreoEvent *GetOwner( void );
|
||||
void SetOwner( CChoreoEvent *event );
|
||||
|
||||
void SetLocked( bool bLocked );
|
||||
bool GetLocked( void );
|
||||
|
||||
void SetLinear( bool bLinear );
|
||||
bool GetLinear( void );
|
||||
|
||||
void SetEntry( bool bEntry );
|
||||
bool GetEntry( void );
|
||||
|
||||
void SetExit( bool bExit );
|
||||
bool GetExit( void );
|
||||
|
||||
protected:
|
||||
|
||||
ChoreoStr_t m_Name;
|
||||
float m_flPercentage;
|
||||
bool m_bLocked:1;
|
||||
bool m_bLinear:1;
|
||||
bool m_bEntry:1;
|
||||
bool m_bExit:1;
|
||||
CChoreoEvent *m_pOwner;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: FLEXANIMATION events can have "timing tags" that are used to align and
|
||||
// manipulate flex animation curves
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFlexTimingTag : public CEventRelativeTag
|
||||
{
|
||||
DECLARE_CLASS( CFlexTimingTag, CEventRelativeTag );
|
||||
|
||||
public:
|
||||
CFlexTimingTag( CChoreoEvent *owner, const char *name, float percentage, bool locked );
|
||||
CFlexTimingTag( const CFlexTimingTag& src );
|
||||
|
||||
bool GetLocked( void );
|
||||
void SetLocked( bool locked );
|
||||
|
||||
protected:
|
||||
bool m_bLocked;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A flex controller position can be animated over a period of time
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFlexAnimationTrack
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_CONTROLLER_NAME = 128,
|
||||
};
|
||||
|
||||
CFlexAnimationTrack( CChoreoEvent *event );
|
||||
CFlexAnimationTrack( const CFlexAnimationTrack* src );
|
||||
virtual ~CFlexAnimationTrack( void );
|
||||
|
||||
void SetEvent( CChoreoEvent *event );
|
||||
CChoreoEvent *GetEvent( void );
|
||||
|
||||
void SetFlexControllerName( const char *name );
|
||||
char const *GetFlexControllerName( void );
|
||||
|
||||
void SetComboType( bool combo );
|
||||
bool IsComboType( void );
|
||||
|
||||
void SetMin( float value );
|
||||
void SetMax( float value );
|
||||
float GetMin( int type = 0 );
|
||||
float GetMax( int type = 0 );
|
||||
|
||||
bool IsInverted( void );
|
||||
void SetInverted( bool isInverted );
|
||||
|
||||
int GetNumSamples( int type = 0 );
|
||||
CExpressionSample *GetSample( int index, int type = 0 );
|
||||
|
||||
bool IsTrackActive( void );
|
||||
void SetTrackActive( bool active );
|
||||
|
||||
// returns scaled value for absolute time per left/right side
|
||||
float GetIntensity( float time, int side = 0 );
|
||||
|
||||
CExpressionSample *AddSample( float time, float value, int type = 0 );
|
||||
void RemoveSample( int index, int type = 0 );
|
||||
void Clear( void );
|
||||
|
||||
void Resort( int type = 0 );
|
||||
|
||||
// Puts in dummy start/end samples to spline to zero ( or 0.5 for
|
||||
// left/right data) at the origins
|
||||
CExpressionSample *GetBoundedSample( int number, bool& bClamped, int type = 0 );
|
||||
|
||||
int GetFlexControllerIndex( int side = 0 );
|
||||
LocalFlexController_t GetRawFlexControllerIndex( int side = 0 );
|
||||
void SetFlexControllerIndex( LocalFlexController_t raw, int index, int side = 0 );
|
||||
|
||||
// returns 0..1 value for 0..1 time fraction per mag/balance
|
||||
float GetFracIntensity( float time, int type );
|
||||
|
||||
// retrieves raw intensity values (for mag vs. left/right slider setting)
|
||||
float GetSampleIntensity( float time );
|
||||
float GetBalanceIntensity( float time );
|
||||
|
||||
void SetEdgeInfo( bool leftEdge, int curveType, float zero );
|
||||
void GetEdgeInfo( bool leftEdge, int& curveType, float& zero ) const;
|
||||
void SetEdgeActive( bool leftEdge, bool state );
|
||||
bool IsEdgeActive( bool leftEdge ) const;
|
||||
int GetEdgeCurveType( bool leftEdge ) const;
|
||||
float GetEdgeZeroValue( bool leftEdge ) const;
|
||||
|
||||
float GetDefaultEdgeZeroPos() const;
|
||||
|
||||
void SetServerSide( bool state );
|
||||
bool IsServerSide() const;
|
||||
private:
|
||||
// remove any samples after endtime
|
||||
void RemoveOutOfRangeSamples( int type );
|
||||
|
||||
// returns scaled value for absolute time per mag/balance
|
||||
float GetIntensityInternal( float time, int type );
|
||||
|
||||
public:
|
||||
// returns the fractional (0..1) value for "zero" based on Min/Max ranges
|
||||
float GetZeroValue( int type, bool leftSide );
|
||||
|
||||
|
||||
private:
|
||||
char *m_pControllerName;
|
||||
|
||||
// base track has range, combo is always 0..1
|
||||
float m_flMin;
|
||||
float m_flMax;
|
||||
|
||||
// 0 == magnitude
|
||||
// 1 == left/right
|
||||
CUtlVector< CExpressionSample > m_Samples[ 2 ];
|
||||
int m_nFlexControllerIndex[ 2 ];
|
||||
LocalFlexController_t m_nFlexControllerIndexRaw[ 2 ];
|
||||
|
||||
// For left and right edge of type 0 flex data ( magnitude track )
|
||||
EdgeInfo_t m_EdgeInfo[ 2 ];
|
||||
|
||||
CChoreoEvent *m_pEvent;
|
||||
|
||||
// Is track active
|
||||
bool m_bActive:1;
|
||||
|
||||
// Is this a combo (magnitude + stereo) track
|
||||
bool m_bCombo:1;
|
||||
bool m_bServerSide:1;
|
||||
|
||||
bool m_bInverted; // track is displayed 1..0 instead of 0..1
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The generic scene event type
|
||||
//-----------------------------------------------------------------------------
|
||||
class CChoreoEvent : public ICurveDataAccessor
|
||||
{
|
||||
public:
|
||||
// Type of event this object represents
|
||||
typedef enum
|
||||
{
|
||||
// Don't know yet
|
||||
UNSPECIFIED = 0,
|
||||
|
||||
// Section start/end
|
||||
SECTION,
|
||||
|
||||
// Play an expression
|
||||
EXPRESSION,
|
||||
|
||||
// Look at another actor
|
||||
LOOKAT,
|
||||
|
||||
// Move to a location
|
||||
MOVETO,
|
||||
|
||||
// Speak/visemes a wave file
|
||||
SPEAK,
|
||||
|
||||
// Play a gesture
|
||||
GESTURE,
|
||||
|
||||
// Play a sequence
|
||||
SEQUENCE,
|
||||
|
||||
// Face another actor
|
||||
FACE,
|
||||
|
||||
// Fire a trigger
|
||||
FIRETRIGGER,
|
||||
|
||||
// One or more flex sliders animated over the course of the event time period
|
||||
FLEXANIMATION,
|
||||
|
||||
// A contained .vcd file
|
||||
SUBSCENE,
|
||||
|
||||
// Loop back to previous time (forever or up to N times)
|
||||
LOOP,
|
||||
|
||||
// A time span during which the scene may be temporarily interrupted
|
||||
INTERRUPT,
|
||||
|
||||
// A dummy event that is used to mark the .vcd end time
|
||||
STOPPOINT,
|
||||
|
||||
// A time span during which this actor can respond to events happening in the world, etc.
|
||||
PERMIT_RESPONSES,
|
||||
|
||||
// A string passed to the game code for interpretation
|
||||
GENERIC,
|
||||
|
||||
// Camera control
|
||||
CAMERA,
|
||||
|
||||
// Script function call
|
||||
SCRIPT,
|
||||
|
||||
// THIS MUST BE LAST!!!
|
||||
NUM_TYPES,
|
||||
} EVENTTYPE;
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_TAGNAME_STRING = 128,
|
||||
MAX_CCTOKEN_STRING = 64,
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DEFAULT = 0,
|
||||
SIMULATION,
|
||||
DISPLAY,
|
||||
} TIMETYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CC_MASTER = 0, // default, implied
|
||||
CC_SLAVE,
|
||||
CC_DISABLED,
|
||||
|
||||
NUM_CC_TYPES,
|
||||
} CLOSECAPTION;
|
||||
|
||||
static int s_nGlobalID;
|
||||
|
||||
// Construction
|
||||
CChoreoEvent( CChoreoScene *scene );
|
||||
CChoreoEvent( CChoreoScene *scene, EVENTTYPE type, const char *name );
|
||||
CChoreoEvent( CChoreoScene *scene, EVENTTYPE type, const char *name, const char *param );
|
||||
|
||||
// Assignment
|
||||
CChoreoEvent& operator=(const CChoreoEvent& src );
|
||||
|
||||
~CChoreoEvent( void );
|
||||
|
||||
// ICurveDataAccessor methods
|
||||
virtual bool CurveHasEndTime();
|
||||
virtual int GetDefaultCurveType();
|
||||
|
||||
// Binary serialization
|
||||
void SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
|
||||
bool RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
|
||||
|
||||
// Accessors
|
||||
EVENTTYPE GetType( void );
|
||||
void SetType( EVENTTYPE type );
|
||||
|
||||
void SetName( const char *name );
|
||||
const char *GetName( void );
|
||||
|
||||
void SetParameters( const char *target );
|
||||
const char *GetParameters( void );
|
||||
void SetParameters2( const char *target );
|
||||
const char *GetParameters2( void );
|
||||
void SetParameters3( const char *target );
|
||||
const char *GetParameters3( void );
|
||||
|
||||
void SetStartTime( float starttime );
|
||||
float GetStartTime( void );
|
||||
|
||||
void SetEndTime( float endtime );
|
||||
float GetEndTime( void );
|
||||
|
||||
float GetDuration( void );
|
||||
|
||||
void SetResumeCondition( bool resumecondition );
|
||||
bool IsResumeCondition( void );
|
||||
|
||||
void SetLockBodyFacing( bool lockbodyfacing );
|
||||
bool IsLockBodyFacing( void );
|
||||
|
||||
void SetDistanceToTarget( float distancetotarget );
|
||||
float GetDistanceToTarget( void );
|
||||
|
||||
void SetForceShortMovement( bool bForceShortMovement );
|
||||
bool GetForceShortMovement( void );
|
||||
|
||||
void SetSyncToFollowingGesture( bool bSyncToFollowingGesture );
|
||||
bool GetSyncToFollowingGesture( void );
|
||||
|
||||
void SetPlayOverScript( bool bPlayOverScript );
|
||||
bool GetPlayOverScript( void );
|
||||
|
||||
int GetRampCount( void ) { return m_Ramp.GetCount(); };
|
||||
CExpressionSample *GetRamp( int index ) { return m_Ramp.Get( index ); };
|
||||
CExpressionSample *AddRamp( float time, float value, bool selected ) { return m_Ramp.Add( time, value, selected ); };
|
||||
void DeleteRamp( int index ) { m_Ramp.Delete( index ); };
|
||||
void ClearRamp( void ) { m_Ramp.Clear(); };
|
||||
void ResortRamp( void ) { m_Ramp.Resort( this ); };
|
||||
CCurveData *GetRamp( void ) { return &m_Ramp; };
|
||||
|
||||
float GetRampIntensity( float time ) { return m_Ramp.GetIntensity( this, time ); };
|
||||
|
||||
// Calculates weighting for a given time
|
||||
float GetIntensity( float scenetime );
|
||||
float GetIntensityArea( float scenetime );
|
||||
|
||||
// Calculates 0..1 completion for a given time
|
||||
float GetCompletion( float time );
|
||||
|
||||
// An end time of -1.0f means that the events is just triggered at the leading edge
|
||||
bool HasEndTime( void );
|
||||
|
||||
// Is the event something that can be sized ( a wave file, e.g. )
|
||||
bool IsFixedLength( void );
|
||||
void SetFixedLength( bool isfixedlength );
|
||||
|
||||
// Move the start/end/both times by the specified dt (fixes up -1.0f endtimes)
|
||||
void OffsetStartTime( float dt );
|
||||
void OffsetEndTime( float dt );
|
||||
void OffsetTime( float dt );
|
||||
|
||||
// Snap to scene framerate
|
||||
void SnapTimes( void );
|
||||
float SnapTime( float t );
|
||||
|
||||
CChoreoScene *GetScene( void );
|
||||
void SetScene( CChoreoScene *scene );
|
||||
|
||||
// The actor the event is associated with
|
||||
void SetActor( CChoreoActor *actor );
|
||||
CChoreoActor *GetActor( void );
|
||||
|
||||
// The channel the event is associated with
|
||||
void SetChannel( CChoreoChannel *channel );
|
||||
CChoreoChannel *GetChannel( void );
|
||||
|
||||
// Get a more involved description of the event
|
||||
const char *GetDescription( void );
|
||||
|
||||
void ClearAllRelativeTags( void );
|
||||
int GetNumRelativeTags( void );
|
||||
CEventRelativeTag *GetRelativeTag( int tagnum );
|
||||
CEventRelativeTag *FindRelativeTag( const char *tagname );
|
||||
void AddRelativeTag( const char *tagname, float percentage );
|
||||
void RemoveRelativeTag( const char *tagname );
|
||||
|
||||
bool IsUsingRelativeTag( void );
|
||||
void SetUsingRelativeTag( bool usetag, const char *tagname = 0, const char *wavname = 0);
|
||||
const char *GetRelativeTagName( void );
|
||||
const char *GetRelativeWavName( void );
|
||||
|
||||
// Absolute tags
|
||||
typedef enum
|
||||
{
|
||||
INVALID = -1,
|
||||
|
||||
PLAYBACK = 0, // new timeline - FIXME: should be stored as an absolute time
|
||||
ORIGINAL, // original timeline - FIXME: should be stored at a fixed percentage of event
|
||||
|
||||
NUM_ABS_TAG_TYPES,
|
||||
} AbsTagType;
|
||||
|
||||
void SetGestureSequenceDuration( float duration );
|
||||
bool GetGestureSequenceDuration( float& duration );
|
||||
|
||||
void ClearAllAbsoluteTags( AbsTagType type );
|
||||
int GetNumAbsoluteTags( AbsTagType type );
|
||||
CEventAbsoluteTag *GetAbsoluteTag( AbsTagType type, int tagnum );
|
||||
CEventAbsoluteTag *FindAbsoluteTag( AbsTagType type, const char *tagname );
|
||||
void AddAbsoluteTag( AbsTagType type, const char *tagname, float t );
|
||||
void RemoveAbsoluteTag( AbsTagType type, const char *tagname );
|
||||
bool VerifyTagOrder( void );
|
||||
float GetOriginalPercentageFromPlaybackPercentage( float t );
|
||||
float GetPlaybackPercentageFromOriginalPercentage( float t );
|
||||
|
||||
static const char *NameForAbsoluteTagType( AbsTagType t );
|
||||
static AbsTagType TypeForAbsoluteTagName( const char *name );
|
||||
|
||||
void RescaleGestureTimes( float newstart, float newend, bool bMaintainAbsoluteTagPositions );
|
||||
bool PreventTagOverlap( void );
|
||||
|
||||
CEventAbsoluteTag *FindEntryTag( AbsTagType type );
|
||||
CEventAbsoluteTag *FindExitTag( AbsTagType type );
|
||||
|
||||
// Flex animation type
|
||||
int GetNumFlexAnimationTracks( void );
|
||||
CFlexAnimationTrack *GetFlexAnimationTrack( int index );
|
||||
CFlexAnimationTrack *AddTrack( const char *controllername );
|
||||
CFlexAnimationTrack *FindTrack( const char *controllername );
|
||||
void RemoveTrack( int index );
|
||||
void RemoveAllTracks( void );
|
||||
void OnEndTimeChanged( void );
|
||||
|
||||
bool GetTrackLookupSet( void );
|
||||
void SetTrackLookupSet( bool set );
|
||||
|
||||
// Flex Timing Tags (used by editor only)
|
||||
void ClearAllTimingTags( void );
|
||||
int GetNumTimingTags( void );
|
||||
CFlexTimingTag *GetTimingTag( int tagnum );
|
||||
CFlexTimingTag *FindTimingTag( const char *tagname );
|
||||
void AddTimingTag( const char *tagname, float percentage, bool locked );
|
||||
void RemoveTimingTag( const char *tagname );
|
||||
|
||||
// Subscene ( embedded .vcd ) support
|
||||
void SetSubScene( CChoreoScene *scene );
|
||||
CChoreoScene *GetSubScene( void );
|
||||
|
||||
bool IsProcessing( void ) const;
|
||||
bool HasStopped() const;
|
||||
void StartProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
|
||||
void ContinueProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
|
||||
void StopProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
|
||||
bool CheckProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
|
||||
void ResetProcessing( void );
|
||||
|
||||
void SetMixer( CAudioMixer *mixer );
|
||||
CAudioMixer *GetMixer( void ) const;
|
||||
|
||||
// Hack for LOOKAT in editor
|
||||
int GetPitch( void ) const;
|
||||
void SetPitch( int pitch );
|
||||
int GetYaw( void ) const;
|
||||
void SetYaw( int yaw );
|
||||
|
||||
// For LOOP events
|
||||
void SetLoopCount( int numloops );
|
||||
int GetLoopCount( void );
|
||||
int GetNumLoopsRemaining( void );
|
||||
void SetNumLoopsRemaining( int loops );
|
||||
|
||||
bool IsMarkedForSave() const { return m_bMarkedForSave; }
|
||||
void SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; }
|
||||
|
||||
void GetMovementStyle( char *style, int maxlen );
|
||||
void GetDistanceStyle( char *style, int maxlen );
|
||||
|
||||
int GetGlobalID() const { return m_nGlobalID; }
|
||||
|
||||
// Localization/CC support (close captioning and multiple wave file recombination)
|
||||
void SetCloseCaptionType( CLOSECAPTION type );
|
||||
CLOSECAPTION GetCloseCaptionType() const;
|
||||
void SetCloseCaptionToken( char const *token );
|
||||
char const *GetCloseCaptionToken() const;
|
||||
void SetUsingCombinedFile( bool isusing );
|
||||
bool IsUsingCombinedFile() const;
|
||||
void SetRequiredCombinedChecksum( unsigned int checksum );
|
||||
unsigned int GetRequiredCombinedChecksum();
|
||||
void SetNumSlaves( int num );
|
||||
int GetNumSlaves() const;
|
||||
void SetLastSlaveEndTime( float t );
|
||||
float GetLastSlaveEndTime() const;
|
||||
void SetCloseCaptionTokenValid( bool valid );
|
||||
bool GetCloseCaptionTokenValid() const;
|
||||
|
||||
bool ComputeCombinedBaseFileName( char *dest, int destlen, bool creategenderwildcard );
|
||||
bool IsCombinedUsingGenderToken() const;
|
||||
void SetCombinedUsingGenderToken( bool using_gender );
|
||||
|
||||
bool IsSuppressingCaptionAttenuation() const;
|
||||
void SetSuppressingCaptionAttenuation( bool suppress );
|
||||
|
||||
int ValidateCombinedFile();
|
||||
|
||||
// This returns false if the wave is CC_DISABLED or is a CC_SLAVE,
|
||||
// otherwise it returns the actual m_szCCToken value, or if that's
|
||||
// blank it'll return the sounds.txt entry name (m_szParameters)
|
||||
bool GetPlaybackCloseCaptionToken( char *dest, int destlen );
|
||||
|
||||
void ClearEventDependencies();
|
||||
void AddEventDependency( CChoreoEvent *other );
|
||||
void GetEventDependencies( CUtlVector< CChoreoEvent * >& list );
|
||||
|
||||
void SetActive( bool state );
|
||||
bool GetActive() const;
|
||||
|
||||
void SetDefaultCurveType( int nCurveType );
|
||||
|
||||
// Turn enum into string and vice versa
|
||||
static EVENTTYPE TypeForName( const char *name );
|
||||
static const char *NameForType( EVENTTYPE type );
|
||||
|
||||
// Turn enum into string and vice versa
|
||||
static CLOSECAPTION CCTypeForName( const char *name );
|
||||
static const char *NameForCCType( CLOSECAPTION type );
|
||||
|
||||
private:
|
||||
|
||||
// Declare copy constructor private to prevent accidental usage...
|
||||
CChoreoEvent(const CChoreoEvent& src );
|
||||
|
||||
void SaveFlexAnimationsToBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool );
|
||||
bool RestoreFlexAnimationsFromBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool );
|
||||
|
||||
float GetBoundedAbsoluteTagPercentage( AbsTagType type, int tagnum );
|
||||
|
||||
float _GetIntensity( float time );
|
||||
|
||||
// String bounds
|
||||
enum
|
||||
{
|
||||
MAX_CHOREOEVENT_NAME = 128,
|
||||
MAX_PARAMETERS_STRING = 128,
|
||||
};
|
||||
|
||||
// Base initialization
|
||||
void Init( CChoreoScene *scene );
|
||||
|
||||
// Type of event
|
||||
byte m_fType;
|
||||
|
||||
// Close caption type
|
||||
byte m_ccType;
|
||||
|
||||
// Name of event
|
||||
ChoreoStr_t m_Name;
|
||||
|
||||
// Event parameters
|
||||
ChoreoStr_t m_Parameters;
|
||||
ChoreoStr_t m_Parameters2;
|
||||
ChoreoStr_t m_Parameters3;
|
||||
|
||||
// Event start time
|
||||
float m_flStartTime;
|
||||
|
||||
// Event end time ( -1.0f means no ending, just leading edge triggered )
|
||||
float m_flEndTime;
|
||||
|
||||
// Duration of underlying gesture sequence
|
||||
float m_flGestureSequenceDuration;
|
||||
|
||||
// For CChoreoEvent::LOOP
|
||||
int m_nNumLoops; // -1 == no limit
|
||||
int m_nLoopsRemaining;
|
||||
|
||||
// Overall intensity curve
|
||||
CCurveData m_Ramp;
|
||||
|
||||
// Start time is computed based on length of item referenced by tagged name
|
||||
ChoreoStr_t m_TagName;
|
||||
ChoreoStr_t m_TagWavName;
|
||||
|
||||
// Associated actor
|
||||
CChoreoActor *m_pActor;
|
||||
// Associated channel
|
||||
CChoreoChannel *m_pChannel;
|
||||
|
||||
CUtlVector < CEventRelativeTag > m_RelativeTags;
|
||||
CUtlVector < CFlexTimingTag > m_TimingTags;
|
||||
CUtlVector < CEventAbsoluteTag > m_AbsoluteTags[ NUM_ABS_TAG_TYPES ];
|
||||
|
||||
CUtlVector < CFlexAnimationTrack * > m_FlexAnimationTracks;
|
||||
|
||||
CChoreoScene *m_pSubScene;
|
||||
CAudioMixer *m_pMixer;
|
||||
|
||||
// Scene which owns this event
|
||||
CChoreoScene *m_pScene;
|
||||
|
||||
int m_nPitch;
|
||||
int m_nYaw;
|
||||
|
||||
float m_flDistanceToTarget;
|
||||
|
||||
int m_nGlobalID;
|
||||
|
||||
ChoreoStr_t m_CCToken;
|
||||
unsigned int m_uRequiredCombinedChecksum;
|
||||
// on master only, the combined file must have the same checksum to be useable
|
||||
int m_nNumSlaves;
|
||||
// Only set on master, helps UI draw underbar
|
||||
float m_flLastSlaveEndTime;
|
||||
// true if the cc token was found in the cc manager's database
|
||||
|
||||
CUtlVector< CChoreoEvent * > m_Dependencies;
|
||||
|
||||
int m_nDefaultCurveType;
|
||||
|
||||
public:
|
||||
// used only during scrubbing of looping sequences
|
||||
float m_flPrevCycle;
|
||||
float m_flPrevTime;
|
||||
|
||||
// Flags
|
||||
|
||||
bool m_bFixedLength:1;
|
||||
// True if this event must be "finished" before the next section can be started
|
||||
// after playback is paused from a globalevent
|
||||
bool m_bResumeCondition:1;
|
||||
bool m_bUsesTag:1;
|
||||
bool m_bTrackLookupSet:1;
|
||||
bool m_bProcessing:1;
|
||||
bool m_bHasStopped : 1;
|
||||
bool m_bLockBodyFacing:1;
|
||||
// Purely for save/load
|
||||
bool m_bMarkedForSave:1;
|
||||
bool m_bUsingCombinedSoundFile:1;
|
||||
bool m_bCCTokenValid:1;
|
||||
bool m_bCombinedUsingGenderToken:1;
|
||||
|
||||
bool m_bSuppressCaptionAttenuation:1;
|
||||
|
||||
bool m_bForceShortMovement:1;
|
||||
bool m_bSyncToFollowingGesture:1;
|
||||
bool m_bActive:1;
|
||||
bool m_bPlayOverScript:1;
|
||||
};
|
||||
|
||||
#endif // CHOREOEVENT_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,410 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CHOREOSCENE_H
|
||||
#define CHOREOSCENE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class CChoreoEvent;
|
||||
class CChoreoChannel;
|
||||
class CChoreoActor;
|
||||
class IChoreoEventCallback;
|
||||
class CEventRelativeTag;
|
||||
class CUtlBuffer;
|
||||
class CFlexAnimationTrack;
|
||||
class ISceneTokenProcessor;
|
||||
class IChoreoStringPool;
|
||||
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utldict.h"
|
||||
#include "bitvec.h"
|
||||
#include "expressionsample.h"
|
||||
#include "choreoevent.h"
|
||||
|
||||
#define DEFAULT_SCENE_FPS 60
|
||||
#define MIN_SCENE_FPS 10
|
||||
#define MAX_SCENE_FPS 240
|
||||
|
||||
#define SCENE_BINARY_TAG MAKEID( 'b', 'v', 'c', 'd' )
|
||||
#define SCENE_BINARY_VERSION 0x04
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Container for choreographed scene of events for actors
|
||||
//-----------------------------------------------------------------------------
|
||||
class CChoreoScene : public ICurveDataAccessor
|
||||
{
|
||||
public:
|
||||
// Construction
|
||||
CChoreoScene( IChoreoEventCallback *callback );
|
||||
~CChoreoScene( void );
|
||||
|
||||
// Assignment
|
||||
CChoreoScene& operator=(const CChoreoScene& src );
|
||||
|
||||
// ICurveDataAccessor methods
|
||||
virtual float GetDuration() { return FindStopTime(); };
|
||||
virtual bool CurveHasEndTime();
|
||||
virtual int GetDefaultCurveType();
|
||||
|
||||
// Binary serialization
|
||||
bool SaveBinary( char const *pszBinaryFileName, char const *pPathID, unsigned int nTextVersionCRC, IChoreoStringPool *pStringPool );
|
||||
void SaveToBinaryBuffer( CUtlBuffer& buf, unsigned int nTextVersionCRC, IChoreoStringPool *pStringPool );
|
||||
bool RestoreFromBinaryBuffer( CUtlBuffer& buf, char const *filename, IChoreoStringPool *pStringPool );
|
||||
static bool GetCRCFromBinaryBuffer( CUtlBuffer& buf, unsigned int& crc );
|
||||
|
||||
// We do some things differently while restoring from a save.
|
||||
inline void SetRestoring( bool bRestoring );
|
||||
inline bool IsRestoring();
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_SCENE_FILENAME = 128,
|
||||
};
|
||||
|
||||
// Event callback handler
|
||||
void SetEventCallbackInterface( IChoreoEventCallback *callback );
|
||||
|
||||
// Loading
|
||||
bool ParseFromBuffer( char const *pFilename, ISceneTokenProcessor *tokenizer );
|
||||
void SetPrintFunc( void ( *pfn )( const char *fmt, ... ) );
|
||||
|
||||
// Saving
|
||||
bool SaveToFile( const char *filename );
|
||||
bool ExportMarkedToFile( const char *filename );
|
||||
void MarkForSaveAll( bool mark );
|
||||
|
||||
// Merges two .vcd's together, returns true if any data was merged
|
||||
bool Merge( CChoreoScene *other );
|
||||
|
||||
static void FileSaveFlexAnimationTrack( CUtlBuffer& buf, int level, CFlexAnimationTrack *track, int nDefaultCurveType );
|
||||
static void FileSaveFlexAnimations( CUtlBuffer& buf, int level, CChoreoEvent *e );
|
||||
static void FileSaveRamp( CUtlBuffer& buf, int level, CChoreoEvent *e );
|
||||
void FileSaveSceneRamp( CUtlBuffer& buf, int level );
|
||||
static void FileSaveScaleSettings( CUtlBuffer& buf, int level, CChoreoScene *scene );
|
||||
|
||||
static void ParseFlexAnimations( ISceneTokenProcessor *tokenizer, CChoreoEvent *e, bool removeold = true );
|
||||
static void ParseRamp( ISceneTokenProcessor *tokenizer, CChoreoEvent *e );
|
||||
static void ParseSceneRamp( ISceneTokenProcessor *tokenizer, CChoreoScene *scene );
|
||||
static void ParseScaleSettings( ISceneTokenProcessor *tokenizer, CChoreoScene *scene );
|
||||
static void ParseEdgeInfo( ISceneTokenProcessor *tokenizer, EdgeInfo_t *edgeinfo );
|
||||
|
||||
// Debugging
|
||||
void SceneMsg( PRINTF_FORMAT_STRING const char *pFormat, ... );
|
||||
void Print( void );
|
||||
|
||||
// Sound system needs to have sounds pre-queued by this much time
|
||||
void SetSoundFileStartupLatency( float time );
|
||||
float GetSoundFileStartupLatency() const;
|
||||
|
||||
// Simulation
|
||||
void Think( float curtime );
|
||||
// Retrieves time in simulation
|
||||
float GetTime( void );
|
||||
// Retrieves start/stop time for looped/debug scene
|
||||
void GetSceneTimes( float& start, float& end );
|
||||
|
||||
void SetTime( float t );
|
||||
void LoopToTime( float t );
|
||||
|
||||
// Has simulation finished
|
||||
bool SimulationFinished( void );
|
||||
// Has the last speech event in the scene already fired
|
||||
bool SpeechFinished( void ) const;
|
||||
// Reset simulation
|
||||
void ResetSimulation( bool forward = true, float starttime = 0.0f, float endtime = 0.0f );
|
||||
// Find time at which last simulation event is triggered
|
||||
float FindStopTime( void );
|
||||
// Find time at which last SPEAK event is complete
|
||||
float FindLastSpeakTime( void ) const;
|
||||
|
||||
void ResumeSimulation( void );
|
||||
|
||||
// Have all the pause events happened
|
||||
bool CheckEventCompletion( void );
|
||||
|
||||
// Find named actor in scene data
|
||||
CChoreoActor *FindActor( const char *name );
|
||||
// Remove actor from scene
|
||||
void RemoveActor( CChoreoActor *actor );
|
||||
// Find index for actor
|
||||
int FindActorIndex( CChoreoActor *actor );
|
||||
|
||||
// Swap actors in the data
|
||||
void SwapActors( int a1, int a2 );
|
||||
|
||||
// General data access
|
||||
int GetNumEvents( void );
|
||||
CChoreoEvent *GetEvent( int event );
|
||||
|
||||
int GetNumActors( void );
|
||||
CChoreoActor *GetActor( int actor );
|
||||
|
||||
int GetNumChannels( void );
|
||||
CChoreoChannel *GetChannel( int channel );
|
||||
|
||||
// Object allocation/destruction
|
||||
void DeleteReferencedObjects( CChoreoActor *actor );
|
||||
void DeleteReferencedObjects( CChoreoChannel *channel );
|
||||
void DeleteReferencedObjects( CChoreoEvent *event );
|
||||
|
||||
CChoreoActor *AllocActor( void );
|
||||
CChoreoChannel *AllocChannel( void );
|
||||
CChoreoEvent *AllocEvent( void );
|
||||
|
||||
void AddEventToScene( CChoreoEvent *event );
|
||||
void AddActorToScene( CChoreoActor *actor );
|
||||
void AddChannelToScene( CChoreoChannel *channel );
|
||||
|
||||
// Fixup simulation times for channel gestures
|
||||
void ReconcileGestureTimes( void );
|
||||
|
||||
// Go through all elements and update relative tags, removing any orphaned
|
||||
// tags and updating the timestamp of normal tags
|
||||
void ReconcileTags( void );
|
||||
CEventRelativeTag *FindTagByName( const char *wavname, const char *name );
|
||||
CChoreoEvent *FindTargetingEvent( const char *wavname, const char *name );
|
||||
|
||||
// Used by UI to provide target actor names
|
||||
char const *GetMapname( void );
|
||||
void SetMapname( const char *name );
|
||||
|
||||
void ExportEvents( const char *filename, CUtlVector< CChoreoEvent * >& events );
|
||||
void ImportEvents( ISceneTokenProcessor *tokenizer, CChoreoActor *actor, CChoreoChannel *channel );
|
||||
|
||||
// Subscene support
|
||||
void SetSubScene( bool sub );
|
||||
bool IsSubScene( void ) const;
|
||||
|
||||
int GetSceneFPS( void ) const;
|
||||
void SetSceneFPS( int fps );
|
||||
bool IsUsingFrameSnap( void ) const;
|
||||
void SetUsingFrameSnap( bool snap );
|
||||
|
||||
float SnapTime( float t );
|
||||
|
||||
int GetSceneRampCount( void ) { return m_SceneRamp.GetCount(); };
|
||||
CExpressionSample *GetSceneRamp( int index ) { return m_SceneRamp.Get( index ); };
|
||||
CExpressionSample *AddSceneRamp( float time, float value, bool selected ) { return m_SceneRamp.Add( time, value, selected ); };
|
||||
void DeleteSceneRamp( int index ) { m_SceneRamp.Delete( index ); };
|
||||
void ClearSceneRamp( void ) { m_SceneRamp.Clear(); };
|
||||
void ResortSceneRamp( void ) { m_SceneRamp.Resort( this ); };
|
||||
|
||||
CCurveData *GetSceneRamp( void ) { return &m_SceneRamp; };
|
||||
|
||||
|
||||
// Global intensity for scene
|
||||
float GetSceneRampIntensity( float time ) { return m_SceneRamp.GetIntensity( this, time ); }
|
||||
|
||||
int GetTimeZoom( char const *tool );
|
||||
void SetTimeZoom( char const *tool, int tz );
|
||||
int TimeZoomFirst();
|
||||
int TimeZoomNext( int i );
|
||||
int TimeZoomInvalid() const;
|
||||
char const *TimeZoomName( int i );
|
||||
|
||||
void ReconcileCloseCaption();
|
||||
|
||||
char const *GetFilename() const;
|
||||
void SetFileName( char const *fn );
|
||||
|
||||
bool GetPlayingSoundName( char *pchBuff, int iBuffLength );
|
||||
bool HasUnplayedSpeech();
|
||||
bool HasFlexAnimation();
|
||||
void SetBackground( bool bIsBackground );
|
||||
bool IsBackground( void );
|
||||
|
||||
void ClearPauseEventDependencies();
|
||||
|
||||
bool HasEventsOfType( CChoreoEvent::EVENTTYPE type ) const;
|
||||
void RemoveEventsExceptTypes( int* typeList, int count );
|
||||
|
||||
void IgnorePhonemes( bool bIgnore );
|
||||
bool ShouldIgnorePhonemes() const;
|
||||
|
||||
// This is set by the engine to signify that we're not modifying the data and
|
||||
// therefore we can precompute the end time
|
||||
static bool s_bEditingDisabled;
|
||||
|
||||
private:
|
||||
|
||||
// Simulation stuff
|
||||
enum
|
||||
{
|
||||
IN_RANGE = 0,
|
||||
BEFORE_RANGE,
|
||||
AFTER_RANGE
|
||||
};
|
||||
|
||||
int IsTimeInRange( float t, float starttime, float endtime );
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROCESSING_TYPE_IGNORE = 0,
|
||||
PROCESSING_TYPE_START,
|
||||
PROCESSING_TYPE_START_RESUMECONDITION,
|
||||
PROCESSING_TYPE_CONTINUE,
|
||||
PROCESSING_TYPE_STOP,
|
||||
} PROCESSING_TYPE;
|
||||
|
||||
struct ActiveList
|
||||
{
|
||||
PROCESSING_TYPE pt;
|
||||
CChoreoEvent *e;
|
||||
};
|
||||
|
||||
static bool EventLess( const CChoreoScene::ActiveList &al0, const CChoreoScene::ActiveList &al1 );
|
||||
|
||||
int EventThink( CChoreoEvent *e,
|
||||
float frame_start_time,
|
||||
float frame_end_time,
|
||||
bool playing_forward, PROCESSING_TYPE& disposition );
|
||||
|
||||
// Prints to debug console, etc
|
||||
void choreoprintf( int level, PRINTF_FORMAT_STRING const char *fmt, ... );
|
||||
|
||||
// Initialize scene
|
||||
void Init( IChoreoEventCallback *callback );
|
||||
|
||||
float FindAdjustedStartTime( void );
|
||||
float FindAdjustedEndTime( void );
|
||||
|
||||
CChoreoEvent *FindPauseBetweenTimes( float starttime, float endtime );
|
||||
|
||||
// Parse scenes from token buffer
|
||||
CChoreoEvent *ParseEvent( CChoreoActor *actor, CChoreoChannel *channel );
|
||||
CChoreoChannel *ParseChannel( CChoreoActor *actor );
|
||||
CChoreoActor *ParseActor( void );
|
||||
|
||||
void ParseFPS( void );
|
||||
void ParseSnap( void );
|
||||
void ParseIgnorePhonemes( void );
|
||||
|
||||
// Map file for retrieving named objects
|
||||
void ParseMapname( void );
|
||||
// When previewing actor in hlfaceposer, this is the model to associate
|
||||
void ParseFacePoserModel( CChoreoActor *actor );
|
||||
|
||||
// Print to printfunc
|
||||
void PrintEvent( int level, CChoreoEvent *e );
|
||||
void PrintChannel( int level, CChoreoChannel *c );
|
||||
void PrintActor( int level, CChoreoActor *a );
|
||||
|
||||
// File I/O
|
||||
public:
|
||||
static void FilePrintf( CUtlBuffer& buf, int level, PRINTF_FORMAT_STRING const char *fmt, ... );
|
||||
private:
|
||||
void FileSaveEvent( CUtlBuffer& buf, int level, CChoreoEvent *e );
|
||||
void FileSaveChannel( CUtlBuffer& buf, int level, CChoreoChannel *c );
|
||||
void FileSaveActor( CUtlBuffer& buf, int level, CChoreoActor *a );
|
||||
void FileSaveHeader( CUtlBuffer& buf );
|
||||
|
||||
// Object destruction
|
||||
void DestroyActor( CChoreoActor *actor );
|
||||
void DestroyChannel( CChoreoChannel *channel );
|
||||
void DestroyEvent( CChoreoEvent *event );
|
||||
|
||||
|
||||
void AddPauseEventDependency( CChoreoEvent *pauseEvent, CChoreoEvent *suppressed );
|
||||
|
||||
void InternalDetermineEventTypes();
|
||||
|
||||
// Global object storage
|
||||
CUtlVector < CChoreoEvent * > m_Events;
|
||||
CUtlVector < CChoreoActor * > m_Actors;
|
||||
CUtlVector < CChoreoChannel * > m_Channels;
|
||||
|
||||
// These are just pointers, the actual objects are in m_Events
|
||||
CUtlVector < CChoreoEvent * > m_ResumeConditions;
|
||||
// These are just pointers, the actual objects are in m_Events
|
||||
CUtlVector < CChoreoEvent * > m_ActiveResumeConditions;
|
||||
// These are just pointers, the actual objects are in m_Events
|
||||
CUtlVector < CChoreoEvent * > m_PauseEvents;
|
||||
|
||||
// Current simulation time
|
||||
float m_flCurrentTime;
|
||||
|
||||
float m_flStartTime;
|
||||
float m_flEndTime;
|
||||
|
||||
bool m_bRecalculateSceneTimes;
|
||||
float m_flEarliestTime;
|
||||
float m_flLatestTime;
|
||||
int m_nActiveEvents;
|
||||
|
||||
// Wave file playback needs to issue play commands a bit ahead of time
|
||||
// in order to hit exact marks
|
||||
float m_flSoundSystemLatency;
|
||||
|
||||
// Scene's linger a bit after finishing to let blends reset themselves
|
||||
float m_flLastActiveTime;
|
||||
|
||||
// Print callback function
|
||||
void ( *m_pfnPrint )( PRINTF_FORMAT_STRING const char *fmt, ... );
|
||||
|
||||
IChoreoEventCallback *m_pIChoreoEventCallback;
|
||||
|
||||
ISceneTokenProcessor *m_pTokenizer;
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_MAPNAME = 128
|
||||
};
|
||||
|
||||
char m_szMapname[ MAX_MAPNAME ];
|
||||
|
||||
int m_nSceneFPS;
|
||||
|
||||
CCurveData m_SceneRamp;
|
||||
|
||||
CUtlDict< int, int > m_TimeZoomLookup;
|
||||
char m_szFileName[ MAX_SCENE_FILENAME ];
|
||||
|
||||
CBitVec< CChoreoEvent::NUM_TYPES > m_bitvecHasEventOfType;
|
||||
|
||||
// tag to suppress vcd when others are playing
|
||||
bool m_bIsBackground : 1;
|
||||
bool m_bIgnorePhonemes : 1;
|
||||
bool m_bSubScene : 1;
|
||||
bool m_bUseFrameSnap : 1;
|
||||
bool m_bRestoring : 1;
|
||||
|
||||
int m_nLastPauseEvent;
|
||||
// This only gets updated if it's loaded from a buffer which means we're not in an editor
|
||||
float m_flPrecomputedStopTime;
|
||||
};
|
||||
|
||||
|
||||
bool CChoreoScene::IsRestoring()
|
||||
{
|
||||
return m_bRestoring;
|
||||
}
|
||||
|
||||
|
||||
void CChoreoScene::SetRestoring( bool bRestoring )
|
||||
{
|
||||
m_bRestoring = bRestoring;
|
||||
}
|
||||
|
||||
|
||||
abstract_class IChoreoStringPool
|
||||
{
|
||||
public:
|
||||
virtual short FindOrAddString( const char *pString ) = 0;
|
||||
virtual bool GetString( short stringId, char *buff, int buffSize ) = 0;
|
||||
};
|
||||
|
||||
CChoreoScene *ChoreoLoadScene(
|
||||
char const *filename,
|
||||
IChoreoEventCallback *callback,
|
||||
ISceneTokenProcessor *tokenizer,
|
||||
void ( *pfn ) ( PRINTF_FORMAT_STRING const char *fmt, ... ) );
|
||||
|
||||
bool IsBufferBinaryVCD( char *pBuffer, int bufferSize );
|
||||
|
||||
#endif // CHOREOSCENE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,505 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef COLLISIONPROPERTY_H
|
||||
#define COLLISIONPROPERTY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "networkvar.h"
|
||||
#include "engine/ICollideable.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "ispatialpartition.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class CBaseEntity;
|
||||
class IHandleEntity;
|
||||
class QAngle;
|
||||
class Vector;
|
||||
struct Ray_t;
|
||||
class IPhysicsObject;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Force spatial partition updates (to avoid threading problems caused by lazy update)
|
||||
//-----------------------------------------------------------------------------
|
||||
void UpdateDirtySpatialPartitionEntities();
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specifies how to compute the surrounding box
|
||||
//-----------------------------------------------------------------------------
|
||||
enum SurroundingBoundsType_t
|
||||
{
|
||||
USE_OBB_COLLISION_BOUNDS = 0,
|
||||
USE_BEST_COLLISION_BOUNDS, // Always use the best bounds (most expensive)
|
||||
USE_HITBOXES,
|
||||
USE_SPECIFIED_BOUNDS,
|
||||
USE_GAME_CODE,
|
||||
USE_ROTATION_EXPANDED_BOUNDS,
|
||||
USE_COLLISION_BOUNDS_NEVER_VPHYSICS,
|
||||
USE_ROTATION_EXPANDED_SEQUENCE_BOUNDS,
|
||||
|
||||
SURROUNDING_TYPE_BIT_COUNT = 3
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Encapsulates collision representation for an entity
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCollisionProperty : public ICollideable
|
||||
{
|
||||
DECLARE_CLASS_NOBASE( CCollisionProperty );
|
||||
DECLARE_EMBEDDED_NETWORKVAR();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifdef GAME_DLL
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
public:
|
||||
CCollisionProperty();
|
||||
~CCollisionProperty();
|
||||
|
||||
void Init( CBaseEntity *pEntity );
|
||||
|
||||
// Methods of ICollideable
|
||||
virtual IHandleEntity *GetEntityHandle();
|
||||
virtual const Vector& OBBMins( ) const;
|
||||
virtual const Vector& OBBMaxs( ) const;
|
||||
virtual void WorldSpaceTriggerBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) const;
|
||||
virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
|
||||
virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
|
||||
virtual int GetCollisionModelIndex();
|
||||
virtual const model_t* GetCollisionModel();
|
||||
virtual const Vector& GetCollisionOrigin() const;
|
||||
virtual const QAngle& GetCollisionAngles() const;
|
||||
virtual const matrix3x4_t& CollisionToWorldTransform() const;
|
||||
virtual SolidType_t GetSolid() const;
|
||||
virtual int GetSolidFlags() const;
|
||||
virtual IClientUnknown* GetIClientUnknown();
|
||||
virtual int GetCollisionGroup() const;
|
||||
virtual void WorldSpaceSurroundingBounds( Vector *pVecMins, Vector *pVecMaxs );
|
||||
virtual uint GetRequiredTriggerFlags() const;
|
||||
virtual const matrix3x4_t *GetRootParentToWorldTransform() const;
|
||||
virtual IPhysicsObject *GetVPhysicsObject() const;
|
||||
|
||||
public:
|
||||
// Spatial partition management
|
||||
void CreatePartitionHandle();
|
||||
void DestroyPartitionHandle();
|
||||
SpatialPartitionHandle_t GetPartitionHandle() const;
|
||||
|
||||
// Marks the spatial partition dirty
|
||||
void MarkPartitionHandleDirty();
|
||||
|
||||
// Sets the collision bounds + the size (OBB)
|
||||
void SetCollisionBounds( const Vector& mins, const Vector &maxs );
|
||||
|
||||
// Sets special trigger bounds. The bloat amount indicates how much bigger the
|
||||
// trigger bounds should be beyond the bounds set in SetCollisionBounds
|
||||
// This method will also set the FSOLID flag FSOLID_USE_TRIGGER_BOUNDS
|
||||
void UseTriggerBounds( bool bEnable, float flBloat = 0.0f );
|
||||
|
||||
// Sets the method by which the surrounding collision bounds is set
|
||||
// You must pass in values for mins + maxs if you select the USE_SPECIFIED_BOUNDS type.
|
||||
void SetSurroundingBoundsType( SurroundingBoundsType_t type, const Vector *pMins = NULL, const Vector *pMaxs = NULL );
|
||||
SurroundingBoundsType_t GetSurroundingBoundsType() const;
|
||||
|
||||
// Sets the solid type (which type of collision representation)
|
||||
void SetSolid( SolidType_t val );
|
||||
|
||||
// Methods related to size. The OBB here is measured in CollisionSpace
|
||||
// (specified by GetCollisionToWorld)
|
||||
const Vector& OBBSize( ) const;
|
||||
|
||||
// Returns a radius (or the square of the radius) of a sphere
|
||||
// *centered at the world space center* bounding the collision representation
|
||||
// of the entity. NOTE: The world space center *may* move when the entity rotates.
|
||||
float BoundingRadius() const;
|
||||
float BoundingRadius2D() const;
|
||||
|
||||
// Returns the center of the OBB in collision space
|
||||
const Vector & OBBCenter( ) const;
|
||||
|
||||
// center point of entity measured in world space
|
||||
// NOTE: This point *may* move when the entity moves depending on
|
||||
// which solid type is being used.
|
||||
const Vector & WorldSpaceCenter( ) const;
|
||||
|
||||
// Methods related to solid flags
|
||||
void ClearSolidFlags( void );
|
||||
void RemoveSolidFlags( int flags );
|
||||
void AddSolidFlags( int flags );
|
||||
bool IsSolidFlagSet( int flagMask ) const;
|
||||
void SetSolidFlags( int flags );
|
||||
bool IsSolid() const;
|
||||
|
||||
// Updates the spatial partition
|
||||
void UpdatePartition( );
|
||||
|
||||
// Are the bounds defined in entity space?
|
||||
bool IsBoundsDefinedInEntitySpace() const;
|
||||
|
||||
// Transforms a point in OBB space to world space
|
||||
const Vector & CollisionToWorldSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Transforms a point in world space to OBB space
|
||||
const Vector & WorldToCollisionSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Transforms a direction in world space to OBB space
|
||||
const Vector & WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Selects a random point in the bounds given the normalized 0-1 bounds
|
||||
void RandomPointInBounds( const Vector &vecNormalizedMins, const Vector &vecNormalizedMaxs, Vector *pPoint) const;
|
||||
|
||||
// Is a worldspace point within the bounds of the OBB?
|
||||
bool IsPointInBounds( const Vector &vecWorldPt ) const;
|
||||
|
||||
// Computes a bounding box in world space surrounding the collision bounds
|
||||
void WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const;
|
||||
|
||||
// Computes a "normalized" point (range 0,0,0 - 1,1,1) in collision space
|
||||
// Useful for things like getting a point 75% of the way along z on the OBB, for example
|
||||
const Vector & NormalizedToCollisionSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Computes a "normalized" point (range 0,0,0 - 1,1,1) in world space
|
||||
const Vector & NormalizedToWorldSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Transforms a point in world space to normalized space
|
||||
const Vector & WorldToNormalizedSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Transforms a point in collision space to normalized space
|
||||
const Vector & CollisionToNormalizedSpace( const Vector &in, Vector *pResult ) const;
|
||||
|
||||
// Computes the nearest point in the OBB to a point specified in world space
|
||||
void CalcNearestPoint( const Vector &vecWorldPt, Vector *pVecNearestWorldPt ) const;
|
||||
|
||||
// Computes the distance from a point in world space to the OBB
|
||||
float CalcDistanceFromPoint( const Vector &vecWorldPt ) const;
|
||||
float CalcSqrDistanceFromPoint( const Vector &vecWorldPt ) const;
|
||||
|
||||
// Does a rotation make us need to recompute the surrounding box?
|
||||
bool DoesRotationInvalidateSurroundingBox( ) const;
|
||||
|
||||
// Does VPhysicsUpdate make us need to recompute the surrounding box?
|
||||
bool DoesVPhysicsInvalidateSurroundingBox( ) const;
|
||||
|
||||
// Does a sequence change make us need to recompute the surrounding box?
|
||||
bool DoesSequenceChangeInvalidateSurroundingBox( ) const;
|
||||
|
||||
// Marks the entity has having a dirty surrounding box
|
||||
void MarkSurroundingBoundsDirty();
|
||||
|
||||
// Compute the largest dot product of the OBB and the specified direction vector
|
||||
float ComputeSupportMap( const Vector &vecDirection ) const;
|
||||
|
||||
private:
|
||||
// Transforms an AABB measured in collision space to a box that surrounds it in world space
|
||||
void CollisionAABBToWorldAABB( const Vector &entityMins, const Vector &entityMaxs, Vector *pWorldMins, Vector *pWorldMaxs ) const;
|
||||
|
||||
// Expand trigger bounds..
|
||||
void ComputeVPhysicsSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Expand trigger bounds..
|
||||
bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Computes the surrounding collision bounds based on the current sequence box
|
||||
void ComputeOBBBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Computes the surrounding collision bounds from the current sequence box
|
||||
void ComputeRotationExpandedSequenceBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Computes the surrounding collision bounds based on whatever algorithm we want...
|
||||
void ComputeCollisionSurroundingBox( bool bUseVPhysics, Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Computes the surrounding collision bounds from the OBB (not vphysics)
|
||||
void ComputeRotationExpandedBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Computes the surrounding collision bounds based on whatever algorithm we want...
|
||||
void ComputeSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Check for untouch
|
||||
void CheckForUntouch();
|
||||
|
||||
// Updates the spatial partition
|
||||
void UpdateServerPartitionMask( );
|
||||
uint ComputeServerPartitionMask( );
|
||||
inline const Vector& GetCollisionOrigin_Inline() const;
|
||||
|
||||
// Outer
|
||||
CBaseEntity *GetOuter();
|
||||
const CBaseEntity *GetOuter() const;
|
||||
|
||||
private:
|
||||
CBaseEntity *m_pOuter;
|
||||
|
||||
// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system)
|
||||
CNetworkVector( m_vecMins );
|
||||
CNetworkVector( m_vecMaxs );
|
||||
CNetworkVar( unsigned short, m_usSolidFlags );
|
||||
// One of the SOLID_ defines. Use GetSolid/SetSolid.
|
||||
CNetworkVar( unsigned char, m_nSolidType );
|
||||
CNetworkVar( unsigned char , m_triggerBloat );
|
||||
// END PREDICTION DATA COMPACTION
|
||||
|
||||
float m_flRadius;
|
||||
|
||||
// Spatial partition
|
||||
SpatialPartitionHandle_t m_Partition;
|
||||
CNetworkVar( unsigned char, m_nSurroundType );
|
||||
|
||||
// SUCKY: We didn't use to have to store this previously
|
||||
// but storing it here means that we can network it + avoid a ton of
|
||||
// client-side mismatch problems
|
||||
CNetworkVector( m_vecSpecifiedSurroundingMins );
|
||||
CNetworkVector( m_vecSpecifiedSurroundingMaxs );
|
||||
|
||||
// Cached off world-aligned surrounding bounds
|
||||
#if 0
|
||||
short m_surroundingMins[3];
|
||||
short m_surroundingMaxs[3];
|
||||
#else
|
||||
Vector m_vecSurroundingMins;
|
||||
Vector m_vecSurroundingMaxs;
|
||||
#endif
|
||||
|
||||
// pointer to the entity's physics object (vphysics.dll)
|
||||
//IPhysicsObject *m_pPhysicsObject;
|
||||
|
||||
friend class CBaseEntity;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// For networking this bad boy
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef CLIENT_DLL
|
||||
EXTERN_RECV_TABLE( DT_CollisionProperty );
|
||||
#else
|
||||
EXTERN_SEND_TABLE( DT_CollisionProperty );
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inline methods
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CBaseEntity *CCollisionProperty::GetOuter()
|
||||
{
|
||||
return m_pOuter;
|
||||
}
|
||||
|
||||
inline const CBaseEntity *CCollisionProperty::GetOuter() const
|
||||
{
|
||||
return m_pOuter;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Spatial partition
|
||||
//-----------------------------------------------------------------------------
|
||||
inline SpatialPartitionHandle_t CCollisionProperty::GetPartitionHandle() const
|
||||
{
|
||||
return m_Partition;
|
||||
}
|
||||
|
||||
inline SurroundingBoundsType_t CCollisionProperty::GetSurroundingBoundsType() const
|
||||
{
|
||||
return (SurroundingBoundsType_t)m_nSurroundType.Get();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods related to size
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const Vector& CCollisionProperty::OBBSize( ) const
|
||||
{
|
||||
// NOTE: Could precache this, but it's not used that often..
|
||||
Vector &temp = AllocTempVector();
|
||||
VectorSubtract( m_vecMaxs, m_vecMins, temp );
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Bounding radius size
|
||||
//-----------------------------------------------------------------------------
|
||||
inline float CCollisionProperty::BoundingRadius() const
|
||||
{
|
||||
return m_flRadius;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods relating to solid flags
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CCollisionProperty::IsBoundsDefinedInEntitySpace() const
|
||||
{
|
||||
return (( m_usSolidFlags & FSOLID_FORCE_WORLD_ALIGNED ) == 0 ) &&
|
||||
( m_nSolidType != SOLID_BBOX ) && ( m_nSolidType != SOLID_NONE );
|
||||
}
|
||||
|
||||
inline void CCollisionProperty::ClearSolidFlags( void )
|
||||
{
|
||||
SetSolidFlags( 0 );
|
||||
}
|
||||
|
||||
inline void CCollisionProperty::RemoveSolidFlags( int flags )
|
||||
{
|
||||
SetSolidFlags( m_usSolidFlags & ~flags );
|
||||
}
|
||||
|
||||
inline void CCollisionProperty::AddSolidFlags( int flags )
|
||||
{
|
||||
SetSolidFlags( m_usSolidFlags | flags );
|
||||
}
|
||||
|
||||
inline int CCollisionProperty::GetSolidFlags( void ) const
|
||||
{
|
||||
return m_usSolidFlags;
|
||||
}
|
||||
|
||||
inline bool CCollisionProperty::IsSolidFlagSet( int flagMask ) const
|
||||
{
|
||||
return (m_usSolidFlags & flagMask) != 0;
|
||||
}
|
||||
|
||||
inline bool CCollisionProperty::IsSolid() const
|
||||
{
|
||||
return ::IsSolid( (SolidType_t)(unsigned char)m_nSolidType, m_usSolidFlags );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the center in OBB space
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const Vector& CCollisionProperty::OBBCenter( ) const
|
||||
{
|
||||
Vector &vecResult = AllocTempVector();
|
||||
VectorLerp( m_vecMins, m_vecMaxs, 0.5f, vecResult );
|
||||
return vecResult;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// center point of entity
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const Vector &CCollisionProperty::WorldSpaceCenter( ) const
|
||||
{
|
||||
Vector &vecResult = AllocTempVector();
|
||||
CollisionToWorldSpace( OBBCenter(), &vecResult );
|
||||
return vecResult;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Transforms a point in OBB space to world space
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const Vector &CCollisionProperty::CollisionToWorldSpace( const Vector &in, Vector *pResult ) const
|
||||
{
|
||||
// Makes sure we don't re-use the same temp twice
|
||||
if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) )
|
||||
{
|
||||
VectorAdd( in, GetCollisionOrigin(), *pResult );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorTransform( in, CollisionToWorldTransform(), *pResult );
|
||||
}
|
||||
return *pResult;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Transforms a point in world space to OBB space
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const Vector &CCollisionProperty::WorldToCollisionSpace( const Vector &in, Vector *pResult ) const
|
||||
{
|
||||
if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) )
|
||||
{
|
||||
VectorSubtract( in, GetCollisionOrigin(), *pResult );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorITransform( in, CollisionToWorldTransform(), *pResult );
|
||||
}
|
||||
return *pResult;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Transforms a direction in world space to OBB space
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const Vector & CCollisionProperty::WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const
|
||||
{
|
||||
if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) )
|
||||
{
|
||||
*pResult = in;
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorIRotate( in, CollisionToWorldTransform(), *pResult );
|
||||
}
|
||||
return *pResult;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes a bounding box in world space surrounding the collision bounds
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CCollisionProperty::WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const
|
||||
{
|
||||
CollisionAABBToWorldAABB( m_vecMins, m_vecMaxs, pWorldMins, pWorldMaxs );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Does a rotation make us need to recompute the surrounding box?
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CCollisionProperty::DoesSequenceChangeInvalidateSurroundingBox( ) const
|
||||
{
|
||||
return ( m_nSurroundType == USE_ROTATION_EXPANDED_SEQUENCE_BOUNDS );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Does a rotation make us need to recompute the surrounding box?
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CCollisionProperty::DoesRotationInvalidateSurroundingBox( ) const
|
||||
{
|
||||
if ( IsSolidFlagSet(FSOLID_ROOT_PARENT_ALIGNED) )
|
||||
return true;
|
||||
|
||||
switch ( m_nSurroundType )
|
||||
{
|
||||
case USE_COLLISION_BOUNDS_NEVER_VPHYSICS:
|
||||
case USE_OBB_COLLISION_BOUNDS:
|
||||
case USE_BEST_COLLISION_BOUNDS:
|
||||
return IsBoundsDefinedInEntitySpace();
|
||||
|
||||
// In the case of game code, we don't really know, so we have to assume it does
|
||||
case USE_HITBOXES:
|
||||
case USE_GAME_CODE:
|
||||
return true;
|
||||
|
||||
case USE_ROTATION_EXPANDED_BOUNDS:
|
||||
case USE_SPECIFIED_BOUNDS:
|
||||
case USE_ROTATION_EXPANDED_SEQUENCE_BOUNDS:
|
||||
return false;
|
||||
|
||||
default:
|
||||
Assert(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // COLLISIONPROPERTY_H
|
||||
@@ -0,0 +1,71 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "cs_achievements_and_stats_interface.h"
|
||||
#include "baseachievement.h"
|
||||
#include "GameEventListener.h"
|
||||
#include "../common/xlast_csgo/csgo.spa.h"
|
||||
#include "iachievementmgr.h"
|
||||
#include "utlmap.h"
|
||||
#include "steam/steam_api.h"
|
||||
|
||||
#include "vgui_controls/Panel.h"
|
||||
#include "vgui_controls/PHandle.h"
|
||||
#include "vgui_controls/MenuItem.h"
|
||||
#include "vgui_controls/messagedialog.h"
|
||||
|
||||
#include "cs_gamestats_shared.h"
|
||||
#include "vgui/IInput.h"
|
||||
#include "vgui/ILocalize.h"
|
||||
#include "vgui/IPanel.h"
|
||||
#include "vgui/ISurface.h"
|
||||
#include "vgui/ISystem.h"
|
||||
#include "vgui/IVGui.h"
|
||||
|
||||
|
||||
#if defined(CSTRIKE_DLL) && defined(CLIENT_DLL)
|
||||
|
||||
CSAchievementsAndStatsInterface::CSAchievementsAndStatsInterface() : AchievementsAndStatsInterface()
|
||||
{
|
||||
m_pAchievementAndStatsSummary = NULL;
|
||||
|
||||
g_pAchievementsAndStatsInterface = this;
|
||||
}
|
||||
|
||||
void CSAchievementsAndStatsInterface::CreatePanel( vgui::Panel* pParent )
|
||||
{
|
||||
// Create achievement & stats dialog if not already created
|
||||
if ( !m_pAchievementAndStatsSummary )
|
||||
{
|
||||
m_pAchievementAndStatsSummary = new CAchievementAndStatsSummary(NULL);
|
||||
}
|
||||
|
||||
if ( m_pAchievementAndStatsSummary )
|
||||
{
|
||||
m_pAchievementAndStatsSummary->SetParent(pParent);
|
||||
}
|
||||
}
|
||||
|
||||
void CSAchievementsAndStatsInterface::DisplayPanel()
|
||||
{
|
||||
// Position & show dialog
|
||||
PositionDialog(m_pAchievementAndStatsSummary);
|
||||
m_pAchievementAndStatsSummary->Activate();
|
||||
}
|
||||
|
||||
void CSAchievementsAndStatsInterface::ReleasePanel()
|
||||
{
|
||||
// Make sure the BasePanel doesn't try to delete this, because it doesn't really own it.
|
||||
if ( m_pAchievementAndStatsSummary )
|
||||
{
|
||||
m_pAchievementAndStatsSummary->SetParent((vgui::Panel*)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef CSACHIEVEMENTSANDSTATSINTERFACE_H
|
||||
#define CSACHIEVEMENTSANDSTATSINTERFACE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "achievements_and_stats_interface.h"
|
||||
#include "vgui/achievement_stats_summary.h"
|
||||
|
||||
|
||||
#if defined(CSTRIKE_DLL) && defined(CLIENT_DLL)
|
||||
|
||||
class CSAchievementsAndStatsInterface : public AchievementsAndStatsInterface
|
||||
{
|
||||
public:
|
||||
CSAchievementsAndStatsInterface();
|
||||
|
||||
virtual void CreatePanel( vgui::Panel* pParent );
|
||||
virtual void DisplayPanel();
|
||||
virtual void ReleasePanel();
|
||||
virtual int GetAchievementsPanelMinWidth( void ) const { return cAchievementsDialogMinWidth; }
|
||||
|
||||
protected:
|
||||
vgui::DHANDLE<vgui::Frame> m_pAchievementAndStatsSummary;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CSACHIEVEMENTSANDSTATSINTERFACE_H
|
||||
@@ -0,0 +1,132 @@
|
||||
//========= Copyright © 1996-2013, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Provide custom material swapping for weapons (when switch from world to view or vice versa)
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "cs_custom_material_swap.h"
|
||||
#include "materialsystem/icustommaterial.h"
|
||||
|
||||
CCSCustomMaterialSwapManager g_CSCustomMaterialSwapManager;
|
||||
|
||||
//
|
||||
// global custom material swap manager
|
||||
// the game uses this to swap custom materials (after the new one is done)
|
||||
//
|
||||
|
||||
CCSCustomMaterialSwapManager::CCSCustomMaterialSwapManager()
|
||||
{
|
||||
m_pPendingSwaps.EnsureCapacity( 4 );
|
||||
}
|
||||
|
||||
CCSCustomMaterialSwapManager::~CCSCustomMaterialSwapManager()
|
||||
{
|
||||
ClearAllPendingSwaps();
|
||||
}
|
||||
|
||||
// this is called at the end of each frame
|
||||
bool ProcessCustomMaterialSwapManager()
|
||||
{
|
||||
return g_CSCustomMaterialSwapManager.Process();
|
||||
}
|
||||
|
||||
bool CCSCustomMaterialSwapManager::Init()
|
||||
{
|
||||
g_pMaterialSystem->AddEndFramePriorToNextContextFunc( ::ProcessCustomMaterialSwapManager );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCSCustomMaterialSwapManager::Shutdown()
|
||||
{
|
||||
g_pMaterialSystem->RemoveEndFramePriorToNextContextFunc( ::ProcessCustomMaterialSwapManager );
|
||||
ClearAllPendingSwaps();
|
||||
}
|
||||
|
||||
// handles swapping materials that are pending swap and ready
|
||||
bool CCSCustomMaterialSwapManager::Process()
|
||||
{
|
||||
for ( int i = m_pPendingSwaps.Count() - 1; i >= 0 ; i-- )
|
||||
{
|
||||
if ( m_pPendingSwaps[ i ].m_pNewCustomMaterial->IsValid() )
|
||||
{
|
||||
C_BaseAnimating* pOwner = ( m_pPendingSwaps[ i ].m_hOwner ) ? m_pPendingSwaps[ i ].m_hOwner->GetBaseAnimating() : NULL;
|
||||
if ( pOwner )
|
||||
{
|
||||
pOwner->SetCustomMaterial( m_pPendingSwaps[ i ].m_pNewCustomMaterial, m_pPendingSwaps[ i ].m_nCustomMaterialIndex );
|
||||
}
|
||||
|
||||
m_pPendingSwaps[ i ].m_hOwner = NULL;
|
||||
m_pPendingSwaps[ i ].m_nCustomMaterialIndex = -1;
|
||||
m_pPendingSwaps[ i ].m_pNewCustomMaterial->Release();
|
||||
m_pPendingSwaps[ i ].m_pNewCustomMaterial = NULL;
|
||||
if ( m_pPendingSwaps[ i ].m_pOldCustomMaterial )
|
||||
{
|
||||
m_pPendingSwaps[ i ].m_pOldCustomMaterial->Release();
|
||||
m_pPendingSwaps[ i ].m_pOldCustomMaterial = NULL;
|
||||
}
|
||||
m_pPendingSwaps.Remove( i );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCSCustomMaterialSwapManager::RequestMaterialSwap( EHANDLE hOwner, int nCustomMaterialIndex, ICustomMaterial *pNewCustomMaterialInterface )
|
||||
{
|
||||
int nSwapIndex = m_pPendingSwaps.AddToTail();
|
||||
CCSPendingCustomMaterialSwap_t &materialSwap = m_pPendingSwaps[ nSwapIndex ];
|
||||
|
||||
materialSwap.m_hOwner = hOwner;
|
||||
materialSwap.m_nCustomMaterialIndex = nCustomMaterialIndex;
|
||||
|
||||
materialSwap.m_pNewCustomMaterial = pNewCustomMaterialInterface;
|
||||
materialSwap.m_pNewCustomMaterial->AddRef();
|
||||
|
||||
ICustomMaterial *pOldCustomMaterialInterface = hOwner->GetBaseAnimating()->GetCustomMaterial( nCustomMaterialIndex );
|
||||
materialSwap.m_pOldCustomMaterial = pOldCustomMaterialInterface;
|
||||
if ( materialSwap.m_pOldCustomMaterial )
|
||||
{
|
||||
materialSwap.m_pOldCustomMaterial->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
void CCSCustomMaterialSwapManager::ClearPendingSwaps( EHANDLE hOwner, int nCustomMaterialIndex )
|
||||
{
|
||||
for ( int i = m_pPendingSwaps.Count() - 1; i >= 0 ; i-- )
|
||||
{
|
||||
if ( m_pPendingSwaps[ i ].m_hOwner == hOwner && m_pPendingSwaps[ i ].m_nCustomMaterialIndex == nCustomMaterialIndex )
|
||||
{
|
||||
m_pPendingSwaps[ i ].m_hOwner = NULL;
|
||||
m_pPendingSwaps[ i ].m_nCustomMaterialIndex = -1;
|
||||
m_pPendingSwaps[ i ].m_pNewCustomMaterial->Release();
|
||||
m_pPendingSwaps[ i ].m_pNewCustomMaterial = NULL;
|
||||
if ( m_pPendingSwaps[ i ].m_pOldCustomMaterial )
|
||||
{
|
||||
m_pPendingSwaps[ i ].m_pOldCustomMaterial->Release();
|
||||
m_pPendingSwaps[ i ].m_pOldCustomMaterial = NULL;
|
||||
}
|
||||
m_pPendingSwaps.Remove( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCSCustomMaterialSwapManager::ClearAllPendingSwaps( void )
|
||||
{
|
||||
for ( int i = 0; i < m_pPendingSwaps.Count(); ++i )
|
||||
{
|
||||
CCSPendingCustomMaterialSwap_t &materialSwap = m_pPendingSwaps[ i ];
|
||||
materialSwap.m_hOwner = NULL;
|
||||
materialSwap.m_nCustomMaterialIndex = -1;
|
||||
materialSwap.m_pNewCustomMaterial->Release();
|
||||
materialSwap.m_pNewCustomMaterial = NULL;
|
||||
if ( m_pPendingSwaps[ i ].m_pOldCustomMaterial )
|
||||
{
|
||||
materialSwap.m_pOldCustomMaterial->Release();
|
||||
materialSwap.m_pOldCustomMaterial = NULL;
|
||||
}
|
||||
}
|
||||
m_pPendingSwaps.RemoveAll();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//========= Copyright © 1996-2012, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Provide custom material swapping for weapons (when switch from world to view or vice versa)
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_CUSTOM_MATERIAL_SWAP_H
|
||||
#define CS_CUSTOM_MATERIAL_SWAP_H
|
||||
|
||||
class ICustomMaterial;
|
||||
|
||||
struct CCSPendingCustomMaterialSwap_t
|
||||
{
|
||||
ICustomMaterial *m_pNewCustomMaterial;
|
||||
ICustomMaterial *m_pOldCustomMaterial;
|
||||
int m_nCustomMaterialIndex;
|
||||
EHANDLE m_hOwner;
|
||||
};
|
||||
|
||||
class CCSCustomMaterialSwapManager : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CCSCustomMaterialSwapManager();
|
||||
virtual ~CCSCustomMaterialSwapManager();
|
||||
|
||||
virtual bool Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
bool Process();
|
||||
|
||||
void RequestMaterialSwap( EHANDLE hOwner, int nCustomMaterialIndex, ICustomMaterial *pNewCustomMaterialInterface );
|
||||
void ClearPendingSwaps( EHANDLE hOwner, int nCustomMaterialIndex );
|
||||
|
||||
private:
|
||||
void ClearAllPendingSwaps();
|
||||
|
||||
CUtlVector< CCSPendingCustomMaterialSwap_t > m_pPendingSwaps;
|
||||
};
|
||||
|
||||
extern CCSCustomMaterialSwapManager g_CSCustomMaterialSwapManager;
|
||||
|
||||
#endif // CS_CUSTOM_MATERIAL_SWAP_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#if !defined ( ACHIEVEMENTS_CS_H )
|
||||
#define ACHIEVEMENTS_CS_H
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_gamestats_shared.h"
|
||||
#include "baseachievement.h"
|
||||
|
||||
#ifdef _PS3
|
||||
#include "steam/steam_api.h"
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole );
|
||||
bool IsLocalCSPlayerClass( int iClass );
|
||||
bool GameRulesAllowsAchievements( void );
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
// Base class for all CS achievements
|
||||
class CCSBaseAchievement : public CBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CCSBaseAchievement, CBaseAchievement );
|
||||
public:
|
||||
|
||||
CCSBaseAchievement();
|
||||
|
||||
virtual void GetSettings( KeyValues* pNodeOut ); // serialize
|
||||
virtual void ApplySettings( /* const */ KeyValues* pNodeIn ); // unserialize
|
||||
|
||||
// [dwenger] Necessary for sorting achievements by award time
|
||||
virtual void OnAchieved();
|
||||
bool GetAwardTime( int& year, int& month, int& day, int& hour, int& minute, int& second );
|
||||
|
||||
int64 GetSortKey() const { return GetUnlockTime(); }
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
// Helper class for achievements that check that the player was playing on a game team for the full round
|
||||
class CCSBaseAchievementFullRound : public CCSBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CCSBaseAchievementFullRound, CCSBaseAchievement );
|
||||
public:
|
||||
virtual void Init() ;
|
||||
virtual void ListenForEvents();
|
||||
void FireGameEvent_Internal( IGameEvent *event );
|
||||
bool PlayerWasInEntireRound( float flRoundTime );
|
||||
|
||||
virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event ) = 0 ;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
// Helper class for achievements based on other achievements
|
||||
class CAchievement_Meta : public CCSBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CAchievement_Meta, CCSBaseAchievement );
|
||||
public:
|
||||
CAchievement_Meta();
|
||||
virtual void Init();
|
||||
|
||||
#if !defined(NO_STEAM)
|
||||
STEAM_CALLBACK( CAchievement_Meta, Steam_OnUserAchievementStored, UserAchievementStored_t, m_CallbackUserAchievement );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void AddRequirement( int nAchievementId );
|
||||
|
||||
private:
|
||||
CUtlVector<int> m_requirements;
|
||||
};
|
||||
|
||||
//Base class for all achievements to kill x players with a given weapon
|
||||
class CAchievement_StatGoal: public CCSBaseAchievement
|
||||
{
|
||||
public:
|
||||
void SetStatId(CSStatType_t stat)
|
||||
{
|
||||
m_StatId = stat;
|
||||
}
|
||||
CSStatType_t GetStatId(void)
|
||||
{
|
||||
return m_StatId;
|
||||
}
|
||||
private:
|
||||
virtual void Init()
|
||||
{
|
||||
SetFlags( ACH_SAVE_GLOBAL );
|
||||
}
|
||||
|
||||
void OnPlayerStatsUpdate( int nUserSlot );
|
||||
CSStatType_t m_StatId;
|
||||
};
|
||||
|
||||
#if defined (_X360)
|
||||
static const int NumXboxMappedAchievements = 11; // number of xbox achievements that have a one to one correspondence with a medal
|
||||
static const int MedalToXBox[NumXboxMappedAchievements][2] = { { CSEnemyKillsHigh, ACHIEVEMENT_KILL_ENEMY_HIGH },
|
||||
{ CSGiveDamageLow, ACHIEVEMENT_GIVE_DAMAGE_LOW },
|
||||
{ CSMoneyEarnedLow, ACHIEVEMENT_EARN_MONEY_LOW },
|
||||
{ CSGunGameProgressiveRampage, ACHIEVEMENT_GUN_GAME_RAMPAGE },
|
||||
{ CSHeadshots, ACHIEVEMENT_HEADSHOTS },
|
||||
{ CSFlawlessVictory, ACHIEVEMENT_FLAWLESS_VICTORY },
|
||||
{ CSDominationsLow, ACHIEVEMENT_DOMINATIONS_LOW },
|
||||
{ CSKillWithEveryWeapon, ACHIEVEMENT_KILL_WITH_EVERY_WEAPON },
|
||||
{ CSKillEnemyLastBullet, ACHIEVEMENT_KILL_ENEMY_LAST_BULLET },
|
||||
{ CSKillEnemyTerrTeamBeforeBombPlant, ACHIEVEMENT_GUN_GAME_FIRST_THING_FIRST },
|
||||
{ CSGGRoundsHigh, ACHIEVEMENT_GUN_GAME_ROUNDS_HIGH }};
|
||||
|
||||
class CAchievementListener : public CAutoGameSystem, public CGameEventListener
|
||||
{
|
||||
public:
|
||||
CAchievementListener();
|
||||
|
||||
virtual bool Init();
|
||||
|
||||
protected:
|
||||
void FireGameEvent( IGameEvent *event );
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
extern CAchievementMgr g_AchievementMgrCS; // global achievement mgr for CS
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
#endif // ACHIEVEMENTS_CS_H
|
||||
@@ -0,0 +1,657 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basecsgrenade_projectile.h"
|
||||
|
||||
extern ConVar sv_gravity;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "c_cs_player.h"
|
||||
#include "hltvcamera.h"
|
||||
#include "in_buttons.h"
|
||||
#include <vgui/IInput.h>
|
||||
#include "vgui_controls/Controls.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "bot_manager.h"
|
||||
#include "cs_player.h"
|
||||
#include "soundent.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "keyvalues.h"
|
||||
#include "cs_gamestats.h"
|
||||
#include "cs_simple_hostage.h"
|
||||
#include "Effects/chicken.h"
|
||||
|
||||
BEGIN_DATADESC( CBaseCSGrenadeProjectile )
|
||||
DEFINE_THINKFUNC( DangerSoundThink ),
|
||||
END_DATADESC()
|
||||
|
||||
#define GRENADE_FAILSAFE_MAX_BOUNCES 20
|
||||
|
||||
#endif
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
extern ConVar spec_show_xray;
|
||||
extern ConVar sv_grenade_trajectory;
|
||||
extern ConVar sv_grenade_trajectory_time_spectator;
|
||||
extern ConVar sv_grenade_trajectory_thickness;
|
||||
extern ConVar sv_grenade_trajectory_dash;
|
||||
#endif
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CBaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropVector( RECVINFO( m_vInitialVelocity ) ),
|
||||
RecvPropInt( RECVINFO( m_nBounces ) )
|
||||
#else
|
||||
SendPropVector( SENDINFO( m_vInitialVelocity ),
|
||||
20, // nbits
|
||||
0, // flags
|
||||
-3000, // low value
|
||||
3000 // high value
|
||||
),
|
||||
SendPropInt( SENDINFO( m_nBounces ) )
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseCSGrenadeProjectile::~CBaseCSGrenadeProjectile()
|
||||
{
|
||||
flNextTrailLineTime = gpGlobals->curtime;
|
||||
CreateGrenadeTrail();
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::PostDataUpdate( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::PostDataUpdate( type );
|
||||
|
||||
//C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
|
||||
if ( type == DATA_UPDATE_CREATED )
|
||||
{
|
||||
SetNextClientThink( gpGlobals->curtime );
|
||||
|
||||
vecLastTrailLinePos = GetLocalOrigin();
|
||||
flNextTrailLineTime = gpGlobals->curtime + 0.1;
|
||||
|
||||
// Now stick our initial velocity into the interpolation history
|
||||
CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
|
||||
|
||||
interpolator.ClearHistory();
|
||||
float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR );
|
||||
|
||||
// Add a sample 1 second back.
|
||||
Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity;
|
||||
interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false );
|
||||
|
||||
// Add the current sample.
|
||||
vCurOrigin = GetLocalOrigin();
|
||||
interpolator.AddToHead( changeTime, &vCurOrigin, false );
|
||||
|
||||
|
||||
// IGameEvent * event = gameeventmanager->CreateEvent( "grenade_projectile_created" );
|
||||
// C_CSPlayer *pPlayer = dynamic_cast<C_CSPlayer*>( GetThrower() );
|
||||
// if( event && pPlayer )
|
||||
// {
|
||||
// event->SetInt( "owneruserid", pPlayer ? pPlayer->GetUserID() : 0 );
|
||||
// event->SetInt( "grenade", GetGrenadeType() );
|
||||
// gameeventmanager->FireEvent( event );
|
||||
// }
|
||||
|
||||
//if ( pLocalPlayer )
|
||||
// pLocalPlayer->NotifyPlayerOfThrownGrenade( this, GetThrower(), GetGrenadeType() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::ClientThink( void )
|
||||
{
|
||||
BaseClass::ClientThink();
|
||||
|
||||
SetNextClientThink( gpGlobals->curtime );
|
||||
|
||||
if ( flNextTrailLineTime <= gpGlobals->curtime )
|
||||
{
|
||||
CreateGrenadeTrail();
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::CreateGrenadeTrail( void )
|
||||
{
|
||||
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
|
||||
if ( !pLocalPlayer )
|
||||
return;
|
||||
|
||||
if ( flNextTrailLineTime <= gpGlobals->curtime )
|
||||
{
|
||||
bool bRenderForSpectator = CanSeeSpectatorOnlyTools() && spec_show_xray.GetInt();
|
||||
if ( sv_grenade_trajectory_time_spectator.GetFloat() > 0.0f && sv_grenade_trajectory.GetInt() == 0 && pLocalPlayer && ( bRenderForSpectator || ( !pLocalPlayer->IsAlive() && ( pLocalPlayer->GetObserverMode() > OBS_MODE_FREEZECAM ) ) ) )
|
||||
{
|
||||
bool bRender = false;
|
||||
|
||||
if ( ( GetTeamNumber() == TEAM_CT ) && ( bRenderForSpectator || ( pLocalPlayer->GetTeamNumber() == TEAM_CT ) ) )
|
||||
bRender = true;
|
||||
else if ( ( GetTeamNumber() == TEAM_TERRORIST ) && ( bRenderForSpectator || ( pLocalPlayer->GetTeamNumber() == TEAM_TERRORIST ) ) )
|
||||
bRender = true;
|
||||
|
||||
if ( bRender )
|
||||
{
|
||||
// Grenade trails for spectators
|
||||
//CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
|
||||
|
||||
QAngle angGrTrajAngles;
|
||||
Vector vec3tempOrientation = ( vecLastTrailLinePos - GetLocalOrigin() );
|
||||
VectorAngles( vec3tempOrientation, angGrTrajAngles );
|
||||
|
||||
float flGrTraThickness = sv_grenade_trajectory_thickness.GetFloat();
|
||||
Vector vec3_GrTrajMin = Vector( 0, -flGrTraThickness, -flGrTraThickness );
|
||||
Vector vec3_GrTrajMax = Vector( vec3tempOrientation.Length(), flGrTraThickness, flGrTraThickness );
|
||||
bool bDotted = ( sv_grenade_trajectory_dash.GetInt() && ( fmod( gpGlobals->curtime, 0.1f ) < 0.05f ) );
|
||||
|
||||
Color traceColor;
|
||||
if ( GetTeamNumber() == TEAM_CT )
|
||||
{
|
||||
traceColor[0] = 114;
|
||||
traceColor[1] = 155;
|
||||
traceColor[2] = 221;
|
||||
}
|
||||
else
|
||||
{
|
||||
traceColor[0] = 224;
|
||||
traceColor[1] = 175;
|
||||
traceColor[2] = 86;
|
||||
}
|
||||
|
||||
if ( bDotted )
|
||||
{
|
||||
traceColor[0] /= 10;
|
||||
traceColor[1] /= 10;
|
||||
traceColor[2] /= 10;
|
||||
}
|
||||
|
||||
//Add extruded box shapes to glow pass to build the arc
|
||||
GlowObjectManager().AddGlowBox( GetLocalOrigin(), angGrTrajAngles, vec3_GrTrajMin, vec3_GrTrajMax, traceColor, sv_grenade_trajectory_time_spectator.GetFloat() );
|
||||
|
||||
//Make the grenade projectile itself glow
|
||||
if ( !m_GlowObject.IsRendering() )
|
||||
{
|
||||
m_GlowObject.SetColor( Vector( traceColor[0] / 255.0f, traceColor[1] / 255.0f, traceColor[2] / 255.0f ) );
|
||||
m_GlowObject.SetAlpha( 0.3f );
|
||||
m_GlowObject.SetGlowAlphaCappedByRenderAlpha( true );
|
||||
m_GlowObject.SetGlowAlphaFunctionOfMaxVelocity( 50.0f );
|
||||
m_GlowObject.SetGlowAlphaMax( 0.3f );
|
||||
m_GlowObject.SetRenderFlags( true, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vecLastTrailLinePos = GetLocalOrigin();
|
||||
flNextTrailLineTime = gpGlobals->curtime + 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
int CBaseCSGrenadeProjectile::DrawModel( int flags, const RenderableInstance_t &instance )
|
||||
{
|
||||
// During the first half-second of our life, don't draw ourselves if he's
|
||||
// still playing his throw animation.
|
||||
// (better yet, we could draw ourselves in his hand).
|
||||
if ( GetThrower() != C_BasePlayer::GetLocalPlayer() )
|
||||
{
|
||||
if ( gpGlobals->curtime - m_flSpawnTime < 0.5 )
|
||||
{
|
||||
C_CSPlayer *pPlayer = dynamic_cast<C_CSPlayer*>( GetThrower() );
|
||||
if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::DrawModel( flags, instance );
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::Spawn()
|
||||
{
|
||||
m_flSpawnTime = gpGlobals->curtime;
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void CBaseCSGrenadeProjectile::PostConstructor( const char *className )
|
||||
{
|
||||
BaseClass::PostConstructor( className );
|
||||
TheBots->AddGrenade( this );
|
||||
}
|
||||
|
||||
CBaseCSGrenadeProjectile::~CBaseCSGrenadeProjectile()
|
||||
{
|
||||
TheBots->RemoveGrenade( this );
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
PrecacheEffect( "gunshotsplash" );
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetSolidFlags( FSOLID_NOT_STANDABLE );
|
||||
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
|
||||
SetSolid( SOLID_BBOX ); // So it will collide with physics props!
|
||||
AddFlag( FL_GRENADE );
|
||||
|
||||
m_lastHitPlayer = NULL;
|
||||
|
||||
// smaller, cube bounding box so we rest on the ground
|
||||
Vector min = Vector( -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE );
|
||||
Vector max = Vector( GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE );
|
||||
|
||||
SetSize( min, max );
|
||||
if ( CollisionProp( ) )
|
||||
CollisionProp( )->SetCollisionBounds( min, max );
|
||||
|
||||
m_nBounces = 0;
|
||||
}
|
||||
|
||||
int CBaseCSGrenadeProjectile::UpdateTransmitState()
|
||||
{
|
||||
// always call ShouldTransmit() for grenades
|
||||
return SetTransmitState( FL_EDICT_FULLCHECK );
|
||||
}
|
||||
|
||||
int CBaseCSGrenadeProjectile::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
|
||||
if ( pRecipientEntity->IsPlayer() )
|
||||
{
|
||||
CBasePlayer *pRecipientPlayer = static_cast<CBasePlayer*>( pRecipientEntity );
|
||||
|
||||
// always transmit to the thrower of the grenade
|
||||
if ( pRecipientPlayer && ( (GetThrower() && pRecipientPlayer == GetThrower()) ||
|
||||
pRecipientPlayer->GetTeamNumber() == TEAM_SPECTATOR) )
|
||||
{
|
||||
return FL_EDICT_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
return FL_EDICT_PVSCHECK;
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::DangerSoundThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
Remove( );
|
||||
return;
|
||||
}
|
||||
|
||||
if( gpGlobals->curtime > m_flDetonateTime )
|
||||
{
|
||||
Detonate();
|
||||
return;
|
||||
}
|
||||
|
||||
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2 );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.2 );
|
||||
|
||||
if (GetWaterLevel() != WL_NotInWater)
|
||||
{
|
||||
SetAbsVelocity( GetAbsVelocity() * 0.5 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Sets the time at which the grenade will explode
|
||||
void CBaseCSGrenadeProjectile::SetDetonateTimerLength( float timer )
|
||||
{
|
||||
m_flDetonateTime = gpGlobals->curtime + timer;
|
||||
}
|
||||
|
||||
unsigned int CBaseCSGrenadeProjectile::PhysicsSolidMaskForEntity( void ) const
|
||||
{
|
||||
if ( GetCollisionGroup() == COLLISION_GROUP_DEBRIS )
|
||||
{
|
||||
return ((CONTENTS_GRENADECLIP | MASK_SOLID) & ~CONTENTS_MONSTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (CONTENTS_GRENADECLIP|MASK_SOLID|MASK_VISIBLE_AND_NPCS|CONTENTS_HITBOX) & ~(CONTENTS_DEBRIS);
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecMove )
|
||||
{
|
||||
const float kSleepVelocity = 20.0f;
|
||||
const float kSleepVelocitySquared = kSleepVelocity * kSleepVelocity;
|
||||
|
||||
// Verify that we have an entity.
|
||||
CBaseEntity *pEntity = trace.m_pEnt;
|
||||
Assert( pEntity );
|
||||
|
||||
if ( pEntity )
|
||||
{
|
||||
CChicken *pChicken = dynamic_cast< CChicken* >( pEntity );
|
||||
if (pChicken)
|
||||
{
|
||||
// hurt the chicken
|
||||
CTakeDamageInfo info( this, this, 10, DMG_CLUB );
|
||||
pChicken->DispatchTraceAttack( info, GetAbsVelocity().Normalized(), &trace );
|
||||
ApplyMultiDamage();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if its breakable glass and we kill it, don't bounce.
|
||||
// give some damage to the glass, and if it breaks, pass
|
||||
// through it.
|
||||
bool breakthrough = false;
|
||||
|
||||
if( pEntity && FClassnameIs( pEntity, "func_breakable" ) )
|
||||
{
|
||||
breakthrough = true;
|
||||
}
|
||||
|
||||
if( pEntity && FClassnameIs( pEntity, "func_breakable_surf" ) )
|
||||
{
|
||||
breakthrough = true;
|
||||
}
|
||||
|
||||
if( pEntity && FClassnameIs( pEntity, "prop_physics_multiplayer" ) && pEntity->GetMaxHealth() > 0 && pEntity->m_takedamage == DAMAGE_YES )
|
||||
{
|
||||
breakthrough = true;
|
||||
}
|
||||
|
||||
// this one is tricky because BounceTouch hits breakable propers before we hit this function and the damage is already applied there (CBaseGrenade::BounceTouch( CBaseEntity *pOther ))
|
||||
// by the time we hit this, the prop hasn't been removed yet, but it broke, is set to not take anymore damage and is marked for deletion - we have to cover this case here
|
||||
if( pEntity && FClassnameIs( pEntity, "prop_dynamic" ) && pEntity->GetMaxHealth() > 0 && (pEntity->m_takedamage == DAMAGE_YES || (pEntity->m_takedamage == DAMAGE_NO && pEntity->IsEFlagSet( EFL_KILLME ))) )
|
||||
{
|
||||
breakthrough = true;
|
||||
}
|
||||
|
||||
if ( breakthrough )
|
||||
{
|
||||
CTakeDamageInfo info( this, this, 10, DMG_CLUB );
|
||||
pEntity->DispatchTraceAttack( info, GetAbsVelocity().Normalized(), &trace );
|
||||
|
||||
ApplyMultiDamage();
|
||||
|
||||
if( pEntity->m_iHealth <= 0 )
|
||||
{
|
||||
// slow our flight a little bit
|
||||
Vector vel = GetAbsVelocity();
|
||||
|
||||
vel *= 0.4;
|
||||
|
||||
SetAbsVelocity( vel );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Assume all surfaces have the same elasticity
|
||||
float flSurfaceElasticity = 1.0;
|
||||
|
||||
//Don't bounce off of players with perfect elasticity
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
flSurfaceElasticity = 0.3f;
|
||||
|
||||
// and do slight damage to players on the opposite team
|
||||
if ( GetTeamNumber() != pEntity->GetTeamNumber() )
|
||||
{
|
||||
CTakeDamageInfo info( this, GetThrower(), 2, DMG_GENERIC );
|
||||
|
||||
pEntity->TakeDamage( info );
|
||||
}
|
||||
}
|
||||
|
||||
//Don't bounce twice on a selection of problematic entities
|
||||
bool bIsProjectile = dynamic_cast< CBaseCSGrenadeProjectile* >( pEntity ) != NULL;
|
||||
if ( pEntity && !pEntity->IsWorld() && m_lastHitPlayer.Get() == pEntity )
|
||||
{
|
||||
bool bIsHostage = dynamic_cast< CHostage* >( pEntity ) != NULL;
|
||||
if ( pEntity->IsPlayer() || bIsHostage || bIsProjectile )
|
||||
{
|
||||
//DevMsg( "Setting %s to DEBRIS, it is in group %i, it hit %s in group %i\n", this->GetClassname(), this->GetCollisionGroup(), pEntity->GetClassname(), pEntity->GetCollisionGroup() );
|
||||
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
|
||||
if ( bIsProjectile )
|
||||
{
|
||||
//DevMsg( "Setting %s to DEBRIS, it is in group %i.\n", pEntity->GetClassname(), pEntity->GetCollisionGroup() );
|
||||
pEntity->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( pEntity )
|
||||
{
|
||||
m_lastHitPlayer = pEntity;
|
||||
}
|
||||
|
||||
float flTotalElasticity = GetElasticity() * flSurfaceElasticity;
|
||||
flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f );
|
||||
|
||||
// NOTE: A backoff of 2.0f is a reflection
|
||||
Vector vecAbsVelocity;
|
||||
PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f );
|
||||
vecAbsVelocity *= flTotalElasticity;
|
||||
|
||||
// Get the total velocity (player + conveyors, etc.)
|
||||
VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecMove );
|
||||
float flSpeedSqr = DotProduct( vecMove, vecMove );
|
||||
|
||||
bool bIsWeapon = dynamic_cast< CBaseCombatWeapon* >( pEntity ) != NULL;
|
||||
|
||||
// Stop if on ground or if we bounce and our velocity is really low (keeps it from bouncing infinitely)
|
||||
if ( pEntity &&
|
||||
( ( trace.plane.normal.z > 0.7f ) || (trace.plane.normal.z > 0.1f && flSpeedSqr < kSleepVelocitySquared) ) &&
|
||||
( pEntity->IsStandable() || bIsProjectile || bIsWeapon || pEntity->IsWorld() )
|
||||
)
|
||||
{
|
||||
// clip it again to emulate old behavior and keep it from bouncing up like crazy when you throw it at the ground on the first toss
|
||||
if ( flSpeedSqr > 96000 )
|
||||
{
|
||||
float alongDist = DotProduct( vecAbsVelocity.Normalized(), trace.plane.normal );
|
||||
if ( alongDist > 0.5f )
|
||||
{
|
||||
float flBouncePadding = (1.0f - alongDist) + 0.5f;
|
||||
vecAbsVelocity *= flBouncePadding;
|
||||
}
|
||||
}
|
||||
|
||||
SetAbsVelocity( vecAbsVelocity );
|
||||
|
||||
if ( flSpeedSqr < kSleepVelocitySquared )
|
||||
{
|
||||
SetGroundEntity( pEntity );
|
||||
|
||||
// Reset velocities.
|
||||
SetAbsVelocity( vec3_origin );
|
||||
SetLocalAngularVelocity( vec3_angle );
|
||||
|
||||
//align to the ground so we're not standing on end
|
||||
QAngle angle;
|
||||
VectorAngles( trace.plane.normal, angle );
|
||||
|
||||
// rotate randomly in yaw
|
||||
angle[1] = random->RandomFloat( 0, 360 );
|
||||
|
||||
// TODO: rotate around trace.plane.normal
|
||||
|
||||
SetAbsAngles( angle );
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vecBaseDir = GetBaseVelocity();
|
||||
if ( !vecBaseDir.IsZero() )
|
||||
{
|
||||
VectorNormalize( vecBaseDir );
|
||||
Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;
|
||||
float flScale = vecDelta.Dot( vecBaseDir );
|
||||
vecAbsVelocity += GetBaseVelocity() * flScale;
|
||||
}
|
||||
|
||||
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecMove );
|
||||
|
||||
PhysicsPushEntity( vecMove, &trace );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAbsVelocity( vecAbsVelocity );
|
||||
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecMove );
|
||||
PhysicsPushEntity( vecMove, &trace );
|
||||
}
|
||||
|
||||
BounceSound();
|
||||
|
||||
// tell the bots a grenade has bounced
|
||||
CCSPlayer *player = ToCSPlayer(GetThrower());
|
||||
if ( player )
|
||||
{
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "grenade_bounce" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetInt( "userid", player->GetUserID() );
|
||||
event->SetFloat( "x", GetAbsOrigin().x );
|
||||
event->SetFloat( "y", GetAbsOrigin().y );
|
||||
event->SetFloat( "z", GetAbsOrigin().z );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
OnBounced();
|
||||
|
||||
if (m_nBounces > GRENADE_FAILSAFE_MAX_BOUNCES )
|
||||
{
|
||||
//failsafe detonate after 20 bounces
|
||||
SetAbsVelocity( vec3_origin );
|
||||
DetonateOnNextThink();
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nBounces++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::SetupInitialTransmittedGrenadeVelocity( const Vector &velocity )
|
||||
{
|
||||
m_vInitialVelocity = velocity;
|
||||
}
|
||||
|
||||
#define MAX_WATER_SURFACE_DISTANCE 512
|
||||
|
||||
void CBaseCSGrenadeProjectile::Splash()
|
||||
{
|
||||
Vector centerPoint = GetAbsOrigin();
|
||||
Vector normal( 0, 0, 1 );
|
||||
|
||||
// Find our water surface by tracing up till we're out of the water
|
||||
trace_t tr;
|
||||
Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
|
||||
UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// If we didn't start in water, we're above it
|
||||
if ( tr.startsolid == false )
|
||||
{
|
||||
// Look downward to find the surface
|
||||
vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
|
||||
UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// If we hit it, setup the explosion
|
||||
if ( tr.fraction < 1.0f )
|
||||
{
|
||||
centerPoint = tr.endpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
//NOTENOTE: We somehow got into a splash without being near water?
|
||||
Assert( 0 );
|
||||
}
|
||||
}
|
||||
else if ( tr.fractionleftsolid )
|
||||
{
|
||||
// Otherwise we came out of the water at this point
|
||||
centerPoint = centerPoint + (vecTrace * tr.fractionleftsolid);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default values, we're really deep
|
||||
}
|
||||
|
||||
CEffectData data;
|
||||
data.m_vOrigin = centerPoint;
|
||||
data.m_vNormal = normal;
|
||||
data.m_flScale = random->RandomFloat( 1.0f, 2.0f );
|
||||
|
||||
if ( GetWaterType() & CONTENTS_SLIME )
|
||||
{
|
||||
data.m_fFlags |= FX_WATER_IN_SLIME;
|
||||
}
|
||||
|
||||
DispatchEffect( "gunshotsplash", data );
|
||||
}
|
||||
|
||||
// Add a row to ogs for the explosion of this grenade. Damage instances are recorded separately.
|
||||
void CBaseCSGrenadeProjectile::RecordDetonation( void )
|
||||
{
|
||||
// I hate having to call this from so many places since half the grenades override the standard detonate and the rest dont...
|
||||
// If this triggers, it's because either somebody changed the way some grenade code chains to base methods or it's taking an uncommon code path
|
||||
// that needs to be investigated.
|
||||
if ( m_bDetonationRecorded )
|
||||
{
|
||||
Warning( "Detonation of grenade '%s' attempted to record twice!\n", GetDebugName() );
|
||||
Assert( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
CCSPlayer::StartNewBulletGroup();
|
||||
|
||||
SWeaponHitData *pHitData = new SWeaponHitData;
|
||||
if ( pHitData->InitAsGrenadeDetonation( this, CCSPlayer::GetBulletGroup() ) )
|
||||
{
|
||||
CCS_GameStats.RecordWeaponHit( pHitData ); // submission deletes the struct.
|
||||
m_bDetonationRecorded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pHitData;
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::Explode( trace_t *pTrace, int bitsDamageType )
|
||||
{
|
||||
RecordDetonation();
|
||||
BaseClass::Explode( pTrace, bitsDamageType );
|
||||
}
|
||||
|
||||
#endif // !CLIENT_DLL
|
||||
@@ -0,0 +1,122 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASECSGRENADE_PROJECTILE_H
|
||||
#define BASECSGRENADE_PROJECTILE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "basegrenade_shared.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CBaseCSGrenadeProjectile C_BaseCSGrenadeProjectile
|
||||
#else
|
||||
class CCSWeaponInfo;
|
||||
#endif
|
||||
|
||||
|
||||
class CBaseCSGrenadeProjectile : public CBaseGrenade
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBaseCSGrenadeProjectile, CBaseGrenade );
|
||||
DECLARE_NETWORKCLASS();
|
||||
|
||||
virtual void Spawn();
|
||||
//virtual bool IsGrenadeProjectile( void ) { return true; };
|
||||
|
||||
public:
|
||||
|
||||
// This gets sent to the client and placed in the client's interpolation history
|
||||
// so the projectile starts out moving right off the bat.
|
||||
CNetworkVector( m_vInitialVelocity );
|
||||
CNetworkVar( int, m_nBounces );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
CBaseCSGrenadeProjectile() {}
|
||||
CBaseCSGrenadeProjectile( const CBaseCSGrenadeProjectile& ) {}
|
||||
virtual ~CBaseCSGrenadeProjectile();
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual void PostDataUpdate( DataUpdateType_t type );
|
||||
virtual void ClientThink( void );
|
||||
|
||||
void CreateGrenadeTrail( void );
|
||||
|
||||
float m_flSpawnTime;
|
||||
Vector vecLastTrailLinePos;
|
||||
float flNextTrailLineTime;
|
||||
#else
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CBaseCSGrenadeProjectile() : m_pWeaponInfo(NULL), m_bDetonationRecorded(false) {}
|
||||
virtual void PostConstructor( const char *className );
|
||||
virtual ~CBaseCSGrenadeProjectile();
|
||||
|
||||
virtual void Precache();
|
||||
|
||||
virtual int UpdateTransmitState();
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
//Constants for all CS Grenades
|
||||
static inline float GetGrenadeGravity() { return 0.4f; }
|
||||
static inline const float GetGrenadeFriction() { return 0.2f; }
|
||||
static inline const float GetGrenadeElasticity() { return 0.45f; }
|
||||
|
||||
//Think function to emit danger sounds for the AI
|
||||
void DangerSoundThink( void );
|
||||
|
||||
virtual void OnBounced( void ) {}
|
||||
virtual void Explode( trace_t *pTrace, int bitsDamageType );
|
||||
|
||||
virtual float GetShakeAmplitude( void ) { return 0.0f; }
|
||||
virtual void Splash();
|
||||
|
||||
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_EXPLOSIVE; }
|
||||
|
||||
// Specify what velocity we want the grenade to have on the client immediately.
|
||||
// Without this, the entity wouldn't have an interpolation history initially, so it would
|
||||
// sit still until it had gotten a few updates from the server.
|
||||
void SetupInitialTransmittedGrenadeVelocity( const Vector &velocity );
|
||||
|
||||
// [jpaquin] give grenade projectiles a link back to the type
|
||||
// of weapon they are
|
||||
const CCSWeaponInfo *m_pWeaponInfo;
|
||||
|
||||
enum
|
||||
{
|
||||
GRENADE_EXTINGUISHED_INFERNO = 1 << 0,
|
||||
};
|
||||
uint8 m_unOGSExtraFlags; // Misc flags about the grenade's effect in game to report to ogs
|
||||
|
||||
EHANDLE m_lastHitPlayer;
|
||||
|
||||
void DetonateOnNextThink( void ) { m_flDetonateTime = 0.0f; }
|
||||
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
//Set the time to detonate ( now + timer )
|
||||
void SetDetonateTimerLength( float timer );
|
||||
|
||||
// Called when this grenade explodes. If your decended class overides some part of the detonation process
|
||||
// and prevents detonate from being called, you need to call this to make ogs still records it.
|
||||
void RecordDetonation( void );
|
||||
bool m_bDetonationRecorded;
|
||||
|
||||
private:
|
||||
|
||||
//Custom collision to allow for constant elasticity on hit surfaces
|
||||
virtual void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity );
|
||||
|
||||
float m_flDetonateTime;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // BASECSGRENADE_PROJECTILE_H
|
||||
@@ -0,0 +1,116 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), Leon Hartwig, 2003
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_shareddefs.h"
|
||||
|
||||
#include "basegrenade_shared.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_util.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
/// @todo Remove this nasty hack - CreateFakeClient() calls CBot::Spawn, which needs the profile and team
|
||||
const BotProfile *g_botInitProfile = NULL;
|
||||
int g_botInitTeam = 0;
|
||||
|
||||
//
|
||||
// NOTE: Because CBot had to be templatized, the code was moved into bot.h
|
||||
//
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
ActiveGrenade::ActiveGrenade( CBaseGrenade *grenadeEntity )
|
||||
{
|
||||
m_entity = grenadeEntity;
|
||||
m_detonationPosition = grenadeEntity->GetAbsOrigin();
|
||||
m_dieTimestamp = 0.0f;
|
||||
|
||||
m_isSmoke = false;
|
||||
m_isFlashbang = false;
|
||||
m_isMolotov = false;
|
||||
m_isDecoy = false;
|
||||
|
||||
switch ( grenadeEntity->GetGrenadeType() )
|
||||
{
|
||||
case GRENADE_TYPE_EXPLOSIVE: m_radius = HEGrenadeRadius; break;
|
||||
case GRENADE_TYPE_FLASH: m_radius = FlashbangGrenadeRadius; m_isFlashbang = true; break;
|
||||
case GRENADE_TYPE_FIRE: m_radius = MolotovGrenadeRadius; m_isMolotov = true; break;
|
||||
case GRENADE_TYPE_DECOY: m_radius = DecoyGrenadeRadius; m_isDecoy = true; break;
|
||||
case GRENADE_TYPE_SMOKE: m_radius = SmokeGrenadeRadius; m_isSmoke = true; break;
|
||||
case GRENADE_TYPE_SENSOR: m_radius = MolotovGrenadeRadius; m_isSensor = true; break;
|
||||
default:
|
||||
AssertMsg( 0, "Invalid grenade type!\n" );
|
||||
m_radius = HEGrenadeRadius;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Called when the grenade in the world goes away
|
||||
*/
|
||||
void ActiveGrenade::OnEntityGone( void )
|
||||
{
|
||||
if (m_isSmoke)
|
||||
{
|
||||
// smoke lingers after grenade is gone
|
||||
const float smokeLingerTime = 4.0f;
|
||||
m_dieTimestamp = gpGlobals->curtime + smokeLingerTime;
|
||||
}
|
||||
|
||||
m_entity = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void ActiveGrenade::Update( void )
|
||||
{
|
||||
if (m_entity != NULL)
|
||||
{
|
||||
m_detonationPosition = m_entity->GetAbsOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this grenade is valid
|
||||
*/
|
||||
bool ActiveGrenade::IsValid( void ) const
|
||||
{
|
||||
if ( m_isSmoke )
|
||||
{
|
||||
if ( m_entity == NULL && gpGlobals->curtime > m_dieTimestamp )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_entity == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const Vector &ActiveGrenade::GetPosition( void ) const
|
||||
{
|
||||
// smoke grenades can vanish before the smoke itself does - refer to the detonation position
|
||||
if (m_entity == NULL)
|
||||
return GetDetonationPosition();
|
||||
|
||||
return m_entity->GetAbsOrigin();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Matthew D. Campbell (matt@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef BOT_CONSTANTS_H
|
||||
#define BOT_CONSTANTS_H
|
||||
|
||||
/// version number is MAJOR.MINOR
|
||||
#define BOT_VERSION_MAJOR 1
|
||||
#define BOT_VERSION_MINOR 50
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Difficulty levels
|
||||
*/
|
||||
enum BotDifficultyType
|
||||
{
|
||||
BOT_EASY = 0,
|
||||
BOT_NORMAL = 1,
|
||||
BOT_HARD = 2,
|
||||
BOT_EXPERT = 3,
|
||||
|
||||
NUM_DIFFICULTY_LEVELS
|
||||
};
|
||||
|
||||
#ifdef DEFINE_DIFFICULTY_NAMES
|
||||
char *BotDifficultyName[] =
|
||||
{
|
||||
"EASY", "NORMAL", "HARD", "EXPERT", NULL
|
||||
};
|
||||
#else
|
||||
extern char *BotDifficultyName[];
|
||||
#endif
|
||||
|
||||
namespace BotProfileInputDevice
|
||||
{
|
||||
enum Device
|
||||
{
|
||||
GAMEPAD = 0,
|
||||
KB_MOUSE = 1,
|
||||
PS3_MOVE = 2,
|
||||
HYDRA = 3,
|
||||
SHARPSHOOTER = 4,
|
||||
|
||||
COUNT, // Auto list counter
|
||||
FORCE_INT32 = 0x7FFFFFFF // Force the typedef to be int32
|
||||
};
|
||||
};
|
||||
typedef BotProfileInputDevice::Device BotProfileDevice_t;
|
||||
|
||||
|
||||
|
||||
#endif // BOT_CONSTANTS_H
|
||||
@@ -0,0 +1,496 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// bot_hide.cpp
|
||||
// Mechanisms for using Hiding Spots in the Navigation Mesh
|
||||
// Author: Michael Booth, 2003-2004
|
||||
|
||||
#include "cbase.h"
|
||||
#include "bot.h"
|
||||
#include "cs_nav_pathfind.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* If a player is at the given spot, return true
|
||||
*/
|
||||
bool IsSpotOccupied( CBaseEntity *me, const Vector &pos )
|
||||
{
|
||||
const float closeRange = 75.0f; // 50
|
||||
|
||||
// is there a player in this spot
|
||||
float range;
|
||||
CBasePlayer *player = UTIL_GetClosestPlayer( pos, &range );
|
||||
|
||||
if (player != me)
|
||||
{
|
||||
if (player && range < closeRange)
|
||||
return true;
|
||||
}
|
||||
|
||||
// is there is a hostage in this spot
|
||||
// BOTPORT: Implement hostage manager
|
||||
/*
|
||||
if (g_pHostages)
|
||||
{
|
||||
CHostage *hostage = g_pHostages->GetClosestHostage( *pos, &range );
|
||||
if (hostage && hostage != me && range < closeRange)
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
class CollectHidingSpotsFunctor
|
||||
{
|
||||
public:
|
||||
CollectHidingSpotsFunctor( CBaseEntity *me, const Vector &origin, float range, int flags, Place place = UNDEFINED_PLACE ) : m_origin( origin )
|
||||
{
|
||||
m_me = me;
|
||||
m_count = 0;
|
||||
m_range = range;
|
||||
m_flags = (unsigned char)flags;
|
||||
m_place = place;
|
||||
m_totalWeight = 0;
|
||||
}
|
||||
|
||||
enum { MAX_SPOTS = 256 };
|
||||
|
||||
bool operator() ( CNavArea *area )
|
||||
{
|
||||
// if a place is specified, only consider hiding spots from areas in that place
|
||||
if (m_place != UNDEFINED_PLACE && area->GetPlace() != m_place)
|
||||
return true;
|
||||
|
||||
// collect all the hiding spots in this area
|
||||
const HidingSpotVector *pSpots = area->GetHidingSpots();
|
||||
|
||||
FOR_EACH_VEC( (*pSpots), it )
|
||||
{
|
||||
const HidingSpot *spot = (*pSpots)[ it ];
|
||||
|
||||
// if we've filled up, stop searching
|
||||
if (m_count == MAX_SPOTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure hiding spot is in range
|
||||
if (m_range > 0.0f)
|
||||
{
|
||||
if ((spot->GetPosition() - m_origin).IsLengthGreaterThan( m_range ))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if a Player is using this hiding spot, don't consider it
|
||||
if (IsSpotOccupied( m_me, spot->GetPosition() ))
|
||||
{
|
||||
// player is in hiding spot
|
||||
/// @todo Check if player is moving or sitting still
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spot->GetArea() && (spot->GetArea()->GetAttributes() & NAV_MESH_DONT_HIDE))
|
||||
{
|
||||
// the area has been marked as DONT_HIDE since the last analysis, so let's ignore it
|
||||
continue;
|
||||
}
|
||||
|
||||
// only collect hiding spots with matching flags
|
||||
if (m_flags & spot->GetFlags())
|
||||
{
|
||||
m_hidingSpot[ m_count ] = &spot->GetPosition();
|
||||
m_hidingSpotWeight[ m_count ] = m_totalWeight;
|
||||
|
||||
// if it's an 'avoid' area, give it a low weight
|
||||
if ( spot->GetArea() && ( spot->GetArea()->GetAttributes() & NAV_MESH_AVOID ) )
|
||||
{
|
||||
m_totalWeight += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_totalWeight += 2;
|
||||
}
|
||||
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
|
||||
return (m_count < MAX_SPOTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the spot at index "i"
|
||||
*/
|
||||
void RemoveSpot( int i )
|
||||
{
|
||||
if (m_count == 0)
|
||||
return;
|
||||
|
||||
for( int j=i+1; j<m_count; ++j )
|
||||
m_hidingSpot[j-1] = m_hidingSpot[j];
|
||||
|
||||
--m_count;
|
||||
}
|
||||
|
||||
|
||||
int GetRandomHidingSpot( void )
|
||||
{
|
||||
int weight = RandomInt( 0, m_totalWeight-1 );
|
||||
for ( int i=0; i<m_count-1; ++i )
|
||||
{
|
||||
// if the next spot's starting weight is over the target weight, this spot is the one
|
||||
if ( m_hidingSpotWeight[i+1] >= weight )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't find any, it's the last one
|
||||
return m_count - 1;
|
||||
}
|
||||
|
||||
CBaseEntity *m_me;
|
||||
const Vector &m_origin;
|
||||
float m_range;
|
||||
|
||||
const Vector *m_hidingSpot[ MAX_SPOTS ];
|
||||
int m_hidingSpotWeight[ MAX_SPOTS ];
|
||||
int m_totalWeight;
|
||||
int m_count;
|
||||
|
||||
unsigned char m_flags;
|
||||
|
||||
Place m_place;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do a breadth-first search to find a nearby hiding spot and return it.
|
||||
* Don't pick a hiding spot that a Player is currently occupying.
|
||||
* @todo Clean up this mess
|
||||
*/
|
||||
const Vector *FindNearbyHidingSpot( CBaseEntity *me, const Vector &pos, float maxRange, bool isSniper, bool useNearest )
|
||||
{
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( pos );
|
||||
if (startArea == NULL)
|
||||
return NULL;
|
||||
|
||||
// collect set of nearby hiding spots
|
||||
if (isSniper)
|
||||
{
|
||||
CollectHidingSpotsFunctor collector( me, pos, maxRange, HidingSpot::IDEAL_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, pos, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = collector.GetRandomHidingSpot();
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no ideal sniping spots, look for "good" sniping spots
|
||||
CollectHidingSpotsFunctor collector( me, pos, maxRange, HidingSpot::GOOD_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, pos, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = collector.GetRandomHidingSpot();
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
// no sniping spots at all.. fall through and pick a normal hiding spot
|
||||
}
|
||||
}
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectHidingSpotsFunctor collector( me, pos, maxRange, HidingSpot::IN_COVER );
|
||||
SearchSurroundingAreas( startArea, pos, collector, maxRange );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
{
|
||||
// no hiding spots at all - if we're not a sniper, try to find a sniper spot to use instead
|
||||
if (!isSniper)
|
||||
{
|
||||
return FindNearbyHidingSpot( me, pos, maxRange, true, useNearest );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (useNearest)
|
||||
{
|
||||
// return closest hiding spot
|
||||
const Vector *closest = NULL;
|
||||
float closeRangeSq = 9999999999.9f;
|
||||
for( int i=0; i<collector.m_count; ++i )
|
||||
{
|
||||
float rangeSq = (*collector.m_hidingSpot[i] - pos).LengthSqr();
|
||||
if (rangeSq < closeRangeSq)
|
||||
{
|
||||
closeRangeSq = rangeSq;
|
||||
closest = collector.m_hidingSpot[i];
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
// select a hiding spot at random
|
||||
int which = collector.GetRandomHidingSpot();
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Select a random hiding spot among the nav areas that are tagged with the given place
|
||||
*/
|
||||
const Vector *FindRandomHidingSpot( CBaseEntity *me, Place place, bool isSniper )
|
||||
{
|
||||
// collect set of nearby hiding spots
|
||||
if (isSniper)
|
||||
{
|
||||
CollectHidingSpotsFunctor collector( me, me->GetAbsOrigin(), -1.0f, HidingSpot::IDEAL_SNIPER_SPOT, place );
|
||||
TheNavMesh->ForAllAreas( collector );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no ideal sniping spots, look for "good" sniping spots
|
||||
CollectHidingSpotsFunctor collector( me, me->GetAbsOrigin(), -1.0f, HidingSpot::GOOD_SNIPER_SPOT, place );
|
||||
TheNavMesh->ForAllAreas( collector );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
// no sniping spots at all.. fall through and pick a normal hiding spot
|
||||
}
|
||||
}
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectHidingSpotsFunctor collector( me, me->GetAbsOrigin(), -1.0f, HidingSpot::IN_COVER, place );
|
||||
TheNavMesh->ForAllAreas( collector );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
return NULL;
|
||||
|
||||
// select a hiding spot at random
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Select a nearby retreat spot.
|
||||
* Don't pick a hiding spot that a Player is currently occupying.
|
||||
* If "avoidTeam" is nonzero, avoid getting close to members of that team.
|
||||
*/
|
||||
const Vector *FindNearbyRetreatSpot( CBaseEntity *me, const Vector &start, float maxRange, int avoidTeam )
|
||||
{
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( start );
|
||||
if (startArea == NULL)
|
||||
return NULL;
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectHidingSpotsFunctor collector( me, start, maxRange, HidingSpot::IN_COVER );
|
||||
SearchSurroundingAreas( startArea, start, collector, maxRange );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
return NULL;
|
||||
|
||||
// find the closest unoccupied hiding spot that crosses the least lines of fire and has the best cover
|
||||
for( int i=0; i<collector.m_count; ++i )
|
||||
{
|
||||
// check if we would have to cross a line of fire to reach this hiding spot
|
||||
if (IsCrossingLineOfFire( start, *collector.m_hidingSpot[i], me ))
|
||||
{
|
||||
collector.RemoveSpot( i );
|
||||
|
||||
// back up a step, so iteration won't skip a spot
|
||||
--i;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if there is someone on the avoidTeam near this hiding spot
|
||||
if (avoidTeam)
|
||||
{
|
||||
float range;
|
||||
if (UTIL_GetClosestPlayer( *collector.m_hidingSpot[i], avoidTeam, &range ))
|
||||
{
|
||||
const float dangerRange = 150.0f;
|
||||
if (range < dangerRange)
|
||||
{
|
||||
// there is an avoidable player too near this spot - remove it
|
||||
collector.RemoveSpot( i );
|
||||
|
||||
// back up a step, so iteration won't skip a spot
|
||||
--i;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (collector.m_count <= 0)
|
||||
return NULL;
|
||||
|
||||
// all remaining spots are ok - pick one at random
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Functor to collect all hiding spots in range that we can reach before the enemy arrives.
|
||||
* NOTE: This only works for the initial rush.
|
||||
*/
|
||||
class CollectArriveFirstSpotsFunctor
|
||||
{
|
||||
public:
|
||||
CollectArriveFirstSpotsFunctor( CBaseEntity *me, const Vector &searchOrigin, float enemyArriveTime, float range, int flags ) : m_searchOrigin( searchOrigin )
|
||||
{
|
||||
m_me = me;
|
||||
m_count = 0;
|
||||
m_range = range;
|
||||
m_flags = (unsigned char)flags;
|
||||
m_enemyArriveTime = enemyArriveTime;
|
||||
}
|
||||
|
||||
enum { MAX_SPOTS = 256 };
|
||||
|
||||
bool operator() ( CNavArea *area )
|
||||
{
|
||||
const HidingSpotVector *pSpots = area->GetHidingSpots();
|
||||
|
||||
FOR_EACH_VEC( (*pSpots), it )
|
||||
{
|
||||
const HidingSpot *spot = (*pSpots)[ it ];
|
||||
|
||||
// make sure hiding spot is in range
|
||||
if (m_range > 0.0f)
|
||||
{
|
||||
if ((spot->GetPosition() - m_searchOrigin).IsLengthGreaterThan( m_range ))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if a Player is using this hiding spot, don't consider it
|
||||
if (IsSpotOccupied( m_me, spot->GetPosition() ))
|
||||
{
|
||||
// player is in hiding spot
|
||||
/// @todo Check if player is moving or sitting still
|
||||
continue;
|
||||
}
|
||||
|
||||
// only collect hiding spots with matching flags
|
||||
if (!(m_flags & spot->GetFlags()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// only collect this hiding spot if we can reach it before the enemy arrives
|
||||
// NOTE: This assumes the area is fairly small and the difference of moving to the corner vs the center is small
|
||||
const float settleTime = 1.0f;
|
||||
|
||||
if(!spot->GetArea())
|
||||
{
|
||||
AssertMsg(false, "Check console spew for Hiding Spot off the Nav Mesh errors.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spot->GetArea()->GetEarliestOccupyTime( m_me->GetTeamNumber() ) + settleTime < m_enemyArriveTime)
|
||||
{
|
||||
m_hidingSpot[ m_count++ ] = spot;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've filled up, stop searching
|
||||
if (m_count == MAX_SPOTS)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CBaseEntity *m_me;
|
||||
const Vector &m_searchOrigin;
|
||||
|
||||
float m_range;
|
||||
float m_enemyArriveTime;
|
||||
unsigned char m_flags;
|
||||
|
||||
const HidingSpot *m_hidingSpot[ MAX_SPOTS ];
|
||||
int m_count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Select a hiding spot that we can reach before the enemy arrives.
|
||||
* NOTE: This only works for the initial rush.
|
||||
*/
|
||||
const HidingSpot *FindInitialEncounterSpot( CBaseEntity *me, const Vector &searchOrigin, float enemyArriveTime, float maxRange, bool isSniper )
|
||||
{
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( searchOrigin );
|
||||
if (startArea == NULL)
|
||||
return NULL;
|
||||
|
||||
// collect set of nearby hiding spots
|
||||
if (isSniper)
|
||||
{
|
||||
CollectArriveFirstSpotsFunctor collector( me, searchOrigin, enemyArriveTime, maxRange, HidingSpot::IDEAL_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, searchOrigin, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no ideal sniping spots, look for "good" sniping spots
|
||||
CollectArriveFirstSpotsFunctor collector( me, searchOrigin, enemyArriveTime, maxRange, HidingSpot::GOOD_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, searchOrigin, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
// no sniping spots at all.. fall through and pick a normal hiding spot
|
||||
}
|
||||
}
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectArriveFirstSpotsFunctor collector( me, searchOrigin, enemyArriveTime, maxRange, HidingSpot::IN_COVER | HidingSpot::EXPOSED );
|
||||
SearchSurroundingAreas( startArea, searchOrigin, collector, maxRange );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
return NULL;
|
||||
|
||||
// select a hiding spot at random
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_manager.h"
|
||||
#include "nav_area.h"
|
||||
#include "bot_util.h"
|
||||
#include "basegrenade_shared.h"
|
||||
|
||||
#include "cs_bot.h"
|
||||
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
float g_BotUpkeepInterval = 0.0f;
|
||||
float g_BotUpdateInterval = 0.0f;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
CBotManager::CBotManager()
|
||||
{
|
||||
InitBotTrig();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
CBotManager::~CBotManager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Invoked when the round is restarting
|
||||
*/
|
||||
void CBotManager::RestartRound( void )
|
||||
{
|
||||
DestroyAllGrenades();
|
||||
ClearDebugMessages();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Invoked at the start of each frame
|
||||
*/
|
||||
void CBotManager::StartFrame( void )
|
||||
{
|
||||
VPROF_BUDGET( "CBotManager::StartFrame", VPROF_BUDGETGROUP_NPCS );
|
||||
|
||||
ValidateActiveGrenades();
|
||||
|
||||
// debug smoke grenade visualization
|
||||
if (cv_bot_debug.GetInt() == 5)
|
||||
{
|
||||
Vector edge, lastEdge;
|
||||
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
const Vector &pos = ag->GetDetonationPosition();
|
||||
|
||||
UTIL_DrawBeamPoints( pos, pos + Vector( 0, 0, 50 ), 1, 255, 100, 0 );
|
||||
|
||||
lastEdge = Vector( ag->GetRadius() + pos.x, pos.y, pos.z );
|
||||
float angle;
|
||||
for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
|
||||
{
|
||||
edge.x = ag->GetRadius() * BotCOS( angle ) + pos.x;
|
||||
edge.y = pos.y;
|
||||
edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
|
||||
|
||||
UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
|
||||
|
||||
lastEdge = edge;
|
||||
}
|
||||
|
||||
lastEdge = Vector( pos.x, ag->GetRadius() + pos.y, pos.z );
|
||||
for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
|
||||
{
|
||||
edge.x = pos.x;
|
||||
edge.y = ag->GetRadius() * BotCOS( angle ) + pos.y;
|
||||
edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
|
||||
|
||||
UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
|
||||
|
||||
lastEdge = edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set frame duration
|
||||
g_BotUpkeepInterval = m_frameTimer.GetElapsedTime();
|
||||
m_frameTimer.Start();
|
||||
|
||||
g_BotUpdateInterval = (g_BotUpdateSkipCount+1) * g_BotUpkeepInterval;
|
||||
|
||||
//
|
||||
// Process each active bot
|
||||
//
|
||||
for( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
// Hack for now so the temp bot code works. The temp bots are very useful for debugging
|
||||
// because they can be setup to mimic the player's usercmds.
|
||||
if (player->IsBot() && IsEntityValid( player ) )
|
||||
{
|
||||
// EVIL: Messes up vtables
|
||||
//CBot< CBasePlayer > *bot = static_cast< CBot< CBasePlayer > * >( player );
|
||||
CCSBot *bot = dynamic_cast< CCSBot * >( player );
|
||||
|
||||
if ( bot )
|
||||
{
|
||||
{
|
||||
SNPROF("Upkeep");
|
||||
bot->Upkeep();
|
||||
}
|
||||
|
||||
if (((gpGlobals->tickcount + bot->entindex()) % g_BotUpdateSkipCount) == 0)
|
||||
{
|
||||
{
|
||||
SNPROF("ResetCommand");
|
||||
bot->ResetCommand();
|
||||
}
|
||||
|
||||
{
|
||||
SNPROF("Bot Update");
|
||||
bot->Update();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
SNPROF("UpdatePlayer");
|
||||
bot->UpdatePlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Add an active grenade to the bot's awareness
|
||||
*/
|
||||
void CBotManager::AddGrenade( CBaseGrenade *grenade )
|
||||
{
|
||||
ActiveGrenade *ag = new ActiveGrenade( grenade );
|
||||
m_activeGrenadeList.AddToTail( ag );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The grenade entity in the world is going away
|
||||
*/
|
||||
void CBotManager::RemoveGrenade( CBaseGrenade *grenade )
|
||||
{
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
if (ag->IsEntity( grenade ))
|
||||
{
|
||||
ag->OnEntityGone();
|
||||
m_activeGrenadeList.Remove( it );
|
||||
delete ag;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The grenade entity has changed its radius
|
||||
*/
|
||||
void CBotManager::SetGrenadeRadius( CBaseGrenade *grenade, float radius )
|
||||
{
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
if (ag->IsEntity( grenade ))
|
||||
{
|
||||
ag->SetRadius( radius );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Destroy any invalid active grenades
|
||||
*/
|
||||
void CBotManager::ValidateActiveGrenades( void )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
|
||||
// lazy validation
|
||||
if (!ag->IsValid())
|
||||
{
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ag->Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void CBotManager::DestroyAllGrenades( void )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while ( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[it];
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
}
|
||||
|
||||
m_activeGrenadeList.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if position is inside a smoke cloud
|
||||
*/
|
||||
bool CBotManager::IsInsideSmokeCloud( const Vector *pos, float radius )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
|
||||
// lazy validation
|
||||
if (!ag->IsValid())
|
||||
{
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ag->IsSmoke())
|
||||
{
|
||||
const Vector &smokeOrigin = ag->GetDetonationPosition();
|
||||
|
||||
if ((smokeOrigin - *pos).IsLengthLessThan( ag->GetRadius() + radius ))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if line intersects smoke volume
|
||||
* Determine the length of the line of sight covered by each smoke cloud,
|
||||
* and sum them (overlap is additive for obstruction).
|
||||
* If the overlap exceeds the threshold, the bot can't see through.
|
||||
*/
|
||||
bool CBotManager::IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat )
|
||||
{
|
||||
VPROF_BUDGET( "CBotManager::IsLineBlockedBySmoke", VPROF_BUDGETGROUP_NPCS );
|
||||
|
||||
float totalSmokedLength = 0.0f; // distance along line of sight covered by smoke
|
||||
|
||||
// compute unit vector and length of line of sight segment
|
||||
//Vector sightDir = to - from;
|
||||
//float sightLength = sightDir.NormalizeInPlace();
|
||||
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
const float smokeRadiusSq = ag->GetRadius() * ag->GetRadius() * grenadeBloat * grenadeBloat;
|
||||
|
||||
if ( ag->IsSmoke() && CSGameRules() )
|
||||
{
|
||||
float flLengthAdd = CSGameRules()->CheckTotalSmokedLength( smokeRadiusSq, ag->GetDetonationPosition(), from, to );
|
||||
// get the totalSmokedLength and check to see if the line starts or stops in smoke. If it does this will return -1 and we should just bail early
|
||||
if ( flLengthAdd == -1 )
|
||||
return true;
|
||||
|
||||
totalSmokedLength += flLengthAdd;
|
||||
}
|
||||
}
|
||||
|
||||
// define how much smoke a bot can see thru
|
||||
const float maxSmokedLength = 0.7f * SmokeGrenadeRadius;
|
||||
|
||||
// return true if the total length of smoke-covered line-of-sight is too much
|
||||
return (totalSmokedLength > maxSmokedLength);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void CBotManager::ClearDebugMessages( void )
|
||||
{
|
||||
m_debugMessageCount = 0;
|
||||
m_currentDebugMessage = -1;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Add a new debug message to the message history
|
||||
*/
|
||||
void CBotManager::AddDebugMessage( const char *msg )
|
||||
{
|
||||
if (++m_currentDebugMessage >= MAX_DBG_MSGS)
|
||||
{
|
||||
m_currentDebugMessage = 0;
|
||||
}
|
||||
|
||||
if (m_debugMessageCount < MAX_DBG_MSGS)
|
||||
{
|
||||
++m_debugMessageCount;
|
||||
}
|
||||
|
||||
Q_strncpy( m_debugMessage[ m_currentDebugMessage ].m_string, msg, MAX_DBG_MSG_SIZE );
|
||||
m_debugMessage[ m_currentDebugMessage ].m_age.Start();
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef BASE_CONTROL_H
|
||||
#define BASE_CONTROL_H
|
||||
|
||||
#pragma warning( disable : 4530 ) // STL uses exceptions, but we are not compiling with them - ignore warning
|
||||
|
||||
extern float g_BotUpkeepInterval; ///< duration between bot upkeeps
|
||||
extern float g_BotUpdateInterval; ///< duration between bot updates
|
||||
const int g_BotUpdateSkipCount = 2; ///< number of upkeep periods to skip update
|
||||
|
||||
class CNavArea;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
class CBaseGrenade;
|
||||
|
||||
/**
|
||||
* An ActiveGrenade is a representation of a grenade in the world
|
||||
* NOTE: Currently only used for smoke grenade line-of-sight testing
|
||||
* @todo Use system allow bots to avoid HE and Flashbangs
|
||||
*/
|
||||
class ActiveGrenade
|
||||
{
|
||||
public:
|
||||
ActiveGrenade( CBaseGrenade *grenadeEntity );
|
||||
|
||||
void OnEntityGone( void ); ///< called when the grenade in the world goes away
|
||||
void Update( void ); ///< called every frame
|
||||
bool IsValid( void ) const ; ///< return true if this grenade is valid
|
||||
|
||||
bool IsEntity( CBaseGrenade *grenade ) const { return (grenade == m_entity) ? true : false; }
|
||||
CBaseGrenade *GetEntity( void ) const { return m_entity; }
|
||||
|
||||
const Vector &GetDetonationPosition( void ) const { return m_detonationPosition; }
|
||||
const Vector &GetPosition( void ) const;
|
||||
bool IsSmoke( void ) const { return m_isSmoke; }
|
||||
bool IsFlashbang( void ) const { return m_isFlashbang; }
|
||||
bool IsMolotov( void ) const { return m_isMolotov; }
|
||||
bool IsDecoy( void ) const { return m_isDecoy; }
|
||||
bool IsSensor( void ) const { return m_isSensor; }
|
||||
CBaseGrenade *GetGrenade( void ) { return m_entity; }
|
||||
float GetRadius( void ) const { return m_radius; }
|
||||
void SetRadius( float radius ) { m_radius = radius; }
|
||||
|
||||
private:
|
||||
CBaseGrenade *m_entity; ///< the entity
|
||||
Vector m_detonationPosition; ///< the location where the grenade detonated (smoke)
|
||||
float m_dieTimestamp; ///< time this should go away after m_entity is NULL
|
||||
bool m_isSmoke; ///< true if this is a smoke grenade
|
||||
bool m_isFlashbang; ///< true if this is a flashbang grenade
|
||||
bool m_isMolotov; ///< true if this is a molotov grenade
|
||||
bool m_isDecoy; ///< true if this is a decoy grenade
|
||||
bool m_isSensor; ///< true if this is a sensor grenade
|
||||
float m_radius;
|
||||
};
|
||||
|
||||
typedef CUtlLinkedList<ActiveGrenade *> ActiveGrenadeList;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* This class manages all active bots, propagating events to them and updating them.
|
||||
*/
|
||||
class CBotManager
|
||||
{
|
||||
public:
|
||||
CBotManager();
|
||||
virtual ~CBotManager();
|
||||
|
||||
CBasePlayer *AllocateAndBindBotEntity( edict_t *ed ); ///< allocate the appropriate entity for the bot and bind it to the given edict
|
||||
virtual CBasePlayer *AllocateBotEntity( void ) = 0; ///< factory method to allocate the appropriate entity for the bot
|
||||
|
||||
virtual void ClientDisconnect( CBaseEntity *entity ) = 0;
|
||||
virtual bool ClientCommand( CBasePlayer *player, const CCommand &args ) = 0;
|
||||
|
||||
virtual void ServerActivate( void ) = 0;
|
||||
virtual void ServerDeactivate( void ) = 0;
|
||||
virtual bool ServerCommand( const char * pcmd ) = 0;
|
||||
|
||||
virtual void RestartRound( void ); ///< (EXTEND) invoked when a new round begins
|
||||
virtual void StartFrame( void ); ///< (EXTEND) called each frame
|
||||
|
||||
virtual unsigned int GetPlayerPriority( CBasePlayer *player ) const = 0; ///< return priority of player (0 = max pri)
|
||||
|
||||
|
||||
void AddGrenade( CBaseGrenade *grenade ); ///< add an active grenade to the bot's awareness
|
||||
void RemoveGrenade( CBaseGrenade *grenade ); ///< the grenade entity in the world is going away
|
||||
void SetGrenadeRadius( CBaseGrenade *grenade, float radius ); ///< the radius of the grenade entity (or associated smoke cloud)
|
||||
void ValidateActiveGrenades( void ); ///< destroy any invalid active grenades
|
||||
void DestroyAllGrenades( void );
|
||||
bool IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat = 1.0f ); ///< return true if line intersects smoke volume, with grenade radius increased by the grenadeBloat factor
|
||||
bool IsInsideSmokeCloud( const Vector *pos, float radius ); ///< return true if sphere at position overlaps a smoke cloud
|
||||
|
||||
//
|
||||
// Invoke functor on all active grenades.
|
||||
// If any functor call return false, return false. Otherwise, return true.
|
||||
//
|
||||
template < typename T >
|
||||
bool ForEachGrenade( T &func )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
|
||||
// lazy validation
|
||||
if (!ag->IsValid())
|
||||
{
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (func( ag ) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum { MAX_DBG_MSG_SIZE = 1024 };
|
||||
struct DebugMessage
|
||||
{
|
||||
char m_string[ MAX_DBG_MSG_SIZE ];
|
||||
IntervalTimer m_age;
|
||||
};
|
||||
|
||||
// debug message history -------------------------------------------------------------------------------
|
||||
int GetDebugMessageCount( void ) const; ///< get number of debug messages in history
|
||||
const DebugMessage *GetDebugMessage( int which = 0 ) const; ///< return the debug message emitted by the bot (0 = most recent)
|
||||
void ClearDebugMessages( void );
|
||||
void AddDebugMessage( const char *msg );
|
||||
|
||||
ActiveGrenadeList m_activeGrenadeList;///< the list of active grenades the bots are aware of
|
||||
|
||||
private:
|
||||
|
||||
enum { MAX_DBG_MSGS = 6 };
|
||||
DebugMessage m_debugMessage[ MAX_DBG_MSGS ]; ///< debug message history
|
||||
int m_debugMessageCount;
|
||||
int m_currentDebugMessage;
|
||||
|
||||
IntervalTimer m_frameTimer; ///< for measuring each frame's duration
|
||||
};
|
||||
|
||||
|
||||
inline CBasePlayer *CBotManager::AllocateAndBindBotEntity( edict_t *ed )
|
||||
{
|
||||
CBasePlayer::s_PlayerEdict = ed;
|
||||
return AllocateBotEntity();
|
||||
}
|
||||
|
||||
inline int CBotManager::GetDebugMessageCount( void ) const
|
||||
{
|
||||
return m_debugMessageCount;
|
||||
}
|
||||
|
||||
inline const CBotManager::DebugMessage *CBotManager::GetDebugMessage( int which ) const
|
||||
{
|
||||
if (which >= m_debugMessageCount)
|
||||
return NULL;
|
||||
|
||||
int i = m_currentDebugMessage - which;
|
||||
if (i < 0)
|
||||
i += MAX_DBG_MSGS;
|
||||
|
||||
return &m_debugMessage[ i ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// global singleton to create and control bots
|
||||
extern CBotManager *TheBots;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,852 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#pragma warning( disable : 4530 ) // STL uses exceptions, but we are not compiling with them - ignore warning
|
||||
|
||||
#define DEFINE_DIFFICULTY_NAMES
|
||||
#include "bot_profile.h"
|
||||
#include "shared_util.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_util.h"
|
||||
#include "cs_bot.h" // BOTPORT: Remove this CS dependency
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
BotProfileManager *TheBotProfiles = NULL;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Generates a filename-decorated skin name
|
||||
*/
|
||||
static const char * GetDecoratedSkinName( const char *name, const char *filename )
|
||||
{
|
||||
const int BufLen = _MAX_PATH + 64;
|
||||
static char buf[BufLen];
|
||||
Q_snprintf( buf, sizeof( buf ), "%s/%s", filename, name );
|
||||
return buf;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const char* BotProfile::GetWeaponPreferenceAsString( int i ) const
|
||||
{
|
||||
if ( i < 0 || i >= m_weaponPreferenceCount )
|
||||
return NULL;
|
||||
|
||||
return WeaponIDToAlias( m_weaponPreference[ i ] );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile has a primary weapon preference
|
||||
*/
|
||||
bool BotProfile::HasPrimaryPreference() const
|
||||
{
|
||||
for ( int i=0; i < m_weaponPreferenceCount; ++i )
|
||||
{
|
||||
if ( IsPrimaryWeapon( m_weaponPreference[i] ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile has a pistol weapon preference
|
||||
*/
|
||||
bool BotProfile::HasPistolPreference() const
|
||||
{
|
||||
for ( int i=0; i < m_weaponPreferenceCount; ++i )
|
||||
if ( IsSecondaryWeapon( m_weaponPreference[i] ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile is valid for the specified team
|
||||
*/
|
||||
bool BotProfile::IsValidForTeam( int team ) const
|
||||
{
|
||||
return ( team == TEAM_UNASSIGNED || m_teams == TEAM_UNASSIGNED || team == m_teams );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile inherits from the specified template
|
||||
*/
|
||||
bool BotProfile::InheritsFrom( const char *name ) const
|
||||
{
|
||||
if ( WildcardMatch( name, GetName() ) )
|
||||
return true;
|
||||
|
||||
for ( int i=0; i<m_templates.Count(); ++i )
|
||||
{
|
||||
const BotProfile *queryTemplate = m_templates[i];
|
||||
if ( queryTemplate && queryTemplate->InheritsFrom( name ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BotProfile::SetName( const char* name )
|
||||
{
|
||||
if ( name )
|
||||
{
|
||||
if ( m_name )
|
||||
{
|
||||
// Delete the current name if it exists
|
||||
delete [] m_name;
|
||||
}
|
||||
|
||||
m_name = CloneString( name );
|
||||
}
|
||||
}
|
||||
|
||||
const BotProfile* BotProfile::GetTemplate( int index ) const
|
||||
{
|
||||
if ( index > 0 && index < m_templates.Count() )
|
||||
{
|
||||
return m_templates[index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void BotProfile::Clone( const BotProfile* source_profile )
|
||||
{
|
||||
if ( source_profile )
|
||||
{
|
||||
SetName( source_profile->GetName() );
|
||||
|
||||
for ( int device = 0; device < BotProfileInputDevice::COUNT; ++device )
|
||||
{
|
||||
m_aggression = source_profile->GetAggression();
|
||||
|
||||
m_skill = source_profile->GetSkill();
|
||||
|
||||
m_teamwork = source_profile->GetTeamwork();
|
||||
|
||||
m_aimFocusInitial = source_profile->GetAimFocusInitial();
|
||||
m_aimFocusDecay = source_profile->GetAimFocusDecay();
|
||||
m_aimFocusOffsetScale = source_profile->GetAimFocusOffsetScale();
|
||||
m_aimFocusInterval = source_profile->GetAimFocusInterval();
|
||||
|
||||
m_weaponPreferenceCount = source_profile->GetWeaponPreferenceCount();
|
||||
for( int i = 0; i < source_profile->GetWeaponPreferenceCount(); ++i )
|
||||
{
|
||||
m_weaponPreference[i] = source_profile->GetWeaponPreference(i);
|
||||
}
|
||||
|
||||
m_cost = source_profile->GetCost();
|
||||
|
||||
m_skin = source_profile->GetSkin();
|
||||
|
||||
m_difficultyFlags = source_profile->GetDifficultyFlags();
|
||||
|
||||
m_voicePitch = source_profile->GetVoicePitch();
|
||||
|
||||
m_reactionTime = source_profile->GetReactionTime();
|
||||
|
||||
m_attackDelay = source_profile->GetAttackDelay();
|
||||
|
||||
m_lookAngleMaxAccelNormal = source_profile->GetLookAngleMaxAccelerationNormal();
|
||||
m_lookAngleStiffnessNormal = source_profile->GetLookAngleStiffnessNormal();
|
||||
m_lookAngleDampingNormal = source_profile->GetLookAngleDampingNormal();
|
||||
|
||||
m_lookAngleMaxAccelAttacking = source_profile->GetLookAngleMaxAccelerationAttacking();
|
||||
m_lookAngleStiffnessAttacking = source_profile->GetLookAngleStiffnessAttacking();
|
||||
m_lookAngleDampingAttacking = source_profile->GetLookAngleDampingAttacking();
|
||||
}
|
||||
|
||||
m_teams = source_profile->GetTeams();
|
||||
|
||||
m_voiceBank = source_profile->GetVoiceBank();
|
||||
|
||||
m_prefersSilencer = source_profile->PrefersSilencer();
|
||||
|
||||
for ( int i = 0; i < source_profile->GetTemplatesCount(); ++i )
|
||||
{
|
||||
m_templates.AddToTail( source_profile->GetTemplate( i ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
BotProfileManager::BotProfileManager( void )
|
||||
{
|
||||
m_nextSkin = 0;
|
||||
for (int i=0; i<NumCustomSkins; ++i)
|
||||
{
|
||||
m_skins[i] = NULL;
|
||||
m_skinFilenames[i] = NULL;
|
||||
m_skinModelnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Load the bot profile database
|
||||
*/
|
||||
void BotProfileManager::Init( const char *filename, unsigned int *checksum )
|
||||
{
|
||||
FileHandle_t file = filesystem->Open( filename, "r" );
|
||||
|
||||
if (!file)
|
||||
{
|
||||
if ( true ) // UTIL_IsGame( "czero" ) )
|
||||
{
|
||||
CONSOLE_ECHO( "WARNING: Cannot access bot profile database '%s'\n", filename );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int dataLength = filesystem->Size( filename );
|
||||
char *dataPointer = new char[ dataLength ];
|
||||
int dataReadLength = filesystem->Read( dataPointer, dataLength, file );
|
||||
filesystem->Close( file );
|
||||
if ( dataReadLength > 0 )
|
||||
{
|
||||
// NULL-terminate based on the length read in, since Read() can transform \r\n to \n and
|
||||
// return fewer bytes than we were expecting.
|
||||
dataPointer[ dataReadLength - 1 ] = 0;
|
||||
}
|
||||
|
||||
const char *dataFile = dataPointer;
|
||||
|
||||
// compute simple checksum
|
||||
if (checksum)
|
||||
{
|
||||
*checksum = 0; // ComputeSimpleChecksum( (const unsigned char *)dataPointer, dataLength );
|
||||
}
|
||||
|
||||
BotProfile defaultProfile;
|
||||
|
||||
//
|
||||
// Parse the BotProfile.db into BotProfile instances
|
||||
//
|
||||
while( true )
|
||||
{
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
break;
|
||||
|
||||
char *token = SharedGetToken();
|
||||
|
||||
bool isDefault = ( !stricmp( token, "Default" ));
|
||||
bool isTemplate = ( !stricmp( token, "Template" ));
|
||||
bool isCustomSkin = ( !stricmp( token, "Skin" ));
|
||||
|
||||
if ( isCustomSkin )
|
||||
{
|
||||
const int BufLen = 64;
|
||||
char skinName[BufLen];
|
||||
|
||||
// get skin name
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected skin name\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
Q_snprintf( skinName, sizeof( skinName ), "%s", token );
|
||||
|
||||
// get attribute name
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
if (stricmp( "Model", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// eat '='
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
if (strcmp( "=", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// get attribute value
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
|
||||
const char *decoratedName = GetDecoratedSkinName( skinName, filename );
|
||||
bool skinExists = GetCustomSkinIndex( decoratedName ) > 0;
|
||||
if ( m_nextSkin < NumCustomSkins && !skinExists )
|
||||
{
|
||||
// decorate the name
|
||||
m_skins[ m_nextSkin ] = CloneString( decoratedName );
|
||||
|
||||
// construct the model filename
|
||||
m_skinModelnames[ m_nextSkin ] = CloneString( token );
|
||||
m_skinFilenames[ m_nextSkin ] = new char[ strlen( token )*2 + strlen("models/player//.mdl") + 1 ];
|
||||
Q_snprintf( m_skinFilenames[ m_nextSkin ], sizeof( m_skinFilenames[ m_nextSkin ] ), "models/player/%s/%s.mdl", token, token );
|
||||
++m_nextSkin;
|
||||
}
|
||||
|
||||
// eat 'End'
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
if (strcmp( "End", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
continue; // it's just a custom skin - no need to do inheritance on a bot profile, etc.
|
||||
}
|
||||
|
||||
// encountered a new profile
|
||||
BotProfile *profile;
|
||||
|
||||
if (isDefault)
|
||||
{
|
||||
profile = &defaultProfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
profile = new BotProfile;
|
||||
|
||||
// always inherit from Default
|
||||
*profile = defaultProfile;
|
||||
}
|
||||
|
||||
// do inheritance in order of appearance
|
||||
if (!isTemplate && !isDefault)
|
||||
{
|
||||
const BotProfile *inherit = NULL;
|
||||
|
||||
// template names are separated by "+"
|
||||
while(true)
|
||||
{
|
||||
char *c = strchr( token, '+' );
|
||||
if (c)
|
||||
*c = '\000';
|
||||
|
||||
// find the given template name
|
||||
FOR_EACH_LL( m_templateList, it )
|
||||
{
|
||||
BotProfile *profile = m_templateList[ it ];
|
||||
if ( !stricmp( profile->GetName(), token ))
|
||||
{
|
||||
inherit = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit == NULL)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing '%s' - invalid template reference '%s'\n", filename, token );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// inherit the data
|
||||
profile->Inherit( inherit, &defaultProfile );
|
||||
|
||||
if (c == NULL)
|
||||
break;
|
||||
|
||||
token = c+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get name of this profile
|
||||
if (!isDefault)
|
||||
{
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing '%s' - expected name\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
profile->m_name = CloneString( SharedGetToken() );
|
||||
|
||||
/**
|
||||
* HACK HACK
|
||||
* Until we have a generalized means of storing bot preferences, we're going to hardcode the bot's
|
||||
* preference towards silencers based on his name.
|
||||
*/
|
||||
if ( profile->m_name[0] % 2 )
|
||||
{
|
||||
profile->m_prefersSilencer = true;
|
||||
}
|
||||
}
|
||||
|
||||
// read attributes for this profile
|
||||
bool isFirstWeaponPref = true;
|
||||
while( true )
|
||||
{
|
||||
// get next token
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
|
||||
// check for End delimiter
|
||||
if ( !stricmp( token, "End" ))
|
||||
break;
|
||||
|
||||
// found attribute name - keep it
|
||||
char attributeName[64];
|
||||
strcpy( attributeName, token );
|
||||
|
||||
// eat '='
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
token = SharedGetToken();
|
||||
if (strcmp( "=", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// get attribute value
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
|
||||
// store value in appropriate attribute
|
||||
if ( !stricmp( "Aggression", attributeName ) )
|
||||
{
|
||||
profile->m_aggression = (float)atof( token ) / 100.0f;
|
||||
}
|
||||
else if ( !stricmp( "Skill", attributeName ) )
|
||||
{
|
||||
profile->m_skill = (float)atof( token ) / 100.0f;
|
||||
}
|
||||
else if ( !stricmp( "Skin", attributeName ) )
|
||||
{
|
||||
profile->m_skin = atoi( token );
|
||||
if ( profile->m_skin == 0 )
|
||||
{
|
||||
// atoi() failed - try to look up a custom skin by name
|
||||
profile->m_skin = GetCustomSkinIndex( token, filename );
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( "Teamwork", attributeName ))
|
||||
{
|
||||
profile->m_teamwork = (float)atof( token ) / 100.0f;
|
||||
}
|
||||
else if ( !V_stricmp( "AimFocusInitial", attributeName ) )
|
||||
{
|
||||
profile->m_aimFocusInitial = (float)atof( token );
|
||||
}
|
||||
else if ( !V_stricmp( "AimFocusDecay", attributeName ) )
|
||||
{
|
||||
profile->m_aimFocusDecay = (float)atof( token );
|
||||
}
|
||||
else if ( !V_stricmp( "AimFocusOffsetScale", attributeName ) )
|
||||
{
|
||||
profile->m_aimFocusOffsetScale = (float)atof( token );
|
||||
}
|
||||
else if ( !V_stricmp( "AimFocusInterval", attributeName ) )
|
||||
{
|
||||
profile->m_aimFocusInterval = (float)atof( token );
|
||||
}
|
||||
else if ( !stricmp( "Cost", attributeName ) )
|
||||
{
|
||||
profile->m_cost = atoi( token );
|
||||
}
|
||||
else if ( !stricmp( "VoicePitch", attributeName ) )
|
||||
{
|
||||
profile->m_voicePitch = atoi( token );
|
||||
}
|
||||
else if ( !stricmp( "VoiceBank", attributeName ) )
|
||||
{
|
||||
profile->m_voiceBank = FindVoiceBankIndex( token );
|
||||
}
|
||||
else if ( !stricmp( "WeaponPreference", attributeName ) )
|
||||
{
|
||||
ParseWeaponPreference( isFirstWeaponPref, profile->m_weaponPreferenceCount, profile->m_weaponPreference, token );
|
||||
}
|
||||
else if ( !stricmp( "ReactionTime", attributeName ) )
|
||||
{
|
||||
profile->m_reactionTime = (float)atof( token );
|
||||
|
||||
}
|
||||
else if ( !stricmp( "AttackDelay", attributeName ))
|
||||
{
|
||||
profile->m_attackDelay = (float)atof( token );
|
||||
}
|
||||
else if ( !stricmp( "Difficulty", attributeName ))
|
||||
{
|
||||
// override inheritance
|
||||
ParseDifficultySetting( profile->m_difficultyFlags, token );
|
||||
}
|
||||
else if ( !stricmp( "Team", attributeName ))
|
||||
{
|
||||
if ( !stricmp( token, "T" ) )
|
||||
{
|
||||
profile->m_teams = TEAM_TERRORIST;
|
||||
}
|
||||
else if ( !stricmp( token, "CT" ) )
|
||||
{
|
||||
profile->m_teams = TEAM_CT;
|
||||
}
|
||||
else
|
||||
{
|
||||
profile->m_teams = TEAM_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( "LookAngleMaxAccelNormal", attributeName ) )
|
||||
{
|
||||
profile->m_lookAngleMaxAccelNormal = atof( token );
|
||||
}
|
||||
else if ( !stricmp( "LookAngleStiffnessNormal", attributeName ) )
|
||||
{
|
||||
profile->m_lookAngleStiffnessNormal = atof( token );
|
||||
}
|
||||
else if ( !stricmp( "LookAngleDampingNormal", attributeName ) )
|
||||
{
|
||||
profile->m_lookAngleDampingNormal = atof( token );
|
||||
}
|
||||
else if ( !stricmp( "LookAngleMaxAccelAttacking", attributeName ) )
|
||||
{
|
||||
profile->m_lookAngleMaxAccelAttacking = atof( token );
|
||||
}
|
||||
else if ( !stricmp( "LookAngleStiffnessAttacking", attributeName ) )
|
||||
{
|
||||
profile->m_lookAngleStiffnessAttacking = atof( token );
|
||||
}
|
||||
else if ( !stricmp( "LookAngleDampingAttacking", attributeName ) )
|
||||
{
|
||||
profile->m_lookAngleDampingAttacking = atof( token );
|
||||
}
|
||||
else
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - unknown attribute '%s'\n", filename, attributeName );
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefault)
|
||||
{
|
||||
if (isTemplate)
|
||||
{
|
||||
// add to template list
|
||||
m_templateList.AddToTail( profile );
|
||||
}
|
||||
else
|
||||
{
|
||||
// add profile to the master list
|
||||
m_profileList.AddToTail( profile );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] dataPointer;
|
||||
}
|
||||
|
||||
void BotProfileManager::ParseDifficultySetting( unsigned char &difficultyFlags, char* token)
|
||||
{
|
||||
// override inheritance
|
||||
difficultyFlags = 0;
|
||||
|
||||
// parse bit flags
|
||||
while(true)
|
||||
{
|
||||
char *c = strchr( token, '+' );
|
||||
if (c)
|
||||
{
|
||||
*c = '\000';
|
||||
}
|
||||
|
||||
for( int i=0; i<NUM_DIFFICULTY_LEVELS; ++i )
|
||||
{
|
||||
if ( !stricmp( BotDifficultyName[i], token ))
|
||||
{
|
||||
difficultyFlags |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
token = c+1;
|
||||
}
|
||||
}
|
||||
|
||||
void BotProfileManager::ParseWeaponPreference( bool &isFirstWeaponPref, int &weaponPreferenceCount, CSWeaponID* weaponPreference, char* token )
|
||||
{
|
||||
// weapon preferences override parent prefs
|
||||
if (isFirstWeaponPref)
|
||||
{
|
||||
isFirstWeaponPref = false;
|
||||
weaponPreferenceCount = 0;
|
||||
}
|
||||
|
||||
if ( !stricmp( token, "none" ))
|
||||
{
|
||||
weaponPreferenceCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS)
|
||||
{
|
||||
weaponPreference[ weaponPreferenceCount++ ] = AliasToWeaponID( token );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
BotProfileManager::~BotProfileManager( void )
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Free all bot profiles
|
||||
*/
|
||||
void BotProfileManager::Reset( void )
|
||||
{
|
||||
m_profileList.PurgeAndDeleteElements();
|
||||
m_templateList.PurgeAndDeleteElements();
|
||||
|
||||
int i;
|
||||
|
||||
for (i=0; i<NumCustomSkins; ++i)
|
||||
{
|
||||
if ( m_skins[i] )
|
||||
{
|
||||
delete[] m_skins[i];
|
||||
m_skins[i] = NULL;
|
||||
}
|
||||
if ( m_skinFilenames[i] )
|
||||
{
|
||||
delete[] m_skinFilenames[i];
|
||||
m_skinFilenames[i] = NULL;
|
||||
}
|
||||
if ( m_skinModelnames[i] )
|
||||
{
|
||||
delete[] m_skinModelnames[i];
|
||||
m_skinModelnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i=0; i<m_voiceBanks.Count(); ++i )
|
||||
{
|
||||
delete[] m_voiceBanks[i];
|
||||
}
|
||||
m_voiceBanks.RemoveAll();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns custom skin name at a particular index
|
||||
*/
|
||||
const char * BotProfileManager::GetCustomSkin( int index )
|
||||
{
|
||||
if ( index < FirstCustomSkin || index > LastCustomSkin )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_skins[ index - FirstCustomSkin ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns custom skin filename at a particular index
|
||||
*/
|
||||
const char * BotProfileManager::GetCustomSkinFname( int index )
|
||||
{
|
||||
if ( index < FirstCustomSkin || index > LastCustomSkin )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_skinFilenames[ index - FirstCustomSkin ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns custom skin modelname at a particular index
|
||||
*/
|
||||
const char * BotProfileManager::GetCustomSkinModelname( int index )
|
||||
{
|
||||
if ( index < FirstCustomSkin || index > LastCustomSkin )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_skinModelnames[ index - FirstCustomSkin ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Looks up a custom skin index by filename-decorated name (will decorate the name if filename is given)
|
||||
*/
|
||||
int BotProfileManager::GetCustomSkinIndex( const char *name, const char *filename )
|
||||
{
|
||||
const char * skinName = name;
|
||||
if ( filename )
|
||||
{
|
||||
skinName = GetDecoratedSkinName( name, filename );
|
||||
}
|
||||
|
||||
for (int i=0; i<NumCustomSkins; ++i)
|
||||
{
|
||||
if ( m_skins[i] )
|
||||
{
|
||||
if ( !stricmp( skinName, m_skins[i] ) )
|
||||
{
|
||||
return FirstCustomSkin + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* return index of the (custom) bot phrase db, inserting it if needed
|
||||
*/
|
||||
int BotProfileManager::FindVoiceBankIndex( const char *filename )
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for ( int i=0; i<m_voiceBanks.Count(); ++i )
|
||||
{
|
||||
if ( !stricmp( filename, m_voiceBanks[i] ) )
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
m_voiceBanks.AddToTail( CloneString( filename ) );
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return random unused profile that matches the given difficulty level
|
||||
*/
|
||||
const BotProfile *BotProfileManager::GetRandomProfile( BotDifficultyType difficulty, int team, CSWeaponType weaponType, bool forceMatchHighestDifficulty ) const
|
||||
{
|
||||
// count up valid profiles
|
||||
CUtlVector< const BotProfile * > profiles;
|
||||
FOR_EACH_LL( m_profileList, it )
|
||||
{
|
||||
const BotProfile *profile = m_profileList[ it ];
|
||||
|
||||
// Match difficulty
|
||||
if ( forceMatchHighestDifficulty )
|
||||
{
|
||||
if ( !profile->IsMaxDifficulty( difficulty ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !profile->IsDifficulty( difficulty ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prevent duplicate names
|
||||
if ( UTIL_IsNameTaken( profile->GetName() ) )
|
||||
continue;
|
||||
|
||||
// Match team choice
|
||||
if ( !profile->IsValidForTeam( team ) )
|
||||
continue;
|
||||
|
||||
// Match desired weapon
|
||||
if ( weaponType != WEAPONTYPE_UNKNOWN )
|
||||
{
|
||||
if ( !profile->GetWeaponPreferenceCount() )
|
||||
continue;
|
||||
|
||||
if ( weaponType != WeaponClassFromWeaponID( (CSWeaponID)profile->GetWeaponPreference( 0 ) ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
profiles.AddToTail( profile );
|
||||
}
|
||||
|
||||
if ( !profiles.Count() )
|
||||
return NULL;
|
||||
|
||||
// select one at random
|
||||
int which = RandomInt( 0, profiles.Count()-1 );
|
||||
return profiles[which];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef _BOT_PROFILE_H_
|
||||
#define _BOT_PROFILE_H_
|
||||
|
||||
#pragma warning( disable : 4786 ) // long STL names get truncated in browse info.
|
||||
|
||||
#include "bot_constants.h"
|
||||
#include "bot_util.h"
|
||||
#include "cs_weapon_parse.h"
|
||||
|
||||
enum
|
||||
{
|
||||
FirstCustomSkin = 100,
|
||||
NumCustomSkins = 100,
|
||||
LastCustomSkin = FirstCustomSkin + NumCustomSkins - 1,
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* A BotProfile describes the "personality" of a given bot
|
||||
*/
|
||||
class BotProfile
|
||||
{
|
||||
public:
|
||||
BotProfile( void )
|
||||
{
|
||||
m_name = NULL;
|
||||
|
||||
m_aggression = 0.0f;
|
||||
m_skill = 0.0f;
|
||||
m_teamwork = 0.0f;
|
||||
m_weaponPreferenceCount = 0;
|
||||
|
||||
m_aimFocusInitial = 0.0f;
|
||||
m_aimFocusDecay = 1.0f;
|
||||
m_aimFocusOffsetScale = 0.0f;
|
||||
m_aimFocusInterval = .5f;
|
||||
|
||||
m_cost = 0;
|
||||
m_skin = 0;
|
||||
m_difficultyFlags = 0;
|
||||
m_voicePitch = 100;
|
||||
m_reactionTime = 0.3f;
|
||||
m_attackDelay = 0.0f;
|
||||
m_lookAngleMaxAccelNormal = 0.0f;
|
||||
m_lookAngleStiffnessNormal = 0.0f;
|
||||
m_lookAngleDampingNormal = 0.0f;
|
||||
m_lookAngleMaxAccelAttacking = 0.0f;
|
||||
m_lookAngleStiffnessAttacking = 0.0f;
|
||||
m_lookAngleDampingAttacking = 0.0f;
|
||||
|
||||
m_teams = TEAM_UNASSIGNED;
|
||||
m_voiceBank = 0;
|
||||
m_prefersSilencer = false;
|
||||
|
||||
}
|
||||
|
||||
~BotProfile( void )
|
||||
{
|
||||
if ( m_name )
|
||||
delete [] m_name;
|
||||
}
|
||||
|
||||
const char *GetName( void ) const { return m_name; } ///< return bot's name
|
||||
float GetAggression() const;
|
||||
float GetSkill() const;
|
||||
float GetTeamwork() const;
|
||||
|
||||
float GetAimFocusInitial() const { return m_aimFocusInitial; }
|
||||
float GetAimFocusDecay() const { return m_aimFocusDecay; }
|
||||
float GetAimFocusOffsetScale() const { return m_aimFocusOffsetScale; }
|
||||
float GetAimFocusInterval() const { return m_aimFocusInterval; }
|
||||
|
||||
CSWeaponID GetWeaponPreference(int i ) const;
|
||||
const char *GetWeaponPreferenceAsString( int i ) const;
|
||||
int GetWeaponPreferenceCount() const;
|
||||
bool HasPrimaryPreference() const; ///< return true if this profile has a primary weapon preference
|
||||
bool HasPistolPreference() const; ///< return true if this profile has a pistol weapon preference
|
||||
|
||||
int GetCost() const;
|
||||
int GetSkin() const;
|
||||
int GetMaxDifficulty() const; ///< return maximum difficulty flag value
|
||||
bool IsDifficulty( BotDifficultyType diff ) const; ///< return true if this profile can be used for the given difficulty level
|
||||
bool IsMaxDifficulty( BotDifficultyType diff ) const; ///< return true if this profile's highest difficulty matches the incoming difficulty level
|
||||
int GetVoicePitch() const;
|
||||
float GetReactionTime() const;
|
||||
float GetAttackDelay() const;
|
||||
int GetVoiceBank() const { return m_voiceBank; }
|
||||
unsigned char GetDifficultyFlags() const;
|
||||
int GetTeams( void ) const { return m_teams; }
|
||||
|
||||
float GetLookAngleMaxAccelerationNormal() const;
|
||||
float GetLookAngleStiffnessNormal() const;
|
||||
float GetLookAngleDampingNormal() const;
|
||||
float GetLookAngleMaxAccelerationAttacking() const;
|
||||
float GetLookAngleStiffnessAttacking() const;
|
||||
float GetLookAngleDampingAttacking() const;
|
||||
|
||||
bool IsValidForTeam( int team ) const;
|
||||
|
||||
bool PrefersSilencer() const { return m_prefersSilencer; }
|
||||
|
||||
bool InheritsFrom( const char *name ) const;
|
||||
|
||||
void Clone( const BotProfile* source_profile );
|
||||
void SetName( const char* name );
|
||||
void SetVoicePitch( int pitch );
|
||||
int GetTemplatesCount( void ) const { return m_templates.Count(); }
|
||||
const BotProfile* GetTemplate( int index ) const;
|
||||
|
||||
private:
|
||||
friend class BotProfileManager; ///< for loading profiles
|
||||
|
||||
void Inherit( const BotProfile *parent, const BotProfile *baseline ); ///< copy values from parent if they differ from baseline
|
||||
|
||||
char *m_name; // the bot's name
|
||||
float m_aggression; // percentage: 0 = coward, 1 = berserker
|
||||
float m_skill; // percentage: 0 = terrible, 1 = expert
|
||||
float m_teamwork; // percentage: 0 = rogue, 1 = complete obeyance to team, lots of comm
|
||||
|
||||
float m_aimFocusInitial; // initial minimum aim error on first attack
|
||||
float m_aimFocusDecay; // how quickly our focus error decays (scale/sec)
|
||||
float m_aimFocusOffsetScale; // how much aim focus error we get based on maximum angle distance from our view angle
|
||||
float m_aimFocusInterval; // how frequently we update our focus
|
||||
|
||||
enum { MAX_WEAPON_PREFS = 16 };
|
||||
CSWeaponID m_weaponPreference[ MAX_WEAPON_PREFS ]; ///< which weapons this bot likes to use, in order of priority
|
||||
int m_weaponPreferenceCount;
|
||||
|
||||
int m_cost; ///< reputation point cost for career mode
|
||||
int m_skin; ///< "skin" index
|
||||
unsigned char m_difficultyFlags; ///< bits set correspond to difficulty levels this is valid for
|
||||
int m_voicePitch; ///< the pitch shift for bot chatter (100 = normal)
|
||||
float m_reactionTime; ///< our reaction time in seconds
|
||||
float m_attackDelay; ///< time in seconds from when we notice an enemy to when we open fire
|
||||
int m_teams; ///< teams for which this profile is valid
|
||||
|
||||
bool m_prefersSilencer; ///< does the bot prefer to use silencers?
|
||||
|
||||
int m_voiceBank; ///< Index of the BotChatter.db voice bank this profile uses (0 is the default)
|
||||
|
||||
float m_lookAngleMaxAccelNormal; // Acceleration of look angle spring under normal conditions
|
||||
float m_lookAngleStiffnessNormal; // Stiffness of look angle spring under normal conditions
|
||||
float m_lookAngleDampingNormal; // Damping of look angle spring under normal conditions
|
||||
|
||||
float m_lookAngleMaxAccelAttacking; // Acceleration of look angle spring under attack conditions
|
||||
float m_lookAngleStiffnessAttacking; // Stiffness of look angle spring under attack conditions
|
||||
float m_lookAngleDampingAttacking; // Damping of look angle spring under attack conditions
|
||||
|
||||
CUtlVector< const BotProfile * > m_templates; ///< List of templates we inherit from
|
||||
};
|
||||
typedef CUtlLinkedList<BotProfile *> BotProfileList;
|
||||
|
||||
|
||||
inline int BotProfile::GetMaxDifficulty() const
|
||||
{
|
||||
for ( int i = NUM_DIFFICULTY_LEVELS - 1; i >= BOT_EASY; --i )
|
||||
{
|
||||
if ( m_difficultyFlags & ( 1 << i ) )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return BOT_EASY;
|
||||
}
|
||||
|
||||
inline bool BotProfile::IsDifficulty( BotDifficultyType diff ) const
|
||||
{
|
||||
return (m_difficultyFlags & (1 << diff)) ? true : false;
|
||||
}
|
||||
|
||||
inline bool BotProfile::IsMaxDifficulty( BotDifficultyType diff ) const
|
||||
{
|
||||
return ( ( m_difficultyFlags >> diff ) == 1 );
|
||||
}
|
||||
|
||||
inline float BotProfile::GetAggression() const
|
||||
{
|
||||
return m_aggression;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetSkill() const
|
||||
{
|
||||
return m_skill;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetTeamwork() const
|
||||
{
|
||||
return m_teamwork;
|
||||
}
|
||||
|
||||
inline CSWeaponID BotProfile::GetWeaponPreference( int i ) const
|
||||
{
|
||||
return m_weaponPreference[ i ];
|
||||
}
|
||||
|
||||
inline int BotProfile::GetWeaponPreferenceCount() const
|
||||
{
|
||||
return m_weaponPreferenceCount;
|
||||
}
|
||||
|
||||
inline int BotProfile::GetCost() const
|
||||
{
|
||||
return m_cost;
|
||||
}
|
||||
|
||||
inline int BotProfile::GetSkin() const
|
||||
{
|
||||
return m_skin;
|
||||
}
|
||||
|
||||
inline int BotProfile::GetVoicePitch() const
|
||||
{
|
||||
return m_voicePitch;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetReactionTime() const
|
||||
{
|
||||
return m_reactionTime;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetAttackDelay() const
|
||||
{
|
||||
return m_attackDelay;
|
||||
}
|
||||
|
||||
inline unsigned char BotProfile::GetDifficultyFlags() const
|
||||
{
|
||||
return m_difficultyFlags;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetLookAngleMaxAccelerationNormal() const
|
||||
{
|
||||
return m_lookAngleMaxAccelNormal;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetLookAngleStiffnessNormal( ) const
|
||||
{
|
||||
return m_lookAngleStiffnessNormal;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetLookAngleDampingNormal() const
|
||||
{
|
||||
return m_lookAngleDampingNormal;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetLookAngleMaxAccelerationAttacking() const
|
||||
{
|
||||
return m_lookAngleMaxAccelAttacking;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetLookAngleStiffnessAttacking() const
|
||||
{
|
||||
return m_lookAngleStiffnessAttacking;
|
||||
}
|
||||
|
||||
inline float BotProfile::GetLookAngleDampingAttacking() const
|
||||
{
|
||||
return m_lookAngleDampingAttacking;
|
||||
}
|
||||
|
||||
inline void BotProfile::SetVoicePitch( int pitch )
|
||||
{
|
||||
m_voicePitch = pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy in data from parent if it differs from the baseline
|
||||
*/
|
||||
inline void BotProfile::Inherit( const BotProfile *parent, const BotProfile *baseline )
|
||||
{
|
||||
if ( parent->m_aggression != baseline->m_aggression )
|
||||
m_aggression = parent->m_aggression;
|
||||
|
||||
if ( parent->m_skill != baseline->m_skill )
|
||||
m_skill = parent->m_skill;
|
||||
|
||||
if ( parent->m_teamwork != baseline->m_teamwork )
|
||||
m_teamwork = parent->m_teamwork;
|
||||
|
||||
if ( parent->m_aimFocusInitial != baseline->m_aimFocusInitial )
|
||||
m_aimFocusInitial = parent->m_aimFocusInitial;
|
||||
|
||||
if ( parent->m_aimFocusDecay != baseline->m_aimFocusDecay )
|
||||
m_aimFocusDecay = parent->m_aimFocusDecay;
|
||||
|
||||
if ( parent->m_aimFocusOffsetScale != baseline->m_aimFocusOffsetScale )
|
||||
m_aimFocusOffsetScale = parent->m_aimFocusOffsetScale;
|
||||
|
||||
if ( parent->m_aimFocusInterval != baseline->m_aimFocusInterval )
|
||||
m_aimFocusInterval = parent->m_aimFocusInterval;
|
||||
|
||||
if (parent->m_weaponPreferenceCount != baseline->m_weaponPreferenceCount)
|
||||
{
|
||||
m_weaponPreferenceCount = parent->m_weaponPreferenceCount;
|
||||
for( int i=0; i<parent->m_weaponPreferenceCount; ++i )
|
||||
m_weaponPreference[i] = parent->m_weaponPreference[i];
|
||||
}
|
||||
|
||||
if (parent->m_cost != baseline->m_cost)
|
||||
m_cost = parent->m_cost;
|
||||
|
||||
if (parent->m_skin != baseline->m_skin)
|
||||
m_skin = parent->m_skin;
|
||||
|
||||
if (parent->m_difficultyFlags != baseline->m_difficultyFlags)
|
||||
m_difficultyFlags = parent->m_difficultyFlags;
|
||||
|
||||
if (parent->m_voicePitch != baseline->m_voicePitch)
|
||||
m_voicePitch = parent->m_voicePitch;
|
||||
|
||||
if (parent->m_reactionTime != baseline->m_reactionTime)
|
||||
m_reactionTime = parent->m_reactionTime;
|
||||
|
||||
if (parent->m_attackDelay != baseline->m_attackDelay)
|
||||
m_attackDelay = parent->m_attackDelay;
|
||||
|
||||
if (parent->m_teams != baseline->m_teams)
|
||||
m_teams = parent->m_teams;
|
||||
|
||||
if (parent->m_voiceBank != baseline->m_voiceBank)
|
||||
m_voiceBank = parent->m_voiceBank;
|
||||
|
||||
m_templates.AddToTail( parent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The BotProfileManager defines the interface to accessing BotProfiles
|
||||
*/
|
||||
class BotProfileManager
|
||||
{
|
||||
public:
|
||||
BotProfileManager( void );
|
||||
~BotProfileManager( void );
|
||||
|
||||
void Init( const char *filename, unsigned int *checksum = NULL );
|
||||
void Reset( void );
|
||||
|
||||
/// given a name, return a profile
|
||||
const BotProfile *GetProfile( const char *name, int team ) const
|
||||
{
|
||||
FOR_EACH_LL( m_profileList, it )
|
||||
{
|
||||
BotProfile *profile = m_profileList[ it ];
|
||||
|
||||
if ( !stricmp( name, profile->GetName() ) && profile->IsValidForTeam( team ) )
|
||||
return profile;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// given a template name and difficulty, return a profile
|
||||
const BotProfile *GetProfileMatchingTemplate( const char *profileName, int team, BotDifficultyType difficulty, BotProfileDevice_t device, bool bAllowDupeNames = false ) const
|
||||
{
|
||||
FOR_EACH_LL( m_profileList, it )
|
||||
{
|
||||
BotProfile *profile = m_profileList[ it ];
|
||||
|
||||
if ( !profile->InheritsFrom( profileName ) )
|
||||
continue;
|
||||
|
||||
if ( !profile->IsValidForTeam( team ) )
|
||||
continue;
|
||||
|
||||
if ( !profile->IsDifficulty( difficulty ) )
|
||||
continue;
|
||||
|
||||
if ( bAllowDupeNames == false && UTIL_IsNameTaken( profile->GetName() ) )
|
||||
continue;
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const BotProfileList *GetProfileList( void ) const { return &m_profileList; } ///< return list of all profiles
|
||||
|
||||
const BotProfile *GetRandomProfile( BotDifficultyType difficulty, int team, CSWeaponType weaponType, bool forceMatchHighestDifficulty = false ) const; ///< return random unused profile that matches the given difficulty level
|
||||
|
||||
const char * GetCustomSkin( int index ); ///< Returns custom skin name at a particular index
|
||||
const char * GetCustomSkinModelname( int index ); ///< Returns custom skin modelname at a particular index
|
||||
const char * GetCustomSkinFname( int index ); ///< Returns custom skin filename at a particular index
|
||||
int GetCustomSkinIndex( const char *name, const char *filename = NULL ); ///< Looks up a custom skin index by name
|
||||
|
||||
typedef CUtlVector<char *> VoiceBankList;
|
||||
const VoiceBankList *GetVoiceBanks( void ) const { return &m_voiceBanks; }
|
||||
int FindVoiceBankIndex( const char *filename ); ///< return index of the (custom) bot phrase db, inserting it if needed
|
||||
|
||||
protected:
|
||||
void ParseDifficultySetting( unsigned char &difficultyFlags, char* token);
|
||||
void ParseWeaponPreference( bool &isFirstWeaponPref, int &weaponPreferenceCount, CSWeaponID* weaponPreference, char* token );
|
||||
|
||||
protected:
|
||||
BotProfileList m_profileList; ///< the list of all bot profiles
|
||||
BotProfileList m_templateList; ///< the list of all bot templates
|
||||
|
||||
VoiceBankList m_voiceBanks;
|
||||
|
||||
char *m_skins[ NumCustomSkins ]; ///< Custom skin names
|
||||
char *m_skinModelnames[ NumCustomSkins ]; ///< Custom skin modelnames
|
||||
char *m_skinFilenames[ NumCustomSkins ]; ///< Custom skin filenames
|
||||
int m_nextSkin; ///< Next custom skin to allocate
|
||||
};
|
||||
|
||||
/// the global singleton for accessing BotProfiles
|
||||
extern BotProfileManager *TheBotProfiles;
|
||||
|
||||
|
||||
#endif // _BOT_PROFILE_H_
|
||||
@@ -0,0 +1,682 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_shareddefs.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "keyvalues.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_util.h"
|
||||
#include "bot_profile.h"
|
||||
|
||||
#include "cs_bot.h"
|
||||
#include <ctype.h>
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static int s_iBeamSprite = 0;
|
||||
|
||||
extern ConVar mp_randomspawn_dist;
|
||||
extern ConVar mp_randomspawn_los;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if given name is already in use by another player
|
||||
*/
|
||||
bool UTIL_IsNameTaken( const char *name, bool ignoreHumans )
|
||||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (player->IsPlayer() && player->IsBot())
|
||||
{
|
||||
// bots can have prefixes so we need to check the name
|
||||
// against the profile name instead.
|
||||
CCSBot *bot = dynamic_cast<CCSBot *>(player);
|
||||
if ( bot && bot->GetProfile()->GetName() && FStrEq(name, bot->GetProfile()->GetName()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ignoreHumans)
|
||||
{
|
||||
if (FStrEq( name, player->GetPlayerName() ))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
int UTIL_ClientsInGame( void )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBaseEntity *player = UTIL_PlayerByIndex( i );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return the number of non-bots on the given team
|
||||
*/
|
||||
int UTIL_HumansOnTeam( int teamID, bool isAlive )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBaseEntity *entity = UTIL_PlayerByIndex( i );
|
||||
|
||||
if ( entity == NULL )
|
||||
continue;
|
||||
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( entity );
|
||||
|
||||
if (player->IsBot())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != teamID)
|
||||
continue;
|
||||
|
||||
if (isAlive && !player->IsAlive())
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
int UTIL_BotsInGame( void )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>(UTIL_PlayerByIndex( i ));
|
||||
|
||||
if ( player == NULL )
|
||||
continue;
|
||||
|
||||
if ( !player->IsBot() )
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Kick a bot from the given team. If no bot exists on the team, return false.
|
||||
*/
|
||||
bool UTIL_KickBotFromTeam( int kickTeam, bool bQueue )
|
||||
{
|
||||
int i;
|
||||
|
||||
// try to kick a dead bot first
|
||||
for ( i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsBot())
|
||||
continue;
|
||||
|
||||
if ( player->GetPendingTeamNumber() == TEAM_SPECTATOR )
|
||||
{
|
||||
// bot has already been flagged for kicking
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !player->IsAlive() )
|
||||
{
|
||||
// Address issue with bots getting kicked during half-time (this was resulting in bots from the wrong team being kicked)
|
||||
if ( player->CanKickFromTeam( kickTeam ) )
|
||||
{
|
||||
if ( bQueue )
|
||||
{
|
||||
// bots flagged as spectators will be kicked at the beginning of the next round restart
|
||||
player->SetPendingTeamNum( TEAM_SPECTATOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
// its a bot on the right team - kick it
|
||||
engine->ServerCommand( UTIL_VarArgs( "kickid %d\n", engine->GetPlayerUserId( player->edict() ) ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no dead bots, kick any bot on the given team
|
||||
for ( i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsBot())
|
||||
continue;
|
||||
|
||||
if ( player->GetPendingTeamNumber() == TEAM_SPECTATOR )
|
||||
{
|
||||
// bot has already been flagged for kicking
|
||||
continue;
|
||||
}
|
||||
|
||||
// Address issue with bots getting kicked during half-time (this was resulting in bots from the wrong team being kicked)
|
||||
if ( player->CanKickFromTeam( kickTeam ) )
|
||||
{
|
||||
if ( bQueue )
|
||||
{
|
||||
// bots flagged as spectators will be kicked at the beginning of the next round restart
|
||||
player->SetPendingTeamNum( TEAM_SPECTATOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
// its a bot on the right team - kick it
|
||||
engine->ServerCommand( UTIL_VarArgs( "kickid %d\n", engine->GetPlayerUserId( player->edict() ) ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if all of the members of the given team are bots
|
||||
*/
|
||||
bool UTIL_IsTeamAllBots( int team )
|
||||
{
|
||||
int botCount = 0;
|
||||
|
||||
for( int i=1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
// skip players on other teams
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
// if not a bot, fail the test
|
||||
if (!player->IsBot())
|
||||
return false;
|
||||
|
||||
// is a bot on given team
|
||||
++botCount;
|
||||
}
|
||||
|
||||
// if team is empty, there are no bots
|
||||
return (botCount) ? true : false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return the closest active player to the given position.
|
||||
* If 'distance' is non-NULL, the distance to the closest player is returned in it.
|
||||
*/
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, float *distance )
|
||||
{
|
||||
CBasePlayer *closePlayer = NULL;
|
||||
float closeDistSq = 999999999999.9f;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (!IsEntityValid( player ))
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
Vector playerOrigin = GetCentroid( player );
|
||||
float distSq = (playerOrigin - pos).LengthSqr();
|
||||
if (distSq < closeDistSq)
|
||||
{
|
||||
closeDistSq = distSq;
|
||||
closePlayer = static_cast<CBasePlayer *>( player );
|
||||
}
|
||||
}
|
||||
|
||||
if (distance)
|
||||
*distance = (float)sqrt( closeDistSq );
|
||||
|
||||
return closePlayer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return the closest active player on the given team to the given position.
|
||||
* If 'distance' is non-NULL, the distance to the closest player is returned in it.
|
||||
*/
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, int team, float *distance )
|
||||
{
|
||||
CBasePlayer *closePlayer = NULL;
|
||||
float closeDistSq = 999999999999.9f;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (!IsEntityValid( player ))
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
Vector playerOrigin = GetCentroid( player );
|
||||
float distSq = (playerOrigin - pos).LengthSqr();
|
||||
if (distSq < closeDistSq)
|
||||
{
|
||||
closeDistSq = distSq;
|
||||
closePlayer = static_cast<CBasePlayer *>( player );
|
||||
}
|
||||
}
|
||||
|
||||
if (distance)
|
||||
*distance = (float)sqrt( closeDistSq );
|
||||
|
||||
return closePlayer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
// Takes the bot pointer and constructs the net name using the current bot name prefix.
|
||||
void UTIL_ConstructBotNetName( char *name, int nameLength, const BotProfile *profile )
|
||||
{
|
||||
if (profile == NULL)
|
||||
{
|
||||
name[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is no bot prefix just use the profile name.
|
||||
if ((cv_bot_prefix.GetString() == NULL) || (strlen(cv_bot_prefix.GetString()) == 0))
|
||||
{
|
||||
Q_strncpy( name, profile->GetName(), nameLength );
|
||||
return;
|
||||
}
|
||||
|
||||
// find the highest difficulty
|
||||
const char *diffStr = BotDifficultyName[0];
|
||||
for ( int i=BOT_EXPERT; i>0; --i )
|
||||
{
|
||||
if ( profile->IsDifficulty( (BotDifficultyType)i ) )
|
||||
{
|
||||
diffStr = BotDifficultyName[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *weaponStr = NULL;
|
||||
if ( profile->GetWeaponPreferenceCount() )
|
||||
{
|
||||
weaponStr = profile->GetWeaponPreferenceAsString( 0 );
|
||||
|
||||
const char *translatedAlias = GetTranslatedWeaponAlias( weaponStr );
|
||||
|
||||
char wpnName[128];
|
||||
Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", translatedAlias );
|
||||
WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( wpnName );
|
||||
if ( hWpnInfo != GetInvalidWeaponInfoHandle() )
|
||||
{
|
||||
CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
|
||||
if ( pWeaponInfo )
|
||||
{
|
||||
CSWeaponType weaponType = pWeaponInfo->GetWeaponType();
|
||||
weaponStr = WeaponClassAsString( weaponType );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !weaponStr )
|
||||
{
|
||||
weaponStr = "";
|
||||
}
|
||||
|
||||
char skillStr[16];
|
||||
Q_snprintf( skillStr, sizeof( skillStr ), "%.0f", profile->GetSkill()*100 );
|
||||
|
||||
char temp[MAX_PLAYER_NAME_LENGTH*2];
|
||||
char prefix[MAX_PLAYER_NAME_LENGTH*2];
|
||||
Q_strncpy( temp, cv_bot_prefix.GetString(), sizeof( temp ) );
|
||||
Q_StrSubst( temp, "<difficulty>", diffStr, prefix, sizeof( prefix ) );
|
||||
Q_StrSubst( prefix, "<weaponclass>", weaponStr, temp, sizeof( temp ) );
|
||||
Q_StrSubst( temp, "<skill>", skillStr, prefix, sizeof( prefix ) );
|
||||
Q_snprintf( name, nameLength, "%s %s", prefix, profile->GetName() );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if anyone on the given team can see the given spot
|
||||
*/
|
||||
bool UTIL_IsVisibleToTeam( const Vector &spot, int team )
|
||||
{
|
||||
for( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
trace_t result;
|
||||
UTIL_TraceLine( player->EyePosition(), spot, CONTENTS_SOLID, player, COLLISION_GROUP_NONE, &result );
|
||||
|
||||
if ( result.fraction == 1.0f )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if anyone on the given team can see the given spot
|
||||
*/
|
||||
bool UTIL_IsRandomSpawnFarEnoughAwayFromTeam( const Vector &spot, int team )
|
||||
{
|
||||
if ( mp_randomspawn_dist.GetInt() <= 0 )
|
||||
return true;
|
||||
|
||||
if ( mp_randomspawn_los.GetInt() == 0 )
|
||||
return true;
|
||||
|
||||
for( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
if ( mp_randomspawn_dist.GetInt() > 0 && (player->GetAbsOrigin()).DistTo( spot ) < mp_randomspawn_dist.GetInt() )
|
||||
{
|
||||
//NDebugOverlay::Line( player->EyePosition(), spot + Vector( 0, 0, 32 ), 255, 0, 0, true, 4 );
|
||||
//NDebugOverlay::Line( spot, spot + Vector( 0, 0, 64 ), 255, 128, 0, true, 4 );
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void UTIL_DrawBeamFromEnt( int i, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue )
|
||||
{
|
||||
/* BOTPORT: What is the replacement for MESSAGE_BEGIN?
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecEnd ); // vecEnd = origin???
|
||||
WRITE_BYTE( TE_BEAMENTPOINT );
|
||||
WRITE_SHORT( i );
|
||||
WRITE_COORD( vecEnd.x );
|
||||
WRITE_COORD( vecEnd.y );
|
||||
WRITE_COORD( vecEnd.z );
|
||||
WRITE_SHORT( s_iBeamSprite );
|
||||
WRITE_BYTE( 0 ); // startframe
|
||||
WRITE_BYTE( 0 ); // framerate
|
||||
WRITE_BYTE( iLifetime ); // life
|
||||
WRITE_BYTE( 10 ); // width
|
||||
WRITE_BYTE( 0 ); // noise
|
||||
WRITE_BYTE( bRed ); // r, g, b
|
||||
WRITE_BYTE( bGreen ); // r, g, b
|
||||
WRITE_BYTE( bBlue ); // r, g, b
|
||||
WRITE_BYTE( 255 ); // brightness
|
||||
WRITE_BYTE( 0 ); // speed
|
||||
MESSAGE_END();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void UTIL_DrawBeamPoints( Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue )
|
||||
{
|
||||
NDebugOverlay::Line( vecStart, vecEnd, bRed, bGreen, bBlue, true, 0.1f );
|
||||
|
||||
/*
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecStart );
|
||||
WRITE_BYTE( TE_BEAMPOINTS );
|
||||
WRITE_COORD( vecStart.x );
|
||||
WRITE_COORD( vecStart.y );
|
||||
WRITE_COORD( vecStart.z );
|
||||
WRITE_COORD( vecEnd.x );
|
||||
WRITE_COORD( vecEnd.y );
|
||||
WRITE_COORD( vecEnd.z );
|
||||
WRITE_SHORT( s_iBeamSprite );
|
||||
WRITE_BYTE( 0 ); // startframe
|
||||
WRITE_BYTE( 0 ); // framerate
|
||||
WRITE_BYTE( iLifetime ); // life
|
||||
WRITE_BYTE( 10 ); // width
|
||||
WRITE_BYTE( 0 ); // noise
|
||||
WRITE_BYTE( bRed ); // r, g, b
|
||||
WRITE_BYTE( bGreen ); // r, g, b
|
||||
WRITE_BYTE( bBlue ); // r, g, b
|
||||
WRITE_BYTE( 255 ); // brightness
|
||||
WRITE_BYTE( 0 ); // speed
|
||||
MESSAGE_END();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void CONSOLE_ECHO( char * pszMsg, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
static char szStr[1024];
|
||||
|
||||
va_start( argptr, pszMsg );
|
||||
vsprintf( szStr, pszMsg, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
Msg( "%s", szStr );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void BotPrecache( void )
|
||||
{
|
||||
s_iBeamSprite = CBaseEntity::PrecacheModel( "sprites/smoke.vmt" );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
#define COS_TABLE_SIZE 256
|
||||
static float cosTable[ COS_TABLE_SIZE ];
|
||||
|
||||
void InitBotTrig( void )
|
||||
{
|
||||
for( int i=0; i<COS_TABLE_SIZE; ++i )
|
||||
{
|
||||
float angle = (float)(2.0f * M_PI * i / (float)(COS_TABLE_SIZE-1));
|
||||
cosTable[i] = (float)cos( angle );
|
||||
}
|
||||
}
|
||||
|
||||
float BotCOS( float angle )
|
||||
{
|
||||
angle = AngleNormalizePositive( angle );
|
||||
int i = (int)( angle * (COS_TABLE_SIZE-1) / 360.0f );
|
||||
return cosTable[i];
|
||||
}
|
||||
|
||||
float BotSIN( float angle )
|
||||
{
|
||||
angle = AngleNormalizePositive( angle - 90 );
|
||||
int i = (int)( angle * (COS_TABLE_SIZE-1) / 360.0f );
|
||||
return cosTable[i];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Send a "hint" message to all players, dead or alive.
|
||||
*/
|
||||
void HintMessageToAllPlayers( const char *message )
|
||||
{
|
||||
hudtextparms_t textParms;
|
||||
|
||||
textParms.x = -1.0f;
|
||||
textParms.y = -1.0f;
|
||||
textParms.fadeinTime = 1.0f;
|
||||
textParms.fadeoutTime = 5.0f;
|
||||
textParms.holdTime = 5.0f;
|
||||
textParms.fxTime = 0.0f;
|
||||
textParms.r1 = 100;
|
||||
textParms.g1 = 255;
|
||||
textParms.b1 = 100;
|
||||
textParms.r2 = 255;
|
||||
textParms.g2 = 255;
|
||||
textParms.b2 = 255;
|
||||
textParms.effect = 0;
|
||||
textParms.channel = 0;
|
||||
|
||||
UTIL_HudMessageAll( textParms, message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if moving from "start" to "finish" will cross a player's line of fire.
|
||||
* The path from "start" to "finish" is assumed to be a straight line.
|
||||
* "start" and "finish" are assumed to be points on the ground.
|
||||
*/
|
||||
bool IsCrossingLineOfFire( const Vector &start, const Vector &finish, CBaseEntity *ignore, int ignoreTeam )
|
||||
{
|
||||
for ( int p=1; p <= gpGlobals->maxClients; ++p )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( p ) );
|
||||
|
||||
if (!IsEntityValid( player ))
|
||||
continue;
|
||||
|
||||
if (player == ignore)
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (ignoreTeam && player->GetTeamNumber() == ignoreTeam)
|
||||
continue;
|
||||
|
||||
// compute player's unit aiming vector
|
||||
Vector viewForward;
|
||||
AngleVectors( player->GetFinalAimAngle(), &viewForward );
|
||||
|
||||
const float longRange = 5000.0f;
|
||||
Vector playerOrigin = GetCentroid( player );
|
||||
Vector playerTarget = playerOrigin + longRange * viewForward;
|
||||
|
||||
Vector result( 0, 0, 0 );
|
||||
if (IsIntersecting2D( start, finish, playerOrigin, playerTarget, &result ))
|
||||
{
|
||||
// simple check to see if intersection lies in the Z range of the path
|
||||
float loZ, hiZ;
|
||||
|
||||
if (start.z < finish.z)
|
||||
{
|
||||
loZ = start.z;
|
||||
hiZ = finish.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
loZ = finish.z;
|
||||
hiZ = start.z;
|
||||
}
|
||||
|
||||
if (result.z >= loZ && result.z <= hiZ + HumanHeight)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Performs a simple case-insensitive string comparison, honoring trailing * wildcards
|
||||
*/
|
||||
bool WildcardMatch( const char *query, const char *test )
|
||||
{
|
||||
if ( !query || !test )
|
||||
return false;
|
||||
|
||||
while ( *test && *query )
|
||||
{
|
||||
char nameChar = *test;
|
||||
char queryChar = *query;
|
||||
if ( tolower(nameChar) != tolower(queryChar) ) // case-insensitive
|
||||
break;
|
||||
++test;
|
||||
++query;
|
||||
}
|
||||
|
||||
if ( *query == 0 && *test == 0 )
|
||||
return true;
|
||||
|
||||
// Support trailing *
|
||||
if ( *query == '*' )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BOT_UTIL_H
|
||||
#define BOT_UTIL_H
|
||||
|
||||
|
||||
#include "convar.h"
|
||||
#include "util.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
enum PriorityType
|
||||
{
|
||||
PRIORITY_LOW, PRIORITY_MEDIUM, PRIORITY_HIGH, PRIORITY_UNINTERRUPTABLE
|
||||
};
|
||||
|
||||
|
||||
extern ConVar cv_bot_traceview;
|
||||
extern ConVar cv_bot_stop;
|
||||
extern ConVar cv_bot_show_nav;
|
||||
extern ConVar cv_bot_walk;
|
||||
extern ConVar cv_bot_difficulty;
|
||||
extern ConVar cv_bot_debug;
|
||||
extern ConVar cv_bot_debug_target;
|
||||
extern ConVar cv_bot_quota;
|
||||
extern ConVar cv_bot_quota_mode;
|
||||
extern ConVar cv_bot_prefix;
|
||||
extern ConVar cv_bot_allow_rogues;
|
||||
extern ConVar cv_bot_allow_pistols;
|
||||
extern ConVar cv_bot_allow_shotguns;
|
||||
extern ConVar cv_bot_allow_sub_machine_guns;
|
||||
extern ConVar cv_bot_allow_rifles;
|
||||
extern ConVar cv_bot_allow_machine_guns;
|
||||
extern ConVar cv_bot_allow_grenades;
|
||||
extern ConVar cv_bot_allow_snipers;
|
||||
extern ConVar cv_bot_allow_shield;
|
||||
extern ConVar cv_bot_join_team;
|
||||
extern ConVar cv_bot_join_after_player;
|
||||
extern ConVar cv_bot_auto_vacate;
|
||||
extern ConVar cv_bot_zombie;
|
||||
extern ConVar cv_bot_defer_to_human_goals;
|
||||
extern ConVar cv_bot_defer_to_human_items;
|
||||
extern ConVar cv_bot_chatter;
|
||||
extern ConVar cv_bot_profile_db;
|
||||
extern ConVar cv_bot_dont_shoot;
|
||||
extern ConVar cv_bot_eco_limit;
|
||||
extern ConVar cv_bot_auto_follow;
|
||||
extern ConVar cv_bot_flipout;
|
||||
#if CS_CONTROLLABLE_BOTS_ENABLED
|
||||
extern ConVar cv_bot_controllable;
|
||||
#endif
|
||||
|
||||
#define RAD_TO_DEG( deg ) ((deg) * 180.0 / M_PI)
|
||||
#define DEG_TO_RAD( rad ) ((rad) * M_PI / 180.0)
|
||||
|
||||
#define SIGN( num ) (((num) < 0) ? -1 : 1)
|
||||
#define ABS( num ) (SIGN(num) * (num))
|
||||
|
||||
|
||||
#define CREATE_FAKE_CLIENT ( *g_engfuncs.pfnCreateFakeClient )
|
||||
#define GET_USERINFO ( *g_engfuncs.pfnGetInfoKeyBuffer )
|
||||
#define SET_KEY_VALUE ( *g_engfuncs.pfnSetKeyValue )
|
||||
#define SET_CLIENT_KEY_VALUE ( *g_engfuncs.pfnSetClientKeyValue )
|
||||
|
||||
class BotProfile;
|
||||
|
||||
extern void BotPrecache( void );
|
||||
extern int UTIL_ClientsInGame( void );
|
||||
|
||||
extern bool UTIL_IsNameTaken( const char *name, bool ignoreHumans = false ); ///< return true if given name is already in use by another player
|
||||
|
||||
#define IS_ALIVE true
|
||||
extern int UTIL_HumansOnTeam( int teamID, bool isAlive = false );
|
||||
|
||||
extern int UTIL_BotsInGame( void );
|
||||
extern bool UTIL_IsTeamAllBots( int team );
|
||||
extern void UTIL_DrawBeamFromEnt( int iIndex, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue );
|
||||
extern void UTIL_DrawBeamPoints( Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue );
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, float *distance = NULL );
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, int team, float *distance = NULL );
|
||||
extern bool UTIL_KickBotFromTeam( int kickTeam, bool bQueue = false ); ///< kick a bot from the given team. If no bot exists on the team, return false, if bQueue is true kick will occur at round restart
|
||||
|
||||
extern bool UTIL_IsVisibleToTeam( const Vector &spot, int team ); ///< return true if anyone on the given team can see the given spot
|
||||
extern bool UTIL_IsRandomSpawnFarEnoughAwayFromTeam( const Vector &spot, int team ); ///< return true if this spot is far enough away from everyone on specified team defined via
|
||||
|
||||
/// return true if moving from "start" to "finish" will cross a player's line of fire.
|
||||
extern bool IsCrossingLineOfFire( const Vector &start, const Vector &finish, CBaseEntity *ignore = NULL, int ignoreTeam = 0 );
|
||||
|
||||
extern void UTIL_ConstructBotNetName(char *name, int nameLength, const BotProfile *bot); ///< constructs a complete name including prefix
|
||||
|
||||
/**
|
||||
* Echos text to the console, and prints it on the client's screen. This is NOT tied to the developer cvar.
|
||||
* If you are adding debugging output in cstrike, use UTIL_DPrintf() (debug.h) instead.
|
||||
*/
|
||||
extern void CONSOLE_ECHO( char * pszMsg, ... );
|
||||
|
||||
extern void InitBotTrig( void );
|
||||
extern float BotCOS( float angle );
|
||||
extern float BotSIN( float angle );
|
||||
|
||||
extern void HintMessageToAllPlayers( const char *message );
|
||||
|
||||
bool WildcardMatch( const char *query, const char *test ); ///< Performs a simple case-insensitive string comparison, honoring trailing * wildcards
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if the given entity is valid
|
||||
*/
|
||||
inline bool IsEntityValid( CBaseEntity *entity )
|
||||
{
|
||||
if (entity == NULL)
|
||||
return false;
|
||||
|
||||
if (FNullEnt( entity->edict() ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Given two line segments: startA to endA, and startB to endB, return true if they intesect
|
||||
* and put the intersection point in "result".
|
||||
* Note that this computes the intersection of the 2D (x,y) projection of the line segments.
|
||||
*/
|
||||
inline bool IsIntersecting2D( const Vector &startA, const Vector &endA,
|
||||
const Vector &startB, const Vector &endB,
|
||||
Vector *result = NULL )
|
||||
{
|
||||
float denom = (endA.x - startA.x) * (endB.y - startB.y) - (endA.y - startA.y) * (endB.x - startB.x);
|
||||
if (denom == 0.0f)
|
||||
{
|
||||
// parallel
|
||||
return false;
|
||||
}
|
||||
|
||||
float numS = (startA.y - startB.y) * (endB.x - startB.x) - (startA.x - startB.x) * (endB.y - startB.y);
|
||||
if (numS == 0.0f)
|
||||
{
|
||||
// coincident
|
||||
return true;
|
||||
}
|
||||
|
||||
float numT = (startA.y - startB.y) * (endA.x - startA.x) - (startA.x - startB.x) * (endA.y - startA.y);
|
||||
|
||||
float s = numS / denom;
|
||||
if (s < 0.0f || s > 1.0f)
|
||||
{
|
||||
// intersection is not within line segment of startA to endA
|
||||
return false;
|
||||
}
|
||||
|
||||
float t = numT / denom;
|
||||
if (t < 0.0f || t > 1.0f)
|
||||
{
|
||||
// intersection is not within line segment of startB to endB
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute intesection point
|
||||
if (result)
|
||||
*result = startA + s * (endA - startA);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// improv_locomotor.h
|
||||
// Interface for moving Improvs along computed paths
|
||||
// Author: Michael Booth, July 2004
|
||||
|
||||
#ifndef _IMPROV_LOCOMOTOR_H_
|
||||
#define _IMPROV_LOCOMOTOR_H_
|
||||
|
||||
// TODO: Remove duplicate methods from CImprov, and update CImprov to use this class
|
||||
|
||||
/**
|
||||
* A locomotor owns the movement of an Improv
|
||||
*/
|
||||
class CImprovLocomotor
|
||||
{
|
||||
public:
|
||||
virtual const Vector &GetCentroid( void ) const = 0;
|
||||
virtual const Vector &GetFeet( void ) const = 0; ///< return position of "feet" - point below centroid of improv at feet level
|
||||
virtual const Vector &GetEyes( void ) const = 0;
|
||||
virtual float GetMoveAngle( void ) const = 0; ///< return direction of movement
|
||||
|
||||
virtual CNavArea *GetLastKnownArea( void ) const = 0;
|
||||
virtual bool GetSimpleGroundHeightWithFloor( const Vector &pos, float *height, Vector *normal = NULL ) = 0; ///< find "simple" ground height, treating current nav area as part of the floor
|
||||
|
||||
virtual void Crouch( void ) = 0;
|
||||
virtual void StandUp( void ) = 0; ///< "un-crouch"
|
||||
virtual bool IsCrouching( void ) const = 0;
|
||||
|
||||
virtual void Jump( void ) = 0; ///< initiate a jump
|
||||
virtual bool IsJumping( void ) const = 0;
|
||||
|
||||
virtual void Run( void ) = 0; ///< set movement speed to running
|
||||
virtual void Walk( void ) = 0; ///< set movement speed to walking
|
||||
virtual bool IsRunning( void ) const = 0;
|
||||
|
||||
virtual void StartLadder( const CNavLadder *ladder, NavTraverseType how, const Vector &approachPos, const Vector &departPos ) = 0; ///< invoked when a ladder is encountered while following a path
|
||||
virtual bool TraverseLadder( const CNavLadder *ladder, NavTraverseType how, const Vector &approachPos, const Vector &departPos, float deltaT ) = 0; ///< traverse given ladder
|
||||
virtual bool IsUsingLadder( void ) const = 0;
|
||||
|
||||
enum MoveToFailureType
|
||||
{
|
||||
FAIL_INVALID_PATH,
|
||||
FAIL_STUCK,
|
||||
FAIL_FELL_OFF,
|
||||
};
|
||||
virtual void TrackPath( const Vector &pathGoal, float deltaT ) = 0; ///< move along path by following "pathGoal"
|
||||
virtual void OnMoveToSuccess( const Vector &goal ) { } ///< invoked when an improv reaches its MoveTo goal
|
||||
virtual void OnMoveToFailure( const Vector &goal, MoveToFailureType reason ) { } ///< invoked when an improv fails to reach a MoveTo goal
|
||||
};
|
||||
|
||||
#endif // _IMPROV_LOCOMOTOR_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// nav_path.h
|
||||
// Navigation Path encapsulation
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), November 2003
|
||||
|
||||
#ifndef _NAV_PATH_H_
|
||||
#define _NAV_PATH_H_
|
||||
|
||||
#include "cs_nav_area.h"
|
||||
#include "bot_util.h"
|
||||
|
||||
class CImprovLocomotor;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The CNavPath class encapsulates a path through space
|
||||
*/
|
||||
class CNavPath
|
||||
{
|
||||
public:
|
||||
CNavPath( void )
|
||||
{
|
||||
m_segmentCount = 0;
|
||||
}
|
||||
|
||||
struct PathSegment
|
||||
{
|
||||
CNavArea *area; ///< the area along the path
|
||||
NavTraverseType how; ///< how to enter this area from the previous one
|
||||
Vector pos; ///< our movement goal position at this point in the path
|
||||
const CNavLadder *ladder; ///< if "how" refers to a ladder, this is it
|
||||
};
|
||||
|
||||
const PathSegment * operator[] ( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; }
|
||||
const PathSegment *GetSegment( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; }
|
||||
int GetSegmentCount( void ) const { return m_segmentCount; }
|
||||
const Vector &GetEndpoint( void ) const { return m_path[ m_segmentCount-1 ].pos; }
|
||||
bool IsAtEnd( const Vector &pos ) const; ///< return true if position is at the end of the path
|
||||
|
||||
float GetLength( void ) const; ///< return length of path from start to finish
|
||||
bool GetPointAlongPath( float distAlong, Vector *pointOnPath ) const; ///< return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end
|
||||
|
||||
/// return the node index closest to the given distance along the path without going over - returns (-1) if error
|
||||
int GetSegmentIndexAlongPath( float distAlong ) const;
|
||||
|
||||
bool IsValid( void ) const { return (m_segmentCount > 0); }
|
||||
void Invalidate( void ) { m_segmentCount = 0; }
|
||||
|
||||
void Draw( const Vector &color = Vector( 1.0f, 0.3f, 0 ) ); ///< draw the path for debugging
|
||||
|
||||
/// compute closest point on path to given point
|
||||
bool FindClosestPointOnPath( const Vector *worldPos, int startIndex, int endIndex, Vector *close ) const;
|
||||
|
||||
void Optimize( void );
|
||||
|
||||
/**
|
||||
* Compute shortest path from 'start' to 'goal' via A* algorithm.
|
||||
* If returns true, path was build to the goal position.
|
||||
* If returns false, path may either be invalid (use IsValid() to check), or valid but
|
||||
* doesn't reach all the way to the goal.
|
||||
*/
|
||||
template< typename CostFunctor >
|
||||
bool Compute( const Vector &start, const Vector &goal, CostFunctor &costFunc )
|
||||
{
|
||||
Invalidate();
|
||||
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( start + Vector( 0.0f, 0.0f, 1.0f ) );
|
||||
if (startArea == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CNavArea *goalArea = TheNavMesh->GetNavArea( goal );
|
||||
|
||||
// if we are already in the goal area, build trivial path
|
||||
if (startArea == goalArea)
|
||||
{
|
||||
BuildTrivialPath( start, goal );
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure path end position is on the ground
|
||||
Vector pathEndPosition = goal;
|
||||
if (goalArea)
|
||||
{
|
||||
pathEndPosition.z = goalArea->GetZ( pathEndPosition );
|
||||
}
|
||||
else
|
||||
{
|
||||
TheNavMesh->GetGroundHeight( pathEndPosition, &pathEndPosition.z );
|
||||
}
|
||||
|
||||
//
|
||||
// Compute shortest path to goal
|
||||
//
|
||||
CNavArea *closestArea;
|
||||
bool pathResult = NavAreaBuildPath( startArea, goalArea, &goal, costFunc, &closestArea );
|
||||
|
||||
//
|
||||
// Build path by following parent links
|
||||
//
|
||||
|
||||
// get count
|
||||
int count = 0;
|
||||
CNavArea *area;
|
||||
for( area = closestArea; area; area = area->GetParent() )
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
// save room for endpoint
|
||||
if (count > MAX_PATH_SEGMENTS-1)
|
||||
{
|
||||
count = MAX_PATH_SEGMENTS-1;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
BuildTrivialPath( start, goal );
|
||||
return true;
|
||||
}
|
||||
|
||||
// build path
|
||||
m_segmentCount = count;
|
||||
for( area = closestArea; count && area; area = area->GetParent() )
|
||||
{
|
||||
--count;
|
||||
m_path[ count ].area = area;
|
||||
m_path[ count ].how = area->GetParentHow();
|
||||
}
|
||||
|
||||
// compute path positions
|
||||
if (ComputePathPositions() == false)
|
||||
{
|
||||
//PrintIfWatched( "CNavPath::Compute: Error building path\n" );
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// append path end position
|
||||
m_path[ m_segmentCount ].area = closestArea;
|
||||
m_path[ m_segmentCount ].pos = pathEndPosition;
|
||||
m_path[ m_segmentCount ].ladder = NULL;
|
||||
m_path[ m_segmentCount ].how = NUM_TRAVERSE_TYPES;
|
||||
++m_segmentCount;
|
||||
|
||||
return pathResult;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { MAX_PATH_SEGMENTS = 256 };
|
||||
PathSegment m_path[ MAX_PATH_SEGMENTS ];
|
||||
int m_segmentCount;
|
||||
|
||||
bool ComputePathPositions( void ); ///< determine actual path positions
|
||||
bool BuildTrivialPath( const Vector &start, const Vector &goal ); ///< utility function for when start and goal are in the same area
|
||||
|
||||
int FindNextOccludedNode( int anchor ); ///< used by Optimize()
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Monitor improv movement and determine if it becomes stuck
|
||||
*/
|
||||
class CStuckMonitor
|
||||
{
|
||||
public:
|
||||
CStuckMonitor( void );
|
||||
|
||||
void Reset( void );
|
||||
void Update( CImprovLocomotor *improv );
|
||||
bool IsStuck( void ) const { return m_isStuck; }
|
||||
|
||||
float GetDuration( void ) const { return (m_isStuck) ? m_stuckTimer.GetElapsedTime() : 0.0f; }
|
||||
|
||||
private:
|
||||
bool m_isStuck; ///< if true, we are stuck
|
||||
Vector m_stuckSpot; ///< the location where we became stuck
|
||||
IntervalTimer m_stuckTimer; ///< how long we have been stuck
|
||||
|
||||
enum { MAX_VEL_SAMPLES = 5 };
|
||||
float m_avgVel[ MAX_VEL_SAMPLES ];
|
||||
int m_avgVelIndex;
|
||||
int m_avgVelCount;
|
||||
Vector m_lastCentroid;
|
||||
float m_lastTime;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The CNavPathFollower class implements path following behavior
|
||||
*/
|
||||
class CNavPathFollower
|
||||
{
|
||||
public:
|
||||
CNavPathFollower( void );
|
||||
|
||||
void SetImprov( CImprovLocomotor *improv ) { m_improv = improv; }
|
||||
void SetPath( CNavPath *path ) { m_path = path; }
|
||||
|
||||
void Reset( void );
|
||||
|
||||
#define DONT_AVOID_OBSTACLES false
|
||||
void Update( float deltaT, bool avoidObstacles = true ); ///< move improv along path
|
||||
void Debug( bool status ) { m_isDebug = status; } ///< turn debugging on/off
|
||||
|
||||
bool IsStuck( void ) const { return m_stuckMonitor.IsStuck(); } ///< return true if improv is stuck
|
||||
void ResetStuck( void ) { m_stuckMonitor.Reset(); }
|
||||
float GetStuckDuration( void ) const { return m_stuckMonitor.GetDuration(); } ///< return how long we've been stuck
|
||||
|
||||
void FeelerReflexAdjustment( Vector *goalPosition, float height = -1.0f ); ///< adjust goal position if "feelers" are touched
|
||||
|
||||
private:
|
||||
CImprovLocomotor *m_improv; ///< who is doing the path following
|
||||
|
||||
CNavPath *m_path; ///< the path being followed
|
||||
|
||||
int m_segmentIndex; ///< the point on the path the improv is moving towards
|
||||
int m_behindIndex; ///< index of the node on the path just behind us
|
||||
Vector m_goal; ///< last computed follow goal
|
||||
|
||||
bool m_isLadderStarted;
|
||||
|
||||
bool m_isDebug;
|
||||
|
||||
int FindOurPositionOnPath( Vector *close, bool local ) const; ///< return the closest point to our current position on current path
|
||||
int FindPathPoint( float aheadRange, Vector *point, int *prevIndex ); ///< compute a point a fixed distance ahead along our path.
|
||||
|
||||
CStuckMonitor m_stuckMonitor;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // _NAV_PATH_H_
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: dll-agnostic routines (no dll dependencies here)
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Matthew D. Campbell (matt@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include "shared_util.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static char s_shared_token[ 1500 ];
|
||||
static char s_shared_quote = '\"';
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
char * SharedVarArgs(PRINTF_FORMAT_STRING const char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
const int BufLen = 1024;
|
||||
const int NumBuffers = 4;
|
||||
static char string[NumBuffers][BufLen];
|
||||
static int curstring = 0;
|
||||
|
||||
curstring = ( curstring + 1 ) % NumBuffers;
|
||||
|
||||
va_start (argptr, format);
|
||||
_vsnprintf( string[curstring], BufLen, format, argptr );
|
||||
va_end (argptr);
|
||||
|
||||
return string[curstring];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
char * BufPrintf(char *buf, int& len, PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
_vsnprintf(buf, len, fmt, argptr);
|
||||
va_end(argptr);
|
||||
// Make sure the buffer is null-terminated.
|
||||
buf[ len - 1 ] = 0;
|
||||
|
||||
len -= strlen(buf);
|
||||
return buf + strlen(buf);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
wchar_t * BufWPrintf(wchar_t *buf, int& len, PRINTF_FORMAT_STRING const wchar_t *fmt, ...)
|
||||
{
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
_vsnwprintf(buf, len, fmt, argptr);
|
||||
va_end(argptr);
|
||||
// Make sure the buffer is null-terminated.
|
||||
buf[ len - 1 ] = 0;
|
||||
|
||||
len -= wcslen(buf);
|
||||
return buf + wcslen(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
#ifdef _WIN32
|
||||
const wchar_t * NumAsWString( int val )
|
||||
{
|
||||
const int BufLen = 16;
|
||||
static wchar_t buf[BufLen];
|
||||
int len = BufLen;
|
||||
BufWPrintf( buf, len, L"%d", val );
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
// dgoodenough - PS3 needs this guy as well.
|
||||
// PS3_BUILDFIX
|
||||
#ifdef _PS3
|
||||
const wchar_t * NumAsWString( int val )
|
||||
{
|
||||
const int BufLen = 16;
|
||||
static wchar_t buf[BufLen];
|
||||
char szBuf[BufLen];
|
||||
|
||||
Q_snprintf(szBuf, BufLen, "%d", val );
|
||||
szBuf[BufLen - 1] = 0;
|
||||
for ( int i = 0; i < BufLen; ++i )
|
||||
{
|
||||
buf[i] = szBuf[i];
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const char * NumAsString( int val )
|
||||
{
|
||||
const int BufLen = 16;
|
||||
static char buf[BufLen];
|
||||
int len = BufLen;
|
||||
BufPrintf( buf, len, "%d", val );
|
||||
return buf;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the token parsed by SharedParse()
|
||||
*/
|
||||
char *SharedGetToken( void )
|
||||
{
|
||||
return s_shared_token;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the token parsed by SharedParse()
|
||||
*/
|
||||
void SharedSetQuoteChar( char c )
|
||||
{
|
||||
s_shared_quote = c;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Parse a token out of a string
|
||||
*/
|
||||
const char *SharedParse( const char *data )
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
s_shared_token[0] = 0;
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
// skip whitespace
|
||||
skipwhite:
|
||||
while ( (c = *data) <= ' ')
|
||||
{
|
||||
if (c == 0)
|
||||
return NULL; // end of file;
|
||||
data++;
|
||||
}
|
||||
|
||||
// skip // comments
|
||||
if (c=='/' && data[1] == '/')
|
||||
{
|
||||
while (*data && *data != '\n')
|
||||
data++;
|
||||
goto skipwhite;
|
||||
}
|
||||
|
||||
|
||||
// handle quoted strings specially
|
||||
if (c == s_shared_quote)
|
||||
{
|
||||
data++;
|
||||
while (1)
|
||||
{
|
||||
c = *data++;
|
||||
if (c==s_shared_quote || !c)
|
||||
{
|
||||
s_shared_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
s_shared_token[len] = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
// parse single characters
|
||||
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' )
|
||||
{
|
||||
s_shared_token[len] = c;
|
||||
len++;
|
||||
s_shared_token[len] = 0;
|
||||
return data+1;
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
s_shared_token[len] = c;
|
||||
data++;
|
||||
len++;
|
||||
c = *data;
|
||||
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' )
|
||||
break;
|
||||
} while (c>32);
|
||||
|
||||
s_shared_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns true if additional data is waiting to be processed on this line
|
||||
*/
|
||||
bool SharedTokenWaiting( const char *buffer )
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = buffer;
|
||||
while ( *p && *p!='\n')
|
||||
{
|
||||
if ( !V_isspace( *p ) || V_isalnum( *p ) )
|
||||
return true;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: dll-agnostic routines (no dll dependencies here)
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Matthew D. Campbell (matt@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef SHARED_UTIL_H
|
||||
#define SHARED_UTIL_H
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the token parsed by SharedParse()
|
||||
*/
|
||||
char *SharedGetToken( void );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Sets the character used to delimit quoted strings. Default is '\"'. Be sure to set it back when done.
|
||||
*/
|
||||
void SharedSetQuoteChar( char c );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Parse a token out of a string
|
||||
*/
|
||||
const char *SharedParse( const char *data );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns true if additional data is waiting to be processed on this line
|
||||
*/
|
||||
bool SharedTokenWaiting( const char *buffer );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Simple utility function to allocate memory and duplicate a string
|
||||
*/
|
||||
/*
|
||||
inline char *CloneString( const char *str )
|
||||
{
|
||||
char *cloneStr = new char [ strlen(str)+1 ];
|
||||
strcpy( cloneStr, str );
|
||||
return cloneStr;
|
||||
}*/
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Simple utility function to allocate memory and duplicate a wide string
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
extern inline wchar_t *CloneWString( const wchar_t *str );
|
||||
// {
|
||||
// wchar_t *cloneStr = new wchar_t [ wcslen(str)+1 ];
|
||||
// wcscpy( cloneStr, str );
|
||||
// return cloneStr;
|
||||
// }
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* snprintf-alike that allows multiple prints into a buffer
|
||||
*/
|
||||
char * BufPrintf(char *buf, int& len, PRINTF_FORMAT_STRING const char *fmt, ...);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* wide char version of BufPrintf
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
wchar_t * BufWPrintf(wchar_t *buf, int& len, PRINTF_FORMAT_STRING const wchar_t *fmt, ...);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* convenience function that prints an int into a static wchar_t*
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
const wchar_t * NumAsWString( int val );
|
||||
#endif
|
||||
// dgoodenough - PS3 needs this guy as well.
|
||||
// PS3_BUILDFIX
|
||||
#ifdef _PS3
|
||||
const wchar_t * NumAsWString( int val );
|
||||
#endif
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* convenience function that prints an int into a static char*
|
||||
*/
|
||||
const char * NumAsString( int val );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* convenience function that composes a string into a static char*
|
||||
*/
|
||||
char * SharedVarArgs(PRINTF_FORMAT_STRING const char *format, ...);
|
||||
|
||||
#include "tier0/memdbgoff.h"
|
||||
|
||||
#endif // SHARED_UTIL_H
|
||||
@@ -0,0 +1,60 @@
|
||||
//-------------------------------------------------------------
|
||||
// File: cs_achievement_constants.h
|
||||
// Desc: Declare contants used by achievements (mostly) in one location for simpler tweaking
|
||||
// Author: Peter Freese <peter@hiddenpath.com>
|
||||
// Date: 2009/03/11
|
||||
// Copyright: © 2009 Hidden Path Entertainment
|
||||
//-------------------------------------------------------------
|
||||
|
||||
#ifndef CS_ACHIEVEMENT_CONSTANTS_H
|
||||
#define CS_ACHIEVEMENT_CONSTANTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace AchievementConsts
|
||||
{
|
||||
const int DefaultMinOpponentsForAchievement = 5;
|
||||
const int KillingSpree_Kills = 4;
|
||||
const float KillingSpree_WindowTime = 15.0f;
|
||||
const float KillingSpreeEnder_TimeWindow = 5.0f;
|
||||
const int KillEnemyTeam_MinKills = 5;
|
||||
const int LastPlayerAlive_MinPlayersOnTeam = 5;
|
||||
const int KillsWithMultipleGuns_MinWeapons = 5;
|
||||
const float BombDefuseCloseCall_MaxTimeRemaining = 1.0f;
|
||||
const int KillLowDamage_MaxHealthLeft = 5;
|
||||
const int StillAlive_MaxHealthLeft = 10;
|
||||
const int DamageNoKill_MaxHealthLeftOnKill = 5;
|
||||
const float BombDefuseNeededKit_MaxTime = 5.0f;
|
||||
const float FastBombPlant_Time = 25.0f;
|
||||
const int KillEnemiesWhileBlind_Kills = 1;
|
||||
const int KillEnemiesWhileBlindHard_Kills = 2;
|
||||
const int SurviveGrenade_MinDamage = 80;
|
||||
const int KillWhenAtLowHealth_MaxHealth = 1;
|
||||
const int KillWhenAtMediumHealth_MaxHealth = 25;
|
||||
const int GrenadeMultiKill_MinKills = 3;
|
||||
const int BombMultiKill_MinKills = 5;
|
||||
const float FastRoundWin_Time = 30.0f;
|
||||
const int UnstoppableForce_Kills = 4;
|
||||
const int ImmovableObject_Kills = 4;
|
||||
//const int BreakPropsInRound_Props = 15;
|
||||
const int HeadshotsInRound_Kills = 5;
|
||||
const int BreakWindowsInOfficeRound_Windows = 14;
|
||||
const float FastHostageRescue_Time = 90.0f;
|
||||
const int SurviveManyAttacks_NumberDamagingPlayers = 5;
|
||||
const float KillInAir_MinimumHeight = 100.0f; //100-120 is probably best. Also used for killing while in the air
|
||||
const float KillBombPickup_MaxTime = 3.0f;
|
||||
const int WinRoundsWithoutBuying_Rounds = 10;
|
||||
const int ConcurrentDominations_MinDominations = 3;
|
||||
const int ExtendedDomination_AdditionalKills = 4;
|
||||
const int SameUniform_MinPlayers = 5;
|
||||
const int FriendsSameUniform_MinPlayers = 4;
|
||||
const float KillEnemyNearBomb_MaxDistance = 480.0f;
|
||||
const float KillEnemyNearHostage_MaxDistance = 250.0f;
|
||||
const int GrenadeDamage_MinDamage = 200;
|
||||
//const int Num_Required_Medals = 166; // earn this many medals, get the 12th xbla achievement (number of total medals displaying to user in game minus 1)
|
||||
const int Num_Medalist_Required_Medals = 100; // earn this many medals, get the 12th xbla achievement (number of total medals displaying to user in game minus 1)
|
||||
|
||||
}
|
||||
|
||||
#endif // CS_ACHIEVEMENT_CONSTANTS_H
|
||||
@@ -0,0 +1,277 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Shared CS definitions.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_ACHIEVEMENTDEFS_H
|
||||
#define CS_ACHIEVEMENTDEFS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Achievement ID Definitions
|
||||
//=============================================================================
|
||||
|
||||
// set below to 1 to enable
|
||||
#define ALL_WEARING_SAME_UNIFORM_ACHIEVEMENT 0
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CSInvalidAchievement = -1,
|
||||
|
||||
// Bomb-related Achievements
|
||||
CSBombAchievementsStart = 1000, // First bomb-related achievement
|
||||
|
||||
CSWinBombPlant,
|
||||
CSWinBombDefuse,
|
||||
CSDefuseAndNeededKit,
|
||||
CSBombDefuseCloseCall,
|
||||
CSKilledDefuser,
|
||||
CSPlantBombWithin25Seconds,
|
||||
CSKillBombPickup,
|
||||
CSBombMultikill,
|
||||
CSGooseChase,
|
||||
CSWinBombPlantAfterRecovery,
|
||||
CSDefuseDefense,
|
||||
CSPlantBombsLow,
|
||||
CSDefuseBombsLow,
|
||||
CSPlantBombsTRLow,
|
||||
CSDefuseBombsTRLow,
|
||||
|
||||
CSBombAchievementsEnd, // Must be after last bomb-related achievement
|
||||
|
||||
|
||||
// Hostage-related Achievements
|
||||
CSHostageAchievementsStart = 2000, // First hostage-related achievement
|
||||
|
||||
CSRescueAllHostagesInARound,
|
||||
CSKilledRescuer,
|
||||
CSFastHostageRescue,
|
||||
CSRescueHostagesLow,
|
||||
CSRescueHostagesMid,
|
||||
|
||||
CSHostageAchievmentEnd, // Must be after last hostage-related achievement
|
||||
|
||||
// General Kill Achievements
|
||||
CSKillAchievementsStart = 3000, // First kill-related achievement
|
||||
|
||||
CSEnemyKillsLow,
|
||||
CSEnemyKillsMed,
|
||||
CSEnemyKillsHigh,
|
||||
CSSurvivedHeadshotDueToHelmet,
|
||||
CSKillEnemyReloading,
|
||||
CSKillingSpree,
|
||||
CSKillsWithMultipleGuns,
|
||||
CSHeadshots,
|
||||
CSAvengeFriend,
|
||||
CSSurviveGrenade,
|
||||
CSDominationsLow,
|
||||
CSDominationsHigh,
|
||||
CSRevengesLow,
|
||||
CSRevengesHigh,
|
||||
CSDominationOverkillsLow,
|
||||
CSDominationOverkillsHigh,
|
||||
CSDominationOverkillsMatch,
|
||||
CSExtendedDomination,
|
||||
CSConcurrentDominations,
|
||||
CSKillEnemyBlinded,
|
||||
CSKillEnemiesWhileBlind,
|
||||
CSKillEnemiesWhileBlindHard,
|
||||
CSKillsEnemyWeapon,
|
||||
CSKillWithEveryWeapon,
|
||||
CSWinKnifeFightsLow,
|
||||
CSWinKnifeFightsHigh,
|
||||
CSKilledDefuserWithGrenade,
|
||||
CSKillSniperWithSniper,
|
||||
CSKillSniperWithKnife,
|
||||
CSHipShot,
|
||||
CSKillSnipers,
|
||||
CSKillWhenAtLowHealth,
|
||||
CSPistolRoundKnifeKill,
|
||||
CSWinDualDuel,
|
||||
CSGrenadeMultikill,
|
||||
CSKillWhileInAir,
|
||||
CSKillEnemyInAir,
|
||||
CSKillerAndEnemyInAir,
|
||||
CSKillEnemyWithFormerGun,
|
||||
CSKillTwoWithOneShot,
|
||||
CSProgressiveGameKills,
|
||||
CSSelectGameKills,
|
||||
CSBombGameKills,
|
||||
CSGunGameKillKnifer,
|
||||
CSGunGameKnifeSuicide,
|
||||
CSGunGameKnifeKillKnifer,
|
||||
CSGunGameSMGKillKnifer,
|
||||
CSFirstBulletKills,
|
||||
CSSpawnCamper,
|
||||
CSBornReady,
|
||||
|
||||
CSKillAchievementEnd, // Must be after last kill-related achievement
|
||||
|
||||
// Weapon-related Achievements
|
||||
CSWeaponAchievementsStart = 4000, // First weapon-related achievement
|
||||
|
||||
CSEnemyKillsDeagle,
|
||||
CSEnemyKillsUSP,
|
||||
CSEnemyKillsGlock,
|
||||
CSEnemyKillsP228,
|
||||
CSEnemyKillsElite,
|
||||
CSEnemyKillsFiveSeven,
|
||||
CSEnemyKillsBizon,
|
||||
CSEnemyKillsTec9,
|
||||
CSEnemyKillsTaser,
|
||||
CSEnemyKillsHKP2000,
|
||||
CSEnemyKillsP250,
|
||||
CSEnemyKillsAWP,
|
||||
CSEnemyKillsAK47,
|
||||
CSEnemyKillsM4A1,
|
||||
CSEnemyKillsAUG,
|
||||
CSEnemyKillsSG552,
|
||||
CSEnemyKillsSG550,
|
||||
CSEnemyKillsGALIL,
|
||||
CSEnemyKillsGALILAR,
|
||||
CSEnemyKillsFAMAS,
|
||||
CSEnemyKillsScout,
|
||||
CSEnemyKillsG3SG1,
|
||||
CSEnemyKillsSCAR17,
|
||||
CSEnemyKillsSCAR20,
|
||||
CSEnemyKillsSG556,
|
||||
CSEnemyKillsSSG08,
|
||||
CSEnemyKillsP90,
|
||||
CSEnemyKillsMP5NAVY,
|
||||
CSEnemyKillsTMP,
|
||||
CSEnemyKillsMAC10,
|
||||
CSEnemyKillsUMP45,
|
||||
CSEnemyKillsMP7,
|
||||
CSEnemyKillsMP9,
|
||||
CSEnemyKillsM3,
|
||||
CSEnemyKillsXM1014,
|
||||
CSEnemyKillsMag7,
|
||||
CSEnemyKillsSawedoff,
|
||||
CSEnemyKillsNova,
|
||||
CSEnemyKillsM249,
|
||||
CSEnemyKillsNegev,
|
||||
CSEnemyKillsKnife,
|
||||
CSEnemyKillsHEGrenade,
|
||||
CSEnemyKillsMolotov,
|
||||
CSMetaPistol,
|
||||
CSMetaRifle,
|
||||
CSMetaSMG,
|
||||
CSMetaShotgun,
|
||||
CSMetaWeaponMaster,
|
||||
|
||||
CSWeaponAchievementsEnd, // Must be after last weapon-related achievement
|
||||
|
||||
// General Achievements
|
||||
CSGeneralAchievementsStart = 5000, // First general achievement
|
||||
|
||||
CSWinRoundsLow,
|
||||
CSWinRoundsMed,
|
||||
CSWinRoundsHigh,
|
||||
CSGGWinRoundsLow,
|
||||
CSGGWinRoundsMed,
|
||||
CSGGWinRoundsHigh,
|
||||
CSGGWinRoundsExtreme,
|
||||
CSGGWinRoundsUltimate,
|
||||
CSGGRoundsLow,
|
||||
CSGGRoundsMed,
|
||||
CSGGRoundsHigh,
|
||||
CSMoneyEarnedLow,
|
||||
CSMoneyEarnedMed,
|
||||
CSMoneyEarnedHigh,
|
||||
CSGiveDamageLow,
|
||||
CSGiveDamageMed,
|
||||
CSGiveDamageHigh,
|
||||
CSPosthumousGrenadeKill,
|
||||
CSKillEnemyTeam,
|
||||
CSLastPlayerAlive,
|
||||
CSKillEnemyLastBullet,
|
||||
CSKillingSpreeEnder,
|
||||
CSDamageNoKill,
|
||||
CSKillLowDamage,
|
||||
CSSurviveManyAttacks,
|
||||
CSLosslessExtermination,
|
||||
CSFlawlessVictory,
|
||||
CSDecalSprays,
|
||||
CSBreakWindows,
|
||||
CSBreakProps,
|
||||
CSUnstoppableForce,
|
||||
CSImmovableObject,
|
||||
CSHeadshotsInRound,
|
||||
CSWinPistolRoundsLow,
|
||||
CSWinPistolRoundsMed,
|
||||
CSWinPistolRoundsHigh,
|
||||
CSFastRoundWin,
|
||||
CSNightvisionDamage,
|
||||
CSSilentWin,
|
||||
CSBloodlessVictory,
|
||||
CSDonateWeapons,
|
||||
CSWinRoundsWithoutBuying,
|
||||
#if(ALL_WEARING_SAME_UNIFORM_ACHIEVEMENT)
|
||||
CSSameUniform,
|
||||
#endif
|
||||
CSFriendsSameUniform,
|
||||
CSCauseFriendlyFireWithFlashbang,
|
||||
|
||||
CSGeneralAchievementsEnd, // Must be after last general achievement
|
||||
|
||||
CSWinMapAchievementsStart = 6000,
|
||||
|
||||
CSWinMapCS_ASSAULT,
|
||||
CSWinMapCS_COMPOUND,
|
||||
CSWinMapCS_HAVANA,
|
||||
CSWinMapCS_ITALY,
|
||||
CSWinMapCS_MILITIA,
|
||||
CSWinMapCS_OFFICE,
|
||||
CSWinMapDE_AZTEC,
|
||||
CSWinMapDE_CBBLE,
|
||||
CSWinMapDE_CHATEAU,
|
||||
CSWinMapDE_DUST,
|
||||
CSWinMapDE_DUST2,
|
||||
CSWinMapDE_INFERNO,
|
||||
CSWinMapDE_NUKE,
|
||||
CSWinMapDE_PIRANESI,
|
||||
CSWinMapDE_PORT,
|
||||
CSWinMapDE_PRODIGY,
|
||||
CSWinMapDE_TIDES,
|
||||
CSWinMapDE_TRAIN,
|
||||
|
||||
CSWinMatchDE_SHORTTRAIN,
|
||||
CSWinMatchDE_LAKE,
|
||||
CSWinMatchDE_SAFEHOUSE,
|
||||
CSWinMatchDE_SUGARCANE,
|
||||
CSWinMatchDE_STMARC,
|
||||
CSWinMatchDE_BANK,
|
||||
CSWinMatchDE_EMBASSY,
|
||||
CSWinMatchDE_DEPOT,
|
||||
CSWinMatchDE_VERTIGO,
|
||||
CSWinMatchDE_BALKAN,
|
||||
CSWinMatchAR_MONASTERY,
|
||||
CSWinMatchAR_SHOOTS,
|
||||
CSWinMatchAR_BAGGAGE,
|
||||
CSWinEveryGGMap,
|
||||
CSPlayEveryGGMap,
|
||||
CSGunGameProgressiveRampage,
|
||||
CSGunGameFirstKill,
|
||||
CSKillEnemyTerrTeamBeforeBombPlant,
|
||||
CSKillEnemyCTTeamBeforeBombPlant,
|
||||
CSGunGameConservationist,
|
||||
CSStillAlive,
|
||||
CSMedalist,
|
||||
|
||||
CSWinMapAchievementsEnd, //Must be after last map-based achievement
|
||||
|
||||
CSSeason1_Start = 6200,
|
||||
CSSeason1_Bronze,
|
||||
CSSeason1_Silver,
|
||||
CSSeason1_Gold,
|
||||
CSSeason1_End // Must be after last season 1 achievement
|
||||
|
||||
} eCSAchievementType;
|
||||
|
||||
|
||||
#endif // CS_ACHIEVEMENTDEFS_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user