diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index f3efe54f..c594e9cf 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2200,11 +2200,15 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptIsEntVisible, "IsEntVisible", "Check if the specified entity can be visible to this entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptIsVisibleWithMask, "IsVisibleWithMask", "Check if the specified position can be visible to this entity with a specific trace mask." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptTakeDamage, "TakeDamage", "Apply damage to this entity with a given info handle" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetContext, "GetContext", "Get a response context value" ) DEFINE_SCRIPTFUNC_NAMED( ScriptAddContext, "AddContext", "Add a response context value" ) DEFINE_SCRIPTFUNC_NAMED( ScriptClassify, "Classify", "Get Class_T class ID" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValue, "GetKeyValue", "Get a keyvalue" ) + DEFINE_SCRIPTFUNC( GetSpawnFlags, "Get spawnflags" ) DEFINE_SCRIPTFUNC( AddSpawnFlags, "Add spawnflag(s)" ) DEFINE_SCRIPTFUNC( RemoveSpawnFlags, "Remove spawnflag(s)" ) @@ -9536,6 +9540,19 @@ const Vector& CBaseEntity::ScriptGetBoundingMaxs(void) } #ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CBaseEntity::ScriptTakeDamage( HSCRIPT pInfo ) +{ + if (pInfo) + { + CTakeDamageInfo *info = HScriptToClass( pInfo ); //ToDamageInfo( pInfo ); + return OnTakeDamage( *info ); + } + + return 0; +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CBaseEntity::ScriptAddContext( const char *name, const char *value, float duration ) @@ -9556,6 +9573,15 @@ int CBaseEntity::ScriptClassify( void ) { return (int)Classify(); } + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const char *CBaseEntity::ScriptGetKeyValue( const char *pszKeyName ) +{ + static char szValue[128]; + GetKeyValue( pszKeyName, szValue, sizeof(szValue) ); + return szValue; +} #endif diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 79cf822f..93480385 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -2000,10 +2000,14 @@ public: bool ScriptIsEntVisible( HSCRIPT pEntity ) { return FVisible( ToEnt( pEntity ) ); } bool ScriptIsVisibleWithMask( const Vector &vecSpot, int traceMask ) { return FVisible( vecSpot, traceMask ); } + int ScriptTakeDamage( HSCRIPT pInfo ); + void ScriptAddContext( const char *name, const char *value, float duration = 0.0f ); const char *ScriptGetContext( const char *name ); int ScriptClassify(void); + + const char *ScriptGetKeyValue( const char *pszKeyName ); #endif string_t m_iszVScripts; diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index f9380dc7..c1746ad1 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -44,6 +44,18 @@ BEGIN_DATADESC( CBaseFilter ) END_DATADESC() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( CBaseFilter, CBaseEntity, "All entities which could be used as filters." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptPassesFilter, "PassesFilter", "Check if the given caller and entity pass the filter." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPassesDamageFilter, "PassesDamageFilter", "Check if the given caller and damage info pass the damage filter." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPassesFinalDamageFilter, "PassesFinalDamageFilter", "Used by filter_damage_redirect to distinguish between standalone filter calls and actually damaging an entity. Returns true if there's no unique behavior." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptBloodAllowed, "BloodAllowed", "Check if the given caller and damage info allow for the production of blood." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptDamageMod, "DamageMod", "Mods the damage info with the given caller." ) + +END_SCRIPTDESC(); +#endif + //----------------------------------------------------------------------------- bool CBaseFilter::PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ) @@ -142,6 +154,14 @@ void CBaseFilter::InputSetField( inputdata_t& inputdata ) } #endif +#ifdef MAPBASE_VSCRIPT +bool CBaseFilter::ScriptPassesFilter( HSCRIPT pCaller, HSCRIPT pEntity ) { return PassesFilter( ToEnt(pCaller), ToEnt(pEntity) ); } +bool CBaseFilter::ScriptPassesDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesDamageFilter( ToEnt( pCaller ), *const_cast(HScriptToClass( pInfo )) ) : NULL; } +bool CBaseFilter::ScriptPassesFinalDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesFinalDamageFilter( ToEnt( pCaller ), *const_cast(HScriptToClass( pInfo )) ) : NULL; } +bool CBaseFilter::ScriptBloodAllowed( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? BloodAllowed( ToEnt( pCaller ), *const_cast(HScriptToClass( pInfo )) ) : NULL; } +bool CBaseFilter::ScriptDamageMod( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? DamageMod( ToEnt( pCaller ), *HScriptToClass( pInfo ) ) : NULL; } +#endif + // ################################################################### // > FilterMultiple @@ -223,6 +243,13 @@ void CFilterMultiple::Activate( void ) Warning("filter_multi: Tried to add entity (%s) which is not a filter entity!\n", STRING( m_iFilterName[i] ) ); continue; } +#ifdef MAPBASE + else if ( pFilter == this ) + { + Warning("filter_multi: Tried to add itself!\n"); + continue; + } +#endif // Take this entity and increment out array pointer m_hFilter[nNextFilter] = pFilter; @@ -2109,3 +2136,152 @@ BEGIN_DATADESC( CFilterDamageLogic ) END_DATADESC() #endif + +#ifdef MAPBASE_VSCRIPT +// ################################################################### +// > CFilterScript +// ################################################################### +class CFilterScript : public CBaseFilter +{ + DECLARE_CLASS( CFilterScript, CBaseFilter ); + DECLARE_DATADESC(); + +public: + bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ) + { + if (m_ScriptScope.IsInitialized()) + { + g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL ); + g_pScriptVM->SetValue( "activator", (pEntity) ? ScriptVariant_t( pEntity->GetScriptInstance() ) : SCRIPT_VARIANT_NULL ); + + ScriptVariant_t functionReturn; + if (!CallScriptFunction( "PassesFilter", &functionReturn )) + { + Warning("%s: No PassesFilter function\n", GetDebugName()); + } + + g_pScriptVM->ClearValue( "caller" ); + g_pScriptVM->ClearValue( "activator" ); + + return functionReturn.m_bool; + } + + Warning("%s: No script scope, cannot filter\n", GetDebugName()); + return false; + } + + bool PassesDamageFilterImpl( CBaseEntity *pCaller, const CTakeDamageInfo &info ) + { + if (m_ScriptScope.IsInitialized()) + { + HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); + + g_pScriptVM->SetValue( "info", pInfo ); + g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL ); + + ScriptVariant_t functionReturn; + if (!CallScriptFunction( "PassesDamageFilter", &functionReturn )) + { + // Fall back to main filter function + return PassesFilterImpl( pCaller, info.GetAttacker() ); + } + + g_pScriptVM->RemoveInstance( pInfo ); + + g_pScriptVM->ClearValue( "info" ); + g_pScriptVM->ClearValue( "caller" ); + + return functionReturn.m_bool; + } + + Warning("%s: No script scope, cannot filter\n", GetDebugName()); + return false; + } + + bool PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info ) + { + if (m_ScriptScope.IsInitialized()) + { + HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); + + g_pScriptVM->SetValue( "info", pInfo ); + g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL ); + + ScriptVariant_t functionReturn; + if (!CallScriptFunction( "PassesFinalDamageFilter", &functionReturn )) + { + return BaseClass::PassesFinalDamageFilter( pCaller, info ); + } + + g_pScriptVM->RemoveInstance( pInfo ); + + g_pScriptVM->ClearValue( "info" ); + g_pScriptVM->ClearValue( "caller" ); + + return functionReturn.m_bool; + } + + Warning("%s: No script scope, cannot filter\n", GetDebugName()); + return false; + } + + bool BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info ) + { + if (m_ScriptScope.IsInitialized()) + { + HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); + + g_pScriptVM->SetValue( "info", pInfo ); + g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL ); + + ScriptVariant_t functionReturn; + if (!CallScriptFunction( "BloodAllowed", &functionReturn )) + { + return BaseClass::BloodAllowed( pCaller, info ); + } + + g_pScriptVM->RemoveInstance( pInfo ); + + g_pScriptVM->ClearValue( "info" ); + g_pScriptVM->ClearValue( "caller" ); + + return functionReturn.m_bool; + } + + Warning("%s: No script scope, cannot filter\n", GetDebugName()); + return false; + } + + bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info ) + { + if (m_ScriptScope.IsInitialized()) + { + HSCRIPT pInfo = g_pScriptVM->RegisterInstance( &info ); + + g_pScriptVM->SetValue( "info", pInfo ); + g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL ); + + ScriptVariant_t functionReturn; + if (!CallScriptFunction( "DamageMod", &functionReturn )) + { + return BaseClass::DamageMod( pCaller, info ); + } + + g_pScriptVM->RemoveInstance( pInfo ); + + g_pScriptVM->ClearValue( "info" ); + g_pScriptVM->ClearValue( "caller" ); + + return functionReturn.m_bool; + } + + Warning("%s: No script scope, cannot filter\n", GetDebugName()); + return false; + } +}; + +LINK_ENTITY_TO_CLASS( filter_script, CFilterScript ); + +BEGIN_DATADESC( CFilterScript ) +END_DATADESC() +#endif diff --git a/sp/src/game/server/filters.h b/sp/src/game/server/filters.h index 46345f51..faaa20fd 100644 --- a/sp/src/game/server/filters.h +++ b/sp/src/game/server/filters.h @@ -38,6 +38,9 @@ class CBaseFilter : public CLogicalEntity public: DECLARE_DATADESC(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif bool PassesFilter( CBaseEntity *pCaller, CBaseEntity *pEntity ); #ifdef MAPBASE @@ -56,6 +59,14 @@ public: bool PassesDamageFilter( const CTakeDamageInfo &info ); #endif +#ifdef MAPBASE_VSCRIPT + bool ScriptPassesFilter( HSCRIPT pCaller, HSCRIPT pEntity ); + bool ScriptPassesDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ); + bool ScriptPassesFinalDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ); + bool ScriptBloodAllowed( HSCRIPT pCaller, HSCRIPT pInfo ); + bool ScriptDamageMod( HSCRIPT pCaller, HSCRIPT pInfo ); +#endif + bool m_bNegated; // Inputs diff --git a/sp/src/game/server/mapbase/logic_externaldata.cpp b/sp/src/game/server/mapbase/logic_externaldata.cpp index de927147..89500b65 100644 --- a/sp/src/game/server/mapbase/logic_externaldata.cpp +++ b/sp/src/game/server/mapbase/logic_externaldata.cpp @@ -312,8 +312,6 @@ HSCRIPT CLogicExternalData::ScriptGetKeyValueBlock( void ) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -extern CScriptKeyValues *ToScriptKeyValues( HSCRIPT hKV ); - void CLogicExternalData::ScriptSetKeyValues( HSCRIPT hKV ) { if (m_pRoot) @@ -322,7 +320,7 @@ void CLogicExternalData::ScriptSetKeyValues( HSCRIPT hKV ) m_pRoot = NULL; } - CScriptKeyValues *pKV = ToScriptKeyValues(hKV); + CScriptKeyValues *pKV = HScriptToClass( hKV ); if (pKV) { m_pRoot = pKV->m_pKeyValues; @@ -337,7 +335,7 @@ void CLogicExternalData::ScriptSetKeyValueBlock( HSCRIPT hKV ) m_pBlock = NULL; } - CScriptKeyValues *pKV = ToScriptKeyValues(hKV); + CScriptKeyValues *pKV = HScriptToClass( hKV ); if (pKV) { m_pBlock = pKV->m_pKeyValues; diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index f0a15841..398b136c 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -10,6 +10,8 @@ //=============================================================================// #include "cbase.h" +#include "matchers.h" +#include "takedamageinfo.h" #ifndef CLIENT_DLL #include "globalstate.h" @@ -19,6 +21,287 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CScriptNetPropManager +{ +public: + +#ifdef CLIENT_DLL + RecvProp *RecurseTable( RecvTable *pTable, const char *pszPropName ) +#else + SendProp *RecurseTable( SendTable *pTable, const char *pszPropName ) +#endif + { +#ifdef CLIENT_DLL + RecvProp *pProp = NULL; +#else + SendProp *pProp = NULL; +#endif + for (int i = 0; i < pTable->GetNumProps(); i++) + { + pProp = pTable->GetProp( i ); + if (pProp->GetType() == DPT_DataTable) + { + pProp = RecurseTable(pProp->GetDataTable(), pszPropName); + if (pProp) + return pProp; + } + else + { + DevMsg( "VScript NetPropManager: Prop name is \"%s\"\n", pProp->GetName() ); + if (FStrEq( pProp->GetName(), pszPropName )) + return pProp; + } + } + + return NULL; + } + +#ifdef CLIENT_DLL + RecvProp *RecurseNetworkClass( ClientClass *pClass, const char *pszPropName ) +#else + SendProp *RecurseNetworkClass( ServerClass *pClass, const char *pszPropName ) +#endif + { +#ifdef CLIENT_DLL + RecvProp *pProp = RecurseTable( pClass->m_pRecvTable, pszPropName ); +#else + SendProp *pProp = RecurseTable( pClass->m_pTable, pszPropName ); +#endif + if (pProp) + return pProp; + + if (pClass->m_pNext) + return RecurseNetworkClass( pClass->m_pNext, pszPropName ); + else + return NULL; + } + +#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; + } +#endif + + int GetPropArraySize( HSCRIPT hEnt, const char *pszPropName ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + auto *pProp = GetPropByName( pEnt, pszPropName ); + if (pProp) + { + // TODO: Is this what this function wants? + return pProp->GetNumElements(); + } + + 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 ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + auto *pProp = GetPropByName( pEnt, pszPropName ); + if (pProp && pProp->GetType() == DPT_Int) + { + return ToHScript( *(CHandle*)((char *)pEnt + pProp->GetOffset()) ); + } + + return NULL; + } + + HSCRIPT GetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + auto *pProp = GetPropByName( pEnt, pszPropName ); + if (pProp && pProp->GetType() == DPT_Int) + { + 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()) + { + 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"; + } + } + + 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) + { + *((CHandle*)((char *)pEnt + pProp->GetOffset())) = ToEnt(value); + } + } + + HSCRIPT SetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value, int iArrayElement ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + auto *pProp = GetPropByName( pEnt, pszPropName ); + if (pProp && pProp->GetType() == DPT_Int) + { + ((CHandle*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = ToEnt(value); + } + + return NULL; + } + +private: +} 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." ) +END_SCRIPTDESC(); + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -163,12 +446,19 @@ HSCRIPT SpawnEntityFromTable( const char *pszClassname, HSCRIPT hKV ) // Mapbase-specific functions start here //----------------------------------------------------------------------------- -#ifndef CLIENT_DLL -inline CScriptKeyValues *ToScriptKeyValues( HSCRIPT hKV ) +static void ScriptColorPrint( int r, int g, int b, const char *pszMsg ) { - return (hKV) ? (CScriptKeyValues*)g_pScriptVM->GetInstanceValue( hKV, GetScriptDescForClass( CScriptKeyValues ) ) : NULL; + const Color clr(r, g, b, 255); + ConColorMsg( clr, "%s", pszMsg ); } +static void ScriptColorPrintL( int r, int g, int b, const char *pszMsg ) +{ + const Color clr(r, g, b, 255); + ConColorMsg( clr, "%s\n", pszMsg ); +} + +#ifndef CLIENT_DLL HSCRIPT SpawnEntityFromKeyValues( const char *pszClassname, HSCRIPT hKV ) { if ( IsEntityCreationAllowedInScripts() == false ) @@ -186,7 +476,7 @@ HSCRIPT SpawnEntityFromKeyValues( const char *pszClassname, HSCRIPT hKV ) gEntList.NotifyCreateEntity( pEntity ); - CScriptKeyValues *pScriptKV = ToScriptKeyValues( hKV ); + CScriptKeyValues *pScriptKV = hKV ? HScriptToClass( hKV ) : NULL; if (pScriptKV) { KeyValues *pKV = pScriptKV->m_pKeyValues; @@ -211,6 +501,142 @@ void ScriptDispatchSpawn( HSCRIPT hEntity ) } #endif +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +static HSCRIPT CreateDamageInfo( HSCRIPT hInflictor, HSCRIPT hAttacker, const Vector &vecForce, const Vector &vecDamagePos, float flDamage, int iDamageType ) +{ + // The script is responsible for deleting this via DestroyDamageInfo(). + CTakeDamageInfo *damageInfo = new CTakeDamageInfo(ToEnt(hInflictor), ToEnt(hAttacker), flDamage, iDamageType); + HSCRIPT hScript = g_pScriptVM->RegisterInstance( damageInfo ); + + damageInfo->SetDamagePosition( vecDamagePos ); + damageInfo->SetDamageForce( vecForce ); + + return hScript; +} + +static void DestroyDamageInfo( HSCRIPT hDamageInfo ) +{ + if (hDamageInfo) + { + CTakeDamageInfo *pInfo = (CTakeDamageInfo*)g_pScriptVM->GetInstanceValue( hDamageInfo, GetScriptDescForClass( CTakeDamageInfo ) ); + if (pInfo) + { + g_pScriptVM->RemoveInstance( hDamageInfo ); + delete pInfo; + } + } +} + +void ScriptCalculateExplosiveDamageForce( HSCRIPT info, const Vector &vecDir, const Vector &vecForceOrigin, float flScale ) { CalculateExplosiveDamageForce( HScriptToClass(info), vecDir, vecForceOrigin, flScale ); } +void ScriptCalculateBulletDamageForce( HSCRIPT info, int iBulletType, const Vector &vecBulletDir, const Vector &vecForceOrigin, float flScale ) { CalculateBulletDamageForce( HScriptToClass(info), iBulletType, vecBulletDir, vecForceOrigin, flScale ); } +void ScriptCalculateMeleeDamageForce( HSCRIPT info, const Vector &vecMeleeDir, const Vector &vecForceOrigin, float flScale ) { CalculateMeleeDamageForce( HScriptToClass( info ), vecMeleeDir, vecForceOrigin, flScale ); } +void ScriptGuessDamageForce( HSCRIPT info, const Vector &vecForceDir, const Vector &vecForceOrigin, float flScale ) { GuessDamageForce( HScriptToClass( info ), vecForceDir, vecForceOrigin, flScale ); } + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CTraceInfoAccessor +{ +public: + + // CGrameTrace stuff + bool DidHitWorld() const { return m_tr.DidHitWorld(); } + bool DidHitNonWorldEntity() const { return m_tr.DidHitNonWorldEntity(); } + int GetEntityIndex() const { return m_tr.GetEntityIndex(); } + bool DidHit() const { return m_tr.DidHit(); } + + float FractionLeftSolid() const { return m_tr.fractionleftsolid; } + int HitGroup() const { return m_tr.hitgroup; } + int PhysicsBone() const { return m_tr.physicsbone; } + + HSCRIPT Entity() const { return ToHScript(m_tr.m_pEnt); } + + int HitBox() const { return m_tr.hitbox; } + + // CBaseTrace stuff + bool IsDispSurface() { return m_tr.IsDispSurface(); } + bool IsDispSurfaceWalkable() { return m_tr.IsDispSurfaceWalkable(); } + bool IsDispSurfaceBuildable() { return m_tr.IsDispSurfaceBuildable(); } + bool IsDispSurfaceProp1() { return m_tr.IsDispSurfaceProp1(); } + bool IsDispSurfaceProp2() { return m_tr.IsDispSurfaceProp2(); } + + Vector StartPos() const { return m_tr.startpos; } + Vector EndPos() const { return m_tr.endpos; } + + float Fraction() const { return m_tr.fraction; } + + int Contents() const { return m_tr.contents; } + int DispFlags() const { return m_tr.dispFlags; } + + bool AllSolid() const { return m_tr.allsolid; } + bool StartSolid() const { return m_tr.startsolid; } + + trace_t &GetTrace() { return m_tr; } + void Destroy() { delete this; } + +private: + trace_t m_tr; + +}; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CTraceInfoAccessor, "CGameTrace", "Handle for accessing trace_t info." ) + DEFINE_SCRIPTFUNC( DidHitWorld, "Returns whether the trace hit the world entity or not." ) + DEFINE_SCRIPTFUNC( DidHitNonWorldEntity, "Returns whether the trace hit something other than the world entity." ) + DEFINE_SCRIPTFUNC( GetEntityIndex, "Returns the index of whatever entity this trace hit." ) + DEFINE_SCRIPTFUNC( DidHit, "Returns whether the trace hit anything." ) + + DEFINE_SCRIPTFUNC( FractionLeftSolid, "If this trace started within a solid, this is the point in the trace's fraction at which it left that solid." ) + DEFINE_SCRIPTFUNC( HitGroup, "Returns the specific hit group this trace hit if it hit an entity." ) + DEFINE_SCRIPTFUNC( PhysicsBone, "Returns the physics bone this trace hit if it hit an entity." ) + DEFINE_SCRIPTFUNC( Entity, "Returns the entity this trace has hit." ) + DEFINE_SCRIPTFUNC( HitBox, "Returns the hitbox of the entity this trace has hit. If it hit the world entity, this returns the static prop index." ) + + DEFINE_SCRIPTFUNC( IsDispSurface, "Returns whether this trace hit a displacement." ) + DEFINE_SCRIPTFUNC( IsDispSurfaceWalkable, "Returns whether DISPSURF_FLAG_WALKABLE is ticked on the displacement this trace hit." ) + DEFINE_SCRIPTFUNC( IsDispSurfaceBuildable, "Returns whether DISPSURF_FLAG_BUILDABLE is ticked on the displacement this trace hit." ) + DEFINE_SCRIPTFUNC( IsDispSurfaceProp1, "Returns whether DISPSURF_FLAG_SURFPROP1 is ticked on the displacement this trace hit." ) + DEFINE_SCRIPTFUNC( IsDispSurfaceProp2, "Returns whether DISPSURF_FLAG_SURFPROP2 is ticked on the displacement this trace hit." ) + + DEFINE_SCRIPTFUNC( StartPos, "Gets the trace's start position." ) + DEFINE_SCRIPTFUNC( EndPos, "Gets the trace's end position." ) + + DEFINE_SCRIPTFUNC( Fraction, "Gets the fraction of the trace completed. For example, if the trace stopped exactly halfway to the end position, this would be 0.5." ) + DEFINE_SCRIPTFUNC( Contents, "Gets the contents of the surface the trace has hit." ) + DEFINE_SCRIPTFUNC( DispFlags, "Gets the displacement flags of the surface the trace has hit." ) + + DEFINE_SCRIPTFUNC( AllSolid, "Returns whether the trace is completely within a solid." ) + DEFINE_SCRIPTFUNC( StartSolid, "Returns whether the trace started within a solid." ) + + DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." ) +END_SCRIPTDESC(); + +static HSCRIPT ScriptTraceLineComplex( const Vector &vecStart, const Vector &vecEnd, HSCRIPT entIgnore, int iMask, int iCollisionGroup ) +{ + // The script is responsible for deleting this via Destroy(). + CTraceInfoAccessor *traceInfo = new CTraceInfoAccessor(); + HSCRIPT hScript = g_pScriptVM->RegisterInstance( traceInfo ); + + CBaseEntity *pLooker = ToEnt(entIgnore); + UTIL_TraceLine( vecStart, vecEnd, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace()); + return hScript; +} + +static HSCRIPT ScriptTraceHullComplex( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, const Vector &hullMax, + HSCRIPT entIgnore, int iMask, int iCollisionGroup ) +{ + // The script is responsible for deleting this via Destroy(). + CTraceInfoAccessor *traceInfo = new CTraceInfoAccessor(); + HSCRIPT hScript = g_pScriptVM->RegisterInstance( traceInfo ); + + CBaseEntity *pLooker = ToEnt(entIgnore); + UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace()); + return hScript; +} + +bool ScriptMatcherMatch( const char *pszQuery, const char *szValue ) { return Matcher_Match( pszQuery, szValue ); } + void RegisterSharedScriptFunctions() { // @@ -232,13 +658,32 @@ void RegisterSharedScriptFunctions() #endif g_pScriptVM->RegisterInstance( &g_ScriptConvarLookup, "Convars" ); + g_pScriptVM->RegisterInstance( &g_ScriptNetPropManager, "NetProps" ); // Functions unique to Mapbase + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptColorPrint, "printc", "Version of print() which takes a color before the message." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptColorPrintL, "printcl", "Version of printl() which takes a color before the message." ); + #ifndef CLIENT_DLL ScriptRegisterFunction( g_pScriptVM, SpawnEntityFromKeyValues, "Spawns an entity with the keyvalues in a CScriptKeyValues handle." ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDispatchSpawn, "DispatchSpawn", "Spawns an unspawned entity." ); #endif + ScriptRegisterFunction( g_pScriptVM, CreateDamageInfo, "Creates damage info." ); + ScriptRegisterFunction( g_pScriptVM, DestroyDamageInfo, "Destroys damage info." ); + ScriptRegisterFunction( g_pScriptVM, ImpulseScale, "Returns an impulse scale required to push an object." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateExplosiveDamageForce, "CalculateExplosiveDamageForce", "Fill out a damage info handle with a damage force for an explosive." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateBulletDamageForce, "CalculateBulletDamageForce", "Fill out a damage info handle with a damage force for a bullet impact." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateMeleeDamageForce, "CalculateMeleeDamageForce", "Fill out a damage info handle with a damage force for a melee impact." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGuessDamageForce, "GuessDamageForce", "Try and guess the physics force to use." ); + + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceLineComplex, "TraceLineComplex", "Complex version of TraceLine which takes 2 points, an ent to ignore, a trace mask, and a collision group. Returns a handle which can access all trace info." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceHullComplex, "TraceHullComplex", "Takes 2 points, min/max hull bounds, an ent to ignore, a trace mask, and a collision group to trace to a point using a hull. Returns a handle which can access all trace info." ); + + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatcherMatch, "Matcher_Match", "Compares a string to a query using Mapbase's matcher system, supporting wildcards, RS matchers, etc." ); + ScriptRegisterFunction( g_pScriptVM, Matcher_NamesMatch, "Compares a string to a query using Mapbase's matcher system using wildcards only." ); + ScriptRegisterFunction( g_pScriptVM, AppearsToBeANumber, "Checks if the given string appears to be a number." ); + #ifdef CLIENT_DLL VScriptRunScript( "vscript_client", true ); #else diff --git a/sp/src/game/shared/takedamageinfo.cpp b/sp/src/game/shared/takedamageinfo.cpp index e9062d80..269f8043 100644 --- a/sp/src/game/shared/takedamageinfo.cpp +++ b/sp/src/game/shared/takedamageinfo.cpp @@ -31,6 +31,60 @@ BEGIN_SIMPLE_DATADESC( CTakeDamageInfo ) DEFINE_FIELD( m_iDamagedOtherPlayers, FIELD_INTEGER), END_DATADESC() +#ifdef MAPBASE_VSCRIPT +BEGIN_SCRIPTDESC_ROOT( CTakeDamageInfo, "Damage information handler." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetInflictor, "GetInflictor", "Gets the inflictor." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetInflictor, "SetInflictor", "Sets the inflictor." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeapon, "GetWeapon", "Gets the weapon." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetWeapon, "SetWeapon", "Sets the weapon." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttacker, "GetAttacker", "Gets the attacker." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetAttacker, "SetAttacker", "Sets the attacker." ) + + DEFINE_SCRIPTFUNC( GetDamage, "Gets the damage." ) + DEFINE_SCRIPTFUNC( SetDamage, "Sets the damage." ) + DEFINE_SCRIPTFUNC( GetMaxDamage, "Gets the max damage." ) + DEFINE_SCRIPTFUNC( SetMaxDamage, "Sets the max damage." ) + DEFINE_SCRIPTFUNC( ScaleDamage, "Scales the damage." ) + DEFINE_SCRIPTFUNC( AddDamage, "Adds to the damage." ) + DEFINE_SCRIPTFUNC( SubtractDamage, "Removes from the damage." ) + DEFINE_SCRIPTFUNC( GetDamageBonus, "Gets the damage bonus." ) + DEFINE_SCRIPTFUNC( SetDamageBonus, "Sets the damage bonus." ) + + DEFINE_SCRIPTFUNC( GetBaseDamage, "Gets the base damage." ) + DEFINE_SCRIPTFUNC( BaseDamageIsValid, "Checks if the base damage is valid." ) + + DEFINE_SCRIPTFUNC( GetDamageForce, "Gets the damage force." ) + DEFINE_SCRIPTFUNC( SetDamageForce, "Sets the damage force." ) + DEFINE_SCRIPTFUNC( ScaleDamageForce, "Scales the damage force." ) + + DEFINE_SCRIPTFUNC( GetDamagePosition, "Gets the damage position." ) + DEFINE_SCRIPTFUNC( SetDamagePosition, "Sets the damage position." ) + + DEFINE_SCRIPTFUNC( GetReportedPosition, "Gets the reported damage position." ) + DEFINE_SCRIPTFUNC( SetReportedPosition, "Sets the reported damage position." ) + + DEFINE_SCRIPTFUNC( GetDamageType, "Gets the damage type." ) + DEFINE_SCRIPTFUNC( SetDamageType, "Sets the damage type." ) + DEFINE_SCRIPTFUNC( AddDamageType, "Adds to the damage type." ) + DEFINE_SCRIPTFUNC( GetDamageCustom, "Gets the damage custom." ) + DEFINE_SCRIPTFUNC( SetDamageCustom, "Sets the damage custom." ) + DEFINE_SCRIPTFUNC( GetDamageStats, "Gets the damage stats." ) + DEFINE_SCRIPTFUNC( SetDamageStats, "Sets the damage stats." ) + DEFINE_SCRIPTFUNC( IsForceFriendlyFire, "Gets force friendly fire." ) + DEFINE_SCRIPTFUNC( SetForceFriendlyFire, "Sets force friendly fire." ) + + DEFINE_SCRIPTFUNC( GetAmmoType, "Gets the ammo type." ) + DEFINE_SCRIPTFUNC( SetAmmoType, "Sets the ammo type." ) + DEFINE_SCRIPTFUNC( GetAmmoName, "Gets the ammo type name." ) + + DEFINE_SCRIPTFUNC( GetPlayerPenetrationCount, "Gets the player penetration count." ) + DEFINE_SCRIPTFUNC( SetPlayerPenetrationCount, "Sets the player penetration count." ) + + DEFINE_SCRIPTFUNC( GetDamagedOtherPlayers, "Gets whether other players have been damaged." ) + DEFINE_SCRIPTFUNC( SetDamagedOtherPlayers, "Sets whether other players have been damaged." ) +END_SCRIPTDESC(); +#endif + void CTakeDamageInfo::Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iCustomDamage ) { m_hInflictor = pInflictor; @@ -166,6 +220,50 @@ const char *CTakeDamageInfo::GetAmmoName() const return pszAmmoType; } +#ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +HSCRIPT CTakeDamageInfo::ScriptGetInflictor() const +{ + return ToHScript( GetInflictor() ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTakeDamageInfo::ScriptSetInflictor( HSCRIPT pInflictor ) +{ + SetInflictor( ToEnt( pInflictor ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +HSCRIPT CTakeDamageInfo::ScriptGetWeapon() const +{ + return ToHScript( GetWeapon() ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTakeDamageInfo::ScriptSetWeapon( HSCRIPT pWeapon ) +{ + SetWeapon( ToEnt( pWeapon ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +HSCRIPT CTakeDamageInfo::ScriptGetAttacker() const +{ + return ToHScript( GetAttacker() ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CTakeDamageInfo::ScriptSetAttacker( HSCRIPT pAttacker ) +{ + SetAttacker( ToEnt( pAttacker ) ); +} +#endif + // -------------------------------------------------------------------------------------------------- // // MultiDamage // Collects multiple small damages into a single damage diff --git a/sp/src/game/shared/takedamageinfo.h b/sp/src/game/shared/takedamageinfo.h index 702e9322..840432b1 100644 --- a/sp/src/game/shared/takedamageinfo.h +++ b/sp/src/game/shared/takedamageinfo.h @@ -14,6 +14,10 @@ #include "networkvar.h" // todo: change this when DECLARE_CLASS is moved into a better location. +#ifdef MAPBASE_VSCRIPT +#include "vscript/ivscript.h" +#endif + // Used to initialize m_flBaseDamage to something that we know pretty much for sure // hasn't been modified by a user. #define BASEDAMAGE_NOT_SPECIFIED FLT_MAX @@ -102,6 +106,15 @@ public: // For designer debug output. static void DebugGetDamageTypeString(unsigned int DamageType, char *outbuf, int outbuflength ); +#ifdef MAPBASE_VSCRIPT + HSCRIPT ScriptGetInflictor() const; + void ScriptSetInflictor( HSCRIPT pInflictor ); + HSCRIPT ScriptGetWeapon() const; + void ScriptSetWeapon( HSCRIPT pWeapon ); + HSCRIPT ScriptGetAttacker() const; + void ScriptSetAttacker( HSCRIPT pAttacker ); +#endif + //private: void CopyDamageToBaseDamage(); diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index cc6f9c8a..aa5c98f3 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -154,6 +154,13 @@ public: DECLARE_POINTER_HANDLE( HSCRIPT ); #define INVALID_HSCRIPT ((HSCRIPT)-1) +#ifdef MAPBASE_VSCRIPT +template T *HScriptToClass( HSCRIPT hObj ) +{ + return (hObj) ? (T*)g_pScriptVM->GetInstanceValue( hObj, GetScriptDesc( (T*)NULL ) ) : NULL; +} +#endif + //----------------------------------------------------------------------------- // //-----------------------------------------------------------------------------