From c86bf826e0940cb74bf3384823059f20fcf6e8de Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Tue, 5 Dec 2023 19:53:46 +0300 Subject: [PATCH 01/64] Rewrite CScriptNetPropManager --- .../shared/mapbase/vscript_singletons.cpp | 2651 +++++++++++++++-- 1 file changed, 2432 insertions(+), 219 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index c5cca45b..6cdf66df 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -14,7 +14,13 @@ #include "ammodef.h" #include "tier1/utlcommon.h" +#include "soundenvelope.h" +#include "saverestore_utlvector.h" +#include "stdstring.h" + #ifndef CLIENT_DLL +#include "ai_speech.h" +#include "ai_memory.h" #include "ai_squad.h" #endif // !CLIENT_DLL @@ -43,285 +49,2492 @@ extern IScriptManager *scriptmanager; + +#ifdef GAME_DLL + extern void SendProxy_StringT_To_String(const SendProp*, const void*, const void*, DVariant*, int, int); + extern void SendProxy_UtlVectorLength(const SendProp*, const void*, const void*, DVariant*, int, int); + class CSendProxyRecipients; + extern void* SendProxy_LengthTable(const SendProp*, const void*, const void* pData, CSendProxyRecipients*, int); + #define DataTableProxy_EHandle SendProxy_EHandleToInt + #define DataTableProxy_String SendProxy_StringToString + #define DataTableProxy_TableLength SendProxy_LengthTable + #define DataTableProxy_UtlVectorLength SendProxy_UtlVectorLength +#else + extern void RecvProxy_UtlVectorLength(const CRecvProxyData*, void*, void*); + extern void DataTableRecvProxy_LengthProxy(const RecvProp*, void**, void*, int); + #define DataTableProxy_EHandle RecvProxy_IntToEHandle + #define DataTableProxy_String RecvProxy_StringToString + #define DataTableProxy_TableLength DataTableRecvProxy_LengthProxy + #define DataTableProxy_UtlVectorLength RecvProxy_UtlVectorLength +#endif +extern ISaveRestoreOps* GetPhysObjSaveRestoreOps( PhysInterfaceId_t ); +extern ISaveRestoreOps* ActivityDataOps(); +extern ISaveRestoreOps* GetSoundSaveRestoreOps(); +extern ISaveRestoreOps* GetStdStringDataOps(); +#ifdef GAME_DLL + #define UTLVECTOR_DATAOPS( fieldType, dataType )\ + CUtlVectorDataopsInstantiator< fieldType >::GetDataOps( (CUtlVector< dataType >*)0 ) + #define IS_EHANDLE_UTLVECTOR( td )\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseEntity > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseFlex > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseAnimating > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseCombatWeapon > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBasePlayer > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CAI_BaseNPC > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CSceneEntity > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CSceneListManager > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CRagdollBoogie > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CFish > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CVGuiScreen > ) + + class CSceneListManager; + class CRagdollBoogie; + class CFish; + #ifdef _DEBUG + class CStringTableSaveRestoreOps; + extern CStringTableSaveRestoreOps g_VguiScreenStringOps; + extern INetworkStringTable *g_pStringTableVguiScreen; + extern ISaveRestoreOps *thinkcontextFuncs; + class CAI_EnemiesListSaveRestoreOps; + extern CAI_EnemiesListSaveRestoreOps g_AI_MemoryListSaveRestoreOps; + class CConceptHistoriesDataOps; + extern CConceptHistoriesDataOps g_ConceptHistoriesSaveDataOps; + #endif +#endif + //============================================================================= // Net Prop Manager // Based on L4D2 API //============================================================================= class CScriptNetPropManager { -public: +private: +#if GAME_DLL + typedef SendProp NetProp; + typedef SendTable NetTable; + typedef ServerClass NetworkClass; -#ifdef CLIENT_DLL - RecvProp *RecurseTable( RecvTable *pTable, const char *pszPropName ) + NetworkClass *GetNetworkClass( CBaseEntity* p ) { return p->GetServerClass(); } + NetTable *GetNetTable( NetworkClass* p ) { return p->m_pTable; } + + void NetworkStateChanged( CBaseEntity* p, int o ) { p->NetworkProp()->NetworkStateChanged( o ); } #else - SendProp *RecurseTable( SendTable *pTable, const char *pszPropName ) + typedef RecvProp NetProp; + typedef RecvTable NetTable; + typedef ClientClass NetworkClass; + + NetworkClass *GetNetworkClass( CBaseEntity* p ) { return p->GetClientClass(); } + NetTable *GetNetTable( NetworkClass* p ) { return p->m_pRecvTable; } + + void NetworkStateChanged( CBaseEntity*, int ) {} #endif + + int GetClassID( CBaseEntity *p ) { -#ifdef CLIENT_DLL - RecvProp *pProp = NULL; + return GetNetworkClass( p )->m_ClassID; + } + + int GetIntPropSize( NetProp *pProp ) + { + Assert( pProp->GetType() == DPT_Int ); + +#ifdef GAME_DLL + extern void SendProxy_UInt8ToInt32( const SendProp*, const void*, const void*, DVariant*, int, int ); + extern void SendProxy_UInt16ToInt32( const SendProp*, const void*, const void*, DVariant*, int, int ); + extern void SendProxy_UInt32ToInt32( const SendProp*, const void*, const void*, DVariant*, int, int ); + + SendVarProxyFn proxy = pProp->GetProxyFn(); + + if ( proxy == SendProxy_Int8ToInt32 || proxy == SendProxy_UInt8ToInt32 ) + return 8; + if ( proxy == SendProxy_Int16ToInt32 || proxy == SendProxy_UInt16ToInt32 ) + return 16; + if ( proxy == SendProxy_Int32ToInt32 || proxy == SendProxy_UInt32ToInt32 ) + return 32; + + return pProp->m_nBits; #else - SendProp *pProp = NULL; + RecvVarProxyFn proxy = pProp->GetProxyFn(); + + if ( proxy == RecvProxy_Int32ToInt8 ) + return 8; + if ( proxy == RecvProxy_Int32ToInt16 ) + return 16; + if ( proxy == RecvProxy_Int32ToInt32 ) + return 32; + + return 0; #endif - for (int i = 0; i < pTable->GetNumProps(); i++) + } + + bool IsEHandle( NetProp *pProp ) + { + return ( pProp->GetProxyFn() == DataTableProxy_EHandle ); + } + + bool IsUtlVector( NetProp *pProp ) + { +#ifdef GAME_DLL + SendVarProxyFn proxy = pProp->GetProxyFn(); +#else + RecvVarProxyFn proxy = pProp->GetProxyFn(); +#endif + + return ( proxy == DataTableProxy_UtlVectorLength ); + } + +private: + enum types + { + _INT1 = ( 1 << 0 ), + _INT8 = ( 1 << 1 ), + _INT16 = ( 1 << 2 ), + _INT32 = ( 1 << 3 ), + _FLOAT = ( 1 << 4 ), + _VEC3 = ( 1 << 5 ), + _VEC2 = ( 1 << 6 ), + _EHANDLE = ( 1 << 7 ), + _CLASSPTR = ( 1 << 8 ), + _EDICT = ( 1 << 9 ), + _CSTRING = ( 1 << 10 ), + _STRING_T = ( 1 << 11 ), + _ARRAY = ( 1 << 12 ), + _DATATABLE = ( 1 << 13 ), + + _PHYS = ( 1 << 14 ), + _STDSTRING = _CSTRING | _STRING_T, + + _DAR_EHANDLE = _EHANDLE | _ARRAY, + _DAR_CLASSPTR = _CLASSPTR | _ARRAY, + _DAR_INT = _INT32 | _ARRAY, + _DAR_FLOAT = _FLOAT | _ARRAY, + + //_MAX = ( 1 << 15 ) + }; + + // UNDONE: Special case for GetPropType() to be able to return the table/array itself + #define INDEX_GET_TYPE 0 + + #define MASK_INT_SIZE( _size ) ( ( 1 << (_size - 1) ) | ( (1 << (_size - 1)) - 1 ) ) + #define MASK_NEAREST_BYTE( _bits ) ( ( (1 << ALIGN_TO_NEAREST_BYTE(_bits)) - 1 ) & ~((1 << _bits) - 1) ) + #define ALIGN_TO_NEAREST_BYTE( _bits ) ( (_bits + 7) & ~7 ) + #define VARINFO_ARRAYSIZE_BITS 12 + + struct varinfo_t + { + int offset : 32; // actually a short + + union { - pProp = pTable->GetProp( i ); - if (pProp->GetType() == DPT_DataTable) + int mask : 32; + int stringsize : 32; + }; + + enum types datatype : 16; + + // element size in bytes + unsigned int elemsize : 8; + unsigned int arraysize : VARINFO_ARRAYSIZE_BITS; + + // Following are only used in integer netprops to handle unsigned and size casting + bool isUnsigned : 1; + bool isNotNetworked : 1; + + int GetOffset( int index ) + { + return offset + index * elemsize; + } + }; + + // Wrapper to be able to set case sensitive comparator in node insertion + class vardict_t : public CUtlDict< varinfo_t > + { + public: + vardict_t() : CUtlDict< varinfo_t >( k_eDictCompareTypeCaseSensitive ) {} + }; + + // NOTE: This is lazy and inefficient. + // Simply map highest level class id to unique caches. + CUtlVector< int > m_EntMap; + CUtlVector< vardict_t > m_VarDicts; + + varinfo_t* CacheNew( CBaseEntity *pEnt, const char *szProp ) + { + int idx = m_EntMap.Find( GetClassID( pEnt ) ); + if ( idx == m_EntMap.InvalidIndex() ) + { + // Vector indices are kept in parallel as a workaround for encapsulating maps + idx = m_EntMap.AddToTail( GetClassID( pEnt ) ); + m_VarDicts.AddToTail(); + } + + vardict_t &dict = m_VarDicts.Element( idx ); + + idx = dict.Find( szProp ); + if ( idx == dict.InvalidIndex() ) + idx = dict.Insert( szProp ); + + varinfo_t *pInfo = &dict.Element( idx ); + V_memset( pInfo, 0, sizeof( varinfo_t ) ); + return pInfo; + } + + varinfo_t* CacheFetch( CBaseEntity *pEnt, const char *szProp ) + { + int idx = m_EntMap.Find( GetClassID( pEnt ) ); + if ( idx == m_EntMap.InvalidIndex() ) + return NULL; + + vardict_t &dict = m_VarDicts.Element( idx ); + idx = dict.Find( szProp ); + if ( idx == dict.InvalidIndex() ) + return NULL; + + varinfo_t *pInfo = &dict.Element( idx ); + return pInfo; + } + +public: + ~CScriptNetPropManager() + { + PurgeCache(); + } + + void PurgeCache() + { + m_EntMap.Purge(); + m_VarDicts.Purge(); + } + +private: + typedescription_t *FindField( char *pBase, datamap_t *map, const char *szName, int *offset ) + { + if ( map->baseMap ) + { + typedescription_t* p = FindField( pBase, map->baseMap, szName, offset ); + if ( p ) + return p; + } + + typedescription_t *pFields = map->dataDesc; + int numFields = map->dataNumFields; + + for ( int i = 0; i < numFields; i++ ) + { + typedescription_t* td = &pFields[i]; + int fieldType = td->fieldType; + int fieldOffset = td->fieldOffset[ TD_OFFSET_NORMAL ]; + + if ( td->flags & (FTYPEDESC_FUNCTIONTABLE | FTYPEDESC_INPUT | FTYPEDESC_OUTPUT) ) + continue; + + if ( fieldType == FIELD_VOID || fieldType == FIELD_FUNCTION ) + continue; + + if ( !V_strcmp( td->fieldName, szName ) ) { - pProp = RecurseTable(pProp->GetDataTable(), pszPropName); - if (pProp) - return pProp; - } - else - { - if (FStrEq( pProp->GetName(), pszPropName )) - return pProp; + *offset += fieldOffset; + + if ( td->flags & FTYPEDESC_PTR ) + { + // Follow the pointer + char * const pRef = *(char**)( pBase + *offset ); + Assert( pRef ); + *offset = pRef - pBase; + } + + return td; } } return NULL; } -#ifdef CLIENT_DLL - RecvProp *RecurseNetworkClass( ClientClass *pClass, const char *pszPropName ) -#else - SendProp *RecurseNetworkClass( ServerClass *pClass, const char *pszPropName ) -#endif + NetProp *FindProp( char *pBase, NetTable *pTable, const char *szName, int *offset ) { -#ifdef CLIENT_DLL - RecvProp *pProp = RecurseTable( pClass->m_pRecvTable, pszPropName ); -#else - SendProp *pProp = RecurseTable( pClass->m_pTable, pszPropName ); -#endif - if (pProp) + int numProps = pTable->GetNumProps(); + + for ( int i = 0; i < numProps; i++ ) + { + NetProp* pProp = pTable->GetProp(i); + + if ( pProp->IsInsideArray() ) + continue; + + if ( !V_strcmp( pProp->GetName(), szName ) ) + { + *offset += pProp->GetOffset(); + return pProp; + } + + // Go into inherited fields but not member tables, they are looked up explicitly + // This is only a problem with m_AnimOverlay + if ( ( pProp->GetFlags() & SPROP_COLLAPSIBLE ) || + ( pProp->GetType() == DPT_DataTable && pProp->GetOffset() == 0 ) ) + { + // Don't go into lengthproxy + if ( pProp->GetDataTableProxyFn() == DataTableProxy_TableLength ) + continue; + + NetProp *p = FindProp( pBase + pProp->GetOffset(), pProp->GetDataTable(), szName, offset ); + if ( p ) + { + *offset += pProp->GetOffset(); + return p; + } + } + } + + return NULL; + } + + typedescription_t *FindInDataMap( char * const pBase, datamap_t *map, const char *szFullProp, int *offset ) + { + *offset = 0; + + // Look for exact match + typedescription_t *pField = FindField( pBase, map, szFullProp, offset ); + if ( pField ) + return pField; + + // Look for members + const char *pszProp = szFullProp; + const char *pszPropEnd = V_strnchr( pszProp, '.', 512 ); + if ( !pszPropEnd ) + return NULL; + do + { + // this string comes from squirrel stringtable, it can be modified + *((char*)pszPropEnd) = 0; + pField = FindField( pBase, map, pszProp, offset ); + *((char*)pszPropEnd) = '.'; + pszProp = pszPropEnd + 1; + + if ( !pField || ( map = pField->td ) == NULL ) + return NULL; + + // Look for exact match again, just in case + pField = FindField( pBase, map, pszProp, offset ); + if ( pField ) + return pField; + } while ( ( pszPropEnd = V_strnchr( pszProp, '.', 512 ) ) != NULL ); + + return FindField( pBase, map, pszProp, offset ); + } + + NetProp *FindInNetTable( char * const pBase, NetTable *pTable, const char *szFullProp, int *offset ) + { + *offset = 0; + + // Look for exact match + NetProp *pProp = FindProp( pBase, pTable, szFullProp, offset ); + if ( pProp ) return pProp; - if (pClass->m_pNext) - return RecurseNetworkClass( pClass->m_pNext, pszPropName ); - else + // Look for members + const char *pszProp = szFullProp; + const char *pszPropEnd = V_strnchr( pszProp, '.', 512 ); + if ( !pszPropEnd ) return NULL; + do + { + // this string comes from squirrel stringtable, it can be modified + *((char*)pszPropEnd) = 0; + pProp = FindProp( pBase, pTable, pszProp, offset ); + *((char*)pszPropEnd) = '.'; + pszProp = pszPropEnd + 1; + + if ( !pProp || ( pTable = pProp->GetDataTable() ) == NULL ) + return NULL; + + // Look for exact match again for fields such as m_Local{m_skybox3d.scale} + pProp = FindProp( pBase, pTable, pszProp, offset ); + if ( pProp ) + return pProp; + } while ( ( pszPropEnd = V_strnchr( pszProp, '.', 512 ) ) != NULL ); + + return FindProp( pBase, pTable, pszProp, offset ); } + // Searches NetTable first to handle overwritten member network variables - see + // CPlayerResource::m_iHealth and CBaseEntity::m_iHealth + varinfo_t *GetVarInfo( CBaseEntity *pEnt, const char *szProp, int index ) + { + int offset = 0; + NetTable *pTable = GetNetTable( GetNetworkClass( pEnt ) ); + NetProp *pProp = FindInNetTable( (char*)pEnt, pTable, szProp, &offset ); + if ( pProp ) + { + +#define SetVarInfo()\ + varinfo_t *pInfo = CacheNew( pEnt, szProp );\ + pInfo->isNotNetworked = 0;\ + pInfo->elemsize = pProp->GetElementStride();\ + pInfo->arraysize = pProp->GetNumElements();\ + pInfo->offset = offset; + + switch ( pProp->GetType() ) + { + case DPT_Int: + { + if ( IsUtlVector( pProp ) ) + { + return NULL; + } + + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + + if ( IsEHandle( pProp ) ) + { + Assert( pProp->GetElementStride() == sizeof(int) || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_EHANDLE; + return pInfo; + } + else + { + const int size = GetIntPropSize( pProp ); #ifdef CLIENT_DLL - RecvProp *GetPropByName( CBaseEntity *pEnt, const char *pszPropName ) - { - if (pEnt) - { - return RecurseNetworkClass( pEnt->GetClientClass(), pszPropName ); - } - - return NULL; - } -#else - SendProp *GetPropByName( CBaseEntity *pEnt, const char *pszPropName ) - { - if (pEnt) - { - return RecurseNetworkClass( pEnt->GetServerClass(), pszPropName ); - } - - return NULL; - } + // Client might be reading any amount of bits in a custom RecvProxy + // Break and check the datamaps + if ( size == 0 ) + break; #endif + Assert( size <= pProp->GetElementStride() || pProp->GetElementStride() < 0 ); - int GetPropArraySize( HSCRIPT hEnt, const char *pszPropName ) + SetVarInfo(); + pInfo->mask = MASK_INT_SIZE( size ); + pInfo->datatype = types::_INT32; + return pInfo; + } + } + case DPT_Float: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + Assert( pProp->GetElementStride() == sizeof(float) || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case DPT_Vector: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + Assert( pProp->GetElementStride() == sizeof(float)*3 || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_VEC3; + return pInfo; + } + case DPT_VectorXY: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + Assert( pProp->GetElementStride() == sizeof(float)*2 || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_VEC2; + return pInfo; + } + case DPT_String: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + + SetVarInfo(); +#ifdef GAME_DLL + pInfo->stringsize = 0; +#else + pInfo->stringsize = pProp->m_StringBufferSize; +#endif +#ifdef GAME_DLL + if ( pProp->GetProxyFn() == SendProxy_StringT_To_String ) + { + pInfo->datatype = types::_STRING_T; + } + else +#endif + { + Assert( pProp->GetProxyFn() == DataTableProxy_String ); + pInfo->datatype = types::_CSTRING; + } + return pInfo; + } + case DPT_DataTable: + { + NetTable* pArray = pProp->GetDataTable(); + + if ( V_strcmp( pProp->GetName(), pArray->GetName() ) != 0 ) + { + Warning( "DT is not an array! %s(%s)\n", pProp->GetName(), pArray->GetName() ); + return NULL; + } + + if ( index < 0 || index >= pArray->GetNumProps() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + pProp = pArray->GetProp( index ); + + switch ( pProp->GetType() ) + { + case DPT_Int: + { + if ( IsEHandle( pProp ) ) + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(int); + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_EHANDLE; + return pInfo; + } + else + { + const int size = GetIntPropSize( pProp ); +#ifdef CLIENT_DLL + // Client might be reading any amount of bits in a custom RecvProxy + // Break and check the datamaps + if ( size == 0 ) + break; +#endif + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + + if ( pArray->GetNumProps() > 1 ) + { + pInfo->elemsize = pArray->GetProp(1)->GetOffset() - pArray->GetProp(0)->GetOffset(); + } + else + { + // Doesn't matter for an array of a single element + pInfo->elemsize = 0; + } + + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->mask = MASK_INT_SIZE( size ); + pInfo->datatype = types::_INT32; + return pInfo; + } + } + case DPT_Float: + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(float); + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case DPT_Vector: + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(float)*3; + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_VEC3; + return pInfo; + } + case DPT_VectorXY: + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(float)*2; + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_VEC2; + return pInfo; + } + case DPT_DataTable: + { + AssertMsg( 0, "DT in DT" ); + return NULL; + } + case DPT_Array: + { + AssertMsg( 0, "Array in DT" ); + return NULL; + } + case DPT_String: + { + AssertMsg( 0, "String in DT" ); + return NULL; + } + default: UNREACHABLE(); + } +#ifdef CLIENT_DLL + // DPT_Int can break into here for datamap fallback + break; +#else + UNREACHABLE(); +#endif + } // DPT_DataTable + case DPT_Array: + { + Assert( pProp->GetArrayProp() ); + + NetProp *pArray = pProp->GetArrayProp(); + offset += pArray->GetOffset(); + + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + switch ( pArray->GetType() ) + { + case DPT_Int: + { + Assert( index == 0 || pProp->GetElementStride() > 0 ); + + if ( IsEHandle( pArray ) ) + { + SetVarInfo(); + pInfo->datatype = types::_EHANDLE; + return pInfo; + } + else + { + const int size = GetIntPropSize( pArray ); +#ifdef CLIENT_DLL + // Client might be reading any amount of bits in a custom RecvProxy + // Break and check the datamaps + if ( size == 0 ) + break; +#endif + SetVarInfo(); + pInfo->mask = MASK_INT_SIZE( size ); + pInfo->datatype = types::_INT32; + return pInfo; + } + } + case DPT_Float: + { + SetVarInfo(); + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case DPT_Vector: + { + SetVarInfo(); + pInfo->datatype = types::_VEC3; + return pInfo; + } + case DPT_VectorXY: + { + SetVarInfo(); + pInfo->datatype = types::_VEC2; + return pInfo; + } + case DPT_String: + { + AssertMsg( 0, "String array not implemented" ); + return NULL; + } + case DPT_Array: + case DPT_DataTable: AssertMsg( 0, "DT in array" ); + default: UNREACHABLE(); + } +#ifdef CLIENT_DLL + // DPT_Int can break into here for datamap fallback + break; +#else + UNREACHABLE(); +#endif + } // DPT_Array + default: UNREACHABLE(); + } + // ambigious int size on client, check the datamaps +#undef SetVarInfo + } + + datamap_t *map = pEnt->GetDataDescMap(); + typedescription_t *pField = FindInDataMap( (char*)pEnt, map, szProp, &offset ); + if ( pField ) + { +#ifdef CLIENT_DLL +find_field: +#endif + if ( index < 0 || index >= pField->fieldSize ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + +#define SetVarInfo()\ + varinfo_t *pInfo = CacheNew( pEnt, szProp );\ + pInfo->isNotNetworked = 1;\ + pInfo->elemsize = pField->fieldSizeInBytes / pField->fieldSize;\ + pInfo->arraysize = pField->fieldSize;\ + pInfo->offset = offset; + + switch ( pField->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_COLOR32: + case FIELD_TICK: + case FIELD_BOOLEAN: + case FIELD_CHARACTER: + case FIELD_SHORT: + { + SetVarInfo(); + pInfo->isUnsigned = ( pField->flags & SPROP_UNSIGNED ) != 0; + pInfo->isNotNetworked = 1; + switch ( pField->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_COLOR32: + case FIELD_TICK: + pInfo->datatype = types::_INT32; break; + case FIELD_BOOLEAN: + pInfo->datatype = types::_INT1; break; + case FIELD_CHARACTER: + Assert( pField->fieldSizeInBytes == pField->fieldSize ); + pInfo->stringsize = pField->fieldSizeInBytes; + pInfo->datatype = types::_INT8; break; + case FIELD_SHORT: + pInfo->datatype = types::_INT16; break; + default: UNREACHABLE(); + } + return pInfo; + } + case FIELD_FLOAT: + case FIELD_TIME: + { + Assert( sizeof(float) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case FIELD_EHANDLE: + { + Assert( sizeof(int) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_EHANDLE; + return pInfo; + } +#ifdef GAME_DLL + case FIELD_CLASSPTR: + { + Assert( sizeof(int*) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_CLASSPTR; + return pInfo; + } + case FIELD_EDICT: + { + Assert( sizeof(int*) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_EDICT; + return pInfo; + } +#endif + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + { + Assert( sizeof(float)*3 == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_VEC3; + return pInfo; + } + case FIELD_STRING: + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + { + SetVarInfo(); + pInfo->stringsize = 0; + pInfo->datatype = types::_STRING_T; + return pInfo; + } + case FIELD_CUSTOM: + { + if ( pField->pSaveRestoreOps == GetPhysObjSaveRestoreOps( PIID_IPHYSICSOBJECT ) ) + { + SetVarInfo(); + pInfo->datatype = types::_PHYS; + return pInfo; + } + else if ( pField->pSaveRestoreOps == ActivityDataOps() ) + { + SetVarInfo(); + pInfo->datatype = types::_INT32; + return pInfo; + } +#ifdef GAME_DLL + else if ( IS_EHANDLE_UTLVECTOR( pField ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_EHANDLE; + } + else if ( pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_CLASSPTR, CBaseEntity* ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_CLASSPTR; + } + else if ( pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_INTEGER, int ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_INT; + } + else if ( pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_FLOAT, float ) || + pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_TIME, float ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_FLOAT; + } + // Only used by CAI_PlayerAlly::m_PendingConcept + else if ( pField->pSaveRestoreOps == GetStdStringDataOps() ) + { + SetVarInfo(); + pInfo->datatype = types::_STDSTRING; + return pInfo; + } +#endif + return NULL; + } + case FIELD_EMBEDDED: + return NULL; + default: + AssertMsg( 0, "Unknown type %d\n", pField->fieldType ); + return NULL; + } + UNREACHABLE(); +#undef SetVarInfo + } +#ifdef CLIENT_DLL + else + { + map = pEnt->GetPredDescMap(); + pField = FindInDataMap( (char*)pEnt, map, szProp, &offset ); + if ( pField ) + { + goto find_field; + } + } +#endif + return NULL; + } + +public: + // FIXME: Cannot get datatable/arrays at the moment + bool HasProp( HSCRIPT hEnt, const char *szProp ) { CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp) + if ( !pEnt ) + return false; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) { - // TODO: Is this what this function wants? - return pProp->GetNumElements(); + pInfo = GetVarInfo( pEnt, szProp, INDEX_GET_TYPE ); + + if ( !pInfo ) + return false; + } + + return true; + } + + // FIXME: Cannot get datatable/arrays at the moment + const char *GetPropType( HSCRIPT hEnt, const char *szProp ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return NULL; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, INDEX_GET_TYPE ); + + if ( !pInfo ) + return NULL; + } + + switch ( pInfo->datatype ) + { + case types::_INT1: + case types::_INT8: + case types::_INT16: + case types::_INT32: + return "integer"; + case types::_FLOAT: + return "float"; + case types::_VEC3: + return "vector"; + case types::_VEC2: + return "vector2d"; + case types::_CSTRING: + case types::_STRING_T: + case types::_STDSTRING: + return "string"; + case types::_EHANDLE: + case types::_CLASSPTR: + case types::_EDICT: + return "entity"; + case types::_PHYS: + return "phys"; + case types::_ARRAY: + return "array"; + case types::_DATATABLE: + return "datatable"; + } + + if ( pInfo->arraysize > 1 ) + return "array"; + + return ""; + } + + int GetPropArraySize( HSCRIPT hEnt, const char *szProp ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return -1; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, INDEX_GET_TYPE ); + + if ( !pInfo ) + return -1; + } +#ifdef GAME_DLL + switch ( pInfo->datatype ) + { + case types::_DAR_EHANDLE: + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + case types::_DAR_CLASSPTR: + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + case types::_DAR_INT: + { + CUtlVector< int > &vec = *(CUtlVector< int >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + case types::_DAR_FLOAT: + { + CUtlVector< float > &vec = *(CUtlVector< float >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + } +#endif + return pInfo->arraysize; + } + +public: + int GetPropIntArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return -1; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return -1; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return -1; + + if ( pInfo->isNotNetworked ) + { + switch ( pInfo->datatype ) + { + case types::_INT32: + if ( pInfo->isUnsigned ) + return *(unsigned int*)((char*)pEnt + pInfo->GetOffset( index )); + return *(int*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_INT1: + return *(bool*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_INT8: + if ( pInfo->isUnsigned ) + return *(unsigned char*)((char*)pEnt + pInfo->GetOffset( index )); + return *(char*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_INT16: + if ( pInfo->isUnsigned ) + return *(unsigned short*)((char*)pEnt + pInfo->GetOffset( index )); + return *(short*)((char*)pEnt + pInfo->GetOffset( index )); +#ifdef GAME_DLL + case types::_DAR_INT: + { + CUtlVector< int > &vec = *(CUtlVector< int >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + if ( index >= vec.Count() ) + return -1; + return vec[ index ]; + } +#endif + } + } + else + { + switch ( pInfo->datatype ) + { + case types::_INT32: + return (*(int*)((char*)pEnt + pInfo->GetOffset( index ))) & pInfo->mask; + } } return -1; } - #define GetPropFunc( name, varType, propType, defaultval ) \ - varType name( HSCRIPT hEnt, const char *pszPropName ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - return *(varType*)((char *)pEnt + pProp->GetOffset()); \ - } \ - return defaultval; \ - } \ - - #define GetPropFuncArray( name, varType, propType, defaultval ) \ - varType name( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - return ((varType*)((char *)pEnt + pProp->GetOffset()))[iArrayElement]; \ - } \ - return defaultval; \ - } \ - - GetPropFunc( GetPropFloat, float, DPT_Float, -1 ); - GetPropFuncArray( GetPropFloatArray, float, DPT_Float, -1 ); - GetPropFunc( GetPropInt, int, DPT_Int, -1 ); - GetPropFuncArray( GetPropIntArray, int, DPT_Int, -1 ); - GetPropFunc( GetPropVector, Vector, DPT_Vector, vec3_invalid ); - GetPropFuncArray( GetPropVectorArray, Vector, DPT_Vector, vec3_invalid ); - - HSCRIPT GetPropEntity( HSCRIPT hEnt, const char *pszPropName ) + void SetPropIntArray( HSCRIPT hEnt, const char *szProp, int value, int index ) { CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) { - return ToHScript( *(CHandle*)((char *)pEnt + pProp->GetOffset()) ); + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; } - return NULL; - } + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; - HSCRIPT GetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + if ( pInfo->isNotNetworked ) { - return ToHScript( ((CHandle*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] ); - } - - return NULL; - } - - const char *GetPropString( HSCRIPT hEnt, const char *pszPropName ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) - { - return (const char*)((char *)pEnt + pProp->GetOffset()); - } - - return NULL; - } - - const char *GetPropStringArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) - { - return ((const char**)((char *)pEnt + pProp->GetOffset()))[iArrayElement]; - } - - return NULL; - } - - const char *GetPropType( HSCRIPT hEnt, const char *pszPropName ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp) - { - switch (pProp->GetType()) + switch ( pInfo->datatype ) { - case DPT_Int: return "integer"; - case DPT_Float: return "float"; - case DPT_Vector: return "vector"; - case DPT_VectorXY: return "vector2d"; - case DPT_String: return "string"; - case DPT_Array: return "array"; - case DPT_DataTable: return "datatable"; + case types::_INT32: + if ( pInfo->isUnsigned ) + { + *(unsigned int*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + *(int*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_INT1: + *(bool*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_INT8: + if ( pInfo->isUnsigned ) + { + *(unsigned char*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + *(char*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_INT16: + if ( pInfo->isUnsigned ) + { + *(unsigned short*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + *(short*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; +#ifdef GAME_DLL + case types::_DAR_INT: + { + CUtlVector< int > &vec = *(CUtlVector< int >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = value; + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } +#endif + } + } + else + { + switch ( pInfo->datatype ) + { + case types::_INT32: + { + int *dest = (int*)((char*)pEnt + pInfo->GetOffset( index )); + *dest = (*dest & ~pInfo->mask) | (value & pInfo->mask); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + } + } + } + + float GetPropFloatArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return -1; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return -1; + } + + if ( pInfo->datatype == types::_VEC3 ) + index /= 3; + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return -1; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + case types::_FLOAT: + return *(float*)((char*)pEnt + pInfo->GetOffset( index )); +#ifdef GAME_DLL + case types::_DAR_FLOAT: + { + CUtlVector< float > &vec = *(CUtlVector< float >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + if ( index >= vec.Count() ) + return -1; + return vec[ index ]; + } +#endif + } + + return -1; + } + + void SetPropFloatArray( HSCRIPT hEnt, const char *szProp, float value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( pInfo->datatype == types::_VEC3 ) + index /= 3; + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + case types::_FLOAT: + *(float*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; +#ifdef GAME_DLL + case types::_DAR_FLOAT: + { + CUtlVector< float > &vec = *(CUtlVector< float >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = value; + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } +#endif + } + } + + HSCRIPT GetPropEntityArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return NULL; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return NULL; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return NULL; + + switch ( pInfo->datatype ) + { + case types::_EHANDLE: + { + EHANDLE &iEHandle = *(EHANDLE*)((char*)pEnt + pInfo->GetOffset( index )); + return ToHScript( iEHandle ); + } +#ifdef GAME_DLL + case types::_CLASSPTR: + { + CBaseEntity* ptr = *(CBaseEntity**)((char*)pEnt + pInfo->GetOffset( index )); + return ToHScript( ptr ); + } + case types::_EDICT: + { + edict_t* ptr = *(edict_t**)((char*)pEnt + pInfo->GetOffset( index )); + return ToHScript( GetContainingEntity( ptr ) ); + } + case types::_DAR_EHANDLE: + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return NULL; + if ( index >= vec.Count() ) + return NULL; + return ToHScript( vec[ index ] ); + } + case types::_DAR_CLASSPTR: + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return NULL; + if ( index >= vec.Count() ) + return NULL; + return ToHScript( vec[ index ] ); + } +#endif + case types::_PHYS: + { + IPhysicsObject* ptr = *(IPhysicsObject**)((char*)pEnt + pInfo->GetOffset( index )); + return ptr ? g_pScriptVM->RegisterInstance( ptr ) : NULL; + } + } + + return NULL; + } + + void SetPropEntityArray( HSCRIPT hEnt, const char *szProp, HSCRIPT value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_EHANDLE: + *(EHANDLE*)((char*)pEnt + pInfo->GetOffset( index )) = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; +#ifdef GAME_DLL + case types::_CLASSPTR: + *(CBaseEntity**)((char*)pEnt + pInfo->GetOffset( index )) = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_EDICT: + { + CBaseEntity* ptr = ToEnt( value ); + *(edict_t**)((char*)pEnt + pInfo->GetOffset( index )) = ptr ? ptr->edict() : NULL; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + case types::_DAR_EHANDLE: + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } + case types::_DAR_CLASSPTR: + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } +#endif + } + } + + const Vector &GetPropVectorArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return vec3_invalid; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return vec3_invalid; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return vec3_invalid; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + return *(Vector*)((char*)pEnt + pInfo->GetOffset( index )); + } + + return vec3_invalid; + } + + void SetPropVectorArray( HSCRIPT hEnt, const char *szProp, const Vector &value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + *(Vector*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + } + + const char *GetPropStringArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return NULL; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return NULL; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return NULL; + + switch ( pInfo->datatype ) + { + case types::_CSTRING: + return (const char*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_STRING_T: // Identical to _CSTRING on client + return STRING( *(string_t*)((char*)pEnt + pInfo->GetOffset( index )) ); + case types::_INT8: + { + if ( !pInfo->stringsize ) + return NULL; + + char * const pVar = ((char*)pEnt + pInfo->GetOffset( index )); + + // Is this null terminated? + int i = 0; + char *c = pVar; + while ( *(c++) && i++ < pInfo->stringsize ); + + if ( i >= pInfo->stringsize ) + { + // Not a null terminated string, don't talk to me ever again + pInfo->stringsize = 0; + return NULL; + } + + return pVar; + } +#ifdef GAME_DLL + case types::_STDSTRING: + return ( (std::string*)((char*)pEnt + pInfo->GetOffset( index )) )->c_str(); +#endif + } + + return NULL; + } + + void SetPropStringArray( HSCRIPT hEnt, const char *szProp, const char *value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_CSTRING: + case types::_INT8: + { + if ( pInfo->stringsize ) + { + V_strncpy( (char*)pEnt + pInfo->GetOffset( index ), value, pInfo->stringsize ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + } + case types::_STRING_T: + { + extern string_t FindPooledString( const char* ); + extern string_t AllocPooledString( const char* ); + + string_t src = FindPooledString( value ); + if ( src == NULL_STRING ) + src = AllocPooledString( value ); +#ifdef GAME_DLL + *(string_t*)((char*)pEnt + pInfo->GetOffset( index )) = src; +#else + V_strcpy( (char*)pEnt + pInfo->GetOffset( index ), src ); +#endif + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } +#ifdef GAME_DLL + case types::_STDSTRING: + { + ( (std::string*)((char*)pEnt + pInfo->GetOffset( index )) )->assign( value, V_strlen(value) ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } +#endif + } + } + +#define GetProp( type, name )\ + type GetProp##name( HSCRIPT hEnt, const char* szProp )\ + {\ + return GetProp##name##Array( hEnt, szProp, 0 );\ + } + +#define SetProp( type, name )\ + void SetProp##name( HSCRIPT hEnt, const char* szProp, type value )\ + {\ + return SetProp##name##Array( hEnt, szProp, value, 0 );\ + } + + GetProp( int, Int ); + SetProp( int, Int ); + GetProp( float, Float ); + SetProp( float, Float ); + GetProp( HSCRIPT, Entity ); + SetProp( HSCRIPT, Entity ); + GetProp( Vector, Vector ); + SetProp( Vector, Vector ); + GetProp( const char*, String ); + SetProp( const char*, String ); + +#undef GetProp +#undef SetProp + +#ifdef _DEBUG +private: + CUtlBuffer m_output; + CUtlString m_indent; + int m_indent_level; + + void IndentStart() + { + m_indent = ""; + m_indent_level = 0; + } + + void Indent1() + { + m_indent_level++; + m_indent.Append("\t"); + } + + void Indent0() + { + m_indent_level--; + m_indent = m_indent.Slice( 0, m_indent_level ); + } + + void PrintVec3( float *pVar ) + { + if ( *(Vector*)pVar != vec3_invalid ) + { + Print( "[%f %f %f]", pVar[0], pVar[1], pVar[2] ); + } + else + { + Print("vec3_invalid"); + } + } + + void PrintVec2( float *pVar ) + { + Print( "[%f %f]", pVar[0], pVar[1] ); + } + + void PrintEntity( EHANDLE* pVar ) + { + CBaseEntity* ent = *pVar; + if ( ent ) + { + Print("[%d]%s", ent->entindex(), ent->GetDebugName()); + } + else + { + Print("null"); + } + } +#ifdef GAME_DLL + void PrintEntity( CBaseEntity* pVar ) + { + CBaseEntity* ent = pVar; + if ( ent ) + { + Print("[%d]%s", ent->entindex(), ent->GetDebugName()); + } + else + { + Print("null"); + } + } + + void PrintEntity( edict_t* pVar ) + { + CBaseEntity* ent = GetContainingEntity( pVar ); + if ( ent ) + { + Print("[%d]%s", ent->entindex(), ent->GetDebugName()); + } + else + { + Print("null"); + } + } +#endif +#ifdef GAME_DLL + void PrintString( string_t pVar ) + { + if ( STRING(pVar) ) + { + Print("\"%s\"", STRING(pVar)); + } + else + { + Print("null"); + } + } +#endif + void PrintString( const char *pVar ) + { + if ( pVar ) + { + Print("\"%s\"", pVar); + } + else + { + Print("null"); + } + } + + void PrintPropType( NetProp *pProp ) + { + switch ( pProp->GetType() ) + { + case DPT_Int: + if ( IsUtlVector( pProp ) ) + { + Print("UtlVector"); + } + else if ( IsEHandle( pProp ) ) + { + Print( "entity" ); + } + else + { + Print( "int" ); + } + break; +#ifdef SUPPORTS_INT64 + case DPT_Int64: + AssertMsg( 0, "not implemented" ); + Print( "int64" ); + break; +#endif + case DPT_Float: + Print( "float" ); + break; + case DPT_Vector: + Print( "vec3" ); + break; + case DPT_VectorXY: + Print( "vec2" ); + break; + case DPT_String: + { +#ifdef GAME_DLL + if ( pProp->GetProxyFn() == SendProxy_StringT_To_String ) + { + Print("string_t"); + } + else +#endif + { +#ifdef CLIENT_DLL + Print("string[%d]", pProp->m_StringBufferSize); +#else + Print("string"); +#endif + } + break; + } + case DPT_Array: + case DPT_DataTable: + break; + default: UNREACHABLE(); + } + } + + void PrintProp_r( char *pVar, NetProp *pProp ) + { + switch ( pProp->GetType() ) + { + case DPT_Int: + { + if ( IsUtlVector( pProp ) ) + { + } + else if ( IsEHandle( pProp ) ) + { + PrintEntity( (EHANDLE*)pVar ); + } + else + { +#ifdef GAME_DLL + // Is this value larger than networked size? + AssertMsg( (*(int*)pVar & MASK_NEAREST_BYTE( pProp->m_nBits )) == 0, + "%s(%i) %d bits doesn't fit networked %d bits", + pProp->GetName(), *(int*)pVar & MASK_NEAREST_BYTE( pProp->m_nBits ), ALIGN_TO_NEAREST_BYTE(pProp->m_nBits), pProp->m_nBits ); +#endif + int size = GetIntPropSize( pProp ); + if ( size ) + { + Print( "%i", *(int*)pVar & MASK_INT_SIZE( size ) ); + } + else + { + Print( " 0x%08x", *(int*)pVar ); + } + } + break; + } +#ifdef SUPPORTS_INT64 + case DPT_Int64: + { + Print( "%lli", *(int64*)pVar ); + break; + } +#endif + case DPT_Float: + { + Assert( pProp->GetElementStride() == sizeof(float) || pProp->GetElementStride() < 0 ); + if ( *(float*)pVar == FLT_MAX ) + { + Print("FLT_MAX"); + } + else + { + Print("%f", *(float*)pVar); + } + break; + } + case DPT_Vector: + { + PrintVec3( (float*)pVar ); + break; + } + case DPT_VectorXY: + { + PrintVec2( (float*)pVar ); + break; + } + case DPT_String: + { +#ifdef GAME_DLL + if ( pProp->GetProxyFn() == SendProxy_StringT_To_String ) + { + PrintString( *(string_t*)pVar ); + } + else +#endif + { + Assert( pProp->GetProxyFn() == DataTableProxy_String ); + PrintString( (char*)pVar ); + } + break; + } + case DPT_DataTable: + { + NetTable* pArray = pProp->GetDataTable(); + Assert( pArray->GetNumProps() ); + + if ( V_strcmp( pProp->GetName(), pArray->GetName() ) != 0 ) + { + Print( " -> (%s)\n", pArray->GetName() ); + DumpNetTable_r( pVar, pArray ); + break; + } + + // Double check that each element is the same size + // Array indexing ints gets element size from this + int diff1 = pArray->GetProp(1)->GetOffset() - pArray->GetProp(0)->GetOffset(); + for ( int k = 0; k < pArray->GetNumProps()-1; k++ ) + { + int diff2 = pArray->GetProp(k+1)->GetOffset() - pArray->GetProp(k)->GetOffset(); + Assert( diff1 == diff2 ); + } + + Print(" <"); + PrintPropType( pArray->GetProp(0) ); + Print(" array> #%d", pArray->GetNumProps()); + Print("\n%s[", m_indent.Get()); + Indent1(); + + for ( int j = 0; j < pArray->GetNumProps(); j++ ) + { + Print("\n%s", m_indent.Get()); + PrintProp_r( pVar + pArray->GetProp(j)->GetOffset(), pArray->GetProp(j) ); + } + + Indent0(); + Print( "\n%s]", m_indent.Get() ); + + break; + } + case DPT_Array: + { + Assert( pProp->GetArrayProp() ); + NetProp *pArray = pProp->GetArrayProp(); + pVar += pArray->GetOffset(); + + int numElements = pProp->GetNumElements(); + int elementStride = pProp->GetElementStride(); + + Print(" <"); + PrintPropType( pArray ); + Print(" array> #%d", numElements); + Print("\n%s[", m_indent.Get()); + Indent1(); + + for ( int j = 0; j < numElements; j++ ) + { + Print("\n%s", m_indent.Get()); + PrintProp_r( pVar + j * elementStride, pArray ); + } + + Indent0(); + Print( "\n%s]", m_indent.Get() ); + + break; + } + default: UNREACHABLE(); + } + } + + void DumpNetTable_r( void *pEnt, NetTable *pTable ) + { + Print("%s{\n", m_indent.Get()); + Indent1(); + + int numProps = pTable->GetNumProps(); + + for ( int i = 0; i < numProps; i++ ) + { + NetProp* pProp = pTable->GetProp(i); + char* pVar = (char*)pEnt + pProp->GetOffset(); + + if ( pProp->IsInsideArray() ) + continue; + + Print( "%s%s", m_indent.Get(), pProp->GetName() ); + + if ( pProp->GetOffset() == 0 ) + Print("<0>"); + + if ( pProp->GetType() != DPT_DataTable ) + Print(" <"); + PrintPropType( pProp ); + if ( pProp->GetType() != DPT_DataTable ) + Print("> "); + PrintProp_r( pVar, pProp ); + Print("\n"); + } + + Indent0(); + Print("%s}", m_indent.Get()); + } + + void PrintFieldType( char *pVar, typedescription_t *td ) + { + switch ( td->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_TICK: + Print( "int" ); + break; + case FIELD_SHORT: + Print( "short" ); + break; + case FIELD_CHARACTER: + Print( "char" ); + break; + case FIELD_BOOLEAN: + Print( "bool" ); + break; + case FIELD_COLOR32: + Print( "clr32" ); + break; + case FIELD_FLOAT: + case FIELD_TIME: + Print( "float" ); + break; + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + Print( "vec3" ); + break; + case FIELD_VECTOR2D: + Print( "vec2" ); + break; + case FIELD_STRING: + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + Print( "string" ); + break; + case FIELD_EHANDLE: +#ifdef GAME_DLL + case FIELD_CLASSPTR: + case FIELD_EDICT: +#endif + Print( "entity" ); + break; + case FIELD_VMATRIX: + Print( "VMatrix" ); + break; + case FIELD_VMATRIX_WORLDSPACE: + Print( "VMatrix WORLDSPACE" ); + break; + case FIELD_MATRIX3X4_WORLDSPACE: + Print( "matrix3x4 WORLDSPACE" ); + break; + case FIELD_INTERVAL: + Print( "interval_t" ); + break; + case FIELD_CUSTOM: + PrintCustomFieldType( pVar, td ); + break; + case FIELD_EMBEDDED: + if ( td->fieldSize > 1 ) + Print( "DT" ); + break; + default: + Print( "unknown %d", td->fieldType ); + } + } + + void PrintCustomFieldType( char *pVar, typedescription_t *td ) + { + Assert( td->fieldType == FIELD_CUSTOM ); + + const char *g_ppszPhysTypeNames[PIID_NUM_TYPES] = + { + "Unknown Phys", + "IPhysicsObject", + "IPhysicsFluidController", + "IPhysicsSpring", + "IPhysicsConstraintGroup", + "IPhysicsConstraint", + "IPhysicsShadowController", + "IPhysicsPlayerController", + "IPhysicsMotionController", + "IPhysicsVehicleController", + }; + + for ( int i = 0; i < PIID_NUM_TYPES; i++ ) + { + if ( td->pSaveRestoreOps == GetPhysObjSaveRestoreOps( (PhysInterfaceId_t)i ) ) + { + Print("%s", g_ppszPhysTypeNames[i]); + return; } } - return NULL; - } - - bool HasProp( HSCRIPT hEnt, const char *pszPropName ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - return GetPropByName( pEnt, pszPropName ) != NULL; - } - - #define SetPropFunc( name, varType, propType ) \ - void name( HSCRIPT hEnt, const char *pszPropName, varType value ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - *(varType*)((char *)pEnt + pProp->GetOffset()) = value; \ - } \ - } \ - - #define SetPropFuncArray( name, varType, propType ) \ - void name( HSCRIPT hEnt, const char *pszPropName, varType value, int iArrayElement ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - ((varType*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = value; \ - } \ - } \ - - SetPropFunc( SetPropFloat, float, DPT_Float ); - SetPropFuncArray( SetPropFloatArray, float, DPT_Float ); - SetPropFunc( SetPropInt, int, DPT_Int ); - SetPropFuncArray( SetPropIntArray, int, DPT_Int ); - SetPropFunc( SetPropVector, Vector, DPT_Vector ); - SetPropFuncArray( SetPropVectorArray, Vector, DPT_Vector ); - SetPropFunc( SetPropString, const char*, DPT_String ); - SetPropFuncArray( SetPropStringArray, const char*, DPT_String ); - - void SetPropEntity( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + if ( td->pSaveRestoreOps == ActivityDataOps() ) { - *((CHandle*)((char *)pEnt + pProp->GetOffset())) = ToEnt(value); + Print("int"); + } + else if ( td->pSaveRestoreOps == GetSoundSaveRestoreOps() ) + { + Print("CSoundPatch"); + } + else if ( td->pSaveRestoreOps == GetStdStringDataOps() ) + { + Print("stdstring"); + } +#ifdef GAME_DLL + else if ( IS_EHANDLE_UTLVECTOR( td ) ) + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)pVar; + if ( vec.Base() ) + Print("entity utlvector #%d", vec.Count()); + else + Print("entity utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_INTEGER, int ) ) + { + CUtlVector< int > &vec = *(CUtlVector< int >*)pVar; + if ( vec.Base() ) + Print("int utlvector #%d", vec.Count()); + else + Print("int utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_FLOAT, float ) || + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_TIME, float ) ) + { + CUtlVector< float > &vec = *(CUtlVector< float >*)pVar; + if ( vec.Base() ) + Print("float utlvector #%d", vec.Count()); + else + Print("float utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_STRING, string_t ) ) + { + CUtlVector< string_t > &vec = *(CUtlVector< string_t >*)pVar; + if ( vec.Base() ) + Print("string utlvector #%d", vec.Count()); + else + Print("string utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_CLASSPTR, CBaseEntity* ) ) + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)pVar; + if ( vec.Base() ) + Print("entity utlvector #%d", vec.Count()); + else + Print("entity utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_VECTOR, Vector ) ) + { + AssertMsg( 0, "Implement me" ); + CUtlVector< Vector > &vec = *(CUtlVector< Vector >*)pVar; + if ( vec.Base() ) + Print("Vector utlvector #%d", vec.Count()); + else + Print("Vector utlvector"); + } + else if ( !V_strcmp( td->fieldName, "m_pIk" ) ) + { + Print("IK"); + } + else if ( td->pSaveRestoreOps == thinkcontextFuncs ) + { + Print("thinkfunc"); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_AI_MemoryListSaveRestoreOps) ) + { + Print("AI memory map"); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_VguiScreenStringOps)) + { + Print("string (vgui screen)"); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_ConceptHistoriesSaveDataOps) ) + { + Print("concept histories"); + } +#endif // GAME_DLL + else + { + Print("custom"); } } - HSCRIPT SetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value, int iArrayElement ) + void PrintCustomField( char *pVar, typedescription_t *td ) { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + Assert( td->fieldType == FIELD_CUSTOM ); + + for ( int i = 0; i < PIID_NUM_TYPES; i++ ) { - ((CHandle*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = ToEnt(value); + if ( td->pSaveRestoreOps == GetPhysObjSaveRestoreOps( (PhysInterfaceId_t)i ) ) + { + Print("0x%x", pVar); + return; + } } - return NULL; + if ( td->pSaveRestoreOps == ActivityDataOps() ) + { + Print("%i", *(int*)pVar); + } + else if ( td->pSaveRestoreOps == GetSoundSaveRestoreOps() ) + { + if ( *pVar ) + { + CSoundPatch *pSound = *(CSoundPatch**)pVar; + PrintString( CSoundEnvelopeController::GetController().SoundGetName( pSound ) ); + } + else + { + Print( "null" ); + } + } + else if ( td->pSaveRestoreOps == GetStdStringDataOps() ) + { + Print("%s", ((std::string*)pVar)->c_str()); + } +#ifdef GAME_DLL + else if ( IS_EHANDLE_UTLVECTOR( td ) ) + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + PrintEntity( vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_INTEGER, int ) ) + { + CUtlVector< int > &vec = *(CUtlVector< int >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + Print( "%i", vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_FLOAT, float ) || + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_TIME, float ) ) + { + CUtlVector< float > &vec = *(CUtlVector< float >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + Print( "%f", vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_STRING, string_t ) ) + { + CUtlVector< string_t > &vec = *(CUtlVector< string_t >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + PrintString( vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_CLASSPTR, CBaseEntity* ) ) + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + PrintEntity( vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_VguiScreenStringOps) ) + { + const char *pString = g_pStringTableVguiScreen->GetString( *(int*)pVar ); + PrintString( (char*)pString ); + } +#endif // GAME_DLL + else + { + Print("0x%x", pVar); + } } -private: + void PrintField_r( char *pVar, typedescription_t *td ) + { + switch ( td->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_TICK: + if ( td->flags & SPROP_UNSIGNED ) + { + Print("%u", *(unsigned int*)pVar); + } + else + { + Print("%i", *(int*)pVar); + } + break; + case FIELD_COLOR32: + Print("0x%08x", *(int*)pVar); + break; + case FIELD_BOOLEAN: + Print("%i", *(bool*)pVar & 1); + break; + case FIELD_CHARACTER: + if ( *pVar < 0x20 ) + { + Print("%i (0x%x)", *pVar, *pVar); + } + else + { + Print("%i '%c'", *pVar, *pVar); + } + break; + case FIELD_SHORT: + if ( td->flags & SPROP_UNSIGNED ) + { + Print("%u", *(unsigned short*)pVar); + } + else + { + Print("%i", *(short*)pVar); + } + break; + case FIELD_FLOAT: + case FIELD_TIME: + if ( *(float*)pVar == FLT_MAX ) + { + Print("FLT_MAX"); + } + else + { + Print("%f", *(float*)pVar); + } + break; + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + PrintVec3( (float*)pVar ); + break; + case FIELD_VECTOR2D: + PrintVec2( (float*)pVar ); + break; + case FIELD_STRING: + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: +#ifdef GAME_DLL + PrintString( *(string_t*)pVar ); +#else + PrintString( *(char**)pVar ); +#endif + break; + case FIELD_EHANDLE: + PrintEntity( (EHANDLE*)pVar ); + break; +#ifdef GAME_DLL + case FIELD_CLASSPTR: + PrintEntity( *(CBaseEntity**)pVar ); + break; + case FIELD_EDICT: + PrintEntity( *(edict_t**)pVar ); + break; +#endif + case FIELD_EMBEDDED: + Print(" -> (%s)\n", td->td->dataClassName); + DumpDataFields_r( pVar, td->td ); + break; + case FIELD_CUSTOM: + PrintCustomField( pVar, td ); + break; + default: + Print( "", td->fieldType ); + } + } + + void DumpDataFields_r( void *pEnt, datamap_t *map ) + { + Print("%s{\n", m_indent.Get()); + Indent1(); + + if ( map->baseMap ) + { + Print("%sbaseclass -> (%s)\n", m_indent.Get(), map->baseMap->dataClassName); + DumpDataFields_r( pEnt, map->baseMap ); + Print("\n"); + } + + typedescription_t *pFields = map->dataDesc; + int numFields = map->dataNumFields; + + for ( int i = 0; i < numFields; i++ ) + { + typedescription_t* td = &pFields[i]; + + if ( td->flags & (FTYPEDESC_FUNCTIONTABLE | FTYPEDESC_INPUT | FTYPEDESC_OUTPUT) ) + continue; + + if ( td->fieldType == FIELD_VOID || td->fieldType == FIELD_FUNCTION ) + continue; + + char *pVar = (char*)pEnt + td->fieldOffset[ TD_OFFSET_NORMAL ]; + + if ( td->flags & FTYPEDESC_PTR ) + { + AssertMsg( *(char**)pVar, "NULL ptr ref" ); + pVar = *(char**)pVar; + } + + Print( "%s%s", m_indent.Get(), td->fieldName ); + + if ( td->fieldSize == 1 ) + { + if ( td->fieldType != FIELD_EMBEDDED ) + Print(" <"); + PrintFieldType( pVar, td ); + if ( td->fieldType != FIELD_EMBEDDED ) + Print("> "); + PrintField_r( pVar, td ); + } + else + { + Print(" <"); + PrintFieldType( pVar, td ); + Print(" array> #%d", td->fieldSize); + + Print("\n%s[", m_indent.Get()); + Indent1(); + + for ( int j = 0; j < td->fieldSize; j++ ) + { + Print("\n%s", m_indent.Get()); + PrintField_r( pVar + j * td->fieldSizeInBytes / td->fieldSize, td ); + } + + Indent0(); + Print("\n%s]", m_indent.Get()); + } + + Print("\n"); + } + + Indent0(); + Print("%s}", m_indent.Get()); + } + + void Print( const char *fmt, ... ) + { + char buf[2048]; + va_list va; + va_start( va, fmt ); + V_vsnprintf( buf, sizeof(buf) - 1, fmt, va ); + va_end( va ); + + m_output.PutString( buf ); + } + +public: + void Dump( HSCRIPT hEnt, const char* filename ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + if ( !filename || !*filename ) + return; + + m_output.SetBufferType( true, false ); + IndentStart(); + + Print( "\n" ); + Print( "(%s)\n", GetNetTable( GetNetworkClass(pEnt) )->GetName() ); + DumpNetTable_r( pEnt, GetNetTable( GetNetworkClass(pEnt) ) ); + Print( "\n\n" ); + + Print( "\n" ); + Print( "(%s)\n", pEnt->GetDataDescMap()->dataClassName ); + DumpDataFields_r( pEnt, pEnt->GetDataDescMap() ); + Print( "\n\n" ); +#ifdef CLIENT_DLL + Print( "\n" ); + Print( "(%s)\n", pEnt->GetPredDescMap()->dataClassName ); + DumpDataFields_r( pEnt, pEnt->GetPredDescMap() ); + Print( "\n\n" ); +#endif + const char *pszFile = V_GetFileName( filename ); + filesystem->WriteFile( pszFile, "MOD", m_output ); + + m_indent.Purge(); + m_output.Purge(); + } +#endif // _DEBUG } g_ScriptNetPropManager; -BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptNetPropManager, "CNetPropManager", SCRIPT_SINGLETON "Allows reading and updating the network properties of an entity." ) - DEFINE_SCRIPTFUNC( GetPropArraySize, "Returns the size of an netprop array, or -1." ) - DEFINE_SCRIPTFUNC( GetPropEntity, "Reads an EHANDLE valued netprop (21 bit integer). Returns the script handle of the entity." ) - DEFINE_SCRIPTFUNC( GetPropEntityArray, "Reads an EHANDLE valued netprop (21 bit integer) from an array. Returns the script handle of the entity." ) - DEFINE_SCRIPTFUNC( GetPropFloat, "Reads a float valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropFloatArray, "Reads a float valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropInt, "Reads an integer valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropIntArray, "Reads an integer valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropString, "Reads a string valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropStringArray, "Reads a string valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropVector, "Reads a 3D vector valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropVectorArray, "Reads a 3D vector valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropType, "Returns the name of the netprop type as a string." ) - DEFINE_SCRIPTFUNC( HasProp, "Checks if a netprop exists." ) - DEFINE_SCRIPTFUNC( SetPropEntity, "Sets an EHANDLE valued netprop (21 bit integer) to reference the specified entity." ) - DEFINE_SCRIPTFUNC( SetPropEntityArray, "Sets an EHANDLE valued netprop (21 bit integer) from an array to reference the specified entity." ) - DEFINE_SCRIPTFUNC( SetPropFloat, "Sets a netprop to the specified float." ) - DEFINE_SCRIPTFUNC( SetPropFloatArray, "Sets a netprop from an array to the specified float." ) - DEFINE_SCRIPTFUNC( SetPropInt, "Sets a netprop to the specified integer." ) - DEFINE_SCRIPTFUNC( SetPropIntArray, "Sets a netprop from an array to the specified integer." ) - DEFINE_SCRIPTFUNC( SetPropString, "Sets a netprop to the specified string." ) - DEFINE_SCRIPTFUNC( SetPropStringArray, "Sets a netprop from an array to the specified string." ) - DEFINE_SCRIPTFUNC( SetPropVector, "Sets a netprop to the specified vector." ) - DEFINE_SCRIPTFUNC( SetPropVectorArray, "Sets a netprop from an array to the specified vector." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptNetPropManager, "CNetPropManager", SCRIPT_SINGLETON "Allows reading and updating the network properties and data fields of an entity." ) + DEFINE_SCRIPTFUNC( GetPropArraySize, "Returns the size of an array." ) + DEFINE_SCRIPTFUNC( GetPropEntity, "Reads an entity." ) + DEFINE_SCRIPTFUNC( GetPropEntityArray, "Reads an entity from an array." ) + DEFINE_SCRIPTFUNC( GetPropFloat, "Reads a float." ) + DEFINE_SCRIPTFUNC( GetPropFloatArray, "Reads a float from an array." ) + DEFINE_SCRIPTFUNC( GetPropInt, "Reads an integer." ) + DEFINE_SCRIPTFUNC( GetPropIntArray, "Reads an integer from an array." ) + DEFINE_SCRIPTFUNC( GetPropString, "Reads a string." ) + DEFINE_SCRIPTFUNC( GetPropStringArray, "Reads a string from an array." ) + DEFINE_SCRIPTFUNC( GetPropVector, "Reads a 3D vector." ) + DEFINE_SCRIPTFUNC( GetPropVectorArray, "Reads a 3D vector from an array." ) + DEFINE_SCRIPTFUNC( GetPropType, "Returns the netprop type as a string." ) + DEFINE_SCRIPTFUNC( HasProp, "Checks if netprop/datafield exists." ) + DEFINE_SCRIPTFUNC( SetPropEntity, "Sets an entity." ) + DEFINE_SCRIPTFUNC( SetPropEntityArray, "Sets an entity in an array." ) + DEFINE_SCRIPTFUNC( SetPropFloat, "Sets to the specified float." ) + DEFINE_SCRIPTFUNC( SetPropFloatArray, "Sets a float in an array." ) + DEFINE_SCRIPTFUNC( SetPropInt, "Sets to the specified integer." ) + DEFINE_SCRIPTFUNC( SetPropIntArray, "Sets an integer in an array." ) + DEFINE_SCRIPTFUNC( SetPropString, "Sets to the specified string." ) + DEFINE_SCRIPTFUNC( SetPropStringArray, "Sets a string in an array." ) + DEFINE_SCRIPTFUNC( SetPropVector, "Sets to the specified vector." ) + DEFINE_SCRIPTFUNC( SetPropVectorArray, "Sets a 3D vector in an array." ) +#ifdef _DEBUG + DEFINE_SCRIPTFUNC( Dump, "Dump all readable netprop and datafield values of this entity. Pass in file name to write into." ); +#endif END_SCRIPTDESC(); //============================================================================= From db0e0fc29e57e4384cd122e0c2215f7e49219a89 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 5 Oct 2022 00:06:38 -0400 Subject: [PATCH 02/64] SiN: Episodes compatible VGUI Screens --- sp/src/game/client/c_baseplayer.cpp | 9 ++ sp/src/game/client/c_vguiscreen.cpp | 129 ++++++++++++++++++++------ sp/src/game/client/c_vguiscreen.h | 4 + sp/src/game/server/baseentity.h | 8 ++ sp/src/game/server/hl2/hl2_player.cpp | 14 +++ sp/src/game/server/vguiscreen.cpp | 110 +++++++++++++++++++--- sp/src/game/server/vguiscreen.h | 13 +++ sp/src/game/shared/gamerules.cpp | 25 +++++ sp/src/game/shared/gamerules.h | 7 +- sp/src/game/shared/in_buttons.h | 4 + 10 files changed, 282 insertions(+), 41 deletions(-) diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 6e068341..5a21e16e 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1133,6 +1133,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_VALIDVGUIINPUT); +#ifdef MAPBASE + pCmd->buttons |= IN_VGUIMODE; +#endif // MAPBASE return; } #else @@ -1142,6 +1145,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); +#ifdef MAPBASE + pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; +#endif // MAPBASE return; } #endif @@ -1206,6 +1212,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); +#ifdef MAPBASE + pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; +#endif // MAPBASE } } diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index adf8830c..3dc9cfd9 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -38,10 +38,14 @@ extern vgui::IInputInternal *g_InputInternal; #define VGUI_SCREEN_MODE_RADIUS 80 //Precache the materials -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectVGuiScreen ) -CLIENTEFFECT_MATERIAL( "engine/writez" ) +CLIENTEFFECT_REGISTER_BEGIN(PrecacheEffectVGuiScreen) +CLIENTEFFECT_MATERIAL("engine/writez") CLIENTEFFECT_REGISTER_END() +#ifdef MAPBASE +C_EntityClassList g_VGUIScreenList; +template <> C_VGuiScreen* C_EntityClassList::m_pClassList = NULL; +#endif // MAPBASE // ----------------------------------------------------------------------------- // // This is a cache of preloaded keyvalues. @@ -102,11 +106,19 @@ C_VGuiScreen::C_VGuiScreen() m_WriteZMaterial.Init( "engine/writez", TEXTURE_GROUP_VGUI ); m_OverlayMaterial.Init( m_WriteZMaterial ); + +#ifdef MAPBASE + g_VGUIScreenList.Insert(this); +#endif // MAPBASE } C_VGuiScreen::~C_VGuiScreen() { DestroyVguiScreen(); + +#ifdef MAPBASE + g_VGUIScreenList.Remove(this); +#endif // MAPBASE } //----------------------------------------------------------------------------- @@ -416,34 +428,69 @@ void C_VGuiScreen::ClientThink( void ) int px = (int)(u * m_nPixelWidth + 0.5f); int py = (int)(v * m_nPixelHeight + 0.5f); +#ifndef MAPBASE // Generate mouse input commands if ((px != m_nOldPx) || (py != m_nOldPy)) { - g_InputInternal->InternalCursorMoved( px, py ); + g_InputInternal->InternalCursorMoved(px, py); + m_nOldPx = px; m_nOldPy = py; } if (m_nButtonPressed & IN_ATTACK) { - g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); + g_InputInternal->SetMouseCodeState(MOUSE_LEFT, vgui::BUTTON_PRESSED); g_InputInternal->InternalMousePressed(MOUSE_LEFT); } if (m_nButtonPressed & IN_ATTACK2) { - g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED ); - g_InputInternal->InternalMousePressed( MOUSE_RIGHT ); + g_InputInternal->SetMouseCodeState(MOUSE_RIGHT, vgui::BUTTON_PRESSED); + g_InputInternal->InternalMousePressed(MOUSE_RIGHT); } - if ( (m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus + if ((m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus { - g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); - g_InputInternal->InternalMouseReleased( MOUSE_LEFT ); + g_InputInternal->SetMouseCodeState(MOUSE_LEFT, vgui::BUTTON_RELEASED); + g_InputInternal->InternalMouseReleased(MOUSE_LEFT); } if (m_nButtonReleased & IN_ATTACK2) { - g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED ); - g_InputInternal->InternalMouseReleased( MOUSE_RIGHT ); + g_InputInternal->SetMouseCodeState(MOUSE_RIGHT, vgui::BUTTON_RELEASED); + g_InputInternal->InternalMouseReleased(MOUSE_RIGHT); } +#else + vgui::VPANEL focus = g_InputInternal->GetMouseOver(); + // Generate mouse input commands + if ((px != m_nOldPx) || (py != m_nOldPy)) + { + g_InputInternal->UpdateCursorPosInternal(px, py); + + m_nOldPx = px; + m_nOldPy = py; + + focus = pPanel->IsWithinTraverse(px, py, true); + g_InputInternal->SetMouseFocus(focus); + vgui::ivgui()->PostMessage(focus, new KeyValues("CursorMoved", "xpos", px, "ypos", py), NULL); + } + + for (int i = 0; i < 2; i++) + { + const int nBit = i ? IN_ATTACK2 : (IN_ATTACK | IN_USE); + const vgui::MouseCode nButton = i ? MOUSE_RIGHT : MOUSE_LEFT; + + if ((m_nButtonReleased & nBit) || m_bLoseThinkNextFrame) // for a button release on loosing focus + { + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); + } + else if (m_nButtonPressed & nBit) + { + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); + } + } +#endif // !MAPBASE + if ( m_bLoseThinkNextFrame == true ) { @@ -627,6 +674,7 @@ bool C_VGuiScreen::IsInputOnlyToOwner( void ) return (m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) != 0; } +#ifndef MAPBASE //----------------------------------------------------------------------------- // // Enumator class for finding vgui screens close to the local player @@ -634,29 +682,29 @@ bool C_VGuiScreen::IsInputOnlyToOwner( void ) //----------------------------------------------------------------------------- class CVGuiScreenEnumerator : public IPartitionEnumerator { - DECLARE_CLASS_GAMEROOT( CVGuiScreenEnumerator, IPartitionEnumerator ); + DECLARE_CLASS_GAMEROOT(CVGuiScreenEnumerator, IPartitionEnumerator); public: - virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + virtual IterationRetval_t EnumElement(IHandleEntity* pHandleEntity); int GetScreenCount(); - C_VGuiScreen *GetVGuiScreen( int index ); + C_VGuiScreen* GetVGuiScreen(int index); private: CUtlVector< CHandle< C_VGuiScreen > > m_VguiScreens; }; -IterationRetval_t CVGuiScreenEnumerator::EnumElement( IHandleEntity *pHandleEntity ) +IterationRetval_t CVGuiScreenEnumerator::EnumElement(IHandleEntity* pHandleEntity) { - C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); - if ( pEnt == NULL ) + C_BaseEntity* pEnt = ClientEntityList().GetBaseEntityFromHandle(pHandleEntity->GetRefEHandle()); + if (pEnt == NULL) return ITERATION_CONTINUE; // FIXME.. pretty expensive... - C_VGuiScreen *pScreen = dynamic_cast(pEnt); - if ( pScreen ) + C_VGuiScreen* pScreen = dynamic_cast(pEnt); + if (pScreen) { - int i = m_VguiScreens.AddToTail( ); - m_VguiScreens[i].Set( pScreen ); + int i = m_VguiScreens.AddToTail(); + m_VguiScreens[i].Set(pScreen); } return ITERATION_CONTINUE; @@ -667,10 +715,12 @@ int CVGuiScreenEnumerator::GetScreenCount() return m_VguiScreens.Count(); } -C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index ) +C_VGuiScreen* CVGuiScreenEnumerator::GetVGuiScreen(int index) { return m_VguiScreens[index].Get(); -} +} +#endif // !MAPBASE + //----------------------------------------------------------------------------- @@ -704,18 +754,29 @@ C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &vi Ray_t lookRay; lookRay.Init( viewPosition, lookEnd ); +#ifndef MAPBASE // Look for vgui screens that are close to the player CVGuiScreenEnumerator localScreens; - partition->EnumerateElementsInSphere( PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens ); + partition->EnumerateElementsInSphere(PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens); +#endif // !MAPBASE Vector vecOut, vecViewDelta; float flBestDist = 2.0f; C_VGuiScreen *pBestScreen = NULL; +#ifndef MAPBASE for (int i = localScreens.GetScreenCount(); --i >= 0; ) +#else + for (C_VGuiScreen* pScreen = g_VGUIScreenList.m_pClassList; pScreen != NULL; pScreen = pScreen->m_pNext) +#endif // !MAPBASE { - C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i); - +#ifndef MAPBASE + C_VGuiScreen* pScreen = localScreens.GetVGuiScreen(i); +#else + // Skip if out of PVS + if (pScreen->IsDormant()) + continue; +#endif if ( pScreen->IsAttachedToViewModel() ) continue; @@ -865,11 +926,21 @@ vgui::Panel *CVGuiScreenPanel::CreateControlByName(const char *controlName) //----------------------------------------------------------------------------- // Purpose: Called when the user presses a button //----------------------------------------------------------------------------- -void CVGuiScreenPanel::OnCommand( const char *command) +void CVGuiScreenPanel::OnCommand(const char* command) { - if ( Q_stricmp( command, "vguicancel" ) ) + if (Q_stricmp(command, "vguicancel")) { - engine->ClientCmd( const_cast( command ) ); +#ifdef MAPBASE + if (m_hEntity && m_hEntity->IsServerEntity()) + { + KeyValues* pCommand = new KeyValues("EntityCommand"); + pCommand->SetInt("entindex", m_hEntity->index); + pCommand->SetString("command_data", command); + engine->ServerCmdKeyValues(pCommand); + } + else +#endif + engine->ClientCmd(const_cast(command)); } BaseClass::OnCommand(command); diff --git a/sp/src/game/client/c_vguiscreen.h b/sp/src/game/client/c_vguiscreen.h index 71780093..331fbc78 100644 --- a/sp/src/game/client/c_vguiscreen.h +++ b/sp/src/game/client/c_vguiscreen.h @@ -66,6 +66,10 @@ class C_VGuiScreen : public C_BaseEntity public: DECLARE_CLIENTCLASS(); +#ifdef MAPBASE + C_VGuiScreen* m_pNext; +#endif // MAPBASE + C_VGuiScreen(); ~C_VGuiScreen(); diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index acbffdb2..3da44bc7 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -606,6 +606,9 @@ public: void ValidateEntityConnections(); void FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay = 0.0f ); +#ifdef MAPBASE + virtual +#endif CBaseEntityOutput *FindNamedOutput( const char *pszOutput ); #ifdef MAPBASE_VSCRIPT void ScriptFireOutput( const char *pszOutput, HSCRIPT hActivator, HSCRIPT hCaller, const char *szValue, float flDelay ); @@ -864,6 +867,11 @@ public: void SetAIWalkable( bool bBlocksLOS ); bool IsAIWalkable( void ); + +#ifdef MAPBASE + virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) {} +#endif // MAPBASE + private: int SaveDataDescBlock( ISave &save, datamap_t *dmap ); int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index cefdeeb4..b99f05b2 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -3617,6 +3617,20 @@ void CHL2_Player::UpdateWeaponPosture( void ) { m_LowerWeaponTimer.Set( .3 ); VPROF( "CHL2_Player::UpdateWeaponPosture-CheckLower" ); + +#ifdef MAPBASE + if (m_nButtons & IN_VGUIMODE) + { + //We're over a friendly, drop our weapon + if (Weapon_Lower() == false) + { + //FIXME: We couldn't lower our weapon! + } + + return; + } +#endif // MAPBASE + Vector vecAim = BaseClass::GetAutoaimVector( AUTOAIM_SCALE_DIRECT_ONLY ); const float CHECK_FRIENDLY_RANGE = 50 * 12; diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index e049da22..8163131c 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -35,21 +35,21 @@ PRECACHE_REGISTER( vgui_screen ); //----------------------------------------------------------------------------- // Save/load //----------------------------------------------------------------------------- -BEGIN_DATADESC( CVGuiScreen ) +BEGIN_DATADESC(CVGuiScreen) - DEFINE_CUSTOM_FIELD( m_nPanelName, &g_VguiScreenStringOps ), - DEFINE_FIELD( m_nAttachmentIndex, FIELD_INTEGER ), +DEFINE_CUSTOM_FIELD(m_nPanelName, &g_VguiScreenStringOps), +DEFINE_FIELD(m_nAttachmentIndex, FIELD_INTEGER), // DEFINE_FIELD( m_nOverlayMaterial, FIELD_INTEGER ), - DEFINE_FIELD( m_fScreenFlags, FIELD_INTEGER ), - DEFINE_KEYFIELD( m_flWidth, FIELD_FLOAT, "width" ), - DEFINE_KEYFIELD( m_flHeight, FIELD_FLOAT, "height" ), - DEFINE_KEYFIELD( m_strOverlayMaterial, FIELD_STRING, "overlaymaterial" ), - DEFINE_FIELD( m_hPlayerOwner, FIELD_EHANDLE ), +DEFINE_FIELD(m_fScreenFlags, FIELD_INTEGER), +DEFINE_KEYFIELD(m_flWidth, FIELD_FLOAT, "width"), +DEFINE_KEYFIELD(m_flHeight, FIELD_FLOAT, "height"), +DEFINE_KEYFIELD(m_strOverlayMaterial, FIELD_STRING, "overlaymaterial"), +DEFINE_FIELD(m_hPlayerOwner, FIELD_EHANDLE), - DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ), - DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ), +DEFINE_INPUTFUNC(FIELD_VOID, "SetActive", InputSetActive), +DEFINE_INPUTFUNC(FIELD_VOID, "SetInactive", InputSetInactive), -END_DATADESC() +END_DATADESC(); //----------------------------------------------------------------------------- @@ -75,6 +75,20 @@ bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) *s = '\0'; } +#ifdef MAPBASE + // Named command outputs + if (szKeyName[0] == '~' && szKeyName[1]) + { + const char* pszOutputName = szKeyName + 1; + int i = m_PanelOutputs.Find(pszOutputName); + if (!m_PanelOutputs.IsValidIndex(i)) + i = m_PanelOutputs.Insert(pszOutputName, new COutputEvent); + + m_PanelOutputs[i]->ParseEventAction(szValue); + return true; + } +#endif // MAPBASE + if ( FStrEq( szKeyName, "panelname" )) { SetPanelName( szValue ); @@ -158,6 +172,80 @@ void CVGuiScreen::OnRestore() BaseClass::OnRestore(); } +#ifdef MAPBASE +CVGuiScreen::~CVGuiScreen() +{ + m_PanelOutputs.PurgeAndDeleteElements(); +} + +int CVGuiScreen::Save(ISave& save) +{ + int status = BaseClass::Save(save); + if (!status) + return 0; + + const int iCount = m_PanelOutputs.Count(); + save.WriteInt(&iCount); + for (int i = 0; i < iCount; i++) + { + CBaseEntityOutput* output = m_PanelOutputs[i]; + const int nElems = output->NumberOfElements(); + save.WriteString(m_PanelOutputs.GetElementName(i)); + save.WriteInt(&nElems); + if (!output->Save(save)) + return 0; + } + + return status; +} + +int CVGuiScreen::Restore(IRestore& restore) +{ + int status = BaseClass::Restore(restore); + if (!status) + return 0; + + const int iCount = restore.ReadInt(); + m_PanelOutputs.EnsureCapacity(iCount); + for (int i = 0; i < iCount; i++) + { + char cName[MAX_KEY]; + restore.ReadString(cName, MAX_KEY, 0); + const int iIndex = m_PanelOutputs.Insert(cName, new COutputEvent); + const int nElems = restore.ReadInt(); + if (!m_PanelOutputs[iIndex]->Restore(restore, nElems)) + return 0; + } + + return status; +} + +void CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) +{ + const int i = m_PanelOutputs.Find(pKeyValues->GetString()); + if (m_PanelOutputs.IsValidIndex(i)) + { + variant_t Val; + Val.Set(FIELD_VOID, NULL); + m_PanelOutputs[i]->FireOutput(Val, pClient, this); + } +} + +CBaseEntityOutput* CVGuiScreen::FindNamedOutput(const char* pszOutput) +{ + if (pszOutput && pszOutput[0] == '~' && pszOutput[1]) + { + const int i = m_PanelOutputs.Find(pszOutput + 1); + if (m_PanelOutputs.IsValidIndex(i)) + return m_PanelOutputs[i]; + + return NULL; + } + + return BaseClass::FindNamedOutput(pszOutput); +} +#endif // MAPBASE + void CVGuiScreen::SetAttachmentIndex( int nIndex ) { m_nAttachmentIndex = nIndex; diff --git a/sp/src/game/server/vguiscreen.h b/sp/src/game/server/vguiscreen.h index cf720916..1cb7dc7e 100644 --- a/sp/src/game/server/vguiscreen.h +++ b/sp/src/game/server/vguiscreen.h @@ -32,6 +32,15 @@ public: virtual void Activate(); virtual void OnRestore(); +#ifdef MAPBASE + ~CVGuiScreen(); + virtual int Save(ISave& save); + virtual int Restore(IRestore& restore); + + virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); + virtual CBaseEntityOutput* FindNamedOutput(const char* pszOutput); +#endif // MAPBASE + const char *GetPanelName() const; // Sets the screen size + resolution @@ -75,6 +84,10 @@ private: CNetworkVar( int, m_fScreenFlags ); CNetworkVar( EHANDLE, m_hPlayerOwner ); +#ifdef MAPBASE + CUtlDict m_PanelOutputs; +#endif // MAPBASE + friend CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex ); }; diff --git a/sp/src/game/shared/gamerules.cpp b/sp/src/game/shared/gamerules.cpp index cb199617..face9d54 100644 --- a/sp/src/game/shared/gamerules.cpp +++ b/sp/src/game/shared/gamerules.cpp @@ -963,3 +963,28 @@ CTacticalMissionManager *CGameRules::TacticalMissionManagerFactory( void ) } #endif + +#ifdef MAPBASE +void CGameRules::ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) +{ +#ifndef CLIENT_DLL + static int s_nEntityCommandSymbol = KeyValues::CallGetSymbolForString("EntityCommand"); + static int s_nEntIndexSymbol = KeyValues::CallGetSymbolForString("entindex"); + static int s_nCommandDataSymbol = KeyValues::CallGetSymbolForString("command_data"); + + CBasePlayer* pPlayer = (CBasePlayer*)GetContainingEntity(pEntity); + if (!pPlayer) + return; + + if (pKeyValues->GetNameSymbol() == s_nEntityCommandSymbol) + { + CBaseEntity* pEntity = CBaseEntity::Instance(pKeyValues->GetInt(s_nEntIndexSymbol)); + KeyValues* pkvCommand = pKeyValues->FindKey(s_nCommandDataSymbol); + if (pEntity && pkvCommand) + { + pEntity->HandleEntityCommand(pPlayer, pkvCommand); + } + } +#endif // GAME_DLL +} +#endif // MAPBASE diff --git a/sp/src/game/shared/gamerules.h b/sp/src/game/shared/gamerules.h index 9ae672b6..a60f2771 100644 --- a/sp/src/game/shared/gamerules.h +++ b/sp/src/game/shared/gamerules.h @@ -178,7 +178,12 @@ public: //Allow thirdperson camera. virtual bool AllowThirdPersonCamera( void ) { return false; } - virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ) {} +#ifdef MAPBASE + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues); +#else + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) {} +#endif // MAPBASE + // IsConnectedUserInfoChangeAllowed allows the clients to change // cvars with the FCVAR_NOT_CONNECTED rule if it returns true diff --git a/sp/src/game/shared/in_buttons.h b/sp/src/game/shared/in_buttons.h index 870961f8..74e2ca5f 100644 --- a/sp/src/game/shared/in_buttons.h +++ b/sp/src/game/shared/in_buttons.h @@ -43,6 +43,10 @@ #define IN_GRENADE2 (1 << 24) // grenade 2 #define IN_ATTACK3 (1 << 25) +#ifdef MAPBASE +#define IN_VGUIMODE (1 << 26) +#endif // MAPBASE + #ifdef VGUI_SCREEN_FIX #define IN_VALIDVGUIINPUT (1 << 23) //bitflag for vgui fix #endif From e304b1a90eb29ec47a40aa6a144acb2759b97ded Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Tue, 1 Aug 2023 17:46:29 -0400 Subject: [PATCH 03/64] Fixed C_VGuiScreen sending reversed pressed/unpressed events to the panel --- sp/src/game/client/c_vguiscreen.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index 3dc9cfd9..c2c17723 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -480,13 +480,13 @@ void C_VGuiScreen::ClientThink( void ) if ((m_nButtonReleased & nBit) || m_bLoseThinkNextFrame) // for a button release on loosing focus { - g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); - vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); } else if (m_nButtonPressed & nBit) { - g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); - vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); } } #endif // !MAPBASE From 146df3c961b0cc7c36857045792cea756a630ed7 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 2 Aug 2023 16:48:00 -0400 Subject: [PATCH 04/64] Also suppress attack3 in vgui screen mode --- sp/src/game/client/c_baseplayer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 5a21e16e..73d593c5 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1146,7 +1146,8 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); #ifdef MAPBASE - pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; + pCmd->buttons &= ~(IN_USE | IN_ATTACK3); + pCmd->buttons |= IN_VGUIMODE; #endif // MAPBASE return; } @@ -1213,7 +1214,8 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); #ifdef MAPBASE - pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; + pCmd->buttons &= ~(IN_USE | IN_ATTACK3); + pCmd->buttons |= IN_VGUIMODE; #endif // MAPBASE } } From eb46739ab57027e52674f640b4a4c6acf4480edf Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Sat, 5 Aug 2023 18:38:04 -0400 Subject: [PATCH 05/64] Fixed vgui screens potentially crashing on save --- sp/src/game/server/vguiscreen.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index 8163131c..e26e08cc 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -82,7 +82,11 @@ bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) const char* pszOutputName = szKeyName + 1; int i = m_PanelOutputs.Find(pszOutputName); if (!m_PanelOutputs.IsValidIndex(i)) - i = m_PanelOutputs.Insert(pszOutputName, new COutputEvent); + { + auto pMem = new COutputEvent; + V_memset(pMem, 0, sizeof(COutputEvent)); + i = m_PanelOutputs.Insert(pszOutputName, pMem); + } m_PanelOutputs[i]->ParseEventAction(szValue); return true; From 9f34a64e636e7d32b8b25ab06cf2df5de1ab5d21 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Fri, 29 Dec 2023 14:08:13 -0500 Subject: [PATCH 06/64] Vgui screens now try to pass panel commands to the entity that created them --- sp/src/game/server/baseentity.h | 4 +++- sp/src/game/server/vguiscreen.cpp | 17 ++++++++++++++++- sp/src/game/server/vguiscreen.h | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 3da44bc7..7cd4670c 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -869,7 +869,9 @@ public: bool IsAIWalkable( void ); #ifdef MAPBASE - virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) {} + // Handle a potentially complex command from a client. + // Returns true if the command was handled successfully. + virtual bool HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) { return false; } #endif // MAPBASE private: diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index e26e08cc..86795342 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -224,15 +224,30 @@ int CVGuiScreen::Restore(IRestore& restore) return status; } -void CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) +// Handle a command from the client-side vgui panel. +bool CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) { +#if defined(HL2MP) // Enable this in multiplayer. + // Restrict to commands from our owning player. + if ((m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) && pClient != m_hPlayerOwner.Get()) + return false; +#endif + + // Give the owning entity a chance to handle the command. + if (GetOwnerEntity() && GetOwnerEntity()->HandleEntityCommand(pClient, pKeyValues)) + return true; + + // See if we have an output for this command. const int i = m_PanelOutputs.Find(pKeyValues->GetString()); if (m_PanelOutputs.IsValidIndex(i)) { variant_t Val; Val.Set(FIELD_VOID, NULL); m_PanelOutputs[i]->FireOutput(Val, pClient, this); + return true; } + + return false; } CBaseEntityOutput* CVGuiScreen::FindNamedOutput(const char* pszOutput) diff --git a/sp/src/game/server/vguiscreen.h b/sp/src/game/server/vguiscreen.h index 1cb7dc7e..557cacd7 100644 --- a/sp/src/game/server/vguiscreen.h +++ b/sp/src/game/server/vguiscreen.h @@ -37,7 +37,7 @@ public: virtual int Save(ISave& save); virtual int Restore(IRestore& restore); - virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); + virtual bool HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); virtual CBaseEntityOutput* FindNamedOutput(const char* pszOutput); #endif // MAPBASE From 9e2bdaab588a1ec8e7a9c96ac4deaccd45c5fc11 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Fri, 29 Dec 2023 21:15:23 -0500 Subject: [PATCH 07/64] Fixed vgui_screens always sending a mouse released event to the panel when the vgui_screen loses focus --- sp/src/game/client/c_vguiscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index c2c17723..7695afd8 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -478,7 +478,7 @@ void C_VGuiScreen::ClientThink( void ) const int nBit = i ? IN_ATTACK2 : (IN_ATTACK | IN_USE); const vgui::MouseCode nButton = i ? MOUSE_RIGHT : MOUSE_LEFT; - if ((m_nButtonReleased & nBit) || m_bLoseThinkNextFrame) // for a button release on loosing focus + if ((m_nButtonReleased & nBit) || ((m_nButtonState & nBit) && m_bLoseThinkNextFrame)) // for a button release on loosing focus { g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); From 02e232babf80b12ba7db102b39a659c584658b66 Mon Sep 17 00:00:00 2001 From: rlen Date: Tue, 2 Jan 2024 01:39:12 +0900 Subject: [PATCH 08/64] add "OnPhysGunPull" output to CPhysicsProp --- sp/src/game/server/hl2/weapon_physcannon.cpp | 5 +++++ sp/src/game/server/props.cpp | 8 ++++++++ sp/src/game/server/props.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 66991e45..19ebb8c3 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -2723,6 +2723,11 @@ CWeaponPhysCannon::FindObjectResult_t CWeaponPhysCannon::FindObject( void ) pullDir *= (mass + 0.5) * (1/50.0f); } + CPhysicsProp* pProp = dynamic_cast(pObj); + if (pProp) { + pProp->OnPhysGunPull( pOwner, pullDir ); + } + // Nudge it towards us pObj->ApplyForceCenter( pullDir ); return OBJECT_NOT_FOUND; diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 5ad4c11a..d7fcf599 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -3021,6 +3021,7 @@ BEGIN_DATADESC( CPhysicsProp ) DEFINE_OUTPUT( m_MotionEnabled, "OnMotionEnabled" ), DEFINE_OUTPUT( m_OnPhysGunPickup, "OnPhysGunPickup" ), DEFINE_OUTPUT( m_OnPhysGunOnlyPickup, "OnPhysGunOnlyPickup" ), + DEFINE_OUTPUT( m_OnPhysGunPull, "OnPhysGunPull" ), DEFINE_OUTPUT( m_OnPhysGunPunt, "OnPhysGunPunt" ), DEFINE_OUTPUT( m_OnPhysGunDrop, "OnPhysGunDrop" ), DEFINE_OUTPUT( m_OnPlayerUse, "OnPlayerUse" ), @@ -3391,6 +3392,13 @@ void CPhysicsProp::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t r CheckRemoveRagdolls(); } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPhysicsProp::OnPhysGunPull( CBasePlayer* pPhysGunUser, Vector pullDir ) { + m_OnPhysGunPull.FireOutput(pPhysGunUser, this); +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/props.h b/sp/src/game/server/props.h index ebd87c4d..c36f11bb 100644 --- a/sp/src/game/server/props.h +++ b/sp/src/game/server/props.h @@ -413,6 +413,7 @@ public: void EnableMotion( void ); bool CanBePickedUpByPhyscannon( void ); void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + void OnPhysGunPull( CBasePlayer *pPhysGunUser, Vector pullDir ); void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); bool GetPropDataAngles( const char *pKeyName, QAngle &vecAngles ); @@ -446,6 +447,7 @@ private: COutputEvent m_OnPhysGunPickup; COutputEvent m_OnPhysGunPunt; COutputEvent m_OnPhysGunOnlyPickup; + COutputEvent m_OnPhysGunPull; COutputEvent m_OnPhysGunDrop; COutputEvent m_OnPlayerUse; COutputEvent m_OnPlayerPickup; From f484aa7ebc8b6cdf5da41040456e7622fca0778d Mon Sep 17 00:00:00 2001 From: rlen Date: Mon, 19 Feb 2024 21:46:04 +0900 Subject: [PATCH 09/64] removed `pullDir` parameter from `OnPhysGunPull` --- sp/src/game/server/hl2/weapon_physcannon.cpp | 2 +- sp/src/game/server/props.cpp | 2 +- sp/src/game/server/props.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 19ebb8c3..8a246a2d 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -2725,7 +2725,7 @@ CWeaponPhysCannon::FindObjectResult_t CWeaponPhysCannon::FindObject( void ) CPhysicsProp* pProp = dynamic_cast(pObj); if (pProp) { - pProp->OnPhysGunPull( pOwner, pullDir ); + pProp->OnPhysGunPull( pOwner ); } // Nudge it towards us diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index d7fcf599..33aba263 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -3395,7 +3395,7 @@ void CPhysicsProp::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t r //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CPhysicsProp::OnPhysGunPull( CBasePlayer* pPhysGunUser, Vector pullDir ) { +void CPhysicsProp::OnPhysGunPull( CBasePlayer* pPhysGunUser ) { m_OnPhysGunPull.FireOutput(pPhysGunUser, this); } diff --git a/sp/src/game/server/props.h b/sp/src/game/server/props.h index c36f11bb..5c57824d 100644 --- a/sp/src/game/server/props.h +++ b/sp/src/game/server/props.h @@ -413,7 +413,7 @@ public: void EnableMotion( void ); bool CanBePickedUpByPhyscannon( void ); void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); - void OnPhysGunPull( CBasePlayer *pPhysGunUser, Vector pullDir ); + void OnPhysGunPull( CBasePlayer *pPhysGunUser ); void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); bool GetPropDataAngles( const char *pKeyName, QAngle &vecAngles ); From 2113410f800c8c102947f27d597cd489e60c3824 Mon Sep 17 00:00:00 2001 From: arbabf Date: Sat, 13 Apr 2024 00:43:14 +1000 Subject: [PATCH 10/64] Add random spawn type for env_headcrabcanister --- .../game/server/hl2/env_headcrabcanister.cpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sp/src/game/server/hl2/env_headcrabcanister.cpp b/sp/src/game/server/hl2/env_headcrabcanister.cpp index e94fe3f1..139b7b08 100644 --- a/sp/src/game/server/hl2/env_headcrabcanister.cpp +++ b/sp/src/game/server/hl2/env_headcrabcanister.cpp @@ -33,6 +33,9 @@ ConVar sk_env_headcrabcanister_shake_radius( "sk_env_headcrabcanister_shake_radi ConVar sk_env_headcrabcanister_shake_radius_vehicle( "sk_env_headcrabcanister_shake_radius_vehicle", "2500" ); #define ENV_HEADCRABCANISTER_TRAIL_TIME 3.0f +#ifdef MAPBASE +#define RANDOM_CRAB_TYPE 3 +#endif //----------------------------------------------------------------------------- // Spawn flags @@ -258,7 +261,22 @@ void CEnvHeadcrabCanister::Precache( void ) PrecacheScriptSound( "HeadcrabCanister.SkyboxExplosion" ); PrecacheScriptSound( "HeadcrabCanister.Open" ); +#ifdef MAPBASE + if (m_nHeadcrabType != RANDOM_CRAB_TYPE) + { + UTIL_PrecacheOther( s_pHeadcrabClass[m_nHeadcrabType] ); + } + else + { + // precache all the headcrabs if we're spawning random species + for (int i = 0; i < ARRAYSIZE(s_pHeadcrabClass); i++) + { + UTIL_PrecacheOther( s_pHeadcrabClass[i] ); + } + } +#else UTIL_PrecacheOther( s_pHeadcrabClass[m_nHeadcrabType] ); +#endif } @@ -733,7 +751,17 @@ void CEnvHeadcrabCanister::HeadcrabCanisterSpawnHeadcrabThink() int nHeadCrabAttachment = LookupAttachment( "headcrab" ); if ( GetAttachment( nHeadCrabAttachment, vecSpawnPosition, vecSpawnAngles ) ) { +#ifdef MAPBASE + int iHeadcrabType = m_nHeadcrabType; + if (m_nHeadcrabType == RANDOM_CRAB_TYPE) + { + iHeadcrabType = RandomInt( 0, ARRAYSIZE(s_pHeadcrabClass) - 1 ); + } + + CBaseEntity *pEnt = CreateEntityByName( s_pHeadcrabClass[iHeadcrabType] ); +#else CBaseEntity *pEnt = CreateEntityByName( s_pHeadcrabClass[m_nHeadcrabType] ); +#endif CBaseHeadcrab *pHeadCrab = assert_cast(pEnt); // Necessary to get it to eject properly (don't allow the NPC From f370074d10ccdeaaad0ee311cc13cc5261529efa Mon Sep 17 00:00:00 2001 From: arbabf Date: Sat, 13 Apr 2024 00:46:36 +1000 Subject: [PATCH 11/64] Fix spacing to be more consistent --- sp/src/game/server/hl2/env_headcrabcanister.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/hl2/env_headcrabcanister.cpp b/sp/src/game/server/hl2/env_headcrabcanister.cpp index 139b7b08..15a39f0d 100644 --- a/sp/src/game/server/hl2/env_headcrabcanister.cpp +++ b/sp/src/game/server/hl2/env_headcrabcanister.cpp @@ -262,14 +262,14 @@ void CEnvHeadcrabCanister::Precache( void ) PrecacheScriptSound( "HeadcrabCanister.Open" ); #ifdef MAPBASE - if (m_nHeadcrabType != RANDOM_CRAB_TYPE) + if ( m_nHeadcrabType != RANDOM_CRAB_TYPE ) { UTIL_PrecacheOther( s_pHeadcrabClass[m_nHeadcrabType] ); } else { // precache all the headcrabs if we're spawning random species - for (int i = 0; i < ARRAYSIZE(s_pHeadcrabClass); i++) + for ( int i = 0; i < ARRAYSIZE( s_pHeadcrabClass ); i++ ) { UTIL_PrecacheOther( s_pHeadcrabClass[i] ); } @@ -753,9 +753,9 @@ void CEnvHeadcrabCanister::HeadcrabCanisterSpawnHeadcrabThink() { #ifdef MAPBASE int iHeadcrabType = m_nHeadcrabType; - if (m_nHeadcrabType == RANDOM_CRAB_TYPE) + if ( m_nHeadcrabType == RANDOM_CRAB_TYPE ) { - iHeadcrabType = RandomInt( 0, ARRAYSIZE(s_pHeadcrabClass) - 1 ); + iHeadcrabType = RandomInt( 0, ARRAYSIZE( s_pHeadcrabClass ) - 1 ); } CBaseEntity *pEnt = CreateEntityByName( s_pHeadcrabClass[iHeadcrabType] ); From 2c001ff2595a3b6414b78027f170ca8ee2291916 Mon Sep 17 00:00:00 2001 From: arbabf Date: Sat, 13 Apr 2024 16:10:01 +1000 Subject: [PATCH 12/64] Change RANDOM_CRAB_TYPE to -1 --- sp/src/game/server/hl2/env_headcrabcanister.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/env_headcrabcanister.cpp b/sp/src/game/server/hl2/env_headcrabcanister.cpp index 15a39f0d..4cf7fffb 100644 --- a/sp/src/game/server/hl2/env_headcrabcanister.cpp +++ b/sp/src/game/server/hl2/env_headcrabcanister.cpp @@ -34,7 +34,7 @@ ConVar sk_env_headcrabcanister_shake_radius_vehicle( "sk_env_headcrabcanister_sh #define ENV_HEADCRABCANISTER_TRAIL_TIME 3.0f #ifdef MAPBASE -#define RANDOM_CRAB_TYPE 3 +#define RANDOM_CRAB_TYPE -1 #endif //----------------------------------------------------------------------------- From a49cff34f9663f24bdf624b4202f400d0cdcec15 Mon Sep 17 00:00:00 2001 From: azzy <67557558+azzyr@users.noreply.github.com> Date: Sat, 27 Apr 2024 04:31:21 +0300 Subject: [PATCH 13/64] Fix vertex blend swapping in Hammer for SDK_LightmappedGeneric Out of bounds array index corrupting the stack --- .../materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp index 6f64a15d..2273db49 100644 --- a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp @@ -1537,7 +1537,7 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar** float envMapOrigin[4] = {0,0,0,0}; params[info.m_nEnvmapOrigin]->GetVecValue( envMapOrigin, 3 ); #ifdef MAPBASE - envMapOrigin[4] = bEditorBlend ? 1.0f : 0.0f; + envMapOrigin[3] = bEditorBlend ? 1.0f : 0.0f; #endif pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, envMapOrigin ); From 24f36566320776378c65d09de31262316cd89c39 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Fri, 21 Jun 2024 18:22:04 -0500 Subject: [PATCH 14/64] Add capability to +USE serverside ragdolls and toggle cleanup of individual ragdolls --- sp/src/game/server/hl2/weapon_physcannon.cpp | 43 +++++++++++-- sp/src/game/server/physics_prop_ragdoll.cpp | 64 +++++++++++++++++++- sp/src/game/server/physics_prop_ragdoll.h | 10 +++ sp/src/game/shared/ragdoll_shared.cpp | 26 ++++++++ sp/src/game/shared/ragdoll_shared.h | 5 +- 5 files changed, 139 insertions(+), 9 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 66991e45..8735e244 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -490,6 +490,9 @@ public: float GetLoadWeight( void ) const { return m_flLoadWeight; } void SetAngleAlignment( float alignAngleCosine ) { m_angleAlignment = alignAngleCosine; } void SetIgnorePitch( bool bIgnore ) { m_bIgnoreRelativePitch = bIgnore; } +#ifdef MAPBASE + void SetDontUseListMass( bool bDontUse ) { m_bDontUseListMass = bDontUse; } +#endif QAngle TransformAnglesToPlayerSpace( const QAngle &anglesIn, CBasePlayer *pPlayer ); QAngle TransformAnglesFromPlayerSpace( const QAngle &anglesIn, CBasePlayer *pPlayer ); @@ -531,6 +534,12 @@ private: // NVNT player controlling this grab controller CBasePlayer* m_pControllingPlayer; +#ifdef MAPBASE + // Prevents using the added mass of every part of the object + // (not saved due to only being used upon attach) + bool m_bDontUseListMass; +#endif + friend class CWeaponPhysCannon; }; @@ -581,6 +590,9 @@ CGrabController::CGrabController( void ) m_flDistanceOffset = 0; // NVNT constructing m_pControllingPlayer to NULL m_pControllingPlayer = NULL; +#ifdef MAPBASE + m_bDontUseListMass = false; +#endif } CGrabController::~CGrabController( void ) @@ -783,12 +795,18 @@ void CGrabController::AttachEntity( CBasePlayer *pPlayer, CBaseEntity *pEntity, { float mass = pList[i]->GetMass(); pList[i]->GetDamping( NULL, &m_savedRotDamping[i] ); - m_flLoadWeight += mass; m_savedMass[i] = mass; - // reduce the mass to prevent the player from adding crazy amounts of energy to the system - pList[i]->SetMass( REDUCED_CARRY_MASS / flFactor ); - pList[i]->SetDamping( NULL, &damping ); +#ifdef MAPBASE + if (!m_bDontUseListMass || pList[i] == pPhys) +#endif + { + m_flLoadWeight += mass; + + // reduce the mass to prevent the player from adding crazy amounts of energy to the system + pList[i]->SetMass( REDUCED_CARRY_MASS / flFactor ); + pList[i]->SetDamping( NULL, &damping ); + } } // NVNT setting m_pControllingPlayer to the player attached @@ -1077,7 +1095,24 @@ void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject ) Pickup_OnPhysGunPickup( pObject, m_pPlayer, PICKED_UP_BY_PLAYER ); +#ifdef MAPBASE + bool bUseGrabPos = false; + Vector vecGrabPos; + if ( dynamic_cast( pObject ) ) + { + m_grabController.SetDontUseListMass( true ); + + // Approximate where we're grabbing from + vecGrabPos = pPlayer->EyePosition() + (pPlayer->EyeDirection3D() * 16.0f); + bUseGrabPos = true; + } + else + m_grabController.SetDontUseListMass( false ); + + m_grabController.AttachEntity( pPlayer, pObject, pPhysics, false, vecGrabPos, bUseGrabPos ); +#else m_grabController.AttachEntity( pPlayer, pObject, pPhysics, false, vec3_origin, false ); +#endif // NVNT apply a downward force to simulate the mass of the held object. #if defined( WIN32 ) && !defined( _X360 ) HapticSetConstantForce(m_pPlayer,clamp(m_grabController.GetLoadWeight()*0.1,1,6)*Vector(0,-1,0)); diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index cc788fc6..e208e620 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -30,6 +30,8 @@ #ifdef MAPBASE ConVar ragdoll_autointeractions("ragdoll_autointeractions", "1", FCVAR_NONE, "Controls whether we should rely on hardcoded keyvalues or automatic flesh checks for ragdoll physgun interactions."); #define IsBody() VPhysicsIsFlesh() + +ConVar ragdoll_always_allow_use( "ragdoll_always_allow_use", "0", FCVAR_NONE, "Allows all ragdolls to be used and, if they aren't explicitly set to prevent pickup, picked up." ); #endif //----------------------------------------------------------------------------- @@ -58,6 +60,8 @@ const float ATTACHED_DAMPING_SCALE = 50.0f; #define SF_RAGDOLLPROP_STARTASLEEP 0x10000 #ifdef MAPBASE #define SF_RAGDOLLPROP_FIXED_CONSTRAINTS 0x20000 +#define SF_RAGDOLLPROP_ALLOW_USE 0x40000 +#define SF_RAGDOLLPROP_PREVENT_PICKUP 0x80000 #endif //----------------------------------------------------------------------------- @@ -104,6 +108,8 @@ BEGIN_DATADESC(CRagdollProp) #ifdef MAPBASE DEFINE_INPUTFUNC( FIELD_VOID, "Wake", InputWake ), DEFINE_INPUTFUNC( FIELD_VOID, "Sleep", InputSleep ), + DEFINE_INPUTFUNC( FIELD_VOID, "AddToLRU", InputAddToLRU ), + DEFINE_INPUTFUNC( FIELD_VOID, "RemoveFromLRU", InputRemoveFromLRU ), #endif DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputTurnOn ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputTurnOff ), @@ -125,6 +131,10 @@ BEGIN_DATADESC(CRagdollProp) DEFINE_FIELD( m_strSourceClassName, FIELD_STRING ), DEFINE_FIELD( m_bHasBeenPhysgunned, FIELD_BOOLEAN ), +#ifdef MAPBASE + DEFINE_OUTPUT( m_OnPlayerUse, "OnPlayerUse" ), +#endif + // think functions DEFINE_THINKFUNC( SetDebrisThink ), DEFINE_THINKFUNC( ClearFlagsThink ), @@ -334,9 +344,39 @@ void CRagdollProp::Precache( void ) int CRagdollProp::ObjectCaps() { - return BaseClass::ObjectCaps() | FCAP_WCEDIT_POSITION; + int caps = FCAP_WCEDIT_POSITION; + +#ifdef MAPBASE + if (HasSpawnFlags( SF_RAGDOLLPROP_ALLOW_USE ) || ragdoll_always_allow_use.GetBool()) + caps |= FCAP_IMPULSE_USE; +#endif + + return BaseClass::ObjectCaps() | caps; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pActivator - +// *pCaller - +// useType - +// value - +//----------------------------------------------------------------------------- +void CRagdollProp::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CBasePlayer *pPlayer = ToBasePlayer( pActivator ); + if (pPlayer) + { + m_OnPlayerUse.FireOutput( pActivator, this ); + + if (!HasSpawnFlags( SF_RAGDOLLPROP_PREVENT_PICKUP )) + { + pPlayer->PickupObject( this, false ); + } + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -405,7 +445,7 @@ void CRagdollProp::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t r m_bHasBeenPhysgunned = true; #ifdef MAPBASE - if( (ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" ) ) + if( ((ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" )) && reason != PICKED_UP_BY_PLAYER ) #else if( HasPhysgunInteraction( "onpickup", "boogie" ) ) #endif @@ -447,7 +487,7 @@ void CRagdollProp::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reaso m_flLastPhysicsInfluenceTime = gpGlobals->curtime; #ifdef MAPBASE - if( (ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" ) ) + if( ((ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" )) && (Reason != DROPPED_BY_PLAYER && Reason != THROWN_BY_PLAYER) ) #else if( HasPhysgunInteraction( "onpickup", "boogie" ) ) #endif @@ -1844,6 +1884,24 @@ void CRagdollProp::InputSleep( inputdata_t &inputdata ) } } } + +//----------------------------------------------------------------------------- +// Purpose: Adds ragdoll to LRU. +//----------------------------------------------------------------------------- +void CRagdollProp::InputAddToLRU( inputdata_t &inputdata ) +{ + AddSpawnFlags( SF_RAGDOLLPROP_USE_LRU_RETIREMENT ); + s_RagdollLRU.MoveToTopOfLRU( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Removes ragdoll from LRU. +//----------------------------------------------------------------------------- +void CRagdollProp::InputRemoveFromLRU( inputdata_t &inputdata ) +{ + RemoveSpawnFlags( SF_RAGDOLLPROP_USE_LRU_RETIREMENT ); + s_RagdollLRU.RemoveFromLRU( this ); +} #endif void CRagdollProp::InputTurnOn( inputdata_t &inputdata ) diff --git a/sp/src/game/server/physics_prop_ragdoll.h b/sp/src/game/server/physics_prop_ragdoll.h index 46e527c3..82a3d77a 100644 --- a/sp/src/game/server/physics_prop_ragdoll.h +++ b/sp/src/game/server/physics_prop_ragdoll.h @@ -42,6 +42,10 @@ public: int ObjectCaps(); +#ifdef MAPBASE + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +#endif + DECLARE_SERVERCLASS(); // Don't treat as a live target virtual bool IsAlive( void ) { return false; } @@ -113,6 +117,8 @@ public: #ifdef MAPBASE void InputWake( inputdata_t &inputdata ); void InputSleep( inputdata_t &inputdata ); + void InputAddToLRU( inputdata_t &inputdata ); + void InputRemoveFromLRU( inputdata_t &inputdata ); #endif void InputTurnOn( inputdata_t &inputdata ); void InputTurnOff( inputdata_t &inputdata ); @@ -158,6 +164,10 @@ private: string_t m_strSourceClassName; bool m_bHasBeenPhysgunned; +#ifdef MAPBASE + COutputEvent m_OnPlayerUse; +#endif + // If not 1, then allow underlying sequence to blend in with simulated bone positions CNetworkVar( float, m_flBlendWeight ); CNetworkVar( int, m_nOverlaySequence ); diff --git a/sp/src/game/shared/ragdoll_shared.cpp b/sp/src/game/shared/ragdoll_shared.cpp index a9da2613..494c9ebe 100644 --- a/sp/src/game/shared/ragdoll_shared.cpp +++ b/sp/src/game/shared/ragdoll_shared.cpp @@ -1178,6 +1178,32 @@ void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImpo #endif } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Remove it from the LRU +//----------------------------------------------------------------------------- +void CRagdollLRURetirement::RemoveFromLRU( CBaseAnimating *pRagdoll ) +{ + for (int i = 0; i < m_LRU.Count(); i++) + { + if (m_LRU[i].Get() == pRagdoll) + { + m_LRU.Remove( i ); + return; + } + } + + for (int i = 0; i < m_LRUImportantRagdolls.Count(); i++) + { + if (m_LRUImportantRagdolls[i].Get() == pRagdoll) + { + m_LRUImportantRagdolls.Remove( i ); + return; + } + } +} +#endif + //EFFECT/ENTITY TRANSFERS diff --git a/sp/src/game/shared/ragdoll_shared.h b/sp/src/game/shared/ragdoll_shared.h index 5f4f7058..db2bd7b2 100644 --- a/sp/src/game/shared/ragdoll_shared.h +++ b/sp/src/game/shared/ragdoll_shared.h @@ -114,8 +114,9 @@ public: virtual void FrameUpdatePostEntityThink( void ); // Move it to the top of the LRU -#ifdef MAPBASE // From Alien Swarm SDK - void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false, float flForcedRetireTime = 0.0f ); +#ifdef MAPBASE + void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false, float flForcedRetireTime = 0.0f ); // From Alien Swarm SDK + void RemoveFromLRU( CBaseAnimating *pRagdoll ); #else void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false ); #endif From 33e047a442a0d7677a50950e3ba2eda873face81 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 22 Jun 2024 01:36:20 -0500 Subject: [PATCH 15/64] Primitive chromatic aberration effect for env_screeneffect --- sp/src/game/client/c_env_screenoverlay.cpp | 39 +++ .../episodic/episodic_screenspaceeffects.cpp | 222 ++++++++++++++++++ .../episodic/episodic_screenspaceeffects.h | 34 +++ 3 files changed, 295 insertions(+) diff --git a/sp/src/game/client/c_env_screenoverlay.cpp b/sp/src/game/client/c_env_screenoverlay.cpp index a3125882..e6d7e553 100644 --- a/sp/src/game/client/c_env_screenoverlay.cpp +++ b/sp/src/game/client/c_env_screenoverlay.cpp @@ -219,6 +219,11 @@ enum SCREENEFFECT_EP2_ADVISOR_STUN, SCREENEFFECT_EP1_INTRO, SCREENEFFECT_EP2_GROGGY, + +#ifdef MAPBASE + SCREENEFFECT_MAPBASE_CHROMATIC_BLUR = 100, // Overlays 3 different frames of red, green, and blue tints respectively with different offsets + SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION, // Similar to above, except it stretches frames in addition to offsetting them +#endif }; // ============================================================================ @@ -303,6 +308,21 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys ); g_pScreenSpaceEffects->EnableScreenSpaceEffect( "ep2_groggy" ); } +#ifdef MAPBASE + else if ( m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_BLUR || m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + return; + + // Set our keys + pKeys->SetFloat( "duration", m_flDuration ); + pKeys->SetInt( "fadeout", 0 ); + pKeys->SetInt( "stretch", m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "mapbase_chromatic_aberration", pKeys ); + g_pScreenSpaceEffects->EnableScreenSpaceEffect( "mapbase_chromatic_aberration" ); + } +#endif pKeys->deleteThis(); } @@ -349,6 +369,25 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys ); } +#ifdef MAPBASE + else if ( m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_BLUR || m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + return; + + // Create a keyvalue block to set these params + KeyValues *pKeys = new KeyValues( "keys" ); + if ( pKeys == NULL ) + return; + + // Set our keys + pKeys->SetFloat( "duration", m_flDuration ); + pKeys->SetInt( "fadeout", 1 ); + pKeys->SetInt( "stretch", m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "mapbase_chromatic_aberration", pKeys ); + } +#endif break; } diff --git a/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp b/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp index a2b59bbc..fd8cafb2 100644 --- a/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp +++ b/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp @@ -462,3 +462,225 @@ void CEP2StunEffect::Render( int x, int y, int w, int h ) pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PopMatrix(); } + +// ================================================================================================================ +// +// Chromatic Aberration +// +// ================================================================================================================ + +#ifdef MAPBASE +ConVar r_chromatic_aberration_offset( "r_chromatic_aberration_offset", "8.0" ); +ConVar r_chromatic_aberration_intensity( "r_chromatic_aberration_intensity", "0.2" ); +ConVar r_chromatic_aberration_noise( "r_chromatic_aberration_noise", "4.0" ); + +ConVar r_chromatic_aberration_frame1_clr( "r_chromatic_aberration_frame1_clr", "1.0 0.0 0.0 1.0" ); +ConVar r_chromatic_aberration_frame1_offset_x( "r_chromatic_aberration_frame1_offset_x", "1.0" ); +ConVar r_chromatic_aberration_frame1_offset_y( "r_chromatic_aberration_frame1_offset_y", "4.0" ); + +ConVar r_chromatic_aberration_frame2_clr( "r_chromatic_aberration_frame2_clr", "0.0 1.0 0.0 1.0" ); +ConVar r_chromatic_aberration_frame2_offset_x( "r_chromatic_aberration_frame2_offset_x", "-5.0" ); +ConVar r_chromatic_aberration_frame2_offset_y( "r_chromatic_aberration_frame2_offset_y", "-1.0" ); + +ConVar r_chromatic_aberration_frame3_clr( "r_chromatic_aberration_frame3_clr", "0.0 0.0 1.0 1.0" ); +ConVar r_chromatic_aberration_frame3_offset_x( "r_chromatic_aberration_frame3_offset_x", "3.0" ); +ConVar r_chromatic_aberration_frame3_offset_y( "r_chromatic_aberration_frame3_offset_y", "-3.0" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CChromaticAberrationEffect::Init( void ) +{ + m_flDuration = 0.0f; + m_flFinishTime = 0.0f; + m_bUpdateView = true; + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE ); + m_EffectMaterial.Init( "__stuneffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues ); + m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS ); +} + +void CChromaticAberrationEffect::Shutdown( void ) +{ + m_EffectMaterial.Shutdown(); + m_StunTexture.Shutdown(); +} + +//------------------------------------------------------------------------------ +// Purpose: Pick up changes in our parameters +//------------------------------------------------------------------------------ +void CChromaticAberrationEffect::SetParameters( KeyValues *params ) +{ + if( params->FindKey( "duration" ) ) + { + m_flDuration = params->GetFloat( "duration" ); + m_flFinishTime = gpGlobals->curtime + m_flDuration; + m_bUpdateView = true; + } + + if( params->FindKey( "fadeout" ) ) + { + m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 ); + } + + if( params->FindKey( "stretch" ) ) + { + m_bStretch = ( params->GetInt( "stretch" ) == 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CChromaticAberrationEffect::RenderColorFrame( CMatRenderContextPtr &pRenderContext, float flEffectPerc, int nColorMode, int x, int y, int w, int h ) +{ + // Change color + float flColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + + float viewOffsX = flEffectPerc; + if (m_bStretch) + viewOffsX *= r_chromatic_aberration_offset.GetFloat() * 2; + else + viewOffsX *= r_chromatic_aberration_offset.GetFloat(); + + float viewOffsY = viewOffsX; + + { + char szColor[16] = { 0 }; + float flNoise = sin( gpGlobals->curtime * r_chromatic_aberration_noise.GetFloat() ) * flEffectPerc; + + switch (nColorMode) + { + // Red + case 0: + Q_strncpy( szColor, r_chromatic_aberration_frame1_clr.GetString(), sizeof( szColor ) ); + + viewOffsX *= r_chromatic_aberration_frame1_offset_x.GetFloat(); + viewOffsY *= r_chromatic_aberration_frame1_offset_y.GetFloat(); + + viewOffsX += flNoise; + viewOffsY += flNoise; + break; + + // Green + case 1: + Q_strncpy( szColor, r_chromatic_aberration_frame2_clr.GetString(), sizeof( szColor ) ); + + viewOffsX *= r_chromatic_aberration_frame2_offset_x.GetFloat(); + viewOffsY *= r_chromatic_aberration_frame2_offset_y.GetFloat(); + + viewOffsX += flNoise; + viewOffsY += flNoise; + break; + + // Blue + case 2: + Q_strncpy( szColor, r_chromatic_aberration_frame3_clr.GetString(), sizeof( szColor ) ); + + viewOffsX *= r_chromatic_aberration_frame3_offset_x.GetFloat(); + viewOffsY *= r_chromatic_aberration_frame3_offset_y.GetFloat(); + + viewOffsX += flNoise; + viewOffsY += flNoise; + break; + } + + char *c = strtok( szColor, " " ); + for (int i = 0; i < 4 && c != NULL; i++, c = strtok( NULL, " " )) + { + flColor[i] = atof( c ); + } + } + + if (flColor[3] == 0.0f || g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80) + return; + + m_EffectMaterial->ColorModulate( flColor[0], flColor[1], flColor[2] ); + + // Set alpha blend value + float flOverlayAlpha = clamp( r_chromatic_aberration_intensity.GetFloat() * flEffectPerc * flColor[3], 0.0f, 1.0f); + m_EffectMaterial->AlphaModulate( flOverlayAlpha ); + + // Draw full screen alpha-blended quad + if (m_bStretch) + { + float vX = x - (viewOffsX * 0.5f); + float vY = y - (viewOffsY * 0.5f); + + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, vX, vY, w + viewOffsX, h + viewOffsY, + 0, 0, (m_StunTexture->GetActualWidth()-1), (m_StunTexture->GetActualHeight()-1), + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + } + else + { + float vX = x + viewOffsX; + float vY = y + viewOffsY; + + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, 0, 0, w, h, + vX, vY, (m_StunTexture->GetActualWidth()-1)+vX, (m_StunTexture->GetActualHeight()-1)+vY, + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CChromaticAberrationEffect::Render( int x, int y, int w, int h ) +{ + // Make sure we're ready to play this effect + if ( !IsEnabled() ) + return; + + if ( m_bFadeOut && m_flFinishTime < gpGlobals->curtime ) + { + g_pScreenSpaceEffects->DisableScreenSpaceEffect( "mapbase_chromatic_aberration" ); + return; + } + + CMatRenderContextPtr pRenderContext( materials ); + + // Set ourselves to the proper rendermode + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + // Draw the texture if we're using it + if ( m_bUpdateView ) + { + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + m_bUpdateView = false; + } + + float flEffectPerc = SmoothCurve( clamp( ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration, 0.0f, 1.0f ) ); + if (!m_bFadeOut) + flEffectPerc = 1.0f - flEffectPerc; + + RenderColorFrame( pRenderContext, flEffectPerc, 0, x, y, w, h ); + RenderColorFrame( pRenderContext, flEffectPerc, 1, x, y, w, h ); + RenderColorFrame( pRenderContext, flEffectPerc, 2, x, y, w, h ); + + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + + // Restore our state + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} +#endif diff --git a/sp/src/game/client/episodic/episodic_screenspaceeffects.h b/sp/src/game/client/episodic/episodic_screenspaceeffects.h index ff5bc716..661aa403 100644 --- a/sp/src/game/client/episodic/episodic_screenspaceeffects.h +++ b/sp/src/game/client/episodic/episodic_screenspaceeffects.h @@ -116,4 +116,38 @@ private: ADD_SCREENSPACE_EFFECT( CEP2StunEffect, ep2_groggy ); +#ifdef MAPBASE +class CChromaticAberrationEffect : public IScreenSpaceEffect +{ +public: + CChromaticAberrationEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ), + m_bEnabled( false ), + m_bFadeOut( false ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; }; + virtual bool IsEnabled( ) { return m_bEnabled; } + + virtual void RenderColorFrame( CMatRenderContextPtr &pRenderContext, float flEffectPerc, int nColorMode, int x, int y, int w, int h ); + virtual void Render( int x, int y, int w, int h ); + +private: + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; + bool m_bStretch; + bool m_bFadeOut; + bool m_bEnabled; +}; + +ADD_SCREENSPACE_EFFECT( CChromaticAberrationEffect, mapbase_chromatic_aberration ); +#endif + #endif // EPISODIC_SCREENSPACEEFFECTS_H From 73988dcc7cdae041cff3bed41afc6c5c40bdeadb Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 22 Jun 2024 02:33:19 -0500 Subject: [PATCH 16/64] Fix maps with multiple sky_cameras not using the correct sky_camera after loading a save --- sp/src/game/server/SkyCamera.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sp/src/game/server/SkyCamera.cpp b/sp/src/game/server/SkyCamera.cpp index be9716d4..f5bb2825 100644 --- a/sp/src/game/server/SkyCamera.cpp +++ b/sp/src/game/server/SkyCamera.cpp @@ -211,6 +211,11 @@ void CSkyCamera::Activate( ) } } #endif + +#ifdef MAPBASE + if (HasSpawnFlags( SF_SKY_MASTER )) + g_hActiveSkybox = this; +#endif } #ifdef MAPBASE @@ -368,9 +373,11 @@ void CSkyCamera::InputActivateSkybox( inputdata_t &inputdata ) // Deactivate that skybox pActiveSky->SetThink( NULL ); pActiveSky->SetNextThink( TICK_NEVER_THINK ); + pActiveSky->RemoveSpawnFlags( SF_SKY_MASTER ); } g_hActiveSkybox = this; + AddSpawnFlags( SF_SKY_MASTER ); if (HasSpawnFlags( SF_SKY_START_UPDATING )) InputStartUpdating( inputdata ); @@ -384,6 +391,7 @@ void CSkyCamera::InputDeactivateSkybox( inputdata_t &inputdata ) if (GetCurrentSkyCamera() == this) { g_hActiveSkybox = NULL; + RemoveSpawnFlags( SF_SKY_MASTER ); // ClientData doesn't catch this immediately CBasePlayer *pPlayer = NULL; From cd6ec90a0f74d85a430af661a6d6ea5f694b10c8 Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Mon, 24 Jun 2024 23:42:07 +0200 Subject: [PATCH 17/64] Fixed the issue. --- sp/src/materialsystem/stdshaders/BlurFilterY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/materialsystem/stdshaders/BlurFilterY.cpp b/sp/src/materialsystem/stdshaders/BlurFilterY.cpp index 57db29c0..f252fea5 100644 --- a/sp/src/materialsystem/stdshaders/BlurFilterY.cpp +++ b/sp/src/materialsystem/stdshaders/BlurFilterY.cpp @@ -85,7 +85,7 @@ BEGIN_VS_SHADER_FLAGS( BlurFilterY, "Help for BlurFilterY", SHADER_NOT_EDITABLE // The temp buffer is 1/4 back buffer size ITexture *src_texture = params[BASETEXTURE]->GetTextureValue(); - int height = src_texture->GetActualWidth(); + int height = src_texture->GetActualHeight(); float dY = 1.0f / height; // dY *= 0.4; float v[4]; From 5cf63d4eb6b6840c26d257c4c122a128764f44c9 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Fri, 28 Jun 2024 16:08:45 -0500 Subject: [PATCH 18/64] Spotlight "Ignore solid" keyvalue from MP branch --- sp/src/game/server/point_spotlight.cpp | 32 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/point_spotlight.cpp b/sp/src/game/server/point_spotlight.cpp index d5901714..71aad0b1 100644 --- a/sp/src/game/server/point_spotlight.cpp +++ b/sp/src/game/server/point_spotlight.cpp @@ -62,6 +62,7 @@ private: private: bool m_bSpotlightOn; bool m_bEfficientSpotlight; + bool m_bIgnoreSolid; Vector m_vSpotlightTargetPos; Vector m_vSpotlightCurrentPos; Vector m_vSpotlightDir; @@ -100,6 +101,7 @@ BEGIN_DATADESC( CPointSpotlight ) DEFINE_FIELD( m_vSpotlightDir, FIELD_VECTOR ), DEFINE_FIELD( m_nHaloSprite, FIELD_INTEGER ), + DEFINE_KEYFIELD( m_bIgnoreSolid, FIELD_BOOLEAN, "IgnoreSolid" ), DEFINE_KEYFIELD( m_flSpotlightMaxLength,FIELD_FLOAT, "SpotlightLength"), DEFINE_KEYFIELD( m_flSpotlightGoalWidth,FIELD_FLOAT, "SpotlightWidth"), DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ), @@ -138,6 +140,7 @@ CPointSpotlight::CPointSpotlight() #endif m_flHDRColorScale = 1.0f; m_nMinDXLevel = 0; + m_bIgnoreSolid = false; #ifdef MAPBASE m_flHaloScale = 60.0f; #endif @@ -380,12 +383,21 @@ void CPointSpotlight::SpotlightCreate(void) AngleVectors( GetAbsAngles(), &m_vSpotlightDir ); - trace_t tr; - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); + Vector vTargetPos; + if ( m_bIgnoreSolid ) + { + vTargetPos = GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength; + } + else + { + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + vTargetPos = tr.endpos; + } m_hSpotlightTarget = (CSpotlightEnd*)CreateEntityByName( "spotlight_end" ); m_hSpotlightTarget->Spawn(); - m_hSpotlightTarget->SetAbsOrigin( tr.endpos ); + m_hSpotlightTarget->SetAbsOrigin( vTargetPos ); m_hSpotlightTarget->SetOwnerEntity( this ); m_hSpotlightTarget->m_clrRender = m_clrRender; m_hSpotlightTarget->m_Radius = m_flSpotlightMaxLength; @@ -437,9 +449,17 @@ Vector CPointSpotlight::SpotlightCurrentPos(void) AngleVectors( GetAbsAngles(), &m_vSpotlightDir ); // Get beam end point. Only collide with solid objects, not npcs - trace_t tr; - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + (m_vSpotlightDir * 2 * m_flSpotlightMaxLength), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); - return tr.endpos; + Vector vEndPos = GetAbsOrigin() + ( m_vSpotlightDir * 2 * m_flSpotlightMaxLength ); + if ( m_bIgnoreSolid ) + { + return vEndPos; + } + else + { + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), vEndPos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + return tr.endpos; + } } //------------------------------------------------------------------------------ From 41233cb475750a09e4a571909d069a9bb096a8be Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Sat, 27 Jul 2024 23:49:31 +0200 Subject: [PATCH 19/64] Added Melee attack keyvalue --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 1 + sp/src/game/server/hl2/npc_BaseZombie.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index f751d09a..1c5cde10 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -211,6 +211,7 @@ BEGIN_DATADESC( CNPC_BaseZombie ) DEFINE_FIELD( m_fIsTorso, FIELD_BOOLEAN ), #ifdef MAPBASE DEFINE_KEYFIELD( m_fIsHeadless, FIELD_BOOLEAN, "Headless" ), + DEFINE_KEYFIELD( m_flMeleeReach, FIELD_FLOAT, "MeleeReach" ), #else DEFINE_FIELD( m_fIsHeadless, FIELD_BOOLEAN ), #endif diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index fb17f037..aa7541c1 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -20,8 +20,6 @@ #define ENVELOPE_CONTROLLER (CSoundEnvelopeController::GetController()) -#define ZOMBIE_MELEE_REACH 55 - extern int AE_ZOMBIE_ATTACK_RIGHT; extern int AE_ZOMBIE_ATTACK_LEFT; extern int AE_ZOMBIE_ATTACK_BOTH; @@ -141,7 +139,7 @@ public: } int MeleeAttack1Conditions ( float flDot, float flDist ); - virtual float GetClawAttackRange() const { return ZOMBIE_MELEE_REACH; } + virtual float GetClawAttackRange() const { return m_flMeleeReach; } // No range attacks int RangeAttack1Conditions ( float flDot, float flDist ) { return( 0 ); } @@ -257,6 +255,8 @@ protected: float m_flNextFlinch; + float m_flMeleeReach; + bool m_bHeadShot; // Used to determine the survival of our crab beyond our death. // From a736b0f96a72136223465cbca9f22d4590f38c14 Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Sun, 28 Jul 2024 14:11:06 +0200 Subject: [PATCH 20/64] Added new spawnflag --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 2 +- sp/src/game/server/hl2/npc_BaseZombie.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index 1c5cde10..0799fcf6 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -787,7 +787,7 @@ bool CNPC_BaseZombie::ShouldBecomeTorso( const CTakeDamageInfo &info, float flDa HeadcrabRelease_t CNPC_BaseZombie::ShouldReleaseHeadcrab( const CTakeDamageInfo &info, float flDamageThreshold ) { #ifdef MAPBASE - if ( m_iHealth <= 0 && !m_fIsHeadless ) + if ( m_iHealth <= 0 && !m_fIsHeadless && !HasSpawnFlags(SF_ZOMBIE_NO_HEADCRAB_SPAWN)) #else if ( m_iHealth <= 0 ) #endif diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index aa7541c1..16ca0db9 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -43,6 +43,7 @@ extern int AE_ZOMBIE_POUND; #ifdef MAPBASE #define SF_ZOMBIE_NO_TORSO ( 1 << 15 ) +#define SF_ZOMBIE_NO_HEADCRAB_SPAWN ( 1 << 16 ) #endif From 4f14f0c5cc056a8d8a121ccbbbab858e9db74e6d Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Wed, 7 Aug 2024 13:16:37 +0200 Subject: [PATCH 21/64] Fixed the issue. --- sp/src/game/server/hl2/weapon_flaregun.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_flaregun.cpp b/sp/src/game/server/hl2/weapon_flaregun.cpp index 110f5c66..f2b74c46 100644 --- a/sp/src/game/server/hl2/weapon_flaregun.cpp +++ b/sp/src/game/server/hl2/weapon_flaregun.cpp @@ -568,10 +568,13 @@ void CFlare::Start( float lifeTime ) //----------------------------------------------------------------------------- void CFlare::Die( float fadeTime ) { - m_flTimeBurnOut = gpGlobals->curtime + fadeTime; + if (m_bInActiveList) + { + m_flTimeBurnOut = gpGlobals->curtime + fadeTime; - SetThink( &CFlare::FlareThink ); - SetNextThink( gpGlobals->curtime + 0.1f ); + SetThink(&CFlare::FlareThink); + SetNextThink(gpGlobals->curtime + 0.1f); + } } //----------------------------------------------------------------------------- From 178a26203248d1bab641ba4ec874838b4534eb03 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 10 Aug 2024 13:47:53 -0500 Subject: [PATCH 22/64] Add VScript function for checking last hit group on CBaseCombatCharacter --- sp/src/game/server/basecombatcharacter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index a1033586..57f6c7a5 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -193,6 +193,8 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by DEFINE_SCRIPTFUNC( EyeDirection2D, "Get the eyes' 2D direction." ) DEFINE_SCRIPTFUNC( EyeDirection3D, "Get the eyes' 3D direction." ) + DEFINE_SCRIPTFUNC( LastHitGroup, "Get the last hitgroup." ) + // // Hooks // From 06596695a30e89bf3bf78259e7177f2187e27f09 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 10 Aug 2024 13:48:48 -0500 Subject: [PATCH 23/64] Fix filter_activator_model issues with save/restore and null activator --- sp/src/game/server/filters.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index e95ba310..ca2f6c7a 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -996,6 +996,9 @@ public: bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ) { + if (!pEntity) + return false; + if (FStrEq(STRING(m_strFilterSkin), "-1") /*m_strFilterSkin == NULL_STRING|| FStrEq(STRING(m_strFilterSkin), "")*/) return Matcher_NamesMatch(STRING(m_iFilterModel), STRING(pEntity->GetModelName())); else if (pEntity->GetBaseAnimating()) @@ -1011,6 +1014,17 @@ public: inputdata.value.Convert(FIELD_STRING); m_iFilterModel = inputdata.value.StringID(); } + + bool KeyValue( const char *szKeyName, const char *szValue ) + { + if (FStrEq( szKeyName, "filtername" )) + { + m_iFilterModel = AllocPooledString( szValue ); + return true; + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + } }; LINK_ENTITY_TO_CLASS( filter_activator_model, CFilterModel ); @@ -1019,7 +1033,6 @@ BEGIN_DATADESC( CFilterModel ) // Keyfields DEFINE_KEYFIELD( m_iFilterModel, FIELD_STRING, "filtermodel" ), - DEFINE_KEYFIELD( m_iFilterModel, FIELD_STRING, "filtername" ), DEFINE_KEYFIELD( m_strFilterSkin, FIELD_STRING, "skin" ), END_DATADESC() From 102c7c3015343d07661f646e3eaa3c7fd2682331 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 10 Aug 2024 13:49:19 -0500 Subject: [PATCH 24/64] New "StopActionLoop" input for scripted_sequence --- sp/src/game/server/scripted.cpp | 11 +++++++++++ sp/src/game/server/scripted.h | 1 + 2 files changed, 12 insertions(+) diff --git a/sp/src/game/server/scripted.cpp b/sp/src/game/server/scripted.cpp index f02a1dcd..1cc14d77 100644 --- a/sp/src/game/server/scripted.cpp +++ b/sp/src/game/server/scripted.cpp @@ -113,6 +113,9 @@ BEGIN_DATADESC( CAI_ScriptedSequence ) DEFINE_INPUTFUNC( FIELD_VOID, "MoveToPosition", InputMoveToPosition ), DEFINE_INPUTFUNC( FIELD_VOID, "BeginSequence", InputBeginSequence ), DEFINE_INPUTFUNC( FIELD_VOID, "CancelSequence", InputCancelSequence ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_VOID, "StopActionLoop", InputStopActionLoop ), +#endif DEFINE_KEYFIELD( m_iPlayerDeathBehavior, FIELD_INTEGER, "onplayerdeath" ), DEFINE_INPUTFUNC( FIELD_VOID, "ScriptPlayerDeath", InputScriptPlayerDeath ), @@ -382,6 +385,14 @@ void CAI_ScriptedSequence::InputSetTarget( inputdata_t &inputdata ) m_iszEntity = AllocPooledString(inputdata.value.String()); m_hTargetEnt = NULL; } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAI_ScriptedSequence::InputStopActionLoop( inputdata_t &inputdata ) +{ + StopActionLoop( false ); +} #endif diff --git a/sp/src/game/server/scripted.h b/sp/src/game/server/scripted.h index 7b1d8254..82aae6b3 100644 --- a/sp/src/game/server/scripted.h +++ b/sp/src/game/server/scripted.h @@ -112,6 +112,7 @@ public: void InputCancelSequence( inputdata_t &inputdata ); void InputMoveToPosition( inputdata_t &inputdata ); #ifdef MAPBASE + void InputStopActionLoop( inputdata_t &inputdata ); void InputSetTarget( inputdata_t &inputdata ); #endif From 5d50335c02353f9a7e7e4e7617b2a06f9237f499 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 10 Aug 2024 13:51:06 -0500 Subject: [PATCH 25/64] New "Destroy" input for func_combine_ball_spawner --- sp/src/game/server/hl2/prop_combine_ball.cpp | 139 +++++++++++++++++++ sp/src/game/server/hl2/prop_combine_ball.h | 6 + 2 files changed, 145 insertions(+) diff --git a/sp/src/game/server/hl2/prop_combine_ball.cpp b/sp/src/game/server/hl2/prop_combine_ball.cpp index 7a6f287b..1606e5b1 100644 --- a/sp/src/game/server/hl2/prop_combine_ball.cpp +++ b/sp/src/game/server/hl2/prop_combine_ball.cpp @@ -1080,6 +1080,113 @@ void CPropCombineBall::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t R StopAnimating(); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPropCombineBall::SpawnerDestroyed( CBaseEntity *pActivator, bool *bSeekEnemy ) +{ + SetState( STATE_THROWN ); + WhizSoundThink(); + + m_bHeld = false; + m_bLaunched = true; + + // Stop with the dissolving + SetContextThink( NULL, gpGlobals->curtime, s_pHoldDissolveContext ); + + // We're ready to start colliding again. + SetCollisionGroup( HL2COLLISION_GROUP_COMBINE_BALL ); + + if ( m_pGlowTrail ) + { + m_pGlowTrail->TurnOn(); + m_pGlowTrail->SetRenderColor( 255, 255, 255, 255 ); + } + + // Set our desired speed to be launched at + SetSpeed( 1500.0f ); + + SetOwnerEntity( pActivator ); + SetWeaponLaunched( false ); + + if (!VPhysicsGetObject()) + return; + + if (pActivator->IsPlayer()) + { + PhysClearGameFlags( VPhysicsGetObject(), FVPHYSICS_NO_NPC_IMPACT_DMG ); + PhysSetGameFlags( VPhysicsGetObject(), FVPHYSICS_DMG_DISSOLVE | FVPHYSICS_HEAVY_OBJECT ); + } + else + { + // Don't do impact damage. Just touch them and do your dissolve damage and move on. + PhysSetGameFlags( VPhysicsGetObject(), FVPHYSICS_NO_NPC_IMPACT_DMG ); + } + + //if (pActivator->IsPlayer()) + //{ + // SetPlayerLaunched( ToBasePlayer( pActivator ) ); + //} + + Vector vecVelocity; + + if (bSeekEnemy) + { + CBaseEntity *pBestTarget = NULL; + CBaseEntity *list[256]; + + float distance; + float flBestDist = MAX_COORD_FLOAT; + int nCount = UTIL_EntitiesInSphere( list, 256, GetAbsOrigin(), sk_combine_ball_search_radius.GetFloat(), FL_NPC | FL_CLIENT ); + + for ( int i = 0; i < nCount; i++ ) + { + if ( !IsAttractiveTarget( list[i] ) ) + continue; + + distance = (list[i]->WorldSpaceCenter() - GetAbsOrigin()).LengthSqr(); + if ( distance < flBestDist ) + { + pBestTarget = list[i]; + flBestDist = distance; + } + } + + if ( pBestTarget ) + { + VectorSubtract( pBestTarget->WorldSpaceCenter(), GetAbsOrigin(), vecVelocity ); + VectorNormalize( vecVelocity ); + } + + *bSeekEnemy = (pBestTarget != NULL); + } + + if (bSeekEnemy == NULL || *bSeekEnemy == false) + { + // Choose a random direction based on current velocity + VPhysicsGetObject()->GetVelocity( &vecVelocity, NULL ); + VectorNormalize( vecVelocity ); + + QAngle shotAng; + VectorAngles( vecVelocity, shotAng ); + + // Offset by some small cone + shotAng[PITCH] += random->RandomInt( -75, 75 ); + shotAng[YAW] += random->RandomInt( -75, 75 ); + + AngleVectors( shotAng, &vecVelocity, NULL, NULL ); + } + + vecVelocity *= GetSpeed(); + + VPhysicsGetObject()->SetVelocity( &vecVelocity, &vec3_origin ); + + SetBallAsLaunched(); + StopAnimating(); +} +#endif + //------------------------------------------------------------------------------ // Stop looping sounds //------------------------------------------------------------------------------ @@ -1849,6 +1956,9 @@ BEGIN_DATADESC( CFuncCombineBallSpawner ) DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_VOID, "Destroy", InputDestroy ), +#endif DEFINE_OUTPUT( m_OnBallGrabbed, "OnBallGrabbed" ), DEFINE_OUTPUT( m_OnBallReinserted, "OnBallReinserted" ), @@ -2001,6 +2111,35 @@ void CFuncCombineBallSpawner::InputDisable( inputdata_t &inputdata ) SetThink( NULL ); } +#ifdef MAPBASE +void CFuncCombineBallSpawner::InputDestroy( inputdata_t &inputdata ) +{ + if ( !m_bEnabled ) + { + UTIL_Remove( this ); + return; + } + + // One ball always seeks the nearest enemy + bool bSoughtEnemy = false; + + CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "prop_combine_ball" ); + while (pEnt) + { + CPropCombineBall *pBall = static_cast(pEnt); + if (pBall && pBall->GetSpawner() == this) + { + BallGrabbed( pBall ); + pBall->SpawnerDestroyed( inputdata.pActivator, bSoughtEnemy ? NULL : &bSoughtEnemy ); + } + + pEnt = gEntList.FindEntityByClassname( pEnt, "prop_combine_ball" ); + } + + UTIL_Remove( this ); +} +#endif + //----------------------------------------------------------------------------- // Choose a random point inside the cylinder diff --git a/sp/src/game/server/hl2/prop_combine_ball.h b/sp/src/game/server/hl2/prop_combine_ball.h index d750d6ad..d798fde1 100644 --- a/sp/src/game/server/hl2/prop_combine_ball.h +++ b/sp/src/game/server/hl2/prop_combine_ball.h @@ -98,6 +98,9 @@ public: void SetSpawner( CFuncCombineBallSpawner *pSpawner ) { m_hSpawner = pSpawner; } void NotifySpawnerOfRemoval( void ); +#ifdef MAPBASE + void SpawnerDestroyed( CBaseEntity *pActivator, bool *bSeekEnemy ); +#endif float LastCaptureTime() const; @@ -243,6 +246,9 @@ private: // Input void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); +#ifdef MAPBASE + void InputDestroy( inputdata_t &inputdata ); +#endif // Fire ball grabbed output void GrabBallTouch( CBaseEntity *pOther ); From e9c45e5235a71045c7fb994e7853b8ea22ccd3ed Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Thu, 5 Sep 2024 23:35:46 +0200 Subject: [PATCH 26/64] Implement GetColorForSurface() failure workaround This function is used to color impact particles. On Linux I've noticed that this function sometimes is not successful on retrieving the surface color, leaving an odd color to render the particles with. The engine function TraceLineMaterialAndLighting() even has a boolean return value indicating success. GetModelMaterialColorAndLighting() does not though, but I still observe failures (the color parameter is not modified). The color is initialized with an invalid value. If it detects that retrieving the color failed (engine function said so or the invalid value was left in place), this now hamfistedly assumes a lightish grey color, but at least still correctly (presumably) incorporates lighting information. When this situation is detected, a warning is also printed to the console. Because why not. --- sp/src/game/client/c_impact_effects.cpp | 41 +++++++++++++++---------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/sp/src/game/client/c_impact_effects.cpp b/sp/src/game/client/c_impact_effects.cpp index 5b350c18..64a51bf3 100644 --- a/sp/src/game/client/c_impact_effects.cpp +++ b/sp/src/game/client/c_impact_effects.cpp @@ -95,18 +95,23 @@ extern PMaterialHandle g_Material_Spark; //----------------------------------------------------------------------------- void GetColorForSurface( trace_t *trace, Vector *color ) { - Vector baseColor, diffuseColor; - Vector end = trace->startpos + ( ( Vector )trace->endpos - ( Vector )trace->startpos ) * 1.1f; - + Vector baseColor = vec3_invalid, diffuseColor; + const char *kind; + if ( trace->DidHitWorld() ) { if ( trace->hitbox == 0 ) { + kind = "World"; + Vector end = trace->startpos + ( trace->endpos - trace->startpos ) * 1.1f; // If we hit the world, then ask the world for the fleck color - engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor ); + if ( !engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor ) ) { + baseColor = vec3_invalid; // Make sure this wasn't modified + } } else { + kind = "Static Prop"; // In this case we hit a static prop. staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor ); } @@ -117,20 +122,24 @@ void GetColorForSurface( trace_t *trace, Vector *color ) C_BaseEntity *pEnt = trace->m_pEnt; if ( !pEnt ) { - Msg("Couldn't find surface in GetColorForSurface()\n"); - color->x = 255; - color->y = 255; - color->z = 255; - return; + kind = "Null-Entity"; + } else { + kind = "Entity"; + ICollideable *pCollide = pEnt->GetCollideable(); + int modelIndex = pCollide->GetCollisionModelIndex(); + model_t* pModel = const_cast(modelinfo->GetModel( modelIndex )); + + // Ask the model info about what we need to know + modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(), + pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor ); } + } - ICollideable *pCollide = pEnt->GetCollideable(); - int modelIndex = pCollide->GetCollisionModelIndex(); - model_t* pModel = const_cast(modelinfo->GetModel( modelIndex )); - - // Ask the model info about what we need to know - modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(), - pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor ); + if ( baseColor == vec3_invalid ) + { + Warning( "Couldn't find surface color of %s\n", kind ); + baseColor = Vector( .5f, .5f, .5f ); + diffuseColor = engine->GetLightForPoint( trace->endpos, true ); } //Get final light value From df6adcc5e9f7aa47947219f556c981b8bb191d6e Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Thu, 5 Sep 2024 23:42:16 +0200 Subject: [PATCH 27/64] Fix -Wdelete-incomplete in CDefaultCustomWeaponEntityFactory::ReleaseData() GCC warns about attempting to delete a void-pointer, since it will not be able to invoke its destructor. Fix by casing it to the expected type. --- sp/src/game/server/mapbase/custom_weapon_factory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/mapbase/custom_weapon_factory.h b/sp/src/game/server/mapbase/custom_weapon_factory.h index 3abb17ed..bf46880b 100644 --- a/sp/src/game/server/mapbase/custom_weapon_factory.h +++ b/sp/src/game/server/mapbase/custom_weapon_factory.h @@ -107,7 +107,7 @@ public: virtual void ReleaseData(const void* pData) const { - delete pData; + delete (Data*)pData; } }; From a999c794f783048ef47ffc6410e480d9a6eb47ca Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Thu, 5 Sep 2024 23:44:50 +0200 Subject: [PATCH 28/64] Fix minor case of const-correctness --- sp/src/game/server/sound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/sound.cpp b/sp/src/game/server/sound.cpp index cb7df905..167644ab 100644 --- a/sp/src/game/server/sound.cpp +++ b/sp/src/game/server/sound.cpp @@ -938,7 +938,7 @@ void CAmbientGeneric::SendSound( SoundFlags_t flags) { #ifdef MAPBASE int iFlags = flags != SND_STOP ? ((int)flags | m_iSoundFlags) : flags; - char *szSoundFile = (char *)STRING( m_iszSound ); + const char *szSoundFile = STRING( m_iszSound ); CBaseEntity* pSoundSource = m_hSoundSource; if ( pSoundSource ) { From 359fcb7196acc4c6689e18a6bfa0d8c4e4d544c9 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Thu, 5 Sep 2024 23:45:20 +0200 Subject: [PATCH 29/64] Ditch attempts trying to obtain sound duration of MP3s Crashes on Linux. Apparently returns incorrect values on Windows. --- sp/src/game/shared/SoundEmitterSystem.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/SoundEmitterSystem.cpp b/sp/src/game/shared/SoundEmitterSystem.cpp index 6b10c6fe..131639bd 100644 --- a/sp/src/game/shared/SoundEmitterSystem.cpp +++ b/sp/src/game/shared/SoundEmitterSystem.cpp @@ -1001,7 +1001,11 @@ public: if ( duration ) { - *duration = enginesound->GetSoundDuration( pSample ); + if ( Q_stristr( pSample, ".mp3" ) ) { + *duration = 0; + } else { + *duration = enginesound->GetSoundDuration( pSample ); + } } TraceEmitSound( "EmitAmbientSound: Raw wave emitted '%s' (ent %i)\n", From ead5668dc82a3618f463d8a09710ca7d43226bf7 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 7 Sep 2024 16:25:23 +0300 Subject: [PATCH 30/64] Fix GetPropVector return type --- sp/src/game/shared/mapbase/vscript_singletons.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 6cdf66df..88bb41ff 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -1615,7 +1615,7 @@ public: #define SetProp( type, name )\ void SetProp##name( HSCRIPT hEnt, const char* szProp, type value )\ {\ - return SetProp##name##Array( hEnt, szProp, value, 0 );\ + SetProp##name##Array( hEnt, szProp, value, 0 );\ } GetProp( int, Int ); @@ -1624,8 +1624,8 @@ public: SetProp( float, Float ); GetProp( HSCRIPT, Entity ); SetProp( HSCRIPT, Entity ); - GetProp( Vector, Vector ); - SetProp( Vector, Vector ); + GetProp( const Vector&, Vector ); + SetProp( const Vector&, Vector ); GetProp( const char*, String ); SetProp( const char*, String ); From 337b58eb3c6d4952448069d2dab52cca57928913 Mon Sep 17 00:00:00 2001 From: Yui <50331474+SirYodaJedi@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:33:07 -0400 Subject: [PATCH 31/64] Don't network info_null Reduces potential for entity limit crashes, as it still exists for the first tick. --- mp/src/game/server/subs.cpp | 4 ++-- sp/src/game/server/subs.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mp/src/game/server/subs.cpp b/mp/src/game/server/subs.cpp index b2bf003f..e7ad7354 100644 --- a/mp/src/game/server/subs.cpp +++ b/mp/src/game/server/subs.cpp @@ -22,10 +22,10 @@ void CPointEntity::Spawn( void ) } -class CNullEntity : public CBaseEntity +class CNullEntity : public CServerOnlyEntity { public: - DECLARE_CLASS( CNullEntity, CBaseEntity ); + DECLARE_CLASS( CNullEntity, CServerOnlyEntity ); void Spawn( void ); }; diff --git a/sp/src/game/server/subs.cpp b/sp/src/game/server/subs.cpp index 0a37e4c1..53ba8f06 100644 --- a/sp/src/game/server/subs.cpp +++ b/sp/src/game/server/subs.cpp @@ -22,10 +22,10 @@ void CPointEntity::Spawn( void ) } -class CNullEntity : public CBaseEntity +class CNullEntity : public CServerOnlyEntity { public: - DECLARE_CLASS( CNullEntity, CBaseEntity ); + DECLARE_CLASS( CNullEntity, CServerOnlyEntity ); void Spawn( void ); }; From 696036219e6d545ac844a98729df32a5841f4c8d Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Wed, 13 Nov 2024 00:25:51 +0100 Subject: [PATCH 32/64] Prevent signed overflow (UB) in SquirrelVM::GenerateUniqueKey() --- sp/src/vscript/vscript_squirrel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 5efb2314..9f46d68c 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -2776,7 +2776,7 @@ void* SquirrelVM::GetInstanceValue(HSCRIPT hInstance, ScriptClassDesc_t* pExpect bool SquirrelVM::GenerateUniqueKey(const char* pszRoot, char* pBuf, int nBufSize) { - static int keyIdx = 0; + static unsigned keyIdx = 0; // This gets used for script scope, still confused why it needs to be inside IScriptVM // is it just to be a compatible name for CreateScope? V_snprintf(pBuf, nBufSize, "%08X_%s", ++keyIdx, pszRoot); From 7ebb26c9963160ec662349fa8fe4527e11f23995 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:35:33 +0300 Subject: [PATCH 33/64] Fix OOB access on CBaseCombatCharacter::m_hMyWeapons --- sp/src/game/server/ai_basenpc.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 002f3f36..927e39a1 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -8045,10 +8045,13 @@ int CAI_BaseNPC::UnholsterWeapon( void ) if (i == -1) { // Set i to the first weapon you can find - for (i = 0; i < WeaponCount(); i++) + for (i = 0;;) { if (GetWeapon(i)) break; + + if (++i >= WeaponCount()) + return -1; } } #else From 47aa8ac3f42dd1dac8f7db39d5b21279a50395a5 Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Mon, 25 Nov 2024 22:16:57 +0100 Subject: [PATCH 34/64] Update triggers.cpp --- sp/src/game/server/triggers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index 2361f8fa..21b7b256 100644 --- a/sp/src/game/server/triggers.cpp +++ b/sp/src/game/server/triggers.cpp @@ -47,6 +47,7 @@ #define DEBUG_TRANSITIONS_VERBOSE 2 ConVar g_debug_transitions( "g_debug_transitions", "0", FCVAR_NONE, "Set to 1 and restart the map to be warned if the map has no trigger_transition volumes. Set to 2 to see a dump of all entities & associated results during a transition." ); +ConVar noclip_changelevel("noclip_changelevel", "0", FCVAR_CHEAT); // Global list of triggers that care about weapon fire // Doesn't need saving, the triggers re-add themselves on restore. @@ -1848,7 +1849,8 @@ void CChangeLevel::TouchChangeLevel( CBaseEntity *pOther ) return; } - if ( !pPlayer->IsInAVehicle() && pPlayer->GetMoveType() == MOVETYPE_NOCLIP ) + + if ( !pPlayer->IsInAVehicle() && pPlayer->GetMoveType() == MOVETYPE_NOCLIP && !noclip_changelevel.GetBool()) { DevMsg("In level transition: %s %s\n", st_szNextMap, st_szNextSpot ); return; From b19f329d5f1e74b975f7d27fe2ed833b16514b91 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 25 Feb 2024 18:30:36 -0600 Subject: [PATCH 35/64] Fix ai_dynint_always_enabled bypassing misc. criteria --- sp/src/game/server/ai_basenpc.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 002f3f36..7701ea63 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -15890,12 +15890,11 @@ bool CAI_BaseNPC::InteractionIsAllowed( CAI_BaseNPC *pOtherNPC, ScriptedNPCInter if (pOtherNPC->Classify() == CLASS_PLAYER_ALLY_VITAL) return false; - // This convar allows all NPCs to perform Mapbase interactions for both testing and player fun. - if (ai_dynint_always_enabled.GetBool() && m_iDynamicInteractionsAllowed != TRS_FALSE) - return true; + if (m_iDynamicInteractionsAllowed == TRS_FALSE) + return false; - // m_iDynamicInteractionsAllowed == TRS_FALSE case is already handled in CanRunAScriptedNPCInteraction(). - if (pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE) + // To maintain existing behavior, Mapbase additions require either explicit TRS_YES or ai_dynint_always_enabled. + if (pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE && !ai_dynint_always_enabled.GetBool()) return false; // Test misc. criteria here since some of it may not have been valid on initial calculation, but could be now From f5db760a66f98fa25f490c804c0eb2e1aebdfe53 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 7 Mar 2024 00:13:41 -0600 Subject: [PATCH 36/64] Add raw scene file support to GetSceneDuration() --- sp/src/game/server/sceneentity.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index ab70e197..06f8f8fd 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -5298,6 +5298,23 @@ float GetSceneDuration( char const *pszScene ) { msecs = cachedData.msecs; } +#ifdef MAPBASE + else + { + // Raw scene file support + void *pBuffer = NULL; + if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, true )) + { + g_TokenProcessor.SetBuffer((char*)pBuffer); + CChoreoScene *pScene = ChoreoLoadScene( pszScene, NULL, &g_TokenProcessor, LocalScene_Printf ); + g_TokenProcessor.SetBuffer(NULL); + + float flDuration = pScene->GetDuration(); + delete pScene; + return flDuration; + } + } +#endif return (float)msecs * 0.001f; } From e954f00f79ee91a3353d388b73d9b5748e7ce2b6 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Wed, 13 Mar 2024 14:00:21 -0500 Subject: [PATCH 37/64] Fix antlions using wrong angles for dynamic interactions --- sp/src/game/server/hl2/npc_antlion.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/npc_antlion.cpp b/sp/src/game/server/hl2/npc_antlion.cpp index 2d59c9a0..bda685ea 100644 --- a/sp/src/game/server/hl2/npc_antlion.cpp +++ b/sp/src/game/server/hl2/npc_antlion.cpp @@ -378,13 +378,14 @@ void CNPC_Antlion::Spawn( void ) sInteraction01.vecRelativeOrigin = Vector(224, 0, 0); sInteraction01.angRelativeAngles = QAngle(0, 180, 0); - //sInteraction01.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; + sInteraction01.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; sInteraction01.iFlags |= SCNPC_FLAG_TEST_END_POSITION; sInteraction01.vecRelativeEndPos = Vector(312, -10, 0); sInteraction01.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; sInteraction01.flDelay = 15.0f; sInteraction01.iFlags |= SCNPC_FLAG_MAPBASE_ADDITION; sInteraction01.flDistSqr = (8 * 8); + sInteraction01.flMaxAngleDiff = 180.0f; // Initiate from any angle ScriptedNPCInteraction_t sInteraction02; @@ -393,11 +394,12 @@ void CNPC_Antlion::Spawn( void ) sInteraction02.vecRelativeOrigin = Vector(64, 0, 0); sInteraction02.angRelativeAngles = QAngle(0, 180, 0); - //sInteraction01.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; + sInteraction02.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; sInteraction02.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; sInteraction02.flDelay = 7.5f; sInteraction02.iFlags |= SCNPC_FLAG_MAPBASE_ADDITION; sInteraction02.flDistSqr = (8 * 8); + sInteraction02.flMaxAngleDiff = 180.0f; // Initiate from any angle AddScriptedNPCInteraction(&sInteraction01); From b59214ca72dae27ac7a3bbb2bd79733b8c40e6af Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Wed, 13 Mar 2024 13:59:41 -0500 Subject: [PATCH 38/64] Fix dynamic interactions using "their_" keyvalues always assuming separate sequence names --- sp/src/game/server/ai_basenpc.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 7701ea63..2d4c064c 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -14895,22 +14895,39 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions(void) else if (!Q_strncmp(szName, "their_", 6)) { const char *szTheirName = szName + 6; - sInteraction.bHasSeparateSequenceNames = true; if (!Q_strncmp(szTheirName, "entry_sequence", 14)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(szValue); + } else if (!Q_strncmp(szTheirName, "entry_activity", 14)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_ENTRY].iActivity = GetOrRegisterActivity(szValue); + } else if (!Q_strncmp(szTheirName, "sequence", 8)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(szValue); + } else if (!Q_strncmp(szTheirName, "activity", 8)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iActivity = GetOrRegisterActivity(szValue); + } else if (!Q_strncmp(szTheirName, "exit_sequence", 13)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(szValue); + } else if (!Q_strncmp(szTheirName, "exit_activity", 13)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_EXIT].iActivity = GetOrRegisterActivity(szValue); + } // Add anything else to our miscellaneous criteria else From bdc34e4badd82972b81d7901ef1b35e332d19c86 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Fri, 21 Jun 2024 19:30:40 -0500 Subject: [PATCH 39/64] Fix autocubemap crashing when not in a level --- sp/src/game/client/mapbase/mapbase_autocubemap.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sp/src/game/client/mapbase/mapbase_autocubemap.cpp b/sp/src/game/client/mapbase/mapbase_autocubemap.cpp index 03602ef2..79f2497d 100644 --- a/sp/src/game/client/mapbase/mapbase_autocubemap.cpp +++ b/sp/src/game/client/mapbase/mapbase_autocubemap.cpp @@ -125,6 +125,12 @@ public: //Msg("No maps to cubemap with!\n"); //return; + if (C_BasePlayer::GetLocalPlayer() == NULL) + { + Msg( "Must be in a level (or have a loaded map list) to begin autocubemap\n" ); + return; + } + // Just do this map m_AutoCubemapMaps.AddToTail( strdup( g_MapName ) ); } From 4efb50283d984416519c720c6a970e94b5589a15 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Fri, 21 Jun 2024 20:24:25 -0500 Subject: [PATCH 40/64] Fix "Fade Corpse" spawnflag on NPCs not applying to serverside ragdolls --- sp/src/game/server/basecombatcharacter.cpp | 21 +++++++++++++++------ sp/src/game/server/basecombatcharacter.h | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 57f6c7a5..6b21a23a 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -1610,6 +1610,15 @@ void CBaseCombatCharacter::FixupBurningServerRagdoll( CBaseEntity *pRagdoll ) } } +inline bool CBaseCombatCharacter::ShouldFadeServerRagdolls() const +{ +#ifdef MAPBASE + return IsNPC() ? HasSpawnFlags( SF_NPC_FADE_CORPSE ) : true; +#else + return true; +#endif +} + bool CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags ) { Assert( CanBecomeRagdoll() ); @@ -1618,7 +1627,7 @@ bool CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, const Vect info.SetDamageForce( forceVector ); - CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); pRagdoll->SetCollisionBounds( CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs() ); @@ -1641,7 +1650,7 @@ CBaseEntity *CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, co info.SetDamageForce( forceVector ); - CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); pRagdoll->SetCollisionBounds( CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs() ); @@ -1690,7 +1699,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec #endif // in single player create ragdolls on the server when the player hits someone // with their vehicle - for more dramatic death/collisions - CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, info2, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, info2, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); FixupBurningServerRagdoll( pRagdoll ); RemoveDeferred(); return true; @@ -1704,7 +1713,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec // Burning corpses are server-side in episodic, if we're in darkness mode if ( IsOnFire() && HL2GameRules()->IsAlyxInDarknessMode() ) { - CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_DEBRIS ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_DEBRIS, ShouldFadeServerRagdolls() ); FixupBurningServerRagdoll( pRagdoll ); RemoveDeferred(); return true; @@ -1725,7 +1734,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec return false; //FIXME: This is fairly leafy to be here, but time is short! - CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); FixupBurningServerRagdoll( pRagdoll ); PhysSetEntityGameFlags( pRagdoll, FVPHYSICS_NO_SELF_COLLISIONS ); RemoveDeferred(); @@ -1735,7 +1744,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec if( hl2_episodic.GetBool() && Classify() == CLASS_PLAYER_ALLY_VITAL ) { - CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); RemoveDeferred(); return true; } diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index cdae243d..20d3973e 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -350,6 +350,8 @@ public: // A version of BecomeRagdollBoogie() that allows the color to change and returns the entity itself instead. // In order to avoid breaking anything, it doesn't change the original function. virtual CBaseEntity *BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags, const Vector *vecColor ); + + bool ShouldFadeServerRagdolls() const; #endif CBaseEntity *FindHealthItem( const Vector &vecPosition, const Vector &range ); From e5d30605d557ed6524d0d11154971a6958079e1d Mon Sep 17 00:00:00 2001 From: celisej567 Date: Fri, 3 Jan 2025 02:26:39 +0300 Subject: [PATCH 41/64] float NaN undefined behavour fix --- mp/src/game/client/particlemgr.cpp | 2 ++ sp/src/game/client/particlemgr.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mp/src/game/client/particlemgr.cpp b/mp/src/game/client/particlemgr.cpp index 0eb09a43..fae2ecf3 100644 --- a/mp/src/game/client/particlemgr.cpp +++ b/mp/src/game/client/particlemgr.cpp @@ -146,6 +146,8 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; + m_flParticleCullRadius = 0.0f + SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; diff --git a/sp/src/game/client/particlemgr.cpp b/sp/src/game/client/particlemgr.cpp index d62c6e73..23768586 100644 --- a/sp/src/game/client/particlemgr.cpp +++ b/sp/src/game/client/particlemgr.cpp @@ -146,6 +146,8 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; + m_flParticleCullRadius = 0.0f + SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; From 138f51e791e6bf39f810eca919730b34352bc94f Mon Sep 17 00:00:00 2001 From: celisej567 Date: Fri, 3 Jan 2025 04:01:44 +0300 Subject: [PATCH 42/64] Update particlemgr.cpp --- mp/src/game/client/particlemgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mp/src/game/client/particlemgr.cpp b/mp/src/game/client/particlemgr.cpp index fae2ecf3..615b7cc4 100644 --- a/mp/src/game/client/particlemgr.cpp +++ b/mp/src/game/client/particlemgr.cpp @@ -146,7 +146,7 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; - m_flParticleCullRadius = 0.0f + m_flParticleCullRadius = 0.0f; SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; From 93bec9d7c0d65a63d2660c6134725d65cea1f64b Mon Sep 17 00:00:00 2001 From: celisej567 Date: Fri, 3 Jan 2025 04:28:09 +0300 Subject: [PATCH 43/64] Update particlemgr.cpp --- sp/src/game/client/particlemgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/particlemgr.cpp b/sp/src/game/client/particlemgr.cpp index 23768586..b37a2000 100644 --- a/sp/src/game/client/particlemgr.cpp +++ b/sp/src/game/client/particlemgr.cpp @@ -146,7 +146,7 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; - m_flParticleCullRadius = 0.0f + m_flParticleCullRadius = 0.0f; SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; From 959af0b130dfa29f74c34a60874a555c1dec2952 Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:13:16 +0100 Subject: [PATCH 44/64] m_iMeleeReach now defaults to 55 --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 6 +++++- sp/src/game/server/hl2/npc_BaseZombie.h | 21 +++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index 0799fcf6..6e389def 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -211,7 +211,7 @@ BEGIN_DATADESC( CNPC_BaseZombie ) DEFINE_FIELD( m_fIsTorso, FIELD_BOOLEAN ), #ifdef MAPBASE DEFINE_KEYFIELD( m_fIsHeadless, FIELD_BOOLEAN, "Headless" ), - DEFINE_KEYFIELD( m_flMeleeReach, FIELD_FLOAT, "MeleeReach" ), + DEFINE_KEYFIELD( m_iMeleeReach, FIELD_INTEGER, "MeleeReach" ), #else DEFINE_FIELD( m_fIsHeadless, FIELD_BOOLEAN ), #endif @@ -257,6 +257,10 @@ CNPC_BaseZombie::CNPC_BaseZombie() // moan loop. m_iMoanSound = g_numZombies; +#ifdef MAPBASE + m_iMeleeReach = 55; +#endif + g_numZombies++; } diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index 16ca0db9..b515144f 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -20,6 +20,10 @@ #define ENVELOPE_CONTROLLER (CSoundEnvelopeController::GetController()) +#ifndef MAPBASE + #define ZOMBIE_MELEE_REACH 55 +#endif + extern int AE_ZOMBIE_ATTACK_RIGHT; extern int AE_ZOMBIE_ATTACK_LEFT; extern int AE_ZOMBIE_ATTACK_BOTH; @@ -42,8 +46,8 @@ extern int AE_ZOMBIE_POUND; #define ZOMBIE_BLOOD_BITE 3 #ifdef MAPBASE -#define SF_ZOMBIE_NO_TORSO ( 1 << 15 ) -#define SF_ZOMBIE_NO_HEADCRAB_SPAWN ( 1 << 16 ) + #define SF_ZOMBIE_NO_TORSO ( 1 << 15 ) + #define SF_ZOMBIE_NO_HEADCRAB_SPAWN ( 1 << 16 ) #endif @@ -140,7 +144,14 @@ public: } int MeleeAttack1Conditions ( float flDot, float flDist ); - virtual float GetClawAttackRange() const { return m_flMeleeReach; } + virtual float GetClawAttackRange() const + { +#ifdef MAPBASE + return m_iMeleeReach; +#else + return ZOMBIE_MELEE_REACH; +#endif + } // No range attacks int RangeAttack1Conditions ( float flDot, float flDist ) { return( 0 ); } @@ -256,7 +267,9 @@ protected: float m_flNextFlinch; - float m_flMeleeReach; +#ifdef MAPBASE + int m_iMeleeReach; +#endif bool m_bHeadShot; // Used to determine the survival of our crab beyond our death. From 99c94f058b9c9b461a562cf51b8f3d9d3dcee75a Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:54:54 +0100 Subject: [PATCH 45/64] Added more customizability --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 25 ++++++++++++++++++----- sp/src/game/server/hl2/npc_BaseZombie.h | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index 6e389def..0c392f74 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -85,9 +85,16 @@ envelopePoint_t envDefaultZombieMoanVolume[] = #define ZOMBIE_FARTHEST_PHYSICS_OBJECT 40.0*12.0 #define ZOMBIE_PHYSICS_SEARCH_DEPTH 100 +#ifndef MAPBASE + // Don't swat objects unless player is closer than this. #define ZOMBIE_PLAYER_MAX_SWAT_DIST 1000 +// The heaviest physics object that a zombie should try to swat. (kg) +#define ZOMBIE_MAX_PHYSOBJ_MASS 60 + +#endif + // // How much health a Zombie torso gets when a whole zombie is broken // It's whole zombie's MAX Health * this value @@ -98,10 +105,6 @@ envelopePoint_t envDefaultZombieMoanVolume[] = // try to release its headcrab. #define ZOMBIE_RELEASE_HEALTH_FACTOR 0.5 -// -// The heaviest physics object that a zombie should try to swat. (kg) -#define ZOMBIE_MAX_PHYSOBJ_MASS 60 - // // Zombie tries to get this close to a physics object's origin to swat it #define ZOMBIE_PHYSOBJ_SWATDIST 80 @@ -212,6 +215,8 @@ BEGIN_DATADESC( CNPC_BaseZombie ) #ifdef MAPBASE DEFINE_KEYFIELD( m_fIsHeadless, FIELD_BOOLEAN, "Headless" ), DEFINE_KEYFIELD( m_iMeleeReach, FIELD_INTEGER, "MeleeReach" ), + DEFINE_KEYFIELD( m_iMaxPlayerDistToSwat, FIELD_INTEGER, "MaxPlayerDistToSwat" ), + DEFINE_KEYFIELD( m_iMaxObjWeightToSwat, FIELD_INTEGER, "MaxObjWeightToSwat" ), #else DEFINE_FIELD( m_fIsHeadless, FIELD_BOOLEAN ), #endif @@ -259,6 +264,8 @@ CNPC_BaseZombie::CNPC_BaseZombie() #ifdef MAPBASE m_iMeleeReach = 55; + m_iMaxPlayerDistToSwat = 1000; + m_iMaxObjWeightToSwat = 60; #endif g_numZombies++; @@ -300,7 +307,11 @@ bool CNPC_BaseZombie::FindNearestPhysicsObject( int iMaxMass ) float dist = VectorNormalize(vecDirToEnemy); vecDirToEnemy.z = 0; - if( dist > ZOMBIE_PLAYER_MAX_SWAT_DIST ) +#ifndef MAPBASE + if (dist > ZOMBIE_PLAYER_MAX_SWAT_DIST) +#else + if (dist > m_iMaxPlayerDistToSwat) +#endif { // Player is too far away. Don't bother // trying to swat anything at them until @@ -2159,7 +2170,11 @@ void CNPC_BaseZombie::GatherConditions( void ) // between him and the object he's heading for already. if( gpGlobals->curtime >= m_flNextSwatScan && (m_hPhysicsEnt == NULL) ) { +#ifdef MAPBASE + FindNearestPhysicsObject( m_iMaxObjWeightToSwat ); +#else FindNearestPhysicsObject( ZOMBIE_MAX_PHYSOBJ_MASS ); +#endif m_flNextSwatScan = gpGlobals->curtime + 2.0; } } diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index b515144f..c6d309cb 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -269,6 +269,8 @@ protected: #ifdef MAPBASE int m_iMeleeReach; + int m_iMaxPlayerDistToSwat; + int m_iMaxObjWeightToSwat; #endif bool m_bHeadShot; // Used to determine the survival of our crab beyond our death. From a00c8234e43ccf6b166d29f29b74e40047f019a5 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sat, 4 Jan 2025 08:35:16 -0600 Subject: [PATCH 46/64] Expose prop_door_rotating to VScript --- sp/src/game/server/BasePropDoor.h | 31 ++++++++++++ sp/src/game/server/props.cpp | 82 +++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/sp/src/game/server/BasePropDoor.h b/sp/src/game/server/BasePropDoor.h index 7e8400d2..ea14d20d 100644 --- a/sp/src/game/server/BasePropDoor.h +++ b/sp/src/game/server/BasePropDoor.h @@ -38,6 +38,9 @@ public: DECLARE_CLASS( CBasePropDoor, CDynamicProp ); DECLARE_SERVERCLASS(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif CBasePropDoor( void ); @@ -79,6 +82,28 @@ public: virtual bool PassesDoorFilter(CBaseEntity *pEntity) { return true; } virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + float GetSpeed() const { return m_flSpeed; } +#endif + +#ifdef MAPBASE_VSCRIPT + bool ScriptIsDoorOpen() { return IsDoorOpen(); } + bool ScriptIsDoorAjar() { return IsDoorAjar(); } + bool ScriptIsDoorOpening() { return IsDoorOpening(); } + bool ScriptIsDoorClosed() { return IsDoorClosed(); } + bool ScriptIsDoorClosing() { return IsDoorClosing(); } + bool ScriptIsDoorLocked() { return IsDoorLocked(); } + bool ScriptIsDoorBlocked() const { return IsDoorBlocked(); } + HSCRIPT ScriptGetActivator() { return ToHScript( m_hActivator.Get() ); } + + HSCRIPT ScriptGetDoorList( int i ) { return m_hDoorList.IsValidIndex(i) ? ToHScript( m_hDoorList[i] ) : NULL; } + int GetDoorListCount() { return m_hDoorList.Count(); } + + const char *ScriptGetFullyOpenSound() { return STRING( m_SoundOpen ); } + const char *ScriptGetFullyClosedSound() { return STRING( m_SoundClose ); } + const char *ScriptGetMovingSound() { return STRING( m_SoundMoving ); } + const char *ScriptGetLockedSound() { return STRING( m_ls.sLockedSound ); } + const char *ScriptGetUnlockedSound() { return STRING( m_ls.sUnlockedSound ); } #endif protected: @@ -178,6 +203,12 @@ private: #ifdef MAPBASE void InputAllowPlayerUse(inputdata_t &inputdata); void InputDisallowPlayerUse(inputdata_t &inputdata); + + void InputSetFullyOpenSound(inputdata_t &inputdata); + void InputSetFullyClosedSound(inputdata_t &inputdata); + void InputSetMovingSound(inputdata_t &inputdata); + void InputSetLockedSound(inputdata_t &inputdata); + void InputSetUnlockedSound(inputdata_t &inputdata); #endif void SetDoorBlocker( CBaseEntity *pBlocker ); diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 33aba263..57e33d87 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -4206,6 +4206,12 @@ BEGIN_DATADESC(CBasePropDoor) #ifdef MAPBASE DEFINE_INPUTFUNC(FIELD_VOID, "AllowPlayerUse", InputAllowPlayerUse), DEFINE_INPUTFUNC(FIELD_VOID, "DisallowPlayerUse", InputDisallowPlayerUse), + + DEFINE_INPUTFUNC( FIELD_STRING, "SetFullyOpenSound", InputSetFullyOpenSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetFullyClosedSound", InputSetFullyClosedSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetMovingSound", InputSetMovingSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetLockedSound", InputSetLockedSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetUnlockedSound", InputSetUnlockedSound ), #endif DEFINE_OUTPUT(m_OnBlockedOpening, "OnBlockedOpening"), @@ -4228,6 +4234,34 @@ END_DATADESC() IMPLEMENT_SERVERCLASS_ST(CBasePropDoor, DT_BasePropDoor) END_SEND_TABLE() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( CBasePropDoor, CBaseAnimating, "The base class used by prop doors, such as prop_door_rotating." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorOpen, "IsDoorOpen", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorAjar, "IsDoorAjar", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorOpening, "IsDoorOpening", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorClosed, "IsDoorClosed", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorClosing, "IsDoorClosing", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorLocked, "IsDoorLocked", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorBlocked, "IsDoorBlocked", "" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetActivator, "GetActivator", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetDoorList, "GetDoorList", "Get connected door entity by index." ) + DEFINE_SCRIPTFUNC( GetDoorListCount, "Get number of connected doors." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFullyOpenSound, "GetFullyOpenSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFullyClosedSound, "GetFullyClosedSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetMovingSound, "GetMovingSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLockedSound, "GetLockedSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetUnlockedSound, "GetUnlockedSound", "" ) + + DEFINE_SCRIPTFUNC( DoorCanClose, "Return true if the door has room to close. Boolean is for whether or not this is an automatic close and not manually triggered by someone." ) + DEFINE_SCRIPTFUNC( DoorCanOpen, "Return true if there are other doors connected to this one." ) + DEFINE_SCRIPTFUNC( HasSlaves, "" ) + +END_SCRIPTDESC(); +#endif + CBasePropDoor::CBasePropDoor( void ) { m_hMaster = NULL; @@ -4701,6 +4735,54 @@ void CBasePropDoor::InputOpenAwayFrom(inputdata_t &inputdata) } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetFullyOpenSound( inputdata_t &inputdata ) +{ + m_SoundOpen = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_SoundOpen ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetFullyClosedSound( inputdata_t &inputdata ) +{ + m_SoundClose = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_SoundClose ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetMovingSound( inputdata_t &inputdata ) +{ + m_SoundMoving = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_SoundMoving ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetLockedSound( inputdata_t &inputdata ) +{ + m_ls.sLockedSound = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_ls.sLockedSound ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetUnlockedSound( inputdata_t &inputdata ) +{ + m_ls.sUnlockedSound = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_ls.sUnlockedSound ) ); +} +#endif + + //----------------------------------------------------------------------------- // Purpose: // From ed476cbbe71a45c75b696bccfe96d3cfe427893c Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Wed, 8 Jan 2025 09:28:38 -0600 Subject: [PATCH 47/64] Increment Mapbase version to v7.3 --- sp/src/public/tier0/platform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sp/src/public/tier0/platform.h b/sp/src/public/tier0/platform.h index 457e5ec9..25bf9bc1 100644 --- a/sp/src/public/tier0/platform.h +++ b/sp/src/public/tier0/platform.h @@ -1281,8 +1281,8 @@ PLATFORM_INTERFACE bool Is64BitOS(); //----------------------------------------------------------------------------- // General Mapbase version constants compiled into projects for versioning purposes //----------------------------------------------------------------------------- -#define MAPBASE_VERSION "7.2" -#define MAPBASE_VER_INT 7200 // For use in #if in a similar fashion to macros like _MSC_VER +#define MAPBASE_VERSION "7.3" +#define MAPBASE_VER_INT 7300 // For use in #if in a similar fashion to macros like _MSC_VER #endif From 0921f7409be0557011d41ca626bbfa13afdaed0a Mon Sep 17 00:00:00 2001 From: Wikot235 <149392035+Wikot235@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:22:06 +0100 Subject: [PATCH 48/64] Fixed miscellaneous things. --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 21 +++++++++------------ sp/src/game/server/hl2/npc_BaseZombie.h | 6 ++---- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index 0c392f74..bb237242 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -85,16 +85,9 @@ envelopePoint_t envDefaultZombieMoanVolume[] = #define ZOMBIE_FARTHEST_PHYSICS_OBJECT 40.0*12.0 #define ZOMBIE_PHYSICS_SEARCH_DEPTH 100 -#ifndef MAPBASE - // Don't swat objects unless player is closer than this. #define ZOMBIE_PLAYER_MAX_SWAT_DIST 1000 -// The heaviest physics object that a zombie should try to swat. (kg) -#define ZOMBIE_MAX_PHYSOBJ_MASS 60 - -#endif - // // How much health a Zombie torso gets when a whole zombie is broken // It's whole zombie's MAX Health * this value @@ -105,6 +98,10 @@ envelopePoint_t envDefaultZombieMoanVolume[] = // try to release its headcrab. #define ZOMBIE_RELEASE_HEALTH_FACTOR 0.5 +// +// The heaviest physics object that a zombie should try to swat. (kg) +#define ZOMBIE_MAX_PHYSOBJ_MASS 60 + // // Zombie tries to get this close to a physics object's origin to swat it #define ZOMBIE_PHYSOBJ_SWATDIST 80 @@ -216,7 +213,7 @@ BEGIN_DATADESC( CNPC_BaseZombie ) DEFINE_KEYFIELD( m_fIsHeadless, FIELD_BOOLEAN, "Headless" ), DEFINE_KEYFIELD( m_iMeleeReach, FIELD_INTEGER, "MeleeReach" ), DEFINE_KEYFIELD( m_iMaxPlayerDistToSwat, FIELD_INTEGER, "MaxPlayerDistToSwat" ), - DEFINE_KEYFIELD( m_iMaxObjWeightToSwat, FIELD_INTEGER, "MaxObjWeightToSwat" ), + DEFINE_KEYFIELD( m_iMaxObjMassToSwat, FIELD_INTEGER, "MaxObjMassToSwat" ), #else DEFINE_FIELD( m_fIsHeadless, FIELD_BOOLEAN ), #endif @@ -263,9 +260,9 @@ CNPC_BaseZombie::CNPC_BaseZombie() m_iMoanSound = g_numZombies; #ifdef MAPBASE - m_iMeleeReach = 55; - m_iMaxPlayerDistToSwat = 1000; - m_iMaxObjWeightToSwat = 60; + m_iMeleeReach = ZOMBIE_MELEE_REACH; + m_iMaxPlayerDistToSwat = ZOMBIE_PLAYER_MAX_SWAT_DIST; + m_iMaxObjMassToSwat = ZOMBIE_MAX_PHYSOBJ_MASS; #endif g_numZombies++; @@ -2171,7 +2168,7 @@ void CNPC_BaseZombie::GatherConditions( void ) if( gpGlobals->curtime >= m_flNextSwatScan && (m_hPhysicsEnt == NULL) ) { #ifdef MAPBASE - FindNearestPhysicsObject( m_iMaxObjWeightToSwat ); + FindNearestPhysicsObject(m_iMaxObjMassToSwat); #else FindNearestPhysicsObject( ZOMBIE_MAX_PHYSOBJ_MASS ); #endif diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index c6d309cb..789d7d9b 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -20,9 +20,7 @@ #define ENVELOPE_CONTROLLER (CSoundEnvelopeController::GetController()) -#ifndef MAPBASE - #define ZOMBIE_MELEE_REACH 55 -#endif +#define ZOMBIE_MELEE_REACH 55 extern int AE_ZOMBIE_ATTACK_RIGHT; extern int AE_ZOMBIE_ATTACK_LEFT; @@ -270,7 +268,7 @@ protected: #ifdef MAPBASE int m_iMeleeReach; int m_iMaxPlayerDistToSwat; - int m_iMaxObjWeightToSwat; + int m_iMaxObjMassToSwat; #endif bool m_bHeadShot; // Used to determine the survival of our crab beyond our death. From aa31835f36fdd50568a1110a64981b044382f2fc Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 9 Jan 2025 12:50:19 -0600 Subject: [PATCH 49/64] Change new CNPC_BaseZombie customization vars to match actual data types --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 10 +++++----- sp/src/game/server/hl2/npc_BaseZombie.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index bb237242..f8609f49 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -211,8 +211,8 @@ BEGIN_DATADESC( CNPC_BaseZombie ) DEFINE_FIELD( m_fIsTorso, FIELD_BOOLEAN ), #ifdef MAPBASE DEFINE_KEYFIELD( m_fIsHeadless, FIELD_BOOLEAN, "Headless" ), - DEFINE_KEYFIELD( m_iMeleeReach, FIELD_INTEGER, "MeleeReach" ), - DEFINE_KEYFIELD( m_iMaxPlayerDistToSwat, FIELD_INTEGER, "MaxPlayerDistToSwat" ), + DEFINE_KEYFIELD( m_flMeleeReach, FIELD_FLOAT, "MeleeReach" ), + DEFINE_KEYFIELD( m_flMaxDistToSwat, FIELD_FLOAT, "MaxDistToSwat" ), DEFINE_KEYFIELD( m_iMaxObjMassToSwat, FIELD_INTEGER, "MaxObjMassToSwat" ), #else DEFINE_FIELD( m_fIsHeadless, FIELD_BOOLEAN ), @@ -260,8 +260,8 @@ CNPC_BaseZombie::CNPC_BaseZombie() m_iMoanSound = g_numZombies; #ifdef MAPBASE - m_iMeleeReach = ZOMBIE_MELEE_REACH; - m_iMaxPlayerDistToSwat = ZOMBIE_PLAYER_MAX_SWAT_DIST; + m_flMeleeReach = ZOMBIE_MELEE_REACH; + m_flMaxDistToSwat = ZOMBIE_PLAYER_MAX_SWAT_DIST; m_iMaxObjMassToSwat = ZOMBIE_MAX_PHYSOBJ_MASS; #endif @@ -307,7 +307,7 @@ bool CNPC_BaseZombie::FindNearestPhysicsObject( int iMaxMass ) #ifndef MAPBASE if (dist > ZOMBIE_PLAYER_MAX_SWAT_DIST) #else - if (dist > m_iMaxPlayerDistToSwat) + if (dist > m_flMaxDistToSwat) #endif { // Player is too far away. Don't bother diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index 789d7d9b..cfc11566 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -145,7 +145,7 @@ public: virtual float GetClawAttackRange() const { #ifdef MAPBASE - return m_iMeleeReach; + return m_flMeleeReach; #else return ZOMBIE_MELEE_REACH; #endif @@ -266,8 +266,8 @@ protected: float m_flNextFlinch; #ifdef MAPBASE - int m_iMeleeReach; - int m_iMaxPlayerDistToSwat; + float m_flMeleeReach; + float m_flMaxDistToSwat; int m_iMaxObjMassToSwat; #endif From a5c754dd00702f7b9d6bcde19116b987a94dadcb Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 2 Jan 2025 11:22:51 -0600 Subject: [PATCH 50/64] Fixes and expansions for Lost/FoundEnemySound on NPCs --- sp/src/game/server/ai_basenpc.cpp | 8 +++++++ sp/src/game/server/ai_basenpc.h | 5 +++++ sp/src/game/server/ai_playerally.cpp | 25 ++++++++++++++++++++++ sp/src/game/server/ai_playerally.h | 7 ++++++ sp/src/game/server/hl2/npc_combine.cpp | 20 +++++++++++++++-- sp/src/game/server/hl2/npc_combine.h | 5 +++++ sp/src/game/server/hl2/npc_metropolice.cpp | 20 +++++++++++++++-- sp/src/game/server/hl2/npc_metropolice.h | 5 +++++ 8 files changed, 91 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 1622ec8d..f087f8a4 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6110,7 +6110,11 @@ bool CAI_BaseNPC::UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position // If the was eluding me and allow the NPC to play a sound if (GetEnemies()->HasEludedMe(pEnemy)) { +#ifdef MAPBASE + FoundEnemySound( pEnemy ); +#else FoundEnemySound(); +#endif } float reactionDelay = ( !pInformer || pInformer == this ) ? GetReactionDelay( pEnemy ) : 0.0; bool result = GetEnemies()->UpdateMemory(GetNavigator()->GetNetwork(), pEnemy, position, reactionDelay, firstHand); @@ -11734,7 +11738,11 @@ bool CAI_BaseNPC::ChooseEnemy( void ) if ( fEnemyEluded ) { SetCondition( COND_LOST_ENEMY ); +#ifdef MAPBASE + LostEnemySound( pInitialEnemy ); +#else LostEnemySound(); +#endif } if ( fEnemyWasPlayer ) diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index dbc229e2..7db67d33 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1401,6 +1401,11 @@ public: virtual void FearSound( void ) { return; }; virtual void LostEnemySound( void ) { return; }; virtual void FoundEnemySound( void ) { return; }; +#ifdef MAPBASE + // New versions of the above functions which pass the enemy in question as a parameter. Chains to the original by default + virtual void LostEnemySound( CBaseEntity *pEnemy ) { LostEnemySound(); }; + virtual void FoundEnemySound( CBaseEntity *pEnemy ) { FoundEnemySound(); }; +#endif virtual void BarnacleDeathSound( void ) { CTakeDamageInfo info; PainSound( info ); } virtual void SpeakSentence( int sentenceType ) { return; }; diff --git a/sp/src/game/server/ai_playerally.cpp b/sp/src/game/server/ai_playerally.cpp index af969868..ea7c986f 100644 --- a/sp/src/game/server/ai_playerally.cpp +++ b/sp/src/game/server/ai_playerally.cpp @@ -14,6 +14,7 @@ #include "gameinterface.h" #ifdef MAPBASE #include "mapbase/matchers.h" +#include "ai_memory.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -133,6 +134,8 @@ ConceptInfo_t g_ConceptInfos[] = { TLK_TAKING_FIRE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, { TLK_NEW_ENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, { TLK_COMBAT_IDLE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, + { TLK_LOSTENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, + { TLK_REFINDENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, #endif }; @@ -1426,6 +1429,28 @@ void CAI_PlayerAlly::PainSound( const CTakeDamageInfo &info ) SpeakIfAllowed( TLK_WOUND ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +void CAI_PlayerAlly::LostEnemySound( CBaseEntity *pEnemy ) +{ + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + modifiers.AppendCriteria( "lastseenenemy", gpGlobals->curtime - GetEnemies()->LastTimeSeen( pEnemy ) ); + + SpeakIfAllowed( TLK_LOSTENEMY, modifiers ); +} + +//----------------------------------------------------------------------------- +void CAI_PlayerAlly::FoundEnemySound( CBaseEntity *pEnemy ) +{ + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + SpeakIfAllowed( TLK_REFINDENEMY, modifiers ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Implemented to look at talk target //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/ai_playerally.h b/sp/src/game/server/ai_playerally.h index 47ddf916..8c34333a 100644 --- a/sp/src/game/server/ai_playerally.h +++ b/sp/src/game/server/ai_playerally.h @@ -137,6 +137,8 @@ #define TLK_TAKING_FIRE "TLK_TAKING_FIRE" // Someone fired at me (regardless of whether I was hit) #define TLK_NEW_ENEMY "TLK_NEW_ENEMY" // A new enemy appeared while combat was already in progress #define TLK_COMBAT_IDLE "TLK_COMBAT_IDLE" // Similar to TLK_ATTACKING, but specifically for when *not* currently attacking (e.g. when in cover or reloading) +#define TLK_LOSTENEMY "TLK_LOSTENEMY" // Current enemy has eluded squad +#define TLK_REFINDENEMY "TLK_REFINDENEMY" // Found a previously eluded enemy #endif //----------------------------------------------------------------------------- @@ -339,6 +341,11 @@ public: virtual void PainSound( const CTakeDamageInfo &info ); +#ifdef MAPBASE + virtual void LostEnemySound( CBaseEntity *pEnemy ); + virtual void FoundEnemySound( CBaseEntity *pEnemy ); +#endif + //--------------------------------- // Speech & Acting //--------------------------------- diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index c2cac902..93116b4d 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -3145,13 +3145,22 @@ void CNPC_Combine::PainSound ( void ) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_Combine::LostEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_Combine::LostEnemySound( void) +#endif { if ( gpGlobals->curtime <= m_flNextLostSoundTime ) return; #ifdef COMBINE_SOLDIER_USES_RESPONSE_SYSTEM - if (SpeakIfAllowed( TLK_CMB_LOSTENEMY, UTIL_VarArgs("lastseenenemy:%d", GetEnemyLastTimeSeen()) )) + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + modifiers.AppendCriteria( "lastseenenemy", gpGlobals->curtime - GetEnemies()->LastTimeSeen( pEnemy ) ); + + if (SpeakIfAllowed( TLK_CMB_LOSTENEMY, modifiers )) { m_flNextLostSoundTime = gpGlobals->curtime + random->RandomFloat(5.0,15.0); } @@ -3179,10 +3188,17 @@ void CNPC_Combine::LostEnemySound( void) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_Combine::FoundEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_Combine::FoundEnemySound( void) +#endif { #ifdef COMBINE_SOLDIER_USES_RESPONSE_SYSTEM - SpeakIfAllowed( TLK_CMB_REFINDENEMY, SENTENCE_PRIORITY_HIGH ); + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + SpeakIfAllowed( TLK_CMB_REFINDENEMY, modifiers, SENTENCE_PRIORITY_HIGH ); #else m_Sentences.Speak( "COMBINE_REFIND_ENEMY", SENTENCE_PRIORITY_HIGH ); #endif diff --git a/sp/src/game/server/hl2/npc_combine.h b/sp/src/game/server/hl2/npc_combine.h index c9af8010..d6a500b9 100644 --- a/sp/src/game/server/hl2/npc_combine.h +++ b/sp/src/game/server/hl2/npc_combine.h @@ -181,8 +181,13 @@ public: #endif void IdleSound( void ); void AlertSound( void ); +#ifdef MAPBASE + void LostEnemySound( CBaseEntity *pEnemy ); + void FoundEnemySound( CBaseEntity *pEnemy ); +#else void LostEnemySound( void ); void FoundEnemySound( void ); +#endif void AnnounceAssault( void ); void AnnounceEnemyType( CBaseEntity *pEnemy ); void AnnounceEnemyKill( CBaseEntity *pEnemy ); diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index ed013fa3..40f1d5be 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -2938,7 +2938,11 @@ void CNPC_MetroPolice::DeathSound( const CTakeDamageInfo &info ) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_MetroPolice::LostEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_MetroPolice::LostEnemySound( void) +#endif { // Don't announce enemies when the player isn't a criminal if ( !PlayerIsCriminal() ) @@ -2948,7 +2952,12 @@ void CNPC_MetroPolice::LostEnemySound( void) return; #ifdef METROPOLICE_USES_RESPONSE_SYSTEM - if (SpeakIfAllowed(TLK_COP_LOSTENEMY)) + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + modifiers.AppendCriteria( "lastseenenemy", gpGlobals->curtime - GetEnemies()->LastTimeSeen( pEnemy ) ); + + if (SpeakIfAllowed(TLK_COP_LOSTENEMY, modifiers )) { m_flNextLostSoundTime = gpGlobals->curtime + random->RandomFloat(5.0,15.0); } @@ -2977,14 +2986,21 @@ void CNPC_MetroPolice::LostEnemySound( void) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_MetroPolice::FoundEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_MetroPolice::FoundEnemySound( void) +#endif { // Don't announce enemies when I'm in arrest behavior if ( HasSpawnFlags( SF_METROPOLICE_ARREST_ENEMY ) ) return; #ifdef METROPOLICE_USES_RESPONSE_SYSTEM - SpeakIfAllowed( TLK_COP_REFINDENEMY, SENTENCE_PRIORITY_HIGH ); + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + SpeakIfAllowed( TLK_COP_REFINDENEMY, modifiers, SENTENCE_PRIORITY_HIGH ); #else m_Sentences.Speak( "METROPOLICE_REFIND_ENEMY", SENTENCE_PRIORITY_HIGH ); #endif diff --git a/sp/src/game/server/hl2/npc_metropolice.h b/sp/src/game/server/hl2/npc_metropolice.h index 742de7e3..1027786b 100644 --- a/sp/src/game/server/hl2/npc_metropolice.h +++ b/sp/src/game/server/hl2/npc_metropolice.h @@ -170,8 +170,13 @@ private: void SpeakAssaultSentence( int nSentenceType ); void SpeakStandoffSentence( int nSentenceType ); +#ifdef MAPBASE + virtual void LostEnemySound( CBaseEntity *pEnemy ); + virtual void FoundEnemySound( CBaseEntity *pEnemy ); +#else virtual void LostEnemySound( void ); virtual void FoundEnemySound( void ); +#endif virtual void AlertSound( void ); virtual void PainSound( const CTakeDamageInfo &info ); virtual void DeathSound( const CTakeDamageInfo &info ); From ad423d1d0775d1f55e74e0fa62de9939e063e153 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 5 Jan 2025 13:06:06 -0600 Subject: [PATCH 51/64] OnStartTipped output for npc_turret_floor --- sp/src/game/server/hl2/npc_turret_floor.cpp | 7 +++++++ sp/src/game/server/hl2/npc_turret_floor.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/sp/src/game/server/hl2/npc_turret_floor.cpp b/sp/src/game/server/hl2/npc_turret_floor.cpp index 8698e742..f365dfd7 100644 --- a/sp/src/game/server/hl2/npc_turret_floor.cpp +++ b/sp/src/game/server/hl2/npc_turret_floor.cpp @@ -152,6 +152,9 @@ BEGIN_DATADESC( CNPC_FloorTurret ) DEFINE_OUTPUT( m_OnTipped, "OnTipped" ), DEFINE_OUTPUT( m_OnPhysGunPickup, "OnPhysGunPickup" ), DEFINE_OUTPUT( m_OnPhysGunDrop, "OnPhysGunDrop" ), +#ifdef MAPBASE + DEFINE_OUTPUT( m_OnStartTipped, "OnStartTipped" ), +#endif DEFINE_BASENPCINTERACTABLE_DATADESC(), @@ -1526,6 +1529,10 @@ bool CNPC_FloorTurret::PreThink( turretState_e state ) SetEyeState( TURRET_EYE_DEAD ); } +#ifdef MAPBASE + m_OnStartTipped.FireOutput( this, this ); +#endif + //Stop being targetted SetState( NPC_STATE_DEAD ); m_lifeState = LIFE_DEAD; diff --git a/sp/src/game/server/hl2/npc_turret_floor.h b/sp/src/game/server/hl2/npc_turret_floor.h index 8600e13a..af006a01 100644 --- a/sp/src/game/server/hl2/npc_turret_floor.h +++ b/sp/src/game/server/hl2/npc_turret_floor.h @@ -265,6 +265,9 @@ protected: COutputEvent m_OnTipped; COutputEvent m_OnPhysGunPickup; COutputEvent m_OnPhysGunDrop; +#ifdef MAPBASE + COutputEvent m_OnStartTipped; +#endif bool m_bHackedByAlyx; HSOUNDSCRIPTHANDLE m_ShotSounds; From 468fa81f47c5900e7ffd94d2e38b79198988f91e Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 2 Jan 2025 10:57:11 -0600 Subject: [PATCH 52/64] Expose VPhysicsInitNormal and VPhysicsDestroyObject to VScript --- sp/src/game/client/c_baseentity.cpp | 2 ++ sp/src/game/client/c_baseentity.h | 2 ++ sp/src/game/server/baseentity.cpp | 2 ++ sp/src/game/server/baseentity.h | 2 ++ sp/src/game/shared/baseentity_shared.cpp | 8 ++++++++ sp/src/game/shared/mapbase/vscript_consts_shared.cpp | 11 +++++++++++ 6 files changed, 27 insertions(+) diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index 1d3de004..4a72bdb7 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -485,6 +485,8 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsInitNormal, "PhysicsInitNormal", "Initializes the entity's physics object with the specified solid type, solid flags, and whether to start asleep" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsDestroyObject, "PhysicsDestroyObject", "Destroys the entity's physics object" ) DEFINE_SCRIPTFUNC( GetWaterLevel, "Get current level of water submergence" ) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index 422a59d4..aa383c73 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -1206,6 +1206,8 @@ public: HSCRIPT ScriptEntityToWorldTransform( void ); HSCRIPT ScriptGetPhysicsObject( void ); + void ScriptPhysicsInitNormal( int nSolidType, int nSolidFlags, bool createAsleep ); + void ScriptPhysicsDestroyObject() { VPhysicsDestroyObject(); } void ScriptSetParent( HSCRIPT hParent, const char *szAttachment ); HSCRIPT ScriptGetMoveParent( void ); diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 9df5cc09..d62e9536 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2312,6 +2312,8 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsInitNormal, "PhysicsInitNormal", "Initializes the entity's physics object with the specified solid type, solid flags, and whether to start asleep" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsDestroyObject, "PhysicsDestroyObject", "Destroys the entity's physics object" ) DEFINE_SCRIPTFUNC( ApplyAbsVelocityImpulse, "" ) DEFINE_SCRIPTFUNC( ApplyLocalAngularVelocityImpulse, "" ) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 7cd4670c..e5899231 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -2107,6 +2107,8 @@ public: HSCRIPT ScriptEntityToWorldTransform( void ); HSCRIPT ScriptGetPhysicsObject( void ); + void ScriptPhysicsInitNormal( int nSolidType, int nSolidFlags, bool createAsleep ); + void ScriptPhysicsDestroyObject() { VPhysicsDestroyObject(); } void ScriptSetParent(HSCRIPT hParent, const char *szAttachment); #endif diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index b2cd6bdc..5f957612 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2811,6 +2811,14 @@ HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) return NULL; } +//----------------------------------------------------------------------------- +// Vscript: Gets the entity's physics object if it has one +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptPhysicsInitNormal( int nSolidType, int nSolidFlags, bool createAsleep ) +{ + VPhysicsInitNormal( (SolidType_t)nSolidType, nSolidFlags, createAsleep ); +} + #ifdef GAME_DLL #define SCRIPT_NEVER_THINK TICK_NEVER_THINK diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 2ced7086..bb47bcb1 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -290,6 +290,17 @@ void RegisterSharedScriptConstants() ScriptRegisterConstant( g_pScriptVM, EF_ITEM_BLINK, "Effect flag used in GetEffects(), etc." ); ScriptRegisterConstant( g_pScriptVM, EF_PARENT_ANIMATES, "Effect flag used in GetEffects(), etc." ); + // + // Solid Types + // + ScriptRegisterConstant( g_pScriptVM, SOLID_NONE, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_BSP, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_BBOX, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_OBB, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_OBB_YAW, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_CUSTOM, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_VPHYSICS, "Solid type used by VPhysics" ); + // // Solid Flags // From 10f08829e57c83ce2664d7cc4c5f8aa004491e23 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 5 Jan 2025 13:37:40 -0600 Subject: [PATCH 53/64] Fix vgui_screen crashing for existing saves until v8.0 --- sp/src/game/server/vguiscreen.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index 86795342..e46afbf5 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -184,6 +184,11 @@ CVGuiScreen::~CVGuiScreen() int CVGuiScreen::Save(ISave& save) { +#if MAPBASE_VER_INT < 8000 + // HACKHACK: Until v8.0, mark this screen as using the new save system to prevent existing saves with vgui_screen from crashing + AddContext( "uses_new_save", "1" ); +#endif + int status = BaseClass::Save(save); if (!status) return 0; @@ -209,6 +214,12 @@ int CVGuiScreen::Restore(IRestore& restore) if (!status) return 0; +#if MAPBASE_VER_INT < 8000 + // HACKHACK: Until v8.0, mark this screen as using the new save system to prevent existing saves with vgui_screen from crashing + if (!HasContext( "uses_new_save", "1" )) + return status; +#endif + const int iCount = restore.ReadInt(); m_PanelOutputs.EnsureCapacity(iCount); for (int i = 0; i < iCount; i++) From b055d776639083aa49ca8c71649bb35f153d6de8 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 9 Jan 2025 12:29:03 -0600 Subject: [PATCH 54/64] Move npc_metropolice enemy kill concept to Event_KilledOther() --- sp/src/game/server/hl2/npc_metropolice.cpp | 17 +++++++++++++++++ sp/src/game/server/hl2/npc_metropolice.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 40f1d5be..f515ab92 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -534,10 +534,12 @@ void CNPC_MetroPolice::OnScheduleChange() { BaseClass::OnScheduleChange(); +#ifndef MAPBASE // Moved to Event_KilledOther() if ( GetEnemy() && HasCondition( COND_ENEMY_DEAD ) ) { AnnounceEnemyKill( GetEnemy() ); } +#endif } @@ -3722,6 +3724,21 @@ void CNPC_MetroPolice::Event_Killed( const CTakeDamageInfo &info ) BaseClass::Event_Killed( info ); } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CNPC_MetroPolice::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) +{ + BaseClass::Event_KilledOther( pVictim, info ); + +#ifdef MAPBASE // Moved from OnScheduleChange() + if ( pVictim && (pVictim->IsPlayer() || pVictim->IsNPC()) ) + { + AnnounceEnemyKill( pVictim ); + } +#endif +} + //----------------------------------------------------------------------------- // Try to enter a slot where we shoot a pistol //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/npc_metropolice.h b/sp/src/game/server/hl2/npc_metropolice.h index 1027786b..690bf2ae 100644 --- a/sp/src/game/server/hl2/npc_metropolice.h +++ b/sp/src/game/server/hl2/npc_metropolice.h @@ -79,6 +79,8 @@ public: virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + virtual void OnScheduleChange(); float GetIdealAccel( void ) const; From 17af09b3d12bc223223d1eadf67d2218bb73a12a Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 9 Jan 2025 11:50:48 -0600 Subject: [PATCH 55/64] Fix workflow not terminating on compile error --- .github/workflows/mapbase_build-base.yml | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/mapbase_build-base.yml b/.github/workflows/mapbase_build-base.yml index fac52365..0a4905d0 100644 --- a/.github/workflows/mapbase_build-base.yml +++ b/.github/workflows/mapbase_build-base.yml @@ -85,45 +85,45 @@ jobs: working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} mathlib\mathlib.vcxproj + msbuild -m -p:Configuration=${{inputs.configuration}} mathlib\mathlib.vcxproj || exit /b - name: Build Base Libraries if: inputs.project-group == 'all' || inputs.project-group == 'game' || inputs.project-group == 'maptools' working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} raytrace\raytrace.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} tier1\tier1.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} vscript\vscript.vcxproj + msbuild -m -p:Configuration=${{inputs.configuration}} raytrace\raytrace.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} tier1\tier1.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} vscript\vscript.vcxproj || exit /b - name: Build Map Tools if: inputs.project-group == 'all' || inputs.project-group == 'maptools' working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} fgdlib\fgdlib.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vbsp\vbsp.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis\vvis_dll.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis_launcher\vvis_launcher.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad\vrad_dll.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad_launcher\vrad_launcher.vcxproj + msbuild -m -p:Configuration=${{inputs.configuration}} fgdlib\fgdlib.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} utils\vbsp\vbsp.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis\vvis_dll.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis_launcher\vvis_launcher.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad\vrad_dll.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad_launcher\vrad_launcher.vcxproj || exit /b - name: Build Shaders if: inputs.project-group == 'shaders' working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_${{inputs.game}}.vcxproj + msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_${{inputs.game}}.vcxproj || exit /b - name: Build Game if: inputs.project-group == 'game' working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_${{inputs.game}}.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_${{inputs.game}}.vcxproj + msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_${{inputs.game}}.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_${{inputs.game}}.vcxproj || exit /b # TODO: Hook to game naming? - name: Build everything @@ -131,13 +131,13 @@ jobs: working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_episodic.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_hl2.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_episodic.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_hl2.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_episodic.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_hl2.vcxproj + msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_episodic.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_hl2.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_episodic.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_hl2.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_episodic.vcxproj || exit /b + msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_hl2.vcxproj || exit /b # -------------------------------------------------------------------- From 466183c4de9ab9267db7bdda9d389dcb4e95903b Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 5 Jan 2025 13:01:28 -0600 Subject: [PATCH 56/64] New VScript functions for player use entity and pickup --- sp/src/game/server/player.cpp | 9 ++++ sp/src/game/server/player.h | 3 ++ sp/src/game/shared/baseplayer_shared.cpp | 34 +++++++++++++ .../game/shared/mapbase/vscript_funcs_hl2.cpp | 49 +++++++++++++++++++ .../shared/mapbase/vscript_funcs_shared.cpp | 22 +++++++++ 5 files changed, 117 insertions(+) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 28c767c5..6fd1c504 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -498,6 +498,7 @@ END_DATADESC() #ifdef MAPBASE_VSCRIPT // TODO: Better placement? ScriptHook_t g_Hook_PlayerRunCommand; +ScriptHook_t g_Hook_FindUseEntity; BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) @@ -552,6 +553,9 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetEyeUp, "GetEyeUp", "Gets the player's up eye vector." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetViewModel, "GetViewModel", "Returns the viewmodel of the specified index." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetUseEntity, "GetUseEntity", "Gets the player's current use entity." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetHeldObject, "GetHeldObject", "Gets the player's currently held object IF it is being held by a gravity gun. To check for the player's held +USE object, use the standalone GetPlayerHeldEntity function." ) // // Hooks @@ -559,6 +563,11 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) BEGIN_SCRIPTHOOK( g_Hook_PlayerRunCommand, "PlayerRunCommand", FIELD_VOID, "Called when running a player command on the server." ) DEFINE_SCRIPTHOOK_PARAM( "command", FIELD_HSCRIPT ) END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( g_Hook_FindUseEntity, "FindUseEntity", FIELD_HSCRIPT, "Called when finding an entity to use. The 'entity' parameter is for the entity found by the default function. If 'is_radius' is true, then this entity was found by searching in a radius around the cursor, rather than being directly used. Return a different entity to use something else." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + DEFINE_SCRIPTHOOK_PARAM( "is_radius", FIELD_BOOLEAN ) + END_SCRIPTHOOK() END_SCRIPTDESC(); #else diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 72a1e38e..c3ef666a 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -414,6 +414,9 @@ public: const Vector& ScriptGetEyeUp() { static Vector vecUp; EyeVectors( NULL, NULL, &vecUp ); return vecUp; } HSCRIPT ScriptGetViewModel( int viewmodelindex ); + + HSCRIPT ScriptGetUseEntity() { return ToHScript( GetUseEntity() ); } + HSCRIPT ScriptGetHeldObject() { return ToHScript( GetHeldObject() ); } #endif // View model prediction setup diff --git a/sp/src/game/shared/baseplayer_shared.cpp b/sp/src/game/shared/baseplayer_shared.cpp index 5ad7d453..9296bfcf 100644 --- a/sp/src/game/shared/baseplayer_shared.cpp +++ b/sp/src/game/shared/baseplayer_shared.cpp @@ -1069,6 +1069,10 @@ float IntervalDistance( float x, float x0, float x1 ) return 0; } +#if !defined(CLIENT_DLL) && defined(MAPBASE_VSCRIPT) +extern ScriptHook_t g_Hook_FindUseEntity; +#endif + CBaseEntity *CBasePlayer::FindUseEntity() { Vector forward, up; @@ -1160,7 +1164,24 @@ CBaseEntity *CBasePlayer::FindUseEntity() // if this is directly under the cursor just return it now if ( i == 0 ) + { +#if !defined(CLIENT_DLL) && defined(MAPBASE_VSCRIPT) + if (m_ScriptScope.IsInitialized() && g_Hook_FindUseEntity.CanRunInScope( m_ScriptScope )) + { + // entity, is_radius + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ToHScript( pNearest ), false }; + if (g_Hook_FindUseEntity.Call( m_ScriptScope, &functionReturn, args )) + { + pObject = ToEnt( functionReturn.m_hScript ); + pNearest = pObject; + } + } + + if (pObject) +#endif return pObject; + } } } } @@ -1245,6 +1266,19 @@ CBaseEntity *CBasePlayer::FindUseEntity() { pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward ); } + +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_FindUseEntity.CanRunInScope(m_ScriptScope)) + { + // entity, is_radius + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ToHScript( pNearest ), true }; + if (g_Hook_FindUseEntity.Call( m_ScriptScope, &functionReturn, args )) + { + pNearest = ToEnt( functionReturn.m_hScript ); + } + } +#endif if ( sv_debug_player_use.GetBool() ) { diff --git a/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp b/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp index 189f8883..529d0291 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp @@ -10,6 +10,8 @@ #include "hl2_gamerules.h" #ifndef CLIENT_DLL #include "eventqueue.h" +#include "weapon_physcannon.h" +#include "player_pickup.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -47,6 +49,48 @@ bool ScriptMegaPhyscannonActive() { return HL2GameRules()->MegaPhyscannonActive(); } + +void ScriptPickup_ForcePlayerToDropThisObject( HSCRIPT hTarget ) +{ + Pickup_ForcePlayerToDropThisObject( ToEnt( hTarget ) ); +} + +float ScriptPlayerPickupGetHeldObjectMass( HSCRIPT hPickupControllerEntity, HSCRIPT hHeldObject ) +{ + IPhysicsObject *pPhysObj = HScriptToClass( hHeldObject ); + if (!pPhysObj) + { + CBaseEntity *pEnt = ToEnt( hHeldObject ); + if (pEnt) + pPhysObj = pEnt->VPhysicsGetObject(); + } + + if (!pPhysObj) + { + Warning( "PlayerPickupGetHeldObjectMass: Invalid physics object\n" ); + return 0.0f; + } + + return PlayerPickupGetHeldObjectMass( ToEnt( hPickupControllerEntity ), pPhysObj ); +} + +HSCRIPT ScriptGetPlayerHeldEntity( HSCRIPT hPlayer ) +{ + CBasePlayer *pPlayer = ToBasePlayer( ToEnt( hPlayer ) ); + if (!pPlayer) + return NULL; + + return ToHScript( GetPlayerHeldEntity( pPlayer ) ); +} + +HSCRIPT ScriptPhysCannonGetHeldEntity( HSCRIPT hWeapon ) +{ + CBaseEntity *pEnt = ToEnt( hWeapon ); + if (!pEnt) + return NULL; + + return ToHScript( PhysCannonGetHeldEntity( pEnt->MyCombatWeaponPointer() ) ); +} #endif //----------------------------------------------------------------------------- @@ -59,5 +103,10 @@ void CHalfLife2::RegisterScriptFunctions( void ) #ifndef CLIENT_DLL ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGameOver, "GameOver", "Ends the game and reloads the last save." ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMegaPhyscannonActive, "MegaPhyscannonActive", "Checks if supercharged gravity gun mode is enabled." ); + + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPickup_ForcePlayerToDropThisObject, "Pickup_ForcePlayerToDropThisObject", "If the specified entity is being carried, instantly drops it." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPlayerPickupGetHeldObjectMass, "PlayerPickupGetHeldObjectMass", "Gets the mass of the specified player_pickup controller, with the second parameter the held object's physics object." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGetPlayerHeldEntity, "GetPlayerHeldEntity", "Gets the specified player's currently held entity." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPhysCannonGetHeldEntity, "PhysCannonGetHeldEntity", "Gets the specified gravity gun's currently held entity." ); #endif } diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index 4c6d4817..227103df 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -771,6 +771,26 @@ static void AddPhysVelocity( HSCRIPT hPhys, const Vector& vecVelocity, const Vec pPhys->AddVelocity( &vecVelocity, &vecAngVelocity ); } +static void ScriptPhysEnableEntityCollisions( HSCRIPT hPhys1, HSCRIPT hPhys2 ) +{ + IPhysicsObject *pPhys1 = HScriptToClass( hPhys1 ); + IPhysicsObject *pPhys2 = HScriptToClass( hPhys2 ); + if (!pPhys1 || !pPhys2) + return; + + PhysEnableEntityCollisions( pPhys1, pPhys2 ); +} + +static void ScriptPhysDisableEntityCollisions( HSCRIPT hPhys1, HSCRIPT hPhys2 ) +{ + IPhysicsObject *pPhys1 = HScriptToClass( hPhys1 ); + IPhysicsObject *pPhys2 = HScriptToClass( hPhys2 ); + if (!pPhys1 || !pPhys2) + return; + + PhysDisableEntityCollisions( pPhys1, pPhys2 ); +} + //============================================================================= //============================================================================= @@ -1045,6 +1065,8 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunction( g_pScriptVM, GetPhysAngVelocity, "Gets physics angular velocity for the given VPhysics object" ); ScriptRegisterFunction( g_pScriptVM, SetPhysVelocity, "Sets physics velocity for the given VPhysics object" ); ScriptRegisterFunction( g_pScriptVM, AddPhysVelocity, "Adds physics velocity for the given VPhysics object" ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPhysEnableEntityCollisions, "PhysEnableEntityCollisions", "Enables collisions between two VPhysics objects"); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPhysDisableEntityCollisions, "PhysDisableEntityCollisions", "Disables collisions between two VPhysics objects"); // // Precaching From d51d44eb73bb9dcccff971ffa688bb722c1893da Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 2 Jan 2025 11:00:30 -0600 Subject: [PATCH 57/64] Fix forced interaction partners being made to face each other even when interaction doesn't require it --- sp/src/game/server/ai_basenpc_schedule.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index 5f57b51d..56e20e03 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -3506,6 +3506,12 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask ) // as this should only run with the NPC "receiving" the interaction ScriptedNPCInteraction_t *pInteraction = m_hForcedInteractionPartner->GetRunningDynamicInteraction(); + if ( !(pInteraction->iFlags & SCNPC_FLAG_TEST_OTHER_ANGLES) ) + { + TaskComplete(); + return; + } + // Get our target's origin Vector vecTarget = m_hForcedInteractionPartner->GetAbsOrigin(); From d4b66b16cdf0cdf55ccdcd0f7605c8e029e9a0c1 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Thu, 2 Jan 2025 10:12:09 -0600 Subject: [PATCH 58/64] Expose CBaseCombatCharacter glow funcs to VScript + add color functionality Co-authored-by: Derek <1upderek@gmail.com> --- sp/src/game/client/c_basecombatcharacter.cpp | 26 ++++++++++++++------ sp/src/game/client/c_basecombatcharacter.h | 6 ++++- sp/src/game/server/basecombatcharacter.cpp | 17 +++++++++++++ sp/src/game/server/basecombatcharacter.h | 3 +++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/c_basecombatcharacter.cpp b/sp/src/game/client/c_basecombatcharacter.cpp index 0afe4cbf..85dbb9d5 100644 --- a/sp/src/game/client/c_basecombatcharacter.cpp +++ b/sp/src/game/client/c_basecombatcharacter.cpp @@ -34,6 +34,10 @@ C_BaseCombatCharacter::C_BaseCombatCharacter() m_pGlowEffect = NULL; m_bGlowEnabled = false; m_bOldGlowEnabled = false; + m_GlowColor.Init( 0.76f, 0.76f, 0.76f ); + m_OldGlowColor = m_GlowColor; + m_GlowAlpha = 1.0f; + m_OldGlowAlpha = 1.0f; #endif // GLOWS_ENABLE } @@ -66,6 +70,8 @@ void C_BaseCombatCharacter::OnPreDataChanged( DataUpdateType_t updateType ) #ifdef GLOWS_ENABLE m_bOldGlowEnabled = m_bGlowEnabled; + m_OldGlowColor = m_GlowColor; + m_OldGlowAlpha = m_GlowAlpha; #endif // GLOWS_ENABLE } @@ -77,7 +83,7 @@ void C_BaseCombatCharacter::OnDataChanged( DataUpdateType_t updateType ) BaseClass::OnDataChanged( updateType ); #ifdef GLOWS_ENABLE - if ( m_bOldGlowEnabled != m_bGlowEnabled ) + if ( m_bOldGlowEnabled != m_bGlowEnabled || m_OldGlowColor != m_GlowColor || m_OldGlowAlpha != m_GlowAlpha ) { UpdateGlowEffect(); } @@ -106,11 +112,13 @@ void C_BaseCombatCharacter::DoMuzzleFlash() //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b ) +void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b, float *a ) { - *r = 0.76f; - *g = 0.76f; - *b = 0.76f; + *r = m_GlowColor.x; + *g = m_GlowColor.y; + *b = m_GlowColor.z; + if (a) + *a = m_GlowAlpha; } //----------------------------------------------------------------------------- @@ -127,10 +135,10 @@ void C_BaseCombatCharacter::UpdateGlowEffect( void ) // create a new effect if ( m_bGlowEnabled ) { - float r, g, b; - GetGlowEffectColor( &r, &g, &b ); + float r, g, b, a; + GetGlowEffectColor( &r, &g, &b, &a ); - m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), 1.0, true ); + m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), a, true ); } } @@ -161,6 +169,8 @@ BEGIN_RECV_TABLE(C_BaseCombatCharacter, DT_BaseCombatCharacter) RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ), #ifdef GLOWS_ENABLE RecvPropBool( RECVINFO( m_bGlowEnabled ) ), + RecvPropVector( RECVINFO( m_GlowColor ) ), + RecvPropFloat( RECVINFO( m_GlowAlpha ) ), #endif // GLOWS_ENABLE #ifdef INVASION_CLIENT_DLL diff --git a/sp/src/game/client/c_basecombatcharacter.h b/sp/src/game/client/c_basecombatcharacter.h index f580fe46..4941b136 100644 --- a/sp/src/game/client/c_basecombatcharacter.h +++ b/sp/src/game/client/c_basecombatcharacter.h @@ -99,7 +99,7 @@ public: #ifdef GLOWS_ENABLE CGlowObject *GetGlowObject( void ){ return m_pGlowEffect; } - virtual void GetGlowEffectColor( float *r, float *g, float *b ); + virtual void GetGlowEffectColor( float *r, float *g, float *b, float *a = NULL ); #endif // GLOWS_ENABLE #ifdef MAPBASE_VSCRIPT @@ -133,6 +133,10 @@ private: bool m_bGlowEnabled; bool m_bOldGlowEnabled; CGlowObject *m_pGlowEffect; + Vector m_GlowColor; + Vector m_OldGlowColor; + float m_GlowAlpha; + int m_OldGlowAlpha; #endif // GLOWS_ENABLE private: diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 6b21a23a..b7a2692d 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -195,6 +195,13 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by DEFINE_SCRIPTFUNC( LastHitGroup, "Get the last hitgroup." ) +#ifdef GLOWS_ENABLE + DEFINE_SCRIPTFUNC( AddGlowEffect, "" ) + DEFINE_SCRIPTFUNC( RemoveGlowEffect, "" ) + DEFINE_SCRIPTFUNC( IsGlowEffectActive, "" ) + DEFINE_SCRIPTFUNC( SetGlowColor, "" ) +#endif + // // Hooks // @@ -293,6 +300,8 @@ END_SEND_TABLE(); IMPLEMENT_SERVERCLASS_ST(CBaseCombatCharacter, DT_BaseCombatCharacter) #ifdef GLOWS_ENABLE SendPropBool( SENDINFO( m_bGlowEnabled ) ), + SendPropVector( SENDINFO( m_GlowColor ), 8, 0, 0, 1 ), + SendPropFloat( SENDINFO( m_GlowAlpha ) ), #endif // GLOWS_ENABLE // Data that only gets sent to the local player. SendPropDataTable( "bcc_localdata", 0, &REFERENCE_SEND_TABLE(DT_BCCLocalPlayerExclusive), SendProxy_SendBaseCombatCharacterLocalDataTable ), @@ -878,6 +887,8 @@ CBaseCombatCharacter::CBaseCombatCharacter( void ) #ifdef GLOWS_ENABLE m_bGlowEnabled.Set( false ); + m_GlowColor.GetForModify().Init( 0.76f, 0.76f, 0.76f ); + m_GlowAlpha.Set(1.0f); #endif // GLOWS_ENABLE } @@ -4098,6 +4109,12 @@ bool CBaseCombatCharacter::IsGlowEffectActive( void ) { return m_bGlowEnabled; } + +void CBaseCombatCharacter::SetGlowColor( float red, float green, float blue, float alpha ) +{ + m_GlowColor.GetForModify().Init( red, green, blue ); + m_GlowAlpha.Set( alpha ); +} #endif // GLOWS_ENABLE //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index 20d3973e..f7aa3d8e 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -532,6 +532,7 @@ public: void AddGlowEffect( void ); void RemoveGlowEffect( void ); bool IsGlowEffectActive( void ); + void SetGlowColor( float red, float green, float blue, float alpha ); #endif // GLOWS_ENABLE #ifdef INVASION_DLL @@ -576,6 +577,8 @@ public: #ifdef GLOWS_ENABLE protected: CNetworkVar( bool, m_bGlowEnabled ); + CNetworkVector( m_GlowColor ); + CNetworkVar( float, m_GlowAlpha ); #endif // GLOWS_ENABLE private: From b03ffdcac494d4ce3d94665ac71a565fa0454325 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 5 Jan 2025 13:04:34 -0600 Subject: [PATCH 59/64] Fix VScript not having "self" during precache, props not using death hook, VScript proxies not cleaning up correctly --- sp/src/game/client/vscript_client.cpp | 2 ++ sp/src/game/server/props.cpp | 6 ++++++ sp/src/game/shared/vscript_shared.cpp | 3 +++ 3 files changed, 11 insertions(+) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 7bece925..2312d6ca 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -272,6 +272,8 @@ void CScriptMaterialProxy::Release( void ) m_hScriptInstance = NULL; } + g_ScriptPersistableList.FindAndRemove( this ); + delete this; } diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 57e33d87..037a0226 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -1338,6 +1338,12 @@ int CBreakableProp::OnTakeDamage( const CTakeDamageInfo &inputInfo ) //----------------------------------------------------------------------------- void CBreakableProp::Event_Killed( const CTakeDamageInfo &info ) { +#ifdef MAPBASE_VSCRIPT + // False = Cheat death + if (ScriptDeathHook( const_cast(&info) ) == false) + return; +#endif + IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics && !pPhysics->IsMoveable() ) { diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index 8ab2ac97..c41ddea6 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -624,6 +624,9 @@ public: if ( g_pScriptVM->GetValue( STRING(pEnt->m_iszScriptId), &variant ) && variant.m_type == FIELD_HSCRIPT ) { pEnt->m_ScriptScope.Init( variant.m_hScript, false ); +#ifdef MAPBASE_VSCRIPT + g_pScriptVM->SetValue( pEnt->m_ScriptScope, "self", pEnt->m_hScriptInstance ); +#endif #ifndef CLIENT_DLL pEnt->RunPrecacheScripts(); #endif From 5bc5a3beece0bb86dd7da159e091a5f783d6a01b Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 12 Jan 2025 15:30:03 -0600 Subject: [PATCH 60/64] Fix vgui_controls being considered a part of map tools in build workflow --- .github/workflows/mapbase_build-base.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mapbase_build-base.yml b/.github/workflows/mapbase_build-base.yml index 0a4905d0..ccf39580 100644 --- a/.github/workflows/mapbase_build-base.yml +++ b/.github/workflows/mapbase_build-base.yml @@ -94,7 +94,6 @@ jobs: run: | msbuild -m -p:Configuration=${{inputs.configuration}} raytrace\raytrace.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} tier1\tier1.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} vscript\vscript.vcxproj || exit /b - name: Build Map Tools @@ -121,6 +120,7 @@ jobs: working-directory: '${{inputs.branch}}/src' shell: cmd run: | + msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_${{inputs.game}}.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_${{inputs.game}}.vcxproj || exit /b From 93d586a82e1ac601e74dd157682ce954b8a42976 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 12 Jan 2025 15:56:02 -0600 Subject: [PATCH 61/64] Add vgui_controls to workflow for all projects --- .github/workflows/mapbase_build-base.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mapbase_build-base.yml b/.github/workflows/mapbase_build-base.yml index ccf39580..d7859284 100644 --- a/.github/workflows/mapbase_build-base.yml +++ b/.github/workflows/mapbase_build-base.yml @@ -131,6 +131,7 @@ jobs: working-directory: '${{inputs.branch}}/src' shell: cmd run: | + msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_episodic.vcxproj || exit /b msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_hl2.vcxproj || exit /b From cfe649e0e0394c0a516097b20e8afe39a7f02ad7 Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Mon, 13 Jan 2025 09:53:06 -0600 Subject: [PATCH 62/64] Change workflow to use .sln and consolidate artifact tasks --- .github/workflows/mapbase_build-base.yml | 135 +++++------------------ 1 file changed, 29 insertions(+), 106 deletions(-) diff --git a/.github/workflows/mapbase_build-base.yml b/.github/workflows/mapbase_build-base.yml index d7859284..45602a72 100644 --- a/.github/workflows/mapbase_build-base.yml +++ b/.github/workflows/mapbase_build-base.yml @@ -54,7 +54,7 @@ jobs: - uses: actions/checkout@v4 - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: compnerd/gha-setup-vsdevenv@v6 - name: Enable VS2022 working-directory: '${{inputs.branch}}/src/vpc_scripts' @@ -77,108 +77,40 @@ jobs: # -------------------------------------------------------------------- - # "I'm invoking msbuild for each project individually, which looks a bit odd considering there is a solution file which should be able to invoke the builds in their proper order automatically, but passing the solution to msbuild doesn't seem to work." - # https://github.com/mapbase-source/source-sdk-2013/pull/162 - - - name: Build mathlib + - name: Build #if: steps.filter.outputs.game == 'true' working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} mathlib\mathlib.vcxproj || exit /b - - - name: Build Base Libraries - if: inputs.project-group == 'all' || inputs.project-group == 'game' || inputs.project-group == 'maptools' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} raytrace\raytrace.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} tier1\tier1.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} vscript\vscript.vcxproj || exit /b - - - name: Build Map Tools - if: inputs.project-group == 'all' || inputs.project-group == 'maptools' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} fgdlib\fgdlib.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vbsp\vbsp.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis\vvis_dll.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis_launcher\vvis_launcher.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad\vrad_dll.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad_launcher\vrad_launcher.vcxproj || exit /b - - - name: Build Shaders - if: inputs.project-group == 'shaders' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_${{inputs.game}}.vcxproj || exit /b - - - name: Build Game - if: inputs.project-group == 'game' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_${{inputs.game}}.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_${{inputs.game}}.vcxproj || exit /b - - # TODO: Hook to game naming? - - name: Build everything - if: inputs.project-group == 'all' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_episodic.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_hl2.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_episodic.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_hl2.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_episodic.vcxproj || exit /b - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_hl2.vcxproj || exit /b + devenv ${{inputs.solution-name}}.sln /upgrade + msbuild -m -t:Rebuild -p:Configuration=${{inputs.configuration}};Platform=x86 ${{inputs.solution-name}}.sln # -------------------------------------------------------------------- - - name: Publish Windows game DLLs - if: inputs.project-group == 'game' - uses: actions/upload-artifact@v3 + - name: Publish game binaries + if: inputs.project-group == 'game' || inputs.project-group == 'shaders' + uses: actions/upload-artifact@v4 with: - name: 'Windows Game DLLs (server & client.dll) [${{ inputs.configuration }}]' + name: '${{inputs.project-group}}_${{inputs.game}}_win32_${{ inputs.configuration }}' path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/client.dll - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/server.dll + ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/*.dll if-no-files-found: error - - name: Publish Windows shader DLL - if: inputs.project-group == 'shaders' - uses: actions/upload-artifact@v3 - with: - name: 'Windows Shader DLL (game_shader_dx9.dll) [${{ inputs.configuration }}]' - path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/game_shader_dx9.dll - if-no-files-found: error - - - name: Publish Windows map tools + - name: Publish map tools if: inputs.project-group == 'maptools' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: 'Windows Map Tools [${{ inputs.configuration }}]' + name: '${{inputs.project-group}}_win32_${{ inputs.configuration }}' path: | - ${{inputs.branch}}/game/bin/vbsp.exe - ${{inputs.branch}}/game/bin/vvis.exe - ${{inputs.branch}}/game/bin/vvis_dll.dll - ${{inputs.branch}}/game/bin/vrad.exe - ${{inputs.branch}}/game/bin/vrad_dll.dll + ${{inputs.branch}}/game/bin/*.exe + ${{inputs.branch}}/game/bin/*.dll if-no-files-found: error - - name: Publish everything (Windows) + - name: Publish everything if: inputs.project-group == 'all' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: 'Everything (Windows) [${{ inputs.configuration }}]' + name: 'everything_win32_${{ inputs.configuration }}' path: | ${{inputs.branch}}/game/bin ${{inputs.branch}}/game/mod_*/bin @@ -225,30 +157,21 @@ jobs: # -------------------------------------------------------------------- - - name: Publish Linux game SOs - if: inputs.project-group == 'game' - uses: actions/upload-artifact@v3 + - name: Publish game binaries + if: inputs.project-group == 'game' || inputs.project-group == 'shaders' + uses: actions/upload-artifact@v4 with: - name: 'Linux Game SOs (server & client.so) [${{ inputs.configuration }}]' + name: '${{inputs.project-group}}_${{inputs.game}}_linux32_${{ inputs.configuration }}' path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/client.so - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/server.so + ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/*.so + !${{inputs.branch}}/game/mod_${{inputs.game}}/bin/*_srv.so if-no-files-found: error - - name: Publish Linux shader SO - if: inputs.project-group == 'shaders' - uses: actions/upload-artifact@v3 - with: - name: 'Linux Shader SO (game_shader_dx9.so) [${{ inputs.configuration }}]' - path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/game_shader_dx9.so - if-no-files-found: error - - #- name: Publish Linux map tools + #- name: Publish map tools # if: inputs.project-group == 'maptools' - # uses: actions/upload-artifact@v3 + # uses: actions/upload-artifact@v4 # with: - # name: 'Linux Map Tools [${{ inputs.configuration }}]' + # name: '${{inputs.project-group}}_linux32_${{ inputs.configuration }}' # path: | # ${{inputs.branch}}/game/bin/vbsp # ${{inputs.branch}}/game/bin/vvis @@ -259,11 +182,11 @@ jobs: # For now, don't publish the .dbg files even though we publish .pdb files on Windows # (they're too big) - - name: Publish everything (Linux) + - name: Publish everything if: inputs.project-group == 'all' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: 'Everything (Linux) [${{ inputs.configuration }}]' + name: 'everything_linux32_${{ inputs.configuration }}' path: | ${{inputs.branch}}/game/bin/*.so !${{inputs.branch}}/game/bin/*_srv.so From f79f07e9158d0461a88a1af91572a66dc3543def Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Sun, 5 Jan 2025 12:25:34 -0600 Subject: [PATCH 63/64] Support for multiple colors for different outro credits columns on the same row --- sp/src/game/client/hl2/hud_credits.cpp | 78 +++++++++++++++++++++----- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/sp/src/game/client/hl2/hud_credits.cpp b/sp/src/game/client/hl2/hud_credits.cpp index fb4354f5..bf0e58fd 100644 --- a/sp/src/game/client/hl2/hud_credits.cpp +++ b/sp/src/game/client/hl2/hud_credits.cpp @@ -35,8 +35,7 @@ struct creditname_t #ifdef MAPBASE // New credits stuff - - Color cColorOverride; + CCopyableUtlVector cColorOverride; // Images int iImageID = -1; @@ -408,8 +407,8 @@ void CHudCredits::DrawOutroCreditsName( void ) Color cColor = m_TextColor; #ifdef MAPBASE - if (pCredit->cColorOverride.a() > 0) - cColor = pCredit->cColorOverride; + if (pCredit->cColorOverride.Count() > 0) + cColor.SetRawColor( pCredit->cColorOverride[0] ); // Some lines should stick around and fade out if ( i >= m_CreditsList.Count()-m_iEndLines ) @@ -473,6 +472,12 @@ void CHudCredits::DrawOutroCreditsName( void ) { FOR_EACH_VEC( outStrings, i ) { + if (i < pCredit->cColorOverride.Count()) + { + // Change color to this particular column's color + cColor.SetRawColor( pCredit->cColorOverride[i] ); + } + int iImageID = GetOrAllocateImageID( outStrings[i] ); // Center the image if needed @@ -492,6 +497,12 @@ void CHudCredits::DrawOutroCreditsName( void ) { FOR_EACH_VEC( outStrings, i ) { + if (i < pCredit->cColorOverride.Count()) + { + // Change color to this particular column's color + cColor.SetRawColor( pCredit->cColorOverride[i] ); + } + DrawOutroCreditFont( outStrings[i], pCredit->flYPos, m_hTFont, cColor, iWidth*(i + 1), iDivisor ); } } @@ -768,8 +779,8 @@ void CHudCredits::DrawIntroCreditsName( void ) surface()->DrawSetTextFont( m_hTFont ); #ifdef MAPBASE Color cColor = m_cColor; - if (pCredit->cColorOverride.a() > 0) - cColor = pCredit->cColorOverride; + if (pCredit->cColorOverride.Count() > 0) + cColor.SetRawColor( pCredit->cColorOverride[0] ); surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], FadeBlend( m_flFadeInTime, m_flFadeOutTime, m_flFadeHoldTime + pCredit->flTimeAdd, localTime ) * cColor[3] ); #else @@ -941,9 +952,25 @@ void CHudCredits::PrepareOutroCredits( void ) // Get color case 2: - int tmp[4]; - UTIL_StringToIntArray( tmp, 4, outStrings[i] ); - pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + char *pToken = strtok( outStrings[i], "," ); + if (pToken) + { + // Multiple colors for multiple columns + while (pToken != NULL) + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, pToken ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + + pToken = strtok( NULL, "," ); + } + } + else + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + } break; } } @@ -999,9 +1026,25 @@ void CHudCredits::PrepareOutroCredits( void ) { // Get color case 1: - int tmp[4]; - UTIL_StringToIntArray( tmp, 4, outStrings[i] ); - pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + char *pToken = strtok( outStrings[i], "," ); + if (pToken) + { + // Multiple colors for multiple columns + while (pToken != NULL) + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, pToken ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + + pToken = strtok( NULL, "," ); + } + } + else + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + } break; } } @@ -1024,8 +1067,12 @@ void CHudCredits::PrepareOutroCredits( void ) #ifdef MAPBASE // Check if the last line has a color override. If it does, use that as the alpha for the fadeout - if (m_CreditsList.Tail().cColorOverride.a() != 0) - m_Alpha = m_CreditsList.Tail().cColorOverride.a(); + if (m_CreditsList.Tail().cColorOverride.Count() > 0) + { + Color clr; + clr.SetRawColor( m_CreditsList.Tail().cColorOverride[0] ); + m_Alpha = clr.a(); + } #endif SetActive( true ); @@ -1057,9 +1104,10 @@ void CHudCredits::PrepareIntroCredits( void ) { // Get color case 1: + // TODO: Columns? int tmp[4]; UTIL_StringToIntArray( tmp, 4, outStrings[i] ); - pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); break; } } From 365d560f12ae1baefa32d05cc980f865a73a8dfe Mon Sep 17 00:00:00 2001 From: "ALLEN-PC\\acj30" Date: Tue, 14 Jan 2025 07:54:52 -0600 Subject: [PATCH 64/64] Updated README --- README | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README b/README index d9d11024..b2fcc972 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ //========================================================================================================================= - Mapbase v7.2 - Source 2013 + Mapbase v7.3 - Source 2013 https://github.com/mapbase-source/source-sdk-2013 https://www.moddb.com/mods/mapbase @@ -117,7 +117,18 @@ Direct contributions: - https://github.com/mapbase-source/source-sdk-2013/pull/237 (Commander goal trace fix by Agrimar) - https://github.com/mapbase-source/source-sdk-2013/pull/245 (ViewPunch random fix by Mr0maks) - https://github.com/mapbase-source/source-sdk-2013/pull/248 (soundlevel_t conversation warning fix by Mechami) +- https://github.com/mapbase-source/source-sdk-2013/pull/266 ("OnPhysGunPull" output in CPhysicsProp by rlenhub) +- https://github.com/mapbase-source/source-sdk-2013/pull/292 (env_headcrabcanister random spawn type by arbabf) +- https://github.com/mapbase-source/source-sdk-2013/pull/294 (SDK_LightmappedGeneric editor blend swap fix by azzyr) +- https://github.com/mapbase-source/source-sdk-2013/pull/308 (BlurFilterY fix by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/312 (Zombie improvements by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/315 (env_flare crash fix by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/324 (server-only info/func_null by SirYodaJedi) +- https://github.com/mapbase-source/source-sdk-2013/pull/333 (Cvar to transition levels while in MOVETYPE_NOCLIP by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/342 (NaN particle cull radius fix by celisej567) - https://github.com/mapbase-source/mapbase-game-src/pull/1 (Advanced video options duplicate field name fix by arbabf; This is asset-based and not reflected in the code) +- https://github.com/mapbase-source/mapbase-game-src/pull/2 (gameinfo.txt typo fix by CarePackage17; This is asset-based and not reflected in the code) +- https://github.com/mapbase-source/mapbase-game-src/pull/3 (HudMessage cutoff fix by arbabf; This is asset-based and not reflected in the code) - Demo autorecord code provided by Klems - cc_emit crash fix provided by 1upD - Custom HL2 ammo crate models created by Rykah (Textures created by Blixibon; This is asset-based and, aside from the SLAM crate, not reflected in the code) @@ -144,8 +155,10 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/206 (Fix CScriptNetMsgHelper::WriteEntity()) =-- https://github.com/mapbase-source/source-sdk-2013/pull/213 (VScript HUD visibility control, optimizations for 3D skybox angles/fake worldportals) =-- https://github.com/mapbase-source/source-sdk-2013/pull/229 (VScript VGUI HUD viewport parenting, game_text and vgui_text_display VScript font fallback) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/260 (CScriptNetPropManager rewrite) =-- https://github.com/mapbase-source/source-sdk-2013/pull/261 (Misc VScript additions) =-- https://github.com/mapbase-source/source-sdk-2013/pull/279 (weapon_custom_scripted fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/332 (Fix OOB access) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) @@ -159,6 +172,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/159 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/162 (VS2019 exception specification fix) =-- https://github.com/mapbase-source/source-sdk-2013/pull/170 (HL2 non-Episodic build fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/322 (Small Mapbase fixes) == Contributions from Petercov: =-- https://github.com/mapbase-source/source-sdk-2013/pull/182 (NPCs load dynamic interactions from all animation MDLs) @@ -168,6 +182,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/183 (Enhanced custom weapons support) =-- https://github.com/mapbase-source/source-sdk-2013/pull/230 (Caption fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/231 (Sentence source bug fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/264 (Outputs for vgui_screen) //-------------------------------------------------------------------------------------------------------------------------