diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 051eeb2c..660c18b4 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -281,6 +281,20 @@ BEGIN_DATADESC( C_ClientRagdoll ) END_DATADESC() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( C_ClientRagdoll, C_BaseAnimating, "Client-side ragdolls" ) + + DEFINE_SCRIPTFUNC_NAMED( SUB_Remove, "FadeOut", "Fades out the ragdoll and removes it from the client." ) + + // TODO: Proper shared ragdoll funcs? + DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObject, "GetRagdollObject", "Gets the ragdoll object of the specified index." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObjectCount, "GetRagdollObjectCount", "Gets the number of ragdoll objects on this ragdoll." ) + +END_SCRIPTDESC(); + +ScriptHook_t C_BaseAnimating::g_Hook_OnClientRagdoll; +#endif + BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" ) #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC_NAMED( ScriptGetPoseParameter, "GetPoseParameter", "Get the specified pose parameter's value" ) @@ -288,6 +302,14 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si DEFINE_SCRIPTFUNC_NAMED( ScriptSetPoseParameter, "SetPoseParameter", "Set the specified pose parameter to the specified value" ) DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" ) #ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC( LookupAttachment, "Get the named attachement id" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentOrigin, "GetAttachmentOrigin", "Get the attachement id's origin vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentAngles, "GetAttachmentAngles", "Get the attachement id's angles as a p,y,r vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentMatrix, "GetAttachmentMatrix", "Get the attachement id's matrix transform" ) + + DEFINE_SCRIPTFUNC( LookupBone, "Get the named bone id" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoneTransform, "GetBoneTransform", "Get the transform for the specified bone" ) + DEFINE_SCRIPTFUNC( SetBodygroup, "Sets a bodygroup") DEFINE_SCRIPTFUNC( GetBodygroup, "Gets a bodygroup" ) DEFINE_SCRIPTFUNC( GetBodygroupName, "Gets a bodygroup name" ) @@ -302,7 +324,28 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si DEFINE_SCRIPTFUNC( LookupActivity, "Gets the ID of the specified activity name" ) DEFINE_SCRIPTFUNC( GetSequenceName, "Gets the name of the specified sequence index" ) DEFINE_SCRIPTFUNC( GetSequenceActivityName, "Gets the activity name of the specified sequence index" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceMoveDist, "GetSequenceMoveDist", "Gets the move distance of the specified sequence" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceActivity, "GetSequenceActivity", "Gets the activity ID of the specified sequence index" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSelectWeightedSequence, "SelectWeightedSequence", "Selects a sequence for the specified activity ID" ) + + DEFINE_SCRIPTFUNC( GetPlaybackRate, "" ) + DEFINE_SCRIPTFUNC( SetPlaybackRate, "" ) + DEFINE_SCRIPTFUNC( GetCycle, "" ) + DEFINE_SCRIPTFUNC( SetCycle, "" ) + DEFINE_SCRIPTFUNC( GetSkin, "Gets the model's skin" ) + DEFINE_SCRIPTFUNC( SetSkin, "Sets the model's skin" ) + + DEFINE_SCRIPTFUNC( GetForceBone, "Gets the entity's force bone, which is used to determine which bone a ragdoll should apply its force to." ) + DEFINE_SCRIPTFUNC( SetForceBone, "Sets the entity's force bone, which is used to determine which bone a ragdoll should apply its force to." ) + DEFINE_SCRIPTFUNC( GetRagdollForce, "Gets the entity's ragdoll force, which is used to apply velocity to a ragdoll." ) + DEFINE_SCRIPTFUNC( SetRagdollForce, "Sets the entity's ragdoll force, which is used to apply velocity to a ragdoll." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptBecomeRagdollOnClient, "BecomeRagdollOnClient", "" ) + DEFINE_SCRIPTFUNC( IsRagdoll, "" ) + + BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_OnClientRagdoll, "OnClientRagdoll", FIELD_VOID, "Called when this entity turns into a client-side ragdoll." ) + DEFINE_SCRIPTHOOK_PARAM( "ragdoll", FIELD_HSCRIPT ) + END_SCRIPTHOOK() #endif END_SCRIPTDESC(); @@ -666,6 +709,24 @@ void C_ClientRagdoll::Release( void ) BaseClass::Release(); } +#ifdef MAPBASE_VSCRIPT +HSCRIPT C_ClientRagdoll::ScriptGetRagdollObject( int iIndex ) +{ + if (iIndex < 0 || iIndex > m_pRagdoll->RagdollBoneCount()) + { + Warning("%s GetRagdollObject: Index %i not valid (%i objects)\n", GetDebugName(), iIndex, m_pRagdoll->RagdollBoneCount()); + return NULL; + } + + return g_pScriptVM->RegisterInstance( m_pRagdoll->GetElement(iIndex) ); +} + +int C_ClientRagdoll::ScriptGetRagdollObjectCount() +{ + return m_pRagdoll->RagdollBoneCount(); +} +#endif + //----------------------------------------------------------------------------- // Incremented each frame in InvalidateModelBones. Models compare this value to what it // was last time they setup their bones to determine if they need to re-setup their bones. @@ -1429,6 +1490,61 @@ float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping ) } #ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +// Purpose: Returns the world location and world angles of an attachment to vscript caller +// Input : attachment name +// Output : location and angles +//----------------------------------------------------------------------------- +const Vector& C_BaseAnimating::ScriptGetAttachmentOrigin( int iAttachment ) +{ + + static Vector absOrigin; + static QAngle qa; + + C_BaseAnimating::GetAttachment( iAttachment, absOrigin, qa ); + + return absOrigin; +} + +const Vector& C_BaseAnimating::ScriptGetAttachmentAngles( int iAttachment ) +{ + + static Vector absOrigin; + static Vector absAngles; + static QAngle qa; + + C_BaseAnimating::GetAttachment( iAttachment, absOrigin, qa ); + absAngles.x = qa.x; + absAngles.y = qa.y; + absAngles.z = qa.z; + return absAngles; +} + +HSCRIPT C_BaseAnimating::ScriptGetAttachmentMatrix( int iAttachment ) +{ + static matrix3x4_t matrix; + + C_BaseAnimating::GetAttachment( iAttachment, matrix ); + return g_pScriptVM->RegisterInstance( &matrix ); +} + +void C_BaseAnimating::ScriptGetBoneTransform( int iBone, HSCRIPT hTransform ) +{ + if (hTransform == NULL) + return; + + GetBoneTransform( iBone, *HScriptToClass( hTransform ) ); +} + +HSCRIPT C_BaseAnimating::ScriptBecomeRagdollOnClient() +{ + C_BaseAnimating *pRagdoll = BecomeRagdollOnClient(); + if (!pRagdoll) + return NULL; + + return pRagdoll->GetScriptInstance(); +} + float C_BaseAnimating::ScriptGetPoseParameter( const char* szName ) { CStudioHdr* pHdr = GetModelPtr(); @@ -4736,6 +4852,17 @@ C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient() const float boneDt = 0.1f; GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + +#ifdef MAPBASE_VSCRIPT + // Hook for ragdolling + if (m_ScriptScope.IsInitialized() && g_Hook_OnClientRagdoll.CanRunInScope( m_ScriptScope )) + { + // ragdoll + ScriptVariant_t args[] = { ScriptVariant_t( pRagdoll->GetScriptInstance() ) }; + g_Hook_OnClientRagdoll.Call( m_ScriptScope, NULL, args ); + } +#endif + return pRagdoll; } diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index e1426b71..2c240a06 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -454,6 +454,28 @@ public: virtual bool IsViewModel() const; #ifdef MAPBASE_VSCRIPT + const Vector& ScriptGetAttachmentOrigin(int iAttachment); + const Vector& ScriptGetAttachmentAngles(int iAttachment); + HSCRIPT ScriptGetAttachmentMatrix(int iAttachment); + + void ScriptGetBoneTransform( int iBone, HSCRIPT hTransform ); + + int ScriptGetSequenceActivity( int iSequence ) { return GetSequenceActivity( iSequence ); } + float ScriptGetSequenceMoveDist( int iSequence ) { return GetSequenceMoveDist( GetModelPtr(), iSequence ); } + int ScriptSelectWeightedSequence( int activity ) { return SelectWeightedSequence( (Activity)activity ); } + + // For VScript + void SetSkin( int iSkin ) { m_nSkin = iSkin; } + + int GetForceBone() { return m_nForceBone; } + void SetForceBone( int iBone ) { m_nForceBone = iBone; } + const Vector& GetRagdollForce() { return m_vecForce; } + void SetRagdollForce( const Vector &vecForce ) { m_vecForce = vecForce; } + + HSCRIPT ScriptBecomeRagdollOnClient(); + + static ScriptHook_t g_Hook_OnClientRagdoll; + float ScriptGetPoseParameter(const char* szName); #endif void ScriptSetPoseParameter(const char* szName, float fValue); @@ -475,10 +497,6 @@ protected: virtual bool CalcAttachments(); -#ifdef MAPBASE_VSCRIPT - int ScriptGetSequenceActivity( int iSequence ) { return GetSequenceActivity( iSequence ); } -#endif - private: // This method should return true if the bones have changed + SetupBones needs to be called virtual float LastBoneChangedTime() { return FLT_MAX; } @@ -667,6 +685,9 @@ public: C_ClientRagdoll( bool bRestoring = true ); DECLARE_CLASS( C_ClientRagdoll, C_BaseAnimating ); DECLARE_DATADESC(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif // inherited from IPVSNotify virtual void OnPVSStatusChanged( bool bInPVS ); @@ -688,6 +709,11 @@ public: void FadeOut( void ); virtual float LastBoneChangedTime(); +#ifdef MAPBASE_VSCRIPT + HSCRIPT ScriptGetRagdollObject( int iIndex ); + int ScriptGetRagdollObjectCount(); +#endif + bool m_bFadeOut; bool m_bImportant; float m_flEffectTime; diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index 41a32a94..a4a29ea1 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -442,6 +442,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC( ValidateScriptScope, "Ensure that an entity's script scope has been created" ) + DEFINE_SCRIPTFUNC( GetOrCreatePrivateScriptScope, "Create and retrieve the script-side data associated with an entity" ) DEFINE_SCRIPTFUNC( GetScriptScope, "Retrieve the script-side data associated with an entity" ) DEFINE_SCRIPTFUNC( GetHealth, "" ) @@ -456,23 +457,92 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC( GetClassname, "" ) DEFINE_SCRIPTFUNC_NAMED( GetEntityName, "GetName", "" ) + DEFINE_SCRIPTFUNC_NAMED( SetAbsOrigin, "SetOrigin", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" ) + + DEFINE_SCRIPTFUNC( GetLocalOrigin, "GetLocalOrigin" ) + DEFINE_SCRIPTFUNC( SetLocalOrigin, "SetLocalOrigin" ) + DEFINE_SCRIPTFUNC( GetLocalAngles, "GetLocalAngles" ) + DEFINE_SCRIPTFUNC( SetLocalAngles, "SetLocalAngles" ) + DEFINE_SCRIPTFUNC_NAMED( WorldSpaceCenter, "GetCenter", "Get vector to center of object - absolute coords" ) DEFINE_SCRIPTFUNC_NAMED( ScriptEyePosition, "EyePosition", "Get vector to eye position - absolute coords" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptEyeAngles, "EyeAngles", "Get eye pitch, yaw, roll as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( GetAbsAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( SetAbsAngles, "SetAngles", "Set entity pitch, yaw, roll" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMins, "GetBoundingMins", "Get a vector containing min bounds, centered on object" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMaxs, "GetBoundingMaxs", "Get a vector containing max bounds, centered on object" ) + 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( GetWaterLevel, "Get current level of water submergence" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptSetParent, "SetParent", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveParent, "GetMoveParent", "If in hierarchy, retrieves the entity's parent" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetRootMoveParent, "GetRootMoveParent", "If in hierarchy, walks up the hierarchy to find the root parent" ) DEFINE_SCRIPTFUNC_NAMED( ScriptFirstMoveChild, "FirstMoveChild", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptNextMovePeer, "NextMovePeer", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptFollowEntity, "FollowEntity", "Begin following the specified entity. This makes this entity non-solid, parents it to the target entity, and teleports it to the specified entity's origin. The second parameter is whether or not to use bonemerging while following." ) + DEFINE_SCRIPTFUNC( StopFollowingEntity, "Stops following an entity if we're following one." ) + DEFINE_SCRIPTFUNC( IsFollowingEntity, "Returns true if this entity is following another entity." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFollowedEntity, "GetFollowedEntity", "Get the entity we're following." ) + + DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" ) + DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetRenderColorVector", "Get the render color as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetRenderColorR", "Get the render color's R value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetRenderColorG", "Get the render color's G value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorB, "GetRenderColorB", "Get the render color's B value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAlpha, "GetRenderAlpha", "Get the render color's alpha value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorVector, "SetRenderColorVector", "Set the render color as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColor, "SetRenderColor", "Set the render color" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorR, "SetRenderColorR", "Set the render color's R value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetRenderColorG", "Set the render color's G value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetRenderColorB", "Set the render color's B value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetRenderAlpha", "Set the render color's alpha value" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetRenderMode, "GetRenderMode", "Get render mode" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetRenderMode, "SetRenderMode", "Set render mode" ) + DEFINE_SCRIPTFUNC( GetEffects, "Get effects" ) + DEFINE_SCRIPTFUNC( AddEffects, "Add effect(s)" ) + DEFINE_SCRIPTFUNC( RemoveEffects, "Remove effect(s)" ) + DEFINE_SCRIPTFUNC( ClearEffects, "Clear effect(s)" ) + DEFINE_SCRIPTFUNC( SetEffects, "Set effect(s)" ) DEFINE_SCRIPTFUNC( IsEffectActive, "Check if an effect is active" ) + DEFINE_SCRIPTFUNC( GetFlags, "Get flags" ) + DEFINE_SCRIPTFUNC( AddFlag, "Add flag" ) + DEFINE_SCRIPTFUNC( RemoveFlag, "Remove flag" ) + + DEFINE_SCRIPTFUNC( GetEFlags, "Get Eflags" ) + DEFINE_SCRIPTFUNC( AddEFlags, "Add Eflags" ) + DEFINE_SCRIPTFUNC( RemoveEFlags, "Remove Eflags" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveType, "GetMoveType", "Get the move type" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetMoveType, "SetMoveType", "Set the move type" ) + + DEFINE_SCRIPTFUNC( GetCollisionGroup, "Get the collision group" ) + DEFINE_SCRIPTFUNC( SetCollisionGroup, "Set the collision group" ) + + DEFINE_SCRIPTFUNC( GetSolidFlags, "Get solid flags" ) + DEFINE_SCRIPTFUNC( AddSolidFlags, "Add solid flags" ) + DEFINE_SCRIPTFUNC( RemoveSolidFlags, "Remove solid flags" ) + + DEFINE_SCRIPTFUNC( IsPlayer, "Returns true if this entity is a player." ) + DEFINE_SCRIPTFUNC( IsNPC, "Returns true if this entity is a NPC." ) + //DEFINE_SCRIPTFUNC( IsCombatCharacter, "Returns true if this entity is a combat character (player or NPC)." ) + DEFINE_SCRIPTFUNC_NAMED( IsBaseCombatWeapon, "IsWeapon", "Returns true if this entity is a weapon." ) + DEFINE_SCRIPTFUNC( IsWorld, "Returns true if this entity is the world." ) + DEFINE_SCRIPTFUNC_NAMED( GetEntityIndex, "entindex", "" ) #endif + END_SCRIPTDESC(); #ifndef NO_ENTITY_PREDICTION diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index 8cd7fec7..598b88c7 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -266,6 +266,7 @@ public: bool ValidateScriptScope(); bool CallScriptFunction( const char* pFunctionName, ScriptVariant_t* pFunctionReturn ); + HSCRIPT GetOrCreatePrivateScriptScope(); HSCRIPT GetScriptScope() { return m_ScriptScope; } HSCRIPT LookupScriptFunction(const char* pFunctionName); @@ -275,6 +276,9 @@ public: bool RunScript( const char* pScriptText, const char* pDebugFilename = "C_BaseEntity::RunScript" ); #endif + HSCRIPT GetScriptOwnerEntity(); + virtual void SetScriptOwnerEntity(HSCRIPT pOwner); + HSCRIPT GetScriptInstance(); HSCRIPT m_hScriptInstance; @@ -1149,6 +1153,11 @@ public: bool IsFollowingEntity(); CBaseEntity *GetFollowedEntity(); +#ifdef MAPBASE_VSCRIPT + void ScriptFollowEntity( HSCRIPT hBaseEntity, bool bBoneMerge ); + HSCRIPT ScriptGetFollowedEntity(); +#endif + // For shadows rendering the correct body + sequence... virtual int GetBody() { return 0; } virtual int GetSkin() { return 0; } @@ -1170,15 +1179,39 @@ public: void VScriptPrecacheScriptSound(const char* soundname); const Vector& ScriptEyePosition(void) { static Vector vec; vec = EyePosition(); return vec; } - const Vector& ScriptGetAngles(void) { static Vector vec; QAngle qa = GetAbsAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; } + const QAngle& ScriptEyeAngles(void) { static QAngle ang; ang = EyeAngles(); return ang; } + void ScriptSetForward( const Vector& v ) { QAngle angles; VectorAngles( v, angles ); SetAbsAngles( angles ); } const Vector& ScriptGetBoundingMins( void ) { return m_Collision.OBBMins(); } const Vector& ScriptGetBoundingMaxs( void ) { return m_Collision.OBBMaxs(); } + HSCRIPT ScriptEntityToWorldTransform( void ); + + HSCRIPT ScriptGetPhysicsObject( void ); + + void ScriptSetParent( HSCRIPT hParent, const char *szAttachment ); HSCRIPT ScriptGetMoveParent( void ); HSCRIPT ScriptGetRootMoveParent(); HSCRIPT ScriptFirstMoveChild( void ); HSCRIPT ScriptNextMovePeer( void ); + + const Vector& ScriptGetColorVector(); + int ScriptGetColorR() { return m_clrRender.GetR(); } + int ScriptGetColorG() { return m_clrRender.GetG(); } + int ScriptGetColorB() { return m_clrRender.GetB(); } + int ScriptGetAlpha() { return m_clrRender.GetA(); } + void ScriptSetColorVector( const Vector& vecColor ); + void ScriptSetColor( int r, int g, int b ); + void ScriptSetColorR( int iVal ) { SetRenderColorR( iVal ); } + void ScriptSetColorG( int iVal ) { SetRenderColorG( iVal ); } + void ScriptSetColorB( int iVal ) { SetRenderColorB( iVal ); } + void ScriptSetAlpha( int iVal ) { SetRenderColorA( iVal ); } + + int ScriptGetRenderMode() { return GetRenderMode(); } + void ScriptSetRenderMode( int nRenderMode ) { SetRenderMode( (RenderMode_t)nRenderMode ); } + + int ScriptGetMoveType() { return GetMoveType(); } + void ScriptSetMoveType( int iMoveType ) { SetMoveType( (MoveType_t)iMoveType ); } #endif // Stubs on client diff --git a/sp/src/game/client/c_props.cpp b/sp/src/game/client/c_props.cpp index 07f5710d..7981fe2c 100644 --- a/sp/src/game/client/c_props.cpp +++ b/sp/src/game/client/c_props.cpp @@ -24,6 +24,11 @@ BEGIN_NETWORK_TABLE( CDynamicProp, DT_DynamicProp ) RecvPropBool(RECVINFO(m_bUseHitboxesForRenderBox)), END_NETWORK_TABLE() +#ifdef MAPBASE_VSCRIPT +// Allows client-side VScript to create dynamic props via CreateProp() +LINK_ENTITY_TO_CLASS( prop_dynamic, C_DynamicProp ); +#endif + C_DynamicProp::C_DynamicProp( void ) { m_iCachedFrameCount = -1; diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 3c2eb00f..243324f1 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -35,6 +35,7 @@ $Project $Folder "Mapbase" { $File "$SRCDIR\game\shared\mapbase\mapbase_shared.cpp" + $File "$SRCDIR\game\shared\mapbase\mapbase_usermessages.cpp" $File "$SRCDIR\game\shared\mapbase\mapbase_rpc.cpp" $File "$SRCDIR\game\shared\mapbase\mapbase_game_log.cpp" $File "$SRCDIR\game\shared\mapbase\MapEdit.cpp" @@ -50,6 +51,7 @@ $Project $File "$SRCDIR\game\shared\mapbase\vscript_consts_weapons.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.h" [$MAPBASE_VSCRIPT] + $File "$SRCDIR\game\shared\mapbase\logic_script_client.cpp" [$MAPBASE_VSCRIPT] $File "mapbase\c_func_clientclip.cpp" $File "mapbase\c_func_fake_worldportal.cpp" diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index dc53cc8c..937ef94a 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -469,6 +469,33 @@ static bool ScriptScreenTransform( const Vector &pos, HSCRIPT hArray ) } return false; } + +// Creates a client-side prop +HSCRIPT CreateProp( const char *pszEntityName, const Vector &vOrigin, const char *pszModelName, int iAnim ) +{ + C_BaseAnimating *pBaseEntity = (C_BaseAnimating *)CreateEntityByName( pszEntityName ); + if (!pBaseEntity) + return NULL; + + pBaseEntity->SetAbsOrigin( vOrigin ); + pBaseEntity->SetModelName( pszModelName ); + if (!pBaseEntity->InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY )) + { + Warning("Can't initialize %s as client entity\n", pszEntityName); + return NULL; + } + + pBaseEntity->SetPlaybackRate( 1.0f ); + + int iSequence = pBaseEntity->SelectWeightedSequence( (Activity)iAnim ); + + if ( iSequence != -1 ) + { + pBaseEntity->SetSequence( iSequence ); + } + + return ToHScript( pBaseEntity ); +} #endif bool VScriptClientInit() @@ -548,6 +575,8 @@ bool VScriptClientInit() ScriptRegisterFunction( g_pScriptVM, ScreenHeight, "Height of the screen in pixels" ); ScriptRegisterFunction( g_pScriptVM, IsWindowedMode, "" ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenTransform, "ScreenTransform", "Get the x & y positions of a world position in screen space. Returns true if it's onscreen" ); + + ScriptRegisterFunction( g_pScriptVM, CreateProp, "Create an animating prop" ); #endif diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 66940c08..59b9eae8 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -623,18 +623,6 @@ CBaseEntity *CBaseEntity::GetFollowedEntity() return GetMoveParent(); } -#ifdef MAPBASE_VSCRIPT -void CBaseEntity::ScriptFollowEntity( HSCRIPT hBaseEntity, bool bBoneMerge ) -{ - FollowEntity( ToEnt( hBaseEntity ), bBoneMerge ); -} - -HSCRIPT CBaseEntity::ScriptGetFollowedEntity() -{ - return ToHScript( GetFollowedEntity() ); -} -#endif - void CBaseEntity::SetClassname( const char *className ) { m_iClassname = AllocPooledString( className ); @@ -2360,6 +2348,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetRenderColorB", "Set the render color's B value" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetRenderAlpha", "Set the render color's alpha value" ) + // LEGACY DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetColorVector", SCRIPT_HIDE ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetColorR", SCRIPT_HIDE ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetColorG", SCRIPT_HIDE ) @@ -2370,6 +2359,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetColorG", SCRIPT_HIDE ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetColorB", SCRIPT_HIDE ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetAlpha", SCRIPT_HIDE ) + // END LEGACY DEFINE_SCRIPTFUNC_NAMED( ScriptGetRenderMode, "GetRenderMode", "Get render mode" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetRenderMode, "SetRenderMode", "Set render mode" ) @@ -8849,51 +8839,6 @@ HSCRIPT CBaseEntity::GetScriptScope() return m_ScriptScope; } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -#ifdef MAPBASE_VSCRIPT -HSCRIPT CBaseEntity::GetOrCreatePrivateScriptScope() -{ - ValidateScriptScope(); - return m_ScriptScope; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CBaseEntity::ScriptSetParent(HSCRIPT hParent, const char *szAttachment) -{ - CBaseEntity *pParent = ToEnt(hParent); - if ( !pParent ) - { - SetParent(NULL); - return; - } - - // if an attachment is specified, the parent needs to be CBaseAnimating - if ( szAttachment && szAttachment[0] != '\0' ) - { - CBaseAnimating *pAnimating = pParent->GetBaseAnimating(); - if ( !pAnimating ) - { - Warning("ERROR: Tried to set parent for entity %s (%s), but its parent has no model.\n", GetClassname(), GetDebugName()); - return; - } - - int iAttachment = pAnimating->LookupAttachment(szAttachment); - if ( iAttachment <= 0 ) - { - Warning("ERROR: Tried to set parent for entity %s (%s), but it has no attachment named %s.\n", GetClassname(), GetDebugName(), szAttachment); - return; - } - - SetParent(pParent, iAttachment); - SetMoveType(MOVETYPE_NONE); - return; - } - - SetParent(pParent); -} -#endif //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- HSCRIPT CBaseEntity::ScriptGetMoveParent(void) @@ -10143,6 +10088,7 @@ void CBaseEntity::RunOnPostSpawnScripts(void) } } +#ifndef MAPBASE_VSCRIPT // This is shared now HSCRIPT CBaseEntity::GetScriptOwnerEntity() { return ToHScript(GetOwnerEntity()); @@ -10152,6 +10098,7 @@ void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner) { SetOwnerEntity(ToEnt(pOwner)); } +#endif //----------------------------------------------------------------------------- // VScript access to model's key values @@ -10318,46 +10265,6 @@ const char *CBaseEntity::ScriptGetKeyValue( const char *pszKeyName ) return szValue; } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -const Vector& CBaseEntity::ScriptGetColorVector() -{ - static Vector vecColor; - vecColor.Init( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB() ); - return vecColor; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CBaseEntity::ScriptSetColorVector( const Vector& vecColor ) -{ - SetRenderColor( vecColor.x, vecColor.y, vecColor.z ); -} - -void CBaseEntity::ScriptSetColor( int r, int g, int b ) -{ - SetRenderColor( r, g, b ); -} - -//----------------------------------------------------------------------------- -// Vscript: Gets the entity matrix transform -//----------------------------------------------------------------------------- -HSCRIPT CBaseEntity::ScriptEntityToWorldTransform( void ) -{ - return g_pScriptVM->RegisterInstance( &EntityToWorldTransform() ); -} - -//----------------------------------------------------------------------------- -// Vscript: Gets the entity's physics object if it has one -//----------------------------------------------------------------------------- -HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) -{ - if (VPhysicsGetObject()) - return g_pScriptVM->RegisterInstance( VPhysicsGetObject() ); - else - return NULL; -} - //----------------------------------------------------------------------------- // Vscript: Dispatch an interaction to the entity //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index 8dbd3844..f417175f 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -169,6 +169,7 @@ BEGIN_ENT_SCRIPTDESC( CRagdollProp, CBaseAnimating, "Ragdoll physics prop." ) DEFINE_SCRIPTFUNC( SetSourceClassName, "Sets the ragdoll's source classname." ) DEFINE_SCRIPTFUNC( HasPhysgunInteraction, "Checks if the ragdoll has the specified interaction." ) + // TODO: Proper shared ragdoll funcs? DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObject, "GetRagdollObject", "Gets the ragdoll object of the specified index." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObjectCount, "GetRagdollObjectCount", "Gets the number of ragdoll objects on this ragdoll." ) diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index 40581e0f..37146238 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -31,6 +31,7 @@ $Project $Folder "Mapbase" { $File "$SRCDIR\game\shared\mapbase\mapbase_shared.cpp" + $File "$SRCDIR\game\shared\mapbase\mapbase_usermessages.cpp" $File "$SRCDIR\game\shared\mapbase\mapbase_rpc.cpp" $File "$SRCDIR\game\shared\mapbase\mapbase_game_log.cpp" $File "$SRCDIR\game\shared\mapbase\MapEdit.cpp" @@ -46,6 +47,7 @@ $Project $File "$SRCDIR\game\shared\mapbase\vscript_consts_weapons.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.h" [$MAPBASE_VSCRIPT] + $File "$SRCDIR\game\shared\mapbase\logic_script_client.cpp" [$MAPBASE_VSCRIPT] $File "mapbase\ai_grenade.cpp" $File "mapbase\ai_grenade.h" diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index 3b656b7a..f07f3775 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2418,6 +2418,18 @@ void CBaseEntity::FollowEntity( CBaseEntity *pBaseEntity, bool bBoneMerge ) } } +#ifdef MAPBASE_VSCRIPT +void CBaseEntity::ScriptFollowEntity( HSCRIPT hBaseEntity, bool bBoneMerge ) +{ + FollowEntity( ToEnt( hBaseEntity ), bBoneMerge ); +} + +HSCRIPT CBaseEntity::ScriptGetFollowedEntity() +{ + return ToHScript( GetFollowedEntity() ); +} +#endif + void CBaseEntity::SetEffectEntity( CBaseEntity *pEffectEnt ) { if ( m_hEffectEntity.Get() != pEffectEnt ) @@ -2607,3 +2619,97 @@ bool CBaseEntity::IsToolRecording() const #endif } #endif + +#ifdef MAPBASE_VSCRIPT +HSCRIPT CBaseEntity::GetOrCreatePrivateScriptScope() +{ + ValidateScriptScope(); + return m_ScriptScope; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetParent(HSCRIPT hParent, const char *szAttachment) +{ + CBaseEntity *pParent = ToEnt(hParent); + if ( !pParent ) + { + SetParent(NULL); + return; + } + + // if an attachment is specified, the parent needs to be CBaseAnimating + if ( szAttachment && szAttachment[0] != '\0' ) + { + CBaseAnimating *pAnimating = pParent->GetBaseAnimating(); + if ( !pAnimating ) + { + Warning("ERROR: Tried to set parent for entity %s (%s), but its parent has no model.\n", GetClassname(), GetDebugName()); + return; + } + + int iAttachment = pAnimating->LookupAttachment(szAttachment); + if ( iAttachment <= 0 ) + { + Warning("ERROR: Tried to set parent for entity %s (%s), but it has no attachment named %s.\n", GetClassname(), GetDebugName(), szAttachment); + return; + } + + SetParent(pParent, iAttachment); + SetMoveType(MOVETYPE_NONE); + return; + } + + SetParent(pParent); +} + +HSCRIPT CBaseEntity::GetScriptOwnerEntity() +{ + return ToHScript(GetOwnerEntity()); +} + +void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner) +{ + SetOwnerEntity(ToEnt(pOwner)); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const Vector& CBaseEntity::ScriptGetColorVector() +{ + static Vector vecColor; + vecColor.Init( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB() ); + return vecColor; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetColorVector( const Vector& vecColor ) +{ + SetRenderColor( vecColor.x, vecColor.y, vecColor.z ); +} + +void CBaseEntity::ScriptSetColor( int r, int g, int b ) +{ + SetRenderColor( r, g, b ); +} + +//----------------------------------------------------------------------------- +// Vscript: Gets the entity matrix transform +//----------------------------------------------------------------------------- +HSCRIPT CBaseEntity::ScriptEntityToWorldTransform( void ) +{ + return g_pScriptVM->RegisterInstance( &EntityToWorldTransform() ); +} + +//----------------------------------------------------------------------------- +// Vscript: Gets the entity's physics object if it has one +//----------------------------------------------------------------------------- +HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) +{ + if (VPhysicsGetObject()) + return g_pScriptVM->RegisterInstance( VPhysicsGetObject() ); + else + return NULL; +} +#endif diff --git a/sp/src/game/shared/mapbase/logic_script_client.cpp b/sp/src/game/shared/mapbase/logic_script_client.cpp new file mode 100644 index 00000000..f7220eb8 --- /dev/null +++ b/sp/src/game/shared/mapbase/logic_script_client.cpp @@ -0,0 +1,232 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Custom client-side equivalent of logic_script. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "vscript_shared.h" +#include "tier1/fmtstr.h" + +#ifdef CLIENT_DLL +ConVar cl_script_think_interval( "cl_script_think_interval", "0.1" ); +#endif + +//----------------------------------------------------------------------------- +// Purpose: An entity that acts as a container for client-side game scripts. +//----------------------------------------------------------------------------- + +#define MAX_SCRIPT_GROUP_CLIENT 8 + +class CLogicScriptClient : public CBaseEntity +{ +public: + DECLARE_CLASS( CLogicScriptClient, CBaseEntity ); + DECLARE_DATADESC(); + DECLARE_NETWORKCLASS(); + +#ifdef CLIENT_DLL + void OnDataChanged( DataUpdateType_t type ) + { + BaseClass::OnDataChanged( type ); + + if ( !m_ScriptScope.IsInitialized() ) + { + RunVScripts(); + } + } +#else + int UpdateTransmitState() { return SetTransmitState( FL_EDICT_ALWAYS ); } +#endif + + bool KeyValue( const char *szKeyName, const char *szValue ) + { + if ( FStrEq( szKeyName, "vscripts" ) ) + { + Q_strcpy( m_iszClientScripts.GetForModify(), szValue ); + } + + return BaseClass::KeyValue( szKeyName, szValue ); + } + + void RunVScripts() + { +#ifdef CLIENT_DLL + if (m_iszClientScripts == NULL_STRING) + { + CGMsg( 0, CON_GROUP_VSCRIPT, "%s has no client scripts", GetDebugName() ); + return; + } + + if (g_pScriptVM == NULL) + { + return; + } + + ValidateScriptScope(); + + // All functions we want to have call chained instead of overwritten + // by other scripts in this entities list. + static const char* sCallChainFunctions[] = + { + "OnPostSpawn", + "Precache" + }; + + ScriptLanguage_t language = g_pScriptVM->GetLanguage(); + + // Make a call chainer for each in this entities scope + for (int j = 0; j < ARRAYSIZE( sCallChainFunctions ); ++j) + { + + if (language == SL_PYTHON) + { + // UNDONE - handle call chaining in python + ; + } + else if (language == SL_SQUIRREL) + { + //TODO: For perf, this should be precompiled and the %s should be passed as a parameter + HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript( CFmtStr( "%sCallChain <- CSimpleCallChainer(\"%s\", self.GetScriptScope(), true)", sCallChainFunctions[j], sCallChainFunctions[j] ) ); + g_pScriptVM->Run( hCreateChainScript, (HSCRIPT)m_ScriptScope ); + } + } + + char szScriptsList[255]; + Q_strcpy( szScriptsList, m_iszClientScripts.Get() ); + CUtlStringList szScripts; + + V_SplitString( szScriptsList, " ", szScripts ); + + for (int i = 0; i < szScripts.Count(); i++) + { + CGMsg( 0, CON_GROUP_VSCRIPT, "%s executing script: %s\n", GetDebugName(), szScripts[i] ); + + RunScriptFile( szScripts[i], IsWorld() ); + + for (int j = 0; j < ARRAYSIZE( sCallChainFunctions ); ++j) + { + if (language == SL_PYTHON) + { + // UNDONE - handle call chaining in python + ; + } + else if (language == SL_SQUIRREL) + { + //TODO: For perf, this should be precompiled and the %s should be passed as a parameter. + HSCRIPT hRunPostScriptExecute = g_pScriptVM->CompileScript( CFmtStr( "%sCallChain.PostScriptExecute()", sCallChainFunctions[j] ) ); + g_pScriptVM->Run( hRunPostScriptExecute, (HSCRIPT)m_ScriptScope ); + } + } + } + + if (m_bClientThink) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +#else + // Avoids issues from having m_iszVScripts set without actually having a script scope + ValidateScriptScope(); + + if (m_bRunOnServer) + { + BaseClass::RunVScripts(); + } +#endif + } + +#ifdef CLIENT_DLL + void ClientThink() + { + ScriptVariant_t varThinkRetVal; + if (CallScriptFunction("ClientThink", &varThinkRetVal)) + { + float flThinkFrequency = 0.0f; + if (!varThinkRetVal.AssignTo(&flThinkFrequency)) + { + // use default think interval if script think function doesn't provide one + flThinkFrequency = cl_script_think_interval.GetFloat(); + } + + if (flThinkFrequency == CLIENT_THINK_ALWAYS) + SetNextClientThink( CLIENT_THINK_ALWAYS ); + else + SetNextClientThink( gpGlobals->curtime + flThinkFrequency ); + } + else + { + DevWarning("%s FAILED to call client script think function!\n", GetDebugName()); + } + + BaseClass::ClientThink(); + } +#else + void InputCallScriptFunctionClient( inputdata_t &inputdata ) + { + // TODO: Support for specific players? + CBroadcastRecipientFilter filter; + filter.MakeReliable(); + + const char *pszFunction = inputdata.value.String(); + if (strlen( pszFunction ) > 64) + { + Msg("%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, strlen(pszFunction)); + return; + } + + UserMessageBegin( filter, "CallClientScriptFunction" ); + WRITE_STRING( pszFunction ); // function + WRITE_SHORT( entindex() ); // entity + MessageEnd(); + } +#endif + + //CNetworkArray( string_t, m_iszGroupMembers, MAX_SCRIPT_GROUP_CLIENT ); + CNetworkString( m_iszClientScripts, 128 ); + CNetworkVar( bool, m_bClientThink ); + +#ifndef CLIENT_DLL + bool m_bRunOnServer; +#endif +}; + +LINK_ENTITY_TO_CLASS( logic_script_client, CLogicScriptClient ); + +BEGIN_DATADESC( CLogicScriptClient ) + + // TODO: Does this need to be saved? + //DEFINE_AUTO_ARRAY( m_iszClientScripts, FIELD_CHARACTER ), + + //DEFINE_KEYFIELD( m_iszGroupMembers[0], FIELD_STRING, "Group00"), + //DEFINE_KEYFIELD( m_iszGroupMembers[1], FIELD_STRING, "Group01"), + //DEFINE_KEYFIELD( m_iszGroupMembers[2], FIELD_STRING, "Group02"), + //DEFINE_KEYFIELD( m_iszGroupMembers[3], FIELD_STRING, "Group03"), + //DEFINE_KEYFIELD( m_iszGroupMembers[4], FIELD_STRING, "Group04"), + //DEFINE_KEYFIELD( m_iszGroupMembers[5], FIELD_STRING, "Group05"), + //DEFINE_KEYFIELD( m_iszGroupMembers[6], FIELD_STRING, "Group06"), + //DEFINE_KEYFIELD( m_iszGroupMembers[7], FIELD_STRING, "Group07"), + + DEFINE_KEYFIELD( m_bClientThink, FIELD_BOOLEAN, "ClientThink" ), + +#ifndef CLIENT_DLL + DEFINE_KEYFIELD( m_bRunOnServer, FIELD_BOOLEAN, "RunOnServer" ), + + DEFINE_INPUTFUNC( FIELD_STRING, "CallScriptFunctionClient", InputCallScriptFunctionClient ), +#endif + +END_DATADESC() + +IMPLEMENT_NETWORKCLASS_DT( CLogicScriptClient, DT_LogicScriptClient ) + +#ifdef CLIENT_DLL + //RecvPropArray( RecvPropString( RECVINFO( m_iszGroupMembers[0] ) ), m_iszGroupMembers ), + RecvPropString( RECVINFO( m_iszClientScripts ) ), + RecvPropBool( RECVINFO( m_bClientThink ) ), +#else + //SendPropArray( SendPropStringT( SENDINFO_ARRAY( m_iszGroupMembers ) ), m_iszGroupMembers ), + SendPropString( SENDINFO( m_iszClientScripts ) ), + SendPropBool( SENDINFO( m_bClientThink ) ), +#endif + +END_NETWORK_TABLE() diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 2763b457..880e851b 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -16,10 +16,12 @@ #include "saverestore_utlvector.h" #include "props_shared.h" #include "utlbuffer.h" +#include "usermessages.h" #ifdef CLIENT_DLL #include "hud_closecaption.h" #include "panelmetaclassmgr.h" #include "c_soundscape.h" +#include "hud_macros.h" #else #include "soundscape_system.h" #include "AI_ResponseSystem.h" diff --git a/sp/src/game/shared/mapbase/mapbase_usermessages.cpp b/sp/src/game/shared/mapbase/mapbase_usermessages.cpp new file mode 100644 index 00000000..6cbe9949 --- /dev/null +++ b/sp/src/game/shared/mapbase/mapbase_usermessages.cpp @@ -0,0 +1,64 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Mapbase-specific user messages. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "usermessages.h" +#ifdef CLIENT_DLL +#include "hud_macros.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifdef CLIENT_DLL +void __MsgFunc_CallClientScriptFunction( bf_read &msg ) +{ + char szFunction[64]; + if (!msg.ReadString( szFunction, sizeof( szFunction ) )) + { + CGMsg( 0, CON_GROUP_VSCRIPT, "Unable to read function string\n" ); + } + + int idx = msg.ReadByte(); + C_BaseEntity *pEntity = CBaseEntity::Instance( idx ); + + if (pEntity) + { + if (pEntity->m_ScriptScope.IsInitialized()) + { + //CGMsg( 0, CON_GROUP_VSCRIPT, "%s calling function \"%s\"\n", pEntity->GetDebugName(), szFunction ); + pEntity->CallScriptFunction( szFunction, NULL ); + } + else + { + CGMsg( 0, CON_GROUP_VSCRIPT, "%s scope not initialized\n", pEntity->GetDebugName() ); + } + } + else + { + CGMsg( 0, CON_GROUP_VSCRIPT, "Clientside entity not found for script function (index %i)\n", idx ); + } +} + +void HookMapbaseUserMessages( void ) +{ + // VScript + HOOK_MESSAGE( CallClientScriptFunction ); +} +#endif + +void RegisterMapbaseUserMessages( void ) +{ + // VScript + usermessages->Register( "CallClientScriptFunction", -1 ); + +#ifdef CLIENT_DLL + // TODO: Better placement? + HookMapbaseUserMessages(); +#endif +} diff --git a/sp/src/game/shared/usermessages.cpp b/sp/src/game/shared/usermessages.cpp index cf1beae3..6b3ad681 100644 --- a/sp/src/game/shared/usermessages.cpp +++ b/sp/src/game/shared/usermessages.cpp @@ -13,6 +13,10 @@ void RegisterUserMessages( void ); +#ifdef MAPBASE +void RegisterMapbaseUserMessages( void ); +#endif + //----------------------------------------------------------------------------- // Purpose: Force registration on .dll load // FIXME: Should this be a client/server system? @@ -21,6 +25,11 @@ CUserMessages::CUserMessages() { // Game specific registration function; RegisterUserMessages(); + +#ifdef MAPBASE + // Mapbase registration function; + RegisterMapbaseUserMessages(); +#endif } CUserMessages::~CUserMessages()