From 0fb0a3319cd7ae3d1be8ed11225bd0b0203d6686 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 28 Jun 2021 23:55:42 -0500 Subject: [PATCH] Added misc. new VScript hooks/constants and the code required to implement them --- sp/src/game/server/basecombatcharacter.cpp | 50 +++++++++++++++++++ sp/src/game/server/basecombatcharacter.h | 3 ++ sp/src/game/server/baseentity.cpp | 22 ++++++++ sp/src/game/server/baseentity.h | 3 +- sp/src/game/server/hl2/npc_alyx_episodic.cpp | 7 +++ .../game/server/hl2/npc_playercompanion.cpp | 2 + sp/src/game/server/hl2/proto_sniper.cpp | 2 + .../shared/mapbase/vscript_consts_shared.cpp | 6 +++ sp/src/vscript/vscript_bindings_base.cpp | 2 + 9 files changed, 96 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 6c59d88a..08d119dc 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -151,6 +151,9 @@ BEGIN_DATADESC( CBaseCombatCharacter ) END_DATADESC() #ifdef MAPBASE_VSCRIPT +ScriptHook_t CBaseCombatCharacter::g_Hook_RelationshipType; +ScriptHook_t CBaseCombatCharacter::g_Hook_RelationshipPriority; + BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by players and NPCs." ) DEFINE_SCRIPTFUNC_NAMED( GetScriptActiveWeapon, "GetActiveWeapon", "Get the character's active weapon entity." ) @@ -192,6 +195,19 @@ 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." ) + // + // Hooks + // + BEGIN_SCRIPTHOOK( CBaseCombatCharacter::g_Hook_RelationshipType, "RelationshipType", FIELD_INTEGER, "Called when a character's relationship to another entity is requested. Returning a disposition will make the game use that disposition instead of the default relationship. (note: 'default' in this case includes overrides from ai_relationship/SetRelationship)" ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + DEFINE_SCRIPTHOOK_PARAM( "def", FIELD_INTEGER ) + END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( CBaseCombatCharacter::g_Hook_RelationshipPriority, "RelationshipPriority", FIELD_INTEGER, "Called when a character's relationship priority for another entity is requested. Returning a number will make the game use that priority instead of the default priority. (note: 'default' in this case includes overrides from ai_relationship/SetRelationship)" ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + DEFINE_SCRIPTHOOK_PARAM( "def", FIELD_INTEGER ) + END_SCRIPTHOOK() + END_SCRIPTDESC(); #endif @@ -3283,7 +3299,24 @@ Relationship_t *CBaseCombatCharacter::FindEntityRelationship( CBaseEntity *pTarg Disposition_t CBaseCombatCharacter::IRelationType ( CBaseEntity *pTarget ) { if ( pTarget ) + { +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_RelationshipType.CanRunInScope( m_ScriptScope )) + { + // entity, default + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ScriptVariant_t( pTarget->GetScriptInstance() ), FindEntityRelationship( pTarget )->disposition }; + if (g_Hook_RelationshipType.Call( m_ScriptScope, &functionReturn, args ) && (functionReturn.m_type == FIELD_INTEGER && functionReturn.m_int != D_ER)) + { + // Use the disposition returned by the script + return (Disposition_t)functionReturn.m_int; + } + } +#endif + return FindEntityRelationship( pTarget )->disposition; + } + return D_NU; } @@ -3295,7 +3328,24 @@ Disposition_t CBaseCombatCharacter::IRelationType ( CBaseEntity *pTarget ) int CBaseCombatCharacter::IRelationPriority( CBaseEntity *pTarget ) { if ( pTarget ) + { +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_RelationshipPriority.CanRunInScope( m_ScriptScope )) + { + // entity, default + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ScriptVariant_t( pTarget->GetScriptInstance() ), FindEntityRelationship( pTarget )->priority }; + if (g_Hook_RelationshipPriority.Call( m_ScriptScope, &functionReturn, args ) && functionReturn.m_type == FIELD_INTEGER) + { + // Use the priority returned by the script + return functionReturn.m_int; + } + } +#endif + return FindEntityRelationship( pTarget )->priority; + } + return 0; } diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index 6d971ca3..d2d76394 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -445,6 +445,9 @@ public: bool ScriptEntInAimCone( HSCRIPT pEntity ) { return FInAimCone( ToEnt( pEntity ) ); } const Vector& ScriptBodyAngles( void ) { static Vector vec; QAngle qa = BodyAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; } + + static ScriptHook_t g_Hook_RelationshipType; + static ScriptHook_t g_Hook_RelationshipPriority; #endif // Interactions diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 8492f299..0a964058 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -1758,6 +1758,22 @@ void CBaseEntity::SendOnKilledGameEvent( const CTakeDamageInfo &info ) } } +void CBaseEntity::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) +{ +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_OnKilledOther.CanRunInScope( m_ScriptScope )) + { + HSCRIPT hInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); + + // victim, info + ScriptVariant_t args[] = { ScriptVariant_t( pVictim->GetScriptInstance() ), ScriptVariant_t( hInfo ) }; + g_Hook_OnKilledOther.Call( m_ScriptScope, NULL, args ); + + g_pScriptVM->RemoveInstance( hInfo ); + } +#endif +} + bool CBaseEntity::HasTarget( string_t targetname ) { @@ -2196,6 +2212,7 @@ ScriptHook_t CBaseEntity::g_Hook_UpdateOnRemove; ScriptHook_t CBaseEntity::g_Hook_VPhysicsCollision; ScriptHook_t CBaseEntity::g_Hook_FireBullets; ScriptHook_t CBaseEntity::g_Hook_OnDeath; +ScriptHook_t CBaseEntity::g_Hook_OnKilledOther; ScriptHook_t CBaseEntity::g_Hook_HandleInteraction; #endif @@ -2462,6 +2479,11 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTHOOK_PARAM( "info", FIELD_HSCRIPT ) END_SCRIPTHOOK() + BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_OnKilledOther, "OnKilledOther", FIELD_VOID, "Called when the entity kills another entity." ) + DEFINE_SCRIPTHOOK_PARAM( "victim", FIELD_HSCRIPT ) + DEFINE_SCRIPTHOOK_PARAM( "info", FIELD_HSCRIPT ) + END_SCRIPTHOOK() + BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_HandleInteraction, "HandleInteraction", FIELD_BOOLEAN, "Called for internal game interactions. See the g_interaction set of constants for more information. Returning true or false will return that value without falling to any internal handling. Returning nothing will allow the interaction to fall to any internal handling." ) DEFINE_SCRIPTHOOK_PARAM( "interaction", FIELD_INTEGER ) //DEFINE_SCRIPTHOOK_PARAM( "data", FIELD_VARIANT ) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index e3388e87..8577749d 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1093,7 +1093,7 @@ public: void SendOnKilledGameEvent( const CTakeDamageInfo &info ); // Notifier that I've killed some other entity. (called from Victim's Event_Killed). - virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) { return; } + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); // UNDONE: Make this data? virtual int BloodColor( void ); @@ -2151,6 +2151,7 @@ public: static ScriptHook_t g_Hook_VPhysicsCollision; static ScriptHook_t g_Hook_FireBullets; static ScriptHook_t g_Hook_OnDeath; + static ScriptHook_t g_Hook_OnKilledOther; static ScriptHook_t g_Hook_HandleInteraction; #endif diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.cpp b/sp/src/game/server/hl2/npc_alyx_episodic.cpp index 19616e10..42c2eb3f 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.cpp +++ b/sp/src/game/server/hl2/npc_alyx_episodic.cpp @@ -1069,6 +1069,13 @@ void CNPC_Alyx::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo & pMemory->timeFirstSeen = gpGlobals->curtime - 10.0f; } } + +#ifdef MAPBASE + // This call has a side effect of causing Alyx to speak a regular companion TLK_ENEMY_DEAD, which may conflict with the TLK_ALYX_ENEMY_DEAD + // further up, but this is fine because concepts are protected against interrupting each other and Alyx may even be overridden + // to use TLK_ENEMY_DEAD instead, which is used by other NPCs and appends more modifiers. + BaseClass::Event_KilledOther( pVictim, info ); +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index b6aa5062..8eec2e6d 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -4183,6 +4183,8 @@ void CNPC_PlayerCompanion::OnPlayerKilledOther( CBaseEntity *pVictim, const CTak //----------------------------------------------------------------------------- void CNPC_PlayerCompanion::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) { + BaseClass::Event_KilledOther( pVictim, info ); + if ( pVictim ) { if (pVictim->IsPlayer() || (pVictim->IsNPC() && diff --git a/sp/src/game/server/hl2/proto_sniper.cpp b/sp/src/game/server/hl2/proto_sniper.cpp index 61460130..64f11d2a 100644 --- a/sp/src/game/server/hl2/proto_sniper.cpp +++ b/sp/src/game/server/hl2/proto_sniper.cpp @@ -1519,6 +1519,8 @@ void CProtoSniper::Event_Killed( const CTakeDamageInfo &info ) void CProtoSniper::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) { #ifdef MAPBASE + BaseClass::Event_KilledOther( pVictim, info ); + if (pVictim == GetEnemy()) SetCondition(COND_SNIPER_KILLED_ENEMY); #endif diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index dd14ddaf..db694201 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -509,6 +509,12 @@ void RegisterSharedScriptConstants() ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_WALK_TO_MARK, "SCRIPT_WALK_TO_MARK", "Walking to the scripted sequence position." ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_RUN_TO_MARK, "SCRIPT_RUN_TO_MARK", "Running to the scripted sequence position." ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_PLAYING, "SCRIPT_PLAYING", "Moving to the scripted sequence position while playing a custom movement animation." ); + + ScriptRegisterConstant( g_pScriptVM, D_ER, "'Error' relationship definition. Used by NPCs and players for relationship disposition." ); + ScriptRegisterConstant( g_pScriptVM, D_HT, "Denotes a 'Hate' relationship. Used by NPCs and players for relationship disposition." ); + ScriptRegisterConstant( g_pScriptVM, D_FR, "Denotes a 'Fear' relationship. Used by NPCs and players for relationship disposition." ); + ScriptRegisterConstant( g_pScriptVM, D_LI, "Denotes a 'Like' relationship. Used by NPCs and players for relationship disposition." ); + ScriptRegisterConstant( g_pScriptVM, D_NU, "Denotes a 'Neutral' relationship. Used by NPCs and players for relationship disposition." ); #endif // diff --git a/sp/src/vscript/vscript_bindings_base.cpp b/sp/src/vscript/vscript_bindings_base.cpp index 9511efa4..e407af5e 100644 --- a/sp/src/vscript/vscript_bindings_base.cpp +++ b/sp/src/vscript/vscript_bindings_base.cpp @@ -459,6 +459,8 @@ void RegisterBaseBindings( IScriptVM *pVM ) //----------------------------------------------------------------------------- + ScriptRegisterConstant( pVM, MAPBASE_VERSION, "The current Mapbase version according to when the VScript library was last compiled." ); + // // Math/world //